Skip to content

Commit 5702be9

Browse files
docs(detection): document SCSS importer JS/TS rejection (issue #245)
1 parent a0944ea commit 5702be9

1 file changed

Lines changed: 1 addition & 0 deletions

File tree

.claude/rules/detection.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ Non-obvious implementation details for each detection feature. These are NOT dis
4040
- **SCSS partial resolution**: `@use 'variables'` and `@import '../styles/variables'` resolve to `_variables.scss` per SCSS convention. Extensionless bare specifiers in `.scss`/`.sass` files (excluding `sass:*` built-ins) are normalized to relative paths at extraction time. Resolution fallback tries: (1) `_filename` partial prefix, (2) `specifier/_index` directory index, (3) `specifier/index` plain index. Prevents false unresolved-imports, unlisted-dependencies, and unused-files from SCSS partial references.
4141
- **SCSS include paths**: framework plugins contribute absolute directories to `PluginResult.scss_include_paths`. The Angular plugin reads `projects.*.architect.build.options.stylePreprocessorOptions.includePaths` from `angular.json`; the Nx plugin reads the same key from `project.json`. Nx workspace tokens (`{projectRoot}`, `{workspaceRoot}`) in include paths are expanded before resolution: `{projectRoot}` is computed from the config file's parent relative to the workspace root, `{workspaceRoot}` is stripped (paths are already resolved from workspace root). See issues #103, #114. Bare SCSS specifiers that fail the file-local `try_scss_partial_fallback` retry against each include dir, applying `<name>`, `_<name>`, `<name>/_index`, `<name>/index` candidates. Only triggers for `.scss`/`.sass` importers and normalized bare specifiers (those prefixed with `./` at extraction time) — explicit parent-relative paths like `../shared/vars` are left alone.
4242
- **SCSS node_modules resolution**: bare SCSS/Sass specifiers that fail both the local-partial and includePaths fallbacks are retried against `node_modules/` by walking up from the importing file to the filesystem root (matching Node.js / Sass semantics). `try_scss_node_modules_fallback` probes `<nm>/<pkg>/<path>.{scss,sass,css}`, `<nm>/<pkg>/<parent>/_<name>.{scss,sass}` (partial convention), and `<nm>/<pkg>/<path>/{_index,index}.{scss,sass}` (directory index). The CSS-extension append handles Sass's fallback for files like `animate.css/animate.min` → `animate.css/animate.min.css`. Because `node_modules/` files are outside fallow's file index (excluded by default ignore patterns), candidates are probed via `is_file()` on disk and a successful hit returns `ResolveResult::NpmPackage` (extracted via `extract_package_name_from_node_modules_path`), keeping `unused-dependencies` / `unlisted-dependencies` accurate. Scoped packages (`@scope/pkg/path`) are not prefixed with `./` by `normalize_css_import_path`, so they flow through `oxc_resolver`'s bare-module path directly and never reach this fallback. See issue #125.
43+
- **SCSS importer JS/TS rejection**: when the importing file is `.scss` / `.sass` AND the standard resolver returns a path with a JS/TS-family extension (`.tsx`, `.ts`, `.mts`, `.cts`, `.js`, `.jsx`, `.mjs`, `.cjs`), the result is rejected and resolution re-routes through the SCSS-aware fallback chain (CSS-extension probe, partial convention, include paths, node_modules). When those also fail, the import is reported as `Unresolvable` rather than falling through to the JS/TS extension list. Sass's resolution algorithm only ever considers `.css` / `.scss` / `.sass` files, so a sibling `.tsx` cannot legally satisfy a Sass `@use` / `@import` even though `oxc_resolver`'s extension list places `.tsx` before `.scss`. Without this guard, `@use 'Widget'` from a `.scss` file resolved to `Widget.tsx` whenever both files existed, creating phantom 3-file circular dependencies in standard CSS-modules / Angular `styleUrls` patterns where `.tsx` components import their own `.scss` and a sibling `.scss` shares variables/mixins via `@use`. See issue #245.
4344
- **Entry point source fallback for ignored output dirs**: when `package.json` `main`/`module`/`exports` resolves inside an output directory (`dist`, `build`, `out`, `esm`, `cjs`) and the direct `src/` mirror in `try_output_to_source_path` does not exist, `resolve_entry_path` probes `src/index.*`, `src/main.*`, `index.*`, `main.*` in the package root. Prevents the entire `src/` tree from becoming unreachable in libraries whose compiled entry (e.g. `dist/esm2022/index.js`) has no one-to-one source mirror. Emits a single `tracing::info!` per fallback. See issue #102.
4445
- **Workspace package self-reference & cross-workspace fallback**: when a bare specifier's package name matches a workspace package and normal resolution either fails or lands inside `node_modules` for that same package, `try_workspace_package_fallback` strips the package name prefix and resolves the subpath (`button`, `internal/base`, etc.) against a synthetic importer inside the workspace root. Uses `oxc_resolver`'s `resolve_file` so directory indices, source extensions, and the workspace's own `tsconfig.json` aliases still apply. Handles both Node.js v12+ self-referencing (`import '@org/pkg/sub'` from inside `@org/pkg`, common in Angular libraries built with `ng-packagr`) and cross-workspace imports in monorepos that haven't run `npm install`. See issue #106.
4546

0 commit comments

Comments
 (0)