Skip to content

Commit 8e7a080

Browse files
committed
Pre-define some SourceFile properties and a more stable cloneNode
1 parent 1c8b104 commit 8e7a080

File tree

6 files changed

+227
-67
lines changed

6 files changed

+227
-67
lines changed

src/compiler/factory/nodeFactory.ts

Lines changed: 184 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import {
2+
__String,
23
addRange,
34
append,
45
appendIfUnique,
@@ -108,6 +109,7 @@ import {
108109
GeneratedIdentifier,
109110
GeneratedIdentifierFlags,
110111
GeneratedNamePart,
112+
GeneratedPrivateIdentifier,
111113
GetAccessorDeclaration,
112114
getAllUnscopedEmitHelpers,
113115
getBuildInfo,
@@ -167,6 +169,7 @@ import {
167169
isFunctionDeclaration,
168170
isFunctionExpression,
169171
isGeneratedIdentifier,
172+
isGeneratedPrivateIdentifier,
170173
isGetAccessorDeclaration,
171174
isHoistedFunction,
172175
isHoistedVariableStatement,
@@ -345,6 +348,7 @@ import {
345348
ParenthesizedTypeNode,
346349
parseNodeFactory,
347350
PartiallyEmittedExpression,
351+
Path,
348352
PlusToken,
349353
PostfixUnaryExpression,
350354
PostfixUnaryOperator,
@@ -370,6 +374,7 @@ import {
370374
QuestionDotToken,
371375
QuestionToken,
372376
ReadonlyKeyword,
377+
RedirectInfo,
373378
reduceLeft,
374379
RegularExpressionLiteral,
375380
RestTypeNode,
@@ -911,6 +916,7 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode
911916
updateEnumMember,
912917
createSourceFile,
913918
updateSourceFile,
919+
createRedirectedSourceFile,
914920
createBundle,
915921
updateBundle,
916922
createUnparsedSource,
@@ -1138,23 +1144,16 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode
11381144
// Identifiers
11391145
//
11401146

1141-
function createBaseIdentifier(text: string, originalKeywordKind: SyntaxKind | undefined) {
1142-
if (originalKeywordKind === undefined && text) {
1143-
originalKeywordKind = stringToToken(text);
1144-
}
1145-
if (originalKeywordKind === SyntaxKind.Identifier) {
1146-
originalKeywordKind = undefined;
1147-
}
1147+
function createBaseIdentifier(escapedText: __String, originalKeywordKind: SyntaxKind | undefined) {
11481148
const node = baseFactory.createBaseIdentifierNode(SyntaxKind.Identifier) as Mutable<Identifier>;
11491149
node.originalKeywordKind = originalKeywordKind;
1150-
node.escapedText = escapeLeadingUnderscores(text);
1151-
1152-
node.flowNode = undefined; // initialized by binder (FlowContainer)
1150+
node.escapedText = escapedText;
1151+
node.autoGenerateFlags = GeneratedIdentifierFlags.None;
11531152
return node;
11541153
}
11551154

11561155
function createBaseGeneratedIdentifier(text: string, autoGenerateFlags: GeneratedIdentifierFlags, prefix: string | GeneratedNamePart | undefined, suffix: string | undefined) {
1157-
const node = createBaseIdentifier(text, /*originalKeywordKind*/ undefined) as Mutable<GeneratedIdentifier>;
1156+
const node = createBaseIdentifier(escapeLeadingUnderscores(text), /*originalKeywordKind*/ undefined) as Mutable<GeneratedIdentifier>;
11581157
node.autoGenerateFlags = autoGenerateFlags;
11591158
node.autoGenerateId = nextAutoGenerateId;
11601159
node.autoGeneratePrefix = prefix;
@@ -1165,22 +1164,29 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode
11651164

11661165
// @api
11671166
function createIdentifier(text: string, typeArguments?: readonly (TypeNode | TypeParameterDeclaration)[], originalKeywordKind?: SyntaxKind, hasExtendedUnicodeEscape?: boolean): Identifier {
1168-
const node = createBaseIdentifier(text, originalKeywordKind);
1169-
node.typeArguments = undefined;
1170-
if (typeArguments) {
1171-
// NOTE: we do not include transform flags of typeArguments in an identifier as they do not contribute to transformations
1172-
node.typeArguments = createNodeArray(typeArguments);
1167+
if (originalKeywordKind === undefined && text) {
1168+
originalKeywordKind = stringToToken(text);
1169+
}
1170+
if (originalKeywordKind === SyntaxKind.Identifier) {
1171+
originalKeywordKind = undefined;
11731172
}
1173+
1174+
const node = createBaseIdentifier(escapeLeadingUnderscores(text), originalKeywordKind);
1175+
node.typeArguments = asNodeArray(typeArguments);
1176+
node.hasExtendedUnicodeEscape = hasExtendedUnicodeEscape;
1177+
node.jsDoc = undefined; // initialized by parser (JsDocContainer)
1178+
node.jsDocCache = undefined; // initialized by parser (JsDocContainer)
1179+
node.flowNode = undefined; // initialized by binder (FlowContainer)
1180+
node.symbol = undefined!; // initialized by checker
1181+
1182+
// NOTE: we do not include transform flags of typeArguments in an identifier as they do not contribute to transformations
11741183
if (node.originalKeywordKind === SyntaxKind.AwaitKeyword) {
11751184
node.transformFlags |= TransformFlags.ContainsPossibleTopLevelAwait;
11761185
}
1177-
if (hasExtendedUnicodeEscape) {
1178-
node.hasExtendedUnicodeEscape = hasExtendedUnicodeEscape;
1186+
if (node.hasExtendedUnicodeEscape) {
11791187
node.transformFlags |= TransformFlags.ContainsES2015;
11801188
}
11811189

1182-
node.jsDoc = undefined; // initialized by parser (JsDocContainer)
1183-
node.jsDocCache = undefined; // initialized by parser (JsDocContainer)
11841190
return node;
11851191
}
11861192

@@ -1231,21 +1237,22 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode
12311237
return name;
12321238
}
12331239

1234-
function createBasePrivateIdentifier(text: string) {
1240+
function createBasePrivateIdentifier(escapedText: __String) {
12351241
const node = baseFactory.createBasePrivateIdentifierNode(SyntaxKind.PrivateIdentifier) as Mutable<PrivateIdentifier>;
1236-
node.escapedText = escapeLeadingUnderscores(text);
1242+
node.escapedText = escapedText;
1243+
node.autoGenerateFlags = GeneratedIdentifierFlags.None;
12371244
node.transformFlags |= TransformFlags.ContainsClassFields;
12381245
return node;
12391246
}
12401247

12411248
// @api
12421249
function createPrivateIdentifier(text: string): PrivateIdentifier {
12431250
if (!startsWith(text, "#")) Debug.fail("First character of private identifier must be #: " + text);
1244-
return createBasePrivateIdentifier(text);
1251+
return createBasePrivateIdentifier(escapeLeadingUnderscores(text));
12451252
}
12461253

12471254
function createBaseGeneratedPrivateIdentifier(text: string, autoGenerateFlags: GeneratedIdentifierFlags, prefix: string | GeneratedNamePart | undefined, suffix: string | undefined) {
1248-
const node = createBasePrivateIdentifier(text);
1255+
const node = createBasePrivateIdentifier(escapeLeadingUnderscores(text));
12491256
node.autoGenerateFlags = autoGenerateFlags;
12501257
node.autoGenerateId = nextAutoGenerateId;
12511258
node.autoGeneratePrefix = prefix;
@@ -1469,6 +1476,7 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode
14691476
node.default = defaultType;
14701477
node.transformFlags = TransformFlags.ContainsTypeScript;
14711478

1479+
node.expression = undefined; // initialized by parser to report grammar errors
14721480
node.jsDoc = undefined; // initialized by parser (JsDocContainer)
14731481
node.jsDocCache = undefined; // initialized by parser (JsDocContainer)
14741482
return node;
@@ -2090,6 +2098,7 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode
20902098
node.type = type!; // TODO(rbuckton): We mark this as required in IndexSignatureDeclaration, but it looks like the parser allows it to be elided.
20912099
node.transformFlags = TransformFlags.ContainsTypeScript;
20922100

2101+
node.illegalDecorators = undefined; // initialized by parser to report grammar errors
20932102
node.jsDoc = undefined; // initialized by parser (JsDocContainer)
20942103
node.jsDocCache = undefined; // initialized by parser (JsDocContainer)
20952104
node.locals = undefined; // initialized by binder (LocalsContainer)
@@ -2191,6 +2200,7 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode
21912200
node.jsDocCache = undefined; // initialized by parser (JsDocContainer)
21922201
node.locals = undefined; // initialized by binder (LocalsContainer)
21932202
node.nextContainer = undefined; // initialized by binder (LocalsContainer)
2203+
node.typeArguments = undefined; // used in quick info
21942204
return node;
21952205
}
21962206

@@ -4101,6 +4111,7 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode
41014111
node.jsDoc = undefined; // initialized by parser (JsDocContainer)
41024112
node.jsDocCache = undefined; // initialized by parser (JsDocContainer)
41034113
node.flowNode = undefined; // initialized by binder (FlowContainer)
4114+
node.possiblyExhaustive = false; // initialized by binder
41044115
return node;
41054116
}
41064117

@@ -6006,20 +6017,102 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode
60066017
node.statements = createNodeArray(statements);
60076018
node.endOfFileToken = endOfFileToken;
60086019
node.flags |= flags;
6009-
node.fileName = "";
60106020
node.text = "";
6021+
node.fileName = "";
6022+
node.path = "" as Path;
6023+
node.resolvedPath = "" as Path;
6024+
node.originalFileName = "";
60116025
node.languageVersion = 0;
60126026
node.languageVariant = 0;
60136027
node.scriptKind = 0;
60146028
node.isDeclarationFile = false;
60156029
node.hasNoDefaultLib = false;
6030+
60166031
node.transformFlags |=
60176032
propagateChildrenFlags(node.statements) |
60186033
propagateChildFlags(node.endOfFileToken);
60196034

60206035
node.locals = undefined; // initialized by binder (LocalsContainer)
60216036
node.nextContainer = undefined; // initialized by binder (LocalsContainer)
60226037
node.endFlowNode = undefined;
6038+
6039+
node.nodeCount = 0;
6040+
node.identifierCount = 0;
6041+
node.symbolCount = 0;
6042+
node.parseDiagnostics = undefined!;
6043+
node.bindDiagnostics = undefined!;
6044+
node.bindSuggestionDiagnostics = undefined;
6045+
node.lineMap = undefined!;
6046+
node.externalModuleIndicator = undefined;
6047+
node.setExternalModuleIndicator = undefined;
6048+
node.pragmas = undefined!;
6049+
node.checkJsDirective = undefined;
6050+
node.referencedFiles = undefined!;
6051+
node.typeReferenceDirectives = undefined!;
6052+
node.libReferenceDirectives = undefined!;
6053+
node.amdDependencies = undefined!;
6054+
node.commentDirectives = undefined;
6055+
node.identifiers = undefined!;
6056+
node.packageJsonLocations = undefined;
6057+
node.packageJsonScope = undefined;
6058+
node.imports = undefined!;
6059+
node.moduleAugmentations = undefined!;
6060+
node.ambientModuleNames = undefined!;
6061+
node.resolvedModules = undefined;
6062+
node.classifiableNames = undefined;
6063+
node.impliedNodeFormat = undefined;
6064+
return node;
6065+
}
6066+
6067+
function createRedirectedSourceFile(redirectInfo: RedirectInfo) {
6068+
const node: SourceFile = Object.create(redirectInfo.redirectTarget);
6069+
Object.defineProperties(node, {
6070+
id: {
6071+
get(this: SourceFile) { return this.redirectInfo!.redirectTarget.id; },
6072+
set(this: SourceFile, value: SourceFile["id"]) { this.redirectInfo!.redirectTarget.id = value; },
6073+
},
6074+
symbol: {
6075+
get(this: SourceFile) { return this.redirectInfo!.redirectTarget.symbol; },
6076+
set(this: SourceFile, value: SourceFile["symbol"]) { this.redirectInfo!.redirectTarget.symbol = value; },
6077+
},
6078+
});
6079+
node.redirectInfo = redirectInfo;
6080+
return node;
6081+
}
6082+
6083+
function cloneRedirectedSourceFile(source: SourceFile) {
6084+
const node = createRedirectedSourceFile(source.redirectInfo!) as Mutable<SourceFile>;
6085+
node.flags |= source.flags & ~NodeFlags.Synthesized;
6086+
node.fileName = source.fileName;
6087+
node.path = source.path;
6088+
node.resolvedPath = source.resolvedPath;
6089+
node.originalFileName = source.originalFileName;
6090+
node.packageJsonLocations = source.packageJsonLocations;
6091+
node.packageJsonScope = source.packageJsonScope;
6092+
node.emitNode = undefined;
6093+
return node;
6094+
}
6095+
6096+
function cloneSourceFileWorker(source: SourceFile) {
6097+
// TODO: explicit property assignments instead of for..in
6098+
const node = baseFactory.createBaseSourceFileNode(SyntaxKind.SourceFile) as Mutable<SourceFile>;
6099+
node.flags |= source.flags & ~NodeFlags.Synthesized;
6100+
for (const p in source) {
6101+
if (hasProperty(node, p) || !hasProperty(source, p)) {
6102+
continue;
6103+
}
6104+
if (p === "emitNode") {
6105+
node.emitNode = undefined;
6106+
continue;
6107+
}
6108+
(node as any)[p] = (source as any)[p];
6109+
}
6110+
return node;
6111+
}
6112+
6113+
function cloneSourceFile(source: SourceFile) {
6114+
const node = source.redirectInfo ? cloneRedirectedSourceFile(source) : cloneSourceFileWorker(source);
6115+
setOriginalNode(node, source);
60236116
return node;
60246117
}
60256118

@@ -6032,14 +6125,8 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode
60326125
hasNoDefaultLib: boolean,
60336126
libReferences: readonly FileReference[]
60346127
) {
6035-
const node = (source.redirectInfo ? Object.create(source.redirectInfo.redirectTarget) : baseFactory.createBaseSourceFileNode(SyntaxKind.SourceFile)) as Mutable<SourceFile>;
6036-
for (const p in source) {
6037-
if (p === "emitNode" || hasProperty(node, p) || !hasProperty(source, p)) continue;
6038-
(node as any)[p] = (source as any)[p];
6039-
}
6040-
node.flags |= source.flags;
6128+
const node = cloneSourceFile(source);
60416129
node.statements = createNodeArray(statements);
6042-
node.endOfFileToken = source.endOfFileToken;
60436130
node.isDeclarationFile = isDeclarationFile;
60446131
node.referencedFiles = referencedFiles;
60456132
node.typeReferenceDirectives = typeReferences;
@@ -6048,7 +6135,6 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode
60486135
node.transformFlags =
60496136
propagateChildrenFlags(node.statements) |
60506137
propagateChildFlags(node.endOfFileToken);
6051-
node.impliedNodeFormat = source.impliedNodeFormat;
60526138
return node;
60536139
}
60546140

@@ -6077,6 +6163,10 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode
60776163
const node = createBaseNode<Bundle>(SyntaxKind.Bundle);
60786164
node.prepends = prepends;
60796165
node.sourceFiles = sourceFiles;
6166+
node.syntheticFileReferences = undefined;
6167+
node.syntheticTypeReferences = undefined;
6168+
node.syntheticLibReferences = undefined;
6169+
node.hasNoDefaultLib = undefined;
60806170
return node;
60816171
}
60826172

@@ -6275,6 +6365,52 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode
62756365
: node;
62766366
}
62776367

6368+
function cloneGeneratedIdentifier(node: GeneratedIdentifier): GeneratedIdentifier {
6369+
const clone = createBaseIdentifier(node.escapedText, /*originalKeywordKind*/ undefined) as Mutable<GeneratedIdentifier>;
6370+
clone.flags |= node.flags & ~NodeFlags.Synthesized;
6371+
clone.autoGenerateFlags = node.autoGenerateFlags;
6372+
clone.autoGenerateId = node.autoGenerateId;
6373+
clone.autoGeneratePrefix = node.autoGeneratePrefix;
6374+
clone.autoGenerateSuffix = node.autoGenerateSuffix;
6375+
clone.transformFlags = node.transformFlags;
6376+
setOriginalNode(clone, node);
6377+
return clone;
6378+
}
6379+
6380+
function cloneIdentifier(node: Identifier): Identifier {
6381+
const clone = createBaseIdentifier(node.escapedText, node.originalKeywordKind);
6382+
clone.flags |= node.flags & ~NodeFlags.Synthesized;
6383+
clone.typeArguments = node.typeArguments;
6384+
clone.hasExtendedUnicodeEscape = node.hasExtendedUnicodeEscape;
6385+
clone.jsDoc = node.jsDoc;
6386+
clone.jsDocCache = node.jsDocCache;
6387+
clone.flowNode = node.flowNode;
6388+
clone.symbol = node.symbol;
6389+
clone.transformFlags = node.transformFlags;
6390+
setOriginalNode(clone, node);
6391+
return clone;
6392+
}
6393+
6394+
function cloneGeneratedPrivateIdentifier(node: GeneratedPrivateIdentifier): GeneratedPrivateIdentifier {
6395+
const clone = createBasePrivateIdentifier(node.escapedText) as Mutable<GeneratedPrivateIdentifier>;
6396+
clone.flags |= node.flags & ~NodeFlags.Synthesized;
6397+
clone.autoGenerateFlags = node.autoGenerateFlags;
6398+
clone.autoGenerateId = node.autoGenerateId;
6399+
clone.autoGeneratePrefix = node.autoGeneratePrefix;
6400+
clone.autoGenerateSuffix = node.autoGenerateSuffix;
6401+
clone.transformFlags = node.transformFlags;
6402+
setOriginalNode(clone, node);
6403+
return clone;
6404+
}
6405+
6406+
function clonePrivateIdentifier(node: PrivateIdentifier): PrivateIdentifier {
6407+
const clone = createBasePrivateIdentifier(node.escapedText);
6408+
clone.flags |= node.flags & ~NodeFlags.Synthesized;
6409+
clone.transformFlags = node.transformFlags;
6410+
setOriginalNode(clone, node);
6411+
return clone;
6412+
}
6413+
62786414
// @api
62796415
function cloneNode<T extends Node | undefined>(node: T): T;
62806416
function cloneNode<T extends Node>(node: T) {
@@ -6284,11 +6420,23 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode
62846420
if (node === undefined) {
62856421
return node;
62866422
}
6423+
if (isSourceFile(node)) {
6424+
return cloneSourceFile(node) as T & SourceFile;
6425+
}
6426+
if (isGeneratedIdentifier(node)) {
6427+
return cloneGeneratedIdentifier(node) as T & GeneratedIdentifier;
6428+
}
6429+
if (isIdentifier(node)) {
6430+
return cloneIdentifier(node) as T & Identifier;
6431+
}
6432+
if (isGeneratedPrivateIdentifier(node)) {
6433+
return cloneGeneratedPrivateIdentifier(node) as T & GeneratedPrivateIdentifier;
6434+
}
6435+
if (isPrivateIdentifier(node)) {
6436+
return clonePrivateIdentifier(node) as T & PrivateIdentifier;
6437+
}
62876438

62886439
const clone =
6289-
isSourceFile(node) ? baseFactory.createBaseSourceFileNode(SyntaxKind.SourceFile) as T :
6290-
isIdentifier(node) ? baseFactory.createBaseIdentifierNode(SyntaxKind.Identifier) as T :
6291-
isPrivateIdentifier(node) ? baseFactory.createBasePrivateIdentifierNode(SyntaxKind.PrivateIdentifier) as T :
62926440
!isNodeKind(node.kind) ? baseFactory.createBaseTokenNode(node.kind) as T :
62936441
baseFactory.createBaseNode(node.kind) as T;
62946442

0 commit comments

Comments
 (0)