@ts-r.dev/typescript 7.0.1000-alpha.3 → 7.0.1000-alpha.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (4) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +77 -30
  3. package/lib/tsc.cjs +42 -15
  4. package/package.json +7 -6
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Webb Ventures and the ts-r contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -5,12 +5,14 @@ A drop-in for the `typescript` package. Its `tsc` type-checks with
5
5
  your own TypeScript on that project, and runs your TypeScript for everything else. Its module API
6
6
  (`typescript`, `typescript/unstable/*`) is your TypeScript's.
7
7
 
8
- Your real TypeScript (7.x) stays installed: it is a peer dependency, and the fallback for every
9
- flag, project and API ts-r doesn't cover.
8
+ Your real TypeScript (7.x) stays installed: it is a peer dependency (or the `typescript-real`
9
+ alias), and the fallback for every flag, project and API ts-r doesn't cover.
10
10
 
11
11
  ## Install
12
12
 
13
- Either way works; undo it by deleting the line(s).
13
+ Either way works; undo it by deleting the line(s). While ts-r is in alpha, name an exact
14
+ version (below, `7.0.1000-alpha.3`; `npm view @ts-r.dev/typescript dist-tags` lists the
15
+ current ones) or the `next` dist-tag, not a range like `^7`: see [Versions](#versions).
14
16
 
15
17
  **Next to TypeScript** (point `typescript.tsdk`, scripts or tools at this package):
16
18
 
@@ -18,37 +20,64 @@ Either way works; undo it by deleting the line(s).
18
20
  // package.json
19
21
  "devDependencies": {
20
22
  "typescript": "^7.0.0",
21
- "@ts-r.dev/typescript": "^7"
23
+ "@ts-r.dev/typescript": "7.0.1000-alpha.3"
22
24
  }
23
25
  ```
24
26
 
25
- Run it as `npx -p @ts-r.dev/typescript tsc` or `node_modules/@ts-r.dev/typescript/bin/tsc`, or set
27
+ or `npm install --save-dev typescript@7 @ts-r.dev/typescript@next`. Run it as
28
+ `npx -p @ts-r.dev/typescript tsc` or `node_modules/@ts-r.dev/typescript/bin/tsc`, or set
26
29
  `"typescript.tsdk": "node_modules/@ts-r.dev/typescript/lib"`.
27
30
 
28
31
  **In place of TypeScript** (every tool that runs `tsc` or imports `typescript` gets this package):
29
32
 
30
33
  ```jsonc
31
34
  "devDependencies": {
32
- "typescript": "npm:@ts-r.dev/typescript@^7",
35
+ "typescript": "npm:@ts-r.dev/typescript@next",
33
36
  "typescript-real": "npm:typescript@^7.0.0"
34
37
  }
35
38
  ```
36
39
 
37
- The `typescript-real` alias is how the drop-in finds your TypeScript when it occupies the
38
- `typescript` name itself.
40
+ (An exact version works too, from the first release after `7.0.1000-alpha.3`: alpha.3 and
41
+ earlier were published with a `typescript` peer range that fails this install with `ERESOLVE`;
42
+ see [Versions](#versions).) The `typescript-real` alias is how the drop-in
43
+ finds your TypeScript when it occupies the `typescript` name itself. Tools that find
44
+ TypeScript by resolving `typescript` from your project, such as `next build`, only use the
45
+ drop-in this way (see [Next.js](#nextjs)).
46
+
47
+ ### Versions
48
+
49
+ The version is TypeScript's `major.minor`, a patch that encodes the ts-r version (ts-r
50
+ 0.1.0 -> `7.0.1000`, 1.2.3 -> `7.0.1002003`) and ts-r's prerelease label: ts-r
51
+ 0.1.0-alpha.3 is `7.0.1000-alpha.3`. By semver's rule, which npm follows, a range like `^7` or
52
+ `^7.0.0` never matches a prerelease; a range only matches prereleases of the exact
53
+ `major.minor.patch` it names itself (`^7.0.1000-alpha.3` matches `7.0.1000-alpha.4`, not
54
+ `7.0.2000-alpha.1`). That is deliberate on npm's side (nobody gets an alpha without asking for
55
+ one), and the drop-in keeps the label so its alphas are marked and ordered the same way as
56
+ ts-r's. So during the alpha, pin an exact version or use `next`; `^7` starts to work with
57
+ ts-r's first stable release.
58
+
59
+ The `typescript` peer dependency is `^7.0.0` plus the drop-in's own version (for
60
+ `7.0.1000-alpha.3`: `^7.0.0 || 7.0.1000-alpha.3`). Installed in place of TypeScript, the
61
+ `typescript` name is the drop-in itself, so npm checks the peer against the drop-in's version;
62
+ without its own version in the range, an alpha fails that check (`ERESOLVE`). Installed next to
63
+ TypeScript, the peer is your TypeScript and must match `^7.0.0`.
39
64
 
40
65
  ## What `tsc` does
41
66
 
42
67
  Every run goes through these steps, in order. The first one that applies decides.
43
68
 
44
69
  1. **`TS_R_TSC=typescript`**: run your TypeScript's `tsc` with the arguments unchanged.
45
- 2. **Flags ts-r-check doesn't support go to your TypeScript.** ts-r-check takes
46
- `-p`/`--project <file or dir>`, `--noEmit [true|false]` and `--pretty [true|false]` (names
47
- are case-insensitive, like tsc's). Anything else (file names, `--build`, `--watch`,
48
- `--declaration`, `--outDir`, `--strict`, `--init`, `--showConfig`, `--listFiles`, ...) runs
49
- your `tsc` with the arguments unchanged and prints one line on stderr:
70
+ 2. **Flags ts-r-check doesn't support go to your TypeScript.** The drop-in takes
71
+ `-p`/`--project <file or dir>`, `--noEmit [true|false]`, `--pretty [true|false]`,
72
+ `--tsBuildInfoFile <file>`, and these emit options when set to `false`: `--declaration`
73
+ (`-d`), `--declarationMap`, `--emitDeclarationOnly`, `--sourceMap`, `--inlineSourceMap` and
74
+ `--inlineSources` (option names are case-insensitive, like tsc's). Anything else (file
75
+ names, `--build`, `--watch`, `--declaration` on its own or `true`, `--outDir`, `--strict`,
76
+ `--init`, `--listFiles`, ...) runs your `tsc` with the arguments unchanged and prints one line
77
+ on stderr:
50
78
  `@ts-r.dev/typescript: ts-r-check doesn't support --watch; running TypeScript 7.0.2's tsc.`
51
- `--version`, `-v`, `--help`, `-h` and `--all` go to your TypeScript without that line.
79
+ `--version`, `-v`, `--help`, `-h`, `--all` and `--showConfig` go to your TypeScript without
80
+ that line.
52
81
  3. **No tsconfig: your TypeScript.** The project is `-p`'s file (or `<dir>/tsconfig.json`), else
53
82
  the nearest `tsconfig.json` from the working directory up. If there is none, your `tsc` runs
54
83
  and reports it.
@@ -62,27 +91,32 @@ Every run goes through these steps, in order. The first one that applies decides
62
91
  7. **Without your TypeScript there is no parity check**: ts-r-check runs, with a note.
63
92
  8. **The parity check decides, per project** (the plan's per-project parity rule, the same one
64
93
  `ts-r-lsp` uses):
65
- - The first run for a project runs ts-r-check and your `tsc` side by side, both with
66
- `-p <tsconfig> --noEmit --pretty false` (ts-r-check also with `--sound=off`), and compares
67
- their exit codes and their diagnostics as multisets of whole diagnostics (location, code,
68
- message and every chained line).
94
+ - The first run for a project runs ts-r-check and your `tsc` side by side, both with your
95
+ `-p` (if you gave one) and your other accepted options (`--tsBuildInfoFile`, the emit
96
+ options set to `false`) as you gave them, then `--noEmit --pretty false` (ts-r-check also
97
+ with `--sound=off`), and compares their exit codes and their diagnostics as multisets of
98
+ whole diagnostics (location, code, message and every chained line).
69
99
  - **Match**: this run and later runs use ts-r-check. **Mismatch**: this run and later runs
70
100
  use your TypeScript for that project, and a stderr note gives the path of a plain-text
71
101
  report listing the diagnostics only one side produced.
72
102
  - The result is cached in `<ts-r cache>/typescript/parity/<key>.json` (the cache is
73
103
  `$TS_R_CACHE_DIR`, else `$XDG_CACHE_HOME/ts-r`, `%LOCALAPPDATA%\ts-r` or `~/.cache/ts-r`).
74
104
  The key covers the tsconfig path, the text of the tsconfig and every config it extends, the
75
- nearest lockfile, your TypeScript's version and the ts-r-check version and binary. Editing
76
- source files doesn't re-run the check; changing any of those does. Delete the directory to
77
- force a re-check.
78
- - On that first run, when the output isn't pretty (`--pretty false`, `"pretty": false`, or
79
- stdout isn't a terminal), the captured output of the chosen side is printed and its exit
80
- code returned, so nothing runs twice. With pretty output, the chosen side runs again with
81
- your arguments.
82
-
83
- When ts-r-check runs, it gets `-p <tsconfig> --noEmit --sound=off --pretty <true|false>` (your
84
- `--pretty`, else tsconfig's `"pretty": false`, else whether stdout is a terminal). Its
85
- output format and exit codes are tsc's: 0 without errors, 1 with errors (no emit happens).
105
+ nearest lockfile, your TypeScript's version, the ts-r-check version and binary, and the
106
+ options passed to both checkers (so `tsc` and `tsc --declarationMap false` are checked
107
+ separately). Editing source files doesn't re-run the check; changing any of those does.
108
+ Delete the directory to force a re-check.
109
+ - On that first run, when the output isn't pretty (see below), the captured output of the
110
+ chosen side is printed and its exit code returned, so nothing runs twice. With pretty
111
+ output, the chosen side runs again with your arguments.
112
+
113
+ When ts-r-check runs, it gets your `-p` only if you gave one (without it, ts-r-check finds the
114
+ nearest `tsconfig.json` the way tsc does, and diagnostic paths stay relative to the working
115
+ directory like tsc's), your other accepted options as given, then
116
+ `--noEmit --sound=off --pretty <true|false>`. Pretty output follows tsc 7: your `--pretty`,
117
+ else off when `NO_COLOR` is set (non-empty), else on when `FORCE_COLOR` is set (non-empty),
118
+ else whether stdout is a terminal; like tsc 7, `pretty` in tsconfig is ignored. Its output
119
+ format and exit codes are tsc's: 0 without errors, 1 with errors (no emit happens).
86
120
  Diagnostics come sorted by file and position; tsc prints them in program order, so the order can
87
121
  differ even when the parity check passed (it compares multisets).
88
122
 
@@ -116,6 +150,16 @@ so its output and exit code are exactly its own.
116
150
  - Nothing in the API is implemented by ts-r yet, so the "everything goes to your TypeScript"
117
151
  part of the parity rule holds for the API at all times.
118
152
 
153
+ ## Next.js
154
+
155
+ `next build` type-checks by running the `tsc` of the `typescript` package it resolves from your
156
+ project, so it uses the drop-in when the drop-in is installed in place of TypeScript. Next.js 16
157
+ runs `tsc --showConfig --project <tsconfig> --pretty false` (this goes to your TypeScript), then
158
+ `tsc --project <tsconfig> --noEmit --declarationMap false --emitDeclarationOnly false`, plus
159
+ `--tsBuildInfoFile .next/cache/.tsbuildinfo` for an `incremental` project (Next.js's default
160
+ tsconfig is). The drop-in takes that second command, so the check runs on ts-r-check once the
161
+ parity check passes, and on your TypeScript otherwise.
162
+
119
163
  ## Editors
120
164
 
121
165
  `typescript.tsdk` pointed at `node_modules/@ts-r.dev/typescript/lib` keeps the editor on your
@@ -126,6 +170,9 @@ applies the same parity rule per project.
126
170
  ## Limits
127
171
 
128
172
  - `tsc --build`, `--watch`, emitting builds and project references always run your TypeScript.
129
- - `incremental`/`composite` projects checked by ts-r-check don't update `.tsbuildinfo`.
173
+ - For `incremental`/`composite` projects ts-r-check writes a `.tsbuildinfo` in its own format at
174
+ the path tsc uses (`--tsBuildInfoFile`/`tsBuildInfoFile`, else tsc's default). tsc reads
175
+ that file as out of date and checks the whole project once, then writes its own; ts-r-check
176
+ does the same with tsc's, so switching between the two costs one full check each way.
130
177
  - tsserver plugins, TypeScript 5/6 as a library (typescript-eslint, ts-morph) need TypeScript
131
178
  5/6 installed under its own name, the same as with TypeScript 7 itself.
package/lib/tsc.cjs CHANGED
@@ -12,7 +12,11 @@ const { OWN, findRealTypeScript, findTsrCheck } = require('./real.cjs');
12
12
 
13
13
  const PREFIX = '@ts-r.dev/typescript:';
14
14
  // Flags that only print something: passed to TypeScript without a note.
15
- const INFO_FLAGS = new Set(['-v', '--version', '-h', '--help', '--all', '-?']);
15
+ const INFO_FLAGS = new Set(['-v', '--version', '-h', '--help', '--all', '-?', '--showconfig']);
16
+ // Emit options that do nothing when set to `false` under noEmit (Next.js's type check passes
17
+ // `--declarationMap false --emitDeclarationOnly false`). Only the `false` form is taken; any
18
+ // other value goes to TypeScript.
19
+ const EMIT_OFF_FLAGS = new Set(['-d', '--declaration', '--declarationmap', '--emitdeclarationonly', '--sourcemap', '--inlinesourcemap', '--inlinesources']);
16
20
 
17
21
  function note(msg) {
18
22
  if (!process.env.TS_R_TSC_QUIET) process.stderr.write(`${PREFIX} ${msg}\n`);
@@ -22,9 +26,13 @@ function verbose(msg) {
22
26
  if (process.env.TS_R_TSC_VERBOSE) process.stderr.write(`${PREFIX} ${msg}\n`);
23
27
  }
24
28
 
25
- /** tsc's command line, reduced to what ts-r-check supports. Option names are case-insensitive. */
29
+ /**
30
+ * tsc's command line, reduced to what ts-r-check supports. Option names are case-insensitive.
31
+ * `passed` holds the accepted options other than -p, --noEmit and --pretty, as given: both
32
+ * checkers get them, in the parity run and after it.
33
+ */
26
34
  function parseArgs(argv) {
27
- const r = { project: null, noEmit: null, pretty: null, unsupported: [] };
35
+ const r = { project: null, noEmit: null, pretty: null, passed: [], unsupported: [] };
28
36
  for (let i = 0; i < argv.length; i++) {
29
37
  const a = argv[i];
30
38
  const lower = a.toLowerCase();
@@ -43,6 +51,11 @@ function parseArgs(argv) {
43
51
  r.noEmit = bool();
44
52
  } else if (lower === '--pretty') {
45
53
  r.pretty = bool();
54
+ } else if (EMIT_OFF_FLAGS.has(lower) && argv[i + 1] === 'false') {
55
+ r.passed.push(a, argv[++i]);
56
+ } else if (lower === '--tsbuildinfofile' && i + 1 < argv.length) {
57
+ // Both checkers write their .tsbuildinfo there (each reads the other's as out of date).
58
+ r.passed.push(a, argv[++i]);
46
59
  } else {
47
60
  r.unsupported.push(a);
48
61
  }
@@ -161,11 +174,15 @@ function cacheRoot() {
161
174
  return path.join(os.homedir(), '.cache', 'ts-r');
162
175
  }
163
176
 
164
- /** Parity is cached per tsconfig (and what it extends), lockfile, TypeScript and ts-r-check. */
165
- function parityKey(config, configFiles, real, tsrCheck) {
177
+ /**
178
+ * Parity is cached per tsconfig (and what it extends), lockfile, TypeScript, ts-r-check and the
179
+ * options passed to both checkers.
180
+ */
181
+ function parityKey(config, configFiles, real, tsrCheck, args) {
166
182
  const h = crypto.createHash('sha256');
167
- h.update('parity-v1\0');
183
+ h.update('parity-v2\0');
168
184
  h.update(`${config}\0${real.version}\0${OWN.version}\0`);
185
+ h.update(`${JSON.stringify(checkArgs(args))}\0`);
169
186
  try {
170
187
  const st = fs.statSync(tsrCheck);
171
188
  h.update(`${st.size}\0${st.mtimeMs}\0`);
@@ -246,14 +263,24 @@ function runReal(real, argv, why) {
246
263
  }
247
264
 
248
265
  // `-p` exactly as given (or none: both tools then find the nearest tsconfig the same way), so
249
- // diagnostic paths come out relative to the working directory just like tsc's.
250
- function projectArgs(args) {
251
- return args.project !== null ? ['-p', args.project] : [];
266
+ // diagnostic paths come out relative to the working directory just like tsc's; then the other
267
+ // accepted options, as given.
268
+ function checkArgs(args) {
269
+ return [...(args.project !== null ? ['-p', args.project] : []), ...args.passed];
252
270
  }
253
271
 
254
- // ts-r-check doesn't read `pretty` from tsconfig, so the effective setting is always passed.
272
+ // The effective setting is always passed, so the parity run and later runs agree on it.
255
273
  function tsrArgs(args, pretty) {
256
- return [...projectArgs(args), '--noEmit', '--sound=off', '--pretty', String(pretty)];
274
+ return [...checkArgs(args), '--noEmit', '--sound=off', '--pretty', String(pretty)];
275
+ }
276
+
277
+ // tsc 7's default for --pretty, as observed: a non-empty NO_COLOR turns it off, else a non-empty
278
+ // FORCE_COLOR turns it on (Next.js sets FORCE_COLOR=1 when its own output is a terminal), else
279
+ // it follows whether stdout is a terminal. tsc 7 ignores `pretty` in tsconfig.
280
+ function defaultPretty(env = process.env, isTTY = process.stdout.isTTY) {
281
+ if (env.NO_COLOR) return false;
282
+ if (env.FORCE_COLOR) return true;
283
+ return Boolean(isTTY);
257
284
  }
258
285
 
259
286
  async function main() {
@@ -278,7 +305,7 @@ async function main() {
278
305
  const tsrCheck = findTsrCheck();
279
306
  if (!tsrCheck) return runReal(real, argv, `the ts-r-check binary for ${process.platform}-${process.arch} isn't installed`);
280
307
  const shownConfig = path.relative(process.cwd(), config) || config;
281
- const pretty = args.pretty !== null ? args.pretty : read.options.pretty === false ? false : Boolean(process.stdout.isTTY);
308
+ const pretty = args.pretty !== null ? args.pretty : defaultPretty();
282
309
  if (mode === 'ts-r') return run(tsrCheck, tsrArgs(args, pretty));
283
310
  if (!real) {
284
311
  note(`TypeScript wasn't found, so ${shownConfig} has no parity check; using ts-r-check.`);
@@ -286,7 +313,7 @@ async function main() {
286
313
  }
287
314
 
288
315
  const dir = path.join(cacheRoot(), 'typescript', 'parity');
289
- const key = parityKey(config, read.files, real, tsrCheck);
316
+ const key = parityKey(config, read.files, real, tsrCheck, args);
290
317
  const cacheFile = path.join(dir, `${key}.json`);
291
318
  let parity = null;
292
319
  try {
@@ -302,7 +329,7 @@ async function main() {
302
329
  }
303
330
 
304
331
  // First run: both checkers, side by side, in tsc's plain format; compare; remember.
305
- const plain = [...projectArgs(args), '--noEmit', '--pretty', 'false'];
332
+ const plain = [...checkArgs(args), '--noEmit', '--pretty', 'false'];
306
333
  const t0 = Date.now();
307
334
  const [ours, theirs] = await Promise.all([
308
335
  capture(tsrCheck, [...plain, '--sound=off']),
@@ -375,6 +402,6 @@ function cli() {
375
402
  });
376
403
  }
377
404
 
378
- module.exports = { cli, parseArgs, parseJsonc, diagnostics, multisetDiff, readConfig };
405
+ module.exports = { cli, parseArgs, parseJsonc, diagnostics, multisetDiff, readConfig, defaultPretty };
379
406
 
380
407
  if (require.main === module) cli();
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "@ts-r.dev/typescript",
3
- "version": "7.0.1000-alpha.3",
3
+ "version": "7.0.1000-alpha.5",
4
4
  "description": "Drop-in for the typescript package: tsc runs ts-r-check where it gives the same results as your TypeScript, and everything else goes to your TypeScript",
5
- "license": "MIT OR Apache-2.0",
5
+ "license": "MIT",
6
6
  "repository": {
7
7
  "type": "git",
8
8
  "url": "git+https://github.com/Webb-Ventures/typescript-rust.git",
@@ -22,7 +22,8 @@
22
22
  "files": [
23
23
  "bin",
24
24
  "lib",
25
- "README.md"
25
+ "README.md",
26
+ "LICENSE"
26
27
  ],
27
28
  "exports": {
28
29
  ".": {
@@ -79,13 +80,13 @@
79
80
  "node": ">=18"
80
81
  },
81
82
  "dependencies": {
82
- "@ts-r.dev/check": "0.1.0-alpha.3"
83
+ "@ts-r.dev/check": "0.1.0-alpha.5"
83
84
  },
84
85
  "peerDependencies": {
85
- "typescript": "^7.0.0"
86
+ "typescript": "^7.0.0 || 7.0.1000-alpha.5"
86
87
  },
87
88
  "ts-r": {
88
- "version": "0.1.0-alpha.3",
89
+ "version": "0.1.0-alpha.5",
89
90
  "typescript": "7.0.2"
90
91
  }
91
92
  }