From 211b0567f0b62d41d714e4e5f13c8c6f03c97f6a Mon Sep 17 00:00:00 2001 From: Titian Cernicova-Dragomir Date: Wed, 29 Nov 2023 07:25:55 -0500 Subject: [PATCH 1/5] Improve declaration emit type safety. Signed-off-by: Titian Cernicova-Dragomir --- src/compiler/transformers/declarations.ts | 118 +++++++----------- .../transformers/declarations/emitResolver.ts | 6 +- .../declarations/localInferenceResolver.ts | 50 ++++---- .../declarations/transpileDeclaration.ts | 55 ++------ .../transformers/declarations/types.ts | 58 +++------ src/compiler/types.ts | 37 +++--- src/compiler/visitorPublic.ts | 50 ++++---- tests/baselines/reference/api/typescript.d.ts | 18 +-- 8 files changed, 152 insertions(+), 240 deletions(-) diff --git a/src/compiler/transformers/declarations.ts b/src/compiler/transformers/declarations.ts index c84c407c97f7c..48a063a0a5344 100644 --- a/src/compiler/transformers/declarations.ts +++ b/src/compiler/transformers/declarations.ts @@ -23,6 +23,7 @@ import { ConstructorTypeNode, ConstructSignatureDeclaration, contains, + CoreEmitResolver, createDiagnosticForNode, createDiagnosticForRange, createEmptyExports, @@ -46,7 +47,6 @@ import { EnumDeclaration, ExportAssignment, ExportDeclaration, - Expression, ExpressionWithTypeArguments, factory, FileReference, @@ -139,7 +139,7 @@ import { isMethodSignature, isModifier, isModuleDeclaration, - IsolatedEmitResolver, + IsolatedTransformationContext, isOmittedExpression, isPrivateIdentifier, isPropertySignature, @@ -167,7 +167,6 @@ import { LateBoundDeclaration, LateVisibilityPaintedStatement, length, - LocalInferenceResolver, map, mapDefined, MethodDeclaration, @@ -293,7 +292,7 @@ const declarationEmitNodeBuilderFlags = NodeBuilderFlags.MultilineObjectLiterals * * @internal */ -export function transformDeclarations(context: TransformationContext, _useTscEmit = true) { +export function transformDeclarations(context: (TransformationContext & { useLocalInferenceTypePrint?: false; }) | IsolatedTransformationContext) { const throwDiagnostic = () => Debug.fail("Diagnostic emitted without context"); let getSymbolAccessibilityDiagnostic: GetSymbolAccessibilityDiagnostic = throwDiagnostic; let needsDeclare = true; @@ -318,70 +317,42 @@ export function transformDeclarations(context: TransformationContext, _useTscEmi let refs: Map; let libs: Map; let emittedImports: readonly AnyImportSyntax[] | undefined; // must be declared in container so it can be `undefined` while transformer's first pass - const { localInferenceResolver, isolatedDeclarations, host, resolver, symbolTracker, ensureNoInitializer, useTscEmit } = createTransformerServices(); + const { localInferenceResolver, isolatedDeclarations, host, resolver, symbolTracker, ensureNoInitializer, useLocalInferenceTypePrint } = createTransformerServices(); const options = context.getCompilerOptions(); const { noResolve, stripInternal } = options; return transformRoot; - function createTransformerServices(): { - isolatedDeclarations: true; - useTscEmit: false; - resolver: IsolatedEmitResolver; - localInferenceResolver: LocalInferenceResolver; - host: undefined; - symbolTracker: undefined; - ensureNoInitializer: (node: CanHaveLiteralInitializer) => Expression | undefined; - } | { - isolatedDeclarations: true; - useTscEmit: true; - resolver: EmitResolver; - localInferenceResolver: LocalInferenceResolver; - host: EmitHost; - symbolTracker: SymbolTracker; - ensureNoInitializer: (node: CanHaveLiteralInitializer) => Expression | undefined; - } | { - isolatedDeclarations: false; - useTscEmit: false; - resolver: EmitResolver; - localInferenceResolver: undefined; - host: EmitHost; - symbolTracker: SymbolTracker; - ensureNoInitializer: (node: CanHaveLiteralInitializer) => Expression | undefined; - } { - const { isolatedDeclarations, resolver: localInferenceResolver } = createLocalInferenceResolver({ - ensureParameter, - context, - visitDeclarationSubtree, - setEnclosingDeclarations(node) { - const oldNode = enclosingDeclaration; - enclosingDeclaration = node; - return oldNode; - }, - checkEntityNameVisibility(name, container) { - return checkEntityNameVisibility(name, container ?? enclosingDeclaration); - }, - }); + function createTransformerServices() { + const isolatedDeclarations = context.getCompilerOptions().isolatedDeclarations; if (isolatedDeclarations) { - if (!_useTscEmit) { - const resolver: IsolatedEmitResolver = context.getEmitResolver(); + const localInferenceResolver = createLocalInferenceResolver({ + ensureParameter, + context, + visitDeclarationSubtree, + setEnclosingDeclarations(node) { + const oldNode = enclosingDeclaration; + enclosingDeclaration = node; + return oldNode; + }, + checkEntityNameVisibility(name, container) { + return checkEntityNameVisibility(name, container ?? enclosingDeclaration); + }, + }); + if (context.useLocalInferenceTypePrint) { + const resolver: CoreEmitResolver = context.getEmitResolver(); // Ideally nothing should require the symbol tracker in isolated declarations mode. // createLiteralConstValue is the one exception const emptySymbolTracker = {}; return { isolatedDeclarations, - useTscEmit: false, + useLocalInferenceTypePrint: true, resolver, localInferenceResolver, symbolTracker: undefined, host: undefined, - ensureNoInitializer: (node: CanHaveLiteralInitializer) => { - if (shouldPrintWithInitializer(node)) { - return resolver.createLiteralConstValue(getParseTreeNode(node) as CanHaveLiteralInitializer, emptySymbolTracker); // TODO: Make safe - } - return undefined; - }, - }; + ensureNoInitializer: createEnsureNoInitializer(emptySymbolTracker), + } as const; } else { const host = context.getEmitHost(); @@ -389,37 +360,37 @@ export function transformDeclarations(context: TransformationContext, _useTscEmi const symbolTracker = createSymbolTracker(resolver, host); return { isolatedDeclarations, - useTscEmit: true, + useLocalInferenceTypePrint: false, resolver, localInferenceResolver, symbolTracker, host, - ensureNoInitializer: (node: CanHaveLiteralInitializer) => { - if (shouldPrintWithInitializer(node)) { - return resolver.createLiteralConstValue(getParseTreeNode(node) as CanHaveLiteralInitializer, symbolTracker); // TODO: Make safe - } - return undefined; - }, - }; + ensureNoInitializer: createEnsureNoInitializer(symbolTracker), + } as const; } } else { + Debug.assert(!context.useLocalInferenceTypePrint); const host = context.getEmitHost(); const resolver = context.getEmitResolver(); const symbolTracker: SymbolTracker = createSymbolTracker(resolver, host); return { - isolatedDeclarations, - useTscEmit: false, - localInferenceResolver, + isolatedDeclarations: false, + useLocalInferenceTypePrint: false, + localInferenceResolver: undefined, resolver, symbolTracker, host, - ensureNoInitializer: (node: CanHaveLiteralInitializer) => { - if (shouldPrintWithInitializer(node)) { - return resolver.createLiteralConstValue(getParseTreeNode(node) as CanHaveLiteralInitializer, symbolTracker); // TODO: Make safe - } - return undefined; - }, + ensureNoInitializer: createEnsureNoInitializer(symbolTracker), + } as const; + } + + function createEnsureNoInitializer(symbolTracker: SymbolTracker) { + return function ensureNoInitializer(node: CanHaveLiteralInitializer) { + if (shouldPrintWithInitializer(node)) { + return resolver.createLiteralConstValue(getParseTreeNode(node) as CanHaveLiteralInitializer, symbolTracker); // TODO: Make safe + } + return undefined; }; } } @@ -659,6 +630,7 @@ export function transformDeclarations(context: TransformationContext, _useTscEmi libs = new Map(); existingTypeReferencesSources = node.sourceFiles; let hasNoDefaultLib = false; + Debug.assert(!isolatedDeclarations, "Bundles are not supported in isolated declarations"); const bundle = factory.createBundle( map(node.sourceFiles, sourceFile => { if (sourceFile.isDeclarationFile) return undefined!; // Omit declaration files from bundle results, too // TODO: GH#18217 @@ -681,7 +653,7 @@ export function transformDeclarations(context: TransformationContext, _useTscEmi sourceFile, [factory.createModuleDeclaration( [factory.createModifier(SyntaxKind.DeclareKeyword)], - factory.createStringLiteral(getResolvedExternalModuleName(context.getEmitHost(), sourceFile)), + factory.createStringLiteral(getResolvedExternalModuleName(host, sourceFile)), factory.createModuleBlock(setTextRange(factory.createNodeArray(transformAndReplaceLatePaintedStatements(statements)), sourceFile.statements)), )], /*isDeclarationFile*/ true, @@ -952,7 +924,7 @@ export function transformDeclarations(context: TransformationContext, _useTscEmi } if (isolatedDeclarations) { const { typeNode, isInvalid } = localInferenceResolver.fromInitializer(node, type, currentSourceFile); - if (!useTscEmit || isInvalid) { + if (useLocalInferenceTypePrint || isInvalid) { return typeNode; } } @@ -1121,7 +1093,7 @@ export function transformDeclarations(context: TransformationContext, _useTscEmi if (isBundledEmit) { // Bundle emit not supported for isolatedDeclarations if (!isolatedDeclarations) { - const newName = getExternalModuleNameFromDeclaration(context.getEmitHost(), resolver, parent); + const newName = getExternalModuleNameFromDeclaration(host, resolver, parent); if (newName) { return factory.createStringLiteral(newName); } diff --git a/src/compiler/transformers/declarations/emitResolver.ts b/src/compiler/transformers/declarations/emitResolver.ts index 9309b193717be..1c9f21f9bb8a6 100644 --- a/src/compiler/transformers/declarations/emitResolver.ts +++ b/src/compiler/transformers/declarations/emitResolver.ts @@ -1,6 +1,7 @@ import { bindSourceFileForDeclarationEmit, ComputedPropertyName, + CoreEmitResolver, createEntityVisibilityChecker, createEvaluator, Debug, @@ -39,7 +40,6 @@ import { isIdentifier, isInfinityOrNaNString, isNumericLiteral, - IsolatedEmitResolver, isPrefixUnaryExpression, isPrimitiveLiteralValue, isPropertyAccessExpression, @@ -70,7 +70,7 @@ import { } from "../../_namespaces/ts"; /** @internal */ -export function createEmitDeclarationResolver(file: SourceFile): IsolatedEmitResolver { +export function createEmitDeclarationResolver(file: SourceFile): CoreEmitResolver { const { getNodeLinks, resolveMemberKey, resolveName, resolveEntityName } = bindSourceFileForDeclarationEmit(file); const { isEntityNameVisible } = createEntityVisibilityChecker({ @@ -394,4 +394,4 @@ export function createEmitDeclarationResolver(file: SourceFile): IsolatedEmitRes return false; } -} + } diff --git a/src/compiler/transformers/declarations/localInferenceResolver.ts b/src/compiler/transformers/declarations/localInferenceResolver.ts index a675271b2122b..64fb78caf2acd 100644 --- a/src/compiler/transformers/declarations/localInferenceResolver.ts +++ b/src/compiler/transformers/declarations/localInferenceResolver.ts @@ -31,6 +31,7 @@ import { isMethodOrAccessor, isNoSubstitutionTemplateLiteral, isNumericLiteral, + IsolatedTransformationContext, isOmittedExpression, isOptionalDeclaration, isParameter, @@ -120,44 +121,39 @@ export function createLocalInferenceResolver({ visitDeclarationSubtree(input: Node): VisitResult; checkEntityNameVisibility(name: EntityNameOrEntityNameExpression, container?: Node): void; ensureParameter(p: ParameterDeclaration): ParameterDeclaration; - context: TransformationContext; -}): { resolver: LocalInferenceResolver; isolatedDeclarations: true; } | { resolver: undefined; isolatedDeclarations: false; } { + context: IsolatedTransformationContext | TransformationContext; +}): LocalInferenceResolver { let currentSourceFile: SourceFile; const options = context.getCompilerOptions(); const resolver = context.getEmitResolver(); - if (!options.isolatedDeclarations) { - return { resolver: undefined, isolatedDeclarations: false }; - } + Debug.assert(options.isolatedDeclarations, "createLocalInferenceResolver can only be called when isolatedDeclarations is true"); const { factory } = context; let inferenceContext: { isInvalid: boolean; disableErrors: boolean; } = undefined!; const strictNullChecks = !!options.strict || !!options.strictNullChecks; return { - resolver: { - fromInitializer(node: HasInferredType | ExportAssignment, type: TypeNode | undefined, sourceFile: SourceFile) { - const oldSourceFile = currentSourceFile; - const hasExistingContext = inferenceContext !== undefined; - if (!hasExistingContext) { - inferenceContext = { isInvalid: false, disableErrors: false }; - } - currentSourceFile = sourceFile; - try { - const typeNode = localInferenceFromInitializer(node, type); - if (typeNode !== undefined) { - return { isInvalid: inferenceContext.isInvalid, typeNode }; - } - return { isInvalid: true, typeNode: invalid(node) }; + fromInitializer(node: HasInferredType | ExportAssignment, type: TypeNode | undefined, sourceFile: SourceFile) { + const oldSourceFile = currentSourceFile; + const hasExistingContext = inferenceContext !== undefined; + if (!hasExistingContext) { + inferenceContext = { isInvalid: false, disableErrors: false }; + } + currentSourceFile = sourceFile; + try { + const typeNode = localInferenceFromInitializer(node, type); + if (typeNode !== undefined) { + return { isInvalid: inferenceContext.isInvalid, typeNode }; } - finally { - currentSourceFile = oldSourceFile; - if (!hasExistingContext) { - inferenceContext = undefined!; - } + return { isInvalid: true, typeNode: invalid(node) }; + } + finally { + currentSourceFile = oldSourceFile; + if (!hasExistingContext) { + inferenceContext = undefined!; } - }, - makeInvalidType, + } }, - isolatedDeclarations: options.isolatedDeclarations, + makeInvalidType, }; function hasParseError(node: Node) { return !!(node.flags & NodeFlags.ThisNodeHasError); diff --git a/src/compiler/transformers/declarations/transpileDeclaration.ts b/src/compiler/transformers/declarations/transpileDeclaration.ts index bddb4afb78989..e117840b4d4ca 100644 --- a/src/compiler/transformers/declarations/transpileDeclaration.ts +++ b/src/compiler/transformers/declarations/transpileDeclaration.ts @@ -11,7 +11,6 @@ import { Diagnostic, EmitHost, ensureTrailingDirectorySeparator, - factory, getAreDeclarationMapsEnabled, getBaseFileName, getDeclarationEmitOutputFilePathWorker, @@ -22,74 +21,44 @@ import { getSourceFilePathInNewDir, normalizePath, normalizeSlashes, + nullTransformationContext, PrinterOptions, SourceFile, SourceMapGenerator, sys, - TransformationContext, transformDeclarations, TranspileDeclarationsOptions, TranspileDeclarationsOutput, } from "../../_namespaces/ts"; -function createEmitDeclarationHost(options: TranspileDeclarationsOptions): EmitHost { - const throws = () => Debug.fail("Function should not be called in isolated declarations emit"); - return { - getCurrentDirectory: () => options.currentDirectory ?? ".", - getCanonicalFileName: createGetCanonicalFileName(sys.useCaseSensitiveFileNames), - useCaseSensitiveFileNames: () => !!options.useCaseSensitiveFileNames, - getCompilerOptions: () => options.compilerOptions, - getCommonSourceDirectory: () => ensureTrailingDirectorySeparator(options.commonSourceDirectory ?? "."), - get redirectTargetsMap(): never { - Debug.fail("redirectTargetsMap should not be used in isolated declarations"); - return undefined!; // Need return despite fail call GH#52214 - }, - directoryExists: throws, - fileExists: throws, - readFile: throws, - realpath: throws, - getLibFileFromReference: throws, - getSourceFileFromReference: throws, - isSourceOfProjectReferenceRedirect: throws, - - getSourceFiles: throws, - isEmitBlocked: throws, - getPrependNodes: throws, - writeFile: throws, - getBuildInfo: throws, - getSourceFile: throws, - getSourceFileByPath: throws, - getProjectReferenceRedirect: throws, - getFileIncludeReasons: throws, - isSourceFileFromExternalLibrary: throws, - getResolvedProjectReferenceToRedirect: throws, - }; -} - export function transpileDeclaration(sourceFile: SourceFile, transpileOptions: TranspileDeclarationsOptions): TranspileDeclarationsOutput { const compilerOptions: CompilerOptions = { ...transpileOptions.compilerOptions, isolatedDeclarations: true, traceResolution: false, }; - const emitHost = createEmitDeclarationHost(transpileOptions); + const emitHost = { + getCurrentDirectory: () => transpileOptions.currentDirectory ?? ".", + getCanonicalFileName: createGetCanonicalFileName(!!compilerOptions.useCaseSensitiveFileNames), + useCaseSensitiveFileNames: () => !!compilerOptions.useCaseSensitiveFileNames, + getCompilerOptions: () => compilerOptions.compilerOptions, + getCommonSourceDirectory: () => ensureTrailingDirectorySeparator(transpileOptions.commonSourceDirectory ?? "."), + }; const emitResolver = createEmitDeclarationResolver(sourceFile); const diagnostics: Diagnostic[] = []; const transformer = transformDeclarations({ - getEmitHost() { - return emitHost; - }, + useLocalInferenceTypePrint: true, + ...nullTransformationContext, getEmitResolver() { return emitResolver; }, getCompilerOptions() { - return emitHost.getCompilerOptions(); + return compilerOptions; }, - factory, addDiagnostic(diag: any) { diagnostics.push(diag); }, - } as TransformationContext, /*useTscEmit*/ false); + }); const result = transformer(sourceFile); const printer = createPrinter({ diff --git a/src/compiler/transformers/declarations/types.ts b/src/compiler/transformers/declarations/types.ts index 8401469892efa..4497b297ea574 100644 --- a/src/compiler/transformers/declarations/types.ts +++ b/src/compiler/transformers/declarations/types.ts @@ -1,51 +1,21 @@ import { - AccessorDeclaration, - AllAccessorDeclarations, - AnyImportSyntax, - ComputedPropertyName, - Declaration, - ElementAccessExpression, - EntityNameOrEntityNameExpression, - EnumMember, - Expression, - FunctionDeclaration, - ImportDeclaration, - LateBoundDeclaration, - Node, - ParameterDeclaration, - PropertyAccessExpression, - PropertyDeclaration, - PropertySignature, - ResolutionMode, - SignatureDeclaration, - StringLiteralLike, - Symbol, - SymbolTracker, - SymbolVisibilityResult, - VariableDeclaration, + CompilerOptions, + CoreEmitResolver, + CoreTransformationContext, + Diagnostic, + NodeFactory, } from "../../_namespaces/ts"; +/** @internal */ +export interface IsolatedTransformationContext extends CoreTransformationContext { + useLocalInferenceTypePrint: true; + getEmitResolver(): CoreEmitResolver; + getCompilerOptions(): CompilerOptions; + factory: NodeFactory; + addDiagnostic(diag: Diagnostic): void; +} + /** @internal */ export type MemberKey = string & { __memberKey: void; }; - -/** @internal */ -export interface IsolatedEmitResolver { - isLiteralComputedName(node: ComputedPropertyName): boolean; - isDeclarationVisible(node: Declaration | AnyImportSyntax): boolean; - isLateBound(node: Declaration): node is LateBoundDeclaration; - isImplementationOfOverload(node: SignatureDeclaration): boolean | undefined; - isExpandoFunction(node: VariableDeclaration | FunctionDeclaration): boolean; - createLiteralConstValue(node: VariableDeclaration | PropertyDeclaration | PropertySignature | ParameterDeclaration, tracker: SymbolTracker): Expression; - isEntityNameVisible(entityName: EntityNameOrEntityNameExpression, enclosingDeclaration: Node): SymbolVisibilityResult; - isOptionalParameter(node: ParameterDeclaration): boolean; - getTypeReferenceDirectivesForEntityName(name: EntityNameOrEntityNameExpression): [specifier: string, mode: ResolutionMode | undefined][] | undefined; - isLiteralConstDeclaration(node: VariableDeclaration | PropertyDeclaration | PropertySignature | ParameterDeclaration): boolean; - getSymbolOfExternalModuleSpecifier(node: StringLiteralLike): Symbol | undefined; - isImportRequiredByAugmentation(decl: ImportDeclaration): boolean; - getConstantValue(node: EnumMember | PropertyAccessExpression | ElementAccessExpression): string | number | undefined; - getAllAccessorDeclarations(declaration: AccessorDeclaration): AllAccessorDeclarations; - tryFindAmbientModule(moduleReferenceExpression: Expression): Symbol | undefined; - getPropertiesOfContainerFunction(node: FunctionDeclaration | VariableDeclaration): Symbol[] -} diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 6f04cdd0470e8..f6aaeedb3094f 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -5678,8 +5678,28 @@ export enum TypeReferenceSerializationKind { ObjectType, } + +/** @internal */ +export interface CoreEmitResolver { + isLiteralComputedName(node: ComputedPropertyName): boolean; + isDeclarationVisible(node: Declaration | AnyImportSyntax): boolean; + isLateBound(node: Declaration): node is LateBoundDeclaration; + isImplementationOfOverload(node: SignatureDeclaration): boolean | undefined; + isExpandoFunction(node: VariableDeclaration | FunctionDeclaration): boolean; + createLiteralConstValue(node: VariableDeclaration | PropertyDeclaration | PropertySignature | ParameterDeclaration, tracker: SymbolTracker): Expression; + isEntityNameVisible(entityName: EntityNameOrEntityNameExpression, enclosingDeclaration: Node): SymbolVisibilityResult; + isOptionalParameter(node: ParameterDeclaration): boolean; + getTypeReferenceDirectivesForEntityName(name: EntityNameOrEntityNameExpression): [specifier: string, mode: ResolutionMode | undefined][] | undefined; + isLiteralConstDeclaration(node: VariableDeclaration | PropertyDeclaration | PropertySignature | ParameterDeclaration): boolean; + getSymbolOfExternalModuleSpecifier(node: StringLiteralLike): Symbol | undefined; + isImportRequiredByAugmentation(decl: ImportDeclaration): boolean; + getConstantValue(node: EnumMember | PropertyAccessExpression | ElementAccessExpression): string | number | undefined; + getAllAccessorDeclarations(declaration: AccessorDeclaration): AllAccessorDeclarations; + tryFindAmbientModule(moduleReferenceExpression: Expression): Symbol | undefined; + getPropertiesOfContainerFunction(node: FunctionDeclaration | VariableDeclaration): Symbol[] +} /** @internal */ -export interface EmitResolver { +export interface EmitResolver extends CoreEmitResolver { hasGlobalName(name: string): boolean; getReferencedExportContainer(node: Identifier, prefixLocals?: boolean): SourceFile | ModuleDeclaration | EnumDeclaration | undefined; getReferencedImportDeclaration(node: Identifier): Declaration | undefined; @@ -5689,41 +5709,26 @@ export interface EmitResolver { isReferencedAliasDeclaration(node: Node, checkChildren?: boolean): boolean; isTopLevelValueImportEqualsWithEntityName(node: ImportEqualsDeclaration): boolean; getNodeCheckFlags(node: Node): NodeCheckFlags; - isDeclarationVisible(node: Declaration | AnyImportSyntax): boolean; - isLateBound(node: Declaration): node is LateBoundDeclaration; collectLinkedAliases(node: Identifier, setVisibility?: boolean): Node[] | undefined; - isImplementationOfOverload(node: SignatureDeclaration): boolean | undefined; isRequiredInitializedParameter(node: ParameterDeclaration): boolean; isOptionalUninitializedParameterProperty(node: ParameterDeclaration): boolean; - isExpandoFunction(node: FunctionDeclaration | VariableDeclaration): boolean; - getPropertiesOfContainerFunction(node: Declaration): Symbol[]; createTypeOfDeclaration(declaration: AccessorDeclaration | VariableLikeDeclaration | PropertyAccessExpression | ElementAccessExpression | BinaryExpression, enclosingDeclaration: Node, flags: NodeBuilderFlags, tracker: SymbolTracker, addUndefined?: boolean): TypeNode | undefined; createReturnTypeOfSignatureDeclaration(signatureDeclaration: SignatureDeclaration, enclosingDeclaration: Node, flags: NodeBuilderFlags, tracker: SymbolTracker): TypeNode | undefined; createTypeOfExpression(expr: Expression, enclosingDeclaration: Node, flags: NodeBuilderFlags, tracker: SymbolTracker): TypeNode | undefined; - createLiteralConstValue(node: VariableDeclaration | PropertyDeclaration | PropertySignature | ParameterDeclaration, tracker: SymbolTracker): Expression; isSymbolAccessible(symbol: Symbol, enclosingDeclaration: Node | undefined, meaning: SymbolFlags | undefined, shouldComputeAliasToMarkVisible: boolean): SymbolAccessibilityResult; - isEntityNameVisible(entityName: EntityNameOrEntityNameExpression, enclosingDeclaration: Node): SymbolVisibilityResult; // Returns the constant value this property access resolves to, or 'undefined' for a non-constant - getConstantValue(node: EnumMember | PropertyAccessExpression | ElementAccessExpression): string | number | undefined; getReferencedValueDeclaration(reference: Identifier): Declaration | undefined; getReferencedValueDeclarations(reference: Identifier): Declaration[] | undefined; getTypeReferenceSerializationKind(typeName: EntityName, location?: Node): TypeReferenceSerializationKind; - isOptionalParameter(node: ParameterDeclaration): boolean; moduleExportsSomeValue(moduleReferenceExpression: Expression): boolean; isArgumentsLocalBinding(node: Identifier): boolean; getExternalModuleFileFromDeclaration(declaration: ImportEqualsDeclaration | ImportDeclaration | ExportDeclaration | ModuleDeclaration | ImportTypeNode | ImportCall): SourceFile | undefined; - getTypeReferenceDirectivesForEntityName(name: EntityNameOrEntityNameExpression): [specifier: string, mode: ResolutionMode][] | undefined; getTypeReferenceDirectivesForSymbol(symbol: Symbol, meaning?: SymbolFlags): [specifier: string, mode: ResolutionMode][] | undefined; - isLiteralConstDeclaration(node: VariableDeclaration | PropertyDeclaration | PropertySignature | ParameterDeclaration | EnumMember): boolean; - isLiteralComputedName(name: ComputedPropertyName): boolean; getJsxFactoryEntity(location?: Node): EntityName | undefined; getJsxFragmentFactoryEntity(location?: Node): EntityName | undefined; - getAllAccessorDeclarations(declaration: AccessorDeclaration): AllAccessorDeclarations; - getSymbolOfExternalModuleSpecifier(node: StringLiteralLike): Symbol | undefined; isBindingCapturedByNode(node: Node, decl: VariableDeclaration | BindingElement): boolean; getDeclarationStatementsForSourceFile(node: SourceFile, flags: NodeBuilderFlags, tracker: SymbolTracker, bundled?: boolean): Statement[] | undefined; isImportRequiredByAugmentation(decl: ImportDeclaration): boolean; - tryFindAmbientModule(moduleReferenceExpression: Expression): Symbol | undefined; } // dprint-ignore diff --git a/src/compiler/visitorPublic.ts b/src/compiler/visitorPublic.ts index c5e99d170911c..2b2f8b31430ac 100644 --- a/src/compiler/visitorPublic.ts +++ b/src/compiler/visitorPublic.ts @@ -1,5 +1,6 @@ import { ConciseBody, + CoreTransformationContext, Debug, EmitFlags, Expression, @@ -99,7 +100,6 @@ import { some, Statement, SyntaxKind, - TransformationContext, Visitor, } from "./_namespaces/ts"; @@ -377,7 +377,7 @@ function visitArrayWorker( * Starts a new lexical environment and visits a statement list, ending the lexical environment * and merging hoisted declarations upon completion. */ -export function visitLexicalEnvironment(statements: NodeArray, visitor: Visitor, context: TransformationContext, start?: number, ensureUseStrict?: boolean, nodesVisitor: NodesVisitor = visitNodes) { +export function visitLexicalEnvironment(statements: NodeArray, visitor: Visitor, context: CoreTransformationContext, start?: number, ensureUseStrict?: boolean, nodesVisitor: NodesVisitor = visitNodes) { context.startLexicalEnvironment(); statements = nodesVisitor(statements, visitor, isStatement, start); if (ensureUseStrict) statements = context.factory.ensureUseStrict(statements); @@ -388,9 +388,9 @@ export function visitLexicalEnvironment(statements: NodeArray, visito * Starts a new lexical environment and visits a parameter list, suspending the lexical * environment upon completion. */ -export function visitParameterList(nodes: NodeArray, visitor: Visitor, context: TransformationContext, nodesVisitor?: NodesVisitor): NodeArray; -export function visitParameterList(nodes: NodeArray | undefined, visitor: Visitor, context: TransformationContext, nodesVisitor?: NodesVisitor): NodeArray | undefined; -export function visitParameterList(nodes: NodeArray | undefined, visitor: Visitor, context: TransformationContext, nodesVisitor = visitNodes) { +export function visitParameterList(nodes: NodeArray, visitor: Visitor, context: CoreTransformationContext, nodesVisitor?: NodesVisitor): NodeArray; +export function visitParameterList(nodes: NodeArray | undefined, visitor: Visitor, context: CoreTransformationContext, nodesVisitor?: NodesVisitor): NodeArray | undefined; +export function visitParameterList(nodes: NodeArray | undefined, visitor: Visitor, context: CoreTransformationContext, nodesVisitor = visitNodes) { let updated: NodeArray | undefined; context.startLexicalEnvironment(); if (nodes) { @@ -415,7 +415,7 @@ export function visitParameterList(nodes: NodeArray | unde return updated; } -function addDefaultValueAssignmentsIfNeeded(parameters: NodeArray, context: TransformationContext) { +function addDefaultValueAssignmentsIfNeeded(parameters: NodeArray, context: CoreTransformationContext) { let result: ParameterDeclaration[] | undefined; for (let i = 0; i < parameters.length; i++) { const parameter = parameters[i]; @@ -431,7 +431,7 @@ function addDefaultValueAssignmentsIfNeeded(parameters: NodeArray, visitor: * @param visitor The callback used to visit each child. * @param context A lexical environment context for the visitor. */ -export function visitEachChild(node: T, visitor: Visitor, context: TransformationContext): T; +export function visitEachChild(node: T, visitor: Visitor, context: CoreTransformationContext): T; /** @internal */ -export function visitEachChild(node: T, visitor: Visitor, context: TransformationContext, nodesVisitor?: NodesVisitor, tokenVisitor?: Visitor, nodeVisitor?: NodeVisitor): T; // eslint-disable-line @typescript-eslint/unified-signatures +export function visitEachChild(node: T, visitor: Visitor, context: CoreTransformationContext, nodesVisitor?: NodesVisitor, tokenVisitor?: Visitor, nodeVisitor?: NodeVisitor): T; // eslint-disable-line @typescript-eslint/unified-signatures /** * Visits each child of a Node using the supplied visitor, possibly returning a new Node of the same kind in its place. * @@ -590,10 +590,10 @@ export function visitEachChild(node: T, visitor: Visitor, contex * @param visitor The callback used to visit each child. * @param context A lexical environment context for the visitor. */ -export function visitEachChild(node: T | undefined, visitor: Visitor, context: TransformationContext, nodesVisitor?: typeof visitNodes, tokenVisitor?: Visitor): T | undefined; +export function visitEachChild(node: T | undefined, visitor: Visitor, context: CoreTransformationContext, nodesVisitor?: typeof visitNodes, tokenVisitor?: Visitor): T | undefined; /** @internal */ -export function visitEachChild(node: T | undefined, visitor: Visitor, context: TransformationContext, nodesVisitor?: NodesVisitor, tokenVisitor?: Visitor, nodeVisitor?: NodeVisitor): T | undefined; -export function visitEachChild(node: T | undefined, visitor: Visitor, context: TransformationContext, nodesVisitor = visitNodes, tokenVisitor?: Visitor, nodeVisitor: NodeVisitor = visitNode): T | undefined { +export function visitEachChild(node: T | undefined, visitor: Visitor, context: CoreTransformationContext, nodesVisitor?: NodesVisitor, tokenVisitor?: Visitor, nodeVisitor?: NodeVisitor): T | undefined; +export function visitEachChild(node: T | undefined, visitor: Visitor, context: CoreTransformationContext, nodesVisitor = visitNodes, tokenVisitor?: Visitor, nodeVisitor: NodeVisitor = visitNode): T | undefined { if (node === undefined) { return undefined; } @@ -602,7 +602,7 @@ export function visitEachChild(node: T | undefined, visitor: Vis return fn === undefined ? node : fn(node, visitor, context, nodesVisitor, nodeVisitor, tokenVisitor); } -type VisitEachChildFunction = (node: T, visitor: Visitor, context: TransformationContext, nodesVisitor: NodesVisitor, nodeVisitor: NodeVisitor, tokenVisitor: Visitor | undefined) => T; +type VisitEachChildFunction = (node: T, visitor: Visitor, context: CoreTransformationContext, nodesVisitor: NodesVisitor, nodeVisitor: NodeVisitor, tokenVisitor: Visitor | undefined) => T; // A type that correlates a `SyntaxKind` to a `VisitEachChildFunction`, for nodes in the `HasChildren` union. // This looks something like: diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index 8ff15c08e4a94..81890bc3694da 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -9828,32 +9828,32 @@ declare namespace ts { * Starts a new lexical environment and visits a statement list, ending the lexical environment * and merging hoisted declarations upon completion. */ - function visitLexicalEnvironment(statements: NodeArray, visitor: Visitor, context: TransformationContext, start?: number, ensureUseStrict?: boolean, nodesVisitor?: NodesVisitor): NodeArray; + function visitLexicalEnvironment(statements: NodeArray, visitor: Visitor, context: CoreTransformationContext, start?: number, ensureUseStrict?: boolean, nodesVisitor?: NodesVisitor): NodeArray; /** * Starts a new lexical environment and visits a parameter list, suspending the lexical * environment upon completion. */ - function visitParameterList(nodes: NodeArray, visitor: Visitor, context: TransformationContext, nodesVisitor?: NodesVisitor): NodeArray; - function visitParameterList(nodes: NodeArray | undefined, visitor: Visitor, context: TransformationContext, nodesVisitor?: NodesVisitor): NodeArray | undefined; + function visitParameterList(nodes: NodeArray, visitor: Visitor, context: CoreTransformationContext, nodesVisitor?: NodesVisitor): NodeArray; + function visitParameterList(nodes: NodeArray | undefined, visitor: Visitor, context: CoreTransformationContext, nodesVisitor?: NodesVisitor): NodeArray | undefined; /** * Resumes a suspended lexical environment and visits a function body, ending the lexical * environment and merging hoisted declarations upon completion. */ - function visitFunctionBody(node: FunctionBody, visitor: Visitor, context: TransformationContext): FunctionBody; + function visitFunctionBody(node: FunctionBody, visitor: Visitor, context: CoreTransformationContext): FunctionBody; /** * Resumes a suspended lexical environment and visits a function body, ending the lexical * environment and merging hoisted declarations upon completion. */ - function visitFunctionBody(node: FunctionBody | undefined, visitor: Visitor, context: TransformationContext): FunctionBody | undefined; + function visitFunctionBody(node: FunctionBody | undefined, visitor: Visitor, context: CoreTransformationContext): FunctionBody | undefined; /** * Resumes a suspended lexical environment and visits a concise body, ending the lexical * environment and merging hoisted declarations upon completion. */ - function visitFunctionBody(node: ConciseBody, visitor: Visitor, context: TransformationContext): ConciseBody; + function visitFunctionBody(node: ConciseBody, visitor: Visitor, context: CoreTransformationContext): ConciseBody; /** * Visits an iteration body, adding any block-scoped variables required by the transformation. */ - function visitIterationBody(body: Statement, visitor: Visitor, context: TransformationContext): Statement; + function visitIterationBody(body: Statement, visitor: Visitor, context: CoreTransformationContext): Statement; /** * Visits the elements of a {@link CommaListExpression}. * @param visitor The visitor to use when visiting expressions whose result will not be discarded at runtime. @@ -9867,7 +9867,7 @@ declare namespace ts { * @param visitor The callback used to visit each child. * @param context A lexical environment context for the visitor. */ - function visitEachChild(node: T, visitor: Visitor, context: TransformationContext): T; + function visitEachChild(node: T, visitor: Visitor, context: CoreTransformationContext): T; /** * Visits each child of a Node using the supplied visitor, possibly returning a new Node of the same kind in its place. * @@ -9875,7 +9875,7 @@ declare namespace ts { * @param visitor The callback used to visit each child. * @param context A lexical environment context for the visitor. */ - function visitEachChild(node: T | undefined, visitor: Visitor, context: TransformationContext, nodesVisitor?: typeof visitNodes, tokenVisitor?: Visitor): T | undefined; + function visitEachChild(node: T | undefined, visitor: Visitor, context: CoreTransformationContext, nodesVisitor?: typeof visitNodes, tokenVisitor?: Visitor): T | undefined; function transpileDeclaration(sourceFile: SourceFile, transpileOptions: TranspileDeclarationsOptions): TranspileDeclarationsOutput; function getTsBuildInfoEmitOutputFilePath(options: CompilerOptions): string | undefined; function getOutputFileNames(commandLine: ParsedCommandLine, inputFileName: string, ignoreCase: boolean): readonly string[]; From 97161e08891d78fbe7f2795528acfded36bea1a5 Mon Sep 17 00:00:00 2001 From: Titian Cernicova-Dragomir Date: Wed, 13 Dec 2023 13:04:24 +0000 Subject: [PATCH 2/5] Added kind to transformation context. Signed-off-by: Titian Cernicova-Dragomir --- src/compiler/_namespaces/ts.ts | 1 - src/compiler/transformer.ts | 82 ++++++++++++------- src/compiler/transformers/declarations.ts | 7 +- .../transformers/declarations/emitBinder.ts | 6 +- .../declarations/transpileDeclaration.ts | 18 +--- .../transformers/declarations/types.ts | 21 ----- src/compiler/types.ts | 21 +++++ src/services/textChanges.ts | 4 +- 8 files changed, 89 insertions(+), 71 deletions(-) delete mode 100644 src/compiler/transformers/declarations/types.ts diff --git a/src/compiler/_namespaces/ts.ts b/src/compiler/_namespaces/ts.ts index 14eb95213c884..20fa80074efca 100644 --- a/src/compiler/_namespaces/ts.ts +++ b/src/compiler/_namespaces/ts.ts @@ -61,7 +61,6 @@ export * from "../transformers/declarations/emitBinder"; export * from "../transformers/declarations/emitResolver"; export * from "../transformers/declarations/transpileDeclaration"; export * from "../transformers/declarations/localInferenceResolver"; -export * from "../transformers/declarations/types"; export * from "../transformers/declarations"; export * from "../transformer"; export * from "../emitter"; diff --git a/src/compiler/transformer.ts b/src/compiler/transformer.ts index 3a37fe0f2d3f4..7187308ea8fef 100644 --- a/src/compiler/transformer.ts +++ b/src/compiler/transformer.ts @@ -4,11 +4,13 @@ import { Bundle, chainBundle, CompilerOptions, + CoreEmitResolver, createEmitHelperFactory, CustomTransformer, CustomTransformerFactory, CustomTransformers, Debug, + Diagnostic, DiagnosticWithLocation, disposeEmitNodes, EmitFlags, @@ -30,6 +32,7 @@ import { getUseDefineForClassFields, Identifier, isBundle, + IsolatedTransformationContext, isSourceFile, LexicalEnvironmentFlags, map, @@ -40,6 +43,7 @@ import { NodeFlags, noop, notImplemented, + NullTransformationContext, returnUndefined, ScriptTarget, setEmitFlags, @@ -49,6 +53,7 @@ import { SyntaxKind, tracing, TransformationContext, + TransformationContextKind, TransformationResult, transformClassFields, transformDeclarations, @@ -267,6 +272,7 @@ export function transformNodes(resolver: EmitResolver | undefine // The transformation context is provided to each transformer as part of transformer // initialization. const context: TransformationContext = { + kind: TransformationContextKind.FullContext, factory, getCompilerOptions: () => options, getEmitResolver: () => resolver!, // TODO: GH#18217 @@ -662,33 +668,51 @@ export function transformNodes(resolver: EmitResolver | undefine } } } - /** @internal */ -export const nullTransformationContext: TransformationContext = { - factory: factory, // eslint-disable-line object-shorthand - getCompilerOptions: () => ({}), - getEmitResolver: notImplemented, - getEmitHost: notImplemented, - getEmitHelperFactory: notImplemented, - startLexicalEnvironment: noop, - resumeLexicalEnvironment: noop, - suspendLexicalEnvironment: noop, - endLexicalEnvironment: returnUndefined, - setLexicalEnvironmentFlags: noop, - getLexicalEnvironmentFlags: () => 0, - hoistVariableDeclaration: noop, - hoistFunctionDeclaration: noop, - addInitializationStatement: noop, - startBlockScope: noop, - endBlockScope: returnUndefined, - addBlockScopedVariable: noop, - requestEmitHelper: noop, - readEmitHelpers: notImplemented, - enableSubstitution: noop, - enableEmitNotification: noop, - isSubstitutionEnabled: notImplemented, - isEmitNotificationEnabled: notImplemented, - onSubstituteNode: noEmitSubstitution, - onEmitNode: noEmitNotification, - addDiagnostic: noop, -}; +export function createTransformationContext(kind: TransformationContextKind.NullContext): NullTransformationContext; +/** @internal */ +export function createTransformationContext( + kind: TransformationContextKind.IsolatedContext, + options: CompilerOptions, + diagnostics: Diagnostic[], + resolver: CoreEmitResolver, +): IsolatedTransformationContext; +export function createTransformationContext( + kind: TransformationContextKind.IsolatedContext | TransformationContextKind.NullContext, + options: CompilerOptions = {}, + diagnostics?: Diagnostic[], + resolver?: EmitResolver | CoreEmitResolver, + host?: EmitHost, +): NullTransformationContext | IsolatedTransformationContext | TransformationContext { + return { + kind, + factory: factory, // eslint-disable-line object-shorthand + getCompilerOptions: () => options, + getEmitResolver: !resolver ? notImplemented : () => resolver, + getEmitHost: !host ? notImplemented : () => host, + getEmitHelperFactory: notImplemented, + startLexicalEnvironment: noop, + resumeLexicalEnvironment: noop, + suspendLexicalEnvironment: noop, + endLexicalEnvironment: returnUndefined, + setLexicalEnvironmentFlags: noop, + getLexicalEnvironmentFlags: () => 0, + hoistVariableDeclaration: noop, + hoistFunctionDeclaration: noop, + addInitializationStatement: noop, + startBlockScope: noop, + endBlockScope: returnUndefined, + addBlockScopedVariable: noop, + requestEmitHelper: noop, + readEmitHelpers: notImplemented, + enableSubstitution: noop, + enableEmitNotification: noop, + isSubstitutionEnabled: notImplemented, + isEmitNotificationEnabled: notImplemented, + onSubstituteNode: noEmitSubstitution, + onEmitNode: noEmitNotification, + addDiagnostic: !diagnostics ? noop : (diag: Diagnostic) => diagnostics.push(diag), + }; +} +/** @internal */ +export const nullTransformationContext: NullTransformationContext = createTransformationContext(TransformationContextKind.NullContext); diff --git a/src/compiler/transformers/declarations.ts b/src/compiler/transformers/declarations.ts index 48a063a0a5344..324a3c2d04ddf 100644 --- a/src/compiler/transformers/declarations.ts +++ b/src/compiler/transformers/declarations.ts @@ -220,6 +220,7 @@ import { SyntaxKind, toFileNameLowerCase, TransformationContext, + TransformationContextKind, transformNodes, tryCast, tryGetModuleSpecifierFromDeclaration, @@ -292,7 +293,7 @@ const declarationEmitNodeBuilderFlags = NodeBuilderFlags.MultilineObjectLiterals * * @internal */ -export function transformDeclarations(context: (TransformationContext & { useLocalInferenceTypePrint?: false; }) | IsolatedTransformationContext) { +export function transformDeclarations(context: TransformationContext | IsolatedTransformationContext) { const throwDiagnostic = () => Debug.fail("Diagnostic emitted without context"); let getSymbolAccessibilityDiagnostic: GetSymbolAccessibilityDiagnostic = throwDiagnostic; let needsDeclare = true; @@ -339,7 +340,7 @@ export function transformDeclarations(context: (TransformationContext & { useLoc return checkEntityNameVisibility(name, container ?? enclosingDeclaration); }, }); - if (context.useLocalInferenceTypePrint) { + if (context.kind === TransformationContextKind.IsolatedContext) { const resolver: CoreEmitResolver = context.getEmitResolver(); // Ideally nothing should require the symbol tracker in isolated declarations mode. // createLiteralConstValue is the one exception @@ -370,7 +371,7 @@ export function transformDeclarations(context: (TransformationContext & { useLoc } } else { - Debug.assert(!context.useLocalInferenceTypePrint); + Debug.assert(context.kind === TransformationContextKind.FullContext); const host = context.getEmitHost(); const resolver = context.getEmitResolver(); const symbolTracker: SymbolTracker = createSymbolTracker(resolver, host); diff --git a/src/compiler/transformers/declarations/emitBinder.ts b/src/compiler/transformers/declarations/emitBinder.ts index e94b4c80ba7a3..a0e76c9c45e77 100644 --- a/src/compiler/transformers/declarations/emitBinder.ts +++ b/src/compiler/transformers/declarations/emitBinder.ts @@ -62,7 +62,6 @@ import { isVarConst, isVariableDeclaration, MappedTypeNode, - MemberKey, MethodDeclaration, MethodSignature, ModifierFlags, @@ -816,6 +815,11 @@ export function bindSourceFileForDeclarationEmit(file: SourceFile) { } } +/** @internal */ +export type MemberKey = string & { + __memberKey: void; +}; + /** * Gets the symbolic name for a member from its type. * @internal diff --git a/src/compiler/transformers/declarations/transpileDeclaration.ts b/src/compiler/transformers/declarations/transpileDeclaration.ts index e117840b4d4ca..cf9b09a5449dc 100644 --- a/src/compiler/transformers/declarations/transpileDeclaration.ts +++ b/src/compiler/transformers/declarations/transpileDeclaration.ts @@ -7,6 +7,7 @@ import { createPrinter, createSourceMapGenerator, createTextWriter, + createTransformationContext, Debug, Diagnostic, EmitHost, @@ -21,11 +22,11 @@ import { getSourceFilePathInNewDir, normalizePath, normalizeSlashes, - nullTransformationContext, PrinterOptions, SourceFile, SourceMapGenerator, sys, + TransformationContextKind, transformDeclarations, TranspileDeclarationsOptions, TranspileDeclarationsOutput, @@ -46,19 +47,8 @@ export function transpileDeclaration(sourceFile: SourceFile, transpileOptions: T }; const emitResolver = createEmitDeclarationResolver(sourceFile); const diagnostics: Diagnostic[] = []; - const transformer = transformDeclarations({ - useLocalInferenceTypePrint: true, - ...nullTransformationContext, - getEmitResolver() { - return emitResolver; - }, - getCompilerOptions() { - return compilerOptions; - }, - addDiagnostic(diag: any) { - diagnostics.push(diag); - }, - }); + const transformationContext = createTransformationContext(TransformationContextKind.IsolatedContext, compilerOptions, diagnostics, emitResolver); + const transformer = transformDeclarations(transformationContext); const result = transformer(sourceFile); const printer = createPrinter({ diff --git a/src/compiler/transformers/declarations/types.ts b/src/compiler/transformers/declarations/types.ts deleted file mode 100644 index 4497b297ea574..0000000000000 --- a/src/compiler/transformers/declarations/types.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { - CompilerOptions, - CoreEmitResolver, - CoreTransformationContext, - Diagnostic, - NodeFactory, -} from "../../_namespaces/ts"; - -/** @internal */ -export interface IsolatedTransformationContext extends CoreTransformationContext { - useLocalInferenceTypePrint: true; - getEmitResolver(): CoreEmitResolver; - getCompilerOptions(): CompilerOptions; - factory: NodeFactory; - addDiagnostic(diag: Diagnostic): void; -} - -/** @internal */ -export type MemberKey = string & { - __memberKey: void; -}; diff --git a/src/compiler/types.ts b/src/compiler/types.ts index f6aaeedb3094f..13d6e7ca9b62d 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -9167,7 +9167,14 @@ export const enum LexicalEnvironmentFlags { VariablesHoistedInParameters = 1 << 1, // a temp variable was hoisted while visiting a parameter list } +export const enum TransformationContextKind { + FullContext = 0, + IsolatedContext = 1, + NullContext = 2, +} + export interface CoreTransformationContext { + /** @internal */ kind: TransformationContextKind; readonly factory: NodeFactory; /** Gets the compiler options supplied to the transformer. */ @@ -9209,6 +9216,7 @@ export interface CoreTransformationContext { } export interface TransformationContext extends CoreTransformationContext { + kind: TransformationContextKind.FullContext; /** @internal */ getEmitResolver(): EmitResolver; /** @internal */ getEmitHost(): EmitHost; /** @internal */ getEmitHelperFactory(): EmitHelperFactory; @@ -9258,6 +9266,19 @@ export interface TransformationContext extends CoreTransformationContext { /** @internal */ addDiagnostic(diag: DiagnosticWithLocation): void; } +/** @internal */ +export interface IsolatedTransformationContext extends CoreTransformationContext { + kind: TransformationContextKind.IsolatedContext; + getEmitResolver(): CoreEmitResolver; + getCompilerOptions(): CompilerOptions; + factory: NodeFactory; + addDiagnostic(diag: Diagnostic): void; +} +/** @internal */ +export interface NullTransformationContext extends CoreTransformationContext { + kind: TransformationContextKind.NullContext; +} + export interface TransformationResult { /** Gets the transformed source files. */ transformed: T[]; diff --git a/src/services/textChanges.ts b/src/services/textChanges.ts index 177e25b18d0e5..2a3a3ba7202aa 100644 --- a/src/services/textChanges.ts +++ b/src/services/textChanges.ts @@ -128,6 +128,7 @@ import { NodeArray, NodeFactoryFlags, nodeIsSynthesized, + NullTransformationContext, nullTransformationContext, ObjectLiteralElementLike, ObjectLiteralExpression, @@ -162,7 +163,6 @@ import { textSpanEnd, Token, tokenToString, - TransformationContext, TypeLiteralNode, TypeNode, TypeParameterDeclaration, @@ -1367,7 +1367,7 @@ function isTrivia(s: string) { // A transformation context that won't perform parenthesization, as some parenthesization rules // are more aggressive than is strictly necessary. -const textChangesTransformationContext: TransformationContext = { +const textChangesTransformationContext: NullTransformationContext = { ...nullTransformationContext, factory: createNodeFactory( nullTransformationContext.factory.flags | NodeFactoryFlags.NoParenthesizerRules, From c45ffaff0261844c13b0c08483d627f5c8dc1e8c Mon Sep 17 00:00:00 2001 From: Titian Cernicova-Dragomir Date: Tue, 2 Jan 2024 11:27:59 +0000 Subject: [PATCH 3/5] Addressed code review. Signed-off-by: Titian Cernicova-Dragomir --- src/compiler/transformer.ts | 69 +++++-------------- .../declarations/transpileDeclaration.ts | 11 ++- src/compiler/types.ts | 5 +- 3 files changed, 30 insertions(+), 55 deletions(-) diff --git a/src/compiler/transformer.ts b/src/compiler/transformer.ts index 7187308ea8fef..9c4cc9ac9fd7a 100644 --- a/src/compiler/transformer.ts +++ b/src/compiler/transformer.ts @@ -4,13 +4,11 @@ import { Bundle, chainBundle, CompilerOptions, - CoreEmitResolver, createEmitHelperFactory, CustomTransformer, CustomTransformerFactory, CustomTransformers, Debug, - Diagnostic, DiagnosticWithLocation, disposeEmitNodes, EmitFlags, @@ -32,7 +30,6 @@ import { getUseDefineForClassFields, Identifier, isBundle, - IsolatedTransformationContext, isSourceFile, LexicalEnvironmentFlags, map, @@ -42,7 +39,6 @@ import { NodeFactory, NodeFlags, noop, - notImplemented, NullTransformationContext, returnUndefined, ScriptTarget, @@ -668,51 +664,22 @@ export function transformNodes(resolver: EmitResolver | undefine } } } + /** @internal */ -export function createTransformationContext(kind: TransformationContextKind.NullContext): NullTransformationContext; -/** @internal */ -export function createTransformationContext( - kind: TransformationContextKind.IsolatedContext, - options: CompilerOptions, - diagnostics: Diagnostic[], - resolver: CoreEmitResolver, -): IsolatedTransformationContext; -export function createTransformationContext( - kind: TransformationContextKind.IsolatedContext | TransformationContextKind.NullContext, - options: CompilerOptions = {}, - diagnostics?: Diagnostic[], - resolver?: EmitResolver | CoreEmitResolver, - host?: EmitHost, -): NullTransformationContext | IsolatedTransformationContext | TransformationContext { - return { - kind, - factory: factory, // eslint-disable-line object-shorthand - getCompilerOptions: () => options, - getEmitResolver: !resolver ? notImplemented : () => resolver, - getEmitHost: !host ? notImplemented : () => host, - getEmitHelperFactory: notImplemented, - startLexicalEnvironment: noop, - resumeLexicalEnvironment: noop, - suspendLexicalEnvironment: noop, - endLexicalEnvironment: returnUndefined, - setLexicalEnvironmentFlags: noop, - getLexicalEnvironmentFlags: () => 0, - hoistVariableDeclaration: noop, - hoistFunctionDeclaration: noop, - addInitializationStatement: noop, - startBlockScope: noop, - endBlockScope: returnUndefined, - addBlockScopedVariable: noop, - requestEmitHelper: noop, - readEmitHelpers: notImplemented, - enableSubstitution: noop, - enableEmitNotification: noop, - isSubstitutionEnabled: notImplemented, - isEmitNotificationEnabled: notImplemented, - onSubstituteNode: noEmitSubstitution, - onEmitNode: noEmitNotification, - addDiagnostic: !diagnostics ? noop : (diag: Diagnostic) => diagnostics.push(diag), - }; -} -/** @internal */ -export const nullTransformationContext: NullTransformationContext = createTransformationContext(TransformationContextKind.NullContext); +export const nullTransformationContext: NullTransformationContext = { + kind: TransformationContextKind.NullContext, + factory: factory, // eslint-disable-line object-shorthand + getCompilerOptions: () => ({}), + startLexicalEnvironment: noop, + resumeLexicalEnvironment: noop, + suspendLexicalEnvironment: noop, + endLexicalEnvironment: returnUndefined, + setLexicalEnvironmentFlags: noop, + getLexicalEnvironmentFlags: () => 0, + hoistVariableDeclaration: noop, + hoistFunctionDeclaration: noop, + addInitializationStatement: noop, + startBlockScope: noop, + endBlockScope: returnUndefined, + addBlockScopedVariable: noop, +}; diff --git a/src/compiler/transformers/declarations/transpileDeclaration.ts b/src/compiler/transformers/declarations/transpileDeclaration.ts index cf9b09a5449dc..828de3cf9dbfa 100644 --- a/src/compiler/transformers/declarations/transpileDeclaration.ts +++ b/src/compiler/transformers/declarations/transpileDeclaration.ts @@ -7,7 +7,6 @@ import { createPrinter, createSourceMapGenerator, createTextWriter, - createTransformationContext, Debug, Diagnostic, EmitHost, @@ -20,8 +19,10 @@ import { getRelativePathToDirectoryOrUrl, getRootLength, getSourceFilePathInNewDir, + IsolatedTransformationContext, normalizePath, normalizeSlashes, + nullTransformationContext, PrinterOptions, SourceFile, SourceMapGenerator, @@ -47,7 +48,13 @@ export function transpileDeclaration(sourceFile: SourceFile, transpileOptions: T }; const emitResolver = createEmitDeclarationResolver(sourceFile); const diagnostics: Diagnostic[] = []; - const transformationContext = createTransformationContext(TransformationContextKind.IsolatedContext, compilerOptions, diagnostics, emitResolver); + const transformationContext: IsolatedTransformationContext = { + ...nullTransformationContext, + kind: TransformationContextKind.IsolatedContext, + getCompilerOptions: () => compilerOptions, + addDiagnostic: diag => diagnostics.push(diag), + getEmitResolver: () => emitResolver, + }; const transformer = transformDeclarations(transformationContext); const result = transformer(sourceFile); diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 13d6e7ca9b62d..c786c2ee5fa78 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -5696,7 +5696,7 @@ export interface CoreEmitResolver { getConstantValue(node: EnumMember | PropertyAccessExpression | ElementAccessExpression): string | number | undefined; getAllAccessorDeclarations(declaration: AccessorDeclaration): AllAccessorDeclarations; tryFindAmbientModule(moduleReferenceExpression: Expression): Symbol | undefined; - getPropertiesOfContainerFunction(node: FunctionDeclaration | VariableDeclaration): Symbol[] + getPropertiesOfContainerFunction(node: FunctionDeclaration | VariableDeclaration): Symbol[]; } /** @internal */ export interface EmitResolver extends CoreEmitResolver { @@ -9167,6 +9167,7 @@ export const enum LexicalEnvironmentFlags { VariablesHoistedInParameters = 1 << 1, // a temp variable was hoisted while visiting a parameter list } +/** @internal */ export const enum TransformationContextKind { FullContext = 0, IsolatedContext = 1, @@ -9216,7 +9217,7 @@ export interface CoreTransformationContext { } export interface TransformationContext extends CoreTransformationContext { - kind: TransformationContextKind.FullContext; + /** @internal */ kind: TransformationContextKind.FullContext; /** @internal */ getEmitResolver(): EmitResolver; /** @internal */ getEmitHost(): EmitHost; /** @internal */ getEmitHelperFactory(): EmitHelperFactory; From a3a5049c3b9c195c333f2a31a09020ad1fb37055 Mon Sep 17 00:00:00 2001 From: Titian Cernicova-Dragomir Date: Wed, 3 Jan 2024 11:27:13 +0000 Subject: [PATCH 4/5] Added back runtime members to nullTransformationContext Signed-off-by: Titian Cernicova-Dragomir --- src/compiler/transformer.ts | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/src/compiler/transformer.ts b/src/compiler/transformer.ts index 9c4cc9ac9fd7a..a0bc8ebfa38db 100644 --- a/src/compiler/transformer.ts +++ b/src/compiler/transformer.ts @@ -39,6 +39,7 @@ import { NodeFactory, NodeFlags, noop, + notImplemented, NullTransformationContext, returnUndefined, ScriptTarget, @@ -665,11 +666,15 @@ export function transformNodes(resolver: EmitResolver | undefine } } -/** @internal */ -export const nullTransformationContext: NullTransformationContext = { +// NullTransformationContext does not have all members of TransformationContext and nullTransformationContext should only be used as a CoreTransformationContext +// To ensure backward compatibility, nullTransformationContext will continue to have all members of TransformationContext (with unsupported methods throwing errors) +const _nullTransformationContext: Omit & { kind: TransformationContextKind.NullContext } = { kind: TransformationContextKind.NullContext, factory: factory, // eslint-disable-line object-shorthand getCompilerOptions: () => ({}), + getEmitResolver: notImplemented, + getEmitHost: notImplemented, + getEmitHelperFactory: notImplemented, startLexicalEnvironment: noop, resumeLexicalEnvironment: noop, suspendLexicalEnvironment: noop, @@ -682,4 +687,16 @@ export const nullTransformationContext: NullTransformationContext = { startBlockScope: noop, endBlockScope: returnUndefined, addBlockScopedVariable: noop, + requestEmitHelper: noop, + readEmitHelpers: notImplemented, + enableSubstitution: noop, + enableEmitNotification: noop, + isSubstitutionEnabled: notImplemented, + isEmitNotificationEnabled: notImplemented, + onSubstituteNode: noEmitSubstitution, + onEmitNode: noEmitNotification, + addDiagnostic: noop, }; + +/** @internal */ +export const nullTransformationContext: NullTransformationContext = _nullTransformationContext From 202d522ddc2438f51e802f3b25dc7b285ef721e9 Mon Sep 17 00:00:00 2001 From: Titian Cernicova-Dragomir Date: Thu, 4 Jan 2024 13:47:34 +0000 Subject: [PATCH 5/5] Changed null context to have all methods from the regular transformation context. Signed-off-by: Titian Cernicova-Dragomir --- src/compiler/transformer.ts | 8 ++------ src/compiler/types.ts | 8 +++++++- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/compiler/transformer.ts b/src/compiler/transformer.ts index a0bc8ebfa38db..28e17448e2cff 100644 --- a/src/compiler/transformer.ts +++ b/src/compiler/transformer.ts @@ -666,9 +666,8 @@ export function transformNodes(resolver: EmitResolver | undefine } } -// NullTransformationContext does not have all members of TransformationContext and nullTransformationContext should only be used as a CoreTransformationContext -// To ensure backward compatibility, nullTransformationContext will continue to have all members of TransformationContext (with unsupported methods throwing errors) -const _nullTransformationContext: Omit & { kind: TransformationContextKind.NullContext } = { +/** @internal */ +export const nullTransformationContext: NullTransformationContext = { kind: TransformationContextKind.NullContext, factory: factory, // eslint-disable-line object-shorthand getCompilerOptions: () => ({}), @@ -697,6 +696,3 @@ const _nullTransformationContext: Omit & { kind: onEmitNode: noEmitNotification, addDiagnostic: noop, }; - -/** @internal */ -export const nullTransformationContext: NullTransformationContext = _nullTransformationContext diff --git a/src/compiler/types.ts b/src/compiler/types.ts index c786c2ee5fa78..c285e7bcd495a 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -9276,8 +9276,14 @@ export interface IsolatedTransformationContext extends CoreTransformationContext addDiagnostic(diag: Diagnostic): void; } /** @internal */ -export interface NullTransformationContext extends CoreTransformationContext { +export interface NullTransformationContext extends Omit { kind: TransformationContextKind.NullContext; + getEmitResolver(): never; + getEmitHost(): never; + getEmitHelperFactory(): never; + readEmitHelpers(): never; + isSubstitutionEnabled(): never; + isEmitNotificationEnabled(): never; } export interface TransformationResult {