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, Serialize, Deserialize)]
62pub struct ExportFact {
63 pub name: ExportName,
64 pub local_name: Option<String>,
65 pub kind: String,
66 pub is_type_only: bool,
67 pub line: u32,
68 pub declared: bool,
69}
70
71#[derive(Debug, Clone, Serialize, Deserialize)]
72pub struct ImportFact {
73 pub source: String,
74 pub kind: ImportKind,
75 pub imported_name: Option<String>,
76 pub local_name: Option<String>,
77 pub is_type_only: bool,
78 pub line: u32,
79}
80
81#[derive(Debug, Clone, Serialize, Deserialize)]
82pub struct ReExportFact {
83 pub source: String,
84 pub kind: ReExportKind,
85 pub imported_name: Option<String>,
86 pub exported_name: Option<String>,
87 pub is_type_only: bool,
88 pub line: u32,
89}
90
91#[derive(Debug, Clone, Serialize, Deserialize)]
92pub struct DynamicImportFact {
93 pub source: Option<String>,
94 pub is_literal: bool,
95 pub line: u32,
96}
97
98#[derive(Debug, Clone, Serialize, Deserialize)]
99pub struct FileFacts {
100 pub file_id: FileId,
101 pub path: PathBuf,
102 pub content_hash: String,
103 pub exports: Vec<ExportFact>,
104 pub imports: Vec<ImportFact>,
105 pub re_exports: Vec<ReExportFact>,
106 pub dynamic_imports: Vec<DynamicImportFact>,
107 pub same_file_value_references: BTreeSet<String>,
108 pub used_import_bindings: BTreeSet<String>,
109 pub type_referenced_import_bindings: BTreeSet<String>,
110 pub value_referenced_import_bindings: BTreeSet<String>,
111 pub parse_error: Option<String>,
112}
113
114impl FileFacts {
115 pub fn empty(
116 file_id: FileId,
117 path: PathBuf,
118 content_hash: String,
119 parse_error: String,
120 ) -> Self {
121 Self {
122 file_id,
123 path,
124 content_hash,
125 exports: Vec::new(),
126 imports: Vec::new(),
127 re_exports: Vec::new(),
128 dynamic_imports: Vec::new(),
129 same_file_value_references: BTreeSet::new(),
130 used_import_bindings: BTreeSet::new(),
131 type_referenced_import_bindings: BTreeSet::new(),
132 value_referenced_import_bindings: BTreeSet::new(),
133 parse_error: Some(parse_error),
134 }
135 }
136}
137
138#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
139#[serde(rename_all = "snake_case")]
140pub enum LivenessVerdict {
141 Used,
142 Unused,
143 Uncertain,
144}
145
146#[derive(Debug, Clone, Serialize, Deserialize)]
147pub struct OxcExportVerdict {
148 pub symbol: String,
149 pub kind: String,
150 pub line: u32,
151 pub verdict: LivenessVerdict,
152 pub reason: String,
153 pub provenance: String,
154}
155
156#[derive(Debug, Clone, Serialize, Deserialize)]
157pub struct OxcFileVerdicts {
158 pub file: PathBuf,
159 pub relative_file: String,
160 pub exports: Vec<OxcExportVerdict>,
161}
162
163impl OxcFileVerdicts {
164 pub fn contribution_payload(&self) -> serde_json::Value {
165 serde_json::json!({
166 "file": self.relative_file,
167 "exports": self.exports,
168 "provenance": OXC_PROVENANCE,
169 })
170 }
171}
172
173#[derive(Debug, Clone, Serialize, Deserialize)]
174pub struct ResolverConfigInput {
175 pub path: PathBuf,
176 pub content_hash: String,
177}
178
179#[derive(Debug, Clone, Serialize, Deserialize)]
180pub struct OxcResolvedEdge {
181 pub from_file: PathBuf,
182 pub specifier: String,
183 pub resolved_file: Option<PathBuf>,
184 pub kind: String,
185}
186
187#[derive(Debug, Clone, Default, Serialize, Deserialize)]
188pub struct OxcEngineStats {
189 pub files: usize,
190 pub cache_hits: usize,
191 pub cache_misses: usize,
192 pub resolved_edges: usize,
193 pub unresolved_edges: usize,
194}
195
196#[derive(Debug, Clone, Serialize, Deserialize)]
197pub struct OxcEngineError {
198 pub file: PathBuf,
199 pub message: String,
200}
201
202#[derive(Debug, Clone, Serialize, Deserialize)]
203pub struct OxcEngineResult {
204 pub files: Vec<OxcFileVerdicts>,
205 pub resolver_config_inputs: Vec<ResolverConfigInput>,
206 pub resolver_config_fingerprint: String,
207 pub edges: Vec<OxcResolvedEdge>,
208 pub stats: OxcEngineStats,
209 pub errors: Vec<OxcEngineError>,
210 #[serde(default)]
211 pub skipped_outside_root: Vec<PathBuf>,
212}
213
214impl OxcEngineResult {
215 pub fn resolver_config_fingerprint(&self) -> &str {
216 &self.resolver_config_fingerprint
217 }
218}