Skip to content
Closed
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
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ domino affected --report report.html
- `--debug`: Enable debug logging
- `--cwd <PATH>`: Set the current working directory
- `--lockfile-strategy <STRATEGY>`: Lockfile change detection strategy (default: `direct`)
- `--ignore-tsconfig-excludes`: Skip tsconfig exclude patterns (e.g., `*.spec.ts`, `*.stories.tsx`). Useful for test targets where test-file imports should also be traced

### Lockfile Change Detection

Expand Down
4 changes: 4 additions & 0 deletions docs/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -1027,6 +1027,10 @@ <h2>
<code>direct</code></span
>
</li>
<li class="option-item">
<span class="option-flag">--ignore-tsconfig-excludes</span>
<span class="option-desc">Skip tsconfig exclude patterns (e.g., <code>*.spec.ts</code>, <code>*.stories.tsx</code>). Useful for test targets where test-file imports should also be traced</span>
</li>
</ul>

<h3>Examples</h3>
Expand Down
7 changes: 7 additions & 0 deletions src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,11 @@ enum Commands {
/// Lockfile change detection strategy: none, direct, full
#[arg(long, default_value = "direct")]
lockfile_strategy: LockfileStrategy,

/// Skip tsconfig exclude patterns (e.g., *.spec.ts, *.stories.tsx).
/// Useful for test targets where test-file imports should also be traced.
#[arg(long)]
ignore_tsconfig_excludes: bool,
},
}

Expand Down Expand Up @@ -98,6 +103,7 @@ pub fn run() -> Result<()> {
profile,
report,
lockfile_strategy,
ignore_tsconfig_excludes,
} => {
let cwd = cwd.unwrap_or_else(|| std::env::current_dir().unwrap());

Expand Down Expand Up @@ -162,6 +168,7 @@ pub fn run() -> Result<()> {
".git".to_string(),
],
lockfile_strategy,
ignore_tsconfig_excludes,
};

// Use the report-generating version if --report is specified
Expand Down
6 changes: 5 additions & 1 deletion src/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,11 @@ fn find_affected_internal(
// Step 2: Build project index for O(unique_roots) lookups instead of O(n_projects)
// Also parses each project's tsconfig to extract exclude patterns, so that
// files excluded by tsconfig (e.g. stories, specs) don't mark a project affected.
let project_index = ProjectIndex::new(&config.projects, &config.cwd);
let project_index = ProjectIndex::new(
&config.projects,
&config.cwd,
config.ignore_tsconfig_excludes,
);

// Step 3: Build workspace analyzer (includes building import index)
debug!("Building workspace semantic analysis...");
Expand Down
3 changes: 3 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ mod napi_bindings {
pub enable_profiling: Option<bool>,
/// Lockfile change detection strategy: "none", "direct", "full" (default: "direct")
pub lockfile_strategy: Option<String>,
/// Skip tsconfig exclude patterns (e.g., *.spec.ts, *.stories.tsx)
pub ignore_tsconfig_excludes: Option<bool>,
}

#[napi(object)]
Expand Down Expand Up @@ -100,6 +102,7 @@ mod napi_bindings {
include: options.include.unwrap_or_default(),
ignored_paths: options.ignored_paths.unwrap_or_default(),
lockfile_strategy,
ignore_tsconfig_excludes: options.ignore_tsconfig_excludes.unwrap_or(false),
};

let result =
Expand Down
3 changes: 3 additions & 0 deletions src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,9 @@ pub struct TrueAffectedConfig {
pub ignored_paths: Vec<String>,
/// Lockfile change detection strategy
pub lockfile_strategy: LockfileStrategy,
/// When true, skip tsconfig exclude patterns (e.g., *.spec.ts, *.stories.tsx).
/// Useful for test targets where test-file imports should also be traced.
pub ignore_tsconfig_excludes: bool,
}

/// Result of the true affected analysis
Expand Down
37 changes: 24 additions & 13 deletions src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,12 @@ pub struct ProjectIndex {
impl ProjectIndex {
/// Build the index from a slice of projects, parsing each project's tsconfig
/// to extract exclude patterns.
pub fn new(projects: &[Project], cwd: &Path) -> Self {
///
/// When `ignore_tsconfig_excludes` is true, tsconfig exclude patterns are not
/// loaded — every file under a project's sourceRoot counts toward marking it
/// affected. This is useful for test targets where test-file imports should
/// also be traced.
pub fn new(projects: &[Project], cwd: &Path, ignore_tsconfig_excludes: bool) -> Self {
let mut map: Vec<(PathBuf, Vec<String>)> = Vec::new();
let mut excludes = FxHashMap::default();

Expand All @@ -47,19 +52,25 @@ impl ProjectIndex {
map.push((project.source_root.clone(), vec![project.name.clone()]));
}

if let Some(ts_config) = &project.ts_config {
if let Some(parsed) = TsconfigExcludes::parse(ts_config, cwd) {
debug!(
"Loaded {} exclude patterns for project '{}' from {}",
parsed.pattern_count(),
project.name,
ts_config.display()
);
excludes.insert(project.name.clone(), parsed);
if !ignore_tsconfig_excludes {
if let Some(ts_config) = &project.ts_config {
if let Some(parsed) = TsconfigExcludes::parse(ts_config, cwd) {
debug!(
"Loaded {} exclude patterns for project '{}' from {}",
parsed.pattern_count(),
project.name,
ts_config.display()
);
excludes.insert(project.name.clone(), parsed);
}
}
}
}

if ignore_tsconfig_excludes {
debug!("Tsconfig excludes disabled — all files count toward affected detection");
}

Self {
entries: map,
excludes,
Expand Down Expand Up @@ -190,7 +201,7 @@ mod tests {
},
];

let index = ProjectIndex::new(&projects, tmp.path());
let index = ProjectIndex::new(&projects, tmp.path(), false);

assert_eq!(
index.get_package_names_by_path(Path::new("libs/core/src/index.ts")),
Expand Down Expand Up @@ -233,7 +244,7 @@ mod tests {
},
];

let index = ProjectIndex::new(&projects, tmp.path());
let index = ProjectIndex::new(&projects, tmp.path(), false);

// File in shared sourceRoot should match both projects
let mut result = index.get_package_names_by_path(Path::new("projects/app-desktop/src/main.ts"));
Expand Down Expand Up @@ -270,7 +281,7 @@ mod tests {
targets: vec![],
}];

let index = ProjectIndex::new(&projects, cwd);
let index = ProjectIndex::new(&projects, cwd, false);

assert_eq!(
index.get_package_names_by_path(Path::new("libs/ui-widgets/src/index.ts")),
Expand Down
Loading
Loading