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
@@ -7,6 +7,7 @@ import { isWhiteSpaceLike } from './character-codes.js';
7
7
  import { Diagnostic } from './diagnostics.js';
8
8
  import { Reparser } from './reparser.js';
9
9
  import { getLeadingCommentRanges, getTrailingCommentRanges } from './scanner.js';
10
+ import { IdentifierName } from './identifier-name.js';
10
11
  /** Comment text collected while parsing, with the indentation it has reached. */
11
12
  class CommentText {
12
13
  parts = [];
@@ -1076,16 +1077,17 @@ export class JSDocParser {
1076
1077
  p.parseErrorAtCurrentToken(293 /* Diagnostics.Identifier_expected_0_is_a_reserved_word_that_cannot_be_used_here */, [
1077
1078
  p.scanner.getTokenText(),
1078
1079
  ]);
1079
- const missing = p.newIdentifier('');
1080
+ const missing = p.newIdentifier(new IdentifierName(''));
1080
1081
  p.finishNode(missing, p.nodePos());
1081
1082
  return missing;
1082
1083
  }
1083
1084
  const pos = p.scanner.getTokenStart();
1084
1085
  const end = p.scanner.getTokenEnd();
1085
1086
  const text = p.scanner.getIdentifierValue();
1087
+ const name = p.scanner.getIdentifierName();
1086
1088
  p.internIdentifier(text);
1087
1089
  p.nextTokenJSDoc();
1088
- const result = p.newIdentifier(text);
1090
+ const result = p.newIdentifier(name);
1089
1091
  p.finishNodeWithEnd(result, pos, end);
1090
1092
  return result;
1091
1093
  }
@@ -1,4 +1,5 @@
1
1
  import { Block, CaseBlock, CatchClause, ExternalModuleIndicatorOptions, Identifier, ImportAttributes, ImportClause, JsxAttributes, JsxClosingElement, JsxClosingFragment, JsxOpeningElement, ModifierList, Node, NodeFlags, NodeList, ObjectLiteralExpression, ParseOptions, ScriptKind, SourceFile, TemplateHead, TemplateLiteralTypeSpan, TemplateSpan, ThisTypeNode, Token, Tristate, TypeParameterDeclaration, VariableDeclaration, VariableDeclarationList, type EntityName, type Expression, type Statement, type TypeNode } from './ast.js';
2
+ import { IdentifierName } from './identifier-name.js';
2
3
  import { OperatorPrecedence } from './ast-utilities.js';
3
4
  import { Diagnostic, type DiagnosticMessage } from './diagnostics.js';
4
5
  import { JSDocParser } from './jsdoc.js';
@@ -385,7 +386,7 @@ export declare class Parser extends ScannerErrorReporter {
385
386
  * A new identifier of the class `use` calls for. Callers create it after the identifier's token, so
386
387
  * for an element name the current token tells a shorthand property from an assignment or a method.
387
388
  */
388
- newIdentifier(text: string, use?: IdentifierUse): Identifier;
389
+ newIdentifier(name: IdentifierName, use?: IdentifierUse): Identifier;
389
390
  /** Whether the current token ends an object literal element name that is not a shorthand property. */
390
391
  isElementNameEnd(): boolean;
391
392
  createMissingIdentifier(use?: IdentifierUse): Identifier;
@@ -6,6 +6,7 @@
6
6
  // for (const statement of file.statements.nodes) console.log(statement.kind);
7
7
  // ```
8
8
  import { appendToList, ArrayLiteralExpression, ArrayTypeNode, ArrowFunction, AsExpression, AwaitExpression, BigIntLiteral, BinaryExpression, BindingElement, BindingPattern, Block, BreakStatement, CallExpression, CallSignatureDeclaration, CaseBlock, CaseOrDefaultClause, CatchClause, CheckJsDirective, ClassDeclaration, ClassExpression, ClassStaticBlockDeclaration, ComputedPropertyName, ConditionalExpression, ConditionalTypeNode, ConstructSignatureDeclaration, ConstructorDeclaration, ConstructorTypeNode, ContinueStatement, DebuggerStatement, Decorator, DeleteExpression, DoStatement, ElementAccessExpression, emptyCommentDirectives, emptyDiagnostics, emptyFileReferences, emptyNodes, emptyPragmas, EmptyStatement, EnumDeclaration, EnumMember, ExportAssignment, ExportDeclaration, ExportSpecifier, ExpressionStatement, ExpressionWithTypeArguments, ExternalModuleIndicatorOptions, ExternalModuleReference, FileReference, ForInOrOfStatement, ForStatement, FunctionDeclaration, FunctionExpression, FunctionTypeNode, GetAccessorDeclaration, HeritageClause, Identifier, IfStatement, ImportAttribute, ImportAttributes, ImportClause, ImportDeclaration, ImportEqualsDeclaration, ImportSpecifier, ImportTypeNode, IndexSignatureDeclaration, IndexedAccessTypeNode, InferTypeNode, InterfaceDeclaration, IntersectionTypeNode, JSDocAllType, JSDocNonNullableType, JSDocNullableType, JSDocOptionalType, JSDocVariadicType, JsxAttribute, JsxAttributes, JsxClosingElement, JsxClosingFragment, JsxElement, JsxExpression, JsxFragment, JsxNamespacedName, JsxOpeningElement, JsxOpeningFragment, JsxSelfClosingElement, JsxSpreadAttribute, JsxText, KeywordExpression, KeywordTypeNode, LabeledStatement, LiteralTypeNode, MappedTypeNode, MetaProperty, MethodDeclaration, MethodSignatureDeclaration, MissingDeclaration, MissingNodeList, ModifierList, ModuleBlock, ModuleDeclaration, NamedExports, NamedImports, NamedTupleMember, NamespaceExport, NamespaceExportDeclaration, NamespaceImport, NewExpression, NoSubstitutionTemplateLiteral, NodeList, NodeVisitor, NonNullExpression, NumericLiteral, ObjectLiteralExpression, OmittedExpression, OptionalTypeNode, ParameterDeclaration, ParenthesizedExpression, ParenthesizedTypeNode, PostfixUnaryExpression, Pragma, PragmaArgument, PrefixUnaryExpression, PrivateIdentifier, PropertyAccessExpression, PropertyAssignment, PropertyDeclaration, PropertySignatureDeclaration, QualifiedName, ReferenceIdentifier, RegularExpressionLiteral, RestTypeNode, ReturnStatement, SatisfiesExpression, SemicolonClassElement, SetAccessorDeclaration, ShorthandPropertyAssignment, SourceFile, SpreadAssignment, SpreadElement, StringLiteral, SwitchStatement, TaggedTemplateExpression, TemplateExpression, TemplateHead, TemplateLiteralTypeNode, TemplateLiteralTypeSpan, TemplateMiddle, TemplateSpan, TemplateTail, ThisTypeNode, ThrowStatement, Token, TryStatement, TupleTypeNode, TypeAliasDeclaration, TypeAssertion, TypeLiteralNode, TypeOfExpression, TypeOperatorNode, TypeParameterDeclaration, TypePredicateNode, TypeQueryNode, TypeReferenceNode, UnionTypeNode, VariableDeclaration, VariableDeclarationList, VariableStatement, VoidExpression, WhileStatement, WithStatement, YieldExpression, getBody, getIsTypeOnly, getModifiers, getName, getPostfixToken, getQuestionToken, getStatements, getText, getType, getTypeArguments, getTypeParameters, newCallExpression, newPropertyAssignment, } from './ast.js';
9
+ import { IdentifierName } from './identifier-name.js';
9
10
  import { canHaveDecorators, canHaveIllegalDecorators, compareNodePositions, getBinaryOperatorPrecedence, getExternalModuleName, getImportTypeNodeLiteral, getTextOfNodeFromSourceText, isAmbientModule, isAnyImportOrReExport, isAssignmentOperator, isClassMemberModifier, isFunctionLike, isImportCall, isImportMeta, isImportPhaseMetaProperty, isInJSFile, isKeyword, isKeywordOrPunctuation, isLeftHandSideExpression, isModifierKind, isRequireCall, isReservedWord, isStringLiteralLike, modifierToFlag, modifiersToFlags, nodeIsMissing, nodeIsPresent, tagNamesAreEquivalent, tokenIsIdentifierOrKeyword, tokenIsIdentifierOrKeywordOrGreaterThan, } from './ast-utilities.js';
10
11
  import { isLineBreak } from './character-codes.js';
11
12
  import { Diagnostic, messageCode } from './diagnostics.js';
@@ -2308,7 +2309,7 @@ export class Parser extends ScannerErrorReporter {
2308
2309
  }
2309
2310
  else {
2310
2311
  this.parseErrorAt(skipTrivia(this.sourceText, name.pos), name.end, 1 /* Diagnostics.Identifier_expected */);
2311
- identifierName = this.newIdentifier('');
2312
+ identifierName = this.newIdentifier(new IdentifierName(''));
2312
2313
  this.finishNode(identifierName, name.pos);
2313
2314
  }
2314
2315
  return this.checkJSSyntax(this.finishNode(new ImportSpecifier(isTypeOnly, propertyName, identifierName), pos));
@@ -2758,13 +2759,13 @@ export class Parser extends ScannerErrorReporter {
2758
2759
  * A new identifier of the class `use` calls for. Callers create it after the identifier's token, so
2759
2760
  * for an element name the current token tells a shorthand property from an assignment or a method.
2760
2761
  */
2761
- newIdentifier(text, use = 0 /* IdentifierUse.Reference */) {
2762
+ newIdentifier(name, use = 0 /* IdentifierUse.Reference */) {
2762
2763
  this.identifierCount++;
2763
- if (text === 'await')
2764
+ if (name.text === 'await')
2764
2765
  this.statementHasAwaitIdentifier = true;
2765
2766
  if (use === 1 /* IdentifierUse.Name */ || (use === 2 /* IdentifierUse.ElementName */ && this.isElementNameEnd()))
2766
- return new Identifier(text);
2767
- return new ReferenceIdentifier(text);
2767
+ return new Identifier(name);
2768
+ return new ReferenceIdentifier(name);
2768
2769
  }
2769
2770
  /** Whether the current token ends an object literal element name that is not a shorthand property. */
2770
2771
  isElementNameEnd() {
@@ -2772,7 +2773,7 @@ export class Parser extends ScannerErrorReporter {
2772
2773
  return token === 58 /* SyntaxKind.ColonToken */ || token === 20 /* SyntaxKind.OpenParenToken */ || token === 29 /* SyntaxKind.LessThanToken */;
2773
2774
  }
2774
2775
  createMissingIdentifier(use = 0 /* IdentifierUse.Reference */) {
2775
- const result = this.newIdentifier('', use);
2776
+ const result = this.newIdentifier(new IdentifierName(''), use);
2776
2777
  this.finishNode(result, this.nodePos());
2777
2778
  return result;
2778
2779
  }
@@ -3959,7 +3960,7 @@ export class Parser extends ScannerErrorReporter {
3959
3960
  // An unclosed opening element took its parent's closing element: restructure
3960
3961
  // (<div>(...<span>...</div>)) into (<div>(...<span>...</>)</div>). The parent reports it.
3961
3962
  const end = lastChild.children.end;
3962
- const missingIdentifier = this.finishNodeWithEnd(this.newIdentifier(''), end, end);
3963
+ const missingIdentifier = this.finishNodeWithEnd(this.newIdentifier(new IdentifierName('')), end, end);
3963
3964
  const newClosingElement = new JsxClosingElement(missingIdentifier);
3964
3965
  this.finishNodeWithEnd(newClosingElement, end, end);
3965
3966
  const newLast = new JsxElement(lastChild.openingElement, lastChild.children, newClosingElement);
@@ -4888,11 +4889,12 @@ export class Parser extends ScannerErrorReporter {
4888
4889
  if (isIdentifier) {
4889
4890
  const pos = this.scanner.hasPrecedingJSDocLeadingAsterisks() ? this.scanner.getTokenStart() : this.nodePos();
4890
4891
  const text = this.scanner.getIdentifierValue();
4892
+ const name = this.scanner.getIdentifierName();
4891
4893
  const record = this.scanner.recordIdentifierValue(text);
4892
4894
  this.nextTokenWithoutCheck();
4893
4895
  if (record)
4894
4896
  this.identifierTexts.push(text);
4895
- const result = this.newIdentifier(text, use);
4897
+ const result = this.newIdentifier(name, use);
4896
4898
  this.finishNode(result, pos);
4897
4899
  return result;
4898
4900
  }
@@ -8,6 +8,7 @@ import { NodeFactoryBase } from './factory-base.js';
8
8
  import { addDisposableResourceHelper, classPrivateFieldGetHelper, classPrivateFieldInHelper, classPrivateFieldSetHelper, disposeResourcesHelper, exportStarHelper, importDefaultHelper, importStarHelper, makeTemplateObjectHelper, rewriteRelativeImportExtensionsHelper, } from './helpers.js';
9
9
  import { formatGeneratedName, isMemberName, nodeIsSynthesized } from './utilities.js';
10
10
  import { isOuterExpression, outerExpressionOperand } from '../transformers/utilities.js';
11
+ import { IdentifierName } from '../identifier-name.js';
11
12
  /**
12
13
  * The node factory of an emit context. The context is the factory (`EmitContext` extends it), so the two are one
13
14
  * object: a factory and a context that pointed at each other made every context a reference cycle.
@@ -36,7 +37,7 @@ export class NodeFactory extends NodeFactoryBase {
36
37
  return copy;
37
38
  }
38
39
  cloneIdentifier(node) {
39
- return this.cloneNode(node, new Identifier(node.text));
40
+ return this.cloneNode(node, new Identifier(node.identifierName));
40
41
  }
41
42
  createNodeList(nodes) {
42
43
  return new NodeList(-1, -1, nodes);
@@ -56,7 +57,7 @@ export class NodeFactory extends NodeFactoryBase {
56
57
  return this.created(new Token(kind));
57
58
  }
58
59
  createIdentifier(text) {
59
- return this.created(new Identifier(text));
60
+ return this.created(new Identifier(new IdentifierName(text)));
60
61
  }
61
62
  createKeywordExpression(kind) {
62
63
  return this.created(new KeywordExpression(kind));
@@ -277,7 +277,7 @@ export class Printer extends NameGeneratorHost {
277
277
  case 297 /* SyntaxKind.JsxNamespacedName */:
278
278
  // Its text either way: the source text, or the text of a node from elsewhere.
279
279
  if (this.textIsSourceText(node))
280
- return node.text;
280
+ return node instanceof Identifier ? node.text : node.text;
281
281
  if (!canUseSourceFile || !this.isInCurrentSourceFile(node)) {
282
282
  if (node instanceof Identifier)
283
283
  return node.text;
@@ -311,7 +311,8 @@ export class Printer extends NameGeneratorHost {
311
311
  return false;
312
312
  if ((node.flags & (8 /* NodeFlags.Reparsed */ | 4194304 /* NodeFlags.JSDoc */ | 268435456 /* NodeFlags.ReparserTransformedLiteral */)) !== 0)
313
313
  return false;
314
- const text = node.text;
314
+ // Natively an identifier's text is read through its name, and a private identifier's from its field.
315
+ const text = node instanceof Identifier ? node.text : node.text;
315
316
  const source = this.sourceText;
316
317
  const end = node.end;
317
318
  const start = end - text.length;
@@ -88,6 +88,18 @@ export declare class CheckedProgram {
88
88
  createChecker(): Checker;
89
89
  /** Frees the checker that reports the program's diagnostics (`disposeChecker`). */
90
90
  disposeCheckers(): void;
91
+ /** Adds the counts a checker thread sent (`CheckerResult.counts`): types, instantiations, symbols. */
92
+ addCheckerCounts(counts: readonly number[]): void;
93
+ /**
94
+ * The types, instantiations and transient symbols of every checker of the program: this thread's and
95
+ * the checker threads', as tsgo's `Program.TypeCount`, `InstantiationCount` and `SymbolCount` add them up.
96
+ * Reading them doesn't create this thread's checker.
97
+ */
98
+ checkerCounts(): {
99
+ types: number;
100
+ instantiations: number;
101
+ symbols: number;
102
+ };
91
103
  getBindDiagnostics(file: SourceFile | undefined): Diagnostic[];
92
104
  /**
93
105
  * Diagnostics of checker threads (parallel-check.ts): the semantic diagnostics of each file by file
@@ -109,6 +121,12 @@ export declare class CheckedProgram {
109
121
  */
110
122
  referenceThreads: number;
111
123
  readonly parallelGlobalDiagnostics: Diagnostic[];
124
+ /** The types checker threads created (`CheckerResult.counts`), which `--diagnostics` adds to `checker`'s. */
125
+ threadTypeCount: number;
126
+ /** The instantiations checker threads made. */
127
+ threadInstantiations: number;
128
+ /** The transient symbols checker threads created. */
129
+ threadSymbolCount: number;
112
130
  /**
113
131
  * Whether the semantic diagnostics of a file include the global diagnostics its checker found while
114
132
  * checking it, as an incremental program caches them (IncrementalProgram). Such a program doesn't report
@@ -176,6 +176,27 @@ export class CheckedProgram {
176
176
  disposeChecker(this.reportingChecker);
177
177
  this.reportingChecker = undefined;
178
178
  }
179
+ /** Adds the counts a checker thread sent (`CheckerResult.counts`): types, instantiations, symbols. */
180
+ addCheckerCounts(counts) {
181
+ if (counts.length < 3)
182
+ return;
183
+ this.threadTypeCount += counts[0];
184
+ this.threadInstantiations += counts[1];
185
+ this.threadSymbolCount += counts[2];
186
+ }
187
+ /**
188
+ * The types, instantiations and transient symbols of every checker of the program: this thread's and
189
+ * the checker threads', as tsgo's `Program.TypeCount`, `InstantiationCount` and `SymbolCount` add them up.
190
+ * Reading them doesn't create this thread's checker.
191
+ */
192
+ checkerCounts() {
193
+ const own = this.reportingChecker;
194
+ return {
195
+ types: (own === undefined ? 0 : own.typeCount) + this.threadTypeCount,
196
+ instantiations: (own === undefined ? 0 : own.totalInstantiations) + this.threadInstantiations,
197
+ symbols: (own === undefined ? 0 : own.symbolCount) + this.threadSymbolCount,
198
+ };
199
+ }
179
200
  getBindDiagnostics(file) {
180
201
  return this.collect(file, (f) => f.bindDiagnostics);
181
202
  }
@@ -199,6 +220,12 @@ export class CheckedProgram {
199
220
  */
200
221
  referenceThreads = 1;
201
222
  parallelGlobalDiagnostics = [];
223
+ /** The types checker threads created (`CheckerResult.counts`), which `--diagnostics` adds to `checker`'s. */
224
+ threadTypeCount = 0;
225
+ /** The instantiations checker threads made. */
226
+ threadInstantiations = 0;
227
+ /** The transient symbols checker threads created. */
228
+ threadSymbolCount = 0;
202
229
  /**
203
230
  * Whether the semantic diagnostics of a file include the global diagnostics its checker found while
204
231
  * checking it, as an incremental program caches them (IncrementalProgram). Such a program doesn't report
@@ -9,6 +9,7 @@
9
9
  import { ArrayTypeNode, ArrowFunction, AsExpression, BinaryExpression, CallSignatureDeclaration, ClassDeclaration, ClassExpression, ConstructSignatureDeclaration, ConstructorDeclaration, ConstructorTypeNode, ElementAccessExpression, ExportAssignment, ExpressionStatement, ExpressionWithTypeArguments, FunctionDeclaration, FunctionExpression, FunctionTypeNode, GetAccessorDeclaration, HeritageClause, Identifier, ImportDeclaration, IndexSignatureDeclaration, JSDoc, JSDocAugmentsTag, JSDocCallbackTag, JSDocImplementsTag, JSDocImportTag, JSDocOverloadTag, JSDocParameterOrPropertyTag, JSDocSatisfiesTag, JSDocSignature, JSDocTemplateTag, JSDocThisTag, JSDocTypeExpression, JSDocTypeLiteral, JSDocTypedefTag, JSDocVariadicType, JSDocOptionalType, KeywordTypeNode, MethodDeclaration, MethodSignatureDeclaration, ModifierList, ModuleBlock, ModuleDeclaration, NodeList, NodeVisitor, NumericLiteral, ParameterDeclaration, ParenthesizedExpression, PropertyAccessExpression, PropertyAssignment, PropertyDeclaration, PropertySignatureDeclaration, QualifiedName, ReturnStatement, SatisfiesExpression, SetAccessorDeclaration, ShorthandPropertyAssignment, StringLiteral, Token, TypeAliasDeclaration, TypeLiteralNode, TypeParameterDeclaration, VariableDeclaration, VariableStatement, getComment, getModifiers, getName, getParameters, getText, getType, getTypeExpression, getTypeParameters, FullPropertyAssignment, } from './ast.js';
10
10
  import { isAssignmentOperator, isFunctionLike, isInJSFile, isLeftHandSideExpression, isStringLiteralLike, } from './ast-utilities.js';
11
11
  import { isIdentifierPart, isIdentifierStart } from './character-codes.js';
12
+ import { IdentifierName } from './identifier-name.js';
12
13
  /** Sets the parent of every node in a subtree. */
13
14
  class ParentInChildrenSetter extends NodeVisitor {
14
15
  parent = undefined;
@@ -219,7 +220,7 @@ export class Reparser {
219
220
  const param = params[pi];
220
221
  let parameter;
221
222
  if (param instanceof JSDocThisTag) {
222
- const thisIdent = new Identifier('this');
223
+ const thisIdent = new Identifier(new IdentifierName('this'));
223
224
  thisIdent.pos = param.pos;
224
225
  thisIdent.end = param.end;
225
226
  thisIdent.flags = p.contextFlags | 8 /* NodeFlags.Reparsed */;
@@ -249,7 +250,7 @@ export class Reparser {
249
250
  let name = param.name;
250
251
  if (name instanceof Identifier && !isValidIdentifier(name.text)) {
251
252
  // Replace invalid characters with `_`, or use `_N` for an empty name, for a valid parameter name.
252
- name = this.addTransformedReparse(new Identifier(sanitizeIdentifier(name.text, pi)), name);
253
+ name = this.addTransformedReparse(new Identifier(new IdentifierName(sanitizeIdentifier(name.text, pi))), name);
253
254
  }
254
255
  else {
255
256
  name = this.addDeepCloneReparse(name);
@@ -433,7 +434,7 @@ export class Reparser {
433
434
  firstName.kind !== 109 /* SyntaxKind.ThisKeyword */ &&
434
435
  !(firstName instanceof Identifier && firstName.text === 'this'))) {
435
436
  // tsgo gives the `this` name no location.
436
- const thisParam = new ParameterDeclaration(undefined, undefined, new Identifier('this'), undefined, undefined, undefined);
437
+ const thisParam = new ParameterDeclaration(undefined, undefined, new Identifier(new IdentifierName('this')), undefined, undefined, undefined);
437
438
  thisParam.type = this.addDeepCloneReparse(getType(tag.typeExpression));
438
439
  this.finishReparsedNode(thisParam, tag.tagName);
439
440
  const newParams = [thisParam];
@@ -1,3 +1,4 @@
1
+ import { IdentifierName } from './identifier-name.js';
1
2
  import type { DiagnosticMessage } from './diagnostics.js';
2
3
  import { EscapeSequenceScanningFlags, RegularExpressionFlags } from './regexp-checker.js';
3
4
  import { SyntaxKind } from './syntax-kind.js';
@@ -60,6 +61,7 @@ export declare class Scanner {
60
61
  /** @internal */ tokenFlags: TokenFlags;
61
62
  /** @internal */ tokenValue: string;
62
63
  /** @internal */ valueStart: number;
64
+ private tokenName;
63
65
  /** @internal */ valueEnd: number;
64
66
  private valueHash;
65
67
  private hashStart;
@@ -68,6 +70,7 @@ export declare class Scanner {
68
70
  /** @internal */ skipJSDocLeadingAsterisks: number;
69
71
  private readonly cutUnits;
70
72
  private readonly identifiers;
73
+ private lastEntry;
71
74
  private loadedBlocks;
72
75
  private textKind;
73
76
  private lineFeedFrom;
@@ -113,6 +116,11 @@ export declare class Scanner {
113
116
  recordIdentifierValue(text: string): boolean;
114
117
  /** @internal Like `getTokenValue`, but identifiers with the same text share one string. */
115
118
  getIdentifierValue(): string;
119
+ /**
120
+ * The identifier value as a name that identifiers with the same text share, after
121
+ * `getIdentifierValue`; a cooked value (with escapes) gets a name of its own.
122
+ */
123
+ getIdentifierName(): IdentifierName;
116
124
  getCommentDirectives(): readonly CommentDirective[];
117
125
  hasUnicodeEscape(): boolean;
118
126
  hasExtendedUnicodeEscape(): boolean;
@@ -1,4 +1,5 @@
1
1
  import { charSize, codePointAt, isASCIILetter, isDigit, isHexDigit, isIdentifierPart, isIdentifierStart, isLineBreak, isOctalDigit, isWhiteSpaceLike, isWhiteSpaceSingleLine, } from './character-codes.js';
2
+ import { IdentifierName } from './identifier-name.js';
2
3
  import { parsePseudoBigInt } from './pseudo-bigint.js';
3
4
  import { checkRegularExpression, regularExpressionFlag, } from './regexp-checker.js';
4
5
  import { CommentDirective, CommentRange, } from './types.js';
@@ -308,58 +309,58 @@ function rangeHash(chars, start, end) {
308
309
  function finishHash(hash) {
309
310
  return hash ^ (hash >>> 15);
310
311
  }
311
- /** Strings for ranges of one text, keyed by their code units: equal identifiers share one string. */
312
+ /**
313
+ * Names for ranges of one text, keyed by their code units: equal identifiers share one
314
+ * `IdentifierName`.
315
+ */
312
316
  class IdentifierTable {
313
- text;
314
317
  // Pairs of (entry index + 1, hash) per slot, (0, 0) when empty; linear probing.
315
318
  slots;
316
319
  // Each entry's length in code units.
317
320
  lengths;
318
- texts;
321
+ names;
319
322
  count;
320
- // Per entry: 1 once its text was recorded among the file's identifier texts (`markRecorded`).
323
+ // Per entry: 1 once its name was recorded among the file's identifier texts (`markRecorded`).
321
324
  recorded;
322
- // The entry the last `intern` returned.
323
- lastEntry;
324
- constructor(text) {
325
- this.text = text;
325
+ constructor() {
326
326
  this.slots = new Int32Array(512);
327
327
  this.lengths = new Int32Array(128);
328
- this.texts = [];
328
+ this.names = [];
329
329
  this.count = 0;
330
330
  this.recorded = new Uint8Array(128);
331
- this.lastEntry = -1;
331
+ }
332
+ /** Empties the table for a new text. */
333
+ clear() {
334
+ if (this.count === 0)
335
+ return;
336
+ this.slots.fill(0);
337
+ this.names.length = 0;
338
+ this.recorded.fill(0, 0, this.count);
339
+ this.count = 0;
332
340
  }
333
341
  /**
334
- * Whether `text`, just returned by `intern`, still needs recording among the file's identifier
335
- * texts; marks it recorded. Texts the table doesn't know are always recorded.
342
+ * Whether `text`, the text of the entry `entry` that `intern` returned (-1 for none), still needs
343
+ * recording among the file's identifier texts; marks it recorded. Texts the table doesn't know are
344
+ * always recorded.
336
345
  */
337
- markRecorded(text) {
338
- const entry = this.lastEntry;
339
- if (entry < 0 || this.texts[entry] !== text)
346
+ markRecorded(entry, text) {
347
+ if (entry < 0 || this.names[entry].text !== text)
340
348
  return true;
341
349
  if (this.recorded[entry] !== 0)
342
350
  return false;
343
351
  this.recorded[entry] = 1;
344
352
  return true;
345
353
  }
346
- /** Empties the table for a new text. */
347
- setText(text) {
348
- this.text = text;
349
- if (this.count === 0)
350
- return;
351
- this.slots.fill(0);
352
- this.recorded.fill(0, 0, this.count);
353
- this.texts.length = 0;
354
- this.count = 0;
355
- this.lastEntry = -1;
354
+ /** The name of the entry `intern` returned. */
355
+ name(entry) {
356
+ return this.names[entry];
356
357
  }
357
358
  /**
358
- * `text.substring(start, end)`, or the string interned for an equal range; `hash` is its `rangeHash`.
359
- * A candidate of the same hash and length is compared with `startsWith`, which natively compares
360
- * the bytes of both strings at once.
359
+ * The entry of `text.substring(start, end)`, added when the table has no equal range; `hash` is its
360
+ * `rangeHash`. A candidate of the same hash and length is compared with `startsWith`, which natively
361
+ * compares the bytes of both strings at once.
361
362
  */
362
- intern(start, end, hash) {
363
+ intern(text, start, end, hash) {
363
364
  start = start | 0;
364
365
  end = end | 0;
365
366
  hash = hash | 0;
@@ -372,15 +373,11 @@ class IdentifierTable {
372
373
  if (entry === 0)
373
374
  break;
374
375
  if ((slots[(slot * 2 + 1) | 0] | 0) === hash && (this.lengths[(entry - 1) | 0] | 0) === length) {
375
- const candidate = this.texts[(entry - 1) | 0];
376
- if (this.text.startsWith(candidate, start)) {
377
- this.lastEntry = (entry - 1) | 0;
378
- return candidate;
379
- }
376
+ if (text.startsWith(this.names[(entry - 1) | 0].text, start))
377
+ return (entry - 1) | 0;
380
378
  }
381
379
  slot = (slot + 1) & mask;
382
380
  }
383
- const value = this.text.substring(start, end);
384
381
  const index = this.count | 0;
385
382
  if (index === this.lengths.length) {
386
383
  const lengths = new Int32Array(index * 2);
@@ -391,14 +388,13 @@ class IdentifierTable {
391
388
  this.recorded = recorded;
392
389
  }
393
390
  this.lengths[index] = length;
394
- this.texts.push(value);
391
+ this.names.push(new IdentifierName(text.substring(start, end)));
395
392
  this.count = (index + 1) | 0;
396
- this.lastEntry = index;
397
393
  slots[(slot * 2) | 0] = (index + 1) | 0;
398
394
  slots[(slot * 2 + 1) | 0] = hash;
399
395
  if (this.count * 2 > mask + 1)
400
396
  this.slots = rehash(slots);
401
- return value;
397
+ return index;
402
398
  }
403
399
  }
404
400
  /** `IdentifierTable` slots in a table twice the size. */
@@ -546,6 +542,8 @@ export class Scanner {
546
542
  // so identifiers and keywords don't allocate until their value is read.
547
543
  /** @internal */ tokenValue;
548
544
  /** @internal */ valueStart;
545
+ // The name `getIdentifierValue` last interned, whose text `tokenValue` then holds.
546
+ tokenName;
549
547
  /** @internal */ valueEnd;
550
548
  // `rangeHash` of `chars[hashStart, hashEnd)`, which the ASCII identifier scan computes as it goes.
551
549
  valueHash;
@@ -556,6 +554,8 @@ export class Scanner {
556
554
  // The code units zeroed by `setTextEnd`.
557
555
  cutUnits;
558
556
  identifiers;
557
+ // The entry `getIdentifierValue` last interned, -1 for none.
558
+ lastEntry;
559
559
  // With code units on demand: per block of `unitBlockSize` code units, 1 once `chars` holds them
560
560
  // (`loadUnits`); `chars` is zero elsewhere.
561
561
  loadedBlocks;
@@ -594,6 +594,7 @@ export class Scanner {
594
594
  this.tokenFlags = 0 /* TokenFlags.None */;
595
595
  this.tokenValue = '';
596
596
  this.valueStart = -1;
597
+ this.tokenName = undefined;
597
598
  this.valueEnd = -1;
598
599
  this.valueHash = 0;
599
600
  this.hashStart = -1;
@@ -601,7 +602,8 @@ export class Scanner {
601
602
  this.commentDirectives = [];
602
603
  this.skipJSDocLeadingAsterisks = 0;
603
604
  this.cutUnits = new Uint16Array(4);
604
- this.identifiers = new IdentifierTable(text);
605
+ this.identifiers = new IdentifierTable();
606
+ this.lastEntry = -1;
605
607
  this.textKind = 0 /* TextKind.Unknown */;
606
608
  this.lineFeedFrom = -1;
607
609
  this.lineFeedAt = -1;
@@ -613,7 +615,8 @@ export class Scanner {
613
615
  this.text = text;
614
616
  this.chars = toCodeUnits(text);
615
617
  this.loadedBlocks = undefined;
616
- this.identifiers.setText(text);
618
+ this.identifiers.clear();
619
+ this.lastEntry = -1;
617
620
  this.textKind = 0 /* TextKind.Unknown */;
618
621
  this.lineFeedFrom = -1;
619
622
  this.lineFeedAt = -1;
@@ -737,7 +740,7 @@ export class Scanner {
737
740
  * file to be recorded; files record each identifier text once.
738
741
  */
739
742
  recordIdentifierValue(text) {
740
- return this.identifiers.markRecorded(text);
743
+ return this.identifiers.markRecorded(this.lastEntry, text);
741
744
  }
742
745
  /** @internal Like `getTokenValue`, but identifiers with the same text share one string. */
743
746
  getIdentifierValue() {
@@ -745,11 +748,24 @@ export class Scanner {
745
748
  if (start >= 0) {
746
749
  const end = this.valueEnd;
747
750
  const hash = start === this.hashStart && end === this.hashEnd ? this.valueHash : rangeHash(this.chars, start, end);
748
- this.tokenValue = this.identifiers.intern(start, end, hash);
751
+ const entry = this.identifiers.intern(this.text, start, end, hash);
752
+ this.lastEntry = entry;
753
+ this.tokenName = this.identifiers.name(entry);
754
+ this.tokenValue = this.tokenName.text;
749
755
  this.valueStart = -1;
750
756
  }
751
757
  return this.tokenValue;
752
758
  }
759
+ /**
760
+ * The identifier value as a name that identifiers with the same text share, after
761
+ * `getIdentifierValue`; a cooked value (with escapes) gets a name of its own.
762
+ */
763
+ getIdentifierName() {
764
+ const name = this.tokenName;
765
+ if (name !== undefined && name.text === this.tokenValue)
766
+ return name;
767
+ return new IdentifierName(this.tokenValue);
768
+ }
753
769
  getCommentDirectives() {
754
770
  return this.commentDirectives;
755
771
  }