Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add correct-ts-specifiers #7

Merged
merged 22 commits into from
Dec 20, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
384674b
feat: add `correct-ts-specifiers`
JakobJingleheimer Dec 1, 2024
71b2e73
chore(deps): update to `@nodejs-loaders/alias`
JakobJingleheimer Dec 7, 2024
4b09553
fix: logger snap file name
JakobJingleheimer Dec 7, 2024
9dd61b0
chore(ci): update import to use project's customiser
JakobJingleheimer Dec 7, 2024
5f4df17
fix(test): e2e main fixture
JakobJingleheimer Dec 7, 2024
cdedddd
fixup!: correct types
JakobJingleheimer Dec 8, 2024
d39dc75
chore(lint): de-lint
JakobJingleheimer Dec 8, 2024
ccf9394
Merge branch 'main' into feat/correct-ts-specifiers
JakobJingleheimer Dec 11, 2024
21db5dd
fixup!: remove redundant gitignore
JakobJingleheimer Dec 11, 2024
b977182
fixup!: remove obsolete test badge from README
JakobJingleheimer Dec 11, 2024
bea0b23
fixup!: tidy
JakobJingleheimer Dec 11, 2024
1e8ec00
fixup!: comment to explain why to _not_ ignore `node_modules` fixture
JakobJingleheimer Dec 11, 2024
79028f7
Merge remote-tracking branch 'origin/main' into feat/correct-ts-speci…
JakobJingleheimer Dec 11, 2024
2b186c8
fixup!: type for extensions
JakobJingleheimer Dec 12, 2024
87c6a1f
Merge remote-tracking branch 'origin/main' into feat/correct-ts-speci…
JakobJingleheimer Dec 12, 2024
b702093
fixup!: revert committing migration to e2e test fixture
JakobJingleheimer Dec 12, 2024
cdc5c41
fixup!: register `@nodejs-loaders/alias` within workflow
JakobJingleheimer Dec 13, 2024
9dab933
fixup!: specifically mention monorepos in README
JakobJingleheimer Dec 13, 2024
9824fd4
fixup!: remove obsolete CLI command from run instructions
JakobJingleheimer Dec 15, 2024
c1d9f99
Merge remote-tracking branch 'origin/main' into feat/correct-ts-speci…
JakobJingleheimer Dec 15, 2024
4fc0083
fixup!: update pjson github links
JakobJingleheimer Dec 16, 2024
3d93029
fixup!: add codemod package info
JakobJingleheimer Dec 16, 2024
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 recipes/correct-ts-specifiers/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
node_modules
JakobJingleheimer marked this conversation as resolved.
Show resolved Hide resolved
92 changes: 92 additions & 0 deletions recipes/correct-ts-specifiers/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
# Correct TypeScript Specifiers

![tests](https://github.com/JakobJingleheimer/correct-ts-specifiers/actions/workflows/ci.yml/badge.svg)
JakobJingleheimer marked this conversation as resolved.
Show resolved Hide resolved

This package transforms import specifiers in source-code from the broken state TypeScript's compiler (`tsc`) required (prior TypeScript v5.7 RC) into proper ones. This is useful when source-code is processed by standards-compliant software like Node.js. This is a one-and-done process, and the updated source-code should be committed to your version control (ex git); thereafter, source-code import statements should be authored compliant with the ECMAScript (JavaScript) standard.

> [!TIP]
> Those using `tsc` to compile will need to enable [`rewriteRelativeImportExtensions`](https://www.typescriptlang.org/tsconfig/#rewriteRelativeImportExtensions); using `tsc` for only type-checking (ex via a lint/test step like `npm run test:types`) needs [`allowImportingTsExtensions`](https://www.typescriptlang.org/tsconfig/#allowImportingTsExtensions) (and some additional compile options—see the cited documentation);

This package does not just blindly find & replace file extensions within specifiers: It confirms that the replacement specifier actually exists; in ambiguous cases (such as two files with the same basename in the same location but different relevant file extensions like `/tmp/foo.js` and `/tmp/foo.ts`), it logs an error, skips that specifier, and continues processing.

> [!CAUTION]
> This package does not confirm that imported modules contain the desired export(s). This _shouldn't_ actually ever result in a problem because ambiguous cases are skipped (so if there is a problem, it existed before the migration started). Merely running your source-code after the mirgration completes will confirm all is well (if there are problems, node will error, citing the problems).

> [!TIP]
> Node.js requires the `type` keyword be present on type imports. For own code, this package usually handles that. However, in some cases and for node modules, it does not. Robust tooling already exists that will automatically fix this, such as [`consistent-type-imports` via typescript-lint](https://typescript-eslint.io/rules/consistent-type-imports) and [`use-import-type` via biome](https://biomejs.dev/linter/rules/use-import-type/). If your source code needs that, first run this codemod and then one of those fixers.

## Running

> [!CAUTION]
> This will change your source-code. Commit any unsaved changes before running this package.

```sh
npx codemod@latest correct-ts-specifiers
```

If you're using `tsconfig`'s `paths`, you will need a loader like [`@nodejs-loaders/alias`](https://github.com/JakobJingleheimer/nodejs-loaders/blob/main/packages/alias?tab=readme-ov-file)


```sh
npm i @nodejs-loaders/alias

NODE_OPTIONS="--loader=@nodejs-loaders/alias" \
npx codemod@latest correct-ts-specifiers
```

## Supported cases

* no file extension → `.cts`, `.mts`, `.js`, `.ts`, `.d.cts`, `.d.mts`, or `.d.ts`
* `.cjs` → `.cts`, `.mjs` → `.mts`, `.js` → `.ts`
* `.js` → `.d.cts`, `.d.mts`, or `.d.ts`
* [Package.json subimports](https://nodejs.org/api/packages.html#subpath-imports)
* [tsconfig paths](https://www.typescriptlang.org/tsconfig/#paths) (requires a loader)
* Commonjs-like directory specifiers

Before:

```ts
import { URL } from 'node:url';

import { bar } from '@dep/bar';
import { foo } from 'foo';

import { Bird } from './Bird'; // a directory
import { Cat } from './Cat.ts';
import { Dog } from '…/Dog/index.mjs'; // tsconfig paths
import { baseUrl } from '#config.js'; // package.json imports

export { Zed } from './zed';

export const makeLink = (path: URL) => (new URL(path, baseUrl)).href;

const nil = await import('./nil.js');

const bird = new Bird('Tweety');
const cat = new Cat('Milo');
const dog = new Dog('Otis');
```

After:

```ts
import { URL } from 'node:url';

import { bar } from '@dep/bar';
import { foo } from 'foo';

import { Bird } from './Bird/index.ts';
import { Cat } from './Cat.ts';
import { Dog } from '…/Dog/index.mts'; // tsconfig paths
import { baseUrl } from '#config.js'; // package.json imports

export type { Zed } from './zed.d.ts';

export const makeLink = (path: URL) => (new URL(path, baseUrl)).href;

const nil = await import('./nil.ts');

const bird = new Bird('Tweety');
const cat = new Cat('Milo');
const dog = new Dog('Otis');
```
Loading
Loading