tsc-ts 0.0.7 → 0.0.8

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.
package/README.md CHANGED
@@ -31,7 +31,7 @@ npx tsc-ts -p tsconfig.json
31
31
  npx tsc-ts --noEmit src/index.ts
32
32
  ```
33
33
 
34
- `tsc-ts --api` serves the TypeScript API over stdin and stdout, like `tsc --api`.
34
+ `tsc-ts --api` serves the TypeScript API over stdin and stdout, like `tsc --api`. On Windows, `--api --pipe \\.\pipe\<name>` serves it over a named pipe it creates, as `tsc --api --pipe` does, for clients that connect to the pipe (such as scriptc under Node.js); only the native executable supports `--pipe`.
35
35
 
36
36
  `--checkers N` checks the program on N threads. Unless `--checkers` or `--singleThreaded` is given, the native executable uses one checker per CPU it may run on (up to 16), and at least tsgo's four; it uses fewer than the CPUs, but never fewer than four, when the estimated peak memory of more checkers would not fit 85% of the machine's memory (`TSC_TS_CHECKERS=fixed` keeps tsgo's four), and checkers beyond the fourth stop taking files, one at a time, when the process's memory reaches that share; it shares one program between its threads and also parses and binds the program's files on them. Unless `--singleThreaded` is given, the program's files are parsed and bound on threads also with `--checkers 1`, as tsgo does. Files that share costly declarations, such as a large generated schema and the few files importing it, are checked together on one checker. Under Node.js, where every thread builds its own copy of the program, tsc-ts checks on one thread unless `--checkers` is given. `--incremental`, `--watch` and `--build` always check on one thread. The diagnostics are the same as with one checker.
37
37
 
@@ -12,7 +12,7 @@ import { getExportSymbolOfValueSymbolIfExported } from './checker-symbols.js';
12
12
  import { getBaseTypes, getDeclaredTypeOfSymbol } from './checker-declared-types.js';
13
13
  import { getPropertyOfType } from './checker-members.js';
14
14
  import { getFunctionFlags } from './checker-utilities.js';
15
- import { getDeclarations } from './symbol.js';
15
+ import { declarationAt, declarationCount } from './symbol.js';
16
16
  /** Reports a block-scoped variable, class or enum resolved at `errorLocation` before its declaration. */
17
17
  export function checkResolvedBlockScopedVariable(c, resolved, errorLocation) {
18
18
  const result = getExportSymbolOfValueSymbolIfExported(c, resolved);
@@ -23,7 +23,8 @@ export function checkResolvedBlockScopedVariable(c, resolved, errorLocation) {
23
23
  (result.flags & 32 /* SymbolFlags.Class */) !== 0)
24
24
  return;
25
25
  let declaration;
26
- for (const d of getDeclarations(result)) {
26
+ for (let i = 0; i < declarationCount(result); i++) {
27
+ const d = declarationAt(result, i);
27
28
  if (isBlockOrCatchScoped(d) || isClassLike(d) || d.kind === 267 /* SyntaxKind.EnumDeclaration */) {
28
29
  declaration = d;
29
30
  break;
@@ -20,7 +20,7 @@ import { getIndexedAccessType, isGenericMappedType } from './checker-type-operat
20
20
  import { getSignatureInstantiation } from './checker-signatures.js';
21
21
  import { evaluateEnumMember } from './checker-evaluator.js';
22
22
  import { checkTypeAssignableTo, isTypeIdenticalTo } from './relations.js';
23
- import { getDeclarations } from './symbol.js';
23
+ import { declarationAt, declarationCount, getDeclarations } from './symbol.js';
24
24
  export { getParentOfSymbol };
25
25
  export function getDeclaredTypeOfSymbol(c, symbol) {
26
26
  return tryGetDeclaredTypeOfSymbol(c, symbol) ?? c.errorType;
@@ -752,11 +752,14 @@ export function getMinTypeArgumentCount(c, typeParameters) {
752
752
  }
753
753
  /** Whether a type parameter is declared with a default, without resolving it. */
754
754
  function hasTypeParameterDefault(t) {
755
- if (t.symbol === undefined)
755
+ const symbol = t.symbol;
756
+ if (symbol === undefined)
756
757
  return false;
757
- for (const d of getDeclarations(t.symbol))
758
+ for (let i = 0; i < declarationCount(symbol); i++) {
759
+ const d = declarationAt(symbol, i);
758
760
  if (d.kind === 169 /* SyntaxKind.TypeParameter */ && d.defaultType !== undefined)
759
761
  return true;
762
+ }
760
763
  return false;
761
764
  }
762
765
  export function fillMissingTypeArguments(c, typeArguments, typeParameters, minTypeArgumentCount, isJavaScriptImplicitAny) {
@@ -12,7 +12,7 @@ import { entityNameToString } from './checker-expressions.js';
12
12
  import { isErrorType } from './checker-type-factory.js';
13
13
  import { getPropertyOfType } from './checker-members.js';
14
14
  import { signatureToString } from './type-printer.js';
15
- import { declarationCount, getDeclarations } from './symbol.js';
15
+ import { declarationAt, declarationCount, getDeclarations } from './symbol.js';
16
16
  /** Whether `declaration`, or the statement it belongs to, has a `@deprecated` JSDoc tag. */
17
17
  export function isDeprecatedDeclaration(declaration) {
18
18
  if ((getCombinedNodeFlags(declaration) & 67108864 /* NodeFlags.PossiblyContainsDeprecatedTag */) === 0)
@@ -38,24 +38,24 @@ function getJSDocDeprecatedTag(node) {
38
38
  * members when all are.
39
39
  */
40
40
  export function isDeprecatedSymbol(c, symbol) {
41
- const declarations = getDeclarations(symbol);
41
+ const count = declarationCount(symbol);
42
42
  const parentSymbol = getParentOfSymbol(c, symbol);
43
- if (parentSymbol !== undefined && declarations.length > 1)
43
+ if (parentSymbol !== undefined && count > 1)
44
44
  return (parentSymbol.flags & 64 /* SymbolFlags.Interface */) !== 0
45
- ? someDeprecatedDeclaration(declarations)
46
- : everyDeprecatedDeclaration(declarations);
45
+ ? someDeprecatedDeclaration(symbol)
46
+ : everyDeprecatedDeclaration(symbol);
47
47
  return ((symbol.valueDeclaration !== undefined && isDeprecatedDeclaration(symbol.valueDeclaration)) ||
48
- (declarations.length !== 0 && everyDeprecatedDeclaration(declarations)));
48
+ (count !== 0 && everyDeprecatedDeclaration(symbol)));
49
49
  }
50
- function someDeprecatedDeclaration(declarations) {
51
- for (const d of declarations)
52
- if (isDeprecatedDeclaration(d))
50
+ function someDeprecatedDeclaration(symbol) {
51
+ for (let i = 0; i < declarationCount(symbol); i++)
52
+ if (isDeprecatedDeclaration(declarationAt(symbol, i)))
53
53
  return true;
54
54
  return false;
55
55
  }
56
- function everyDeprecatedDeclaration(declarations) {
57
- for (const d of declarations)
58
- if (!isDeprecatedDeclaration(d))
56
+ function everyDeprecatedDeclaration(symbol) {
57
+ for (let i = 0; i < declarationCount(symbol); i++)
58
+ if (!isDeprecatedDeclaration(declarationAt(symbol, i)))
59
59
  return false;
60
60
  return true;
61
61
  }
@@ -290,7 +290,8 @@ export function checkDeprecatedTypeReference(c, node, type) {
290
290
  const symbol = c.resolvedSymbols.get(node.id);
291
291
  if (symbol === undefined)
292
292
  return;
293
- for (const d of getDeclarations(symbol)) {
293
+ for (let i = 0; i < declarationCount(symbol); i++) {
294
+ const d = declarationAt(symbol, i);
294
295
  if (isTypeDeclaration(d) && isDeprecatedDeclaration(d)) {
295
296
  addDeprecatedSuggestion(c, getDeprecatedSuggestionNode(node), getDeclarations(symbol), symbol.name);
296
297
  return;
@@ -22,7 +22,7 @@ import { getNonNullableType, getTypeWithFacts, hasTypeFacts } from './checker-fl
22
22
  import { sliceTupleType } from './checker-signatures.js';
23
23
  import { getPropertyNameFromType, isTypeUsableAsPropertyName, maybeTypeOfKind } from './checker-utilities.js';
24
24
  import { checkPropertyAccessibility } from './checker-property-access.js';
25
- import { copyDeclarations, getDeclarations, getSymbolId } from './symbol.js';
25
+ import { copyDeclarations, declarationAt, declarationCount, getSymbolId, } from './symbol.js';
26
26
  function isBindingPatternNode(node) {
27
27
  return (node !== undefined &&
28
28
  (node.kind === 207 /* SyntaxKind.ObjectBindingPattern */ || node.kind === 208 /* SyntaxKind.ArrayBindingPattern */));
@@ -548,7 +548,8 @@ export function isSpreadableProperty(prop) {
548
548
  const notMethodOrAccessor = (prop.flags & (8192 /* SymbolFlags.Method */ | 32768 /* SymbolFlags.GetAccessor */ | 65536 /* SymbolFlags.SetAccessor */)) === 0;
549
549
  let hasPrivateName = false;
550
550
  let inClass = false;
551
- for (const d of getDeclarations(prop)) {
551
+ for (let i = 0; i < declarationCount(prop); i++) {
552
+ const d = declarationAt(prop, i);
552
553
  if (isPrivateIdentifierClassElementDeclaration(d))
553
554
  hasPrivateName = true;
554
555
  if (d.parent !== undefined && isClassLike(d.parent))
@@ -26,7 +26,7 @@ import { getTypeForBindingElement, getTypeFromBindingPattern } from './checker-d
26
26
  import { checkRightHandSideOfForOf } from './checker-statements.js';
27
27
  import { getTypeWithFacts, hasTypeFacts, getNonNullableType } from './checker-flow.js';
28
28
  import { getTypeOfModuleExportsSymbol, getWidenedTypeForAssignmentDeclaration } from './checker-javascript.js';
29
- import { copyDeclarations, getDeclarations, getSymbolId } from './symbol.js';
29
+ import { copyDeclarations, declarationAt, declarationCount, getDeclarations, getSymbolId, } from './symbol.js';
30
30
  export function getTypeOfSymbol(c, symbol) {
31
31
  const checkFlags = symbol.checkFlags;
32
32
  if ((checkFlags & 65536 /* CheckFlags.DeferredType */) !== 0)
@@ -748,11 +748,11 @@ export function isReadonlySymbol(c, symbol) {
748
748
  (getDeclarationNodeFlagsFromSymbol(symbol) & 6 /* NodeFlags.Constant */) !== 0) ||
749
749
  ((symbol.flags & 98304 /* SymbolFlags.Accessor */) !== 0 && (symbol.flags & 65536 /* SymbolFlags.SetAccessor */) === 0) ||
750
750
  (symbol.flags & 8 /* SymbolFlags.EnumMember */) !== 0 ||
751
- someReadonlyAssignmentDeclaration(c, getDeclarations(symbol)));
751
+ someReadonlyAssignmentDeclaration(c, symbol));
752
752
  }
753
- function someReadonlyAssignmentDeclaration(c, declarations) {
754
- for (const d of declarations)
755
- if (isReadonlyAssignmentDeclaration(c, d))
753
+ function someReadonlyAssignmentDeclaration(c, symbol) {
754
+ for (let i = 0; i < declarationCount(symbol); i++)
755
+ if (isReadonlyAssignmentDeclaration(c, declarationAt(symbol, i)))
756
756
  return true;
757
757
  return false;
758
758
  }
@@ -1459,9 +1459,11 @@ export function symbolIsValue(c, symbol) {
1459
1459
  function isDeclarationContainedBy(symbol, container) {
1460
1460
  const declaration = symbol.valueDeclaration;
1461
1461
  if (declaration !== undefined)
1462
- for (const d of getDeclarations(container))
1462
+ for (let i = 0; i < declarationCount(container); i++) {
1463
+ const d = declarationAt(container, i);
1463
1464
  if (declaration.pos >= d.pos && declaration.end <= d.end)
1464
1465
  return true;
1466
+ }
1465
1467
  return false;
1466
1468
  }
1467
1469
  /** Value members other than signatures and index signatures, declared ones first, each part ordered by declaration. */
@@ -135,6 +135,8 @@ export declare class Parser extends ScannerErrorReporter {
135
135
  reparseList: Node[];
136
136
  private readonly reparseLists;
137
137
  private reparseDepth;
138
+ private readonly listScratch;
139
+ private listDepth;
138
140
  reparsedClones: Node[];
139
141
  /** Nodes with eagerly parsed JSDoc, for rewinding. */
140
142
  jsDocInfos: Node[];
@@ -209,6 +211,11 @@ export declare class Parser extends ScannerErrorReporter {
209
211
  parseList(kind: ParsingContext, element: ListElement): NodeList;
210
212
  /** The list, or undefined if an element parser returned undefined. */
211
213
  parseDelimitedList(kind: ParsingContext, element: ListElement): NodeList | undefined;
214
+ /** The scratch array for a list at the next nesting depth, empty. */
215
+ private openList;
216
+ /** The elements collected in `list` (the scratch array from `openList`) as an array of their exact
217
+ * length, or the shared empty array; empties the scratch array for the next list at its depth. */
218
+ private closeList;
212
219
  /** The list; a missing list if `opening` is absent; undefined if an element parser returned undefined. */
213
220
  parseBracketedList(kind: ParsingContext, element: ListElement, opening: SyntaxKind, closing: SyntaxKind): NodeList | undefined;
214
221
  parseEmptyNodeList(): NodeList;
@@ -147,6 +147,10 @@ export class Parser extends ScannerErrorReporter {
147
147
  // receives reparsed nodes, and a fresh array per parsed list would be one more allocation each.
148
148
  reparseLists;
149
149
  reparseDepth;
150
+ // One scratch array per nesting depth of the lists being parsed. A list collects its elements in
151
+ // its depth's array and is copied out at its exact length, so the tree keeps no spare capacity.
152
+ listScratch;
153
+ listDepth;
150
154
  reparsedClones;
151
155
  /** Nodes with eagerly parsed JSDoc, for rewinding. */
152
156
  jsDocInfos;
@@ -200,6 +204,8 @@ export class Parser extends ScannerErrorReporter {
200
204
  this.reparseList = [];
201
205
  this.reparseLists = [this.reparseList];
202
206
  this.reparseDepth = 0;
207
+ this.listScratch = [];
208
+ this.listDepth = -1;
203
209
  this.reparsedClones = [];
204
210
  this.jsDocInfos = [];
205
211
  this.jsDocTable = undefined;
@@ -610,7 +616,7 @@ export class Parser extends ScannerErrorReporter {
610
616
  this.reparseLists.push([]);
611
617
  const reparseList = this.reparseLists[depth];
612
618
  this.reparseList = reparseList;
613
- const list = [];
619
+ const list = this.openList();
614
620
  while (!this.isListTerminator(kind)) {
615
621
  if (this.isListElement(kind, false)) {
616
622
  const elt = this.parseListElement(element, list.length);
@@ -636,7 +642,7 @@ export class Parser extends ScannerErrorReporter {
636
642
  this.reparseDepth = depth - 1;
637
643
  this.reparseList = outerReparseList;
638
644
  this.parsingContexts = saveParsingContexts;
639
- return list;
645
+ return this.closeList(list);
640
646
  }
641
647
  parseList(kind, element) {
642
648
  const pos = this.nodePos();
@@ -648,12 +654,13 @@ export class Parser extends ScannerErrorReporter {
648
654
  const pos = this.nodePos();
649
655
  const saveParsingContexts = this.parsingContexts;
650
656
  this.parsingContexts |= 1 << kind;
651
- const list = [];
657
+ const list = this.openList();
652
658
  for (;;) {
653
659
  if (this.isListElement(kind, false)) {
654
660
  const startPos = this.nodePos();
655
661
  const result = this.parseListElement(element, list.length);
656
662
  if (result === this.noElement) {
663
+ this.closeList(list);
657
664
  this.parsingContexts = saveParsingContexts;
658
665
  return undefined;
659
666
  }
@@ -683,7 +690,24 @@ export class Parser extends ScannerErrorReporter {
683
690
  break;
684
691
  }
685
692
  this.parsingContexts = saveParsingContexts;
686
- return this.newNodeList(pos, this.nodePos(), list);
693
+ return this.newNodeList(pos, this.nodePos(), this.closeList(list));
694
+ }
695
+ /** The scratch array for a list at the next nesting depth, empty. */
696
+ openList() {
697
+ const depth = ++this.listDepth;
698
+ if (depth === this.listScratch.length)
699
+ this.listScratch.push([]);
700
+ return this.listScratch[depth];
701
+ }
702
+ /** The elements collected in `list` (the scratch array from `openList`) as an array of their exact
703
+ * length, or the shared empty array; empties the scratch array for the next list at its depth. */
704
+ closeList(list) {
705
+ this.listDepth--;
706
+ if (list.length === 0)
707
+ return emptyListNodes;
708
+ const nodes = list.slice();
709
+ list.length = 0;
710
+ return nodes;
687
711
  }
688
712
  /** The list; a missing list if `opening` is absent; undefined if an element parser returned undefined. */
689
713
  parseBracketedList(kind, element, opening, closing) {
@@ -2373,10 +2397,11 @@ export class Parser extends ScannerErrorReporter {
2373
2397
  ? this.parseFunctionOrConstructorTypeToError(isUnionType)
2374
2398
  : this.parseConstituentType(isUnionType);
2375
2399
  if (this.token() === operator || hasLeadingOperator) {
2376
- const types = [type];
2400
+ const types = this.openList();
2401
+ types.push(type);
2377
2402
  while (this.parseOptional(operator))
2378
2403
  types.push(this.parseFunctionOrConstructorTypeToError(isUnionType));
2379
- const list = this.newNodeList(pos, this.nodePos(), types);
2404
+ const list = this.newNodeList(pos, this.nodePos(), this.closeList(types));
2380
2405
  type = isUnionType ? new UnionTypeNode(list) : new IntersectionTypeNode(list);
2381
2406
  this.finishNode(type, pos);
2382
2407
  }
@@ -3175,14 +3200,14 @@ export class Parser extends ScannerErrorReporter {
3175
3200
  }
3176
3201
  parseTemplateTypeSpans() {
3177
3202
  const pos = this.nodePos();
3178
- const list = [];
3203
+ const list = this.openList();
3179
3204
  for (;;) {
3180
3205
  const span = this.parseTemplateTypeSpan();
3181
3206
  list.push(span);
3182
3207
  if (span.literal.kind !== 16 /* SyntaxKind.TemplateMiddle */)
3183
3208
  break;
3184
3209
  }
3185
- return this.newNodeList(pos, this.nodePos(), list);
3210
+ return this.newNodeList(pos, this.nodePos(), this.closeList(list));
3186
3211
  }
3187
3212
  parseTemplateTypeSpan() {
3188
3213
  const pos = this.nodePos();
@@ -3282,12 +3307,10 @@ export class Parser extends ScannerErrorReporter {
3282
3307
  let hasTrailingModifier = false;
3283
3308
  let hasStaticModifier = false;
3284
3309
  const pos = this.nodePos();
3285
- let list;
3310
+ const list = this.openList();
3286
3311
  for (;;) {
3287
3312
  if (allowDecorators && this.token() === 59 /* SyntaxKind.AtToken */ && !hasTrailingModifier) {
3288
3313
  const decorator = this.parseDecorator();
3289
- if (list === undefined)
3290
- list = [];
3291
3314
  list.push(decorator);
3292
3315
  if (hasLeadingModifier)
3293
3316
  hasTrailingDecorator = true;
@@ -3298,8 +3321,6 @@ export class Parser extends ScannerErrorReporter {
3298
3321
  break;
3299
3322
  if (modifier.kind === 125 /* SyntaxKind.StaticKeyword */)
3300
3323
  hasStaticModifier = true;
3301
- if (list === undefined)
3302
- list = [];
3303
3324
  list.push(modifier);
3304
3325
  if (hasTrailingDecorator)
3305
3326
  hasTrailingModifier = true;
@@ -3307,7 +3328,8 @@ export class Parser extends ScannerErrorReporter {
3307
3328
  hasLeadingModifier = true;
3308
3329
  }
3309
3330
  }
3310
- return list === undefined ? undefined : this.newModifierList(pos, this.nodePos(), list);
3331
+ const nodes = this.closeList(list);
3332
+ return nodes.length === 0 ? undefined : this.newModifierList(pos, this.nodePos(), nodes);
3311
3333
  }
3312
3334
  parseDecorator() {
3313
3335
  const pos = this.nodePos();
@@ -3941,7 +3963,7 @@ export class Parser extends ScannerErrorReporter {
3941
3963
  const pos = this.nodePos();
3942
3964
  const saveParsingContexts = this.parsingContexts;
3943
3965
  this.parsingContexts |= 1 << 14 /* ParsingContext.JsxChildren */;
3944
- const list = [];
3966
+ const list = this.openList();
3945
3967
  for (;;) {
3946
3968
  // Like tsgo, this leaves the parser's current token unchanged.
3947
3969
  const currentToken = this.scanner.reScanJsxToken(true);
@@ -3957,7 +3979,7 @@ export class Parser extends ScannerErrorReporter {
3957
3979
  break;
3958
3980
  }
3959
3981
  this.parsingContexts = saveParsingContexts;
3960
- return this.newNodeList(pos, this.nodePos(), list);
3982
+ return this.newNodeList(pos, this.nodePos(), this.closeList(list));
3961
3983
  }
3962
3984
  parseJsxChild(openingTag, token) {
3963
3985
  switch (token) {
@@ -4519,14 +4541,14 @@ export class Parser extends ScannerErrorReporter {
4519
4541
  }
4520
4542
  parseTemplateSpans(isTaggedTemplate) {
4521
4543
  const pos = this.nodePos();
4522
- const list = [];
4544
+ const list = this.openList();
4523
4545
  for (;;) {
4524
4546
  const span = this.parseTemplateSpan(isTaggedTemplate);
4525
4547
  list.push(span);
4526
4548
  if (span.literal.kind !== 16 /* SyntaxKind.TemplateMiddle */)
4527
4549
  break;
4528
4550
  }
4529
- return this.newNodeList(pos, this.nodePos(), list);
4551
+ return this.newNodeList(pos, this.nodePos(), this.closeList(list));
4530
4552
  }
4531
4553
  parseTemplateSpan(isTaggedTemplate) {
4532
4554
  const pos = this.nodePos();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tsc-ts",
3
- "version": "0.0.7",
3
+ "version": "0.0.8",
4
4
  "description": "The TypeScript 7 compiler, ported to TypeScript and compiled to a native executable.",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -29,18 +29,18 @@
29
29
  "./package.json": "./package.json"
30
30
  },
31
31
  "dependencies": {
32
- "@scriptc/threads": "0.4.1"
32
+ "@scriptc/threads": "0.4.2"
33
33
  },
34
34
  "engines": {
35
35
  "node": ">=20"
36
36
  },
37
37
  "optionalDependencies": {
38
- "@tsc-ts/darwin-arm64": "0.0.7",
39
- "@tsc-ts/darwin-x64": "0.0.7",
40
- "@tsc-ts/linux-arm64-gnu": "0.0.7",
41
- "@tsc-ts/linux-arm64-musl": "0.0.7",
42
- "@tsc-ts/linux-x64-gnu": "0.0.7",
43
- "@tsc-ts/linux-x64-musl": "0.0.7",
44
- "@tsc-ts/win32-x64-msvc": "0.0.7"
38
+ "@tsc-ts/darwin-arm64": "0.0.8",
39
+ "@tsc-ts/darwin-x64": "0.0.8",
40
+ "@tsc-ts/linux-arm64-gnu": "0.0.8",
41
+ "@tsc-ts/linux-arm64-musl": "0.0.8",
42
+ "@tsc-ts/linux-x64-gnu": "0.0.8",
43
+ "@tsc-ts/linux-x64-musl": "0.0.8",
44
+ "@tsc-ts/win32-x64-msvc": "0.0.8"
45
45
  }
46
46
  }
@@ -37,7 +37,7 @@ import { getExportSymbolOfValueSymbolIfExported } from './checker-symbols.js';
37
37
  import { getBaseTypes, getDeclaredTypeOfSymbol } from './checker-declared-types.js';
38
38
  import { getPropertyOfType } from './checker-members.js';
39
39
  import { FunctionFlags, getFunctionFlags } from './checker-utilities.js';
40
- import { getDeclarations, type Symbol, SymbolFlags } from './symbol.js';
40
+ import { declarationAt, declarationCount, type Symbol, SymbolFlags } from './symbol.js';
41
41
 
42
42
  /** Reports a block-scoped variable, class or enum resolved at `errorLocation` before its declaration. */
43
43
  export function checkResolvedBlockScopedVariable(c: Checker, resolved: Symbol, errorLocation: Node): void {
@@ -50,7 +50,8 @@ export function checkResolvedBlockScopedVariable(c: Checker, resolved: Symbol, e
50
50
  )
51
51
  return;
52
52
  let declaration: Node | undefined;
53
- for (const d of getDeclarations(result)) {
53
+ for (let i = 0; i < declarationCount(result); i++) {
54
+ const d = declarationAt(result, i);
54
55
  if (isBlockOrCatchScoped(d) || isClassLike(d) || d.kind === SyntaxKind.EnumDeclaration) {
55
56
  declaration = d;
56
57
  break;
@@ -87,7 +87,7 @@ import { getIndexedAccessType, isGenericMappedType } from './checker-type-operat
87
87
  import { getSignatureInstantiation } from './checker-signatures.js';
88
88
  import { evaluateEnumMember, EvaluatedFlags, EvaluatedKind } from './checker-evaluator.js';
89
89
  import { checkTypeAssignableTo, isTypeIdenticalTo } from './relations.js';
90
- import { getDeclarations, type Symbol, SymbolFlags } from './symbol.js';
90
+ import { declarationAt, declarationCount, getDeclarations, type Symbol, SymbolFlags } from './symbol.js';
91
91
 
92
92
  export { getParentOfSymbol };
93
93
 
@@ -877,9 +877,12 @@ export function getMinTypeArgumentCount(c: Checker, typeParameters: readonly Typ
877
877
 
878
878
  /** Whether a type parameter is declared with a default, without resolving it. */
879
879
  function hasTypeParameterDefault(t: Type): boolean {
880
- if (t.symbol === undefined) return false;
881
- for (const d of getDeclarations(t.symbol))
880
+ const symbol = t.symbol;
881
+ if (symbol === undefined) return false;
882
+ for (let i = 0; i < declarationCount(symbol); i++) {
883
+ const d = declarationAt(symbol, i);
882
884
  if (d.kind === SyntaxKind.TypeParameter && (d as TypeParameterDeclaration).defaultType !== undefined) return true;
885
+ }
883
886
  return false;
884
887
  }
885
888
 
@@ -32,7 +32,7 @@ import { entityNameToString } from './checker-expressions.js';
32
32
  import { isErrorType } from './checker-type-factory.js';
33
33
  import { getPropertyOfType } from './checker-members.js';
34
34
  import { signatureToString } from './type-printer.js';
35
- import { declarationCount, getDeclarations, type Symbol, SymbolFlags } from './symbol.js';
35
+ import { declarationAt, declarationCount, getDeclarations, type Symbol, SymbolFlags } from './symbol.js';
36
36
 
37
37
  /** Whether `declaration`, or the statement it belongs to, has a `@deprecated` JSDoc tag. */
38
38
  export function isDeprecatedDeclaration(declaration: Node): boolean {
@@ -56,25 +56,26 @@ function getJSDocDeprecatedTag(node: Node): Node | undefined {
56
56
  * members when all are.
57
57
  */
58
58
  export function isDeprecatedSymbol(c: Checker, symbol: Symbol): boolean {
59
- const declarations = getDeclarations(symbol);
59
+ const count = declarationCount(symbol);
60
60
  const parentSymbol = getParentOfSymbol(c, symbol);
61
- if (parentSymbol !== undefined && declarations.length > 1)
61
+ if (parentSymbol !== undefined && count > 1)
62
62
  return (parentSymbol.flags & SymbolFlags.Interface) !== 0
63
- ? someDeprecatedDeclaration(declarations)
64
- : everyDeprecatedDeclaration(declarations);
63
+ ? someDeprecatedDeclaration(symbol)
64
+ : everyDeprecatedDeclaration(symbol);
65
65
  return (
66
66
  (symbol.valueDeclaration !== undefined && isDeprecatedDeclaration(symbol.valueDeclaration)) ||
67
- (declarations.length !== 0 && everyDeprecatedDeclaration(declarations))
67
+ (count !== 0 && everyDeprecatedDeclaration(symbol))
68
68
  );
69
69
  }
70
70
 
71
- function someDeprecatedDeclaration(declarations: readonly Node[]): boolean {
72
- for (const d of declarations) if (isDeprecatedDeclaration(d)) return true;
71
+ function someDeprecatedDeclaration(symbol: Symbol): boolean {
72
+ for (let i = 0; i < declarationCount(symbol); i++) if (isDeprecatedDeclaration(declarationAt(symbol, i))) return true;
73
73
  return false;
74
74
  }
75
75
 
76
- function everyDeprecatedDeclaration(declarations: readonly Node[]): boolean {
77
- for (const d of declarations) if (!isDeprecatedDeclaration(d)) return false;
76
+ function everyDeprecatedDeclaration(symbol: Symbol): boolean {
77
+ for (let i = 0; i < declarationCount(symbol); i++)
78
+ if (!isDeprecatedDeclaration(declarationAt(symbol, i))) return false;
78
79
  return true;
79
80
  }
80
81
 
@@ -330,7 +331,8 @@ export function checkDeprecatedTypeReference(c: Checker, node: Node, type: Type)
330
331
  if (isErrorType(c, type)) return;
331
332
  const symbol = c.resolvedSymbols.get(node.id);
332
333
  if (symbol === undefined) return;
333
- for (const d of getDeclarations(symbol)) {
334
+ for (let i = 0; i < declarationCount(symbol); i++) {
335
+ const d = declarationAt(symbol, i);
334
336
  if (isTypeDeclaration(d) && isDeprecatedDeclaration(d)) {
335
337
  addDeprecatedSuggestion(c, getDeprecatedSuggestionNode(node), getDeclarations(symbol), symbol.name);
336
338
  return;
@@ -115,7 +115,15 @@ import { TypeFacts, getNonNullableType, getTypeWithFacts, hasTypeFacts } from '.
115
115
  import { sliceTupleType } from './checker-signatures.js';
116
116
  import { getPropertyNameFromType, isTypeUsableAsPropertyName, maybeTypeOfKind } from './checker-utilities.js';
117
117
  import { checkPropertyAccessibility } from './checker-property-access.js';
118
- import { CheckFlags, copyDeclarations, getDeclarations, getSymbolId, type Symbol, SymbolFlags } from './symbol.js';
118
+ import {
119
+ CheckFlags,
120
+ copyDeclarations,
121
+ declarationAt,
122
+ declarationCount,
123
+ getSymbolId,
124
+ type Symbol,
125
+ SymbolFlags,
126
+ } from './symbol.js';
119
127
 
120
128
  function isBindingPatternNode(node: Node | undefined): boolean {
121
129
  return (
@@ -766,7 +774,8 @@ export function isSpreadableProperty(prop: Symbol): boolean {
766
774
  (prop.flags & (SymbolFlags.Method | SymbolFlags.GetAccessor | SymbolFlags.SetAccessor)) === 0;
767
775
  let hasPrivateName = false;
768
776
  let inClass = false;
769
- for (const d of getDeclarations(prop)) {
777
+ for (let i = 0; i < declarationCount(prop); i++) {
778
+ const d = declarationAt(prop, i);
770
779
  if (isPrivateIdentifierClassElementDeclaration(d)) hasPrivateName = true;
771
780
  if (d.parent !== undefined && isClassLike(d.parent)) inClass = true;
772
781
  }
@@ -129,7 +129,16 @@ import { getTypeForBindingElement, getTypeFromBindingPattern } from './checker-d
129
129
  import { checkRightHandSideOfForOf } from './checker-statements.js';
130
130
  import { getTypeWithFacts, TypeFacts, hasTypeFacts, getNonNullableType } from './checker-flow.js';
131
131
  import { getTypeOfModuleExportsSymbol, getWidenedTypeForAssignmentDeclaration } from './checker-javascript.js';
132
- import { CheckFlags, copyDeclarations, getDeclarations, getSymbolId, type Symbol, SymbolFlags } from './symbol.js';
132
+ import {
133
+ CheckFlags,
134
+ copyDeclarations,
135
+ declarationAt,
136
+ declarationCount,
137
+ getDeclarations,
138
+ getSymbolId,
139
+ type Symbol,
140
+ SymbolFlags,
141
+ } from './symbol.js';
133
142
 
134
143
  export function getTypeOfSymbol(c: Checker, symbol: Symbol): Type {
135
144
  const checkFlags = symbol.checkFlags;
@@ -932,12 +941,13 @@ export function isReadonlySymbol(c: Checker, symbol: Symbol): boolean {
932
941
  (getDeclarationNodeFlagsFromSymbol(symbol) & NodeFlags.Constant) !== 0) ||
933
942
  ((symbol.flags & SymbolFlags.Accessor) !== 0 && (symbol.flags & SymbolFlags.SetAccessor) === 0) ||
934
943
  (symbol.flags & SymbolFlags.EnumMember) !== 0 ||
935
- someReadonlyAssignmentDeclaration(c, getDeclarations(symbol))
944
+ someReadonlyAssignmentDeclaration(c, symbol)
936
945
  );
937
946
  }
938
947
 
939
- function someReadonlyAssignmentDeclaration(c: Checker, declarations: readonly Node[]): boolean {
940
- for (const d of declarations) if (isReadonlyAssignmentDeclaration(c, d)) return true;
948
+ function someReadonlyAssignmentDeclaration(c: Checker, symbol: Symbol): boolean {
949
+ for (let i = 0; i < declarationCount(symbol); i++)
950
+ if (isReadonlyAssignmentDeclaration(c, declarationAt(symbol, i))) return true;
941
951
  return false;
942
952
  }
943
953
 
@@ -1761,7 +1761,10 @@ export function symbolIsValue(c: Checker, symbol: Symbol): boolean {
1761
1761
  function isDeclarationContainedBy(symbol: Symbol, container: Symbol): boolean {
1762
1762
  const declaration = symbol.valueDeclaration;
1763
1763
  if (declaration !== undefined)
1764
- for (const d of getDeclarations(container)) if (declaration.pos >= d.pos && declaration.end <= d.end) return true;
1764
+ for (let i = 0; i < declarationCount(container); i++) {
1765
+ const d = declarationAt(container, i);
1766
+ if (declaration.pos >= d.pos && declaration.end <= d.end) return true;
1767
+ }
1765
1768
  return false;
1766
1769
  }
1767
1770
 
@@ -503,6 +503,10 @@ export class Parser extends ScannerErrorReporter {
503
503
  // receives reparsed nodes, and a fresh array per parsed list would be one more allocation each.
504
504
  private readonly reparseLists: Node[][];
505
505
  private reparseDepth: number;
506
+ // One scratch array per nesting depth of the lists being parsed. A list collects its elements in
507
+ // its depth's array and is copied out at its exact length, so the tree keeps no spare capacity.
508
+ private readonly listScratch: Node[][];
509
+ private listDepth: number;
506
510
  reparsedClones: Node[];
507
511
  /** Nodes with eagerly parsed JSDoc, for rewinding. */
508
512
  jsDocInfos: Node[];
@@ -562,6 +566,8 @@ export class Parser extends ScannerErrorReporter {
562
566
  this.reparseList = [];
563
567
  this.reparseLists = [this.reparseList];
564
568
  this.reparseDepth = 0;
569
+ this.listScratch = [];
570
+ this.listDepth = -1;
565
571
  this.reparsedClones = [];
566
572
  this.jsDocInfos = [];
567
573
  this.jsDocTable = undefined;
@@ -1024,7 +1030,7 @@ export class Parser extends ScannerErrorReporter {
1024
1030
  if (depth === this.reparseLists.length) this.reparseLists.push([]);
1025
1031
  const reparseList = this.reparseLists[depth]!;
1026
1032
  this.reparseList = reparseList;
1027
- const list: Node[] = [];
1033
+ const list = this.openList();
1028
1034
  while (!this.isListTerminator(kind)) {
1029
1035
  if (this.isListElement(kind, false)) {
1030
1036
  const elt = this.parseListElement(element, list.length);
@@ -1049,7 +1055,7 @@ export class Parser extends ScannerErrorReporter {
1049
1055
  this.reparseDepth = depth - 1;
1050
1056
  this.reparseList = outerReparseList;
1051
1057
  this.parsingContexts = saveParsingContexts;
1052
- return list;
1058
+ return this.closeList(list);
1053
1059
  }
1054
1060
 
1055
1061
  parseList(kind: ParsingContext, element: ListElement): NodeList {
@@ -1063,12 +1069,13 @@ export class Parser extends ScannerErrorReporter {
1063
1069
  const pos = this.nodePos();
1064
1070
  const saveParsingContexts = this.parsingContexts;
1065
1071
  this.parsingContexts |= 1 << kind;
1066
- const list: Node[] = [];
1072
+ const list = this.openList();
1067
1073
  for (;;) {
1068
1074
  if (this.isListElement(kind, false)) {
1069
1075
  const startPos = this.nodePos();
1070
1076
  const result = this.parseListElement(element, list.length);
1071
1077
  if (result === this.noElement) {
1078
+ this.closeList(list);
1072
1079
  this.parsingContexts = saveParsingContexts;
1073
1080
  return undefined;
1074
1081
  }
@@ -1094,7 +1101,24 @@ export class Parser extends ScannerErrorReporter {
1094
1101
  if (this.abortParsingListOrMoveToNextToken(kind)) break;
1095
1102
  }
1096
1103
  this.parsingContexts = saveParsingContexts;
1097
- return this.newNodeList(pos, this.nodePos(), list);
1104
+ return this.newNodeList(pos, this.nodePos(), this.closeList(list));
1105
+ }
1106
+
1107
+ /** The scratch array for a list at the next nesting depth, empty. */
1108
+ private openList(): Node[] {
1109
+ const depth = ++this.listDepth;
1110
+ if (depth === this.listScratch.length) this.listScratch.push([]);
1111
+ return this.listScratch[depth]!;
1112
+ }
1113
+
1114
+ /** The elements collected in `list` (the scratch array from `openList`) as an array of their exact
1115
+ * length, or the shared empty array; empties the scratch array for the next list at its depth. */
1116
+ private closeList(list: Node[]): Node[] {
1117
+ this.listDepth--;
1118
+ if (list.length === 0) return emptyListNodes;
1119
+ const nodes = list.slice();
1120
+ list.length = 0;
1121
+ return nodes;
1098
1122
  }
1099
1123
 
1100
1124
  /** The list; a missing list if `opening` is absent; undefined if an element parser returned undefined. */
@@ -3123,9 +3147,10 @@ export class Parser extends ScannerErrorReporter {
3123
3147
  ? this.parseFunctionOrConstructorTypeToError(isUnionType)
3124
3148
  : this.parseConstituentType(isUnionType);
3125
3149
  if (this.token() === operator || hasLeadingOperator) {
3126
- const types: Node[] = [type];
3150
+ const types = this.openList();
3151
+ types.push(type);
3127
3152
  while (this.parseOptional(operator)) types.push(this.parseFunctionOrConstructorTypeToError(isUnionType));
3128
- const list = this.newNodeList(pos, this.nodePos(), types);
3153
+ const list = this.newNodeList(pos, this.nodePos(), this.closeList(types));
3129
3154
  type = isUnionType ? new UnionTypeNode(list) : new IntersectionTypeNode(list);
3130
3155
  this.finishNode(type, pos);
3131
3156
  }
@@ -4059,13 +4084,13 @@ export class Parser extends ScannerErrorReporter {
4059
4084
 
4060
4085
  parseTemplateTypeSpans(): NodeList {
4061
4086
  const pos = this.nodePos();
4062
- const list: Node[] = [];
4087
+ const list = this.openList();
4063
4088
  for (;;) {
4064
4089
  const span = this.parseTemplateTypeSpan();
4065
4090
  list.push(span);
4066
4091
  if (span.literal.kind !== SyntaxKind.TemplateMiddle) break;
4067
4092
  }
4068
- return this.newNodeList(pos, this.nodePos(), list);
4093
+ return this.newNodeList(pos, this.nodePos(), this.closeList(list));
4069
4094
  }
4070
4095
 
4071
4096
  parseTemplateTypeSpan(): TemplateLiteralTypeSpan {
@@ -4189,24 +4214,23 @@ export class Parser extends ScannerErrorReporter {
4189
4214
  let hasTrailingModifier = false;
4190
4215
  let hasStaticModifier = false;
4191
4216
  const pos = this.nodePos();
4192
- let list: Node[] | undefined;
4217
+ const list = this.openList();
4193
4218
  for (;;) {
4194
4219
  if (allowDecorators && this.token() === SyntaxKind.AtToken && !hasTrailingModifier) {
4195
4220
  const decorator = this.parseDecorator();
4196
- if (list === undefined) list = [];
4197
4221
  list.push(decorator);
4198
4222
  if (hasLeadingModifier) hasTrailingDecorator = true;
4199
4223
  } else {
4200
4224
  const modifier = this.tryParseModifier(hasStaticModifier, permitConstAsModifier, stopOnStartOfClassStaticBlock);
4201
4225
  if (modifier === undefined) break;
4202
4226
  if (modifier.kind === SyntaxKind.StaticKeyword) hasStaticModifier = true;
4203
- if (list === undefined) list = [];
4204
4227
  list.push(modifier);
4205
4228
  if (hasTrailingDecorator) hasTrailingModifier = true;
4206
4229
  else hasLeadingModifier = true;
4207
4230
  }
4208
4231
  }
4209
- return list === undefined ? undefined : this.newModifierList(pos, this.nodePos(), list);
4232
+ const nodes = this.closeList(list);
4233
+ return nodes.length === 0 ? undefined : this.newModifierList(pos, this.nodePos(), nodes);
4210
4234
  }
4211
4235
 
4212
4236
  parseDecorator(): Node {
@@ -4938,7 +4962,7 @@ export class Parser extends ScannerErrorReporter {
4938
4962
  const pos = this.nodePos();
4939
4963
  const saveParsingContexts = this.parsingContexts;
4940
4964
  this.parsingContexts |= 1 << ParsingContext.JsxChildren;
4941
- const list: Node[] = [];
4965
+ const list = this.openList();
4942
4966
  for (;;) {
4943
4967
  // Like tsgo, this leaves the parser's current token unchanged.
4944
4968
  const currentToken = this.scanner.reScanJsxToken(true);
@@ -4958,7 +4982,7 @@ export class Parser extends ScannerErrorReporter {
4958
4982
  break;
4959
4983
  }
4960
4984
  this.parsingContexts = saveParsingContexts;
4961
- return this.newNodeList(pos, this.nodePos(), list);
4985
+ return this.newNodeList(pos, this.nodePos(), this.closeList(list));
4962
4986
  }
4963
4987
 
4964
4988
  parseJsxChild(openingTag: Node, token: SyntaxKind): Expression | undefined {
@@ -5633,13 +5657,13 @@ export class Parser extends ScannerErrorReporter {
5633
5657
 
5634
5658
  parseTemplateSpans(isTaggedTemplate: boolean): NodeList {
5635
5659
  const pos = this.nodePos();
5636
- const list: Node[] = [];
5660
+ const list = this.openList();
5637
5661
  for (;;) {
5638
5662
  const span = this.parseTemplateSpan(isTaggedTemplate);
5639
5663
  list.push(span);
5640
5664
  if (span.literal.kind !== SyntaxKind.TemplateMiddle) break;
5641
5665
  }
5642
- return this.newNodeList(pos, this.nodePos(), list);
5666
+ return this.newNodeList(pos, this.nodePos(), this.closeList(list));
5643
5667
  }
5644
5668
 
5645
5669
  parseTemplateSpan(isTaggedTemplate: boolean): TemplateSpan {