1use std::collections::BTreeSet;
2use std::fmt;
3use std::path::PathBuf;
4
5use serde::{Deserialize, Serialize};
6
7pub const OXC_PROVENANCE: &str = "oxc";
8
9#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
10pub struct FileId(pub usize);
11
12#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
13#[serde(tag = "kind", content = "name", rename_all = "snake_case")]
14pub enum ExportName {
15 Named(String),
16 Default,
17}
18
19impl ExportName {
20 pub fn matches_str(&self, name: &str) -> bool {
21 match self {
22 Self::Named(value) => value == name,
23 Self::Default => name == "default",
24 }
25 }
26
27 pub fn as_symbol(&self) -> String {
28 match self {
29 Self::Named(value) => value.clone(),
30 Self::Default => "default".to_string(),
31 }
32 }
33}
34
35impl fmt::Display for ExportName {
36 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
37 match self {
38 Self::Named(name) => f.write_str(name),
39 Self::Default => f.write_str("default"),
40 }
41 }
42}
43
44#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
45#[serde(rename_all = "snake_case")]
46pub enum ImportKind {
47 Named,
48 Default,
49 Namespace,
50 SideEffect,
51}
52
53#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
54#[serde(rename_all = "snake_case")]
55pub enum ReExportKind {
56 Named,
57 Star,
58 Namespace,
59}
60
61#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
62pub struct DecoratorFact {
63 pub name: String,
64 pub segments: Vec<String>,
65 pub line: u32,
66}
67
68#[derive(Debug, Clone, Serialize, Deserialize)]
69pub struct ExportFact {
70 pub name: ExportName,
71 pub local_name: Option<String>,
72 pub kind: String,
73 pub is_type_only: bool,
74 pub line: u32,
75 pub declared: bool,
76 #[serde(default, skip_serializing_if = "Vec::is_empty")]
77 pub decorators: Vec<DecoratorFact>,
78}
79
80#[derive(Debug, Clone, Serialize, Deserialize)]
81pub struct ImportFact {
82 pub source: String,
83 pub kind: ImportKind,
84 pub imported_name: Option<String>,
85 pub local_name: Option<String>,
86 pub is_type_only: bool,
87 pub line: u32,
88}
89
90#[derive(Debug, Clone, Serialize, Deserialize)]
91pub struct ReExportFact {
92 pub source: String,
93 pub kind: ReExportKind,
94 pub imported_name: Option<String>,
95 pub exported_name: Option<String>,
96 pub is_type_only: bool,
97 pub line: u32,
98}
99
100#[derive(Debug, Clone, Serialize, Deserialize)]
101pub struct DynamicImportFact {
102 pub source: Option<String>,
103 pub is_literal: bool,
104 pub line: u32,
105}
106
107#[derive(Debug, Clone, Serialize, Deserialize)]
108pub struct FileFacts {
109 pub file_id: FileId,
110 pub path: PathBuf,
111 pub content_hash: String,
112 pub exports: Vec<ExportFact>,
113 pub imports: Vec<ImportFact>,
114 pub re_exports: Vec<ReExportFact>,
115 pub dynamic_imports: Vec<DynamicImportFact>,
116 pub same_file_value_references: BTreeSet<String>,
117 pub used_import_bindings: BTreeSet<String>,
118 pub type_referenced_import_bindings: BTreeSet<String>,
119 pub value_referenced_import_bindings: BTreeSet<String>,
120 pub parse_error: Option<String>,
121}
122
123impl FileFacts {
124 pub fn empty(
125 file_id: FileId,
126 path: PathBuf,
127 content_hash: String,
128 parse_error: String,
129 ) -> Self {
130 Self {
131 file_id,
132 path,
133 content_hash,
134 exports: Vec::new(),
135 imports: Vec::new(),
136 re_exports: Vec::new(),
137 dynamic_imports: Vec::new(),
138 same_file_value_references: BTreeSet::new(),
139 used_import_bindings: BTreeSet::new(),
140 type_referenced_import_bindings: BTreeSet::new(),
141 value_referenced_import_bindings: BTreeSet::new(),
142 parse_error: Some(parse_error),
143 }
144 }
145}
146
147#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
148#[serde(rename_all = "snake_case")]
149pub enum LivenessVerdict {
150 Used,
151 Unused,
152 Uncertain,
153}
154
155#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
156pub struct OxcReExportContext {
157 pub file: String,
158 pub line: u32,
159 pub exported_name: String,
160}
161
162fn is_false(value: &bool) -> bool {
163 !*value
164}
165
166#[derive(Debug, Clone, Serialize, Deserialize)]
167pub struct OxcExportVerdict {
168 pub symbol: String,
169 pub kind: String,
170 pub line: u32,
171 pub verdict: LivenessVerdict,
172 pub reason: String,
173 pub provenance: String,
174 #[serde(default, skip_serializing_if = "is_false")]
175 pub has_references: bool,
176 #[serde(default, skip_serializing_if = "Vec::is_empty")]
177 pub test_only_reference_files: Vec<String>,
178 #[serde(default, skip_serializing_if = "Vec::is_empty")]
179 pub also_reexported: Vec<OxcReExportContext>,
180}
181
182#[derive(Debug, Clone, Serialize, Deserialize)]
183pub struct OxcFileVerdicts {
184 pub file: PathBuf,
185 pub relative_file: String,
186 pub exports: Vec<OxcExportVerdict>,
187}
188
189impl OxcFileVerdicts {
190 pub fn contribution_payload(&self) -> serde_json::Value {
191 serde_json::json!({
192 "file": self.relative_file,
193 "exports": self.exports,
194 "provenance": OXC_PROVENANCE,
195 })
196 }
197}
198
199#[derive(Debug, Clone, Serialize, Deserialize)]
200pub struct ResolverConfigInput {
201 pub path: PathBuf,
202 pub content_hash: String,
203}
204
205#[derive(Debug, Clone, Serialize, Deserialize)]
206pub struct OxcResolvedEdge {
207 pub from_file: PathBuf,
208 pub specifier: String,
209 pub resolved_file: Option<PathBuf>,
210 pub kind: String,
211 pub line: u32,
212 pub is_type_only: bool,
213}
214
215#[derive(Debug, Clone, Default, Serialize, Deserialize)]
216pub struct OxcEngineStats {
217 pub files: usize,
218 pub cache_hits: usize,
219 pub cache_misses: usize,
220 pub resolved_edges: usize,
221 pub unresolved_edges: usize,
222}
223
224#[derive(Debug, Clone, Serialize, Deserialize)]
225pub struct OxcEngineError {
226 pub file: PathBuf,
227 pub message: String,
228}
229
230#[derive(Debug, Clone, Serialize, Deserialize)]
231pub struct OxcEngineResult {
232 pub files: Vec<OxcFileVerdicts>,
233 #[serde(default)]
234 pub facts: Vec<FileFacts>,
235 pub resolver_config_inputs: Vec<ResolverConfigInput>,
236 pub resolver_config_fingerprint: String,
237 pub edges: Vec<OxcResolvedEdge>,
238 pub stats: OxcEngineStats,
239 pub errors: Vec<OxcEngineError>,
240 #[serde(default)]
241 pub skipped_outside_root: Vec<PathBuf>,
242}
243
244impl OxcEngineResult {
245 pub fn resolver_config_fingerprint(&self) -> &str {
246 &self.resolver_config_fingerprint
247 }
248}