ddd-ts-kit/imports-extension
Architecture id: imports/extension. Default severity: error in recommended, error in strict. Fixable (eslint --fix).
Applies to: every TypeScript file under the source root, under test/ and under scripts/.
An import of a file of the project has one spelling. importExtension in ddd-ts-kit.config.json says which:
importExtension |
An import is written | The compiler resolves it | Who holds the other spelling |
|---|---|---|---|
none, the default of a new project |
@/contexts/billing/domain/aggregates/invoice.aggregate |
as a bundler does ("moduleResolution": "Bundler", with the node condition), which accepts both spellings |
this rule: the compiler would let .js through |
js, also what a config without the key means |
@/contexts/billing/domain/aggregates/invoice.aggregate.js |
as Node does ("moduleResolution": "NodeNext"), which requires the extension |
the compiler (TS2835), and this rule, which fixes it |
Node needs the extension at run time whatever the sources write: ddd-ts-kit build-aliases, the second step of npm run build, rewrites each alias of the compiled output into a relative path ending in .js. The build names one file per specifier and guesses nothing, so a specifier written the other way stops it: this rule reports the mistake in the editor instead. See Import aliases.
Reported
Section titled “Reported”- under
none: an alias specifier that ends with.js,.mjs,.cjs,.ts,.mtsor.cts: fixed by removing the extension - under
js: an alias specifier that does not end with.js(.mjsand.cjsare accepted, they name what an.mtsor a.ctsfile emits): fixed by writing.jsin place of what it ends with
Incorrect under none:
import { Invoice } from '@/contexts/billing/domain/aggregates/invoice.aggregate.js';import { startApplication } from '$test/e2e/support/start-application.ts';Correct under none:
import { Invoice } from '@/contexts/billing/domain/aggregates/invoice.aggregate';import { startApplication } from '$test/e2e/support/start-application';Incorrect under js:
import { Invoice } from '@/contexts/billing/domain/aggregates/invoice.aggregate';Correct under js:
import { Invoice } from '@/contexts/billing/domain/aggregates/invoice.aggregate.js';Details
Section titled “Details”Static imports, type-only imports, export ... from, export *, dynamic import(), import() types and require() are all read. A dynamic import whose specifier is computed is not judged.
Only a specifier that starts with an alias of the project is judged (importAlias, $test/, $scripts/, and $generated/ with stack.orm prisma). A package is never a file of the project, whatever its subpath ends with: zod/v4/core.js and @scope/package/file.js are left alone, and so is a Node built-in. A relative import is reported by imports/alias-only, whose fix writes the alias with the right ending.
A dot in a file name is not an extension: invoice.aggregate, issue-invoice.command and load-config are all read as written without one.
The fix keeps the quotes of the specifier. Under none a fixed import is three characters shorter and may now fit on one line: run the formatter after the fix (npm run format). Fixing twice changes nothing.
Not judged: a file outside the three directories (a config file at the project root, a JavaScript migration, which Node runs as written and which therefore keeps its extensions) and the client under generated/, which a tool writes.
Moving a project to the other spelling
Section titled “Moving a project to the other spelling”A project generated before the key existed is read as js and keeps working untouched. To drop the extensions:
- set
"importExtension": "none"inddd-ts-kit.config.json; - run
ddd-ts-kit check:imports/alias-declaredgives themodule,moduleResolutionandcustomConditionsto write intsconfig.json, and the jest mapping when the project runs jest; - run
eslint --fix, thennpm run format; - regenerate what the kit generates (
ddd-ts-kit generateorddd-ts-kit docsrewrites the declarations barrels), thennpm run verify.
Options
Section titled “Options”None. importExtension of ddd-ts-kit.config.json decides.
rules."imports/extension" in ddd-ts-kit.config.json set to off silences the rule, and // ddd-ts-kit-disable-next-line imports/extension -- <reason> silences one line, exactly as for ddd-ts-kit check.
Limits
Section titled “Limits”- A specifier that names a directory (
@/contexts/billing/published-language, resolved by a bundler to itsindex.ts) is not reported here: this rule reads no disk.ddd-ts-kit checkreports it under the same id, andddd-ts-kit build-aliasesrefuses it: an alias names one file,.../published-language/index. - The rule does not check that
tsconfig.jsonresolves as the config says:imports/alias-declaredofddd-ts-kit checkdoes.
With the CLI checker
Section titled “With the CLI checker”ddd-ts-kit check reports the same id from the import specifiers it reads in the text of the files, under the source root, test/ and scripts/, gives the specifier to write in its fix sentence, and also reports an alias that names a directory. This rule is the one that rewrites the import.