tsc-ts 0.1.0 → 0.1.2

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 (81) hide show
  1. package/README.md +7 -1
  2. package/dist/api/compiler/ast.d.ts +15 -3
  3. package/dist/api/compiler/ast.js +36 -15
  4. package/dist/api/compiler/checker-classes.js +2 -1
  5. package/dist/api/compiler/checker-contextual.d.ts +20 -0
  6. package/dist/api/compiler/checker-contextual.js +111 -1
  7. package/dist/api/compiler/checker-expressions.js +14 -1
  8. package/dist/api/compiler/checker-grammar.d.ts +39 -4
  9. package/dist/api/compiler/checker-grammar.js +239 -75
  10. package/dist/api/compiler/checker-heritage.js +20 -14
  11. package/dist/api/compiler/checker-jsx.js +2 -1
  12. package/dist/api/compiler/checker-modules.js +4 -2
  13. package/dist/api/compiler/checker-source-file.js +1 -1
  14. package/dist/api/compiler/checker-type-factory.js +70 -19
  15. package/dist/api/compiler/checker-type-nodes.d.ts +1 -1
  16. package/dist/api/compiler/checker-type-nodes.js +5 -5
  17. package/dist/api/compiler/checker-unused.js +15 -10
  18. package/dist/api/compiler/checker.d.ts +7 -1
  19. package/dist/api/compiler/checker.js +14 -4
  20. package/dist/api/compiler/compile-program.d.ts +5 -0
  21. package/dist/api/compiler/compile-program.js +8 -0
  22. package/dist/api/compiler/expr-record.d.ts +11 -0
  23. package/dist/api/compiler/expr-record.js +53 -0
  24. package/dist/api/compiler/file-loader.d.ts +5 -0
  25. package/dist/api/compiler/file-loader.js +7 -0
  26. package/dist/api/compiler/identifier-name.d.ts +9 -0
  27. package/dist/api/compiler/identifier-name.js +10 -0
  28. package/dist/api/compiler/jsdoc.js +4 -2
  29. package/dist/api/compiler/parser.d.ts +2 -1
  30. package/dist/api/compiler/parser.js +10 -8
  31. package/dist/api/compiler/printer/factory.js +3 -2
  32. package/dist/api/compiler/printer/printer.js +3 -2
  33. package/dist/api/compiler/program-checker.d.ts +18 -0
  34. package/dist/api/compiler/program-checker.js +27 -0
  35. package/dist/api/compiler/reparser.js +4 -3
  36. package/dist/api/compiler/scanner.d.ts +8 -0
  37. package/dist/api/compiler/scanner.js +58 -42
  38. package/dist/api/compiler/shared-results.d.ts +376 -143
  39. package/dist/api/compiler/shared-results.js +1550 -773
  40. package/dist/api/compiler/transformers/declarations.js +2 -1
  41. package/package.json +15 -10
  42. package/src/compiler/ast.ts +39 -15
  43. package/src/compiler/cgroup.ts +157 -0
  44. package/src/compiler/checker-classes.ts +2 -1
  45. package/src/compiler/checker-contextual.ts +104 -0
  46. package/src/compiler/checker-expressions.ts +16 -1
  47. package/src/compiler/checker-grammar.ts +247 -88
  48. package/src/compiler/checker-heritage.ts +31 -17
  49. package/src/compiler/checker-jsx.ts +2 -1
  50. package/src/compiler/checker-modules.ts +4 -2
  51. package/src/compiler/checker-source-file.ts +1 -1
  52. package/src/compiler/checker-type-factory.ts +67 -21
  53. package/src/compiler/checker-type-nodes.ts +5 -5
  54. package/src/compiler/checker-unused.ts +13 -8
  55. package/src/compiler/checker.ts +15 -4
  56. package/src/compiler/compile-program.ts +8 -0
  57. package/src/compiler/decoder.ts +2 -1
  58. package/src/compiler/doctor-report.ts +133 -0
  59. package/src/compiler/expr-record.ts +59 -0
  60. package/src/compiler/file-loader.ts +8 -0
  61. package/src/compiler/identifier-name.ts +13 -0
  62. package/src/compiler/jsdoc.ts +4 -2
  63. package/src/compiler/parallel-check.ts +364 -146
  64. package/src/compiler/parallel-emit.ts +3 -3
  65. package/src/compiler/parse-thread.ts +24 -2
  66. package/src/compiler/parser.ts +10 -8
  67. package/src/compiler/printer/factory.ts +3 -2
  68. package/src/compiler/printer/printer.ts +4 -2
  69. package/src/compiler/program-checker.ts +28 -0
  70. package/src/compiler/reparser.ts +7 -3
  71. package/src/compiler/run-config.ts +1383 -0
  72. package/src/compiler/run-record-read.ts +87 -0
  73. package/src/compiler/run-records.ts +575 -0
  74. package/src/compiler/scanner.ts +57 -41
  75. package/src/compiler/shared-results.ts +1626 -896
  76. package/src/compiler/thread-entry.ts +3 -1
  77. package/src/compiler/transformers/declarations.ts +2 -1
  78. package/src/compiler/tsc-build.ts +64 -6
  79. package/src/compiler/tsc-cli.ts +33 -4
  80. package/src/compiler/tsc-compile.ts +223 -9
  81. package/src/compiler/tsc-watch.ts +25 -4
@@ -15,12 +15,12 @@
15
15
  * thread's checker finds every diagnostic but those of declaration emit.
16
16
  */
17
17
  import type { Worker } from 'node:worker_threads';
18
- import { availableParallelism } from 'node:os';
19
18
  import { publish } from '@scriptc/threads';
20
19
  import { lastNodeIdValue, type SourceFile } from './ast.js';
21
20
  import { JavaScriptEmitter, type OutputWriter } from './compile-program.js';
22
21
  import type { Diagnostic, DiagnosticFile } from './diagnostics.js';
23
22
  import { EmitOnly, EmitResult, sourceFileMayBeEmitted } from './emitter.js';
23
+ import { availableCpus } from './cgroup.js';
24
24
  import {
25
25
  CheckerResult,
26
26
  packResult,
@@ -78,7 +78,7 @@ export function emitThreads(
78
78
  emitKinds: readonly number[] | undefined = undefined,
79
79
  ): number {
80
80
  if (parallelEmit.spawn === undefined || singleThreaded === true) return 0;
81
- const cpus = availableParallelism();
81
+ const cpus = availableCpus();
82
82
  if (cpus < 2) return 0;
83
83
  const files = program.getSourceFiles();
84
84
  let text = 0;
@@ -220,7 +220,7 @@ const maxDeclarationThreadCheckers = 8;
220
220
  * from 1 to 8 checkers, about even at 12, and 32-38% slower at 16. It also needs a CPU of its own.
221
221
  */
222
222
  export function declarationThreadPays(checkers: number): boolean {
223
- return checkers <= maxDeclarationThreadCheckers && checkers < availableParallelism();
223
+ return checkers <= maxDeclarationThreadCheckers && checkers < availableCpus();
224
224
  }
225
225
 
226
226
  /**
@@ -6,10 +6,11 @@
6
6
  import { publish } from '@scriptc/threads';
7
7
  import { type ExternalModuleIndicatorOptions, ParseOptions, ScriptKind, type SourceFile } from './ast.js';
8
8
  import { bindSourceFile } from './binder.js';
9
+ import { checkGrammarSourceFileInParseThread } from './checker-grammar.js';
9
10
  import { useThreadTextCaches } from './diagnostics.js';
10
11
  import { CompilerHost, FileLoader } from './file-loader.js';
11
12
  import { computeHash } from './incremental.js';
12
- import { isIncremental } from './options.js';
13
+ import { type CompilerOptions, isIncremental } from './options.js';
13
14
  import type { FileSystem } from './file-system.js';
14
15
  import {
15
16
  fileSize,
@@ -29,6 +30,18 @@ class PreparingHost extends CompilerHost {
29
30
  prepared: PreparedFile[] = [];
30
31
  /** Whether the files' build info versions are computed (an incremental program). */
31
32
  computesVersions = false;
33
+ /**
34
+ * Whether the files the loader parses here run their grammar checks before they are published. The
35
+ * walk is the checker's, run off the checking threads (checker-grammar.ts).
36
+ */
37
+ grammarChecks = true;
38
+ /** The program's options, which the grammar checks of a file are given. */
39
+ readonly options: CompilerOptions;
40
+
41
+ constructor(fs: FileSystem, currentDirectory: string, defaultLibraryPath: string, options: CompilerOptions) {
42
+ super(fs, currentDirectory, defaultLibraryPath);
43
+ this.options = options;
44
+ }
32
45
  readMs = 0;
33
46
  parseMs = 0;
34
47
  bindMs = 0;
@@ -49,6 +62,12 @@ class PreparingHost extends CompilerHost {
49
62
  );
50
63
  const t2 = timeline ? performance.now() : 0;
51
64
  bindSourceFile(file);
65
+ // The checker does not check the declaration files `skipLibCheck` names, so it does not walk their
66
+ // grammar either. The walk reads the metadata the loader computed for the file, which is the one the
67
+ // checking thread reads it with, so it looks up no package.json the load has not looked up.
68
+ const metadata = this.loadingSourceFileMetadata;
69
+ if (this.grammarChecks && metadata !== undefined && !(this.options.skipLibCheck === true && file.isDeclarationFile))
70
+ checkGrammarSourceFileInParseThread(file, this.options, metadata);
52
71
  // Published now, while its nodes are in cache: the chunk's publish (`ParseThread.load`) then skips
53
72
  // them, where walking the whole chunk's files at once reads each node from memory again.
54
73
  publish(file);
@@ -85,11 +104,14 @@ export class ParseThread {
85
104
  private sentPackageJsons = 0;
86
105
 
87
106
  constructor(config: ParsedCommandLine, fs: FileSystem, currentDirectory: string, defaultLibraryPath: string) {
88
- this.host = new PreparingHost(fs, currentDirectory, defaultLibraryPath);
107
+ this.host = new PreparingHost(fs, currentDirectory, defaultLibraryPath, config.options);
89
108
  // The versions of an incremental program's files are computed here rather than one after another
90
109
  // on the main thread (programToSnapshot, incremental.ts).
91
110
  this.host.computesVersions = isIncremental(config.options);
92
111
  this.loader = new FileLoader(this.host, config);
112
+ // A program that does not check has no grammar diagnostics to report. An incremental program checks
113
+ // the files a change affects and parses all of them, so the walk stays with the checker there.
114
+ this.host.grammarChecks = config.options.noCheck !== true && !isIncremental(config.options);
93
115
  // The files this thread loads are published with their chunk: text caches it computes later (of
94
116
  // declaration files, which the parser leaves out) go to copies.
95
117
  useThreadTextCaches();
@@ -202,6 +202,7 @@ import {
202
202
  newCallExpression,
203
203
  newPropertyAssignment,
204
204
  } from './ast.js';
205
+ import { IdentifierName } from './identifier-name.js';
205
206
  import {
206
207
  OperatorPrecedence,
207
208
  canHaveDecorators,
@@ -3038,7 +3039,7 @@ export class Parser extends ScannerErrorReporter {
3038
3039
  identifierName = name;
3039
3040
  } else {
3040
3041
  this.parseErrorAt(skipTrivia(this.sourceText, name.pos), name.end, Diagnostics.Identifier_expected);
3041
- identifierName = this.newIdentifier('');
3042
+ identifierName = this.newIdentifier(new IdentifierName(''));
3042
3043
  this.finishNode(identifierName, name.pos);
3043
3044
  }
3044
3045
  return this.checkJSSyntax(this.finishNode(new ImportSpecifier(isTypeOnly, propertyName, identifierName), pos));
@@ -3559,12 +3560,12 @@ export class Parser extends ScannerErrorReporter {
3559
3560
  * A new identifier of the class `use` calls for. Callers create it after the identifier's token, so
3560
3561
  * for an element name the current token tells a shorthand property from an assignment or a method.
3561
3562
  */
3562
- newIdentifier(text: string, use: IdentifierUse = IdentifierUse.Reference): Identifier {
3563
+ newIdentifier(name: IdentifierName, use: IdentifierUse = IdentifierUse.Reference): Identifier {
3563
3564
  this.identifierCount++;
3564
- if (text === 'await') this.statementHasAwaitIdentifier = true;
3565
+ if (name.text === 'await') this.statementHasAwaitIdentifier = true;
3565
3566
  if (use === IdentifierUse.Name || (use === IdentifierUse.ElementName && this.isElementNameEnd()))
3566
- return new Identifier(text);
3567
- return new ReferenceIdentifier(text);
3567
+ return new Identifier(name);
3568
+ return new ReferenceIdentifier(name);
3568
3569
  }
3569
3570
 
3570
3571
  /** Whether the current token ends an object literal element name that is not a shorthand property. */
@@ -3574,7 +3575,7 @@ export class Parser extends ScannerErrorReporter {
3574
3575
  }
3575
3576
 
3576
3577
  createMissingIdentifier(use: IdentifierUse = IdentifierUse.Reference): Identifier {
3577
- const result = this.newIdentifier('', use);
3578
+ const result = this.newIdentifier(new IdentifierName(''), use);
3578
3579
  this.finishNode(result, this.nodePos());
3579
3580
  return result;
3580
3581
  }
@@ -4971,7 +4972,7 @@ export class Parser extends ScannerErrorReporter {
4971
4972
  // An unclosed opening element took its parent's closing element: restructure
4972
4973
  // (<div>(...<span>...</div>)) into (<div>(...<span>...</>)</div>). The parent reports it.
4973
4974
  const end = (lastChild as JsxElement).children.end;
4974
- const missingIdentifier = this.finishNodeWithEnd(this.newIdentifier(''), end, end);
4975
+ const missingIdentifier = this.finishNodeWithEnd(this.newIdentifier(new IdentifierName('')), end, end);
4975
4976
  const newClosingElement = new JsxClosingElement(missingIdentifier);
4976
4977
  this.finishNodeWithEnd(newClosingElement, end, end);
4977
4978
  const newLast = new JsxElement(
@@ -6091,10 +6092,11 @@ export class Parser extends ScannerErrorReporter {
6091
6092
  if (isIdentifier) {
6092
6093
  const pos = this.scanner.hasPrecedingJSDocLeadingAsterisks() ? this.scanner.getTokenStart() : this.nodePos();
6093
6094
  const text = this.scanner.getIdentifierValue();
6095
+ const name = this.scanner.getIdentifierName();
6094
6096
  const record = this.scanner.recordIdentifierValue(text);
6095
6097
  this.nextTokenWithoutCheck();
6096
6098
  if (record) this.identifierTexts.push(text);
6097
- const result = this.newIdentifier(text, use);
6099
+ const result = this.newIdentifier(name, use);
6098
6100
  this.finishNode(result, pos);
6099
6101
  return result;
6100
6102
  }
@@ -70,6 +70,7 @@ import {
70
70
  } from './helpers.js';
71
71
  import { formatGeneratedName, isMemberName, nodeIsSynthesized } from './utilities.js';
72
72
  import { OuterExpressionKinds, isOuterExpression, outerExpressionOperand } from '../transformers/utilities.js';
73
+ import { IdentifierName } from '../identifier-name.js';
73
74
 
74
75
  /**
75
76
  * The node factory of an emit context. The context is the factory (`EmitContext` extends it), so the two are one
@@ -108,7 +109,7 @@ export abstract class NodeFactory extends NodeFactoryBase {
108
109
  }
109
110
 
110
111
  cloneIdentifier(node: Identifier): Identifier {
111
- return this.cloneNode(node, new Identifier(node.text));
112
+ return this.cloneNode(node, new Identifier(node.identifierName));
112
113
  }
113
114
 
114
115
  createNodeList(nodes: Node[]): NodeList {
@@ -132,7 +133,7 @@ export abstract class NodeFactory extends NodeFactoryBase {
132
133
  }
133
134
 
134
135
  createIdentifier(text: string): Identifier {
135
- return this.created(new Identifier(text));
136
+ return this.created(new Identifier(new IdentifierName(text)));
136
137
  }
137
138
 
138
139
  createKeywordExpression(kind: SyntaxKind): KeywordExpression {
@@ -660,7 +660,8 @@ export class Printer extends NameGeneratorHost {
660
660
  case SyntaxKind.PrivateIdentifier:
661
661
  case SyntaxKind.JsxNamespacedName:
662
662
  // Its text either way: the source text, or the text of a node from elsewhere.
663
- if (this.textIsSourceText(node)) return (node as Identifier | PrivateIdentifier).text;
663
+ if (this.textIsSourceText(node))
664
+ return node instanceof Identifier ? node.text : (node as PrivateIdentifier).text;
664
665
  if (!canUseSourceFile || !this.isInCurrentSourceFile(node)) {
665
666
  if (node instanceof Identifier) return node.text;
666
667
  if (node instanceof PrivateIdentifier) return node.text;
@@ -691,7 +692,8 @@ export class Printer extends NameGeneratorHost {
691
692
  if (!(node instanceof Identifier) && !(node instanceof PrivateIdentifier)) return false;
692
693
  if ((node.flags & (NodeFlags.Reparsed | NodeFlags.JSDoc | NodeFlags.ReparserTransformedLiteral)) !== 0)
693
694
  return false;
694
- const text = node.text;
695
+ // Natively an identifier's text is read through its name, and a private identifier's from its field.
696
+ const text = node instanceof Identifier ? node.text : (node as PrivateIdentifier).text;
695
697
  const source = this.sourceText;
696
698
  const end = node.end;
697
699
  const start = end - text.length;
@@ -248,6 +248,28 @@ export class CheckedProgram {
248
248
  this.reportingChecker = undefined;
249
249
  }
250
250
 
251
+ /** Adds the counts a checker thread sent (`CheckerResult.counts`): types, instantiations, symbols. */
252
+ addCheckerCounts(counts: readonly number[]): void {
253
+ if (counts.length < 3) return;
254
+ this.threadTypeCount += counts[0]!;
255
+ this.threadInstantiations += counts[1]!;
256
+ this.threadSymbolCount += counts[2]!;
257
+ }
258
+
259
+ /**
260
+ * The types, instantiations and transient symbols of every checker of the program: this thread's and
261
+ * the checker threads', as tsgo's `Program.TypeCount`, `InstantiationCount` and `SymbolCount` add them up.
262
+ * Reading them doesn't create this thread's checker.
263
+ */
264
+ checkerCounts(): { types: number; instantiations: number; symbols: number } {
265
+ const own = this.reportingChecker;
266
+ return {
267
+ types: (own === undefined ? 0 : own.typeCount) + this.threadTypeCount,
268
+ instantiations: (own === undefined ? 0 : own.totalInstantiations) + this.threadInstantiations,
269
+ symbols: (own === undefined ? 0 : own.symbolCount) + this.threadSymbolCount,
270
+ };
271
+ }
272
+
251
273
  getBindDiagnostics(file: SourceFile | undefined): Diagnostic[] {
252
274
  return this.collect(file, (f) => f.bindDiagnostics);
253
275
  }
@@ -272,6 +294,12 @@ export class CheckedProgram {
272
294
  */
273
295
  referenceThreads = 1;
274
296
  readonly parallelGlobalDiagnostics: Diagnostic[] = [];
297
+ /** The types checker threads created (`CheckerResult.counts`), which `--diagnostics` adds to `checker`'s. */
298
+ threadTypeCount = 0;
299
+ /** The instantiations checker threads made. */
300
+ threadInstantiations = 0;
301
+ /** The transient symbols checker threads created. */
302
+ threadSymbolCount = 0;
275
303
  /**
276
304
  * Whether the semantic diagnostics of a file include the global diagnostics its checker found while
277
305
  * checking it, as an incremental program caches them (IncrementalProgram). Such a program doesn't report
@@ -98,6 +98,7 @@ import { Diagnostics } from './diagnostic-messages.js';
98
98
  import type { Parser } from './parser.js';
99
99
  import { SyntaxKind } from './syntax-kind.js';
100
100
  import { TokenFlags } from './types.js';
101
+ import { IdentifierName } from './identifier-name.js';
101
102
 
102
103
  /** Sets the parent of every node in a subtree. */
103
104
  class ParentInChildrenSetter extends NodeVisitor {
@@ -360,7 +361,7 @@ export class Reparser {
360
361
  const param = params[pi]!;
361
362
  let parameter: ParameterDeclaration;
362
363
  if (param instanceof JSDocThisTag) {
363
- const thisIdent = new Identifier('this');
364
+ const thisIdent = new Identifier(new IdentifierName('this'));
364
365
  thisIdent.pos = (param as JSDocThisTag).pos;
365
366
  thisIdent.end = (param as JSDocThisTag).end;
366
367
  thisIdent.flags = p.contextFlags | NodeFlags.Reparsed;
@@ -387,7 +388,10 @@ export class Reparser {
387
388
  let name: Node = (param as JSDocParameterOrPropertyTag).name;
388
389
  if (name instanceof Identifier && !isValidIdentifier((name as Identifier).text)) {
389
390
  // Replace invalid characters with `_`, or use `_N` for an empty name, for a valid parameter name.
390
- name = this.addTransformedReparse(new Identifier(sanitizeIdentifier((name as Identifier).text, pi)), name);
391
+ name = this.addTransformedReparse(
392
+ new Identifier(new IdentifierName(sanitizeIdentifier((name as Identifier).text, pi))),
393
+ name,
394
+ );
391
395
  } else {
392
396
  name = this.addDeepCloneReparse(name);
393
397
  }
@@ -611,7 +615,7 @@ export class Reparser {
611
615
  const thisParam = new ParameterDeclaration(
612
616
  undefined,
613
617
  undefined,
614
- new Identifier('this'),
618
+ new Identifier(new IdentifierName('this')),
615
619
  undefined,
616
620
  undefined,
617
621
  undefined,