Skip to content

Commit ff00f9d

Browse files
Merge pull request #94 from CodeDeficient/claude/project-thread-36cl1x-deno-config-names
Read import maps from deno.<name>.json configs too
2 parents 3f6a1d7 + ca17c1a commit ff00f9d

3 files changed

Lines changed: 14 additions & 4 deletions

File tree

‎CHANGELOG.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ All notable changes will be documented in this file.
1717
- A `customPatterns` entry whose `id` is a built-in rule id (`empty_catch`) or the id of another custom pattern is an invalid config. A shared id made `severityOverrides` and the exit code treat two rules as one.
1818
- A run fails (exit 1) on high and critical findings only. Medium findings such as `type_assertion` and `any_type_usage` are still reported but no longer fail a build; every clean repository tested (ky, express, hono, zod, date-fns, TanStack Query) exited 1 before. `--fail-on=<critical|high|medium|low>` sets the threshold.
1919
- A bundler config marks an import as an alias only when it quotes the whole name (`'@components'`, `'~/lib'`, webpack's `'@acme/ui$'`). A scoped name covers that package only: `'@acme/ui'` in a config or tsconfig `paths` does not cover `@acme/other`. A longer name that starts the same way (`'vite-plugin-pwa'` for `vite-plugin`) used to hide an undeclared or nonexistent package.
20-
- Names in a Deno import map (`imports` in `deno.json`/`deno.jsonc`, or the file its `importMap` names) are aliases, not npm packages. hono's Deno tests import `@std/assert` from JSR and got four critical `nonexistent_package` findings, so `--strict` failed a clean repository.
20+
- Names in a Deno import map (`imports` in `deno.json`, `deno.jsonc` or a `deno.<name>.json` passed with `--config`, or the file its `importMap` names) are aliases, not npm packages. hono's Deno tests import `@std/assert` from JSR and got four critical `nonexistent_package` findings, so `--strict` failed a clean repository.
2121
- `hallucinated_import` reports a relative or tsconfig `paths` import with no file behind it (`import { validate } from '../lib/validation'`). A file with any extension counts (`./Widget.vue`, `./styles.css?raw`). Paths into build output or generated code (`dist/`, `build/`, `out/`, `generated/`, dot-folders, SvelteKit `$types`) are skipped, since they are often absent from a checkout.
2222
- Benchmark and example folders (`bench/`, `benchmarks/`, `examples/`, `runtime-tests/`, `perf-measures/`) count as non-production code, like tests: rules for application code skip them and they are left out of finding density. zod's `packages/bench` produced 375 `production_console_log` findings and express's `examples/` 36.
2323
- `any_type_usage` skips the rest parameter and bare `any` return of a function type such as `type AnyFn = (...args: any[]) => any`. Parameters are contravariant, so `(...args: unknown[]) => unknown` does not accept `(x: string) => void` and there is no safer spelling.

‎imports.ts‎

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -316,15 +316,23 @@ class ResolutionIndex {
316316

317317
/**
318318
* Keys of the Deno import maps from `dir` up to the filesystem root: the
319-
* `imports` of deno.json/deno.jsonc and of the file its `importMap` names.
319+
* `imports` of every deno config there (deno.json, deno.jsonc, deno.<name>.json)
320+
* and of the file its `importMap` names.
320321
* They map names such as `@std/assert` to `jsr:` or URL modules, not npm.
321322
*/
322323
private denoImportKeys(dir: string): string[] {
323324
const cached = this.denoKeys.get(dir);
324325
if (cached !== undefined) return cached;
325326
const parent = path.dirname(dir);
326327
const keys = parent === dir ? [] : [...this.denoImportKeys(parent)];
327-
for (const name of ['deno.json', 'deno.jsonc']) {
328+
let entries: string[] = [];
329+
try {
330+
entries = fs.readdirSync(dir);
331+
} catch {
332+
// Unreadable directory: no import map here.
333+
}
334+
// deno.json, deno.jsonc, and variants passed with --config (deno.react-jsx.json, deno.react.precompile.json).
335+
for (const name of entries.filter(entry => /^deno(\.[\w-]+)*\.jsonc?$/.test(entry))) {
328336
const config = readJsoncObject(path.join(dir, name));
329337
if (config === undefined) continue;
330338
keys.push(...Object.keys(asObject(config.imports) ?? {}));

‎tests/rules.test.ts‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -675,10 +675,12 @@ test('checkImports: names from a Deno import map are not npm packages', async ()
675675
'package.json': JSON.stringify({ name: 'repo', private: true }),
676676
'runtime-tests/deno/deno.jsonc': '{\n // JSR packages\n "imports": { "@std/assert": "jsr:@std/assert@^1", "@std/path/": "jsr:/@std/path@^1/" },\n "importMap": "./map.json"\n}\n',
677677
'runtime-tests/deno/map.json': JSON.stringify({ imports: { 'oak': 'https://deno.land/x/oak/mod.ts' } }),
678+
'runtime-tests/deno-jsx/deno.react.precompile.json': JSON.stringify({ imports: { '@std/expect': 'jsr:@std/expect@^1' } }),
679+
'runtime-tests/deno-jsx/b.test.tsx': "import { expect } from '@std/expect';\n",
678680
'runtime-tests/deno/a.test.ts': "import { assertEquals } from '@std/assert';\nimport { join } from '@std/path/posix';\nimport { Application } from 'oak';\nimport { x } from 'left-padx-utils-ai';\n"
679681
});
680682
try {
681-
const findings = await checkImports([path.join(dir, 'runtime-tests/deno/a.test.ts')], dir, recording);
683+
const findings = await checkImports([path.join(dir, 'runtime-tests/deno/a.test.ts'), path.join(dir, 'runtime-tests/deno-jsx/b.test.tsx')], dir, recording);
682684
assert.deepEqual(findings.map(f => [f.type, f.line]), [['nonexistent_package', 4]]);
683685
assert.deepEqual(lookups, ['left-padx-utils-ai']);
684686
} finally {

0 commit comments

Comments
 (0)