tsc-ts 0.1.0 → 0.1.1

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 (60) hide show
  1. package/README.md +1 -1
  2. package/dist/api/compiler/ast.d.ts +9 -3
  3. package/dist/api/compiler/ast.js +17 -12
  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-jsx.js +2 -1
  9. package/dist/api/compiler/checker-type-factory.js +53 -12
  10. package/dist/api/compiler/checker.d.ts +5 -1
  11. package/dist/api/compiler/checker.js +10 -4
  12. package/dist/api/compiler/compile-program.d.ts +5 -0
  13. package/dist/api/compiler/compile-program.js +8 -0
  14. package/dist/api/compiler/expr-record.d.ts +11 -0
  15. package/dist/api/compiler/expr-record.js +53 -0
  16. package/dist/api/compiler/identifier-name.d.ts +9 -0
  17. package/dist/api/compiler/identifier-name.js +10 -0
  18. package/dist/api/compiler/jsdoc.js +4 -2
  19. package/dist/api/compiler/parser.d.ts +2 -1
  20. package/dist/api/compiler/parser.js +10 -8
  21. package/dist/api/compiler/printer/factory.js +3 -2
  22. package/dist/api/compiler/printer/printer.js +3 -2
  23. package/dist/api/compiler/reparser.js +4 -3
  24. package/dist/api/compiler/scanner.d.ts +8 -0
  25. package/dist/api/compiler/scanner.js +58 -42
  26. package/dist/api/compiler/shared-results.d.ts +376 -143
  27. package/dist/api/compiler/shared-results.js +1550 -773
  28. package/dist/api/compiler/transformers/declarations.js +2 -1
  29. package/package.json +9 -9
  30. package/src/compiler/ast.ts +19 -12
  31. package/src/compiler/cgroup.ts +157 -0
  32. package/src/compiler/checker-classes.ts +2 -1
  33. package/src/compiler/checker-contextual.ts +104 -0
  34. package/src/compiler/checker-expressions.ts +16 -1
  35. package/src/compiler/checker-jsx.ts +2 -1
  36. package/src/compiler/checker-type-factory.ts +53 -14
  37. package/src/compiler/checker.ts +11 -4
  38. package/src/compiler/compile-program.ts +8 -0
  39. package/src/compiler/decoder.ts +2 -1
  40. package/src/compiler/doctor-report.ts +133 -0
  41. package/src/compiler/expr-record.ts +59 -0
  42. package/src/compiler/identifier-name.ts +13 -0
  43. package/src/compiler/jsdoc.ts +4 -2
  44. package/src/compiler/parallel-check.ts +353 -146
  45. package/src/compiler/parallel-emit.ts +3 -3
  46. package/src/compiler/parser.ts +10 -8
  47. package/src/compiler/printer/factory.ts +3 -2
  48. package/src/compiler/printer/printer.ts +4 -2
  49. package/src/compiler/reparser.ts +7 -3
  50. package/src/compiler/run-config.ts +1383 -0
  51. package/src/compiler/run-record-read.ts +87 -0
  52. package/src/compiler/run-records.ts +575 -0
  53. package/src/compiler/scanner.ts +57 -41
  54. package/src/compiler/shared-results.ts +1626 -896
  55. package/src/compiler/thread-entry.ts +3 -1
  56. package/src/compiler/transformers/declarations.ts +2 -1
  57. package/src/compiler/tsc-build.ts +64 -6
  58. package/src/compiler/tsc-cli.ts +33 -4
  59. package/src/compiler/tsc-compile.ts +213 -8
  60. package/src/compiler/tsc-watch.ts +25 -4
@@ -201,6 +201,7 @@ import {
201
201
  import { modifiersToFlags } from './ast-utilities.js';
202
202
  import { protocolVersion } from './encoder.js';
203
203
  import { SyntaxKind } from './syntax-kind.js';
204
+ import { IdentifierName } from './identifier-name.js';
204
205
 
205
206
  const nodeSize = 28;
206
207
  const headerSize = 64;
@@ -354,7 +355,7 @@ class Decoder {
354
355
  createString(kind: SyntaxKind, text: string, common: number): Node {
355
356
  switch (kind) {
356
357
  case SyntaxKind.Identifier:
357
- return new Identifier(text);
358
+ return new Identifier(new IdentifierName(text));
358
359
  case SyntaxKind.PrivateIdentifier:
359
360
  return new PrivateIdentifier(text);
360
361
  case SyntaxKind.JsxText:
@@ -0,0 +1,133 @@
1
+ /**
2
+ * The report a `tsc-ts doctor` child writes: `TSC_TS_DOCTOR_REPORT` names a file, and `main.ts` writes
3
+ * what the child's compile measured to it before the process exits. The doctor process reads the file
4
+ * after the child exits; its own runs are unaffected, since nothing here is set for them.
5
+ *
6
+ * The parent times the child and compares its diagnostic output itself, so the report carries what only
7
+ * the child knows: the phase times, the program's shape, the signals, the run's configuration and the
8
+ * key the run's record would have.
9
+ */
10
+ import { writeFileSync } from 'node:fs';
11
+ import { residentMB } from './parallel-check.js';
12
+
13
+ /** The report path, or `undefined` when this process is not a doctor child. */
14
+ export function doctorReportPath(): string | undefined {
15
+ const path = process.env.TSC_TS_DOCTOR_REPORT;
16
+ return path === undefined || path === '' ? undefined : path;
17
+ }
18
+
19
+ /** What a bound program showed about the cost of checking it (`CheckSignals`), as the report keeps it. */
20
+ export interface DoctorSignals {
21
+ count: number;
22
+ ranges: number;
23
+ library: number;
24
+ own: number;
25
+ redundancy: number;
26
+ declarationShare: number;
27
+ nodeModulesShare: number;
28
+ fileShare: number;
29
+ }
30
+
31
+ /** The program's size, as a run record keeps it. */
32
+ export interface DoctorShape {
33
+ files: number;
34
+ chars: number;
35
+ declarationChars: number;
36
+ checkChars: number;
37
+ }
38
+
39
+ /** The phase times of a compile, in milliseconds (`CompileTimes`). */
40
+ export interface DoctorTimes {
41
+ parseMs: number;
42
+ checkMs: number;
43
+ totalMs: number;
44
+ }
45
+
46
+ /** What this child's compile measured. */
47
+ export interface DoctorCompile {
48
+ /** The version the executable reports (`help.ts`). */
49
+ version: string;
50
+ /** The project's config file, or `undefined` for root files on the command line. */
51
+ configFile: string | undefined;
52
+ /** The key a record of this run would have (`run-records.ts`). */
53
+ key: string;
54
+ checkers: number;
55
+ share: boolean;
56
+ parseThreads: number;
57
+ times: DoctorTimes;
58
+ shape: DoctorShape;
59
+ signals: DoctorSignals | undefined;
60
+ }
61
+
62
+ /**
63
+ * What the file holds: the compile the child measured, where it measured one, plus the exit status,
64
+ * the CPU time and the peak memory. A child that never compiled writes only the last three.
65
+ */
66
+ export interface DoctorReport {
67
+ version?: string;
68
+ configFile?: string;
69
+ key?: string;
70
+ checkers?: number;
71
+ share?: boolean;
72
+ parseThreads?: number;
73
+ times?: DoctorTimes;
74
+ shape?: DoctorShape;
75
+ signals?: DoctorSignals;
76
+ status: number;
77
+ cpuMs: number;
78
+ peakMB: number;
79
+ }
80
+
81
+ /** The report the process writes, once its compile measured something. */
82
+ let pending: DoctorCompile | undefined;
83
+
84
+ /** Records what this child's compile measured; `main.ts` writes it before the process exits. */
85
+ export function setDoctorCompile(compile: DoctorCompile): void {
86
+ pending = compile;
87
+ }
88
+
89
+ /**
90
+ * Exits with `status`, writing the doctor report first where `TSC_TS_DOCTOR_REPORT` names a file. The
91
+ * compile's exits go through here: the thread drivers in `node-system.ts` exit from their callbacks,
92
+ * without returning to `main.ts`.
93
+ */
94
+ export function exitWithDoctorReport(status: number): never {
95
+ if (doctorReportPath() !== undefined) {
96
+ const cpu = process.cpuUsage();
97
+ writeDoctorReport(status, (cpu.user + cpu.system) / 1000);
98
+ }
99
+ return process.exit(status);
100
+ }
101
+
102
+ /**
103
+ * Writes the report to the file `TSC_TS_DOCTOR_REPORT` names, with the exit status, the CPU time and the
104
+ * peak memory read at exit. Never throws: a report that cannot be written leaves the parent to time the
105
+ * child without one.
106
+ */
107
+ export function writeDoctorReport(status: number, cpuMs: number): void {
108
+ const path = doctorReportPath();
109
+ if (path === undefined) return;
110
+ const compile = pending;
111
+ const report: DoctorReport =
112
+ compile === undefined
113
+ ? { status, cpuMs, peakMB: residentMB()[1] }
114
+ : {
115
+ version: compile.version,
116
+ configFile: compile.configFile,
117
+ key: compile.key,
118
+ checkers: compile.checkers,
119
+ share: compile.share,
120
+ parseThreads: compile.parseThreads,
121
+ times: compile.times,
122
+ shape: compile.shape,
123
+ signals: compile.signals,
124
+ status,
125
+ cpuMs,
126
+ peakMB: residentMB()[1],
127
+ };
128
+ try {
129
+ writeFileSync(path, JSON.stringify(report) + '\n');
130
+ } catch {
131
+ // The parent reports the run without a report file.
132
+ }
133
+ }
@@ -0,0 +1,59 @@
1
+ // The type the last completed check of an expression produced, by node and check mode, for the
2
+ // expressions that are checked with no contextual type.
3
+ //
4
+ // The checker checks some expressions more than once with the same inputs: a body that the eager
5
+ // pass reached and the deferred pass reaches again, a node re-checked after a loop body, an
6
+ // argument of a second inference round. A check is a function of the node, the check mode and the
7
+ // checker's state, and the state only grows while the checker runs, so a check that completed
8
+ // earlier answers the next check of the same node: the later check would produce the type the
9
+ // earlier one produced, report the diagnostics it reported and defer the nodes it deferred.
10
+ //
11
+ // A contextual type is part of the inputs, so the record can only serve an expression whose check
12
+ // has none: the checker-contextual predicate says so before the record is consulted, and a check
13
+ // under a contextual type never reads or writes the record. For the same reason the record is not
14
+ // consulted while an inference context is in force: what the check infers into depends on it.
15
+ //
16
+ // The record is a direct-mapped table that stores the key beside the value, so a lookup that lands
17
+ // on another node reads the entry as a miss. Its size bounds the memory and the cache the lookups
18
+ // use: an entry is a node id, a mode and a type slot, the whole table takes about 200 KB, and 2^14
19
+ // entries serve nearly all repeats (2^14 against 2^20 loses 0.1% of the check on the largest
20
+ // program measured).
21
+
22
+ import type { Type } from './checker-types.js';
23
+
24
+ /** Entries in the record; a power of two. */
25
+ const EntryCount = 1 << 14;
26
+ const EntryMask = EntryCount - 1;
27
+
28
+ /** The types by entry; a slot holds the type of the check recorded at that entry. */
29
+ function newTypeSlots(): (Type | undefined)[] {
30
+ const slots: (Type | undefined)[] = [];
31
+ for (let i = 0; i < EntryCount; i++) slots.push(undefined);
32
+ return slots;
33
+ }
34
+
35
+ function entryOf(nodeId: number, mode: number): number {
36
+ return (Math.imul(nodeId, 0x9e3779b1) ^ mode) & EntryMask;
37
+ }
38
+
39
+ export class ExprCheckRecord {
40
+ /** The node id of the check at each entry, plus one; zero where no check is recorded. */
41
+ private readonly nodeIds = new Int32Array(EntryCount);
42
+ private readonly modes = new Uint8Array(EntryCount);
43
+ private readonly types = newTypeSlots();
44
+
45
+ /** The type the last completed check of the node under `mode` produced, if the entry holds it. */
46
+ get(nodeId: number, mode: number): Type | undefined {
47
+ const entry = entryOf(nodeId, mode);
48
+ if (this.nodeIds[entry] !== nodeId + 1 || this.modes[entry] !== mode) return undefined;
49
+ return this.types[entry];
50
+ }
51
+
52
+ /** Records that a check of the node under `mode` produced `type`. */
53
+ set(nodeId: number, mode: number, type: Type): void {
54
+ const entry = entryOf(nodeId, mode);
55
+ this.nodeIds[entry] = nodeId + 1;
56
+ this.modes[entry] = mode;
57
+ this.types[entry] = type;
58
+ }
59
+ }
@@ -0,0 +1,13 @@
1
+ import type { ProgramLifetime } from '@scriptc/types';
2
+
3
+ /**
4
+ * The text of an identifier. The identifiers a parser's scanner interns with the same text share one
5
+ * (scanner.ts `IdentifierTable`), and natively an identifier refers to it in 4 bytes.
6
+ */
7
+ export class IdentifierName implements ProgramLifetime {
8
+ readonly text: string;
9
+
10
+ constructor(text: string) {
11
+ this.text = text;
12
+ }
13
+ }
@@ -57,6 +57,7 @@ import { Reparser } from './reparser.js';
57
57
  import { getLeadingCommentRanges, getTrailingCommentRanges } from './scanner.js';
58
58
  import { SyntaxKind } from './syntax-kind.js';
59
59
  import type { CommentRange } from './types.js';
60
+ import { IdentifierName } from './identifier-name.js';
60
61
 
61
62
  const enum JSDocState {
62
63
  BeginningOfLine,
@@ -1230,16 +1231,17 @@ export class JSDocParser {
1230
1231
  p.parseErrorAtCurrentToken(Diagnostics.Identifier_expected_0_is_a_reserved_word_that_cannot_be_used_here, [
1231
1232
  p.scanner.getTokenText(),
1232
1233
  ]);
1233
- const missing = p.newIdentifier('');
1234
+ const missing = p.newIdentifier(new IdentifierName(''));
1234
1235
  p.finishNode(missing, p.nodePos());
1235
1236
  return missing;
1236
1237
  }
1237
1238
  const pos = p.scanner.getTokenStart();
1238
1239
  const end = p.scanner.getTokenEnd();
1239
1240
  const text = p.scanner.getIdentifierValue();
1241
+ const name = p.scanner.getIdentifierName();
1240
1242
  p.internIdentifier(text);
1241
1243
  p.nextTokenJSDoc();
1242
- const result = p.newIdentifier(text);
1244
+ const result = p.newIdentifier(name);
1243
1245
  p.finishNodeWithEnd(result, pos, end);
1244
1246
  return result;
1245
1247
  }