Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 16 additions & 3 deletions codescythe.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,22 @@
},
"unresolvedImports": {
"description": "Controls how unresolved imports are handled.",
"type": "string",
"enum": ["report", "ignore", "error"],
"default": "report"
"type": "object",
"additionalProperties": false,
"properties": {
"mode": {
"type": "string",
"enum": ["report", "ignore", "error"],
"default": "report"
},
"ignore": {
"description": "Unresolved import specifier glob patterns to ignore.",
"$ref": "#/$defs/stringOrStringArray"
}
},
"default": {
"mode": "report"
}
},
"includeEntryExports": {
"type": "boolean",
Expand Down
50 changes: 44 additions & 6 deletions crates/codescythe/analyze.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ pub fn analyze_path(
.map(|(index, file)| (file.path.clone(), index))
.collect::<HashMap<_, _>>();
let module_resolver = ModuleResolver::new(&cwd, &files, config);
let unresolved_policy = UnresolvedImportPolicy::new(config);
let unresolved_policy = UnresolvedImportPolicy::new(config)?;

let mut entry_indexes = HashSet::<usize>::new();
let mut used_files = UsedFiles::new();
Expand Down Expand Up @@ -622,13 +622,15 @@ fn is_relative_alias_path(value: &str) -> bool {

struct UnresolvedImportPolicy {
mode: UnresolvedImportsMode,
ignore: GlobSet,
}

impl UnresolvedImportPolicy {
fn new(config: &CodescytheConfig) -> Self {
Self {
mode: config.unresolved_imports,
}
fn new(config: &CodescytheConfig) -> Result<Self> {
Ok(Self {
mode: config.unresolved_imports.mode,
ignore: build_glob_set(&config.unresolved_imports.ignore)?,
})
}

fn record(
Expand All @@ -637,6 +639,10 @@ impl UnresolvedImportPolicy {
importer: &str,
specifier: &str,
) -> Result<()> {
if self.ignore.is_match(specifier) {
return Ok(());
}

match self.mode {
UnresolvedImportsMode::Report => {
unresolved
Expand Down Expand Up @@ -1484,6 +1490,38 @@ mod tests {
assert!(message.contains("./missing"));
}

#[test]
fn ignored_unresolved_patterns_do_not_count_as_issues() {
let tempdir = tempfile::tempdir().unwrap();
let cwd = tempdir.path();

write_file(
cwd,
"codescythe.json",
r##"{
"entry": "src/main.ts",
"project": "src/**/*.ts",
"unresolvedImports": {
"ignore": ["#virtual_generated/**"]
}
}"##,
);
write_file(
cwd,
"src/main.ts",
"import '#virtual_generated/api/foo';\nimport './missing';\n",
);

let config = crate::load_config(cwd, None).unwrap();
let analysis = analyze_path(cwd, &config, AnalysisOptions::default()).unwrap();

assert_eq!(
analysis.issues.unresolved["src/main.ts"],
vec!["./missing".to_string()]
);
assert_eq!(analysis.counters.unresolved, 1);
}

#[test]
fn reports_missing_local_imports() {
let tempdir = tempfile::tempdir().unwrap();
Expand Down Expand Up @@ -1522,7 +1560,7 @@ console.log(missingExternal, missingExternalSubpath);
let tempdir = tempfile::tempdir().unwrap();
let cwd = tempdir.path();
let mode_config = mode
.map(|mode| format!(r#", "unresolvedImports": "{mode}""#))
.map(|mode| format!(r#", "unresolvedImports": {{ "mode": "{mode}" }}"#))
.unwrap_or_default();

write_file(
Expand Down
10 changes: 9 additions & 1 deletion crates/codescythe/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,19 @@ pub struct CodescytheConfig {
pub ignore: Vec<String>,
#[serde(deserialize_with = "deserialize_aliases")]
pub aliases: BTreeMap<String, Vec<String>>,
pub unresolved_imports: UnresolvedImportsMode,
pub unresolved_imports: UnresolvedImportsConfig,
pub include_entry_exports: bool,
pub ignore_exports_used_in_file: bool,
}

#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "camelCase", default)]
pub struct UnresolvedImportsConfig {
pub mode: UnresolvedImportsMode,
#[serde(deserialize_with = "deserialize_patterns")]
pub ignore: Vec<String>,
}

#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub enum UnresolvedImportsMode {
Expand Down
2 changes: 1 addition & 1 deletion crates/codescythe/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ mod fix;
pub use analyze::{
Analysis, AnalysisOptions, Counters, FileIssue, Issues, SymbolIssue, analyze_path,
};
pub use config::{CodescytheConfig, UnresolvedImportsMode, load_config};
pub use config::{CodescytheConfig, UnresolvedImportsConfig, UnresolvedImportsMode, load_config};
pub use fix::{FixResult, apply_fixes};

use std::path::Path;
Expand Down
Loading