diff --git a/src/compiler/builder.ts b/src/compiler/builder.ts index 550baef382984..28f7de4506112 100644 --- a/src/compiler/builder.ts +++ b/src/compiler/builder.ts @@ -1163,7 +1163,7 @@ function convertToReusableCompilerOptionValue(option: CommandLineOption | undefi if (option) { Debug.assert(option.type !== "listOrElement"); if (option.type === "list") { - const values = value as readonly (string | number)[]; + const values = value as readonly string[]; if (option.element.isFilePath && values.length) { return values.map(relativeToBuildInfo); } diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 58851b8b536c5..f133d503c6f4f 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2174,7 +2174,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (jsxFragmentPragma) { const chosenPragma = isArray(jsxFragmentPragma) ? jsxFragmentPragma[0] : jsxFragmentPragma; file.localJsxFragmentFactory = parseIsolatedEntityName(chosenPragma.arguments.factory, languageVersion); - visitNode(file.localJsxFragmentFactory, markAsSynthetic); + visitNode(file.localJsxFragmentFactory, markAsSynthetic, isEntityName); if (file.localJsxFragmentFactory) { return file.localJsxFragmentNamespace = getFirstIdentifier(file.localJsxFragmentFactory).escapedText; } @@ -2220,14 +2220,14 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (jsxPragma) { const chosenPragma = isArray(jsxPragma) ? jsxPragma[0] : jsxPragma; file.localJsxFactory = parseIsolatedEntityName(chosenPragma.arguments.factory, languageVersion); - visitNode(file.localJsxFactory, markAsSynthetic); + visitNode(file.localJsxFactory, markAsSynthetic, isEntityName); if (file.localJsxFactory) { return file.localJsxNamespace = getFirstIdentifier(file.localJsxFactory).escapedText; } } } - function markAsSynthetic(node: Node): VisitResult { + function markAsSynthetic(node: T): VisitResult { setTextRangePosEnd(node, -1, -1); return visitEachChild(node, markAsSynthetic, nullTransformationContext); } @@ -4026,7 +4026,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return valueSymbol; } const result = createSymbol(valueSymbol.flags | typeSymbol.flags, valueSymbol.escapedName); - result.declarations = deduplicate(concatenate(valueSymbol.declarations, typeSymbol.declarations), equateValues); + Debug.assert(valueSymbol.declarations || typeSymbol.declarations); + result.declarations = deduplicate(concatenate(valueSymbol.declarations!, typeSymbol.declarations), equateValues); result.parent = valueSymbol.parent || typeSymbol.parent; if (valueSymbol.valueDeclaration) result.valueDeclaration = valueSymbol.valueDeclaration; if (typeSymbol.members) result.members = new Map(typeSymbol.members); @@ -4980,7 +4981,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function resolveExternalModuleSymbol(moduleSymbol: Symbol, dontResolveAlias?: boolean): Symbol; function resolveExternalModuleSymbol(moduleSymbol: Symbol | undefined, dontResolveAlias?: boolean): Symbol | undefined; - function resolveExternalModuleSymbol(moduleSymbol: Symbol, dontResolveAlias?: boolean): Symbol | undefined { + function resolveExternalModuleSymbol(moduleSymbol: Symbol | undefined, dontResolveAlias?: boolean): Symbol | undefined { if (moduleSymbol?.exports) { const exportEquals = resolveSymbol(moduleSymbol.exports.get(InternalSymbolName.ExportEquals), dontResolveAlias); const exported = getCommonJsExportEquals(getMergedSymbol(exportEquals), getMergedSymbol(moduleSymbol)); @@ -6330,7 +6331,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (objectFlags & ObjectFlags.Reference) { Debug.assert(!!(type.flags & TypeFlags.Object)); - return (type as TypeReference).node ? visitAndTransformType(type, typeReferenceToTypeNode) : typeReferenceToTypeNode(type as TypeReference); + return (type as TypeReference).node ? visitAndTransformType(type as TypeReference, typeReferenceToTypeNode) : typeReferenceToTypeNode(type as TypeReference); } if (type.flags & TypeFlags.TypeParameter || objectFlags & ObjectFlags.ClassOrInterface) { if (type.flags & TypeFlags.TypeParameter && contains(context.inferTypeParameters, type)) { @@ -6584,11 +6585,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } - function visitAndTransformType(type: Type, transform: (type: Type) => T) { + function visitAndTransformType(type: T, transform: (type: T) => TypeNode) { const typeId = type.id; const isConstructorObject = getObjectFlags(type) & ObjectFlags.Anonymous && type.symbol && type.symbol.flags & SymbolFlags.Class; - const id = getObjectFlags(type) & ObjectFlags.Reference && (type as TypeReference).node ? "N" + getNodeId((type as TypeReference).node!) : - type.flags & TypeFlags.Conditional ? "N" + getNodeId((type as ConditionalType).root.node) : + const id = getObjectFlags(type) & ObjectFlags.Reference && (type as TypeReference & T).node ? "N" + getNodeId((type as TypeReference & T).node!) : + type.flags & TypeFlags.Conditional ? "N" + getNodeId((type as ConditionalType & T).root.node) : type.symbol ? (isConstructorObject ? "+" : "") + getSymbolId(type.symbol) : undefined; // Since instantiations of the same anonymous type have the same symbol, tracking symbols instead @@ -6611,7 +6612,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { context.truncating = true; } context.approximateLength += cachedResult.addedLength; - return deepCloneOrReuseNode(cachedResult.node) as T; + return deepCloneOrReuseNode(cachedResult.node); } let depth: number | undefined; @@ -6635,20 +6636,24 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } return result; - function deepCloneOrReuseNode(node: Node): Node { + function deepCloneOrReuseNode(node: T): T { if (!nodeIsSynthesized(node) && getParseTreeNode(node) === node) { return node; } return setTextRange(factory.cloneNode(visitEachChild(node, deepCloneOrReuseNode, nullTransformationContext, deepCloneOrReuseNodes)), node); } - function deepCloneOrReuseNodes(nodes: NodeArray, visitor: Visitor | undefined, test?: (node: Node) => boolean, start?: number, count?: number): NodeArray; - function deepCloneOrReuseNodes(nodes: NodeArray | undefined, visitor: Visitor | undefined, test?: (node: Node) => boolean, start?: number, count?: number): NodeArray | undefined; - function deepCloneOrReuseNodes(nodes: NodeArray | undefined, visitor: Visitor | undefined, test?: (node: Node) => boolean, start?: number, count?: number): NodeArray | undefined { + function deepCloneOrReuseNodes( + nodes: NodeArray | undefined, + visitor: Visitor, + test?: (node: Node) => boolean, + start?: number, + count?: number, + ): NodeArray | undefined { if (nodes && nodes.length === 0) { // Ensure we explicitly make a copy of an empty array; visitNodes will not do this unless the array has elements, // which can lead to us reusing the same empty NodeArray more than once within the same AST during type noding. - return setTextRange(factory.createNodeArray(/*nodes*/ undefined, nodes.hasTrailingComma), nodes); + return setTextRange(factory.createNodeArray(/*nodes*/ undefined, nodes.hasTrailingComma), nodes); } return visitNodes(nodes, visitor, test, start, count); } @@ -7956,13 +7961,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } let hadError = false; const file = getSourceFileOfNode(existing); - const transformed = visitNode(existing, visitExistingNodeTreeSymbols); + const transformed = visitNode(existing, visitExistingNodeTreeSymbols, isTypeNode); if (hadError) { return undefined; } return transformed === existing ? setTextRange(factory.cloneNode(existing), existing) : transformed; - function visitExistingNodeTreeSymbols(node: T): Node { + function visitExistingNodeTreeSymbols(node: Node): Node { // We don't _actually_ support jsdoc namepath types, emit `any` instead if (isJSDocAllType(node) || node.kind === SyntaxKind.JSDocNamepathType) { return factory.createKeywordTypeNode(SyntaxKind.AnyKeyword); @@ -7971,16 +7976,16 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return factory.createKeywordTypeNode(SyntaxKind.UnknownKeyword); } if (isJSDocNullableType(node)) { - return factory.createUnionTypeNode([visitNode(node.type, visitExistingNodeTreeSymbols), factory.createLiteralTypeNode(factory.createNull())]); + return factory.createUnionTypeNode([visitNode(node.type, visitExistingNodeTreeSymbols, isTypeNode), factory.createLiteralTypeNode(factory.createNull())]); } if (isJSDocOptionalType(node)) { - return factory.createUnionTypeNode([visitNode(node.type, visitExistingNodeTreeSymbols), factory.createKeywordTypeNode(SyntaxKind.UndefinedKeyword)]); + return factory.createUnionTypeNode([visitNode(node.type, visitExistingNodeTreeSymbols, isTypeNode), factory.createKeywordTypeNode(SyntaxKind.UndefinedKeyword)]); } if (isJSDocNonNullableType(node)) { return visitNode(node.type, visitExistingNodeTreeSymbols); } if (isJSDocVariadicType(node)) { - return factory.createArrayTypeNode(visitNode((node as JSDocVariadicType).type, visitExistingNodeTreeSymbols)); + return factory.createArrayTypeNode(visitNode(node.type, visitExistingNodeTreeSymbols, isTypeNode)); } if (isJSDocTypeLiteral(node)) { return factory.createTypeLiteralNode(map(node.jsDocPropertyTags, t => { @@ -7992,7 +7997,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { /*modifiers*/ undefined, name, t.isBracketed || t.typeExpression && isJSDocOptionalType(t.typeExpression.type) ? factory.createToken(SyntaxKind.QuestionToken) : undefined, - overrideTypeNode || (t.typeExpression && visitNode(t.typeExpression.type, visitExistingNodeTreeSymbols)) || factory.createKeywordTypeNode(SyntaxKind.AnyKeyword) + overrideTypeNode || (t.typeExpression && visitNode(t.typeExpression.type, visitExistingNodeTreeSymbols, isTypeNode)) || factory.createKeywordTypeNode(SyntaxKind.AnyKeyword) ); })); } @@ -8007,9 +8012,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { /*dotdotdotToken*/ undefined, "x", /*questionToken*/ undefined, - visitNode(node.typeArguments![0], visitExistingNodeTreeSymbols) + visitNode(node.typeArguments![0], visitExistingNodeTreeSymbols, isTypeNode) )], - visitNode(node.typeArguments![1], visitExistingNodeTreeSymbols) + visitNode(node.typeArguments![1], visitExistingNodeTreeSymbols, isTypeNode) )]); } if (isJSDocFunctionType(node)) { @@ -8017,30 +8022,30 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { let newTypeNode: TypeNode | undefined; return factory.createConstructorTypeNode( /*modifiers*/ undefined, - visitNodes(node.typeParameters, visitExistingNodeTreeSymbols), + visitNodes(node.typeParameters, visitExistingNodeTreeSymbols, isTypeParameterDeclaration), mapDefined(node.parameters, (p, i) => p.name && isIdentifier(p.name) && p.name.escapedText === "new" ? (newTypeNode = p.type, undefined) : factory.createParameterDeclaration( /*modifiers*/ undefined, getEffectiveDotDotDotForParameter(p), getNameForJSDocFunctionParameter(p, i), p.questionToken, - visitNode(p.type, visitExistingNodeTreeSymbols), + visitNode(p.type, visitExistingNodeTreeSymbols, isTypeNode), /*initializer*/ undefined )), - visitNode(newTypeNode || node.type, visitExistingNodeTreeSymbols) || factory.createKeywordTypeNode(SyntaxKind.AnyKeyword) + visitNode(newTypeNode || node.type, visitExistingNodeTreeSymbols, isTypeNode) || factory.createKeywordTypeNode(SyntaxKind.AnyKeyword) ); } else { return factory.createFunctionTypeNode( - visitNodes(node.typeParameters, visitExistingNodeTreeSymbols), + visitNodes(node.typeParameters, visitExistingNodeTreeSymbols, isTypeParameterDeclaration), map(node.parameters, (p, i) => factory.createParameterDeclaration( /*modifiers*/ undefined, getEffectiveDotDotDotForParameter(p), getNameForJSDocFunctionParameter(p, i), p.questionToken, - visitNode(p.type, visitExistingNodeTreeSymbols), + visitNode(p.type, visitExistingNodeTreeSymbols, isTypeNode), /*initializer*/ undefined )), - visitNode(node.type, visitExistingNodeTreeSymbols) || factory.createKeywordTypeNode(SyntaxKind.AnyKeyword) + visitNode(node.type, visitExistingNodeTreeSymbols, isTypeNode) || factory.createKeywordTypeNode(SyntaxKind.AnyKeyword) ); } } @@ -8797,7 +8802,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { /*isTypeOnly*/ false, factory.createNamedExports([factory.createExportSpecifier(/*isTypeOnly*/ false, d.expression, factory.createIdentifier(InternalSymbolName.Default))]) ) : d); - const exportModifierStripped = every(defaultReplaced, d => hasSyntacticModifier(d, ModifierFlags.Export)) ? map(defaultReplaced, removeExportModifier) : defaultReplaced; + const exportModifierStripped = every(defaultReplaced, d => hasSyntacticModifier(d, ModifierFlags.Export)) ? map(defaultReplaced as Extract[], removeExportModifier) : defaultReplaced; fakespace = factory.updateModuleDeclaration( fakespace, fakespace.modifiers, @@ -9015,7 +9020,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { case SyntaxKind.ImportEqualsDeclaration: // This _specifically_ only exists to handle json declarations - where we make aliases, but since // we emit no declarations for the json document, must not refer to it in the declarations - if (target.escapedName === InternalSymbolName.ExportEquals && some(target.declarations, isJsonSourceFile)) { + if (target.escapedName === InternalSymbolName.ExportEquals && some(target.declarations, d => isSourceFile(d) && isJsonSourceFile(d))) { serializeMaybeAliasAssignment(symbol); break; } @@ -20155,7 +20160,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return true; } - function isRelatedToWorker(source: Type, target: Type, reportErrors: boolean) { + function isRelatedToWorker(source: Type, target: Type, reportErrors?: boolean) { return isRelatedTo(source, target, RecursionFlags.Both, reportErrors); } @@ -22658,7 +22663,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function getCombinedTypeFlags(types: Type[]): TypeFlags { - return reduceLeft(types, (flags, t) => flags | (t.flags & TypeFlags.Union ? getCombinedTypeFlags((t as UnionType).types) : t.flags), 0); + return reduceLeft(types, (flags, t) => flags | (t.flags & TypeFlags.Union ? getCombinedTypeFlags((t as UnionType).types) : t.flags), 0 as TypeFlags); } function getCommonSupertype(types: Type[]): Type { @@ -24014,7 +24019,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { inferWithPriority(getSubstitutionIntersection(source as SubstitutionType), target, InferencePriority.SubstituteSource); // Make substitute inference at a lower priority } else if (target.flags & TypeFlags.Conditional) { - invokeOnce(source, target, inferToConditionalType); + invokeOnce(source, (target as ConditionalType), inferToConditionalType); } else if (target.flags & TypeFlags.UnionOrIntersection) { inferToMultipleTypes(source, (target as UnionOrIntersectionType).types, target.flags); @@ -24076,7 +24081,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { priority = savePriority; } - function invokeOnce(source: Type, target: Type, action: (source: Type, target: Type) => void) { + function invokeOnce(source: Source, target: Target, action: (source: Source, target: Target) => void) { const key = source.id + "," + target.id; const status = visited && visited.get(key); if (status !== undefined) { @@ -29108,9 +29113,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return getStrictOptionValue(compilerOptions, "noImplicitAny") ? reduceLeft( signatures, - (left, right) => + (left: Signature | undefined, right) => left === right || !left ? left - : compareTypeParametersIdentical(left.typeParameters, right.typeParameters) ? combineSignaturesOfIntersectionMembers(left, right) + : compareTypeParametersIdentical(left.typeParameters, right!.typeParameters) ? combineSignaturesOfIntersectionMembers(left, right!) : undefined) : undefined; } diff --git a/src/compiler/commandLineParser.ts b/src/compiler/commandLineParser.ts index a510b158b4431..7d30e47739f64 100644 --- a/src/compiler/commandLineParser.ts +++ b/src/compiler/commandLineParser.ts @@ -2880,7 +2880,7 @@ export function convertToOptionsWithAbsolutePaths(options: CompilerOptions, toAb function convertToOptionValueWithAbsolutePaths(option: CommandLineOption | undefined, value: CompilerOptionsValue, toAbsolutePath: (path: string) => string) { if (option && !isNullOrUndefined(value)) { if (option.type === "list") { - const values = value as readonly (string | number)[]; + const values = value as readonly string[]; if (option.element.isFilePath && values.length) { return values.map(toAbsolutePath); } @@ -3846,7 +3846,8 @@ function validateSpecs(specs: readonly string[], errors: Push, disal } } -function specToDiagnostic(spec: string, disallowTrailingRecursion?: boolean): [DiagnosticMessage, string] | undefined { +function specToDiagnostic(spec: CompilerOptionsValue, disallowTrailingRecursion?: boolean): [DiagnosticMessage, string] | undefined { + Debug.assert(typeof spec === "string"); if (disallowTrailingRecursion && invalidTrailingRecursionPattern.test(spec)) { return [Diagnostics.File_specification_cannot_end_in_a_recursive_directory_wildcard_Asterisk_Asterisk_Colon_0, spec]; } diff --git a/src/compiler/core.ts b/src/compiler/core.ts index 3e19350823c1a..f8827baf4df72 100644 --- a/src/compiler/core.ts +++ b/src/compiler/core.ts @@ -142,6 +142,11 @@ export function intersperse(input: T[], element: T): T[] { * * @internal */ +export function every(array: readonly T[], callback: (element: T, index: number) => element is U): array is readonly U[]; +/** @internal */ +export function every(array: readonly T[] | undefined, callback: (element: T, index: number) => element is U): array is readonly U[] | undefined; +/** @internal */ +export function every(array: readonly T[] | undefined, callback: (element: T, index: number) => boolean): boolean; export function every(array: readonly T[] | undefined, callback: (element: T, index: number) => boolean): boolean { if (array) { for (let i = 0; i < array.length; i++) { @@ -478,7 +483,7 @@ export function sameFlatMap(array: T[], mapfn: (x: T, i: number) => T | reado /** @internal */ export function sameFlatMap(array: readonly T[], mapfn: (x: T, i: number) => T | readonly T[]): readonly T[]; /** @internal */ -export function sameFlatMap(array: T[], mapfn: (x: T, i: number) => T | T[]): T[] { +export function sameFlatMap(array: readonly T[], mapfn: (x: T, i: number) => T | readonly T[]): readonly T[] { let result: T[] | undefined; if (array) { for (let i = 0; i < array.length; i++) { @@ -703,11 +708,19 @@ export function concatenate(array1: T[], array2: T[]): T[]; /** @internal */ export function concatenate(array1: readonly T[], array2: readonly T[]): readonly T[]; /** @internal */ -export function concatenate(array1: T[] | undefined, array2: T[] | undefined): T[]; +export function concatenate(array1: T[], array2: T[] | undefined): T[]; // eslint-disable-line @typescript-eslint/unified-signatures +/** @internal */ +export function concatenate(array1: T[] | undefined, array2: T[]): T[]; // eslint-disable-line @typescript-eslint/unified-signatures +/** @internal */ +export function concatenate(array1: readonly T[], array2: readonly T[] | undefined): readonly T[]; // eslint-disable-line @typescript-eslint/unified-signatures +/** @internal */ +export function concatenate(array1: readonly T[] | undefined, array2: readonly T[]): readonly T[]; // eslint-disable-line @typescript-eslint/unified-signatures /** @internal */ -export function concatenate(array1: readonly T[] | undefined, array2: readonly T[] | undefined): readonly T[]; +export function concatenate(array1: T[] | undefined, array2: T[] | undefined): T[] | undefined; /** @internal */ -export function concatenate(array1: T[], array2: T[]): T[] { +export function concatenate(array1: readonly T[] | undefined, array2: readonly T[] | undefined): readonly T[] | undefined; +/** @internal */ +export function concatenate(array1: readonly T[] | undefined, array2: readonly T[] | undefined): readonly T[] | undefined { if (!some(array2)) return array1; if (!some(array1)) return array2; return [...array1, ...array2]; @@ -856,7 +869,7 @@ export function detectSortCaseSensitivity(array: readonly string[], useEslintOrd /** @internal */ export function detectSortCaseSensitivity(array: readonly T[], useEslintOrdering: boolean, getString: (element: T) => string): SortKind; /** @internal */ -export function detectSortCaseSensitivity(array: readonly T[], useEslintOrdering: boolean, getString?: (element: T) => string): SortKind { +export function detectSortCaseSensitivity(array: readonly T[], useEslintOrdering?: boolean, getString?: (element: T) => string): SortKind { let kind = SortKind.Both; if (array.length < 2) return kind; const caseSensitiveComparer = getString @@ -915,7 +928,7 @@ export function compact(array: T[]): T[]; // eslint-disable-line @typescript- /** @internal */ export function compact(array: readonly T[]): readonly T[]; // eslint-disable-line @typescript-eslint/unified-signatures /** @internal */ -export function compact(array: T[]): T[] { +export function compact(array: readonly T[]): readonly T[] { let result: T[] | undefined; if (array) { for (let i = 0; i < array.length; i++) { @@ -998,11 +1011,12 @@ export function append(to: T[] | undefined, value: T | undefined): T[] | unde /** @internal */ export function append(to: Push, value: T | undefined): void; /** @internal */ -export function append(to: T[], value: T | undefined): T[] | undefined { - if (value === undefined) return to; +export function append(to: Push | T[] | undefined, value: T | undefined): T[] | undefined { + // If to is Push, return value is void, so safe to cast to T[]. + if (value === undefined) return to as T[]; if (to === undefined) return [value]; to.push(value); - return to; + return to as T[]; } /** @@ -1315,7 +1329,7 @@ export function reduceLeft(array: readonly T[] | undefined, f: (memo: U, v /** @internal */ export function reduceLeft(array: readonly T[], f: (memo: T, value: T, i: number) => T): T | undefined; /** @internal */ -export function reduceLeft(array: T[], f: (memo: T, value: T, i: number) => T, initial?: T, start?: number, count?: number): T | undefined { +export function reduceLeft(array: readonly T[] | undefined, f: (memo: T, value: T, i: number) => T, initial?: T, start?: number, count?: number): T | undefined { if (array && array.length > 0) { const size = array.length; if (size > 0) { @@ -1867,11 +1881,7 @@ export function isNumber(x: unknown): x is number { } /** @internal */ -export function tryCast(value: TIn | undefined, test: (value: TIn) => value is TOut): TOut | undefined; -/** @internal */ -export function tryCast(value: T, test: (value: T) => boolean): T | undefined; -/** @internal */ -export function tryCast(value: T, test: (value: T) => boolean): T | undefined { +export function tryCast(value: TIn | undefined, test: (value: TIn) => value is TOut): TOut | undefined { return value !== undefined && test(value) ? value : undefined; } diff --git a/src/compiler/debug.ts b/src/compiler/debug.ts index ffbef3ef157c4..94838e3f8634a 100644 --- a/src/compiler/debug.ts +++ b/src/compiler/debug.ts @@ -275,13 +275,13 @@ export namespace Debug { export function assertEachNode(nodes: readonly T[], test: (node: T) => node is U, message?: string, stackCrawlMark?: AnyFunction): asserts nodes is readonly U[]; export function assertEachNode(nodes: NodeArray | undefined, test: (node: T) => node is U, message?: string, stackCrawlMark?: AnyFunction): asserts nodes is NodeArray | undefined; export function assertEachNode(nodes: readonly T[] | undefined, test: (node: T) => node is U, message?: string, stackCrawlMark?: AnyFunction): asserts nodes is readonly U[] | undefined; - export function assertEachNode(nodes: readonly Node[], test: (node: Node) => boolean, message?: string, stackCrawlMark?: AnyFunction): void; - export function assertEachNode(nodes: readonly Node[] | undefined, test: (node: Node) => boolean, message?: string, stackCrawlMark?: AnyFunction) { + export function assertEachNode(nodes: readonly Node[], test: ((node: Node) => boolean) | undefined, message?: string, stackCrawlMark?: AnyFunction): void; + export function assertEachNode(nodes: readonly Node[] | undefined, test: ((node: Node) => boolean) | undefined, message?: string, stackCrawlMark?: AnyFunction) { if (shouldAssertFunction(AssertionLevel.Normal, "assertEachNode")) { assert( test === undefined || every(nodes, test), message || "Unexpected node.", - () => `Node array did not pass test '${getFunctionName(test)}'.`, + () => `Node array did not pass test '${getFunctionName(test!)}'.`, stackCrawlMark || assertEachNode); } } diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index e765fec95e644..81b320d9ee0e6 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -279,6 +279,7 @@ import { JSDocVariadicType, JsxAttribute, JsxAttributes, + JsxAttributeValue, JsxClosingElement, JsxClosingFragment, JsxElement, @@ -1402,10 +1403,10 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri let hasWrittenComment = false; let commentsDisabled = !!printerOptions.removeComments; let lastSubstitution: Node | undefined; - let currentParenthesizerRule: ((node: Node) => Node) | undefined; + let currentParenthesizerRule: ParenthesizerRule | undefined; const { enter: enterComment, exit: exitComment } = performance.createTimerIf(extendedDiagnostics, "commentTime", "beforeComment", "afterComment"); const parenthesizer = factory.parenthesizer; - const typeArgumentParenthesizerRuleSelector: OrdinalParentheizerRuleSelector = { + const typeArgumentParenthesizerRuleSelector: OrdinalParentheizerRuleSelector = { select: index => index === 0 ? parenthesizer.parenthesizeLeadingTypeArgument : undefined }; const emitBinaryExpression = createEmitBinaryExpression(); @@ -1676,9 +1677,9 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri return currentLineMap || (currentLineMap = getLineStarts(Debug.checkDefined(currentSourceFile))); } - function emit(node: Node, parenthesizerRule?: (node: Node) => Node): void; - function emit(node: Node | undefined, parenthesizerRule?: (node: Node) => Node): void; - function emit(node: Node | undefined, parenthesizerRule?: (node: Node) => Node) { + function emit(node: T, parenthesizerRule?: (node: T) => T): void; + function emit(node: T | undefined, parenthesizerRule?: (node: T) => T): void; + function emit(node: T | undefined, parenthesizerRule?: (node: T) => T) { if (node === undefined) return; const prevSourceFileTextKind = recordBundleFileInternalSectionStart(node); pipelineEmit(EmitHint.Unspecified, node, parenthesizerRule); @@ -1692,14 +1693,14 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri pipelineEmit(EmitHint.IdentifierName, node, /*parenthesizerRule*/ undefined); } - function emitExpression(node: Expression, parenthesizerRule?: (node: Expression) => Expression): void; - function emitExpression(node: Expression | undefined, parenthesizerRule?: (node: Expression) => Expression): void; - function emitExpression(node: Expression | undefined, parenthesizerRule?: (node: Expression) => Expression) { + function emitExpression(node: T, parenthesizerRule?: (node: T) => T): void; + function emitExpression(node: T | undefined, parenthesizerRule?: (node: T) => T): void; + function emitExpression(node: T | undefined, parenthesizerRule?: (node: T) => T) { if (node === undefined) return; pipelineEmit(EmitHint.Expression, node, parenthesizerRule); } - function emitJsxAttributeValue(node: StringLiteral | JsxExpression): void { + function emitJsxAttributeValue(node: JsxAttributeValue): void { pipelineEmit(isStringLiteral(node) ? EmitHint.JsxAttributeValue : EmitHint.Unspecified, node); } @@ -1713,7 +1714,7 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri preserveSourceNewlines = savedPreserveSourceNewlines; } - function pipelineEmit(emitHint: EmitHint, node: Node, parenthesizerRule?: (node: Node) => Node) { + function pipelineEmit(emitHint: EmitHint, node: T, parenthesizerRule?: (node: T) => T) { currentParenthesizerRule = parenthesizerRule; const pipelinePhase = getPipelinePhase(PipelinePhase.Notification, emitHint, node); pipelinePhase(emitHint, node); @@ -3668,7 +3669,7 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri emitSignatureAndBody(node, emitSignatureHead); } - function emitSignatureAndBody(node: FunctionLikeDeclaration, emitSignatureHead: (node: SignatureDeclaration) => void) { + function emitSignatureAndBody(node: T, emitSignatureHead: (node: T) => void) { const body = node.body; if (body) { if (isBlock(body)) { @@ -3702,7 +3703,7 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri } - function emitSignatureHead(node: FunctionDeclaration | FunctionExpression | MethodDeclaration | AccessorDeclaration | ConstructorDeclaration) { + function emitSignatureHead(node: SignatureDeclaration) { emitTypeParameters(node, node.typeParameters); emitParameters(node, node.parameters); emitTypeAnnotation(node.type); @@ -4906,7 +4907,7 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri } } - function emitList(parentNode: Node | undefined, children: NodeArray | undefined, format: ListFormat, parenthesizerRule?: ParenthesizerRuleOrSelector, start?: number, count?: number) { + function emitList>(parentNode: Node | undefined, children: Children | undefined, format: ListFormat, parenthesizerRule?: ParenthesizerRuleOrSelector, start?: number, count?: number) { emitNodeList( emit, parentNode, @@ -4917,11 +4918,11 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri count); } - function emitExpressionList(parentNode: Node | undefined, children: NodeArray | undefined, format: ListFormat, parenthesizerRule?: ParenthesizerRuleOrSelector, start?: number, count?: number) { + function emitExpressionList>(parentNode: Node | undefined, children: Children | undefined, format: ListFormat, parenthesizerRule?: ParenthesizerRuleOrSelector, start?: number, count?: number) { emitNodeList(emitExpression, parentNode, children, format, parenthesizerRule, start, count); } - function emitNodeList(emit: (node: Node, parenthesizerRule?: ((node: Node) => Node) | undefined) => void, parentNode: Node | undefined, children: NodeArray | undefined, format: ListFormat, parenthesizerRule: ParenthesizerRuleOrSelector | undefined, start = 0, count = children ? children.length - start : 0) { + function emitNodeList>(emit: EmitFunction, parentNode: Node | undefined, children: Children | undefined, format: ListFormat, parenthesizerRule: ParenthesizerRuleOrSelector | undefined, start = 0, count = children ? children.length - start : 0) { const isUndefined = children === undefined; if (isUndefined && format & ListFormat.OptionalIfUndefined) { return; @@ -4971,7 +4972,7 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri * * NOTE: You probably don't want to call this directly and should be using `emitList` or `emitExpressionList` instead. */ - function emitNodeListItems(emit: (node: Node, parenthesizerRule?: ((node: Node) => Node) | undefined) => void, parentNode: Node | undefined, children: readonly Node[], format: ListFormat, parenthesizerRule: ParenthesizerRuleOrSelector | undefined, start: number, count: number, hasTrailingComma: boolean, childrenTextRange: TextRange | undefined) { + function emitNodeListItems(emit: EmitFunction, parentNode: Node | undefined, children: readonly Child[], format: ListFormat, parenthesizerRule: ParenthesizerRuleOrSelector | undefined, start: number, count: number, hasTrailingComma: boolean, childrenTextRange: TextRange | undefined) { // Write the opening line terminator or leading whitespace. const mayEmitInterveningComments = (format & ListFormat.NoInterveningComments) === 0; let shouldEmitInterveningComments = mayEmitInterveningComments; @@ -6118,7 +6119,7 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri : `//${comment.text}`; } - function emitBodyWithDetachedComments(node: Node, detachedRange: TextRange, emitCallback: (node: Node) => void) { + function emitBodyWithDetachedComments(node: T, detachedRange: TextRange, emitCallback: (node: T) => void) { enterComment(); const { pos, end } = detachedRange; const emitFlags = getEmitFlags(node); @@ -6351,7 +6352,7 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri } } - function emitComment(text: string, lineMap: number[], writer: EmitTextWriter, commentPos: number, commentEnd: number, newLine: string) { + function emitComment(text: string, lineMap: readonly number[], writer: EmitTextWriter, commentPos: number, commentEnd: number, newLine: string) { if (!currentSourceFile || !shouldWriteComment(currentSourceFile.text, commentPos)) return; emitPos(commentPos); writeCommentRange(text, lineMap, writer, commentPos, commentEnd, newLine); @@ -6577,20 +6578,23 @@ type ParenthesizerRule = (node: T) => T; type ParenthesizerRuleOrSelector = OrdinalParentheizerRuleSelector | ParenthesizerRule; -function emitListItemNoParenthesizer(node: Node, emit: (node: Node, parenthesizerRule?: ((node: Node) => Node) | undefined) => void, _parenthesizerRule: ParenthesizerRuleOrSelector | undefined, _index: number) { +type EmitFunction = (node: T, parenthesizerRule?: ParenthesizerRule) => void; +type EmitListItemFunction = (node: Node, emit: EmitFunction, parenthesizerRule: ParenthesizerRuleOrSelector | undefined, index: number) => void; + +function emitListItemNoParenthesizer(node: Node, emit: EmitFunction, _parenthesizerRule: ParenthesizerRuleOrSelector | undefined, _index: number) { emit(node); } -function emitListItemWithParenthesizerRuleSelector(node: Node, emit: (node: Node, parenthesizerRule?: ((node: Node) => Node) | undefined) => void, parenthesizerRuleSelector: OrdinalParentheizerRuleSelector, index: number) { - emit(node, parenthesizerRuleSelector.select(index)); +function emitListItemWithParenthesizerRuleSelector(node: Node, emit: EmitFunction, parenthesizerRuleSelector: OrdinalParentheizerRuleSelector | undefined, index: number) { + emit(node, parenthesizerRuleSelector!.select(index)); } -function emitListItemWithParenthesizerRule(node: Node, emit: (node: Node, parenthesizerRule?: ((node: Node) => Node) | undefined) => void, parenthesizerRule: ParenthesizerRule | undefined, _index: number) { +function emitListItemWithParenthesizerRule(node: Node, emit: EmitFunction, parenthesizerRule: ParenthesizerRule | undefined, _index: number) { emit(node, parenthesizerRule); } -function getEmitListItem | undefined>(emit: (node: Node, parenthesizerRule?: ((node: Node) => Node) | undefined) => void, parenthesizerRule: R): (node: Node, emit: (node: Node, parenthesizerRule?: ((node: Node) => Node) | undefined) => void, parenthesizerRule: R, index: number) => void { - return emit.length === 1 ? emitListItemNoParenthesizer : - typeof parenthesizerRule === "object" ? emitListItemWithParenthesizerRuleSelector : - emitListItemWithParenthesizerRule; +function getEmitListItem(emit: EmitFunction, parenthesizerRule: ParenthesizerRuleOrSelector | undefined): EmitListItemFunction { + return emit.length === 1 ? emitListItemNoParenthesizer as EmitListItemFunction : + typeof parenthesizerRule === "object" ? emitListItemWithParenthesizerRuleSelector as EmitListItemFunction : + emitListItemWithParenthesizerRule as EmitListItemFunction; } diff --git a/src/compiler/factory/baseNodeFactory.ts b/src/compiler/factory/baseNodeFactory.ts index 019d3b9e27477..5641e25703ebe 100644 --- a/src/compiler/factory/baseNodeFactory.ts +++ b/src/compiler/factory/baseNodeFactory.ts @@ -11,9 +11,9 @@ import { * @internal */ export interface BaseNodeFactory { - createBaseSourceFileNode(kind: SyntaxKind): Node; - createBaseIdentifierNode(kind: SyntaxKind): Node; - createBasePrivateIdentifierNode(kind: SyntaxKind): Node; + createBaseSourceFileNode(kind: SyntaxKind.SourceFile): Node; + createBaseIdentifierNode(kind: SyntaxKind.Identifier): Node; + createBasePrivateIdentifierNode(kind: SyntaxKind.PrivateIdentifier): Node; createBaseTokenNode(kind: SyntaxKind): Node; createBaseNode(kind: SyntaxKind): Node; } @@ -24,11 +24,11 @@ export interface BaseNodeFactory { * @internal */ export function createBaseNodeFactory(): BaseNodeFactory { - let NodeConstructor: new (kind: SyntaxKind, pos?: number, end?: number) => Node; - let TokenConstructor: new (kind: SyntaxKind, pos?: number, end?: number) => Node; - let IdentifierConstructor: new (kind: SyntaxKind, pos?: number, end?: number) => Node; - let PrivateIdentifierConstructor: new (kind: SyntaxKind, pos?: number, end?: number) => Node; - let SourceFileConstructor: new (kind: SyntaxKind, pos?: number, end?: number) => Node; + let NodeConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node; + let TokenConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node; + let IdentifierConstructor: new (kind: SyntaxKind.Identifier, pos: number, end: number) => Node; + let PrivateIdentifierConstructor: new (kind: SyntaxKind.PrivateIdentifier, pos: number, end: number) => Node; + let SourceFileConstructor: new (kind: SyntaxKind.SourceFile, pos: number, end: number) => Node; return { createBaseSourceFileNode, @@ -38,15 +38,15 @@ export function createBaseNodeFactory(): BaseNodeFactory { createBaseNode }; - function createBaseSourceFileNode(kind: SyntaxKind): Node { + function createBaseSourceFileNode(kind: SyntaxKind.SourceFile): Node { return new (SourceFileConstructor || (SourceFileConstructor = objectAllocator.getSourceFileConstructor()))(kind, /*pos*/ -1, /*end*/ -1); } - function createBaseIdentifierNode(kind: SyntaxKind): Node { + function createBaseIdentifierNode(kind: SyntaxKind.Identifier): Node { return new (IdentifierConstructor || (IdentifierConstructor = objectAllocator.getIdentifierConstructor()))(kind, /*pos*/ -1, /*end*/ -1); } - function createBasePrivateIdentifierNode(kind: SyntaxKind): Node { + function createBasePrivateIdentifierNode(kind: SyntaxKind.PrivateIdentifier): Node { return new (PrivateIdentifierConstructor || (PrivateIdentifierConstructor = objectAllocator.getPrivateIdentifierConstructor()))(kind, /*pos*/ -1, /*end*/ -1); } diff --git a/src/compiler/factory/nodeFactory.ts b/src/compiler/factory/nodeFactory.ts index aef623811d658..ea7d745599157 100644 --- a/src/compiler/factory/nodeFactory.ts +++ b/src/compiler/factory/nodeFactory.ts @@ -6883,9 +6883,9 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode * @param statementOffset The offset at which to begin the copy. * @param visitor Optional callback used to visit any custom prologue directives. */ - function copyCustomPrologue(source: readonly Statement[], target: Push, statementOffset: number, visitor?: (node: Node) => VisitResult, filter?: (node: Node) => boolean): number; - function copyCustomPrologue(source: readonly Statement[], target: Push, statementOffset: number | undefined, visitor?: (node: Node) => VisitResult, filter?: (node: Node) => boolean): number | undefined; - function copyCustomPrologue(source: readonly Statement[], target: Push, statementOffset: number | undefined, visitor?: (node: Node) => VisitResult, filter: (node: Node) => boolean = returnTrue): number | undefined { + function copyCustomPrologue(source: readonly Statement[], target: Push, statementOffset: number, visitor?: (node: Node) => VisitResult, filter?: (node: Statement) => boolean): number; + function copyCustomPrologue(source: readonly Statement[], target: Push, statementOffset: number | undefined, visitor?: (node: Node) => VisitResult, filter?: (node: Statement) => boolean): number | undefined; + function copyCustomPrologue(source: readonly Statement[], target: Push, statementOffset: number | undefined, visitor?: (node: Node) => VisitResult, filter: (node: Statement) => boolean = returnTrue): number | undefined { const numStatements = source.length; while (statementOffset !== undefined && statementOffset < numStatements) { const statement = source[statementOffset]; diff --git a/src/compiler/factory/utilities.ts b/src/compiler/factory/utilities.ts index 91823cef7cc1b..2db193390a873 100644 --- a/src/compiler/factory/utilities.ts +++ b/src/compiler/factory/utilities.ts @@ -1455,7 +1455,7 @@ export function createBinaryExpressionTrampoline( const machine = new BinaryExpressionStateMachine(onEnter, onLeft, onOperator, onRight, onExit, foldState); return trampoline; - function trampoline(node: BinaryExpression, outerState?: TOuterState) { + function trampoline(node: BinaryExpression, outerState: TOuterState) { const resultHolder: { value: TResult } = { value: undefined! }; const stateStack: BinaryExpressionState[] = [BinaryExpressionState.enter]; const nodeStack: BinaryExpression[] = [node]; diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index bfdd8a82677b9..e22fe45942ad4 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -406,11 +406,11 @@ const enum SpeculationKind { Reparse } -let NodeConstructor: new (kind: SyntaxKind, pos?: number, end?: number) => Node; -let TokenConstructor: new (kind: SyntaxKind, pos?: number, end?: number) => Node; -let IdentifierConstructor: new (kind: SyntaxKind, pos?: number, end?: number) => Node; -let PrivateIdentifierConstructor: new (kind: SyntaxKind, pos?: number, end?: number) => Node; -let SourceFileConstructor: new (kind: SyntaxKind, pos?: number, end?: number) => Node; +let NodeConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node; +let TokenConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node; +let IdentifierConstructor: new (kind: SyntaxKind.Identifier, pos: number, end: number) => Node; +let PrivateIdentifierConstructor: new (kind: SyntaxKind.PrivateIdentifier, pos: number, end: number) => Node; +let SourceFileConstructor: new (kind: SyntaxKind.SourceFile, pos: number, end: number) => Node; /** * NOTE: You should not use this, it is only exported to support `createNode` in `~/src/deprecatedCompat/deprecations.ts`. @@ -1426,9 +1426,9 @@ namespace Parser { // capture constructors in 'initializeState' to avoid null checks let NodeConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node; let TokenConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node; - let IdentifierConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node; - let PrivateIdentifierConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node; - let SourceFileConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node; + let IdentifierConstructor: new (kind: SyntaxKind.Identifier, pos: number, end: number) => Identifier; + let PrivateIdentifierConstructor: new (kind: SyntaxKind.PrivateIdentifier, pos: number, end: number) => PrivateIdentifier; + let SourceFileConstructor: new (kind: SyntaxKind.SourceFile, pos: number, end: number) => SourceFile; function countNode(node: Node) { nodeCount++; @@ -2543,9 +2543,9 @@ namespace Parser { function createMissingNode(kind: T["kind"], reportAtCurrentPosition: false, diagnosticMessage?: DiagnosticMessage, arg0?: any): T; function createMissingNode(kind: T["kind"], reportAtCurrentPosition: boolean, diagnosticMessage: DiagnosticMessage, arg0?: any): T; - function createMissingNode(kind: T["kind"], reportAtCurrentPosition: boolean, diagnosticMessage: DiagnosticMessage, arg0?: any): T { + function createMissingNode(kind: T["kind"], reportAtCurrentPosition: boolean, diagnosticMessage?: DiagnosticMessage, arg0?: any): T { if (reportAtCurrentPosition) { - parseErrorAtPosition(scanner.getStartPos(), 0, diagnosticMessage, arg0); + parseErrorAtPosition(scanner.getStartPos(), 0, diagnosticMessage!, arg0); } else if (diagnosticMessage) { parseErrorAtCurrentToken(diagnosticMessage, arg0); @@ -9639,7 +9639,9 @@ namespace IncrementalParser { } } - function moveElementEntirelyPastChangeRange(element: IncrementalElement, isArray: boolean, delta: number, oldText: string, newText: string, aggressiveChecks: boolean) { + function moveElementEntirelyPastChangeRange(element: IncrementalNode, isArray: false, delta: number, oldText: string, newText: string, aggressiveChecks: boolean): void; + function moveElementEntirelyPastChangeRange(element: IncrementalNodeArray, isArray: true, delta: number, oldText: string, newText: string, aggressiveChecks: boolean): void; + function moveElementEntirelyPastChangeRange(element: IncrementalNode | IncrementalNodeArray, isArray: boolean, delta: number, oldText: string, newText: string, aggressiveChecks: boolean) { if (isArray) { visitArray(element as IncrementalNodeArray); } @@ -9666,7 +9668,7 @@ namespace IncrementalParser { Debug.assert(text === newText.substring(node.pos, node.end)); } - forEachChild(node, visitNode, visitArray); + forEachChild(node, visitNode as (node: Node) => void, visitArray as (nodes: NodeArray) => void); if (hasJSDocNodes(node)) { for (const jsDocComment of node.jsDoc!) { visitNode(jsDocComment as Node as IncrementalNode); @@ -9819,7 +9821,7 @@ namespace IncrementalParser { // Adjust the pos or end (or both) of the intersecting element accordingly. adjustIntersectingElement(child, changeStart, changeRangeOldEnd, changeRangeNewEnd, delta); - forEachChild(child, visitNode, visitArray); + forEachChild(child, visitNode as (node: Node) => void, visitArray as (nodes: NodeArray) => void); if (hasJSDocNodes(child)) { for (const jsDocComment of child.jsDoc!) { visitNode(jsDocComment as Node as IncrementalNode); diff --git a/src/compiler/path.ts b/src/compiler/path.ts index b963c9e0cc929..b2e7d890185a1 100644 --- a/src/compiler/path.ts +++ b/src/compiler/path.ts @@ -967,14 +967,14 @@ export function forEachAncestorDirectory(directory: Path, callback: (director /** @internal */ export function forEachAncestorDirectory(directory: string, callback: (directory: string) => T | undefined): T | undefined; /** @internal */ -export function forEachAncestorDirectory(directory: Path, callback: (directory: Path) => T | undefined): T | undefined { +export function forEachAncestorDirectory(directory: P, callback: (directory: P) => T | undefined): T | undefined { while (true) { const result = callback(directory); if (result !== undefined) { return result; } - const parentPath = getDirectoryPath(directory); + const parentPath = getDirectoryPath(directory) as P; if (parentPath === directory) { return undefined; } diff --git a/src/compiler/program.ts b/src/compiler/program.ts index dc7cd4784245b..4bbe445845f80 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -1540,7 +1540,7 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg } let actualResolveTypeReferenceDirectiveNamesWorker: ( - typeDirectiveNames: T[], + typeDirectiveNames: readonly T[], containingFile: string, redirectedReference: ResolvedProjectReference | undefined, options: CompilerOptions, @@ -1879,7 +1879,7 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg return result; } - function resolveTypeReferenceDirectiveNamesWorker(typeDirectiveNames: T[], containingFile: string | SourceFile, reusedNames: readonly T[] | undefined): readonly ResolvedTypeReferenceDirectiveWithFailedLookupLocations[] { + function resolveTypeReferenceDirectiveNamesWorker(typeDirectiveNames: readonly T[], containingFile: string | SourceFile, reusedNames: readonly T[] | undefined): readonly ResolvedTypeReferenceDirectiveWithFailedLookupLocations[] { if (!typeDirectiveNames.length) return []; const containingSourceFile = !isString(containingFile) ? containingFile : undefined; const containingFileName = !isString(containingFile) ? getNormalizedAbsolutePath(containingFile.originalFileName, currentDirectory) : containingFile; @@ -2113,7 +2113,7 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg function resolveTypeReferenceDirectiveNamesReusingOldState(typeDirectiveNames: readonly FileReference[], containingFile: SourceFile): readonly ResolvedTypeReferenceDirectiveWithFailedLookupLocations[]; function resolveTypeReferenceDirectiveNamesReusingOldState(typeDirectiveNames: string[], containingFile: string): readonly ResolvedTypeReferenceDirectiveWithFailedLookupLocations[]; - function resolveTypeReferenceDirectiveNamesReusingOldState(typeDirectiveNames: T[], containingFile: string | SourceFile): readonly ResolvedTypeReferenceDirectiveWithFailedLookupLocations[] { + function resolveTypeReferenceDirectiveNamesReusingOldState(typeDirectiveNames: readonly T[], containingFile: string | SourceFile): readonly ResolvedTypeReferenceDirectiveWithFailedLookupLocations[] { if (structureIsReused === StructureIsReused.Not) { // If the old program state does not permit reusing resolutions and `file` does not contain locally defined ambient modules, // the best we can do is fallback to the default logic. @@ -3077,7 +3077,7 @@ export function createProgram(rootNamesOrOptions: readonly string[] | CreateProg return result; } - function getDeclarationDiagnosticsForFile(sourceFile: SourceFile, cancellationToken: CancellationToken): readonly DiagnosticWithLocation[] { + function getDeclarationDiagnosticsForFile(sourceFile: SourceFile, cancellationToken: CancellationToken | undefined): readonly DiagnosticWithLocation[] { return sourceFile.isDeclarationFile ? [] : getDeclarationDiagnosticsWorker(sourceFile, cancellationToken); } diff --git a/src/compiler/scanner.ts b/src/compiler/scanner.ts index db14e8710fa87..180e380052c3e 100644 --- a/src/compiler/scanner.ts +++ b/src/compiler/scanner.ts @@ -884,28 +884,24 @@ function iterateCommentRanges(reduce: boolean, text: string, pos: number, export function forEachLeadingCommentRange(text: string, pos: number, cb: (pos: number, end: number, kind: CommentKind, hasTrailingNewLine: boolean) => U): U | undefined; export function forEachLeadingCommentRange(text: string, pos: number, cb: (pos: number, end: number, kind: CommentKind, hasTrailingNewLine: boolean, state: T) => U, state: T): U | undefined; export function forEachLeadingCommentRange(text: string, pos: number, cb: (pos: number, end: number, kind: CommentKind, hasTrailingNewLine: boolean, state: T) => U, state?: T): U | undefined { - return iterateCommentRanges(/*reduce*/ false, text, pos, /*trailing*/ false, cb, state); + return iterateCommentRanges(/*reduce*/ false, text, pos, /*trailing*/ false, cb, state!); } export function forEachTrailingCommentRange(text: string, pos: number, cb: (pos: number, end: number, kind: CommentKind, hasTrailingNewLine: boolean) => U): U | undefined; export function forEachTrailingCommentRange(text: string, pos: number, cb: (pos: number, end: number, kind: CommentKind, hasTrailingNewLine: boolean, state: T) => U, state: T): U | undefined; export function forEachTrailingCommentRange(text: string, pos: number, cb: (pos: number, end: number, kind: CommentKind, hasTrailingNewLine: boolean, state: T) => U, state?: T): U | undefined { - return iterateCommentRanges(/*reduce*/ false, text, pos, /*trailing*/ true, cb, state); + return iterateCommentRanges(/*reduce*/ false, text, pos, /*trailing*/ true, cb, state!); } -export function reduceEachLeadingCommentRange(text: string, pos: number, cb: (pos: number, end: number, kind: CommentKind, hasTrailingNewLine: boolean, state: T, memo: U) => U, state: T, initial: U) { +export function reduceEachLeadingCommentRange(text: string, pos: number, cb: (pos: number, end: number, kind: CommentKind, hasTrailingNewLine: boolean, state: T) => U, state: T, initial: U) { return iterateCommentRanges(/*reduce*/ true, text, pos, /*trailing*/ false, cb, state, initial); } -export function reduceEachTrailingCommentRange(text: string, pos: number, cb: (pos: number, end: number, kind: CommentKind, hasTrailingNewLine: boolean, state: T, memo: U) => U, state: T, initial: U) { +export function reduceEachTrailingCommentRange(text: string, pos: number, cb: (pos: number, end: number, kind: CommentKind, hasTrailingNewLine: boolean, state: T) => U, state: T, initial: U) { return iterateCommentRanges(/*reduce*/ true, text, pos, /*trailing*/ true, cb, state, initial); } -function appendCommentRange(pos: number, end: number, kind: CommentKind, hasTrailingNewLine: boolean, _state: any, comments: CommentRange[]) { - if (!comments) { - comments = []; - } - +function appendCommentRange(pos: number, end: number, kind: CommentKind, hasTrailingNewLine: boolean, _state: any, comments: CommentRange[] = []) { comments.push({ kind, pos, end, hasTrailingNewLine }); return comments; } diff --git a/src/compiler/symbolWalker.ts b/src/compiler/symbolWalker.ts index 591e19c8eb647..09853623cc5db 100644 --- a/src/compiler/symbolWalker.ts +++ b/src/compiler/symbolWalker.ts @@ -1,4 +1,5 @@ import { + BaseType, clear, EntityNameOrEntityNameExpression, forEach, @@ -9,7 +10,6 @@ import { IndexType, InterfaceType, MappedType, - Node, ObjectFlags, ObjectType, ResolvedType, @@ -31,10 +31,10 @@ export function createGetSymbolWalker( getRestTypeOfSignature: (sig: Signature) => Type, getTypePredicateOfSignature: (sig: Signature) => TypePredicate | undefined, getReturnTypeOfSignature: (sig: Signature) => Type, - getBaseTypes: (type: Type) => Type[], + getBaseTypes: (type: InterfaceType) => BaseType[], resolveStructuredTypeMembers: (type: ObjectType) => ResolvedType, getTypeOfSymbol: (sym: Symbol) => Type, - getResolvedSymbol: (node: Node) => Symbol, + getResolvedSymbol: (node: Identifier) => Symbol, getConstraintOfTypeParameter: (typeParameter: TypeParameter) => Type | undefined, getFirstIdentifier: (node: EntityNameOrEntityNameExpression) => Identifier, getTypeArguments: (type: TypeReference) => readonly Type[]) { @@ -214,3 +214,4 @@ export function createGetSymbolWalker( } } } + diff --git a/src/compiler/sys.ts b/src/compiler/sys.ts index 097960d0e2634..7efb312fadc51 100644 --- a/src/compiler/sys.ts +++ b/src/compiler/sys.ts @@ -1296,7 +1296,6 @@ export function patchWriteFileEnsuringDirectory(sys: System) { path => sys.directoryExists(path)); } -/** @internal */ export type BufferEncoding = "ascii" | "utf8" | "utf-8" | "utf16le" | "ucs2" | "ucs-2" | "base64" | "latin1" | "binary" | "hex"; /** @internal */ diff --git a/src/compiler/transformers/classFields.ts b/src/compiler/transformers/classFields.ts index c299f16f2a24a..6a5a1a6aa52fc 100644 --- a/src/compiler/transformers/classFields.ts +++ b/src/compiler/transformers/classFields.ts @@ -9,7 +9,6 @@ import { AssignmentPattern, AutoAccessorPropertyDeclaration, BinaryExpression, - BindingOrAssignmentElement, Bundle, CallExpression, chainBundle, @@ -70,6 +69,7 @@ import { isArrowFunction, isAssignmentExpression, isAutoAccessorPropertyDeclaration, + isBindingOrAssignmentElement, isCallChain, isClassDeclaration, isClassElement, @@ -392,7 +392,7 @@ export function transformClassFields(context: TransformationContext): (x: Source return visited; } - function visitor(node: Node): VisitResult { + function visitor(node: Node): VisitResult { if (!(node.transformFlags & TransformFlags.ContainsClassFields) && !(node.transformFlags & TransformFlags.ContainsLexicalThisOrSuper)) { return node; @@ -455,7 +455,7 @@ export function transformClassFields(context: TransformationContext): (x: Source /** * Visits a node in an expression whose result is discarded. */ - function discardedValueVisitor(node: Node): VisitResult { + function discardedValueVisitor(node: Node): VisitResult { switch (node.kind) { case SyntaxKind.PrefixUnaryExpression: case SyntaxKind.PostfixUnaryExpression: @@ -470,7 +470,7 @@ export function transformClassFields(context: TransformationContext): (x: Source /** * Visits a node in a {@link HeritageClause}. */ - function heritageClauseVisitor(node: Node): VisitResult { + function heritageClauseVisitor(node: Node): VisitResult { switch (node.kind) { case SyntaxKind.HeritageClause: return visitEachChild(node, heritageClauseVisitor, context); @@ -484,7 +484,7 @@ export function transformClassFields(context: TransformationContext): (x: Source /** * Visits the assignment target of a destructuring assignment. */ - function assignmentTargetVisitor(node: Node): VisitResult { + function assignmentTargetVisitor(node: Node): VisitResult { switch (node.kind) { case SyntaxKind.ObjectLiteralExpression: case SyntaxKind.ArrayLiteralExpression: @@ -497,7 +497,7 @@ export function transformClassFields(context: TransformationContext): (x: Source /** * Visits a member of a class. */ - function classElementVisitor(node: Node): VisitResult { + function classElementVisitor(node: Node): VisitResult { switch (node.kind) { case SyntaxKind.Constructor: return visitConstructorDeclaration(node as ConstructorDeclaration); @@ -568,6 +568,7 @@ export function transformClassFields(context: TransformationContext): (x: Source const info = accessPrivateIdentifier(node.left); if (info) { const receiver = visitNode(node.right, visitor, isExpression); + Debug.assert(receiver); return setOriginalNode( context.getEmitHelperFactory().createClassPrivateFieldInHelper(info.brandCheckIdentifier, receiver), @@ -594,6 +595,7 @@ export function transformClassFields(context: TransformationContext): (x: Source function visitComputedPropertyName(node: ComputedPropertyName) { let expression = visitNode(node.expression, visitor, isExpression); + Debug.assert(expression); if (some(pendingExpressions)) { if (isParenthesizedExpression(expression)) { expression = factory.updateParenthesizedExpression(expression, factory.inlineExpressions([...pendingExpressions, expression.expression])); @@ -702,6 +704,7 @@ export function transformClassFields(context: TransformationContext): (x: Source const temp = factory.createTempVariable(hoistVariableDeclaration); setSourceMapRange(temp, name.expression); const expression = visitNode(name.expression, visitor, isExpression); + Debug.assert(expression); const assignment = factory.createAssignment(temp, expression); setSourceMapRange(assignment, name.expression); getterName = factory.updateComputedPropertyName(name, factory.inlineExpressions([assignment, temp])); @@ -814,7 +817,7 @@ export function transformClassFields(context: TransformationContext): (x: Source } function createPrivateIdentifierAccess(info: PrivateIdentifierInfo, receiver: Expression): Expression { - return createPrivateIdentifierAccessHelper(info, visitNode(receiver, visitor, isExpression)); + return createPrivateIdentifierAccessHelper(info, Debug.checkDefined(visitNode(receiver, visitor, isExpression))); } function createPrivateIdentifierAccessHelper(info: PrivateIdentifierInfo, receiver: Expression): Expression { @@ -898,7 +901,7 @@ export function transformClassFields(context: TransformationContext): (x: Source // converts `super[x]` into `Reflect.get(_baseTemp, x, _classTemp)` const superProperty = factory.createReflectGetCall( superClassReference, - visitNode(node.argumentExpression, visitor, isExpression), + Debug.checkDefined(visitNode(node.argumentExpression, visitor, isExpression)), classConstructor ); setOriginalNode(superProperty, node.expression); @@ -918,6 +921,7 @@ export function transformClassFields(context: TransformationContext): (x: Source let info: PrivateIdentifierInfo | undefined; if (info = accessPrivateIdentifier(operand.name)) { const receiver = visitNode(operand.expression, visitor, isExpression); + Debug.assert(receiver); const { readExpression, initializeExpression } = createCopiableReceiverExpr(receiver); let expression: Expression = createPrivateIdentifierAccess(info, readExpression); @@ -971,7 +975,7 @@ export function transformClassFields(context: TransformationContext): (x: Source } else { getterName = factory.createTempVariable(hoistVariableDeclaration); - setterName = factory.createAssignment(getterName, visitNode(operand.argumentExpression, visitor, isExpression)); + setterName = factory.createAssignment(getterName, Debug.checkDefined(visitNode(operand.argumentExpression, visitor, isExpression))); } } if (setterName && getterName) { @@ -1008,7 +1012,7 @@ export function transformClassFields(context: TransformationContext): (x: Source function visitExpressionStatement(node: ExpressionStatement) { return factory.updateExpressionStatement( node, - visitNode(node.expression, discardedValueVisitor, isExpression) + Debug.checkDefined(visitNode(node.expression, discardedValueVisitor, isExpression)) ); } @@ -1032,17 +1036,17 @@ export function transformClassFields(context: TransformationContext): (x: Source if (isCallChain(node)) { return factory.updateCallChain( node, - factory.createPropertyAccessChain(visitNode(target, visitor), node.questionDotToken, "call"), + factory.createPropertyAccessChain(Debug.checkDefined(visitNode(target, visitor, isExpression)), node.questionDotToken, "call"), /*questionDotToken*/ undefined, /*typeArguments*/ undefined, - [visitNode(thisArg, visitor, isExpression), ...visitNodes(node.arguments, visitor, isExpression)] + [Debug.checkDefined(visitNode(thisArg, visitor, isExpression)), ...visitNodes(node.arguments, visitor, isExpression)] ); } return factory.updateCallExpression( node, - factory.createPropertyAccessExpression(visitNode(target, visitor), "call"), + factory.createPropertyAccessExpression(Debug.checkDefined(visitNode(target, visitor, isExpression)), "call"), /*typeArguments*/ undefined, - [visitNode(thisArg, visitor, isExpression), ...visitNodes(node.arguments, visitor, isExpression)] + [Debug.checkDefined(visitNode(thisArg, visitor, isExpression)), ...visitNodes(node.arguments, visitor, isExpression)] ); } @@ -1055,7 +1059,7 @@ export function transformClassFields(context: TransformationContext): (x: Source // converts `super.f(...)` into `Reflect.get(_baseTemp, "f", _classTemp).call(_classTemp, ...)` const invocation = factory.createFunctionCallCall( - visitNode(node.expression, visitor, isExpression), + Debug.checkDefined(visitNode(node.expression, visitor, isExpression)), currentClassLexicalEnvironment.classConstructor, visitNodes(node.arguments, visitor, isExpression) ); @@ -1075,12 +1079,12 @@ export function transformClassFields(context: TransformationContext): (x: Source return factory.updateTaggedTemplateExpression( node, factory.createCallExpression( - factory.createPropertyAccessExpression(visitNode(target, visitor), "bind"), + factory.createPropertyAccessExpression(Debug.checkDefined(visitNode(target, visitor, isExpression)), "bind"), /*typeArguments*/ undefined, - [visitNode(thisArg, visitor, isExpression)] + [Debug.checkDefined(visitNode(thisArg, visitor, isExpression))] ), /*typeArguments*/ undefined, - visitNode(node.template, visitor, isTemplateLiteral) + Debug.checkDefined(visitNode(node.template, visitor, isTemplateLiteral)) ); } if (shouldTransformSuperInStaticInitializers && @@ -1090,7 +1094,7 @@ export function transformClassFields(context: TransformationContext): (x: Source // converts `` super.f`x` `` into `` Reflect.get(_baseTemp, "f", _classTemp).bind(_classTemp)`x` `` const invocation = factory.createFunctionBindCall( - visitNode(node.tag, visitor, isExpression), + Debug.checkDefined(visitNode(node.tag, visitor, isExpression)), currentClassLexicalEnvironment.classConstructor, [] ); @@ -1100,7 +1104,7 @@ export function transformClassFields(context: TransformationContext): (x: Source node, invocation, /*typeArguments*/ undefined, - visitNode(node.template, visitor, isTemplateLiteral) + Debug.checkDefined(visitNode(node.template, visitor, isTemplateLiteral)) ); } return visitEachChild(node, visitor, context); @@ -1137,9 +1141,9 @@ export function transformClassFields(context: TransformationContext): (x: Source pendingExpressions = undefined; node = factory.updateBinaryExpression( node, - visitNode(node.left, assignmentTargetVisitor), + Debug.checkDefined(visitNode(node.left, assignmentTargetVisitor, isExpression)), node.operatorToken, - visitNode(node.right, visitor) + Debug.checkDefined(visitNode(node.right, visitor, isExpression)) ); const expr = some(pendingExpressions) ? factory.inlineExpressions(compact([...pendingExpressions, node])) : @@ -1176,7 +1180,7 @@ export function transformClassFields(context: TransformationContext): (x: Source node, visitInvalidSuperProperty(node.left), node.operatorToken, - visitNode(node.right, visitor, isExpression)); + Debug.checkDefined(visitNode(node.right, visitor, isExpression))); } if (classConstructor && superClassReference) { let setterName = @@ -1204,6 +1208,7 @@ export function transformClassFields(context: TransformationContext): (x: Source setOriginalNode(superPropertyGet, node.left); setTextRange(superPropertyGet, node.left); + Debug.assert(expression); expression = factory.createBinaryExpression( superPropertyGet, getNonAssignmentOperatorForCompoundAssignment(node.operatorToken.kind), @@ -1214,10 +1219,12 @@ export function transformClassFields(context: TransformationContext): (x: Source const temp = valueIsDiscarded ? undefined : factory.createTempVariable(hoistVariableDeclaration); if (temp) { + Debug.assert(expression); expression = factory.createAssignment(temp, expression); setTextRange(temp, node); } + Debug.assert(expression); expression = factory.createReflectSetCall( superClassReference, setterName, @@ -1246,8 +1253,8 @@ export function transformClassFields(context: TransformationContext): (x: Source } function createPrivateIdentifierAssignment(info: PrivateIdentifierInfo, receiver: Expression, right: Expression, operator: AssignmentOperator): Expression { - receiver = visitNode(receiver, visitor, isExpression); - right = visitNode(right, visitor, isExpression); + receiver = Debug.checkDefined(visitNode(receiver, visitor, isExpression)); + right = Debug.checkDefined(visitNode(right, visitor, isExpression)); if (isCompoundAssignment(operator)) { const { readExpression, initializeExpression } = createCopiableReceiverExpr(receiver); @@ -1361,7 +1368,7 @@ export function transformClassFields(context: TransformationContext): (x: Source node, factory.createAssignment( temp, - visitNode(node.expression, visitor, isExpression) + Debug.checkDefined(visitNode(node.expression, visitor, isExpression)) ), /*typeArguments*/ undefined ); @@ -2071,7 +2078,7 @@ export function transformClassFields(context: TransformationContext): (x: Source factory.updateElementAccessExpression( node, factory.createVoidZero(), - visitNode(node.argumentExpression, visitor, isExpression)); + Debug.checkDefined(visitNode(node.argumentExpression, visitor, isExpression))); } function onEmitNode(hint: EmitHint, node: Node, emitCallback: (hint: EmitHint, node: Node) => void) { @@ -2215,6 +2222,7 @@ export function transformClassFields(context: TransformationContext): (x: Source function getPropertyNameExpressionIfNeeded(name: PropertyName, shouldHoist: boolean): Expression | undefined { if (isComputedPropertyName(name)) { const expression = visitNode(name.expression, visitor, isExpression); + Debug.assert(expression); const innerExpression = skipPartiallyEmittedExpressions(expression); const inlinable = isSimpleInlineableExpression(innerExpression); const alreadyTransformed = isAssignmentExpression(innerExpression) && isGeneratedIdentifier(innerExpression.left); @@ -2542,7 +2550,7 @@ export function transformClassFields(context: TransformationContext): (x: Source // differently inside the function. if (isThisProperty(node) || isSuperProperty(node) || !isSimpleCopiableExpression(node.expression)) { receiver = factory.createTempVariable(hoistVariableDeclaration, /*reservedInNestedScopes*/ true); - getPendingExpressions().push(factory.createBinaryExpression(receiver, SyntaxKind.EqualsToken, visitNode(node.expression, visitor, isExpression))); + getPendingExpressions().push(factory.createBinaryExpression(receiver, SyntaxKind.EqualsToken, Debug.checkDefined(visitNode(node.expression, visitor, isExpression)))); } return factory.createAssignmentTargetWrapper( parameter, @@ -2555,7 +2563,8 @@ export function transformClassFields(context: TransformationContext): (x: Source ); } - function visitArrayAssignmentTarget(node: BindingOrAssignmentElement) { + function visitArrayAssignmentTarget(node: Node) { + Debug.assertNode(node, isBindingOrAssignmentElement); const target = getTargetOfBindingOrAssignmentElement(node); if (target) { let wrapped: LeftHandSideExpression | undefined; @@ -2595,7 +2604,7 @@ export function transformClassFields(context: TransformationContext): (x: Source node, wrapped, node.operatorToken, - visitNode(node.right, visitor, isExpression) + Debug.checkDefined(visitNode(node.right, visitor, isExpression)) ); } else if (isSpreadElement(node)) { @@ -2649,16 +2658,16 @@ export function transformClassFields(context: TransformationContext): (x: Source const initializer = getInitializerOfBindingOrAssignmentElement(node); return factory.updatePropertyAssignment( node, - visitNode(node.name, visitor, isPropertyName), + Debug.checkDefined(visitNode(node.name, visitor, isPropertyName)), wrapped ? - initializer ? factory.createAssignment(wrapped, visitNode(initializer, visitor)) : wrapped : - visitNode(node.initializer, assignmentTargetVisitor, isExpression) + initializer ? factory.createAssignment(wrapped, Debug.checkDefined(visitNode(initializer, visitor, isExpression))) : wrapped : + Debug.checkDefined(visitNode(node.initializer, assignmentTargetVisitor, isExpression)) ); } if (isSpreadAssignment(node)) { return factory.updateSpreadAssignment( node, - wrapped || visitNode(node.expression, assignmentTargetVisitor, isExpression) + wrapped || Debug.checkDefined(visitNode(node.expression, assignmentTargetVisitor, isExpression)) ); } Debug.assert(wrapped === undefined, "Should not have generated a wrapped target"); diff --git a/src/compiler/transformers/declarations.ts b/src/compiler/transformers/declarations.ts index cce16221d24c4..e14bd6d5fe250 100644 --- a/src/compiler/transformers/declarations.ts +++ b/src/compiler/transformers/declarations.ts @@ -93,13 +93,17 @@ import { InterfaceDeclaration, isAnyImportSyntax, isArray, + isArrayBindingElement, + isBindingElement, isBindingPattern, isClassDeclaration, + isClassElement, isDeclaration, isEntityName, isEntityNameExpression, isExportAssignment, isExportDeclaration, + isExpressionWithTypeArguments, isExternalModule, isExternalModuleAugmentation, isExternalModuleIndicator, @@ -131,15 +135,18 @@ import { isSourceFile, isSourceFileJS, isSourceFileNotJson, + isStatement, isStringANonContextualKeyword, isStringLiteral, isStringLiteralLike, isTupleTypeNode, isTypeAliasDeclaration, + isTypeElement, isTypeNode, isTypeParameterDeclaration, isTypeQueryNode, isUnparsedSource, + isVariableDeclaration, last, LateBoundDeclaration, LateVisibilityPaintedStatement, @@ -277,7 +284,7 @@ export function transformDeclarations(context: TransformationContext) { let enclosingDeclaration: Node; let necessaryTypeReferences: Set<[specifier: string, mode: ResolutionMode]> | undefined; let lateMarkedStatements: LateVisibilityPaintedStatement[] | undefined; - let lateStatementReplacementMap: Map>; + let lateStatementReplacementMap: Map>; let suppressNewDiagnosticContexts: boolean; let exportedModulesFromDeclarationEmit: Symbol[] | undefined; @@ -502,7 +509,7 @@ export function transformDeclarations(context: TransformationContext) { if (isExternalOrCommonJsModule(sourceFile) || isJsonSourceFile(sourceFile)) { resultHasExternalModuleIndicator = false; // unused in external module bundle emit (all external modules are within module blocks, therefore are known to be modules) needsDeclare = false; - const statements = isSourceFileJS(sourceFile) ? factory.createNodeArray(transformDeclarationsForJS(sourceFile, /*bundled*/ true)) : visitNodes(sourceFile.statements, visitDeclarationStatements); + const statements = isSourceFileJS(sourceFile) ? factory.createNodeArray(transformDeclarationsForJS(sourceFile, /*bundled*/ true)) : visitNodes(sourceFile.statements, visitDeclarationStatements, isStatement); const newFile = factory.updateSourceFile(sourceFile, [factory.createModuleDeclaration( [factory.createModifier(SyntaxKind.DeclareKeyword)], factory.createStringLiteral(getResolvedExternalModuleName(context.getEmitHost(), sourceFile)), @@ -511,7 +518,7 @@ export function transformDeclarations(context: TransformationContext) { return newFile; } needsDeclare = true; - const updated = isSourceFileJS(sourceFile) ? factory.createNodeArray(transformDeclarationsForJS(sourceFile)) : visitNodes(sourceFile.statements, visitDeclarationStatements); + const updated = isSourceFileJS(sourceFile) ? factory.createNodeArray(transformDeclarationsForJS(sourceFile)) : visitNodes(sourceFile.statements, visitDeclarationStatements, isStatement); return factory.updateSourceFile(sourceFile, transformAndReplaceLatePaintedStatements(updated), /*isDeclarationFile*/ true, /*referencedFiles*/ [], /*typeReferences*/ [], /*hasNoDefaultLib*/ false, /*libReferences*/ []); } ), mapDefined(node.prepends, prepend => { @@ -560,7 +567,7 @@ export function transformDeclarations(context: TransformationContext) { emittedImports = filter(combinedStatements, isAnyImportSyntax); } else { - const statements = visitNodes(node.statements, visitDeclarationStatements); + const statements = visitNodes(node.statements, visitDeclarationStatements, isStatement); combinedStatements = setTextRange(factory.createNodeArray(transformAndReplaceLatePaintedStatements(statements)), node.statements); refs.forEach(referenceVisitor); emittedImports = filter(combinedStatements, isAnyImportSyntax); @@ -676,14 +683,14 @@ export function transformDeclarations(context: TransformationContext) { } else { if (name.kind === SyntaxKind.ArrayBindingPattern) { - return factory.updateArrayBindingPattern(name, visitNodes(name.elements, visitBindingElement)); + return factory.updateArrayBindingPattern(name, visitNodes(name.elements, visitBindingElement, isArrayBindingElement)); } else { - return factory.updateObjectBindingPattern(name, visitNodes(name.elements, visitBindingElement)); + return factory.updateObjectBindingPattern(name, visitNodes(name.elements, visitBindingElement, isBindingElement)); } } - function visitBindingElement(elem: T): T; + function visitBindingElement(elem: T): T; function visitBindingElement(elem: ArrayBindingElement): ArrayBindingElement { if (elem.kind === SyntaxKind.OmittedExpression) { return elem; @@ -767,10 +774,10 @@ export function transformDeclarations(context: TransformationContext) { (resolver.isRequiredInitializedParameter(node) || resolver.isOptionalUninitializedParameterProperty(node)); if (type && !shouldUseResolverType) { - return visitNode(type, visitDeclarationSubtree); + return visitNode(type, visitDeclarationSubtree, isTypeNode); } if (!getParseTreeNode(node)) { - return type ? visitNode(type, visitDeclarationSubtree) : factory.createKeywordTypeNode(SyntaxKind.AnyKeyword); + return type ? visitNode(type, visitDeclarationSubtree, isTypeNode) : factory.createKeywordTypeNode(SyntaxKind.AnyKeyword); } if (node.kind === SyntaxKind.SetAccessor) { // Set accessors with no associated type node (from it's param or get accessor return) are `any` since they are never contextually typed right now @@ -891,7 +898,7 @@ export function transformDeclarations(context: TransformationContext) { } function ensureTypeParams(node: Node, params: NodeArray | undefined) { - return hasEffectiveModifier(node, ModifierFlags.Private) ? undefined : visitNodes(params, visitDeclarationSubtree); + return hasEffectiveModifier(node, ModifierFlags.Private) ? undefined : visitNodes(params, visitDeclarationSubtree, isTypeParameterDeclaration); } function isEnclosingDeclaration(node: Node) { @@ -1061,13 +1068,13 @@ export function transformDeclarations(context: TransformationContext) { // And lastly, we need to get the final form of all those indetermine import declarations from before and add them to the output list // (and remove them from the set to examine for outter declarations) - return visitNodes(statements, visitLateVisibilityMarkedStatements); + return visitNodes(statements, visitLateVisibilityMarkedStatements, isStatement); function visitLateVisibilityMarkedStatements(statement: Statement) { if (isLateVisibilityPaintedStatement(statement)) { const key = getOriginalNodeId(statement); if (lateStatementReplacementMap.has(key)) { - const result = lateStatementReplacementMap.get(key); + const result = lateStatementReplacementMap.get(key) as Statement | readonly Statement[] | undefined; lateStatementReplacementMap.delete(key); if (result) { if (isArray(result) ? some(result, needsScopeMarker) : needsScopeMarker(result)) { @@ -1085,7 +1092,7 @@ export function transformDeclarations(context: TransformationContext) { } } - function visitDeclarationSubtree(input: Node): VisitResult { + function visitDeclarationSubtree(input: Node): VisitResult { if (shouldStripInternal(input)) return; if (isDeclaration(input)) { if (isDeclarationAndNotVisible(input)) return; @@ -1254,7 +1261,7 @@ export function transformDeclarations(context: TransformationContext) { input, ensureModifiers(input), updateParamsList(input, input.parameters), - visitNode(input.type, visitDeclarationSubtree) || factory.createKeywordTypeNode(SyntaxKind.AnyKeyword) + visitNode(input.type, visitDeclarationSubtree, isTypeNode) || factory.createKeywordTypeNode(SyntaxKind.AnyKeyword) )); } case SyntaxKind.VariableDeclaration: { @@ -1274,20 +1281,24 @@ export function transformDeclarations(context: TransformationContext) { case SyntaxKind.ConditionalType: { // We have to process conditional types in a special way because for visibility purposes we need to push a new enclosingDeclaration // just for the `infer` types in the true branch. It's an implicit declaration scope that only applies to _part_ of the type. - const checkType = visitNode(input.checkType, visitDeclarationSubtree); - const extendsType = visitNode(input.extendsType, visitDeclarationSubtree); + const checkType = visitNode(input.checkType, visitDeclarationSubtree, isTypeNode); + const extendsType = visitNode(input.extendsType, visitDeclarationSubtree, isTypeNode); const oldEnclosingDecl = enclosingDeclaration; enclosingDeclaration = input.trueType; - const trueType = visitNode(input.trueType, visitDeclarationSubtree); + const trueType = visitNode(input.trueType, visitDeclarationSubtree, isTypeNode); enclosingDeclaration = oldEnclosingDecl; - const falseType = visitNode(input.falseType, visitDeclarationSubtree); + const falseType = visitNode(input.falseType, visitDeclarationSubtree, isTypeNode); + Debug.assert(checkType); + Debug.assert(extendsType); + Debug.assert(trueType); + Debug.assert(falseType); return cleanup(factory.updateConditionalTypeNode(input, checkType, extendsType, trueType, falseType)); } case SyntaxKind.FunctionType: { - return cleanup(factory.updateFunctionTypeNode(input, visitNodes(input.typeParameters, visitDeclarationSubtree), updateParamsList(input, input.parameters), visitNode(input.type, visitDeclarationSubtree))); + return cleanup(factory.updateFunctionTypeNode(input, visitNodes(input.typeParameters, visitDeclarationSubtree, isTypeParameterDeclaration), updateParamsList(input, input.parameters), Debug.checkDefined(visitNode(input.type, visitDeclarationSubtree, isTypeNode)))); } case SyntaxKind.ConstructorType: { - return cleanup(factory.updateConstructorTypeNode(input, ensureModifiers(input), visitNodes(input.typeParameters, visitDeclarationSubtree), updateParamsList(input, input.parameters), visitNode(input.type, visitDeclarationSubtree))); + return cleanup(factory.updateConstructorTypeNode(input, ensureModifiers(input), visitNodes(input.typeParameters, visitDeclarationSubtree, isTypeParameterDeclaration), updateParamsList(input, input.parameters), Debug.checkDefined(visitNode(input.type, visitDeclarationSubtree, isTypeNode)))); } case SyntaxKind.ImportType: { if (!isLiteralImportTypeNode(input)) return cleanup(input); @@ -1334,7 +1345,7 @@ export function transformDeclarations(context: TransformationContext) { return node.parent.kind === SyntaxKind.MethodDeclaration && hasEffectiveModifier(node.parent, ModifierFlags.Private); } - function visitDeclarationStatements(input: Node): VisitResult { + function visitDeclarationStatements(input: Node): VisitResult { if (!isPreservedDeclarationStatement(input)) { // return undefined for unmatched kinds to omit them from the tree return; @@ -1441,7 +1452,7 @@ export function transformDeclarations(context: TransformationContext) { ensureModifiers(input), input.name, visitNodes(input.typeParameters, visitDeclarationSubtree, isTypeParameterDeclaration), - visitNode(input.type, visitDeclarationSubtree, isTypeNode) + Debug.checkDefined(visitNode(input.type, visitDeclarationSubtree, isTypeNode)) )); needsDeclare = previousNeedsDeclare; return clean; @@ -1453,7 +1464,7 @@ export function transformDeclarations(context: TransformationContext) { input.name, ensureTypeParams(input, input.typeParameters), transformHeritageClauses(input.heritageClauses), - visitNodes(input.members, visitDeclarationSubtree) + visitNodes(input.members, visitDeclarationSubtree, isTypeElement) )); } case SyntaxKind.FunctionDeclaration: { @@ -1553,7 +1564,7 @@ export function transformDeclarations(context: TransformationContext) { const oldHasScopeFix = resultHasScopeMarker; resultHasScopeMarker = false; needsScopeFixMarker = false; - const statements = visitNodes(inner.statements, visitDeclarationStatements); + const statements = visitNodes(inner.statements, visitDeclarationStatements, isStatement); let lateStatements = transformAndReplaceLatePaintedStatements(statements); if (input.flags & NodeFlags.Ambient) { needsScopeFixMarker = false; // If it was `declare`'d everything is implicitly exported already, ignore late printed "privates" @@ -1567,7 +1578,7 @@ export function transformDeclarations(context: TransformationContext) { lateStatements = factory.createNodeArray([...lateStatements, createEmptyExports(factory)]); } else { - lateStatements = visitNodes(lateStatements, stripExportModifiers); + lateStatements = visitNodes(lateStatements, stripExportModifiers, isStatement); } } const body = factory.updateModuleBlock(inner, lateStatements); @@ -1658,7 +1669,7 @@ export function transformDeclarations(context: TransformationContext) { /*initializer*/ undefined ) ] : undefined; - const memberNodes = concatenate(concatenate(privateIdentifier, parameterProperties), visitNodes(input.members, visitDeclarationSubtree)); + const memberNodes = concatenate(concatenate(privateIdentifier, parameterProperties), visitNodes(input.members, visitDeclarationSubtree, isClassElement)); const members = factory.createNodeArray(memberNodes); const extendsClause = getEffectiveBaseTypeNode(input); @@ -1678,11 +1689,11 @@ export function transformDeclarations(context: TransformationContext) { if (clause.token === SyntaxKind.ExtendsKeyword) { const oldDiag = getSymbolAccessibilityDiagnostic; getSymbolAccessibilityDiagnostic = createGetSymbolAccessibilityDiagnosticForNode(clause.types[0]); - const newClause = factory.updateHeritageClause(clause, map(clause.types, t => factory.updateExpressionWithTypeArguments(t, newId, visitNodes(t.typeArguments, visitDeclarationSubtree)))); + const newClause = factory.updateHeritageClause(clause, map(clause.types, t => factory.updateExpressionWithTypeArguments(t, newId, visitNodes(t.typeArguments, visitDeclarationSubtree, isTypeNode)))); getSymbolAccessibilityDiagnostic = oldDiag; return newClause; } - return factory.updateHeritageClause(clause, visitNodes(factory.createNodeArray(filter(clause.types, t => isEntityNameExpression(t.expression) || t.expression.kind === SyntaxKind.NullKeyword)), visitDeclarationSubtree)); + return factory.updateHeritageClause(clause, visitNodes(factory.createNodeArray(filter(clause.types, t => isEntityNameExpression(t.expression) || t.expression.kind === SyntaxKind.NullKeyword)), visitDeclarationSubtree, isExpressionWithTypeArguments)); })); return [statement, cleanup(factory.updateClassDeclaration( input, @@ -1741,7 +1752,7 @@ export function transformDeclarations(context: TransformationContext) { function transformVariableStatement(input: VariableStatement) { if (!forEach(input.declarationList.declarations, getBindingNameVisible)) return; - const nodes = visitNodes(input.declarationList.declarations, visitDeclarationSubtree); + const nodes = visitNodes(input.declarationList.declarations, visitDeclarationSubtree, isVariableDeclaration); if (!length(nodes)) return; return factory.updateVariableStatement(input, factory.createNodeArray(ensureModifiers(input)), factory.updateVariableDeclarationList(input.declarationList, nodes)); } @@ -1832,7 +1843,7 @@ export function transformDeclarations(context: TransformationContext) { function transformHeritageClauses(nodes: NodeArray | undefined) { return factory.createNodeArray(filter(map(nodes, clause => factory.updateHeritageClause(clause, visitNodes(factory.createNodeArray(filter(clause.types, t => { return isEntityNameExpression(t.expression) || (clause.token === SyntaxKind.ExtendsKeyword && t.expression.kind === SyntaxKind.NullKeyword); - })), visitDeclarationSubtree))), clause => clause.types && !!clause.types.length)); + })), visitDeclarationSubtree, isExpressionWithTypeArguments))), clause => clause.types && !!clause.types.length)); } } diff --git a/src/compiler/transformers/destructuring.ts b/src/compiler/transformers/destructuring.ts index 2effd35cfc65f..f95c9fabab7b2 100644 --- a/src/compiler/transformers/destructuring.ts +++ b/src/compiler/transformers/destructuring.ts @@ -2,9 +2,7 @@ import { __String, addRange, append, - ArrayBindingElement, ArrayBindingOrAssignmentPattern, - BindingElement, BindingName, BindingOrAssignmentElement, BindingOrAssignmentElementTarget, @@ -24,9 +22,11 @@ import { Identifier, idText, isArrayBindingElement, + isArrayBindingOrAssignmentElement, isArrayBindingOrAssignmentPattern, isBindingElement, isBindingName, + isBindingOrAssignmentElement, isBindingOrAssignmentPattern, isComputedPropertyName, isDeclarationBindingElement, @@ -36,6 +36,7 @@ import { isExpression, isIdentifier, isLiteralExpression, + isObjectBindingOrAssignmentElement, isObjectBindingOrAssignmentPattern, isOmittedExpression, isPropertyNameLiteral, @@ -73,7 +74,7 @@ interface FlattenContext { createArrayBindingOrAssignmentPattern: (elements: BindingOrAssignmentElement[]) => ArrayBindingOrAssignmentPattern; createObjectBindingOrAssignmentPattern: (elements: BindingOrAssignmentElement[]) => ObjectBindingOrAssignmentPattern; createArrayBindingOrAssignmentElement: (node: Identifier) => BindingOrAssignmentElement; - visitor?: (node: Node) => VisitResult; + visitor: (node: Node) => VisitResult; } /** @internal */ @@ -97,7 +98,7 @@ export const enum FlattenLevel { */ export function flattenDestructuringAssignment( node: VariableDeclaration | DestructuringAssignment, - visitor: ((node: Node) => VisitResult) | undefined, + visitor: ((node: Node) => VisitResult), context: TransformationContext, level: FlattenLevel, needsValue?: boolean, @@ -112,7 +113,7 @@ export function flattenDestructuringAssignment( value = node.right; } else { - return visitNode(value, visitor, isExpression); + return Debug.checkDefined(visitNode(value, visitor, isExpression)); } } } @@ -133,6 +134,7 @@ export function flattenDestructuringAssignment( if (value) { value = visitNode(value, visitor, isExpression); + Debug.assert(value); if (isIdentifier(value) && bindingOrAssignmentElementAssignsToName(node, value.escapedText) || bindingOrAssignmentElementContainsNonLiteralComputedName(node)) { @@ -176,12 +178,12 @@ export function flattenDestructuringAssignment( expressions = append(expressions, expression); } - function emitBindingOrAssignment(target: BindingOrAssignmentElementTarget, value: Expression, location: TextRange, original: Node) { + function emitBindingOrAssignment(target: BindingOrAssignmentElementTarget, value: Expression, location: TextRange, original: Node | undefined) { Debug.assertNode(target, createAssignmentCallback ? isIdentifier : isExpression); const expression = createAssignmentCallback ? createAssignmentCallback(target as Identifier, value, location) : setTextRange( - context.factory.createAssignment(visitNode(target as Expression, visitor, isExpression), value), + context.factory.createAssignment(Debug.checkDefined(visitNode(target as Expression, visitor, isExpression)), value), location ); expression.original = original; @@ -238,7 +240,7 @@ function bindingOrAssignmentPatternContainsNonLiteralComputedName(pattern: Bindi */ export function flattenDestructuringBinding( node: VariableDeclaration | ParameterDeclaration, - visitor: (node: Node) => VisitResult, + visitor: (node: Node) => VisitResult, context: TransformationContext, level: FlattenLevel, rval?: Expression, @@ -266,7 +268,7 @@ export function flattenDestructuringBinding( bindingOrAssignmentElementContainsNonLiteralComputedName(node))) { // If the right-hand value of the assignment is also an assignment target then // we need to cache the right-hand value. - initializer = ensureIdentifier(flattenContext, visitNode(initializer, flattenContext.visitor), /*reuseIdentifierExpressions*/ false, initializer); + initializer = ensureIdentifier(flattenContext, Debug.checkDefined(visitNode(initializer, flattenContext.visitor, isExpression)), /*reuseIdentifierExpressions*/ false, initializer); node = context.factory.updateVariableDeclaration(node, node.name, /*exclamationToken*/ undefined, /*type*/ undefined, initializer); } } @@ -395,7 +397,7 @@ function flattenObjectBindingOrAssignmentPattern(flattenContext: FlattenContext, && !(element.transformFlags & (TransformFlags.ContainsRestOrSpread | TransformFlags.ContainsObjectRestOrSpread)) && !(getTargetOfBindingOrAssignmentElement(element)!.transformFlags & (TransformFlags.ContainsRestOrSpread | TransformFlags.ContainsObjectRestOrSpread)) && !isComputedPropertyName(propertyName)) { - bindingElements = append(bindingElements, visitNode(element, flattenContext.visitor)); + bindingElements = append(bindingElements, visitNode(element, flattenContext.visitor, isBindingOrAssignmentElement)); } else { if (bindingElements) { @@ -542,7 +544,7 @@ function createDefaultValueCheck(flattenContext: FlattenContext, value: Expressi */ function createDestructuringPropertyAccess(flattenContext: FlattenContext, value: Expression, propertyName: PropertyName): LeftHandSideExpression { if (isComputedPropertyName(propertyName)) { - const argumentExpression = ensureIdentifier(flattenContext, visitNode(propertyName.expression, flattenContext.visitor), /*reuseIdentifierExpressions*/ false, /*location*/ propertyName); + const argumentExpression = ensureIdentifier(flattenContext, Debug.checkDefined(visitNode(propertyName.expression, flattenContext.visitor, isExpression)), /*reuseIdentifierExpressions*/ false, /*location*/ propertyName); return flattenContext.context.factory.createElementAccessExpression(value, argumentExpression); } else if (isStringOrNumericLiteralLike(propertyName)) { @@ -585,19 +587,21 @@ function ensureIdentifier(flattenContext: FlattenContext, value: Expression, reu function makeArrayBindingPattern(factory: NodeFactory, elements: BindingOrAssignmentElement[]) { Debug.assertEachNode(elements, isArrayBindingElement); - return factory.createArrayBindingPattern(elements as ArrayBindingElement[]); + return factory.createArrayBindingPattern(elements); } function makeArrayAssignmentPattern(factory: NodeFactory, elements: BindingOrAssignmentElement[]) { + Debug.assertEachNode(elements, isArrayBindingOrAssignmentElement); return factory.createArrayLiteralExpression(map(elements, factory.converters.convertToArrayAssignmentElement)); } function makeObjectBindingPattern(factory: NodeFactory, elements: BindingOrAssignmentElement[]) { Debug.assertEachNode(elements, isBindingElement); - return factory.createObjectBindingPattern(elements as BindingElement[]); + return factory.createObjectBindingPattern(elements); } function makeObjectAssignmentPattern(factory: NodeFactory, elements: BindingOrAssignmentElement[]) { + Debug.assertEachNode(elements, isObjectBindingOrAssignmentElement); return factory.createObjectLiteralExpression(map(elements, factory.converters.convertToObjectAssignmentElement)); } diff --git a/src/compiler/transformers/es2015.ts b/src/compiler/transformers/es2015.ts index 85acbeb46ef0a..c2e9bdaf2b79a 100644 --- a/src/compiler/transformers/es2015.ts +++ b/src/compiler/transformers/es2015.ts @@ -46,7 +46,6 @@ import { filter, first, firstOrUndefined, - flatMap, flatten, flattenDestructuringAssignment, flattenDestructuringBinding, @@ -125,6 +124,7 @@ import { isSuperProperty, isSwitchStatement, isTryStatement, + isVariableDeclaration, isVariableDeclarationList, isVariableStatement, isWithStatement, @@ -352,7 +352,7 @@ interface ConvertedLoopState { loopOutParameters: LoopOutParameter[]; } -type LoopConverter = (node: IterationStatement, outermostLabeledStatement: LabeledStatement | undefined, convertedLoopBodyStatements: Statement[] | undefined, ancestorFacts: HierarchyFacts) => Statement; +type LoopConverter = (node: T, outermostLabeledStatement: LabeledStatement | undefined, convertedLoopBodyStatements: Statement[] | undefined, ancestorFacts: HierarchyFacts) => Statement; // Facts we track as we traverse the tree const enum HierarchyFacts { @@ -582,15 +582,15 @@ export function transformES2015(context: TransformationContext): (x: SourceFile || (getEmitFlags(node) & EmitFlags.TypeScriptClassWrapper) !== 0; } - function visitor(node: Node): VisitResult { + function visitor(node: Node): VisitResult { return shouldVisitNode(node) ? visitorWorker(node, /*expressionResultIsUnused*/ false) : node; } - function visitorWithUnusedExpressionResult(node: Node): VisitResult { + function visitorWithUnusedExpressionResult(node: Node): VisitResult { return shouldVisitNode(node) ? visitorWorker(node, /*expressionResultIsUnused*/ true) : node; } - function classWrapperStatementVisitor(node: Node): VisitResult { + function classWrapperStatementVisitor(node: Node): VisitResult { if (shouldVisitNode(node)) { const original = getOriginalNode(node); if (isPropertyDeclaration(original) && hasStaticModifier(original)) { @@ -607,14 +607,14 @@ export function transformES2015(context: TransformationContext): (x: SourceFile return node; } - function callExpressionVisitor(node: Node): VisitResult { + function callExpressionVisitor(node: Node): VisitResult { if (node.kind === SyntaxKind.SuperKeyword) { return visitSuperKeyword(/*isExpressionOfCall*/ true); } return visitor(node); } - function visitorWorker(node: Node, expressionResultIsUnused: boolean): VisitResult { + function visitorWorker(node: Node, expressionResultIsUnused: boolean): VisitResult { switch (node.kind) { case SyntaxKind.StaticKeyword: return undefined; // elide static keyword @@ -818,7 +818,7 @@ export function transformES2015(context: TransformationContext): (x: SourceFile factory.createPropertyAssignment( factory.createIdentifier("value"), node.expression - ? visitNode(node.expression, visitor, isExpression) + ? Debug.checkDefined(visitNode(node.expression, visitor, isExpression)) : factory.createVoidZero() ) ] @@ -1057,7 +1057,7 @@ export function transformES2015(context: TransformationContext): (x: SourceFile outer, /*typeArguments*/ undefined, extendsClauseElement - ? [visitNode(extendsClauseElement.expression, visitor, isExpression)] + ? [Debug.checkDefined(visitNode(extendsClauseElement.expression, visitor, isExpression))] : [] ) ); @@ -1567,7 +1567,7 @@ export function transformES2015(context: TransformationContext): (x: SourceFile factory.createExpressionStatement( factory.createAssignment( factory.getGeneratedNameForNode(parameter), - visitNode(initializer, visitor, isExpression) + Debug.checkDefined(visitNode(initializer, visitor, isExpression)) ) ), EmitFlags.CustomPrologue @@ -1587,7 +1587,7 @@ export function transformES2015(context: TransformationContext): (x: SourceFile * @param initializer The initializer for the parameter. */ function insertDefaultValueAssignmentForInitializer(statements: Statement[], parameter: ParameterDeclaration, name: Identifier, initializer: Expression): void { - initializer = visitNode(initializer, visitor, isExpression); + initializer = Debug.checkDefined(visitNode(initializer, visitor, isExpression)); const statement = factory.createIfStatement( factory.createTypeCheck(factory.cloneNode(name), "undefined"), setEmitFlags( @@ -1928,6 +1928,7 @@ export function transformES2015(context: TransformationContext): (x: SourceFile const sourceMapRange = getSourceMapRange(member); const memberFunction = transformFunctionLikeToExpression(member, /*location*/ member, /*name*/ undefined, container); const propertyName = visitNode(member.name, visitor, isPropertyName); + Debug.assert(propertyName); let e: Expression; if (!isPrivateIdentifier(propertyName) && getUseDefineForClassFields(context.getCompilerOptions())) { const name = isComputedPropertyName(propertyName) ? propertyName.expression @@ -1984,6 +1985,7 @@ export function transformES2015(context: TransformationContext): (x: SourceFile setSourceMapRange(target, firstAccessor.name); const visitedAccessorName = visitNode(firstAccessor.name, visitor, isPropertyName); + Debug.assert(visitedAccessorName); if (isPrivateIdentifier(visitedAccessorName)) { return Debug.failBadSyntaxKind(visitedAccessorName, "Encountered unhandled private identifier while transforming ES2015."); } @@ -2316,9 +2318,9 @@ export function transformES2015(context: TransformationContext): (x: SourceFile if (node.operatorToken.kind === SyntaxKind.CommaToken) { return factory.updateBinaryExpression( node, - visitNode(node.left, visitorWithUnusedExpressionResult, isExpression), + Debug.checkDefined(visitNode(node.left, visitorWithUnusedExpressionResult, isExpression)), node.operatorToken, - visitNode(node.right, expressionResultIsUnused ? visitorWithUnusedExpressionResult : visitor, isExpression) + Debug.checkDefined(visitNode(node.right, expressionResultIsUnused ? visitorWithUnusedExpressionResult : visitor, isExpression)) ); } return visitEachChild(node, visitor, context); @@ -2338,6 +2340,7 @@ export function transformES2015(context: TransformationContext): (x: SourceFile const visited = visitNode(element, i < node.elements.length - 1 ? visitorWithUnusedExpressionResult : visitor, isExpression); if (result || visited !== element) { result ||= node.elements.slice(0, i); + Debug.assert(visited); result.push(visited); } } @@ -2370,7 +2373,7 @@ export function transformES2015(context: TransformationContext): (x: SourceFile ); } else { - assignment = factory.createBinaryExpression(decl.name, SyntaxKind.EqualsToken, visitNode(decl.initializer, visitor, isExpression)); + assignment = factory.createBinaryExpression(decl.name, SyntaxKind.EqualsToken, Debug.checkDefined(visitNode(decl.initializer, visitor, isExpression))); setTextRange(assignment, decl); } @@ -2404,9 +2407,9 @@ export function transformES2015(context: TransformationContext): (x: SourceFile enableSubstitutionsForBlockScopedBindings(); } - const declarations = flatMap(node.declarations, node.flags & NodeFlags.Let + const declarations = visitNodes(node.declarations, node.flags & NodeFlags.Let ? visitVariableDeclarationInLetDeclarationList - : visitVariableDeclaration); + : visitVariableDeclaration, isVariableDeclaration); const declarationList = factory.createVariableDeclarationList(declarations); setOriginalNode(declarationList, node); @@ -2558,14 +2561,14 @@ export function transformES2015(context: TransformationContext): (x: SourceFile convertedLoopState!.labels!.set(idText(node.label), false); } - function visitLabeledStatement(node: LabeledStatement): VisitResult { + function visitLabeledStatement(node: LabeledStatement): VisitResult { if (convertedLoopState && !convertedLoopState.labels) { convertedLoopState.labels = new Map(); } const statement = unwrapInnermostStatementOfLabel(node, convertedLoopState && recordLabel); return isIterationStatement(statement, /*lookInLabeledStatements*/ false) ? visitIterationStatement(statement, /*outermostLabeledStatement*/ node) - : factory.restoreEnclosingLabel(visitNode(statement, visitor, isStatement, factory.liftToBlock), node, convertedLoopState && resetLabel); + : factory.restoreEnclosingLabel(Debug.checkDefined(visitNode(statement, visitor, isStatement, factory.liftToBlock)), node, convertedLoopState && resetLabel); } function visitIterationStatement(node: IterationStatement, outermostLabeledStatement: LabeledStatement) { @@ -2582,7 +2585,7 @@ export function transformES2015(context: TransformationContext): (x: SourceFile } } - function visitIterationStatementWithFacts(excludeFacts: HierarchyFacts, includeFacts: HierarchyFacts, node: IterationStatement, outermostLabeledStatement: LabeledStatement | undefined, convert?: LoopConverter) { + function visitIterationStatementWithFacts(excludeFacts: HierarchyFacts, includeFacts: HierarchyFacts, node: T, outermostLabeledStatement: LabeledStatement | undefined, convert?: LoopConverter) { const ancestorFacts = enterSubtree(excludeFacts, includeFacts); const updated = convertIterationStatementBodyIfNecessary(node, outermostLabeledStatement, ancestorFacts, convert); exitSubtree(ancestorFacts, HierarchyFacts.None, HierarchyFacts.None); @@ -2611,7 +2614,7 @@ export function transformES2015(context: TransformationContext): (x: SourceFile visitNode(node.initializer, visitorWithUnusedExpressionResult, isForInitializer), visitNode(node.condition, visitor, isExpression), visitNode(node.incrementor, visitorWithUnusedExpressionResult, isExpression), - visitNode(node.statement, visitor, isStatement, factory.liftToBlock) + Debug.checkDefined(visitNode(node.statement, visitor, isStatement, factory.liftToBlock)) ); } @@ -2632,7 +2635,7 @@ export function transformES2015(context: TransformationContext): (x: SourceFile compilerOptions.downlevelIteration ? convertForOfStatementForIterable : convertForOfStatementForArray); } - function convertForOfStatementHead(node: ForOfStatement, boundValue: Expression, convertedLoopBodyStatements: Statement[]) { + function convertForOfStatementHead(node: ForOfStatement, boundValue: Expression, convertedLoopBodyStatements: Statement[] | undefined) { const statements: Statement[] = []; const initializer = node.initializer; if (isVariableDeclarationList(initializer)) { @@ -2702,7 +2705,7 @@ export function transformES2015(context: TransformationContext): (x: SourceFile } else { setTextRangeEnd(assignment, initializer.end); - statements.push(setTextRange(factory.createExpressionStatement(visitNode(assignment, visitor, isExpression)), moveRangeEnd(initializer, -1))); + statements.push(setTextRange(factory.createExpressionStatement(Debug.checkDefined(visitNode(assignment, visitor, isExpression))), moveRangeEnd(initializer, -1))); } } @@ -2711,6 +2714,7 @@ export function transformES2015(context: TransformationContext): (x: SourceFile } else { const statement = visitNode(node.statement, visitor, isStatement, factory.liftToBlock); + Debug.assert(statement); if (isBlock(statement)) { return factory.updateBlock(statement, setTextRange(factory.createNodeArray(concatenate(statements, statement.statements)), statement.statements)); } @@ -2731,7 +2735,7 @@ export function transformES2015(context: TransformationContext): (x: SourceFile ); } - function convertForOfStatementForArray(node: ForOfStatement, outermostLabeledStatement: LabeledStatement, convertedLoopBodyStatements: Statement[]): Statement { + function convertForOfStatementForArray(node: ForOfStatement, outermostLabeledStatement: LabeledStatement | undefined, convertedLoopBodyStatements: Statement[] | undefined): Statement { // The following ES6 code: // // for (let v of expr) { } @@ -2754,6 +2758,7 @@ export function transformES2015(context: TransformationContext): (x: SourceFile // for-of bodies are always emitted as blocks. const expression = visitNode(node.expression, visitor, isExpression); + Debug.assert(expression); // In the case where the user wrote an identifier as the RHS, like this: // @@ -2801,8 +2806,9 @@ export function transformES2015(context: TransformationContext): (x: SourceFile return factory.restoreEnclosingLabel(forStatement, outermostLabeledStatement, convertedLoopState && resetLabel); } - function convertForOfStatementForIterable(node: ForOfStatement, outermostLabeledStatement: LabeledStatement, convertedLoopBodyStatements: Statement[], ancestorFacts: HierarchyFacts): Statement { + function convertForOfStatementForIterable(node: ForOfStatement, outermostLabeledStatement: LabeledStatement | undefined, convertedLoopBodyStatements: Statement[] | undefined, ancestorFacts: HierarchyFacts): Statement { const expression = visitNode(node.expression, visitor, isExpression); + Debug.assert(expression); const iterator = isIdentifier(expression) ? factory.getGeneratedNameForNode(expression) : factory.createTempVariable(/*recordTempVariable*/ undefined); const result = isIdentifier(expression) ? factory.getGeneratedNameForNode(iterator) : factory.createTempVariable(/*recordTempVariable*/ undefined); const errorRecord = factory.createUniqueName("e"); @@ -3029,7 +3035,7 @@ export function transformES2015(context: TransformationContext): (x: SourceFile } } - function convertIterationStatementBodyIfNecessary(node: IterationStatement, outermostLabeledStatement: LabeledStatement | undefined, ancestorFacts: HierarchyFacts, convert?: LoopConverter): VisitResult { + function convertIterationStatementBodyIfNecessary(node: T, outermostLabeledStatement: LabeledStatement | undefined, ancestorFacts: HierarchyFacts, convert?: LoopConverter): VisitResult { if (!shouldConvertIterationStatement(node)) { let saveAllowedNonLabeledJumps: Jump | undefined; if (convertedLoopState) { @@ -3083,7 +3089,7 @@ export function transformES2015(context: TransformationContext): (x: SourceFile } } else { - const clone = convertIterationStatementCore(node, initializerFunction, visitNode(node.statement, visitor, isStatement, factory.liftToBlock)); + const clone = convertIterationStatementCore(node, initializerFunction, Debug.checkDefined(visitNode(node.statement, visitor, isStatement, factory.liftToBlock))); loop = factory.restoreEnclosingLabel(clone, outermostLabeledStatement, convertedLoopState && resetLabel); } @@ -3118,16 +3124,16 @@ export function transformES2015(context: TransformationContext): (x: SourceFile return factory.updateForOfStatement( node, /*awaitModifier*/ undefined, - visitNode(node.initializer, visitor, isForInitializer), - visitNode(node.expression, visitor, isExpression), + Debug.checkDefined(visitNode(node.initializer, visitor, isForInitializer)), + Debug.checkDefined(visitNode(node.expression, visitor, isExpression)), convertedLoopBody); } function convertForInStatement(node: ForInStatement, convertedLoopBody: Statement) { return factory.updateForInStatement( node, - visitNode(node.initializer, visitor, isForInitializer), - visitNode(node.expression, visitor, isExpression), + Debug.checkDefined(visitNode(node.initializer, visitor, isForInitializer)), + Debug.checkDefined(visitNode(node.expression, visitor, isExpression)), convertedLoopBody); } @@ -3135,13 +3141,13 @@ export function transformES2015(context: TransformationContext): (x: SourceFile return factory.updateDoStatement( node, convertedLoopBody, - visitNode(node.expression, visitor, isExpression)); + Debug.checkDefined(visitNode(node.expression, visitor, isExpression))); } function convertWhileStatement(node: WhileStatement, convertedLoopBody: Statement) { return factory.updateWhileStatement( node, - visitNode(node.expression, visitor, isExpression), + Debug.checkDefined(visitNode(node.expression, visitor, isExpression)), convertedLoopBody); } @@ -3347,11 +3353,11 @@ export function transformES2015(context: TransformationContext): (x: SourceFile /*typeParameters*/ undefined, /*parameters*/ undefined, /*type*/ undefined, - visitNode( + Debug.checkDefined(visitNode( factory.createBlock(statements, /*multiLine*/ true), visitor, isBlock - ) + )) ), emitFlags ) @@ -3421,7 +3427,7 @@ export function transformES2015(context: TransformationContext): (x: SourceFile if (node.incrementor) { statements.push(factory.createIfStatement( currentState.conditionVariable, - factory.createExpressionStatement(visitNode(node.incrementor, visitor, isExpression)), + factory.createExpressionStatement(Debug.checkDefined(visitNode(node.incrementor, visitor, isExpression))), factory.createExpressionStatement(factory.createAssignment(currentState.conditionVariable, factory.createTrue())) )); } @@ -3434,12 +3440,13 @@ export function transformES2015(context: TransformationContext): (x: SourceFile if (shouldConvertConditionOfForStatement(node)) { statements.push(factory.createIfStatement( - factory.createPrefixUnaryExpression(SyntaxKind.ExclamationToken, visitNode(node.condition, visitor, isExpression)), - visitNode(factory.createBreakStatement(), visitor, isStatement) + factory.createPrefixUnaryExpression(SyntaxKind.ExclamationToken, Debug.checkDefined(visitNode(node.condition, visitor, isExpression))), + Debug.checkDefined(visitNode(factory.createBreakStatement(), visitor, isStatement)) )); } } + Debug.assert(statement); if (isBlock(statement)) { addRange(statements, statement.statements); } @@ -3732,9 +3739,9 @@ export function transformES2015(context: TransformationContext): (x: SourceFile createMemberAccessForPropertyName( factory, receiver, - visitNode(property.name, visitor, isPropertyName) + Debug.checkDefined(visitNode(property.name, visitor, isPropertyName)) ), - visitNode(property.initializer, visitor, isExpression) + Debug.checkDefined(visitNode(property.initializer, visitor, isExpression)) ); setTextRange(expression, property); if (startsOnNewLine) { @@ -3755,7 +3762,7 @@ export function transformES2015(context: TransformationContext): (x: SourceFile createMemberAccessForPropertyName( factory, receiver, - visitNode(property.name, visitor, isPropertyName) + Debug.checkDefined(visitNode(property.name, visitor, isPropertyName)) ), factory.cloneNode(property.name) ); @@ -3778,7 +3785,7 @@ export function transformES2015(context: TransformationContext): (x: SourceFile createMemberAccessForPropertyName( factory, receiver, - visitNode(method.name, visitor, isPropertyName) + Debug.checkDefined(visitNode(method.name, visitor, isPropertyName)) ), transformFunctionLikeToExpression(method, /*location*/ method, /*name*/ undefined, container) ); @@ -3929,7 +3936,7 @@ export function transformES2015(context: TransformationContext): (x: SourceFile return factory.updateCallExpression( node, - visitNode(node.expression, callExpressionVisitor, isExpression), + Debug.checkDefined(visitNode(node.expression, callExpressionVisitor, isExpression)), /*typeArguments*/ undefined, visitNodes(node.arguments, visitor, isExpression) ); @@ -4127,8 +4134,8 @@ export function transformES2015(context: TransformationContext): (x: SourceFile // _super.prototype.m.apply(this, a.concat([b])) resultingCall = factory.createFunctionApplyCall( - visitNode(target, callExpressionVisitor, isExpression), - node.expression.kind === SyntaxKind.SuperKeyword ? thisArg : visitNode(thisArg, visitor, isExpression), + Debug.checkDefined(visitNode(target, callExpressionVisitor, isExpression)), + node.expression.kind === SyntaxKind.SuperKeyword ? thisArg : Debug.checkDefined(visitNode(thisArg, visitor, isExpression)), transformAndSpreadElements(node.arguments, /*isArgumentList*/ true, /*multiLine*/ false, /*hasTrailingComma*/ false) ); } @@ -4144,8 +4151,8 @@ export function transformES2015(context: TransformationContext): (x: SourceFile // _super.prototype.m.call(this, a) resultingCall = setTextRange( factory.createFunctionCallCall( - visitNode(target, callExpressionVisitor, isExpression), - node.expression.kind === SyntaxKind.SuperKeyword ? thisArg : visitNode(thisArg, visitor, isExpression), + Debug.checkDefined(visitNode(target, callExpressionVisitor, isExpression)), + node.expression.kind === SyntaxKind.SuperKeyword ? thisArg : Debug.checkDefined(visitNode(thisArg, visitor, isExpression)), visitNodes(node.arguments, visitor, isExpression) ), node @@ -4185,7 +4192,7 @@ export function transformES2015(context: TransformationContext): (x: SourceFile const { target, thisArg } = factory.createCallBinding(factory.createPropertyAccessExpression(node.expression, "bind"), hoistVariableDeclaration); return factory.createNewExpression( factory.createFunctionApplyCall( - visitNode(target, visitor, isExpression), + Debug.checkDefined(visitNode(target, visitor, isExpression)), thisArg, transformAndSpreadElements(factory.createNodeArray([factory.createVoidZero(), ...node.arguments!]), /*isArgumentList*/ true, /*multiLine*/ false, /*hasTrailingComma*/ false) ), @@ -4288,8 +4295,10 @@ export function transformES2015(context: TransformationContext): (x: SourceFile return map(chunk, visitExpressionOfSpread); } - function visitExpressionOfSpread(node: SpreadElement): SpreadSegment { + function visitExpressionOfSpread(node: Expression): SpreadSegment { + Debug.assertNode(node, isSpreadElement); let expression = visitNode(node.expression, visitor, isExpression); + Debug.assert(expression); // We don't need to pack already packed array literals, or existing calls to the `__read` helper. const isCallToReadHelper = isCallToHelper(expression, "___read" as __String); @@ -4376,7 +4385,7 @@ export function transformES2015(context: TransformationContext): (x: SourceFile function visitTemplateExpression(node: TemplateExpression): Expression { let expression: Expression = factory.createStringLiteral(node.head.text); for (const span of node.templateSpans) { - const args = [visitNode(span.expression, visitor, isExpression)]; + const args = [Debug.checkDefined(visitNode(span.expression, visitor, isExpression))]; if (span.literal.text.length > 0) { args.push(factory.createStringLiteral(span.literal.text)); diff --git a/src/compiler/transformers/es2017.ts b/src/compiler/transformers/es2017.ts index 4c7a90fa6944e..bb5029285be23 100644 --- a/src/compiler/transformers/es2017.ts +++ b/src/compiler/transformers/es2017.ts @@ -42,6 +42,7 @@ import { getNodeId, getOriginalNode, insertStatementsAfterStandardPrologue, + isAwaitKeyword, isBlock, isConciseBody, isEffectiveStrictModeSourceFile, @@ -51,13 +52,13 @@ import { isFunctionLike, isFunctionLikeDeclaration, isIdentifier, + isModifier, isModifierLike, isNodeWithPossibleHoistedDeclaration, isOmittedExpression, isPropertyAccessExpression, isStatement, isSuperProperty, - isToken, isVariableDeclarationList, LeftHandSideExpression, map, @@ -202,7 +203,7 @@ export function transformES2017(context: TransformationContext): (x: SourceFile return visitEachChild(node, visitor, context); } - function visitor(node: Node): VisitResult { + function visitor(node: Node): VisitResult { if ((node.transformFlags & TransformFlags.ContainsES2017) === 0) { return node; } @@ -253,7 +254,7 @@ export function transformES2017(context: TransformationContext): (x: SourceFile } } - function asyncBodyVisitor(node: Node): VisitResult { + function asyncBodyVisitor(node: Node): VisitResult { if (isNodeWithPossibleHoistedDeclaration(node)) { switch (node.kind) { case SyntaxKind.VariableStatement: @@ -325,8 +326,8 @@ export function transformES2017(context: TransformationContext): (x: SourceFile node, isVariableDeclarationListWithCollidingName(node.initializer) ? visitVariableDeclarationListWithCollidingNames(node.initializer, /*hasReceiver*/ true)! - : visitNode(node.initializer, visitor, isForInitializer), - visitNode(node.expression, visitor, isExpression), + : Debug.checkDefined(visitNode(node.initializer, visitor, isForInitializer)), + Debug.checkDefined(visitNode(node.expression, visitor, isExpression)), visitIterationBody(node.statement, asyncBodyVisitor, context) ); } @@ -334,11 +335,11 @@ export function transformES2017(context: TransformationContext): (x: SourceFile function visitForOfStatementInAsyncBody(node: ForOfStatement) { return factory.updateForOfStatement( node, - visitNode(node.awaitModifier, visitor, isToken), + visitNode(node.awaitModifier, visitor, isAwaitKeyword), isVariableDeclarationListWithCollidingName(node.initializer) ? visitVariableDeclarationListWithCollidingNames(node.initializer, /*hasReceiver*/ true)! - : visitNode(node.initializer, visitor, isForInitializer), - visitNode(node.expression, visitor, isExpression), + : Debug.checkDefined(visitNode(node.initializer, visitor, isForInitializer)), + Debug.checkDefined(visitNode(node.expression, visitor, isExpression)), visitIterationBody(node.statement, asyncBodyVisitor, context) ); } @@ -383,7 +384,7 @@ export function transformES2017(context: TransformationContext): (x: SourceFile function visitConstructorDeclaration(node: ConstructorDeclaration) { return factory.updateConstructorDeclaration( node, - visitNodes(node.modifiers, visitor, isModifierLike), + visitNodes(node.modifiers, visitor, isModifier), visitParameterList(node.parameters, visitor, context), transformMethodBody(node) ); @@ -468,7 +469,7 @@ export function transformES2017(context: TransformationContext): (x: SourceFile function visitFunctionExpression(node: FunctionExpression): Expression { return factory.updateFunctionExpression( node, - visitNodes(node.modifiers, visitor, isModifierLike), + visitNodes(node.modifiers, visitor, isModifier), node.asteriskToken, node.name, /*typeParameters*/ undefined, @@ -491,7 +492,7 @@ export function transformES2017(context: TransformationContext): (x: SourceFile function visitArrowFunction(node: ArrowFunction) { return factory.updateArrowFunction( node, - visitNodes(node.modifiers, visitor, isModifierLike), + visitNodes(node.modifiers, visitor, isModifier), /*typeParameters*/ undefined, visitParameterList(node.parameters, visitor, context), /*type*/ undefined, @@ -561,7 +562,7 @@ export function transformES2017(context: TransformationContext): (x: SourceFile ), node ); - return visitNode(converted, visitor, isExpression); + return Debug.checkDefined(visitNode(converted, visitor, isExpression)); } function collidesWithParameterName({ name }: VariableDeclaration | BindingElement): boolean { @@ -728,7 +729,7 @@ export function transformES2017(context: TransformationContext): (x: SourceFile return factory.updateBlock(body, visitNodes(body.statements, asyncBodyVisitor, isStatement, start)); } else { - return factory.converters.convertToFunctionBlock(visitNode(body, asyncBodyVisitor, isConciseBody)); + return factory.converters.convertToFunctionBlock(Debug.checkDefined(visitNode(body, asyncBodyVisitor, isConciseBody))); } } diff --git a/src/compiler/transformers/es2018.ts b/src/compiler/transformers/es2018.ts index 296cfaeae2fca..35f28a2ee8d6b 100644 --- a/src/compiler/transformers/es2018.ts +++ b/src/compiler/transformers/es2018.ts @@ -61,9 +61,9 @@ import { isParameter, isPropertyAccessExpression, isPropertyName, + isQuestionToken, isStatement, isSuperProperty, - isToken, isVariableDeclarationList, LabeledStatement, LeftHandSideExpression, @@ -95,7 +95,6 @@ import { SyntaxKind, TaggedTemplateExpression, TextRange, - Token, TransformationContext, TransformFlags, unwrapInnermostStatementOfLabel, @@ -240,7 +239,7 @@ export function transformES2018(context: TransformationContext): (x: SourceFile return visitorWorker(node, /*expressionResultIsUnused*/ true); } - function visitorNoAsyncModifier(node: Node): VisitResult { + function visitorNoAsyncModifier(node: Node): VisitResult { if (node.kind === SyntaxKind.AsyncKeyword) { return undefined; } @@ -1041,7 +1040,7 @@ export function transformES2018(context: TransformationContext): (x: SourceFile ? undefined : node.asteriskToken, visitNode(node.name, visitor, isPropertyName), - visitNode>(/*questionToken*/ undefined, visitor, isToken), + visitNode(/*questionToken*/ undefined, visitor, isQuestionToken), /*typeParameters*/ undefined, visitParameterList(node.parameters, parameterVisitor, context), /*type*/ undefined, diff --git a/src/compiler/transformers/generators.ts b/src/compiler/transformers/generators.ts index 86abe24d056d0..cf15cb43c326a 100644 --- a/src/compiler/transformers/generators.ts +++ b/src/compiler/transformers/generators.ts @@ -408,7 +408,7 @@ export function transformGenerators(context: TransformationContext): (x: SourceF * * @param node The node to visit. */ - function visitor(node: Node): VisitResult { + function visitor(node: Node): VisitResult { const transformFlags = node.transformFlags; if (inStatementContainingYield) { return visitJavaScriptInStatementContainingYield(node); @@ -432,7 +432,7 @@ export function transformGenerators(context: TransformationContext): (x: SourceF * * @param node The node to visit. */ - function visitJavaScriptInStatementContainingYield(node: Node): VisitResult { + function visitJavaScriptInStatementContainingYield(node: Node): VisitResult { switch (node.kind) { case SyntaxKind.DoStatement: return visitDoStatement(node as DoStatement); @@ -452,7 +452,7 @@ export function transformGenerators(context: TransformationContext): (x: SourceF * * @param node The node to visit. */ - function visitJavaScriptInGeneratorFunctionBody(node: Node): VisitResult { + function visitJavaScriptInGeneratorFunctionBody(node: Node): VisitResult { switch (node.kind) { case SyntaxKind.FunctionDeclaration: return visitFunctionDeclaration(node as FunctionDeclaration); @@ -521,7 +521,7 @@ export function transformGenerators(context: TransformationContext): (x: SourceF * * @param node The node to visit. */ - function visitGenerator(node: Node): VisitResult { + function visitGenerator(node: Node): VisitResult { switch (node.kind) { case SyntaxKind.FunctionDeclaration: return visitFunctionDeclaration(node as FunctionDeclaration); @@ -791,7 +791,7 @@ export function transformGenerators(context: TransformationContext): (x: SourceF target = factory.updatePropertyAccessExpression( left as PropertyAccessExpression, - cacheExpression(visitNode((left as PropertyAccessExpression).expression, visitor, isLeftHandSideExpression)), + cacheExpression(Debug.checkDefined(visitNode((left as PropertyAccessExpression).expression, visitor, isLeftHandSideExpression))), (left as PropertyAccessExpression).name ); break; @@ -809,13 +809,13 @@ export function transformGenerators(context: TransformationContext): (x: SourceF // _a[_b] = %sent%; target = factory.updateElementAccessExpression(left as ElementAccessExpression, - cacheExpression(visitNode((left as ElementAccessExpression).expression, visitor, isLeftHandSideExpression)), - cacheExpression(visitNode((left as ElementAccessExpression).argumentExpression, visitor, isExpression)) + cacheExpression(Debug.checkDefined(visitNode((left as ElementAccessExpression).expression, visitor, isLeftHandSideExpression))), + cacheExpression(Debug.checkDefined(visitNode((left as ElementAccessExpression).argumentExpression, visitor, isExpression))) ); break; default: - target = visitNode(left, visitor, isExpression); + target = Debug.checkDefined(visitNode(left, visitor, isExpression)); break; } @@ -828,7 +828,7 @@ export function transformGenerators(context: TransformationContext): (x: SourceF factory.createBinaryExpression( cacheExpression(target), getNonAssignmentOperatorForCompoundAssignment(operator), - visitNode(right, visitor, isExpression) + Debug.checkDefined(visitNode(right, visitor, isExpression)) ), node ) @@ -837,7 +837,7 @@ export function transformGenerators(context: TransformationContext): (x: SourceF ); } else { - return factory.updateBinaryExpression(node, target, node.operatorToken, visitNode(right, visitor, isExpression)); + return factory.updateBinaryExpression(node, target, node.operatorToken, Debug.checkDefined(visitNode(right, visitor, isExpression))); } } @@ -863,9 +863,9 @@ export function transformGenerators(context: TransformationContext): (x: SourceF // _a + %sent% + c() return factory.updateBinaryExpression(node, - cacheExpression(visitNode(node.left, visitor, isExpression)), + cacheExpression(Debug.checkDefined(visitNode(node.left, visitor, isExpression))), node.operatorToken, - visitNode(node.right, visitor, isExpression)); + Debug.checkDefined(visitNode(node.right, visitor, isExpression))); } return visitEachChild(node, visitor, context); @@ -902,7 +902,7 @@ export function transformGenerators(context: TransformationContext): (x: SourceF pendingExpressions = []; } - pendingExpressions.push(visitNode(node, visitor, isExpression)); + pendingExpressions.push(Debug.checkDefined(visitNode(node, visitor, isExpression))); } } } @@ -924,7 +924,7 @@ export function transformGenerators(context: TransformationContext): (x: SourceF emitWorker(OpCode.Statement, [factory.createExpressionStatement(factory.inlineExpressions(pendingExpressions))]); pendingExpressions = []; } - pendingExpressions.push(visitNode(elem, visitor, isExpression)); + pendingExpressions.push(Debug.checkDefined(visitNode(elem, visitor, isExpression))); } } return factory.inlineExpressions(pendingExpressions); @@ -968,7 +968,7 @@ export function transformGenerators(context: TransformationContext): (x: SourceF const resultLabel = defineLabel(); const resultLocal = declareLocal(); - emitAssignment(resultLocal, visitNode(node.left, visitor, isExpression), /*location*/ node.left); + emitAssignment(resultLocal, Debug.checkDefined(visitNode(node.left, visitor, isExpression)), /*location*/ node.left); if (node.operatorToken.kind === SyntaxKind.AmpersandAmpersandToken) { // Logical `&&` shortcuts when the left-hand operand is falsey. emitBreakWhenFalse(resultLabel, resultLocal, /*location*/ node.left); @@ -978,7 +978,7 @@ export function transformGenerators(context: TransformationContext): (x: SourceF emitBreakWhenTrue(resultLabel, resultLocal, /*location*/ node.left); } - emitAssignment(resultLocal, visitNode(node.right, visitor, isExpression), /*location*/ node.right); + emitAssignment(resultLocal, Debug.checkDefined(visitNode(node.right, visitor, isExpression)), /*location*/ node.right); markLabel(resultLabel); return resultLocal; } @@ -1011,11 +1011,11 @@ export function transformGenerators(context: TransformationContext): (x: SourceF const whenFalseLabel = defineLabel(); const resultLabel = defineLabel(); const resultLocal = declareLocal(); - emitBreakWhenFalse(whenFalseLabel, visitNode(node.condition, visitor, isExpression), /*location*/ node.condition); - emitAssignment(resultLocal, visitNode(node.whenTrue, visitor, isExpression), /*location*/ node.whenTrue); + emitBreakWhenFalse(whenFalseLabel, Debug.checkDefined(visitNode(node.condition, visitor, isExpression)), /*location*/ node.condition); + emitAssignment(resultLocal, Debug.checkDefined(visitNode(node.whenTrue, visitor, isExpression)), /*location*/ node.whenTrue); emitBreak(resultLabel); markLabel(whenFalseLabel); - emitAssignment(resultLocal, visitNode(node.whenFalse, visitor, isExpression), /*location*/ node.whenFalse); + emitAssignment(resultLocal, Debug.checkDefined(visitNode(node.whenFalse, visitor, isExpression)), /*location*/ node.whenFalse); markLabel(resultLabel); return resultLocal; } @@ -1128,7 +1128,7 @@ export function transformGenerators(context: TransformationContext): (x: SourceF expressions = []; } - expressions.push(visitNode(element, visitor, isExpression)); + expressions.push(Debug.checkDefined(visitNode(element, visitor, isExpression))); return expressions; } } @@ -1205,8 +1205,8 @@ export function transformGenerators(context: TransformationContext): (x: SourceF // a = _a[%sent%] return factory.updateElementAccessExpression(node, - cacheExpression(visitNode(node.expression, visitor, isLeftHandSideExpression)), - visitNode(node.argumentExpression, visitor, isExpression)); + cacheExpression(Debug.checkDefined(visitNode(node.expression, visitor, isLeftHandSideExpression))), + Debug.checkDefined(visitNode(node.argumentExpression, visitor, isExpression))); } return visitEachChild(node, visitor, context); @@ -1228,7 +1228,7 @@ export function transformGenerators(context: TransformationContext): (x: SourceF return setOriginalNode( setTextRange( factory.createFunctionApplyCall( - cacheExpression(visitNode(target, visitor, isLeftHandSideExpression)), + cacheExpression(Debug.checkDefined(visitNode(target, visitor, isLeftHandSideExpression))), thisArg, visitElements(node.arguments) ), @@ -1259,7 +1259,7 @@ export function transformGenerators(context: TransformationContext): (x: SourceF setTextRange( factory.createNewExpression( factory.createFunctionApplyCall( - cacheExpression(visitNode(target, visitor, isExpression)), + cacheExpression(Debug.checkDefined(visitNode(target, visitor, isExpression))), thisArg, visitElements( node.arguments!, @@ -1388,7 +1388,7 @@ export function transformGenerators(context: TransformationContext): (x: SourceF return setSourceMapRange( factory.createAssignment( setSourceMapRange(factory.cloneNode(node.name) as Identifier, node.name), - visitNode(node.initializer, visitor, isExpression) + Debug.checkDefined(visitNode(node.initializer, visitor, isExpression)) ), node ); @@ -1413,7 +1413,7 @@ export function transformGenerators(context: TransformationContext): (x: SourceF if (containsYield(node.thenStatement) || containsYield(node.elseStatement)) { const endLabel = defineLabel(); const elseLabel = node.elseStatement ? defineLabel() : undefined; - emitBreakWhenFalse(node.elseStatement ? elseLabel! : endLabel, visitNode(node.expression, visitor, isExpression), /*location*/ node.expression); + emitBreakWhenFalse(node.elseStatement ? elseLabel! : endLabel, Debug.checkDefined(visitNode(node.expression, visitor, isExpression)), /*location*/ node.expression); transformAndEmitEmbeddedStatement(node.thenStatement); if (node.elseStatement) { emitBreak(endLabel); @@ -1454,7 +1454,7 @@ export function transformGenerators(context: TransformationContext): (x: SourceF markLabel(loopLabel); transformAndEmitEmbeddedStatement(node.statement); markLabel(conditionLabel); - emitBreakWhenTrue(loopLabel, visitNode(node.expression, visitor, isExpression)); + emitBreakWhenTrue(loopLabel, Debug.checkDefined(visitNode(node.expression, visitor, isExpression))); endLoopBlock(); } else { @@ -1493,7 +1493,7 @@ export function transformGenerators(context: TransformationContext): (x: SourceF const loopLabel = defineLabel(); const endLabel = beginLoopBlock(loopLabel); markLabel(loopLabel); - emitBreakWhenFalse(endLabel, visitNode(node.expression, visitor, isExpression)); + emitBreakWhenFalse(endLabel, Debug.checkDefined(visitNode(node.expression, visitor, isExpression))); transformAndEmitEmbeddedStatement(node.statement); emitBreak(loopLabel); endLoopBlock(); @@ -1547,7 +1547,7 @@ export function transformGenerators(context: TransformationContext): (x: SourceF emitStatement( setTextRange( factory.createExpressionStatement( - visitNode(initializer, visitor, isExpression) + Debug.checkDefined(visitNode(initializer, visitor, isExpression)) ), initializer ) @@ -1557,7 +1557,7 @@ export function transformGenerators(context: TransformationContext): (x: SourceF markLabel(conditionLabel); if (node.condition) { - emitBreakWhenFalse(endLabel, visitNode(node.condition, visitor, isExpression)); + emitBreakWhenFalse(endLabel, Debug.checkDefined(visitNode(node.condition, visitor, isExpression))); } transformAndEmitEmbeddedStatement(node.statement); @@ -1567,7 +1567,7 @@ export function transformGenerators(context: TransformationContext): (x: SourceF emitStatement( setTextRange( factory.createExpressionStatement( - visitNode(node.incrementor, visitor, isExpression) + Debug.checkDefined(visitNode(node.incrementor, visitor, isExpression)) ), node.incrementor ) @@ -1645,7 +1645,7 @@ export function transformGenerators(context: TransformationContext): (x: SourceF const keysIndex = factory.createLoopVariable(); // _i const initializer = node.initializer; hoistVariableDeclaration(keysIndex); - emitAssignment(obj, visitNode(node.expression, visitor, isExpression)); + emitAssignment(obj, Debug.checkDefined(visitNode(node.expression, visitor, isExpression))); emitAssignment(keysArray, factory.createArrayLiteralExpression()); emitStatement( @@ -1683,7 +1683,7 @@ export function transformGenerators(context: TransformationContext): (x: SourceF variable = factory.cloneNode(initializer.declarations[0].name) as Identifier; } else { - variable = visitNode(initializer, visitor, isExpression); + variable = Debug.checkDefined(visitNode(initializer, visitor, isExpression)); Debug.assert(isLeftHandSideExpression(variable)); } @@ -1727,8 +1727,8 @@ export function transformGenerators(context: TransformationContext): (x: SourceF node = factory.updateForInStatement(node, initializer.declarations[0].name as Identifier, - visitNode(node.expression, visitor, isExpression), - visitNode(node.statement, visitor, isStatement, factory.liftToBlock) + Debug.checkDefined(visitNode(node.expression, visitor, isExpression)), + Debug.checkDefined(visitNode(node.statement, visitor, isStatement, factory.liftToBlock)) ); } else { @@ -1811,7 +1811,7 @@ export function transformGenerators(context: TransformationContext): (x: SourceF // .with (x) // /*body*/ // .endwith - beginWithBlock(cacheExpression(visitNode(node.expression, visitor, isExpression))); + beginWithBlock(cacheExpression(Debug.checkDefined(visitNode(node.expression, visitor, isExpression)))); transformAndEmitEmbeddedStatement(node.statement); endWithBlock(); } @@ -1858,7 +1858,7 @@ export function transformGenerators(context: TransformationContext): (x: SourceF const numClauses = caseBlock.clauses.length; const endLabel = beginSwitchBlock(); - const expression = cacheExpression(visitNode(node.expression, visitor, isExpression)); + const expression = cacheExpression(Debug.checkDefined(visitNode(node.expression, visitor, isExpression))); // Create labels for each clause and find the index of the first default clause. const clauseLabels: Label[] = []; @@ -1887,7 +1887,7 @@ export function transformGenerators(context: TransformationContext): (x: SourceF pendingClauses.push( factory.createCaseClause( - visitNode(clause.expression, visitor, isExpression), + Debug.checkDefined(visitNode(clause.expression, visitor, isExpression)), [ createInlineBreak(clauseLabels[i], /*location*/ clause.expression) ] @@ -1981,7 +1981,7 @@ export function transformGenerators(context: TransformationContext): (x: SourceF function transformAndEmitThrowStatement(node: ThrowStatement): void { // TODO(rbuckton): `expression` should be required on `throw`. emitThrow( - visitNode(node.expression ?? factory.createVoidZero(), visitor, isExpression), + Debug.checkDefined(visitNode(node.expression ?? factory.createVoidZero(), visitor, isExpression)), /*location*/ node ); } @@ -2614,7 +2614,7 @@ export function transformGenerators(context: TransformationContext): (x: SourceF * * @param node A statement. */ - function emitStatement(node: Statement): void { + function emitStatement(node: Statement | undefined): void { if (node) { emitWorker(OpCode.Statement, [node]); } diff --git a/src/compiler/transformers/jsx.ts b/src/compiler/transformers/jsx.ts index 2dc169b2d9a4b..7efa35b87fc70 100644 --- a/src/compiler/transformers/jsx.ts +++ b/src/compiler/transformers/jsx.ts @@ -193,7 +193,7 @@ export function transformJsx(context: TransformationContext): (x: SourceFile | B return visited; } - function visitor(node: Node): VisitResult { + function visitor(node: Node): VisitResult { if (node.transformFlags & TransformFlags.ContainsJsx) { return visitorWorker(node); } @@ -202,7 +202,7 @@ export function transformJsx(context: TransformationContext): (x: SourceFile | B } } - function visitorWorker(node: Node): VisitResult { + function visitorWorker(node: Node): VisitResult { switch (node.kind) { case SyntaxKind.JsxElement: return visitJsxElement(node as JsxElement, /*isChild*/ false); @@ -428,7 +428,7 @@ export function transformJsx(context: TransformationContext): (x: SourceFile | B } function transformJsxSpreadAttributeToSpreadAssignment(node: JsxSpreadAttribute) { - return factory.createSpreadAssignment(visitNode(node.expression, visitor, isExpression)); + return factory.createSpreadAssignment(Debug.checkDefined(visitNode(node.expression, visitor, isExpression))); } function transformJsxAttributesToObjectProps(attrs: readonly(JsxSpreadAttribute | JsxAttribute)[], children?: PropertyAssignment) { @@ -451,8 +451,8 @@ export function transformJsx(context: TransformationContext): (x: SourceFile | B // of JsxSpreadAttribute nodes into expressions. const expressions = flatten( spanMap(attrs, isJsxSpreadAttribute, (attrs, isSpread) => isSpread - ? map(attrs, transformJsxSpreadAttributeToExpression) - : factory.createObjectLiteralExpression(map(attrs, transformJsxAttributeToObjectLiteralElement)) + ? map(attrs as JsxSpreadAttribute[], transformJsxSpreadAttributeToExpression) + : factory.createObjectLiteralExpression(map(attrs as JsxAttribute[], transformJsxAttributeToObjectLiteralElement)) ) ); @@ -470,7 +470,7 @@ export function transformJsx(context: TransformationContext): (x: SourceFile | B } function transformJsxSpreadAttributeToExpression(node: JsxSpreadAttribute) { - return visitNode(node.expression, visitor, isExpression); + return Debug.checkDefined(visitNode(node.expression, visitor, isExpression)); } function transformJsxAttributeToObjectLiteralElement(node: JsxAttribute) { @@ -494,7 +494,7 @@ export function transformJsx(context: TransformationContext): (x: SourceFile | B if (node.expression === undefined) { return factory.createTrue(); } - return visitNode(node.expression, visitor, isExpression); + return Debug.checkDefined(visitNode(node.expression, visitor, isExpression)); } if (isJsxElement(node)) { return visitJsxElement(node, /*isChild*/ false); diff --git a/src/compiler/transformers/legacyDecorators.ts b/src/compiler/transformers/legacyDecorators.ts index 976e0705e730b..86d2d0ea10cd9 100644 --- a/src/compiler/transformers/legacyDecorators.ts +++ b/src/compiler/transformers/legacyDecorators.ts @@ -13,6 +13,7 @@ import { ClassLikeDeclaration, classOrConstructorParameterIsDecorated, ConstructorDeclaration, + Debug, Decorator, elideNodes, EmitFlags, @@ -42,7 +43,7 @@ import { isHeritageClause, isIdentifier, isModifier, - isParameterDeclaration, + isParameter, isPrivateIdentifier, isPropertyDeclaration, isPropertyName, @@ -111,11 +112,11 @@ export function transformLegacyDecorators(context: TransformationContext): (x: S return visited; } - function modifierVisitor(node: Node): VisitResult { + function modifierVisitor(node: Node): VisitResult { return isDecorator(node) ? undefined : node; } - function visitor(node: Node): VisitResult { + function visitor(node: Node): VisitResult { if (!(node.transformFlags & TransformFlags.ContainsDecorators)) { return node; } @@ -383,7 +384,7 @@ export function transformLegacyDecorators(context: TransformationContext): (x: S return factory.updateConstructorDeclaration( node, visitNodes(node.modifiers, modifierVisitor, isModifier), - visitNodes(node.parameters, visitor, isParameterDeclaration), + visitNodes(node.parameters, visitor, isParameter), visitNode(node.body, visitor, isBlock)); } @@ -402,10 +403,10 @@ export function transformLegacyDecorators(context: TransformationContext): (x: S node, visitNodes(node.modifiers, modifierVisitor, isModifier), node.asteriskToken, - visitNode(node.name, visitor, isPropertyName), + Debug.checkDefined(visitNode(node.name, visitor, isPropertyName)), /*questionToken*/ undefined, /*typeParameters*/ undefined, - visitNodes(node.parameters, visitor, isParameterDeclaration), + visitNodes(node.parameters, visitor, isParameter), /*type*/ undefined, visitNode(node.body, visitor, isBlock) ), node); @@ -415,8 +416,8 @@ export function transformLegacyDecorators(context: TransformationContext): (x: S return finishClassElement(factory.updateGetAccessorDeclaration( node, visitNodes(node.modifiers, modifierVisitor, isModifier), - visitNode(node.name, visitor, isPropertyName), - visitNodes(node.parameters, visitor, isParameterDeclaration), + Debug.checkDefined(visitNode(node.name, visitor, isPropertyName)), + visitNodes(node.parameters, visitor, isParameter), /*type*/ undefined, visitNode(node.body, visitor, isBlock) ), node); @@ -426,8 +427,8 @@ export function transformLegacyDecorators(context: TransformationContext): (x: S return finishClassElement(factory.updateSetAccessorDeclaration( node, visitNodes(node.modifiers, modifierVisitor, isModifier), - visitNode(node.name, visitor, isPropertyName), - visitNodes(node.parameters, visitor, isParameterDeclaration), + Debug.checkDefined(visitNode(node.name, visitor, isPropertyName)), + visitNodes(node.parameters, visitor, isParameter), visitNode(node.body, visitor, isBlock) ), node); } @@ -440,7 +441,7 @@ export function transformLegacyDecorators(context: TransformationContext): (x: S return finishClassElement(factory.updatePropertyDeclaration( node, visitNodes(node.modifiers, modifierVisitor, isModifier), - visitNode(node.name, visitor, isPropertyName), + Debug.checkDefined(visitNode(node.name, visitor, isPropertyName)), /*questionOrExclamationToken*/ undefined, /*type*/ undefined, visitNode(node.initializer, visitor, isExpression) @@ -452,7 +453,7 @@ export function transformLegacyDecorators(context: TransformationContext): (x: S node, elideNodes(factory, node.modifiers), node.dotDotDotToken, - visitNode(node.name, visitor, isBindingName), + Debug.checkDefined(visitNode(node.name, visitor, isBindingName)), /*questionToken*/ undefined, /*type*/ undefined, visitNode(node.initializer, visitor, isExpression) @@ -649,7 +650,7 @@ export function transformLegacyDecorators(context: TransformationContext): (x: S * @param decorator The decorator node. */ function transformDecorator(decorator: Decorator) { - return visitNode(decorator.expression, visitor, isExpression); + return Debug.checkDefined(visitNode(decorator.expression, visitor, isExpression)); } /** @@ -658,7 +659,7 @@ export function transformLegacyDecorators(context: TransformationContext): (x: S * @param decorators The decorators for the parameter at the provided offset. * @param parameterOffset The offset of the parameter. */ - function transformDecoratorsOfParameter(decorators: Decorator[], parameterOffset: number) { + function transformDecoratorsOfParameter(decorators: readonly Decorator[] | undefined, parameterOffset: number) { let expressions: Expression[] | undefined; if (decorators) { expressions = []; @@ -787,3 +788,4 @@ export function transformLegacyDecorators(context: TransformationContext): (x: S return undefined; } } + diff --git a/src/compiler/transformers/module/esnextAnd2015.ts b/src/compiler/transformers/module/esnextAnd2015.ts index c6d065a77b88f..a9e8037372569 100644 --- a/src/compiler/transformers/module/esnextAnd2015.ts +++ b/src/compiler/transformers/module/esnextAnd2015.ts @@ -116,7 +116,7 @@ export function transformECMAScriptModule(context: TransformationContext): (x: S } } - function visitor(node: Node): VisitResult { + function visitor(node: Node): VisitResult { switch (node.kind) { case SyntaxKind.ImportEqualsDeclaration: // Though an error in es2020 modules, in node-flavor es2020 modules, we can helpfully transform this to a synthetic `require` call @@ -189,7 +189,7 @@ export function transformECMAScriptModule(context: TransformationContext): (x: S * * @param node The node to visit. */ - function visitImportEqualsDeclaration(node: ImportEqualsDeclaration): VisitResult { + function visitImportEqualsDeclaration(node: ImportEqualsDeclaration): VisitResult { Debug.assert(isExternalModuleImportEqualsDeclaration(node), "import= for internal module references should be handled in an earlier transformer."); let statements: Statement[] | undefined; @@ -231,7 +231,7 @@ export function transformECMAScriptModule(context: TransformationContext): (x: S return statements; } - function visitExportAssignment(node: ExportAssignment): VisitResult { + function visitExportAssignment(node: ExportAssignment): VisitResult { // Elide `export=` as it is not legal with --module ES6 return node.isExportEquals ? undefined : node; } diff --git a/src/compiler/transformers/module/module.ts b/src/compiler/transformers/module/module.ts index ac9fa5aa134d3..cdcb78401c126 100644 --- a/src/compiler/transformers/module/module.ts +++ b/src/compiler/transformers/module/module.ts @@ -60,6 +60,7 @@ import { isArrowFunction, isAssignmentOperator, isBindingPattern, + isClassElement, isClassExpression, isDeclarationNameOfEnumOrNamespace, isDefaultImport, @@ -74,11 +75,13 @@ import { isForInitializer, isFunctionExpression, isGeneratedIdentifier, + isHeritageClause, isIdentifier, isImportCall, isImportClause, isImportEqualsDeclaration, isImportSpecifier, + isInitializedVariable, isJsonSourceFile, isLocalName, isModifier, @@ -86,6 +89,7 @@ import { isNamedExports, isObjectLiteralExpression, isOmittedExpression, + isParameter, isPrefixUnaryExpression, isShorthandPropertyAssignment, isSimpleCopiableExpression, @@ -604,7 +608,7 @@ export function transformModule(context: TransformationContext): (x: SourceFile */ function addExportEqualsIfNeeded(statements: Statement[], emitAsReturn: boolean) { if (currentModuleInfo.exportEquals) { - const expressionResult = visitNode(currentModuleInfo.exportEquals.expression, visitor); + const expressionResult = visitNode(currentModuleInfo.exportEquals.expression, visitor, isExpression); if (expressionResult) { if (emitAsReturn) { const statement = factory.createReturnStatement(expressionResult); @@ -640,7 +644,7 @@ export function transformModule(context: TransformationContext): (x: SourceFile * * @param node The node to visit. */ - function topLevelVisitor(node: Node): VisitResult { + function topLevelVisitor(node: Node): VisitResult { switch (node.kind) { case SyntaxKind.ImportDeclaration: return visitImportDeclaration(node as ImportDeclaration); @@ -845,7 +849,7 @@ export function transformModule(context: TransformationContext): (x: SourceFile function visitImportCallExpression(node: ImportCall): Expression { const externalModuleName = getExternalModuleNameLiteral(factory, node, currentSourceFile, host, resolver, compilerOptions); - const firstArgument = visitNode(firstOrUndefined(node.arguments), visitor); + const firstArgument = visitNode(firstOrUndefined(node.arguments), visitor, isExpression); // Only use the external module name if it differs from the first argument. This allows us to preserve the quote style of the argument on output. const argument = externalModuleName && (!firstArgument || !isStringLiteral(firstArgument) || firstArgument.text !== externalModuleName.text) ? externalModuleName : firstArgument; const containsLexicalThis = !!(node.transformFlags & TransformFlags.ContainsLexicalThis); @@ -1057,7 +1061,7 @@ export function transformModule(context: TransformationContext): (x: SourceFile * * @param node The node to visit. */ - function visitImportDeclaration(node: ImportDeclaration): VisitResult { + function visitImportDeclaration(node: ImportDeclaration): VisitResult { let statements: Statement[] | undefined; const namespaceDeclaration = getNamespaceDeclarationNode(node); if (moduleKind !== ModuleKind.AMD) { @@ -1177,7 +1181,7 @@ export function transformModule(context: TransformationContext): (x: SourceFile * * @param node The node to visit. */ - function visitImportEqualsDeclaration(node: ImportEqualsDeclaration): VisitResult { + function visitImportEqualsDeclaration(node: ImportEqualsDeclaration): VisitResult { Debug.assert(isExternalModuleImportEqualsDeclaration(node), "import= for internal module references should be handled in an earlier transformer."); let statements: Statement[] | undefined; @@ -1253,7 +1257,7 @@ export function transformModule(context: TransformationContext): (x: SourceFile * * @param The node to visit. */ - function visitExportDeclaration(node: ExportDeclaration): VisitResult { + function visitExportDeclaration(node: ExportDeclaration): VisitResult { if (!node.moduleSpecifier) { // Elide export declarations with no module specifier as they are handled // elsewhere. @@ -1363,7 +1367,7 @@ export function transformModule(context: TransformationContext): (x: SourceFile * * @param node The node to visit. */ - function visitExportAssignment(node: ExportAssignment): VisitResult { + function visitExportAssignment(node: ExportAssignment): VisitResult { if (node.isExportEquals) { return undefined; } @@ -1373,10 +1377,10 @@ export function transformModule(context: TransformationContext): (x: SourceFile if (original && hasAssociatedEndOfDeclarationMarker(original)) { // Defer exports until we encounter an EndOfDeclarationMarker node const id = getOriginalNodeId(node); - deferredExports[id] = appendExportStatement(deferredExports[id], factory.createIdentifier("default"), visitNode(node.expression, visitor), /*location*/ node, /*allowComments*/ true); + deferredExports[id] = appendExportStatement(deferredExports[id], factory.createIdentifier("default"), visitNode(node.expression, visitor, isExpression), /*location*/ node, /*allowComments*/ true); } else { - statements = appendExportStatement(statements, factory.createIdentifier("default"), visitNode(node.expression, visitor), /*location*/ node, /*allowComments*/ true); + statements = appendExportStatement(statements, factory.createIdentifier("default"), visitNode(node.expression, visitor, isExpression), /*location*/ node, /*allowComments*/ true); } return singleOrMany(statements); @@ -1387,7 +1391,7 @@ export function transformModule(context: TransformationContext): (x: SourceFile * * @param node The node to visit. */ - function visitFunctionDeclaration(node: FunctionDeclaration): VisitResult { + function visitFunctionDeclaration(node: FunctionDeclaration): VisitResult { let statements: Statement[] | undefined; if (hasSyntacticModifier(node, ModifierFlags.Export)) { statements = append(statements, @@ -1398,7 +1402,7 @@ export function transformModule(context: TransformationContext): (x: SourceFile node.asteriskToken, factory.getDeclarationName(node, /*allowComments*/ true, /*allowSourceMaps*/ true), /*typeParameters*/ undefined, - visitNodes(node.parameters, visitor), + visitNodes(node.parameters, visitor, isParameter), /*type*/ undefined, visitEachChild(node.body, visitor, context) ), @@ -1429,7 +1433,7 @@ export function transformModule(context: TransformationContext): (x: SourceFile * * @param node The node to visit. */ - function visitClassDeclaration(node: ClassDeclaration): VisitResult { + function visitClassDeclaration(node: ClassDeclaration): VisitResult { let statements: Statement[] | undefined; if (hasSyntacticModifier(node, ModifierFlags.Export)) { statements = append(statements, @@ -1439,8 +1443,8 @@ export function transformModule(context: TransformationContext): (x: SourceFile visitNodes(node.modifiers, modifierVisitor, isModifierLike), factory.getDeclarationName(node, /*allowComments*/ true, /*allowSourceMaps*/ true), /*typeParameters*/ undefined, - visitNodes(node.heritageClauses, visitor), - visitNodes(node.members, visitor) + visitNodes(node.heritageClauses, visitor, isHeritageClause), + visitNodes(node.members, visitor, isClassElement) ), node ), @@ -1469,7 +1473,7 @@ export function transformModule(context: TransformationContext): (x: SourceFile * * @param node The node to visit. */ - function visitVariableStatement(node: VariableStatement): VisitResult { + function visitVariableStatement(node: VariableStatement): VisitResult { let statements: Statement[] | undefined; let variables: VariableDeclaration[] | undefined; let expressions: Expression[] | undefined; @@ -1503,7 +1507,7 @@ export function transformModule(context: TransformationContext): (x: SourceFile variable.name, variable.exclamationToken, variable.type, - visitNode(variable.initializer, visitor) + visitNode(variable.initializer, visitor, isExpression) ); variables = append(variables, updatedVariable); @@ -1568,8 +1572,8 @@ export function transformModule(context: TransformationContext): (x: SourceFile function transformInitializedVariable(node: InitializedVariableDeclaration): Expression { if (isBindingPattern(node.name)) { return flattenDestructuringAssignment( - visitNode(node, visitor), - /*visitor*/ undefined, + visitNode(node, visitor, isInitializedVariable), + visitor, context, FlattenLevel.All, /*needsValue*/ false, @@ -1585,7 +1589,7 @@ export function transformModule(context: TransformationContext): (x: SourceFile ), /*location*/ node.name ), - node.initializer ? visitNode(node.initializer, visitor) : factory.createVoidZero() + node.initializer ? visitNode(node.initializer, visitor, isExpression) : factory.createVoidZero() ); } } @@ -1909,7 +1913,7 @@ export function transformModule(context: TransformationContext): (x: SourceFile * * @param node The node to visit. */ - function modifierVisitor(node: Node): VisitResult { + function modifierVisitor(node: Node): VisitResult { // Elide module-specific modifiers. switch (node.kind) { case SyntaxKind.ExportKeyword: diff --git a/src/compiler/transformers/module/system.ts b/src/compiler/transformers/module/system.ts index c773832382369..8ecbb68f0e167 100644 --- a/src/compiler/transformers/module/system.ts +++ b/src/compiler/transformers/module/system.ts @@ -78,7 +78,7 @@ import { isNamedExports, isObjectLiteralExpression, isOmittedExpression, - isParameterDeclaration, + isParameter, isPrefixUnaryExpression, isPropertyAssignment, isShorthandPropertyAssignment, @@ -708,7 +708,7 @@ export function transformSystemModule(context: TransformationContext): (x: Sourc * * @param node The node to visit. */ - function topLevelVisitor(node: Node): VisitResult { + function topLevelVisitor(node: Node): VisitResult { switch (node.kind) { case SyntaxKind.ImportDeclaration: return visitImportDeclaration(node as ImportDeclaration); @@ -732,7 +732,7 @@ export function transformSystemModule(context: TransformationContext): (x: Sourc * * @param node The node to visit. */ - function visitImportDeclaration(node: ImportDeclaration): VisitResult { + function visitImportDeclaration(node: ImportDeclaration): VisitResult { let statements: Statement[] | undefined; if (node.importClause) { hoistVariableDeclaration(getLocalNameForExternalImport(factory, node, currentSourceFile)!); // TODO: GH#18217 @@ -750,7 +750,7 @@ export function transformSystemModule(context: TransformationContext): (x: Sourc return singleOrMany(statements); } - function visitExportDeclaration(node: ExportDeclaration): VisitResult { + function visitExportDeclaration(node: ExportDeclaration): VisitResult { Debug.assertIsDefined(node); return undefined; } @@ -760,7 +760,7 @@ export function transformSystemModule(context: TransformationContext): (x: Sourc * * @param node The node to visit. */ - function visitImportEqualsDeclaration(node: ImportEqualsDeclaration): VisitResult { + function visitImportEqualsDeclaration(node: ImportEqualsDeclaration): VisitResult { Debug.assert(isExternalModuleImportEqualsDeclaration(node), "import= for internal module references should be handled in an earlier transformer."); let statements: Statement[] | undefined; @@ -783,7 +783,7 @@ export function transformSystemModule(context: TransformationContext): (x: Sourc * * @param node The node to visit. */ - function visitExportAssignment(node: ExportAssignment): VisitResult { + function visitExportAssignment(node: ExportAssignment): VisitResult { if (node.isExportEquals) { // Elide `export=` as it is illegal in a SystemJS module. return undefined; @@ -806,7 +806,7 @@ export function transformSystemModule(context: TransformationContext): (x: Sourc * * @param node The node to visit. */ - function visitFunctionDeclaration(node: FunctionDeclaration): VisitResult { + function visitFunctionDeclaration(node: FunctionDeclaration): VisitResult { if (hasSyntacticModifier(node, ModifierFlags.Export)) { hoistedStatements = append(hoistedStatements, factory.updateFunctionDeclaration( @@ -815,7 +815,7 @@ export function transformSystemModule(context: TransformationContext): (x: Sourc node.asteriskToken, factory.getDeclarationName(node, /*allowComments*/ true, /*allowSourceMaps*/ true), /*typeParameters*/ undefined, - visitNodes(node.parameters, visitor, isParameterDeclaration), + visitNodes(node.parameters, visitor, isParameter), /*type*/ undefined, visitNode(node.body, visitor, isBlock))); } @@ -840,7 +840,7 @@ export function transformSystemModule(context: TransformationContext): (x: Sourc * * @param node The node to visit. */ - function visitClassDeclaration(node: ClassDeclaration): VisitResult { + function visitClassDeclaration(node: ClassDeclaration): VisitResult { let statements: Statement[] | undefined; // Hoist the name of the class declaration to the outer module body function. @@ -887,7 +887,7 @@ export function transformSystemModule(context: TransformationContext): (x: Sourc * * @param node The node to visit. */ - function visitVariableStatement(node: VariableStatement): VisitResult { + function visitVariableStatement(node: VariableStatement): VisitResult { if (!shouldHoistVariableDeclarationList(node.declarationList)) { return visitNode(node, visitor, isStatement); } @@ -1293,7 +1293,7 @@ export function transformSystemModule(context: TransformationContext): (x: Sourc * * @param node The node to visit. */ - function topLevelNestedVisitor(node: Node): VisitResult { + function topLevelNestedVisitor(node: Node): VisitResult { switch (node.kind) { case SyntaxKind.VariableStatement: return visitVariableStatement(node as VariableStatement); @@ -1448,7 +1448,7 @@ export function transformSystemModule(context: TransformationContext): (x: Sourc return expressions ? factory.inlineExpressions(expressions) : factory.createOmittedExpression(); } else { - return visitNode(node, discardedValueVisitor, isExpression); + return visitNode(node, discardedValueVisitor, isForInitializer); } } @@ -1487,7 +1487,7 @@ export function transformSystemModule(context: TransformationContext): (x: Sourc return factory.updateLabeledStatement( node, node.label, - visitNode(node.statement, topLevelNestedVisitor, isStatement, factory.liftToBlock) + Debug.checkDefined(visitNode(node.statement, topLevelNestedVisitor, isStatement, factory.liftToBlock)) ); } @@ -1500,7 +1500,7 @@ export function transformSystemModule(context: TransformationContext): (x: Sourc return factory.updateWithStatement( node, visitNode(node.expression, visitor, isExpression), - visitNode(node.statement, topLevelNestedVisitor, isStatement, factory.liftToBlock) + Debug.checkDefined(visitNode(node.statement, topLevelNestedVisitor, isStatement, factory.liftToBlock)) ); } @@ -1513,7 +1513,7 @@ export function transformSystemModule(context: TransformationContext): (x: Sourc return factory.updateSwitchStatement( node, visitNode(node.expression, visitor, isExpression), - visitNode(node.caseBlock, topLevelNestedVisitor, isCaseBlock) + Debug.checkDefined(visitNode(node.caseBlock, topLevelNestedVisitor, isCaseBlock)) ); } @@ -1578,7 +1578,7 @@ export function transformSystemModule(context: TransformationContext): (x: Sourc node = factory.updateCatchClause( node, node.variableDeclaration, - visitNode(node.block, topLevelNestedVisitor, isBlock) + Debug.checkDefined(visitNode(node.block, topLevelNestedVisitor, isBlock)) ); enclosingBlockScopedContainer = savedEnclosingBlockScopedContainer; @@ -1676,7 +1676,7 @@ export function transformSystemModule(context: TransformationContext): (x: Sourc // }; // }); const externalModuleName = getExternalModuleNameLiteral(factory, node, currentSourceFile, host, resolver, compilerOptions); - const firstArgument = visitNode(firstOrUndefined(node.arguments), visitor); + const firstArgument = visitNode(firstOrUndefined(node.arguments), visitor, isExpression); // Only use the external module name if it differs from the first argument. This allows us to preserve the quote style of the argument on output. const argument = externalModuleName && (!firstArgument || !isStringLiteral(firstArgument) || firstArgument.text !== externalModuleName.text) ? externalModuleName : firstArgument; return factory.createCallExpression( @@ -1798,7 +1798,7 @@ export function transformSystemModule(context: TransformationContext): (x: Sourc * * @param node The node to visit. */ - function modifierVisitor(node: Node): VisitResult { + function modifierVisitor(node: Node): VisitResult { switch (node.kind) { case SyntaxKind.ExportKeyword: case SyntaxKind.DefaultKeyword: diff --git a/src/compiler/transformers/taggedTemplate.ts b/src/compiler/transformers/taggedTemplate.ts index 041e0adf84acb..208244c659cc1 100644 --- a/src/compiler/transformers/taggedTemplate.ts +++ b/src/compiler/transformers/taggedTemplate.ts @@ -41,6 +41,7 @@ export function processTaggedTemplateExpression( // Visit the tag expression const tag = visitNode(node.tag, visitor, isExpression); + Debug.assert(tag); // Build up the template arguments and the raw and cooked strings for the template. // We start out with 'undefined' for the first argument and revisit later @@ -64,7 +65,7 @@ export function processTaggedTemplateExpression( for (const templateSpan of template.templateSpans) { cookedStrings.push(createTemplateCooked(templateSpan.literal)); rawStrings.push(getRawLiteral(templateSpan.literal, currentSourceFile)); - templateArguments.push(visitNode(templateSpan.expression, visitor, isExpression)); + templateArguments.push(Debug.checkDefined(visitNode(templateSpan.expression, visitor, isExpression))); } } diff --git a/src/compiler/transformers/ts.ts b/src/compiler/transformers/ts.ts index 1b27a345ce67b..d47ada78383fb 100644 --- a/src/compiler/transformers/ts.ts +++ b/src/compiler/transformers/ts.ts @@ -110,7 +110,7 @@ import { isNamedExportBindings, isNamedImportBindings, isNamespaceExport, - isObjectLiteralElement, + isObjectLiteralElementLike, isParameterPropertyDeclaration, isPrivateIdentifier, isPropertyAccessExpression, @@ -119,6 +119,7 @@ import { isSimpleInlineableExpression, isSourceFile, isStatement, + isTemplateLiteral, JsxOpeningElement, JsxSelfClosingElement, lastOrUndefined, @@ -319,7 +320,7 @@ export function transformTypeScript(context: TransformationContext) { * * @param node The node to visit. */ - function saveStateAndInvoke(node: Node, f: (node: Node) => T): T { + function saveStateAndInvoke(node: U, f: (node: U) => T): T { // Save state const savedCurrentScope = currentLexicalScope; const savedCurrentScopeFirstDeclarationsOfName = currentScopeFirstDeclarationsOfName; @@ -381,7 +382,7 @@ export function transformTypeScript(context: TransformationContext) { * * @param node The node to visit. */ - function visitor(node: Node): VisitResult { + function visitor(node: Node): VisitResult { return saveStateAndInvoke(node, visitorWorker); } @@ -390,7 +391,7 @@ export function transformTypeScript(context: TransformationContext) { * * @param node The node to visit. */ - function visitorWorker(node: Node): VisitResult { + function visitorWorker(node: Node): VisitResult { if (node.transformFlags & TransformFlags.ContainsTypeScript) { return visitTypeScript(node); } @@ -402,7 +403,7 @@ export function transformTypeScript(context: TransformationContext) { * * @param node The node to visit. */ - function sourceElementVisitor(node: Node): VisitResult { + function sourceElementVisitor(node: Node): VisitResult { return saveStateAndInvoke(node, sourceElementVisitorWorker); } @@ -411,7 +412,7 @@ export function transformTypeScript(context: TransformationContext) { * * @param node The node to visit. */ - function sourceElementVisitorWorker(node: Node): VisitResult { + function sourceElementVisitorWorker(node: Node): VisitResult { switch (node.kind) { case SyntaxKind.ImportDeclaration: case SyntaxKind.ImportEqualsDeclaration: @@ -423,7 +424,7 @@ export function transformTypeScript(context: TransformationContext) { } } - function visitElidableStatement(node: ImportDeclaration | ImportEqualsDeclaration | ExportAssignment | ExportDeclaration): VisitResult { + function visitElidableStatement(node: ImportDeclaration | ImportEqualsDeclaration | ExportAssignment | ExportDeclaration): VisitResult { const parsed = getParseTreeNode(node); if (parsed !== node) { // If the node has been transformed by a `before` transformer, perform no ellision on it @@ -456,7 +457,7 @@ export function transformTypeScript(context: TransformationContext) { * * @param node The node to visit. */ - function namespaceElementVisitor(node: Node): VisitResult { + function namespaceElementVisitor(node: Node): VisitResult { return saveStateAndInvoke(node, namespaceElementVisitorWorker); } @@ -465,7 +466,7 @@ export function transformTypeScript(context: TransformationContext) { * * @param node The node to visit. */ - function namespaceElementVisitorWorker(node: Node): VisitResult { + function namespaceElementVisitorWorker(node: Node): VisitResult { if (node.kind === SyntaxKind.ExportDeclaration || node.kind === SyntaxKind.ImportDeclaration || node.kind === SyntaxKind.ImportClause || @@ -486,7 +487,7 @@ export function transformTypeScript(context: TransformationContext) { * * @param parent The class containing the elements to visit. */ - function getClassElementVisitor(parent: ClassLikeDeclaration): (node: Node) => VisitResult { + function getClassElementVisitor(parent: ClassLikeDeclaration): (node: Node) => VisitResult { return node => saveStateAndInvoke(node, n => classElementVisitorWorker(n, parent)); } @@ -495,7 +496,7 @@ export function transformTypeScript(context: TransformationContext) { * * @param node The node to visit. */ - function classElementVisitorWorker(node: Node, parent: ClassLikeDeclaration): VisitResult { + function classElementVisitorWorker(node: Node, parent: ClassLikeDeclaration): VisitResult { switch (node.kind) { case SyntaxKind.Constructor: return visitConstructor(node as ConstructorDeclaration); @@ -533,11 +534,11 @@ export function transformTypeScript(context: TransformationContext) { } } - function getObjectLiteralElementVisitor(parent: ObjectLiteralExpression): (node: Node) => VisitResult { + function getObjectLiteralElementVisitor(parent: ObjectLiteralExpression): (node: T) => VisitResult { return node => saveStateAndInvoke(node, n => objectLiteralElementVisitorWorker(n, parent)); } - function objectLiteralElementVisitorWorker(node: Node, parent: ObjectLiteralExpression): VisitResult { + function objectLiteralElementVisitorWorker(node: Node, parent: ObjectLiteralExpression): VisitResult { switch (node.kind) { case SyntaxKind.PropertyAssignment: case SyntaxKind.ShorthandPropertyAssignment: @@ -562,7 +563,7 @@ export function transformTypeScript(context: TransformationContext) { } } - function modifierVisitor(node: Node): VisitResult { + function modifierVisitor(node: Node): VisitResult { if (isDecorator(node)) return undefined; if (modifierToFlag(node.kind) & ModifierFlags.TypeScriptModifier) { return undefined; @@ -579,7 +580,7 @@ export function transformTypeScript(context: TransformationContext) { * * @param node The node to visit. */ - function visitTypeScript(node: Node): VisitResult { + function visitTypeScript(node: Node): VisitResult { if (isStatement(node) && hasSyntacticModifier(node, ModifierFlags.Ambient)) { // TypeScript ambient declarations are elided, but some comments may be preserved. // See the implementation of `getLeadingComments` in comments.ts for more details. @@ -789,7 +790,7 @@ export function transformTypeScript(context: TransformationContext) { function visitObjectLiteralExpression(node: ObjectLiteralExpression) { return factory.updateObjectLiteralExpression( node, - visitNodes(node.properties, getObjectLiteralElementVisitor(node), isObjectLiteralElement) + visitNodes(node.properties, getObjectLiteralElementVisitor(node), isObjectLiteralElementLike) ); } @@ -1013,11 +1014,12 @@ export function transformTypeScript(context: TransformationContext) { * @param parameterDecorators The decorators for the parameter at the provided offset. * @param parameterOffset The offset of the parameter. */ - function transformDecoratorsOfParameter(parameterDecorators: Decorator[], parameterOffset: number) { + function transformDecoratorsOfParameter(parameterDecorators: readonly Decorator[] | undefined, parameterOffset: number) { if (parameterDecorators) { const decorators: Decorator[] = []; for (const parameterDecorator of parameterDecorators) { const expression = visitNode(parameterDecorator.expression, visitor, isExpression); + Debug.assert(expression); const helper = emitHelpers().createParamHelper(expression, parameterOffset); setTextRange(helper, parameterDecorator.expression); setEmitFlags(helper, EmitFlags.NoComments); @@ -1169,6 +1171,7 @@ export function transformTypeScript(context: TransformationContext) { // - the property has a decorator. if (isComputedPropertyName(name) && ((!hasStaticModifier(member) && currentClassHasParameterProperties) || hasDecorators(member))) { const expression = visitNode(name.expression, visitor, isExpression); + Debug.assert(expression); const innerExpression = skipPartiallyEmittedExpressions(expression); if (!isSimpleInlineableExpression(innerExpression)) { const generatedName = factory.getGeneratedNameForNode(name); @@ -1176,7 +1179,7 @@ export function transformTypeScript(context: TransformationContext) { return factory.updateComputedPropertyName(name, factory.createAssignment(generatedName, expression)); } } - return visitNode(name, visitor, isPropertyName); + return Debug.checkDefined(visitNode(name, visitor, isPropertyName)); } /** @@ -1207,7 +1210,7 @@ export function transformTypeScript(context: TransformationContext) { function visitExpressionWithTypeArguments(node: ExpressionWithTypeArguments): ExpressionWithTypeArguments { return factory.updateExpressionWithTypeArguments( node, - visitNode(node.expression, visitor, isLeftHandSideExpression), + Debug.checkDefined(visitNode(node.expression, visitor, isLeftHandSideExpression)), /*typeArguments*/ undefined ); } @@ -1236,7 +1239,7 @@ export function transformTypeScript(context: TransformationContext) { return factory.updatePropertyDeclaration( node, concatenate(decorators, factory.createModifiersFromModifierFlags(ModifierFlags.Ambient)), - visitNode(node.name, visitor, isPropertyName), + Debug.checkDefined(visitNode(node.name, visitor, isPropertyName)), /*questionOrExclamationToken*/ undefined, /*type*/ undefined, /*initializer*/ undefined @@ -1249,7 +1252,7 @@ export function transformTypeScript(context: TransformationContext) { visitPropertyNameOfClassElement(node), /*questionOrExclamationToken*/ undefined, /*type*/ undefined, - visitNode(node.initializer, visitor) + visitNode(node.initializer, visitor, isExpression) ); } @@ -1268,7 +1271,7 @@ export function transformTypeScript(context: TransformationContext) { function transformConstructorBody(body: Block, constructor: ConstructorDeclaration) { const parametersWithPropertyAssignments = constructor && - filter(constructor.parameters, p => isParameterPropertyDeclaration(p, constructor)); + filter(constructor.parameters, p => isParameterPropertyDeclaration(p, constructor)) as readonly ParameterPropertyDeclaration[] | undefined; if (!some(parametersWithPropertyAssignments)) { return visitFunctionBody(body, visitor, context); } @@ -1510,7 +1513,7 @@ export function transformTypeScript(context: TransformationContext) { node, elideNodes(factory, node.modifiers), // preserve positions, if available node.dotDotDotToken, - visitNode(node.name, visitor, isBindingName), + Debug.checkDefined(visitNode(node.name, visitor, isBindingName)), /*questionToken*/ undefined, /*type*/ undefined, visitNode(node.initializer, visitor, isExpression) @@ -1564,7 +1567,7 @@ export function transformTypeScript(context: TransformationContext) { return setTextRange( factory.createAssignment( getNamespaceMemberNameWithSourceMapsAndWithoutComments(name), - visitNode(node.initializer, visitor, isExpression) + Debug.checkDefined(visitNode(node.initializer, visitor, isExpression)) ), /*location*/ node ); @@ -1574,7 +1577,7 @@ export function transformTypeScript(context: TransformationContext) { function visitVariableDeclaration(node: VariableDeclaration) { const updated = factory.updateVariableDeclaration( node, - visitNode(node.name, visitor, isBindingName), + Debug.checkDefined(visitNode(node.name, visitor, isBindingName)), /*exclamationToken*/ undefined, /*type*/ undefined, visitNode(node.initializer, visitor, isExpression)); @@ -1590,6 +1593,7 @@ export function transformTypeScript(context: TransformationContext) { // Make sure we consider all nested cast expressions, e.g.: // (-A).x; const expression = visitNode(node.expression, visitor, isExpression); + Debug.assert(expression); // We have an expression of the form: (SubExpr). Emitting this as (SubExpr) // is really not desirable. We would like to emit the subexpression as-is. Omitting @@ -1616,23 +1620,26 @@ export function transformTypeScript(context: TransformationContext) { function visitAssertionExpression(node: AssertionExpression): Expression { const expression = visitNode(node.expression, visitor, isExpression); + Debug.assert(expression); return factory.createPartiallyEmittedExpression(expression, node); } function visitNonNullExpression(node: NonNullExpression): Expression { const expression = visitNode(node.expression, visitor, isLeftHandSideExpression); + Debug.assert(expression); return factory.createPartiallyEmittedExpression(expression, node); } function visitSatisfiesExpression(node: SatisfiesExpression): Expression { const expression = visitNode(node.expression, visitor, isExpression); + Debug.assert(expression); return factory.createPartiallyEmittedExpression(expression, node); } function visitCallExpression(node: CallExpression) { return factory.updateCallExpression( node, - visitNode(node.expression, visitor, isExpression), + Debug.checkDefined(visitNode(node.expression, visitor, isExpression)), /*typeArguments*/ undefined, visitNodes(node.arguments, visitor, isExpression)); } @@ -1640,7 +1647,7 @@ export function transformTypeScript(context: TransformationContext) { function visitNewExpression(node: NewExpression) { return factory.updateNewExpression( node, - visitNode(node.expression, visitor, isExpression), + Debug.checkDefined(visitNode(node.expression, visitor, isExpression)), /*typeArguments*/ undefined, visitNodes(node.arguments, visitor, isExpression)); } @@ -1648,25 +1655,25 @@ export function transformTypeScript(context: TransformationContext) { function visitTaggedTemplateExpression(node: TaggedTemplateExpression) { return factory.updateTaggedTemplateExpression( node, - visitNode(node.tag, visitor, isExpression), + Debug.checkDefined(visitNode(node.tag, visitor, isExpression)), /*typeArguments*/ undefined, - visitNode(node.template, visitor, isExpression)); + Debug.checkDefined(visitNode(node.template, visitor, isTemplateLiteral))); } function visitJsxSelfClosingElement(node: JsxSelfClosingElement) { return factory.updateJsxSelfClosingElement( node, - visitNode(node.tagName, visitor, isJsxTagNameExpression), + Debug.checkDefined(visitNode(node.tagName, visitor, isJsxTagNameExpression)), /*typeArguments*/ undefined, - visitNode(node.attributes, visitor, isJsxAttributes)); + Debug.checkDefined(visitNode(node.attributes, visitor, isJsxAttributes))); } function visitJsxJsxOpeningElement(node: JsxOpeningElement) { return factory.updateJsxOpeningElement( node, - visitNode(node.tagName, visitor, isJsxTagNameExpression), + Debug.checkDefined(visitNode(node.tagName, visitor, isJsxTagNameExpression)), /*typeArguments*/ undefined, - visitNode(node.attributes, visitor, isJsxAttributes)); + Debug.checkDefined(visitNode(node.attributes, visitor, isJsxAttributes))); } /** @@ -1847,7 +1854,7 @@ export function transformTypeScript(context: TransformationContext) { else { enableSubstitutionForNonQualifiedEnumMembers(); if (member.initializer) { - return visitNode(member.initializer, visitor, isExpression); + return Debug.checkDefined(visitNode(member.initializer, visitor, isExpression)); } else { return factory.createVoidZero(); @@ -2095,7 +2102,7 @@ export function transformTypeScript(context: TransformationContext) { let blockLocation: TextRange | undefined; if (node.body) { if (node.body.kind === SyntaxKind.ModuleBlock) { - saveStateAndInvoke(node.body, body => addRange(statements, visitNodes((body as ModuleBlock).statements, namespaceElementVisitor, isStatement))); + saveStateAndInvoke(node.body, body => addRange(statements, visitNodes(body.statements, namespaceElementVisitor, isStatement))); statementsLocation = node.body.statements; blockLocation = node.body; } @@ -2167,7 +2174,7 @@ export function transformTypeScript(context: TransformationContext) { * * @param node The import declaration node. */ - function visitImportDeclaration(node: ImportDeclaration): VisitResult { + function visitImportDeclaration(node: ImportDeclaration): VisitResult { if (!node.importClause) { // Do not elide a side-effect only import declaration. // import "foo"; @@ -2197,7 +2204,7 @@ export function transformTypeScript(context: TransformationContext) { * * @param node The import clause node. */ - function visitImportClause(node: ImportClause): VisitResult { + function visitImportClause(node: ImportClause): VisitResult | undefined { Debug.assert(!node.isTypeOnly); // Elide the import clause if we elide both its name and its named bindings. const name = shouldEmitAliasDeclaration(node) ? node.name : undefined; @@ -2210,7 +2217,7 @@ export function transformTypeScript(context: TransformationContext) { * * @param node The named import bindings node. */ - function visitNamedImportBindings(node: NamedImportBindings): VisitResult { + function visitNamedImportBindings(node: NamedImportBindings): VisitResult | undefined { if (node.kind === SyntaxKind.NamespaceImport) { // Elide a namespace import if it is not referenced. return shouldEmitAliasDeclaration(node) ? node : undefined; @@ -2230,7 +2237,7 @@ export function transformTypeScript(context: TransformationContext) { * * @param node The import specifier node. */ - function visitImportSpecifier(node: ImportSpecifier): VisitResult { + function visitImportSpecifier(node: ImportSpecifier): VisitResult | undefined { return !node.isTypeOnly && shouldEmitAliasDeclaration(node) ? node : undefined; } @@ -2240,7 +2247,7 @@ export function transformTypeScript(context: TransformationContext) { * * @param node The export assignment node. */ - function visitExportAssignment(node: ExportAssignment): VisitResult { + function visitExportAssignment(node: ExportAssignment): VisitResult { // Elide the export assignment if it does not reference a value. return resolver.isValueAliasDeclaration(node) ? visitEachChild(node, visitor, context) @@ -2252,7 +2259,7 @@ export function transformTypeScript(context: TransformationContext) { * * @param node The export declaration node. */ - function visitExportDeclaration(node: ExportDeclaration): VisitResult { + function visitExportDeclaration(node: ExportDeclaration): VisitResult { if (node.isTypeOnly) { return undefined; } @@ -2290,17 +2297,17 @@ export function transformTypeScript(context: TransformationContext) { * * @param node The named exports node. */ - function visitNamedExports(node: NamedExports, allowEmpty: boolean): VisitResult { + function visitNamedExports(node: NamedExports, allowEmpty: boolean): VisitResult | undefined { // Elide the named exports if all of its export specifiers were elided. const elements = visitNodes(node.elements, visitExportSpecifier, isExportSpecifier); return allowEmpty || some(elements) ? factory.updateNamedExports(node, elements) : undefined; } function visitNamespaceExports(node: NamespaceExport): VisitResult { - return factory.updateNamespaceExport(node, visitNode(node.name, visitor, isIdentifier)); + return factory.updateNamespaceExport(node, Debug.checkDefined(visitNode(node.name, visitor, isIdentifier))); } - function visitNamedExportBindings(node: NamedExportBindings, allowEmpty: boolean): VisitResult { + function visitNamedExportBindings(node: NamedExportBindings, allowEmpty: boolean): VisitResult | undefined { return isNamespaceExport(node) ? visitNamespaceExports(node) : visitNamedExports(node, allowEmpty); } @@ -2309,7 +2316,7 @@ export function transformTypeScript(context: TransformationContext) { * * @param node The export specifier node. */ - function visitExportSpecifier(node: ExportSpecifier): VisitResult { + function visitExportSpecifier(node: ExportSpecifier): VisitResult | undefined { // Elide an export specifier if it does not reference a value. return !node.isTypeOnly && resolver.isValueAliasDeclaration(node) ? node : undefined; } @@ -2333,7 +2340,7 @@ export function transformTypeScript(context: TransformationContext) { * * @param node The import equals declaration node. */ - function visitImportEqualsDeclaration(node: ImportEqualsDeclaration): VisitResult { + function visitImportEqualsDeclaration(node: ImportEqualsDeclaration): VisitResult { // Always elide type-only imports if (node.isTypeOnly) { return undefined; diff --git a/src/compiler/tsbuildPublic.ts b/src/compiler/tsbuildPublic.ts index 1c07510c35002..836b9f3b98bde 100644 --- a/src/compiler/tsbuildPublic.ts +++ b/src/compiler/tsbuildPublic.ts @@ -364,7 +364,7 @@ interface BuildInfoCacheEntry { latestChangedDtsTime?: Date | false; } -interface SolutionBuilderState extends WatchFactory { +interface SolutionBuilderState extends WatchFactory { readonly host: SolutionBuilderHost; readonly hostWithWatch: SolutionBuilderWithWatchHost; readonly parseConfigFileHost: ParseConfigFileHost; @@ -524,11 +524,11 @@ function createSolutionBuilderState(watch: boolean, ho return state; } -function toPath(state: SolutionBuilderState, fileName: string) { +function toPath(state: SolutionBuilderState, fileName: string) { return ts.toPath(fileName, state.compilerHost.getCurrentDirectory(), state.compilerHost.getCanonicalFileName); } -function toResolvedConfigFilePath(state: SolutionBuilderState, fileName: ResolvedConfigFileName): ResolvedConfigFilePath { +function toResolvedConfigFilePath(state: SolutionBuilderState, fileName: ResolvedConfigFileName): ResolvedConfigFilePath { const { resolvedConfigFilePaths } = state; const path = resolvedConfigFilePaths.get(fileName); if (path !== undefined) return path; @@ -542,12 +542,12 @@ function isParsedCommandLine(entry: ConfigFileCacheEntry): entry is ParsedComman return !!(entry as ParsedCommandLine).options; } -function getCachedParsedConfigFile(state: SolutionBuilderState, configFilePath: ResolvedConfigFilePath): ParsedCommandLine | undefined { +function getCachedParsedConfigFile(state: SolutionBuilderState, configFilePath: ResolvedConfigFilePath): ParsedCommandLine | undefined { const value = state.configFileCache.get(configFilePath); return value && isParsedCommandLine(value) ? value : undefined; } -function parseConfigFile(state: SolutionBuilderState, configFileName: ResolvedConfigFileName, configFilePath: ResolvedConfigFilePath): ParsedCommandLine | undefined { +function parseConfigFile(state: SolutionBuilderState, configFileName: ResolvedConfigFileName, configFilePath: ResolvedConfigFilePath): ParsedCommandLine | undefined { const { configFileCache } = state; const value = configFileCache.get(configFilePath); if (value) { @@ -573,11 +573,11 @@ function parseConfigFile(state: SolutionBuilderState, configFileName: ResolvedCo return parsed; } -function resolveProjectName(state: SolutionBuilderState, name: string): ResolvedConfigFileName { +function resolveProjectName(state: SolutionBuilderState, name: string): ResolvedConfigFileName { return resolveConfigFileProjectName(resolvePath(state.compilerHost.getCurrentDirectory(), name)); } -function createBuildOrder(state: SolutionBuilderState, roots: readonly ResolvedConfigFileName[]): AnyBuildOrder { +function createBuildOrder(state: SolutionBuilderState, roots: readonly ResolvedConfigFileName[]): AnyBuildOrder { const temporaryMarks = new Map(); const permanentMarks = new Map(); const circularityReportStack: string[] = []; @@ -624,11 +624,11 @@ function createBuildOrder(state: SolutionBuilderState, roots: readonly ResolvedC } } -function getBuildOrder(state: SolutionBuilderState) { +function getBuildOrder(state: SolutionBuilderState) { return state.buildOrder || createStateBuildOrder(state); } -function createStateBuildOrder(state: SolutionBuilderState) { +function createStateBuildOrder(state: SolutionBuilderState) { const buildOrder = createBuildOrder(state, state.rootNames.map(f => resolveProjectName(state, f))); // Clear all to ResolvedConfigFilePaths cache to start fresh @@ -689,7 +689,7 @@ function createStateBuildOrder(state: SolutionBuilderState) { return state.buildOrder = buildOrder; } -function getBuildOrderFor(state: SolutionBuilderState, project: string | undefined, onlyReferences: boolean | undefined): AnyBuildOrder | undefined { +function getBuildOrderFor(state: SolutionBuilderState, project: string | undefined, onlyReferences: boolean | undefined): AnyBuildOrder | undefined { const resolvedProject = project && resolveProjectName(state, project); const buildOrderFromState = getBuildOrder(state); if (isCircularBuildOrder(buildOrderFromState)) return buildOrderFromState; @@ -708,7 +708,7 @@ function getBuildOrderFor(state: SolutionBuilderState, project: string | undefin return onlyReferences ? buildOrder.slice(0, buildOrder.length - 1) : buildOrder; } -function enableCache(state: SolutionBuilderState) { +function enableCache(state: SolutionBuilderState) { if (state.cache) { disableCache(state); } @@ -741,7 +741,7 @@ function enableCache(state: SolutionBuilderState) { }; } -function disableCache(state: SolutionBuilderState) { +function disableCache(state: SolutionBuilderState) { if (!state.cache) return; const { cache, host, compilerHost, extendedConfigCache, moduleResolutionCache, typeReferenceDirectiveResolutionCache } = state; @@ -759,12 +759,12 @@ function disableCache(state: SolutionBuilderState) { state.cache = undefined; } -function clearProjectStatus(state: SolutionBuilderState, resolved: ResolvedConfigFilePath) { +function clearProjectStatus(state: SolutionBuilderState, resolved: ResolvedConfigFilePath) { state.projectStatus.delete(resolved); state.diagnostics.delete(resolved); } -function addProjToQueue({ projectPendingBuild }: SolutionBuilderState, proj: ResolvedConfigFilePath, reloadLevel: ConfigFileProgramReloadLevel) { +function addProjToQueue({ projectPendingBuild }: SolutionBuilderState, proj: ResolvedConfigFilePath, reloadLevel: ConfigFileProgramReloadLevel) { const value = projectPendingBuild.get(proj); if (value === undefined) { projectPendingBuild.set(proj, reloadLevel); @@ -774,7 +774,7 @@ function addProjToQueue({ projectPendingBuild }: SolutionBuilderState, proj: Res } } -function setupInitialBuild(state: SolutionBuilderState, cancellationToken: CancellationToken | undefined) { +function setupInitialBuild(state: SolutionBuilderState, cancellationToken: CancellationToken | undefined) { // Set initial build if not already built if (!state.allProjectBuildPending) return; state.allProjectBuildPending = false; @@ -854,8 +854,8 @@ export interface UpdateBundleProject extends Invalidat export type InvalidatedProject = UpdateOutputFileStampsProject | BuildInvalidedProject | UpdateBundleProject; -function doneInvalidatedProject( - state: SolutionBuilderState, +function doneInvalidatedProject( + state: SolutionBuilderState, projectPath: ResolvedConfigFilePath ) { state.projectPendingBuild.delete(projectPath); @@ -864,8 +864,8 @@ function doneInvalidatedProject( ExitStatus.Success; } -function createUpdateOutputFileStampsProject( - state: SolutionBuilderState, +function createUpdateOutputFileStampsProject( + state: SolutionBuilderState, project: ResolvedConfigFileName, projectPath: ResolvedConfigFilePath, config: ParsedCommandLine, @@ -1340,7 +1340,7 @@ function createBuildOrUpdateInvalidedProject( } } -function needsBuild({ options }: SolutionBuilderState, status: UpToDateStatus, config: ParsedCommandLine) { +function needsBuild({ options }: SolutionBuilderState, status: UpToDateStatus, config: ParsedCommandLine) { if (status.type !== UpToDateStatusType.OutOfDateWithPrepend || options.force) return true; return config.fileNames.length === 0 || !!getConfigFileParsingDiagnostics(config).length || @@ -1500,7 +1500,7 @@ function getNextInvalidatedProject( return createInvalidatedProjectWithInfo(state, info, buildOrder); } -function listEmittedFile({ write }: SolutionBuilderState, proj: ParsedCommandLine, file: string) { +function listEmittedFile({ write }: SolutionBuilderState, proj: ParsedCommandLine, file: string) { if (write && proj.options.listEmittedFiles) { write(`TSFILE: ${file}`); } @@ -1554,7 +1554,7 @@ function isFileWatcherWithModifiedTime(value: FileWatcherWithModifiedTime | Date return !!(value as FileWatcherWithModifiedTime).watcher; } -function getModifiedTime(state: SolutionBuilderState, fileName: string): Date { +function getModifiedTime(state: SolutionBuilderState, fileName: string): Date { const path = toPath(state, fileName); const existing = state.filesWatched.get(path); if (state.watch && !!existing) { @@ -1572,7 +1572,7 @@ function getModifiedTime(state: SolutionBuilderState, fileName: string): Date { return result; } -function watchFile(state: SolutionBuilderState, file: string, callback: FileWatcherCallback, pollingInterval: PollingInterval, options: WatchOptions | undefined, watchType: WatchType, project?: ResolvedConfigFileName): FileWatcher { +function watchFile(state: SolutionBuilderState, file: string, callback: FileWatcherCallback, pollingInterval: PollingInterval, options: WatchOptions | undefined, watchType: WatchType, project?: ResolvedConfigFileName): FileWatcher { const path = toPath(state, file); const existing = state.filesWatched.get(path); if (existing && isFileWatcherWithModifiedTime(existing)) { @@ -1610,7 +1610,7 @@ function watchFile(state: SolutionBuilderState, file: string, callback: FileWatc }; } -function getOutputTimeStampMap(state: SolutionBuilderState, resolvedConfigFilePath: ResolvedConfigFilePath) { +function getOutputTimeStampMap(state: SolutionBuilderState, resolvedConfigFilePath: ResolvedConfigFilePath) { // Output timestamps are stored only in watch mode if (!state.watch) return undefined; let result = state.outputTimeStamps.get(resolvedConfigFilePath); @@ -1618,8 +1618,8 @@ function getOutputTimeStampMap(state: SolutionBuilderState, resolvedConfigFilePa return result; } -function setBuildInfo( - state: SolutionBuilderState, +function setBuildInfo( + state: SolutionBuilderState, buildInfo: BuildInfo, resolvedConfigPath: ResolvedConfigFilePath, options: CompilerOptions, @@ -1643,13 +1643,13 @@ function setBuildInfo( } } -function getBuildInfoCacheEntry(state: SolutionBuilderState, buildInfoPath: string, resolvedConfigPath: ResolvedConfigFilePath) { +function getBuildInfoCacheEntry(state: SolutionBuilderState, buildInfoPath: string, resolvedConfigPath: ResolvedConfigFilePath) { const path = toPath(state, buildInfoPath); const existing = state.buildInfoCache.get(resolvedConfigPath); return existing?.path === path ? existing : undefined; } -function getBuildInfo(state: SolutionBuilderState, buildInfoPath: string, resolvedConfigPath: ResolvedConfigFilePath, modifiedTime: Date | undefined): BuildInfo | undefined { +function getBuildInfo(state: SolutionBuilderState, buildInfoPath: string, resolvedConfigPath: ResolvedConfigFilePath, modifiedTime: Date | undefined): BuildInfo | undefined { const path = toPath(state, buildInfoPath); const existing = state.buildInfoCache.get(resolvedConfigPath); if (existing !== undefined && existing.path === path) { @@ -1661,7 +1661,7 @@ function getBuildInfo(state: SolutionBuilderState, buildInfoPath: string, resolv return buildInfo; } -function checkConfigFileUpToDateStatus(state: SolutionBuilderState, configFile: string, oldestOutputFileTime: Date, oldestOutputFileName: string): Status.OutOfDateWithSelf | undefined { +function checkConfigFileUpToDateStatus(state: SolutionBuilderState, configFile: string, oldestOutputFileTime: Date, oldestOutputFileName: string): Status.OutOfDateWithSelf | undefined { // Check tsconfig time const tsconfigTime = getModifiedTime(state, configFile); if (oldestOutputFileTime < tsconfigTime) { @@ -1673,7 +1673,7 @@ function checkConfigFileUpToDateStatus(state: SolutionBuilderState, configFile: } } -function getUpToDateStatusWorker(state: SolutionBuilderState, project: ParsedCommandLine, resolvedPath: ResolvedConfigFilePath): UpToDateStatus { +function getUpToDateStatusWorker(state: SolutionBuilderState, project: ParsedCommandLine, resolvedPath: ResolvedConfigFilePath): UpToDateStatus { // Container if no files are specified in the project if (!project.fileNames.length && !canJsonReportNoInputFiles(project.raw)) { return { @@ -1953,12 +1953,12 @@ function getUpToDateStatusWorker(state: SolutionBuilderState, project: ParsedCom }; } -function hasSameBuildInfo(state: SolutionBuilderState, buildInfoCacheEntry: BuildInfoCacheEntry, resolvedRefPath: ResolvedConfigFilePath) { +function hasSameBuildInfo(state: SolutionBuilderState, buildInfoCacheEntry: BuildInfoCacheEntry, resolvedRefPath: ResolvedConfigFilePath) { const refBuildInfo = state.buildInfoCache.get(resolvedRefPath)!; return refBuildInfo.path === buildInfoCacheEntry.path; } -function getUpToDateStatus(state: SolutionBuilderState, project: ParsedCommandLine | undefined, resolvedPath: ResolvedConfigFilePath): UpToDateStatus { +function getUpToDateStatus(state: SolutionBuilderState, project: ParsedCommandLine | undefined, resolvedPath: ResolvedConfigFilePath): UpToDateStatus { if (project === undefined) { return { type: UpToDateStatusType.Unbuildable, reason: "File deleted mid-build" }; } @@ -1976,8 +1976,8 @@ function getUpToDateStatus(state: SolutionBuilderState, project: ParsedCommandLi return actual; } -function updateOutputTimestampsWorker( - state: SolutionBuilderState, +function updateOutputTimestampsWorker( + state: SolutionBuilderState, proj: ParsedCommandLine, projectPath: ResolvedConfigFilePath, verboseMessage: DiagnosticMessage, @@ -2026,7 +2026,7 @@ function updateOutputTimestampsWorker( }); } -function getLatestChangedDtsTime(state: SolutionBuilderState, options: CompilerOptions, resolvedConfigPath: ResolvedConfigFilePath) { +function getLatestChangedDtsTime(state: SolutionBuilderState, options: CompilerOptions, resolvedConfigPath: ResolvedConfigFilePath) { if (!options.composite) return undefined; const entry = Debug.checkDefined(state.buildInfoCache.get(resolvedConfigPath)); if (entry.latestChangedDtsTime !== undefined) return entry.latestChangedDtsTime || undefined; @@ -2037,7 +2037,7 @@ function getLatestChangedDtsTime(state: SolutionBuilderState, options: CompilerO return latestChangedDtsTime; } -function updateOutputTimestamps(state: SolutionBuilderState, proj: ParsedCommandLine, resolvedPath: ResolvedConfigFilePath) { +function updateOutputTimestamps(state: SolutionBuilderState, proj: ParsedCommandLine, resolvedPath: ResolvedConfigFilePath) { if (state.options.dry) { return reportStatus(state, Diagnostics.A_non_dry_build_would_update_timestamps_for_output_of_project_0, proj.options.configFilePath!); } @@ -2048,8 +2048,8 @@ function updateOutputTimestamps(state: SolutionBuilderState, proj: ParsedCommand }); } -function queueReferencingProjects( - state: SolutionBuilderState, +function queueReferencingProjects( + state: SolutionBuilderState, project: ResolvedConfigFileName, projectPath: ResolvedConfigFilePath, projectIndex: number, @@ -2119,7 +2119,7 @@ function queueReferencingProjects( } } -function build(state: SolutionBuilderState, project?: string, cancellationToken?: CancellationToken, writeFile?: WriteFileCallback, getCustomTransformers?: (project: string) => CustomTransformers, onlyReferences?: boolean): ExitStatus { +function build(state: SolutionBuilderState, project?: string, cancellationToken?: CancellationToken, writeFile?: WriteFileCallback, getCustomTransformers?: (project: string) => CustomTransformers, onlyReferences?: boolean): ExitStatus { performance.mark("SolutionBuilder::beforeBuild"); const result = buildWorker(state, project, cancellationToken, writeFile, getCustomTransformers, onlyReferences); performance.mark("SolutionBuilder::afterBuild"); @@ -2127,7 +2127,7 @@ function build(state: SolutionBuilderState, project?: string, cancellationToken? return result; } -function buildWorker(state: SolutionBuilderState, project: string | undefined, cancellationToken: CancellationToken | undefined, writeFile: WriteFileCallback | undefined, getCustomTransformers: ((project: string) => CustomTransformers) | undefined, onlyReferences: boolean | undefined): ExitStatus { +function buildWorker(state: SolutionBuilderState, project: string | undefined, cancellationToken: CancellationToken | undefined, writeFile: WriteFileCallback | undefined, getCustomTransformers: ((project: string) => CustomTransformers) | undefined, onlyReferences: boolean | undefined): ExitStatus { const buildOrder = getBuildOrderFor(state, project, onlyReferences); if (!buildOrder) return ExitStatus.InvalidProject_OutputsSkipped; @@ -2156,7 +2156,7 @@ function buildWorker(state: SolutionBuilderState, project: string | undefined, c : ExitStatus.DiagnosticsPresent_OutputsSkipped; } -function clean(state: SolutionBuilderState, project?: string, onlyReferences?: boolean): ExitStatus { +function clean(state: SolutionBuilderState, project?: string, onlyReferences?: boolean): ExitStatus { performance.mark("SolutionBuilder::beforeClean"); const result = cleanWorker(state, project, onlyReferences); performance.mark("SolutionBuilder::afterClean"); @@ -2164,7 +2164,7 @@ function clean(state: SolutionBuilderState, project?: string, onlyReferences?: b return result; } -function cleanWorker(state: SolutionBuilderState, project: string | undefined, onlyReferences: boolean | undefined) { +function cleanWorker(state: SolutionBuilderState, project: string | undefined, onlyReferences: boolean | undefined) { const buildOrder = getBuildOrderFor(state, project, onlyReferences); if (!buildOrder) return ExitStatus.InvalidProject_OutputsSkipped; @@ -2208,7 +2208,7 @@ function cleanWorker(state: SolutionBuilderState, project: string | undefined, o return ExitStatus.Success; } -function invalidateProject(state: SolutionBuilderState, resolved: ResolvedConfigFilePath, reloadLevel: ConfigFileProgramReloadLevel) { +function invalidateProject(state: SolutionBuilderState, resolved: ResolvedConfigFilePath, reloadLevel: ConfigFileProgramReloadLevel) { // If host implements getParsedCommandLine, we cant get list of files from parseConfigFileHost if (state.host.getParsedCommandLine && reloadLevel === ConfigFileProgramReloadLevel.Partial) { reloadLevel = ConfigFileProgramReloadLevel.Full; @@ -2223,13 +2223,13 @@ function invalidateProject(state: SolutionBuilderState, resolved: ResolvedConfig enableCache(state); } -function invalidateProjectAndScheduleBuilds(state: SolutionBuilderState, resolvedPath: ResolvedConfigFilePath, reloadLevel: ConfigFileProgramReloadLevel) { +function invalidateProjectAndScheduleBuilds(state: SolutionBuilderState, resolvedPath: ResolvedConfigFilePath, reloadLevel: ConfigFileProgramReloadLevel) { state.reportFileChangeDetected = true; invalidateProject(state, resolvedPath, reloadLevel); scheduleBuildInvalidatedProject(state, 250, /*changeDetected*/ true); } -function scheduleBuildInvalidatedProject(state: SolutionBuilderState, time: number, changeDetected: boolean) { +function scheduleBuildInvalidatedProject(state: SolutionBuilderState, time: number, changeDetected: boolean) { const { hostWithWatch } = state; if (!hostWithWatch.setTimeout || !hostWithWatch.clearTimeout) { return; @@ -2240,7 +2240,7 @@ function scheduleBuildInvalidatedProject(state: SolutionBuilderState, time: numb state.timerToBuildInvalidatedProject = hostWithWatch.setTimeout(buildNextInvalidatedProject, time, state, changeDetected); } -function buildNextInvalidatedProject(state: SolutionBuilderState, changeDetected: boolean) { +function buildNextInvalidatedProject(state: SolutionBuilderState, changeDetected: boolean) { performance.mark("SolutionBuilder::beforeBuild"); const buildOrder = buildNextInvalidatedProjectWorker(state, changeDetected); performance.mark("SolutionBuilder::afterBuild"); @@ -2248,7 +2248,7 @@ function buildNextInvalidatedProject(state: SolutionBuilderState, changeDetected if (buildOrder) reportErrorSummary(state, buildOrder); } -function buildNextInvalidatedProjectWorker(state: SolutionBuilderState, changeDetected: boolean) { +function buildNextInvalidatedProjectWorker(state: SolutionBuilderState, changeDetected: boolean) { state.timerToBuildInvalidatedProject = undefined; if (state.reportFileChangeDetected) { state.reportFileChangeDetected = false; @@ -2281,7 +2281,7 @@ function buildNextInvalidatedProjectWorker(state: SolutionBuilderState, changeDe return buildOrder; } -function watchConfigFile(state: SolutionBuilderState, resolved: ResolvedConfigFileName, resolvedPath: ResolvedConfigFilePath, parsed: ParsedCommandLine | undefined) { +function watchConfigFile(state: SolutionBuilderState, resolved: ResolvedConfigFileName, resolvedPath: ResolvedConfigFilePath, parsed: ParsedCommandLine | undefined) { if (!state.watch || state.allWatchedConfigFiles.has(resolvedPath)) return; state.allWatchedConfigFiles.set(resolvedPath, watchFile( state, @@ -2294,7 +2294,7 @@ function watchConfigFile(state: SolutionBuilderState, resolved: ResolvedConfigFi )); } -function watchExtendedConfigFiles(state: SolutionBuilderState, resolvedPath: ResolvedConfigFilePath, parsed: ParsedCommandLine | undefined) { +function watchExtendedConfigFiles(state: SolutionBuilderState, resolvedPath: ResolvedConfigFilePath, parsed: ParsedCommandLine | undefined) { updateSharedExtendedConfigFileWatcher( resolvedPath, parsed?.options, @@ -2312,7 +2312,7 @@ function watchExtendedConfigFiles(state: SolutionBuilderState, resolvedPath: Res ); } -function watchWildCardDirectories(state: SolutionBuilderState, resolved: ResolvedConfigFileName, resolvedPath: ResolvedConfigFilePath, parsed: ParsedCommandLine) { +function watchWildCardDirectories(state: SolutionBuilderState, resolved: ResolvedConfigFileName, resolvedPath: ResolvedConfigFilePath, parsed: ParsedCommandLine) { if (!state.watch) return; updateWatchingWildcardDirectories( getOrCreateValueMapFromConfigFileMap(state.allWatchedWildcardDirectories, resolvedPath), @@ -2343,7 +2343,7 @@ function watchWildCardDirectories(state: SolutionBuilderState, resolved: Resolve ); } -function watchInputFiles(state: SolutionBuilderState, resolved: ResolvedConfigFileName, resolvedPath: ResolvedConfigFilePath, parsed: ParsedCommandLine) { +function watchInputFiles(state: SolutionBuilderState, resolved: ResolvedConfigFileName, resolvedPath: ResolvedConfigFilePath, parsed: ParsedCommandLine) { if (!state.watch) return; mutateMap( getOrCreateValueMapFromConfigFileMap(state.allWatchedInputFiles, resolvedPath), @@ -2363,7 +2363,7 @@ function watchInputFiles(state: SolutionBuilderState, resolved: ResolvedConfigFi ); } -function watchPackageJsonFiles(state: SolutionBuilderState, resolved: ResolvedConfigFileName, resolvedPath: ResolvedConfigFilePath, parsed: ParsedCommandLine) { +function watchPackageJsonFiles(state: SolutionBuilderState, resolved: ResolvedConfigFileName, resolvedPath: ResolvedConfigFilePath, parsed: ParsedCommandLine) { if (!state.watch || !state.lastCachedPackageJsonLookups) return; mutateMap( getOrCreateValueMapFromConfigFileMap(state.allWatchedPackageJsonFiles, resolvedPath), @@ -2383,7 +2383,7 @@ function watchPackageJsonFiles(state: SolutionBuilderState, resolved: ResolvedCo ); } -function startWatching(state: SolutionBuilderState, buildOrder: AnyBuildOrder) { +function startWatching(state: SolutionBuilderState, buildOrder: AnyBuildOrder) { if (!state.watchAllProjectsPending) return; performance.mark("SolutionBuilder::beforeWatcherCreation"); state.watchAllProjectsPending = false; @@ -2408,7 +2408,7 @@ function startWatching(state: SolutionBuilderState, buildOrder: AnyBuildOrder) { performance.measure("SolutionBuilder::Watcher creation", "SolutionBuilder::beforeWatcherCreation", "SolutionBuilder::afterWatcherCreation"); } -function stopWatching(state: SolutionBuilderState) { +function stopWatching(state: SolutionBuilderState) { clearMap(state.allWatchedConfigFiles, closeFileWatcher); clearMap(state.allWatchedExtendedConfigFiles, closeFileWatcherOf); clearMap(state.allWatchedWildcardDirectories, watchedWildcardDirectories => clearMap(watchedWildcardDirectories, closeFileWatcherOf)); @@ -2444,23 +2444,23 @@ function createSolutionBuilderWorker(watch: boolean, h }; } -function relName(state: SolutionBuilderState, path: string): string { +function relName(state: SolutionBuilderState, path: string): string { return convertToRelativePath(path, state.compilerHost.getCurrentDirectory(), state.compilerHost.getCanonicalFileName); } -function reportStatus(state: SolutionBuilderState, message: DiagnosticMessage, ...args: string[]) { +function reportStatus(state: SolutionBuilderState, message: DiagnosticMessage, ...args: string[]) { state.host.reportSolutionBuilderStatus(createCompilerDiagnostic(message, ...args)); } -function reportWatchStatus(state: SolutionBuilderState, message: DiagnosticMessage, ...args: (string | number | undefined)[]) { +function reportWatchStatus(state: SolutionBuilderState, message: DiagnosticMessage, ...args: (string | number | undefined)[]) { state.hostWithWatch.onWatchStatusChange?.(createCompilerDiagnostic(message, ...args), state.host.getNewLine(), state.baseCompilerOptions); } -function reportErrors({ host }: SolutionBuilderState, errors: readonly Diagnostic[]) { +function reportErrors({ host }: SolutionBuilderState, errors: readonly Diagnostic[]) { errors.forEach(err => host.reportDiagnostic(err)); } -function reportAndStoreErrors(state: SolutionBuilderState, proj: ResolvedConfigFilePath, errors: readonly Diagnostic[]) { +function reportAndStoreErrors(state: SolutionBuilderState, proj: ResolvedConfigFilePath, errors: readonly Diagnostic[]) { reportErrors(state, errors); state.projectErrorsReported.set(proj, true); if (errors.length) { @@ -2468,11 +2468,11 @@ function reportAndStoreErrors(state: SolutionBuilderState, proj: ResolvedConfigF } } -function reportParseConfigFileDiagnostic(state: SolutionBuilderState, proj: ResolvedConfigFilePath) { +function reportParseConfigFileDiagnostic(state: SolutionBuilderState, proj: ResolvedConfigFilePath) { reportAndStoreErrors(state, proj, [state.configFileCache.get(proj) as Diagnostic]); } -function reportErrorSummary(state: SolutionBuilderState, buildOrder: AnyBuildOrder) { +function reportErrorSummary(state: SolutionBuilderState, buildOrder: AnyBuildOrder) { if (!state.needsSummary) return; state.needsSummary = false; const canReportSummary = state.watch || !!state.host.reportErrorSummary; @@ -2508,13 +2508,13 @@ function reportErrorSummary(state: SolutionBuilderState, buildOrder: AnyBuildOrd /** * Report the build ordering inferred from the current project graph if we're in verbose mode */ -function reportBuildQueue(state: SolutionBuilderState, buildQueue: readonly ResolvedConfigFileName[]) { +function reportBuildQueue(state: SolutionBuilderState, buildQueue: readonly ResolvedConfigFileName[]) { if (state.options.verbose) { reportStatus(state, Diagnostics.Projects_in_this_build_Colon_0, buildQueue.map(s => "\r\n * " + relName(state, s)).join("")); } } -function reportUpToDateStatus(state: SolutionBuilderState, configFileName: string, status: UpToDateStatus) { +function reportUpToDateStatus(state: SolutionBuilderState, configFileName: string, status: UpToDateStatus) { switch (status.type) { case UpToDateStatusType.OutOfDateWithSelf: return reportStatus( @@ -2642,7 +2642,7 @@ function reportUpToDateStatus(state: SolutionBuilderState, configFileName: strin /** * Report the up-to-date status of a project if we're in verbose mode */ -function verboseReportProjectStatus(state: SolutionBuilderState, configFileName: string, status: UpToDateStatus) { +function verboseReportProjectStatus(state: SolutionBuilderState, configFileName: string, status: UpToDateStatus) { if (state.options.verbose) { reportUpToDateStatus(state, configFileName, status); } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 52e33ada64d4a..760c2a97170e7 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -8586,10 +8586,10 @@ export interface NodeFactory { updateJSDocReadonlyTag(node: JSDocReadonlyTag, tagName: Identifier | undefined, comment: string | NodeArray | undefined): JSDocReadonlyTag; createJSDocUnknownTag(tagName: Identifier, comment?: string | NodeArray): JSDocUnknownTag; updateJSDocUnknownTag(node: JSDocUnknownTag, tagName: Identifier, comment: string | NodeArray | undefined): JSDocUnknownTag; - createJSDocDeprecatedTag(tagName: Identifier, comment?: string | NodeArray): JSDocDeprecatedTag; - updateJSDocDeprecatedTag(node: JSDocDeprecatedTag, tagName: Identifier, comment?: string | NodeArray): JSDocDeprecatedTag; - createJSDocOverrideTag(tagName: Identifier, comment?: string | NodeArray): JSDocOverrideTag; - updateJSDocOverrideTag(node: JSDocOverrideTag, tagName: Identifier, comment?: string | NodeArray): JSDocOverrideTag; + createJSDocDeprecatedTag(tagName: Identifier | undefined, comment?: string | NodeArray): JSDocDeprecatedTag; + updateJSDocDeprecatedTag(node: JSDocDeprecatedTag, tagName: Identifier | undefined, comment?: string | NodeArray): JSDocDeprecatedTag; + createJSDocOverrideTag(tagName: Identifier | undefined, comment?: string | NodeArray): JSDocOverrideTag; + updateJSDocOverrideTag(node: JSDocOverrideTag, tagName: Identifier | undefined, comment?: string | NodeArray): JSDocOverrideTag; createJSDocThrowsTag(tagName: Identifier, typeExpression: JSDocTypeExpression | undefined, comment?: string | NodeArray): JSDocThrowsTag; updateJSDocThrowsTag(node: JSDocThrowsTag, tagName: Identifier | undefined, typeExpression: JSDocTypeExpression | undefined, comment?: string | NodeArray | undefined): JSDocThrowsTag; createJSDocSatisfiesTag(tagName: Identifier | undefined, typeExpression: JSDocTypeExpression, comment?: string | NodeArray): JSDocSatisfiesTag; @@ -8871,7 +8871,7 @@ export interface NodeFactory { * * @internal */ - copyPrologue(source: readonly Statement[], target: Push, ensureUseStrict?: boolean, visitor?: (node: Node) => VisitResult): number; + copyPrologue(source: readonly Statement[], target: Push, ensureUseStrict?: boolean, visitor?: (node: Node) => VisitResult): number; /** * Copies only the standard (string-expression) prologue-directives into the target statement-array. * @param source origin statements array @@ -8891,8 +8891,8 @@ export interface NodeFactory { * * @internal */ - copyCustomPrologue(source: readonly Statement[], target: Push, statementOffset: number, visitor?: (node: Node) => VisitResult, filter?: (node: Node) => boolean): number; - /** @internal */ copyCustomPrologue(source: readonly Statement[], target: Push, statementOffset: number | undefined, visitor?: (node: Node) => VisitResult, filter?: (node: Node) => boolean): number | undefined; + copyCustomPrologue(source: readonly Statement[], target: Push, statementOffset: number, visitor?: (node: Node) => VisitResult, filter?: (node: Statement) => boolean): number; + /** @internal */ copyCustomPrologue(source: readonly Statement[], target: Push, statementOffset: number | undefined, visitor?: (node: Node) => VisitResult, filter?: (node: Statement) => boolean): number | undefined; /** @internal */ ensureUseStrict(statements: NodeArray): NodeArray; /** @internal */ liftToBlock(nodes: readonly Node[]): Statement; /** @@ -9068,19 +9068,64 @@ export type Transformer = (node: T) => T; /** * A function that accepts and possibly transforms a node. */ -export type Visitor = (node: Node) => VisitResult; +export type Visitor = (node: TIn) => VisitResult; +/** + * A function that walks a node using the given visitor, lifting node arrays into single nodes, + * returning an node which satisfies the test. + * + * - If the input node is undefined, then the output is undefined. + * - If the visitor returns undefined, then the output is undefined. + * - If the output node is not undefined, then it will satisfy the test function. + * - In order to obtain a return type that is more specific than `Node`, a test + * function _must_ be provided, and that function must be a type predicate. + * + * For the canonical implementation of this type, @see {visitNode}. + */ export interface NodeVisitor { - (nodes: T, visitor: Visitor | undefined, test?: (node: Node) => boolean, lift?: (node: readonly Node[]) => T): T; - (nodes: T | undefined, visitor: Visitor | undefined, test?: (node: Node) => boolean, lift?: (node: readonly Node[]) => T): T | undefined; + ( + node: TIn, + visitor: Visitor, TVisited>, + test: (node: Node) => node is TOut, + lift?: (node: readonly Node[]) => Node, + ): TOut | (TIn & undefined) | (TVisited & undefined); + ( + node: TIn, + visitor: Visitor, TVisited>, + test?: (node: Node) => boolean, + lift?: (node: readonly Node[]) => Node, + ): Node | (TIn & undefined) | (TVisited & undefined); } +/** + * A function that walks a node array using the given visitor, returning an array whose contents satisfy the test. + * + * - If the input node array is undefined, the output is undefined. + * - If the visitor can return undefined, the node it visits in the array will be reused. + * - If the output node array is not undefined, then its contents will satisfy the test. + * - In order to obtain a return type that is more specific than `NodeArray`, a test + * function _must_ be provided, and that function must be a type predicate. + * + * For the canonical implementation of this type, @see {visitNodes}. + */ export interface NodesVisitor { - (nodes: NodeArray, visitor: Visitor | undefined, test?: (node: Node) => boolean, start?: number, count?: number): NodeArray; - (nodes: NodeArray | undefined, visitor: Visitor | undefined, test?: (node: Node) => boolean, start?: number, count?: number): NodeArray | undefined; -} - -export type VisitResult = T | readonly T[] | undefined; + | undefined, TOut extends Node>( + nodes: TInArray, + visitor: Visitor, + test: (node: Node) => node is TOut, + start?: number, + count?: number, + ): NodeArray | (TInArray & undefined); + | undefined>( + nodes: TInArray, + visitor: Visitor, + test?: (node: Node) => boolean, + start?: number, + count?: number, + ): NodeArray | (TInArray & undefined); +} + +export type VisitResult = T | readonly Node[]; export interface Printer { /** diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 7812c428eb6bf..dd6376699cb2f 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -848,7 +848,7 @@ export function getSourceFileOfNode(node: Node): SourceFile; /** @internal */ export function getSourceFileOfNode(node: Node | undefined): SourceFile | undefined; /** @internal */ -export function getSourceFileOfNode(node: Node): SourceFile { +export function getSourceFileOfNode(node: Node | undefined): SourceFile | undefined { while (node && node.kind !== SyntaxKind.SourceFile) { node = node.parent; } @@ -1528,9 +1528,8 @@ export function isBlockScope(node: Node, parentNode: Node | undefined): boolean } /** @internal */ -export function isDeclarationWithTypeParameters(node: Node): node is DeclarationWithTypeParameters; -/** @internal */ -export function isDeclarationWithTypeParameters(node: DeclarationWithTypeParameters): node is DeclarationWithTypeParameters { +export function isDeclarationWithTypeParameters(node: Node): node is DeclarationWithTypeParameters { + Debug.type(node); switch (node.kind) { case SyntaxKind.JSDocCallbackTag: case SyntaxKind.JSDocTypedefTag: @@ -1543,9 +1542,8 @@ export function isDeclarationWithTypeParameters(node: DeclarationWithTypeParamet } /** @internal */ -export function isDeclarationWithTypeParameterChildren(node: Node): node is DeclarationWithTypeParameterChildren; -/** @internal */ -export function isDeclarationWithTypeParameterChildren(node: DeclarationWithTypeParameterChildren): node is DeclarationWithTypeParameterChildren { +export function isDeclarationWithTypeParameterChildren(node: Node): node is DeclarationWithTypeParameterChildren { + Debug.type(node); switch (node.kind) { case SyntaxKind.CallSignature: case SyntaxKind.ConstructSignature: @@ -4533,8 +4531,20 @@ export function isPushOrUnshiftIdentifier(node: Identifier) { return node.escapedText === "push" || node.escapedText === "unshift"; } -/** @internal */ -export function isParameterDeclaration(node: VariableLikeDeclaration): boolean { +// TODO(jakebailey): this function should not be named this. While it does technically +// return true if the argument is a ParameterDeclaration, it also returns true for nodes +// that are children of ParameterDeclarations inside binding elements. +// Probably, this should be called `rootDeclarationIsParameter`. +/** + * This function returns true if the this node's root declaration is a parameter. + * For example, passing a `ParameterDeclaration` will return true, as will passing a + * binding element that is a child of a `ParameterDeclaration`. + * + * If you are looking to test that a `Node` is a `ParameterDeclaration`, use `isParameter`. + * + * @internal + */ +export function isParameterDeclaration(node: Declaration): boolean { const root = getRootDeclaration(node); return root.kind === SyntaxKind.Parameter; } @@ -6833,8 +6843,9 @@ export function getInitializedVariables(node: VariableDeclarationList) { return filter(node.declarations, isInitializedVariable); } -function isInitializedVariable(node: VariableDeclaration): node is InitializedVariableDeclaration { - return node.initializer !== undefined; +/** @internal */ +export function isInitializedVariable(node: Node): node is InitializedVariableDeclaration { + return isVariableDeclaration(node) && node.initializer !== undefined; } /** @internal */ @@ -7147,6 +7158,7 @@ export function isTypeNodeKind(kind: SyntaxKind): kind is TypeNodeSyntaxKind { || kind === SyntaxKind.VoidKeyword || kind === SyntaxKind.UndefinedKeyword || kind === SyntaxKind.NeverKeyword + || kind === SyntaxKind.IntrinsicKeyword || kind === SyntaxKind.ExpressionWithTypeArguments || kind === SyntaxKind.JSDocAllType || kind === SyntaxKind.JSDocUnknownType @@ -7276,11 +7288,11 @@ export function getLeftmostExpression(node: Expression, stopAtCallExpressions: b /** @internal */ export interface ObjectAllocator { - getNodeConstructor(): new (kind: SyntaxKind, pos?: number, end?: number) => Node; - getTokenConstructor(): new (kind: TKind, pos?: number, end?: number) => Token; - getIdentifierConstructor(): new (kind: SyntaxKind.Identifier, pos?: number, end?: number) => Identifier; - getPrivateIdentifierConstructor(): new (kind: SyntaxKind.PrivateIdentifier, pos?: number, end?: number) => PrivateIdentifier; - getSourceFileConstructor(): new (kind: SyntaxKind.SourceFile, pos?: number, end?: number) => SourceFile; + getNodeConstructor(): new (kind: SyntaxKind, pos: number, end: number) => Node; + getTokenConstructor(): new (kind: TKind, pos: number, end: number) => Token; + getIdentifierConstructor(): new (kind: SyntaxKind.Identifier, pos: number, end: number) => Identifier; + getPrivateIdentifierConstructor(): new (kind: SyntaxKind.PrivateIdentifier, pos: number, end: number) => PrivateIdentifier; + getSourceFileConstructor(): new (kind: SyntaxKind.SourceFile, pos: number, end: number) => SourceFile; getSymbolConstructor(): new (flags: SymbolFlags, name: __String) => Symbol; getTypeConstructor(): new (checker: TypeChecker, flags: TypeFlags) => Type; getSignatureConstructor(): new (checker: TypeChecker, flags: SignatureFlags) => Signature; @@ -8735,7 +8747,7 @@ export function isAnySupportedFileExtension(path: string): boolean { /** @internal */ export function tryGetExtensionFromPath(path: string): Extension | undefined { - return find(extensionsToRemove, e => fileExtensionIs(path, e)); + return find(extensionsToRemove, e => fileExtensionIs(path, e)); } /** @internal */ diff --git a/src/compiler/utilitiesPublic.ts b/src/compiler/utilitiesPublic.ts index 8a13b258be14a..da47384f21edd 100644 --- a/src/compiler/utilitiesPublic.ts +++ b/src/compiler/utilitiesPublic.ts @@ -3,6 +3,7 @@ import { AccessExpression, AccessorDeclaration, ArrayBindingElement, + ArrayBindingOrAssignmentElement, ArrayBindingOrAssignmentPattern, AssertionExpression, AssertionKey, @@ -98,6 +99,7 @@ import { isAmbientModule, isAnyImportOrReExport, isArrowFunction, + isAssignmentExpression, isBinaryExpression, isBindableStaticElementAccessExpression, isBindingElement, @@ -220,6 +222,7 @@ import { NonNullChain, normalizePath, NotEmittedStatement, + NullLiteral, ObjectBindingOrAssignmentElement, ObjectBindingOrAssignmentPattern, ObjectLiteralElement, @@ -545,7 +548,10 @@ export function isEmptyBindingPattern(node: BindingName): node is BindingPattern return false; } -export function isEmptyBindingElement(node: BindingElement): boolean { +// TODO(jakebailey): It is very weird that we have BindingElement and ArrayBindingElement; +// we should have ObjectBindingElement and ArrayBindingElement, which are both BindingElement, +// just like BindingPattern is a ObjectBindingPattern or a ArrayBindingPattern. +export function isEmptyBindingElement(node: BindingElement | ArrayBindingElement): boolean { if (isOmittedExpression(node)) { return true; } @@ -676,15 +682,19 @@ export function validateLocaleAndSetLanguage( export function getOriginalNode(node: Node): Node; export function getOriginalNode(node: Node, nodeTest: (node: Node) => node is T): T; export function getOriginalNode(node: Node | undefined): Node | undefined; -export function getOriginalNode(node: Node | undefined, nodeTest: (node: Node | undefined) => node is T): T | undefined; -export function getOriginalNode(node: Node | undefined, nodeTest?: (node: Node | undefined) => boolean): Node | undefined { +export function getOriginalNode(node: Node | undefined, nodeTest: (node: Node) => node is T): T | undefined; +export function getOriginalNode(node: Node | undefined, nodeTest?: (node: Node) => node is T): T | undefined { if (node) { while (node.original !== undefined) { node = node.original; } } - return !nodeTest || nodeTest(node) ? node : undefined; + if (!node || !nodeTest) { + return node as T | undefined; + } + + return nodeTest(node) ? node : undefined; } /** @@ -695,7 +705,7 @@ export function getOriginalNode(node: Node | undefined, nodeTest?: (node: Node | */ export function findAncestor(node: Node | undefined, callback: (element: Node) => element is T): T | undefined; export function findAncestor(node: Node | undefined, callback: (element: Node) => boolean | "quit"): Node | undefined; -export function findAncestor(node: Node, callback: (element: Node) => boolean | "quit"): Node | undefined { +export function findAncestor(node: Node | undefined, callback: (element: Node) => boolean | "quit"): Node | undefined { while (node) { const result = callback(node); if (result === "quit") { @@ -1784,6 +1794,14 @@ export function isDeclarationBindingElement(bindingElement: BindingOrAssignmentE return false; } +/** @internal */ +export function isBindingOrAssignmentElement(node: Node): node is BindingOrAssignmentElement { + return isVariableDeclaration(node) + || isParameter(node) + || isObjectBindingOrAssignmentElement(node) + || isArrayBindingOrAssignmentElement(node); +} + /** * Determines whether a node is a BindingOrAssignmentPattern * @@ -1836,6 +1854,22 @@ export function isArrayBindingOrAssignmentPattern(node: BindingOrAssignmentEleme return false; } +/** @internal */ +export function isArrayBindingOrAssignmentElement(node: Node): node is ArrayBindingOrAssignmentElement { + switch (node.kind) { + case SyntaxKind.BindingElement: + case SyntaxKind.OmittedExpression: // Elision + case SyntaxKind.SpreadElement: // AssignmentRestElement + case SyntaxKind.ArrayLiteralExpression: // ArrayAssignmentPattern + case SyntaxKind.ObjectLiteralExpression: // ObjectAssignmentPattern + case SyntaxKind.Identifier: // DestructuringAssignmentTarget + case SyntaxKind.PropertyAccessExpression: // DestructuringAssignmentTarget + case SyntaxKind.ElementAccessExpression: // DestructuringAssignmentTarget + return true; + } + return isAssignmentExpression(node, /*excludeCompoundAssignment*/ true); // AssignmentElement +} + /** @internal */ export function isPropertyAccessOrQualifiedNameOrImportTypeNode(node: Node): node is PropertyAccessExpression | QualifiedName | ImportTypeNode { const kind = node.kind; @@ -1952,6 +1986,23 @@ export function isUnaryExpressionWithWrite(expr: Node): expr is PrefixUnaryExpre } } +/** + * See isExpression; not for use in transforms. + * @internal + */ +export function isLiteralTypeLiteral(node: Node): node is NullLiteral | BooleanLiteral | LiteralExpression | PrefixUnaryExpression { + node = skipPartiallyEmittedExpressions(node); + switch (skipPartiallyEmittedExpressions(node).kind) { + case SyntaxKind.NullKeyword: + case SyntaxKind.TrueKeyword: + case SyntaxKind.FalseKeyword: + case SyntaxKind.PrefixUnaryExpression: + return true; + default: + return isLiteralExpression(node); + } +} + /** * Determines whether a node is an expression based only on its kind. * Use `isExpressionNode` if not in transforms. diff --git a/src/compiler/visitorPublic.ts b/src/compiler/visitorPublic.ts index 7bd2806644378..67e9dc5965954 100644 --- a/src/compiler/visitorPublic.ts +++ b/src/compiler/visitorPublic.ts @@ -53,6 +53,7 @@ import { isJsxOpeningElement, isJsxOpeningFragment, isJsxTagNameExpression, + isLiteralTypeLiteral, isMemberName, isModifier, isModifierLike, @@ -63,7 +64,7 @@ import { isNamedImportBindings, isObjectLiteralElementLike, isOptionalChain, - isParameterDeclaration, + isParameter, isPropertyAccessChain, isPropertyName, isQuestionDotToken, @@ -78,7 +79,6 @@ import { isTemplateLiteralTypeSpan, isTemplateMiddleOrTemplateTail, isTemplateSpan, - isToken, isTypeElement, isTypeNode, isTypeParameterDeclaration, @@ -105,35 +105,61 @@ import { /** * Visits a Node using the supplied visitor, possibly returning a new Node in its place. * + * - If the input node is undefined, then the output is undefined. + * - If the visitor returns undefined, then the output is undefined. + * - If the output node is not undefined, then it will satisfy the test function. + * - In order to obtain a return type that is more specific than `Node`, a test + * function _must_ be provided, and that function must be a type predicate. + * * @param node The Node to visit. * @param visitor The callback used to visit the Node. * @param test A callback to execute to verify the Node is valid. * @param lift An optional callback to execute to lift a NodeArray into a valid Node. */ -export function visitNode(node: T, visitor: Visitor | undefined, test?: (node: Node) => boolean, lift?: (node: readonly Node[]) => T): T; - +export function visitNode( + node: TIn, + visitor: Visitor, TVisited>, + test: (node: Node) => node is TOut, + lift?: (node: readonly Node[]) => Node, +): TOut | (TIn & undefined) | (TVisited & undefined); /** * Visits a Node using the supplied visitor, possibly returning a new Node in its place. * + * - If the input node is undefined, then the output is undefined. + * - If the visitor returns undefined, then the output is undefined. + * - If the output node is not undefined, then it will satisfy the test function. + * - In order to obtain a return type that is more specific than `Node`, a test + * function _must_ be provided, and that function must be a type predicate. + * * @param node The Node to visit. * @param visitor The callback used to visit the Node. * @param test A callback to execute to verify the Node is valid. * @param lift An optional callback to execute to lift a NodeArray into a valid Node. */ -export function visitNode(node: T | undefined, visitor: Visitor | undefined, test?: (node: Node) => boolean, lift?: (node: readonly Node[]) => T): T | undefined; - -export function visitNode(node: T | undefined, visitor: Visitor | undefined, test?: (node: Node) => boolean, lift?: (node: readonly Node[]) => T): T | undefined { - if (node === undefined || visitor === undefined) { +export function visitNode( + node: TIn, + visitor: Visitor, TVisited>, + test?: (node: Node) => boolean, + lift?: (node: readonly Node[]) => Node, +): Node | (TIn & undefined) | (TVisited & undefined); +export function visitNode( + node: Node, + visitor: Visitor, + test?: (node: Node) => boolean, + lift?: (node: readonly Node[]) => Node, +): Node | undefined { + if (node === undefined) { + // If the input type is undefined, then the output type can be undefined. return node; } const visited = visitor(node); - if (visited === node) { - return node; - } let visitedNode: Node | undefined; if (visited === undefined) { + // If the visited node is undefined, then the visitor must have returned undefined, + // so the visitor must have been declared as able to return undefined, so TOut must be + // potentially undefined. return undefined; } else if (isArray(visited)) { @@ -144,28 +170,17 @@ export function visitNode(node: T | undefined, visitor: Visitor } Debug.assertNode(visitedNode, test); - return visitedNode as T; + return visitedNode; } -/** @internal */ -export function visitNodes(nodes: NodeArray, visitor: Visitor, test: (node: Node) => node is U, start?: number, count?: number): NodeArray; - /** * Visits a NodeArray using the supplied visitor, possibly returning a new NodeArray in its place. * - * @param nodes The NodeArray to visit. - * @param visitor The callback used to visit a Node. - * @param test A node test to execute for each node. - * @param start An optional value indicating the starting offset at which to start visiting. - * @param count An optional value indicating the maximum number of nodes to visit. - */ -export function visitNodes(nodes: NodeArray, visitor: Visitor | undefined, test?: (node: Node) => boolean, start?: number, count?: number): NodeArray; - -/** @internal */ -export function visitNodes(nodes: NodeArray | undefined, visitor: Visitor, test: (node: Node) => node is U, start?: number, count?: number): NodeArray | undefined; - -/** - * Visits a NodeArray using the supplied visitor, possibly returning a new NodeArray in its place. + * - If the input node array is undefined, the output is undefined. + * - If the visitor can return undefined, the node it visits in the array will be reused. + * - If the output node array is not undefined, then its contents will satisfy the test. + * - In order to obtain a return type that is more specific than `NodeArray`, a test + * function _must_ be provided, and that function must be a type predicate. * * @param nodes The NodeArray to visit. * @param visitor The callback used to visit a Node. @@ -173,19 +188,44 @@ export function visitNodes(nodes: NodeArray | un * @param start An optional value indicating the starting offset at which to start visiting. * @param count An optional value indicating the maximum number of nodes to visit. */ -export function visitNodes(nodes: NodeArray | undefined, visitor: Visitor | undefined, test?: (node: Node) => boolean, start?: number, count?: number): NodeArray | undefined; - +export function visitNodes | undefined, TOut extends Node>( + nodes: TInArray, + visitor: Visitor, + test: (node: Node) => node is TOut, + start?: number, + count?: number, +): NodeArray | (TInArray & undefined); /** * Visits a NodeArray using the supplied visitor, possibly returning a new NodeArray in its place. * + * - If the input node array is undefined, the output is undefined. + * - If the visitor can return undefined, the node it visits in the array will be reused. + * - If the output node array is not undefined, then its contents will satisfy the test. + * - In order to obtain a return type that is more specific than `NodeArray`, a test + * function _must_ be provided, and that function must be a type predicate. + * * @param nodes The NodeArray to visit. * @param visitor The callback used to visit a Node. * @param test A node test to execute for each node. * @param start An optional value indicating the starting offset at which to start visiting. * @param count An optional value indicating the maximum number of nodes to visit. */ -export function visitNodes(nodes: NodeArray | undefined, visitor: Visitor | undefined, test?: (node: Node) => boolean, start?: number, count?: number): NodeArray | undefined { - if (nodes === undefined || visitor === undefined) { +export function visitNodes | undefined>( + nodes: TInArray, + visitor: Visitor, + test?: (node: Node) => boolean, + start?: number, + count?: number, +): NodeArray | (TInArray & undefined); +export function visitNodes( + nodes: NodeArray | undefined, + visitor: Visitor, + test?: (node: Node) => boolean, + start?: number, + count?: number, +): NodeArray | undefined { + if (nodes === undefined) { + // If the input type is undefined, then the output type can be undefined. return nodes; } @@ -214,26 +254,44 @@ export function visitNodes(nodes: NodeArray | undefined, visi } const updated = visitArrayWorker(nodes, visitor, test, start, count); - if (updated !== nodes as readonly T[]) { + if (updated !== nodes as readonly Node[]) { // TODO(rbuckton): Remove dependency on `ts.factory` in favor of a provided factory. const updatedArray = factory.createNodeArray(updated, hasTrailingComma); setTextRangePosEnd(updatedArray, pos, end); return updatedArray; } + // If we are here, updated === nodes. This means that it's still a NodeArray, + // and also that its contents passed the tests in visitArrayWorker, so has contents + // of type TOut. return nodes; } /** @internal */ -export function visitArray(nodes: T[] | undefined, visitor: Visitor, test: (node: Node) => node is U, start?: number, count?: number): U[] | undefined; -/** @internal */ -export function visitArray(nodes: readonly T[] | undefined, visitor: Visitor, test: (node: Node) => node is U, start?: number, count?: number): readonly U[] | undefined; +export function visitArray( + nodes: TInArray, + visitor: Visitor, + test: (node: Node) => node is TOut, + start?: number, + count?: number, +): readonly TOut[] | (TInArray & undefined); /** @internal */ -export function visitArray(nodes: T[] | undefined, visitor: Visitor, test: (node: Node) => node is T, start?: number, count?: number): T[] | undefined; -/** @internal */ -export function visitArray(nodes: readonly T[] | undefined, visitor: Visitor, test: (node: Node) => node is T, start?: number, count?: number): readonly T[] | undefined; -export function visitArray(nodes: readonly T[] | undefined, visitor: Visitor, test: (node: Node) => node is U, start?: number, count?: number) { +export function visitArray( + nodes: TInArray, + visitor: Visitor, + test?: (node: Node) => boolean, + start?: number, + count?: number, +): readonly Node[] | (TInArray & undefined); +export function visitArray( + nodes: readonly Node[] | undefined, + visitor: Visitor, + test?: (node: Node) => boolean, + start?: number, + count?: number, +): readonly Node[] | undefined { if (nodes === undefined) { + // If the input type is undefined, then the output type can be undefined. return nodes; } @@ -247,12 +305,31 @@ export function visitArray(nodes: readonly T[] | un count = length - start; } - return visitArrayWorker(nodes, visitor, test, start, count) as readonly U[]; + return visitArrayWorker(nodes, visitor, test, start, count); } -/** @internal */ -function visitArrayWorker(nodes: readonly T[], visitor: Visitor, test: ((node: Node) => boolean) | undefined, start: number, count: number): readonly T[] | undefined { - let updated: T[] | undefined; +function visitArrayWorker( + nodes: TInArray, + visitor: Visitor, + test: (node: Node) => node is TOut, + start: number, + count: number, +): readonly TOut[]; +function visitArrayWorker( + nodes: TInArray, + visitor: Visitor, + test: ((node: Node) => boolean) | undefined, + start: number, + count: number, +): readonly Node[]; +function visitArrayWorker( + nodes: readonly Node[], + visitor: Visitor | undefined, + test: ((node: Node) => boolean) | undefined, + start: number, + count: number, +): readonly Node[] { + let updated: Node[] | undefined; const length = nodes.length; if (start > 0 || count < length) { @@ -262,29 +339,37 @@ function visitArrayWorker(nodes: readonly T[], visitor: Visitor, // Visit each original node. for (let i = 0; i < count; i++) { - const node: T = nodes[i + start]; - const visited = node !== undefined ? visitor(node) : undefined; + const node = nodes[i + start]; + const visited = node !== undefined ? (visitor ? visitor(node) : node) : undefined; if (updated !== undefined || visited === undefined || visited !== node) { if (updated === undefined) { // Ensure we have a copy of `nodes`, up to the current index. updated = nodes.slice(0, i); + Debug.assertEachNode(updated, test); } if (visited) { if (isArray(visited)) { for (const visitedNode of visited) { - void Debug.assertNode(visitedNode, test); - updated.push(visitedNode as T); + Debug.assertNode(visitedNode, test); + updated.push(visitedNode); } } else { - void Debug.assertNode(visited, test); - updated.push(visited as T); + Debug.assertNode(visited, test); + updated.push(visited); } } } } - return updated ?? nodes; + if (updated) { + // If we have an updated array, then all items will have been tested. + return updated; + } + + // If we are going to return the original array, ensure it passes the test. + Debug.assertEachNode(nodes, test); + return nodes; } /** @@ -309,7 +394,7 @@ export function visitParameterList(nodes: NodeArray | unde context.startLexicalEnvironment(); if (nodes) { context.setLexicalEnvironmentFlags(LexicalEnvironmentFlags.InParameters, true); - updated = nodesVisitor(nodes, visitor, isParameterDeclaration); + updated = nodesVisitor(nodes, visitor, isParameter); // As of ES2015, any runtime execution of that occurs in for a parameter (such as evaluating an // initializer or a binding pattern), occurs in its own lexical scope. As a result, any expression @@ -465,6 +550,7 @@ export function visitIterationBody(body: Statement, visitor: Visitor, context: T export function visitIterationBody(body: Statement, visitor: Visitor, context: TransformationContext, nodeVisitor: NodeVisitor = visitNode): Statement { context.startBlockScope(); const updated = nodeVisitor(body, visitor, isStatement, context.factory.liftToBlock); + Debug.assert(updated); const declarations = context.endBlockScope(); if (some(declarations)) { if (isBlock(updated)) { @@ -525,20 +611,20 @@ type VisitEachChildTable = { [TNode in HasChildren as TNode["kind"]]: VisitEachC const visitEachChildTable: VisitEachChildTable = { [SyntaxKind.QualifiedName]: function visitEachChildOfQualifiedName(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { return context.factory.updateQualifiedName(node, - nodeVisitor(node.left, visitor, isEntityName), - nodeVisitor(node.right, visitor, isIdentifier)); + Debug.checkDefined(nodeVisitor(node.left, visitor, isEntityName)), + Debug.checkDefined(nodeVisitor(node.right, visitor, isIdentifier))); }, [SyntaxKind.ComputedPropertyName]: function visitEachChildOfComputedPropertyName(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { return context.factory.updateComputedPropertyName(node, - nodeVisitor(node.expression, visitor, isExpression)); + Debug.checkDefined(nodeVisitor(node.expression, visitor, isExpression))); }, // Signature elements [SyntaxKind.TypeParameter]: function visitEachChildOfTypeParameterDeclaration(node, visitor, context, nodesVisitor, nodeVisitor, _tokenVisitor) { return context.factory.updateTypeParameterDeclaration(node, nodesVisitor(node.modifiers, visitor, isModifier), - nodeVisitor(node.name, visitor, isIdentifier), + Debug.checkDefined(nodeVisitor(node.name, visitor, isIdentifier)), nodeVisitor(node.constraint, visitor, isTypeNode), nodeVisitor(node.default, visitor, isTypeNode)); }, @@ -546,33 +632,33 @@ const visitEachChildTable: VisitEachChildTable = { [SyntaxKind.Parameter]: function visitEachChildOfParameterDeclaration(node, visitor, context, nodesVisitor, nodeVisitor, tokenVisitor) { return context.factory.updateParameterDeclaration(node, nodesVisitor(node.modifiers, visitor, isModifierLike), - nodeVisitor(node.dotDotDotToken, tokenVisitor, isDotDotDotToken), - nodeVisitor(node.name, visitor, isBindingName), - nodeVisitor(node.questionToken, tokenVisitor, isQuestionToken), + tokenVisitor ? nodeVisitor(node.dotDotDotToken, tokenVisitor, isDotDotDotToken) : node.dotDotDotToken, + Debug.checkDefined(nodeVisitor(node.name, visitor, isBindingName)), + tokenVisitor ? nodeVisitor(node.questionToken, tokenVisitor, isQuestionToken) : node.questionToken, nodeVisitor(node.type, visitor, isTypeNode), nodeVisitor(node.initializer, visitor, isExpression)); }, [SyntaxKind.Decorator]: function visitEachChildOfDecorator(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { return context.factory.updateDecorator(node, - nodeVisitor(node.expression, visitor, isExpression)); + Debug.checkDefined(nodeVisitor(node.expression, visitor, isExpression))); }, // Type elements [SyntaxKind.PropertySignature]: function visitEachChildOfPropertySignature(node, visitor, context, nodesVisitor, nodeVisitor, tokenVisitor) { return context.factory.updatePropertySignature(node, nodesVisitor(node.modifiers, visitor, isModifier), - nodeVisitor(node.name, visitor, isPropertyName), - nodeVisitor(node.questionToken, tokenVisitor, isToken), + Debug.checkDefined(nodeVisitor(node.name, visitor, isPropertyName)), + tokenVisitor ? nodeVisitor(node.questionToken, tokenVisitor, isQuestionToken) : node.questionToken, nodeVisitor(node.type, visitor, isTypeNode)); }, [SyntaxKind.PropertyDeclaration]: function visitEachChildOfPropertyDeclaration(node, visitor, context, nodesVisitor, nodeVisitor, tokenVisitor) { return context.factory.updatePropertyDeclaration(node, nodesVisitor(node.modifiers, visitor, isModifierLike), - nodeVisitor(node.name, visitor, isPropertyName), + Debug.checkDefined(nodeVisitor(node.name, visitor, isPropertyName)), // QuestionToken and ExclamationToken are mutually exclusive in PropertyDeclaration - nodeVisitor(node.questionToken ?? node.exclamationToken, tokenVisitor, isQuestionOrExclamationToken), + tokenVisitor ? nodeVisitor(node.questionToken ?? node.exclamationToken, tokenVisitor, isQuestionOrExclamationToken) : node.questionToken ?? node.exclamationToken, nodeVisitor(node.type, visitor, isTypeNode), nodeVisitor(node.initializer, visitor, isExpression)); }, @@ -580,19 +666,19 @@ const visitEachChildTable: VisitEachChildTable = { [SyntaxKind.MethodSignature]: function visitEachChildOfMethodSignature(node, visitor, context, nodesVisitor, nodeVisitor, tokenVisitor) { return context.factory.updateMethodSignature(node, nodesVisitor(node.modifiers, visitor, isModifier), - nodeVisitor(node.name, visitor, isPropertyName), - nodeVisitor(node.questionToken, tokenVisitor, isQuestionToken), + Debug.checkDefined(nodeVisitor(node.name, visitor, isPropertyName)), + tokenVisitor ? nodeVisitor(node.questionToken, tokenVisitor, isQuestionToken) : node.questionToken, nodesVisitor(node.typeParameters, visitor, isTypeParameterDeclaration), - nodesVisitor(node.parameters, visitor, isParameterDeclaration), + nodesVisitor(node.parameters, visitor, isParameter), nodeVisitor(node.type, visitor, isTypeNode)); }, [SyntaxKind.MethodDeclaration]: function visitEachChildOfMethodDeclaration(node, visitor, context, nodesVisitor, nodeVisitor, tokenVisitor) { return context.factory.updateMethodDeclaration(node, nodesVisitor(node.modifiers, visitor, isModifierLike), - nodeVisitor(node.asteriskToken, tokenVisitor, isAsteriskToken), - nodeVisitor(node.name, visitor, isPropertyName), - nodeVisitor(node.questionToken, tokenVisitor, isQuestionToken), + tokenVisitor ? nodeVisitor(node.asteriskToken, tokenVisitor, isAsteriskToken) : node.asteriskToken, + Debug.checkDefined(nodeVisitor(node.name, visitor, isPropertyName)), + tokenVisitor ? nodeVisitor(node.questionToken, tokenVisitor, isQuestionToken) : node.questionToken, nodesVisitor(node.typeParameters, visitor, isTypeParameterDeclaration), visitParameterList(node.parameters, visitor, context, nodesVisitor), nodeVisitor(node.type, visitor, isTypeNode), @@ -609,7 +695,7 @@ const visitEachChildTable: VisitEachChildTable = { [SyntaxKind.GetAccessor]: function visitEachChildOfGetAccessorDeclaration(node, visitor, context, nodesVisitor, nodeVisitor, _tokenVisitor) { return context.factory.updateGetAccessorDeclaration(node, nodesVisitor(node.modifiers, visitor, isModifierLike), - nodeVisitor(node.name, visitor, isPropertyName), + Debug.checkDefined(nodeVisitor(node.name, visitor, isPropertyName)), visitParameterList(node.parameters, visitor, context, nodesVisitor), nodeVisitor(node.type, visitor, isTypeNode), visitFunctionBody(node.body!, visitor, context, nodeVisitor)); @@ -618,7 +704,7 @@ const visitEachChildTable: VisitEachChildTable = { [SyntaxKind.SetAccessor]: function visitEachChildOfSetAccessorDeclaration(node, visitor, context, nodesVisitor, nodeVisitor, _tokenVisitor) { return context.factory.updateSetAccessorDeclaration(node, nodesVisitor(node.modifiers, visitor, isModifierLike), - nodeVisitor(node.name, visitor, isPropertyName), + Debug.checkDefined(nodeVisitor(node.name, visitor, isPropertyName)), visitParameterList(node.parameters, visitor, context, nodesVisitor), visitFunctionBody(node.body!, visitor, context, nodeVisitor)); }, @@ -633,56 +719,56 @@ const visitEachChildTable: VisitEachChildTable = { [SyntaxKind.CallSignature]: function visitEachChildOfCallSignatureDeclaration(node, visitor, context, nodesVisitor, nodeVisitor, _tokenVisitor) { return context.factory.updateCallSignature(node, nodesVisitor(node.typeParameters, visitor, isTypeParameterDeclaration), - nodesVisitor(node.parameters, visitor, isParameterDeclaration), + nodesVisitor(node.parameters, visitor, isParameter), nodeVisitor(node.type, visitor, isTypeNode)); }, [SyntaxKind.ConstructSignature]: function visitEachChildOfConstructSignatureDeclaration(node, visitor, context, nodesVisitor, nodeVisitor, _tokenVisitor) { return context.factory.updateConstructSignature(node, nodesVisitor(node.typeParameters, visitor, isTypeParameterDeclaration), - nodesVisitor(node.parameters, visitor, isParameterDeclaration), + nodesVisitor(node.parameters, visitor, isParameter), nodeVisitor(node.type, visitor, isTypeNode)); }, [SyntaxKind.IndexSignature]: function visitEachChildOfIndexSignatureDeclaration(node, visitor, context, nodesVisitor, nodeVisitor, _tokenVisitor) { return context.factory.updateIndexSignature(node, nodesVisitor(node.modifiers, visitor, isModifier), - nodesVisitor(node.parameters, visitor, isParameterDeclaration), - nodeVisitor(node.type, visitor, isTypeNode)); + nodesVisitor(node.parameters, visitor, isParameter), + Debug.checkDefined(nodeVisitor(node.type, visitor, isTypeNode))); }, // Types [SyntaxKind.TypePredicate]: function visitEachChildOfTypePredicateNode(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { return context.factory.updateTypePredicateNode(node, nodeVisitor(node.assertsModifier, visitor, isAssertsKeyword), - nodeVisitor(node.parameterName, visitor, isIdentifierOrThisTypeNode), + Debug.checkDefined(nodeVisitor(node.parameterName, visitor, isIdentifierOrThisTypeNode)), nodeVisitor(node.type, visitor, isTypeNode)); }, [SyntaxKind.TypeReference]: function visitEachChildOfTypeReferenceNode(node, visitor, context, nodesVisitor, nodeVisitor, _tokenVisitor) { return context.factory.updateTypeReferenceNode(node, - nodeVisitor(node.typeName, visitor, isEntityName), + Debug.checkDefined(nodeVisitor(node.typeName, visitor, isEntityName)), nodesVisitor(node.typeArguments, visitor, isTypeNode)); }, [SyntaxKind.FunctionType]: function visitEachChildOfFunctionTypeNode(node, visitor, context, nodesVisitor, nodeVisitor, _tokenVisitor) { return context.factory.updateFunctionTypeNode(node, nodesVisitor(node.typeParameters, visitor, isTypeParameterDeclaration), - nodesVisitor(node.parameters, visitor, isParameterDeclaration), - nodeVisitor(node.type, visitor, isTypeNode)); + nodesVisitor(node.parameters, visitor, isParameter), + Debug.checkDefined(nodeVisitor(node.type, visitor, isTypeNode))); }, [SyntaxKind.ConstructorType]: function visitEachChildOfConstructorTypeNode(node, visitor, context, nodesVisitor, nodeVisitor, _tokenVisitor) { return context.factory.updateConstructorTypeNode(node, nodesVisitor(node.modifiers, visitor, isModifier), nodesVisitor(node.typeParameters, visitor, isTypeParameterDeclaration), - nodesVisitor(node.parameters, visitor, isParameterDeclaration), - nodeVisitor(node.type, visitor, isTypeNode)); + nodesVisitor(node.parameters, visitor, isParameter), + Debug.checkDefined(nodeVisitor(node.type, visitor, isTypeNode))); }, [SyntaxKind.TypeQuery]: function visitEachChildOfTypeQueryNode(node, visitor, context, nodesVisitor, nodeVisitor, _tokenVisitor) { return context.factory.updateTypeQueryNode(node, - nodeVisitor(node.exprName, visitor, isEntityName), + Debug.checkDefined(nodeVisitor(node.exprName, visitor, isEntityName)), nodesVisitor(node.typeArguments, visitor, isTypeNode)); }, @@ -693,7 +779,7 @@ const visitEachChildTable: VisitEachChildTable = { [SyntaxKind.ArrayType]: function visitEachChildOfArrayTypeNode(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { return context.factory.updateArrayTypeNode(node, - nodeVisitor(node.elementType, visitor, isTypeNode)); + Debug.checkDefined(nodeVisitor(node.elementType, visitor, isTypeNode))); }, [SyntaxKind.TupleType]: function visitEachChildOfTupleTypeNode(node, visitor, context, nodesVisitor, _nodeVisitor, _tokenVisitor) { @@ -703,12 +789,12 @@ const visitEachChildTable: VisitEachChildTable = { [SyntaxKind.OptionalType]: function visitEachChildOfOptionalTypeNode(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { return context.factory.updateOptionalTypeNode(node, - nodeVisitor(node.type, visitor, isTypeNode)); + Debug.checkDefined(nodeVisitor(node.type, visitor, isTypeNode))); }, [SyntaxKind.RestType]: function visitEachChildOfRestTypeNode(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { return context.factory.updateRestTypeNode(node, - nodeVisitor(node.type, visitor, isTypeNode)); + Debug.checkDefined(nodeVisitor(node.type, visitor, isTypeNode))); }, [SyntaxKind.UnionType]: function visitEachChildOfUnionTypeNode(node, visitor, context, nodesVisitor, _nodeVisitor, _tokenVisitor) { @@ -723,20 +809,20 @@ const visitEachChildTable: VisitEachChildTable = { [SyntaxKind.ConditionalType]: function visitEachChildOfConditionalTypeNode(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { return context.factory.updateConditionalTypeNode(node, - nodeVisitor(node.checkType, visitor, isTypeNode), - nodeVisitor(node.extendsType, visitor, isTypeNode), - nodeVisitor(node.trueType, visitor, isTypeNode), - nodeVisitor(node.falseType, visitor, isTypeNode)); + Debug.checkDefined(nodeVisitor(node.checkType, visitor, isTypeNode)), + Debug.checkDefined(nodeVisitor(node.extendsType, visitor, isTypeNode)), + Debug.checkDefined(nodeVisitor(node.trueType, visitor, isTypeNode)), + Debug.checkDefined(nodeVisitor(node.falseType, visitor, isTypeNode))); }, [SyntaxKind.InferType]: function visitEachChildOfInferTypeNode(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { return context.factory.updateInferTypeNode(node, - nodeVisitor(node.typeParameter, visitor, isTypeParameterDeclaration)); + Debug.checkDefined(nodeVisitor(node.typeParameter, visitor, isTypeParameterDeclaration))); }, [SyntaxKind.ImportType]: function visitEachChildOfImportTypeNode(node, visitor, context, nodesVisitor, nodeVisitor, _tokenVisitor) { return context.factory.updateImportTypeNode(node, - nodeVisitor(node.argument, visitor, isTypeNode), + Debug.checkDefined(nodeVisitor(node.argument, visitor, isTypeNode)), nodeVisitor(node.assertions, visitor, isImportTypeAssertionContainer), nodeVisitor(node.qualifier, visitor, isEntityName), nodesVisitor(node.typeArguments, visitor, isTypeNode), @@ -746,61 +832,61 @@ const visitEachChildTable: VisitEachChildTable = { [SyntaxKind.ImportTypeAssertionContainer]: function visitEachChildOfImportTypeAssertionContainer(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { return context.factory.updateImportTypeAssertionContainer(node, - nodeVisitor(node.assertClause, visitor, isAssertClause), + Debug.checkDefined(nodeVisitor(node.assertClause, visitor, isAssertClause)), node.multiLine ); }, [SyntaxKind.NamedTupleMember]: function visitEachChildOfNamedTupleMember(node, visitor, context, _nodesVisitor, nodeVisitor, tokenVisitor) { return context.factory.updateNamedTupleMember(node, - nodeVisitor(node.dotDotDotToken, tokenVisitor, isDotDotDotToken), - nodeVisitor(node.name, visitor, isIdentifier), - nodeVisitor(node.questionToken, tokenVisitor, isQuestionToken), - nodeVisitor(node.type, visitor, isTypeNode), + tokenVisitor ? nodeVisitor(node.dotDotDotToken, tokenVisitor, isDotDotDotToken) : node.dotDotDotToken, + Debug.checkDefined(nodeVisitor(node.name, visitor, isIdentifier)), + tokenVisitor ? nodeVisitor(node.questionToken, tokenVisitor, isQuestionToken) : node.questionToken, + Debug.checkDefined(nodeVisitor(node.type, visitor, isTypeNode)), ); }, [SyntaxKind.ParenthesizedType]: function visitEachChildOfParenthesizedType(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { return context.factory.updateParenthesizedType(node, - nodeVisitor(node.type, visitor, isTypeNode)); + Debug.checkDefined(nodeVisitor(node.type, visitor, isTypeNode))); }, [SyntaxKind.TypeOperator]: function visitEachChildOfTypeOperatorNode(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { return context.factory.updateTypeOperatorNode(node, - nodeVisitor(node.type, visitor, isTypeNode)); + Debug.checkDefined(nodeVisitor(node.type, visitor, isTypeNode))); }, [SyntaxKind.IndexedAccessType]: function visitEachChildOfIndexedAccessType(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { return context.factory.updateIndexedAccessTypeNode(node, - nodeVisitor(node.objectType, visitor, isTypeNode), - nodeVisitor(node.indexType, visitor, isTypeNode)); + Debug.checkDefined(nodeVisitor(node.objectType, visitor, isTypeNode)), + Debug.checkDefined(nodeVisitor(node.indexType, visitor, isTypeNode))); }, [SyntaxKind.MappedType]: function visitEachChildOfMappedType(node, visitor, context, nodesVisitor, nodeVisitor, tokenVisitor) { return context.factory.updateMappedTypeNode(node, - nodeVisitor(node.readonlyToken, tokenVisitor, isReadonlyKeywordOrPlusOrMinusToken), - nodeVisitor(node.typeParameter, visitor, isTypeParameterDeclaration), + tokenVisitor ? nodeVisitor(node.readonlyToken, tokenVisitor, isReadonlyKeywordOrPlusOrMinusToken) : node.readonlyToken, + Debug.checkDefined(nodeVisitor(node.typeParameter, visitor, isTypeParameterDeclaration)), nodeVisitor(node.nameType, visitor, isTypeNode), - nodeVisitor(node.questionToken, tokenVisitor, isQuestionOrPlusOrMinusToken), + tokenVisitor ? nodeVisitor(node.questionToken, tokenVisitor, isQuestionOrPlusOrMinusToken) : node.questionToken, nodeVisitor(node.type, visitor, isTypeNode), nodesVisitor(node.members, visitor, isTypeElement)); }, [SyntaxKind.LiteralType]: function visitEachChildOfLiteralTypeNode(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { return context.factory.updateLiteralTypeNode(node, - nodeVisitor(node.literal, visitor, isExpression)); + Debug.checkDefined(nodeVisitor(node.literal, visitor, isLiteralTypeLiteral))); }, [SyntaxKind.TemplateLiteralType]: function visitEachChildOfTemplateLiteralType(node, visitor, context, nodesVisitor, nodeVisitor, _tokenVisitor) { return context.factory.updateTemplateLiteralType(node, - nodeVisitor(node.head, visitor, isTemplateHead), + Debug.checkDefined(nodeVisitor(node.head, visitor, isTemplateHead)), nodesVisitor(node.templateSpans, visitor, isTemplateLiteralTypeSpan)); }, [SyntaxKind.TemplateLiteralTypeSpan]: function visitEachChildOfTemplateLiteralTypeSpan(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { return context.factory.updateTemplateLiteralTypeSpan(node, - nodeVisitor(node.type, visitor, isTypeNode), - nodeVisitor(node.literal, visitor, isTemplateMiddleOrTemplateTail)); + Debug.checkDefined(nodeVisitor(node.type, visitor, isTypeNode)), + Debug.checkDefined(nodeVisitor(node.literal, visitor, isTemplateMiddleOrTemplateTail))); }, // Binding patterns @@ -816,9 +902,9 @@ const visitEachChildTable: VisitEachChildTable = { [SyntaxKind.BindingElement]: function visitEachChildOfBindingElement(node, visitor, context, _nodesVisitor, nodeVisitor, tokenVisitor) { return context.factory.updateBindingElement(node, - nodeVisitor(node.dotDotDotToken, tokenVisitor, isDotDotDotToken), + tokenVisitor ? nodeVisitor(node.dotDotDotToken, tokenVisitor, isDotDotDotToken) : node.dotDotDotToken, nodeVisitor(node.propertyName, visitor, isPropertyName), - nodeVisitor(node.name, visitor, isBindingName), + Debug.checkDefined(nodeVisitor(node.name, visitor, isBindingName)), nodeVisitor(node.initializer, visitor, isExpression)); }, @@ -836,67 +922,67 @@ const visitEachChildTable: VisitEachChildTable = { [SyntaxKind.PropertyAccessExpression]: function visitEachChildOfPropertyAccessExpression(node, visitor, context, _nodesVisitor, nodeVisitor, tokenVisitor) { return isPropertyAccessChain(node) ? context.factory.updatePropertyAccessChain(node, - nodeVisitor(node.expression, visitor, isExpression), - nodeVisitor(node.questionDotToken, tokenVisitor, isQuestionDotToken), - nodeVisitor(node.name, visitor, isMemberName)) : + Debug.checkDefined(nodeVisitor(node.expression, visitor, isExpression)), + tokenVisitor ? nodeVisitor(node.questionDotToken, tokenVisitor, isQuestionDotToken) : node.questionDotToken, + Debug.checkDefined(nodeVisitor(node.name, visitor, isMemberName))) : context.factory.updatePropertyAccessExpression(node, - nodeVisitor(node.expression, visitor, isExpression), - nodeVisitor(node.name, visitor, isMemberName)); + Debug.checkDefined(nodeVisitor(node.expression, visitor, isExpression)), + Debug.checkDefined(nodeVisitor(node.name, visitor, isMemberName))); }, [SyntaxKind.ElementAccessExpression]: function visitEachChildOfElementAccessExpression(node, visitor, context, _nodesVisitor, nodeVisitor, tokenVisitor) { return isElementAccessChain(node) ? context.factory.updateElementAccessChain(node, - nodeVisitor(node.expression, visitor, isExpression), - nodeVisitor(node.questionDotToken, tokenVisitor, isQuestionDotToken), - nodeVisitor(node.argumentExpression, visitor, isExpression)) : + Debug.checkDefined(nodeVisitor(node.expression, visitor, isExpression)), + tokenVisitor ? nodeVisitor(node.questionDotToken, tokenVisitor, isQuestionDotToken) : node.questionDotToken, + Debug.checkDefined(nodeVisitor(node.argumentExpression, visitor, isExpression))) : context.factory.updateElementAccessExpression(node, - nodeVisitor(node.expression, visitor, isExpression), - nodeVisitor(node.argumentExpression, visitor, isExpression)); + Debug.checkDefined(nodeVisitor(node.expression, visitor, isExpression)), + Debug.checkDefined(nodeVisitor(node.argumentExpression, visitor, isExpression))); }, [SyntaxKind.CallExpression]: function visitEachChildOfCallExpression(node, visitor, context, nodesVisitor, nodeVisitor, tokenVisitor) { return isCallChain(node) ? context.factory.updateCallChain(node, - nodeVisitor(node.expression, visitor, isExpression), - nodeVisitor(node.questionDotToken, tokenVisitor, isQuestionDotToken), + Debug.checkDefined(nodeVisitor(node.expression, visitor, isExpression)), + tokenVisitor ? nodeVisitor(node.questionDotToken, tokenVisitor, isQuestionDotToken) : node.questionDotToken, nodesVisitor(node.typeArguments, visitor, isTypeNode), nodesVisitor(node.arguments, visitor, isExpression)) : context.factory.updateCallExpression(node, - nodeVisitor(node.expression, visitor, isExpression), + Debug.checkDefined(nodeVisitor(node.expression, visitor, isExpression)), nodesVisitor(node.typeArguments, visitor, isTypeNode), nodesVisitor(node.arguments, visitor, isExpression)); }, [SyntaxKind.NewExpression]: function visitEachChildOfNewExpression(node, visitor, context, nodesVisitor, nodeVisitor, _tokenVisitor) { return context.factory.updateNewExpression(node, - nodeVisitor(node.expression, visitor, isExpression), + Debug.checkDefined(nodeVisitor(node.expression, visitor, isExpression)), nodesVisitor(node.typeArguments, visitor, isTypeNode), nodesVisitor(node.arguments, visitor, isExpression)); }, [SyntaxKind.TaggedTemplateExpression]: function visitEachChildOfTaggedTemplateExpression(node, visitor, context, nodesVisitor, nodeVisitor, _tokenVisitor) { return context.factory.updateTaggedTemplateExpression(node, - nodeVisitor(node.tag, visitor, isExpression), + Debug.checkDefined(nodeVisitor(node.tag, visitor, isExpression)), nodesVisitor(node.typeArguments, visitor, isTypeNode), - nodeVisitor(node.template, visitor, isTemplateLiteral)); + Debug.checkDefined(nodeVisitor(node.template, visitor, isTemplateLiteral))); }, [SyntaxKind.TypeAssertionExpression]: function visitEachChildOfTypeAssertionExpression(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { return context.factory.updateTypeAssertion(node, - nodeVisitor(node.type, visitor, isTypeNode), - nodeVisitor(node.expression, visitor, isExpression)); + Debug.checkDefined(nodeVisitor(node.type, visitor, isTypeNode)), + Debug.checkDefined(nodeVisitor(node.expression, visitor, isExpression))); }, [SyntaxKind.ParenthesizedExpression]: function visitEachChildOfParenthesizedExpression(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { return context.factory.updateParenthesizedExpression(node, - nodeVisitor(node.expression, visitor, isExpression)); + Debug.checkDefined(nodeVisitor(node.expression, visitor, isExpression))); }, [SyntaxKind.FunctionExpression]: function visitEachChildOfFunctionExpression(node, visitor, context, nodesVisitor, nodeVisitor, tokenVisitor) { return context.factory.updateFunctionExpression(node, nodesVisitor(node.modifiers, visitor, isModifier), - nodeVisitor(node.asteriskToken, tokenVisitor, isAsteriskToken), + tokenVisitor ? nodeVisitor(node.asteriskToken, tokenVisitor, isAsteriskToken) : node.asteriskToken, nodeVisitor(node.name, visitor, isIdentifier), nodesVisitor(node.typeParameters, visitor, isTypeParameterDeclaration), visitParameterList(node.parameters, visitor, context, nodesVisitor), @@ -910,71 +996,71 @@ const visitEachChildTable: VisitEachChildTable = { nodesVisitor(node.typeParameters, visitor, isTypeParameterDeclaration), visitParameterList(node.parameters, visitor, context, nodesVisitor), nodeVisitor(node.type, visitor, isTypeNode), - nodeVisitor(node.equalsGreaterThanToken, tokenVisitor, isEqualsGreaterThanToken), + tokenVisitor ? Debug.checkDefined(nodeVisitor(node.equalsGreaterThanToken, tokenVisitor, isEqualsGreaterThanToken)) : node.equalsGreaterThanToken, visitFunctionBody(node.body, visitor, context, nodeVisitor)); }, [SyntaxKind.DeleteExpression]: function visitEachChildOfDeleteExpression(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { return context.factory.updateDeleteExpression(node, - nodeVisitor(node.expression, visitor, isExpression)); + Debug.checkDefined(nodeVisitor(node.expression, visitor, isExpression))); }, [SyntaxKind.TypeOfExpression]: function visitEachChildOfTypeOfExpression(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { return context.factory.updateTypeOfExpression(node, - nodeVisitor(node.expression, visitor, isExpression)); + Debug.checkDefined(nodeVisitor(node.expression, visitor, isExpression))); }, [SyntaxKind.VoidExpression]: function visitEachChildOfVoidExpression(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { return context.factory.updateVoidExpression(node, - nodeVisitor(node.expression, visitor, isExpression)); + Debug.checkDefined(nodeVisitor(node.expression, visitor, isExpression))); }, [SyntaxKind.AwaitExpression]: function visitEachChildOfAwaitExpression(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { return context.factory.updateAwaitExpression(node, - nodeVisitor(node.expression, visitor, isExpression)); + Debug.checkDefined(nodeVisitor(node.expression, visitor, isExpression))); }, [SyntaxKind.PrefixUnaryExpression]: function visitEachChildOfPrefixUnaryExpression(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { return context.factory.updatePrefixUnaryExpression(node, - nodeVisitor(node.operand, visitor, isExpression)); + Debug.checkDefined(nodeVisitor(node.operand, visitor, isExpression))); }, [SyntaxKind.PostfixUnaryExpression]: function visitEachChildOfPostfixUnaryExpression(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { return context.factory.updatePostfixUnaryExpression(node, - nodeVisitor(node.operand, visitor, isExpression)); + Debug.checkDefined(nodeVisitor(node.operand, visitor, isExpression))); }, [SyntaxKind.BinaryExpression]: function visitEachChildOfBinaryExpression(node, visitor, context, _nodesVisitor, nodeVisitor, tokenVisitor) { return context.factory.updateBinaryExpression(node, - nodeVisitor(node.left, visitor, isExpression), - nodeVisitor(node.operatorToken, tokenVisitor, isBinaryOperatorToken), - nodeVisitor(node.right, visitor, isExpression)); + Debug.checkDefined(nodeVisitor(node.left, visitor, isExpression)), + tokenVisitor ? Debug.checkDefined(nodeVisitor(node.operatorToken, tokenVisitor, isBinaryOperatorToken)) : node.operatorToken, + Debug.checkDefined(nodeVisitor(node.right, visitor, isExpression))); }, [SyntaxKind.ConditionalExpression]: function visitEachChildOfConditionalExpression(node, visitor, context, _nodesVisitor, nodeVisitor, tokenVisitor) { return context.factory.updateConditionalExpression(node, - nodeVisitor(node.condition, visitor, isExpression), - nodeVisitor(node.questionToken, tokenVisitor, isQuestionToken), - nodeVisitor(node.whenTrue, visitor, isExpression), - nodeVisitor(node.colonToken, tokenVisitor, isColonToken), - nodeVisitor(node.whenFalse, visitor, isExpression)); + Debug.checkDefined(nodeVisitor(node.condition, visitor, isExpression)), + tokenVisitor ? Debug.checkDefined(nodeVisitor(node.questionToken, tokenVisitor, isQuestionToken)) : node.questionToken, + Debug.checkDefined(nodeVisitor(node.whenTrue, visitor, isExpression)), + tokenVisitor ? Debug.checkDefined(nodeVisitor(node.colonToken, tokenVisitor, isColonToken)) : node.colonToken, + Debug.checkDefined(nodeVisitor(node.whenFalse, visitor, isExpression))); }, [SyntaxKind.TemplateExpression]: function visitEachChildOfTemplateExpression(node, visitor, context, nodesVisitor, nodeVisitor, _tokenVisitor) { return context.factory.updateTemplateExpression(node, - nodeVisitor(node.head, visitor, isTemplateHead), + Debug.checkDefined(nodeVisitor(node.head, visitor, isTemplateHead)), nodesVisitor(node.templateSpans, visitor, isTemplateSpan)); }, [SyntaxKind.YieldExpression]: function visitEachChildOfYieldExpression(node, visitor, context, _nodesVisitor, nodeVisitor, tokenVisitor) { return context.factory.updateYieldExpression(node, - nodeVisitor(node.asteriskToken, tokenVisitor, isAsteriskToken), + tokenVisitor ? nodeVisitor(node.asteriskToken, tokenVisitor, isAsteriskToken) : node.asteriskToken, nodeVisitor(node.expression, visitor, isExpression)); }, [SyntaxKind.SpreadElement]: function visitEachChildOfSpreadElement(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { return context.factory.updateSpreadElement(node, - nodeVisitor(node.expression, visitor, isExpression)); + Debug.checkDefined(nodeVisitor(node.expression, visitor, isExpression))); }, [SyntaxKind.ClassExpression]: function visitEachChildOfClassExpression(node, visitor, context, nodesVisitor, nodeVisitor, _tokenVisitor) { @@ -988,40 +1074,40 @@ const visitEachChildTable: VisitEachChildTable = { [SyntaxKind.ExpressionWithTypeArguments]: function visitEachChildOfExpressionWithTypeArguments(node, visitor, context, nodesVisitor, nodeVisitor, _tokenVisitor) { return context.factory.updateExpressionWithTypeArguments(node, - nodeVisitor(node.expression, visitor, isExpression), + Debug.checkDefined(nodeVisitor(node.expression, visitor, isExpression)), nodesVisitor(node.typeArguments, visitor, isTypeNode)); }, [SyntaxKind.AsExpression]: function visitEachChildOfAsExpression(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { return context.factory.updateAsExpression(node, - nodeVisitor(node.expression, visitor, isExpression), - nodeVisitor(node.type, visitor, isTypeNode)); + Debug.checkDefined(nodeVisitor(node.expression, visitor, isExpression)), + Debug.checkDefined(nodeVisitor(node.type, visitor, isTypeNode))); }, [SyntaxKind.SatisfiesExpression]: function visitEachChildOfSatisfiesExpression(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { return context.factory.updateSatisfiesExpression(node, - nodeVisitor(node.expression, visitor, isExpression), - nodeVisitor(node.type, visitor, isTypeNode)); + Debug.checkDefined(nodeVisitor(node.expression, visitor, isExpression)), + Debug.checkDefined(nodeVisitor(node.type, visitor, isTypeNode))); }, [SyntaxKind.NonNullExpression]: function visitEachChildOfNonNullExpression(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { return isOptionalChain(node) ? context.factory.updateNonNullChain(node, - nodeVisitor(node.expression, visitor, isExpression)) : + Debug.checkDefined(nodeVisitor(node.expression, visitor, isExpression))) : context.factory.updateNonNullExpression(node, - nodeVisitor(node.expression, visitor, isExpression)); + Debug.checkDefined(nodeVisitor(node.expression, visitor, isExpression))); }, [SyntaxKind.MetaProperty]: function visitEachChildOfMetaProperty(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { return context.factory.updateMetaProperty(node, - nodeVisitor(node.name, visitor, isIdentifier)); + Debug.checkDefined(nodeVisitor(node.name, visitor, isIdentifier))); }, // Misc [SyntaxKind.TemplateSpan]: function visitEachChildOfTemplateSpan(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { return context.factory.updateTemplateSpan(node, - nodeVisitor(node.expression, visitor, isExpression), - nodeVisitor(node.literal, visitor, isTemplateMiddleOrTemplateTail)); + Debug.checkDefined(nodeVisitor(node.expression, visitor, isExpression)), + Debug.checkDefined(nodeVisitor(node.literal, visitor, isTemplateMiddleOrTemplateTail))); }, // Element @@ -1033,30 +1119,30 @@ const visitEachChildTable: VisitEachChildTable = { [SyntaxKind.VariableStatement]: function visitEachChildOfVariableStatement(node, visitor, context, nodesVisitor, nodeVisitor, _tokenVisitor) { return context.factory.updateVariableStatement(node, nodesVisitor(node.modifiers, visitor, isModifier), - nodeVisitor(node.declarationList, visitor, isVariableDeclarationList)); + Debug.checkDefined(nodeVisitor(node.declarationList, visitor, isVariableDeclarationList))); }, [SyntaxKind.ExpressionStatement]: function visitEachChildOfExpressionStatement(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { return context.factory.updateExpressionStatement(node, - nodeVisitor(node.expression, visitor, isExpression)); + Debug.checkDefined(nodeVisitor(node.expression, visitor, isExpression))); }, [SyntaxKind.IfStatement]: function visitEachChildOfIfStatement(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { return context.factory.updateIfStatement(node, - nodeVisitor(node.expression, visitor, isExpression), - nodeVisitor(node.thenStatement, visitor, isStatement, context.factory.liftToBlock), + Debug.checkDefined(nodeVisitor(node.expression, visitor, isExpression)), + Debug.checkDefined(nodeVisitor(node.thenStatement, visitor, isStatement, context.factory.liftToBlock)), nodeVisitor(node.elseStatement, visitor, isStatement, context.factory.liftToBlock)); }, [SyntaxKind.DoStatement]: function visitEachChildOfDoStatement(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { return context.factory.updateDoStatement(node, visitIterationBody(node.statement, visitor, context, nodeVisitor), - nodeVisitor(node.expression, visitor, isExpression)); + Debug.checkDefined(nodeVisitor(node.expression, visitor, isExpression))); }, [SyntaxKind.WhileStatement]: function visitEachChildOfWhileStatement(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { return context.factory.updateWhileStatement(node, - nodeVisitor(node.expression, visitor, isExpression), + Debug.checkDefined(nodeVisitor(node.expression, visitor, isExpression)), visitIterationBody(node.statement, visitor, context, nodeVisitor)); }, @@ -1070,16 +1156,16 @@ const visitEachChildTable: VisitEachChildTable = { [SyntaxKind.ForInStatement]: function visitEachChildOfForInStatement(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { return context.factory.updateForInStatement(node, - nodeVisitor(node.initializer, visitor, isForInitializer), - nodeVisitor(node.expression, visitor, isExpression), + Debug.checkDefined(nodeVisitor(node.initializer, visitor, isForInitializer)), + Debug.checkDefined(nodeVisitor(node.expression, visitor, isExpression)), visitIterationBody(node.statement, visitor, context, nodeVisitor)); }, [SyntaxKind.ForOfStatement]: function visitEachChildOfForOfStatement(node, visitor, context, _nodesVisitor, nodeVisitor, tokenVisitor) { return context.factory.updateForOfStatement(node, - nodeVisitor(node.awaitModifier, tokenVisitor, isAwaitKeyword), - nodeVisitor(node.initializer, visitor, isForInitializer), - nodeVisitor(node.expression, visitor, isExpression), + tokenVisitor ? nodeVisitor(node.awaitModifier, tokenVisitor, isAwaitKeyword) : node.awaitModifier, + Debug.checkDefined(nodeVisitor(node.initializer, visitor, isForInitializer)), + Debug.checkDefined(nodeVisitor(node.expression, visitor, isExpression)), visitIterationBody(node.statement, visitor, context, nodeVisitor)); }, @@ -1100,38 +1186,38 @@ const visitEachChildTable: VisitEachChildTable = { [SyntaxKind.WithStatement]: function visitEachChildOfWithStatement(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { return context.factory.updateWithStatement(node, - nodeVisitor(node.expression, visitor, isExpression), - nodeVisitor(node.statement, visitor, isStatement, context.factory.liftToBlock)); + Debug.checkDefined(nodeVisitor(node.expression, visitor, isExpression)), + Debug.checkDefined(nodeVisitor(node.statement, visitor, isStatement, context.factory.liftToBlock))); }, [SyntaxKind.SwitchStatement]: function visitEachChildOfSwitchStatement(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { return context.factory.updateSwitchStatement(node, - nodeVisitor(node.expression, visitor, isExpression), - nodeVisitor(node.caseBlock, visitor, isCaseBlock)); + Debug.checkDefined(nodeVisitor(node.expression, visitor, isExpression)), + Debug.checkDefined(nodeVisitor(node.caseBlock, visitor, isCaseBlock))); }, [SyntaxKind.LabeledStatement]: function visitEachChildOfLabeledStatement(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { return context.factory.updateLabeledStatement(node, - nodeVisitor(node.label, visitor, isIdentifier), - nodeVisitor(node.statement, visitor, isStatement, context.factory.liftToBlock)); + Debug.checkDefined(nodeVisitor(node.label, visitor, isIdentifier)), + Debug.checkDefined(nodeVisitor(node.statement, visitor, isStatement, context.factory.liftToBlock))); }, [SyntaxKind.ThrowStatement]: function visitEachChildOfThrowStatement(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { return context.factory.updateThrowStatement(node, - nodeVisitor(node.expression, visitor, isExpression)); + Debug.checkDefined(nodeVisitor(node.expression, visitor, isExpression))); }, [SyntaxKind.TryStatement]: function visitEachChildOfTryStatement(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { return context.factory.updateTryStatement(node, - nodeVisitor(node.tryBlock, visitor, isBlock), + Debug.checkDefined(nodeVisitor(node.tryBlock, visitor, isBlock)), nodeVisitor(node.catchClause, visitor, isCatchClause), nodeVisitor(node.finallyBlock, visitor, isBlock)); }, [SyntaxKind.VariableDeclaration]: function visitEachChildOfVariableDeclaration(node, visitor, context, _nodesVisitor, nodeVisitor, tokenVisitor) { return context.factory.updateVariableDeclaration(node, - nodeVisitor(node.name, visitor, isBindingName), - nodeVisitor(node.exclamationToken, tokenVisitor, isExclamationToken), + Debug.checkDefined(nodeVisitor(node.name, visitor, isBindingName)), + tokenVisitor ? nodeVisitor(node.exclamationToken, tokenVisitor, isExclamationToken) : node.exclamationToken, nodeVisitor(node.type, visitor, isTypeNode), nodeVisitor(node.initializer, visitor, isExpression)); }, @@ -1144,7 +1230,7 @@ const visitEachChildTable: VisitEachChildTable = { [SyntaxKind.FunctionDeclaration]: function visitEachChildOfFunctionDeclaration(node, visitor, context, nodesVisitor, nodeVisitor, tokenVisitor) { return context.factory.updateFunctionDeclaration(node, nodesVisitor(node.modifiers, visitor, isModifier), - nodeVisitor(node.asteriskToken, tokenVisitor, isAsteriskToken), + tokenVisitor ? nodeVisitor(node.asteriskToken, tokenVisitor, isAsteriskToken) : node.asteriskToken, nodeVisitor(node.name, visitor, isIdentifier), nodesVisitor(node.typeParameters, visitor, isTypeParameterDeclaration), visitParameterList(node.parameters, visitor, context, nodesVisitor), @@ -1164,7 +1250,7 @@ const visitEachChildTable: VisitEachChildTable = { [SyntaxKind.InterfaceDeclaration]: function visitEachChildOfInterfaceDeclaration(node, visitor, context, nodesVisitor, nodeVisitor, _tokenVisitor) { return context.factory.updateInterfaceDeclaration(node, nodesVisitor(node.modifiers, visitor, isModifier), - nodeVisitor(node.name, visitor, isIdentifier), + Debug.checkDefined(nodeVisitor(node.name, visitor, isIdentifier)), nodesVisitor(node.typeParameters, visitor, isTypeParameterDeclaration), nodesVisitor(node.heritageClauses, visitor, isHeritageClause), nodesVisitor(node.members, visitor, isTypeElement)); @@ -1173,22 +1259,22 @@ const visitEachChildTable: VisitEachChildTable = { [SyntaxKind.TypeAliasDeclaration]: function visitEachChildOfTypeAliasDeclaration(node, visitor, context, nodesVisitor, nodeVisitor, _tokenVisitor) { return context.factory.updateTypeAliasDeclaration(node, nodesVisitor(node.modifiers, visitor, isModifier), - nodeVisitor(node.name, visitor, isIdentifier), + Debug.checkDefined(nodeVisitor(node.name, visitor, isIdentifier)), nodesVisitor(node.typeParameters, visitor, isTypeParameterDeclaration), - nodeVisitor(node.type, visitor, isTypeNode)); + Debug.checkDefined(nodeVisitor(node.type, visitor, isTypeNode))); }, [SyntaxKind.EnumDeclaration]: function visitEachChildOfEnumDeclaration(node, visitor, context, nodesVisitor, nodeVisitor, _tokenVisitor) { return context.factory.updateEnumDeclaration(node, nodesVisitor(node.modifiers, visitor, isModifier), - nodeVisitor(node.name, visitor, isIdentifier), + Debug.checkDefined(nodeVisitor(node.name, visitor, isIdentifier)), nodesVisitor(node.members, visitor, isEnumMember)); }, [SyntaxKind.ModuleDeclaration]: function visitEachChildOfModuleDeclaration(node, visitor, context, nodesVisitor, nodeVisitor, _tokenVisitor) { return context.factory.updateModuleDeclaration(node, nodesVisitor(node.modifiers, visitor, isModifier), - nodeVisitor(node.name, visitor, isModuleName), + Debug.checkDefined(nodeVisitor(node.name, visitor, isModuleName)), nodeVisitor(node.body, visitor, isModuleBody)); }, @@ -1204,22 +1290,22 @@ const visitEachChildTable: VisitEachChildTable = { [SyntaxKind.NamespaceExportDeclaration]: function visitEachChildOfNamespaceExportDeclaration(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { return context.factory.updateNamespaceExportDeclaration(node, - nodeVisitor(node.name, visitor, isIdentifier)); + Debug.checkDefined(nodeVisitor(node.name, visitor, isIdentifier))); }, [SyntaxKind.ImportEqualsDeclaration]: function visitEachChildOfImportEqualsDeclaration(node, visitor, context, nodesVisitor, nodeVisitor, _tokenVisitor) { return context.factory.updateImportEqualsDeclaration(node, nodesVisitor(node.modifiers, visitor, isModifier), node.isTypeOnly, - nodeVisitor(node.name, visitor, isIdentifier), - nodeVisitor(node.moduleReference, visitor, isModuleReference)); + Debug.checkDefined(nodeVisitor(node.name, visitor, isIdentifier)), + Debug.checkDefined(nodeVisitor(node.moduleReference, visitor, isModuleReference))); }, [SyntaxKind.ImportDeclaration]: function visitEachChildOfImportDeclaration(node, visitor, context, nodesVisitor, nodeVisitor, _tokenVisitor) { return context.factory.updateImportDeclaration(node, nodesVisitor(node.modifiers, visitor, isModifier), nodeVisitor(node.importClause, visitor, isImportClause), - nodeVisitor(node.moduleSpecifier, visitor, isExpression), + Debug.checkDefined(nodeVisitor(node.moduleSpecifier, visitor, isExpression)), nodeVisitor(node.assertClause, visitor, isAssertClause)); }, @@ -1231,8 +1317,8 @@ const visitEachChildTable: VisitEachChildTable = { [SyntaxKind.AssertEntry]: function visitEachChildOfAssertEntry(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { return context.factory.updateAssertEntry(node, - nodeVisitor(node.name, visitor, isAssertionKey), - nodeVisitor(node.value, visitor, isExpression)); + Debug.checkDefined(nodeVisitor(node.name, visitor, isAssertionKey)), + Debug.checkDefined(nodeVisitor(node.value, visitor, isExpression))); }, [SyntaxKind.ImportClause]: function visitEachChildOfImportClause(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { @@ -1244,12 +1330,12 @@ const visitEachChildTable: VisitEachChildTable = { [SyntaxKind.NamespaceImport]: function visitEachChildOfNamespaceImport(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { return context.factory.updateNamespaceImport(node, - nodeVisitor(node.name, visitor, isIdentifier)); + Debug.checkDefined(nodeVisitor(node.name, visitor, isIdentifier))); }, [SyntaxKind.NamespaceExport]: function visitEachChildOfNamespaceExport(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { return context.factory.updateNamespaceExport(node, - nodeVisitor(node.name, visitor, isIdentifier)); + Debug.checkDefined(nodeVisitor(node.name, visitor, isIdentifier))); }, [SyntaxKind.NamedImports]: function visitEachChildOfNamedImports(node, visitor, context, nodesVisitor, _nodeVisitor, _tokenVisitor) { @@ -1261,13 +1347,13 @@ const visitEachChildTable: VisitEachChildTable = { return context.factory.updateImportSpecifier(node, node.isTypeOnly, nodeVisitor(node.propertyName, visitor, isIdentifier), - nodeVisitor(node.name, visitor, isIdentifier)); + Debug.checkDefined(nodeVisitor(node.name, visitor, isIdentifier))); }, [SyntaxKind.ExportAssignment]: function visitEachChildOfExportAssignment(node, visitor, context, nodesVisitor, nodeVisitor, _tokenVisitor) { return context.factory.updateExportAssignment(node, nodesVisitor(node.modifiers, visitor, isModifier), - nodeVisitor(node.expression, visitor, isExpression)); + Debug.checkDefined(nodeVisitor(node.expression, visitor, isExpression))); }, [SyntaxKind.ExportDeclaration]: function visitEachChildOfExportDeclaration(node, visitor, context, nodesVisitor, nodeVisitor, _tokenVisitor) { @@ -1288,52 +1374,52 @@ const visitEachChildTable: VisitEachChildTable = { return context.factory.updateExportSpecifier(node, node.isTypeOnly, nodeVisitor(node.propertyName, visitor, isIdentifier), - nodeVisitor(node.name, visitor, isIdentifier)); + Debug.checkDefined(nodeVisitor(node.name, visitor, isIdentifier))); }, // Module references [SyntaxKind.ExternalModuleReference]: function visitEachChildOfExternalModuleReference(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { return context.factory.updateExternalModuleReference(node, - nodeVisitor(node.expression, visitor, isExpression)); + Debug.checkDefined(nodeVisitor(node.expression, visitor, isExpression))); }, // JSX [SyntaxKind.JsxElement]: function visitEachChildOfJsxElement(node, visitor, context, nodesVisitor, nodeVisitor, _tokenVisitor) { return context.factory.updateJsxElement(node, - nodeVisitor(node.openingElement, visitor, isJsxOpeningElement), + Debug.checkDefined(nodeVisitor(node.openingElement, visitor, isJsxOpeningElement)), nodesVisitor(node.children, visitor, isJsxChild), - nodeVisitor(node.closingElement, visitor, isJsxClosingElement)); + Debug.checkDefined(nodeVisitor(node.closingElement, visitor, isJsxClosingElement))); }, [SyntaxKind.JsxSelfClosingElement]: function visitEachChildOfJsxSelfClosingElement(node, visitor, context, nodesVisitor, nodeVisitor, _tokenVisitor) { return context.factory.updateJsxSelfClosingElement(node, - nodeVisitor(node.tagName, visitor, isJsxTagNameExpression), + Debug.checkDefined(nodeVisitor(node.tagName, visitor, isJsxTagNameExpression)), nodesVisitor(node.typeArguments, visitor, isTypeNode), - nodeVisitor(node.attributes, visitor, isJsxAttributes)); + Debug.checkDefined(nodeVisitor(node.attributes, visitor, isJsxAttributes))); }, [SyntaxKind.JsxOpeningElement]: function visitEachChildOfJsxOpeningElement(node, visitor, context, nodesVisitor, nodeVisitor, _tokenVisitor) { return context.factory.updateJsxOpeningElement(node, - nodeVisitor(node.tagName, visitor, isJsxTagNameExpression), + Debug.checkDefined(nodeVisitor(node.tagName, visitor, isJsxTagNameExpression)), nodesVisitor(node.typeArguments, visitor, isTypeNode), - nodeVisitor(node.attributes, visitor, isJsxAttributes)); + Debug.checkDefined(nodeVisitor(node.attributes, visitor, isJsxAttributes))); }, [SyntaxKind.JsxClosingElement]: function visitEachChildOfJsxClosingElement(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { return context.factory.updateJsxClosingElement(node, - nodeVisitor(node.tagName, visitor, isJsxTagNameExpression)); + Debug.checkDefined(nodeVisitor(node.tagName, visitor, isJsxTagNameExpression))); }, [SyntaxKind.JsxFragment]: function visitEachChildOfJsxFragment(node, visitor, context, nodesVisitor, nodeVisitor, _tokenVisitor) { return context.factory.updateJsxFragment(node, - nodeVisitor(node.openingFragment, visitor, isJsxOpeningFragment), + Debug.checkDefined(nodeVisitor(node.openingFragment, visitor, isJsxOpeningFragment)), nodesVisitor(node.children, visitor, isJsxChild), - nodeVisitor(node.closingFragment, visitor, isJsxClosingFragment)); + Debug.checkDefined(nodeVisitor(node.closingFragment, visitor, isJsxClosingFragment))); }, [SyntaxKind.JsxAttribute]: function visitEachChildOfJsxAttribute(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { return context.factory.updateJsxAttribute(node, - nodeVisitor(node.name, visitor, isIdentifier), + Debug.checkDefined(nodeVisitor(node.name, visitor, isIdentifier)), nodeVisitor(node.initializer, visitor, isStringLiteralOrJsxExpression)); }, @@ -1344,18 +1430,18 @@ const visitEachChildTable: VisitEachChildTable = { [SyntaxKind.JsxSpreadAttribute]: function visitEachChildOfJsxSpreadAttribute(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { return context.factory.updateJsxSpreadAttribute(node, - nodeVisitor(node.expression, visitor, isExpression)); + Debug.checkDefined(nodeVisitor(node.expression, visitor, isExpression))); }, [SyntaxKind.JsxExpression]: function visitEachChildOfJsxExpression(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { return context.factory.updateJsxExpression(node, - nodeVisitor(node.expression, visitor, isExpression)); + Debug.checkDefined(nodeVisitor(node.expression, visitor, isExpression))); }, // Clauses [SyntaxKind.CaseClause]: function visitEachChildOfCaseClause(node, visitor, context, nodesVisitor, nodeVisitor, _tokenVisitor) { return context.factory.updateCaseClause(node, - nodeVisitor(node.expression, visitor, isExpression), + Debug.checkDefined(nodeVisitor(node.expression, visitor, isExpression)), nodesVisitor(node.statements, visitor, isStatement)); }, @@ -1372,31 +1458,31 @@ const visitEachChildTable: VisitEachChildTable = { [SyntaxKind.CatchClause]: function visitEachChildOfCatchClause(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { return context.factory.updateCatchClause(node, nodeVisitor(node.variableDeclaration, visitor, isVariableDeclaration), - nodeVisitor(node.block, visitor, isBlock)); + Debug.checkDefined(nodeVisitor(node.block, visitor, isBlock))); }, // Property assignments [SyntaxKind.PropertyAssignment]: function visitEachChildOfPropertyAssignment(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { return context.factory.updatePropertyAssignment(node, - nodeVisitor(node.name, visitor, isPropertyName), - nodeVisitor(node.initializer, visitor, isExpression)); + Debug.checkDefined(nodeVisitor(node.name, visitor, isPropertyName)), + Debug.checkDefined(nodeVisitor(node.initializer, visitor, isExpression))); }, [SyntaxKind.ShorthandPropertyAssignment]: function visitEachChildOfShorthandPropertyAssignment(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { return context.factory.updateShorthandPropertyAssignment(node, - nodeVisitor(node.name, visitor, isIdentifier), + Debug.checkDefined(nodeVisitor(node.name, visitor, isIdentifier)), nodeVisitor(node.objectAssignmentInitializer, visitor, isExpression)); }, [SyntaxKind.SpreadAssignment]: function visitEachChildOfSpreadAssignment(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { return context.factory.updateSpreadAssignment(node, - nodeVisitor(node.expression, visitor, isExpression)); + Debug.checkDefined(nodeVisitor(node.expression, visitor, isExpression))); }, // Enum [SyntaxKind.EnumMember]: function visitEachChildOfEnumMember(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { return context.factory.updateEnumMember(node, - nodeVisitor(node.name, visitor, isPropertyName), + Debug.checkDefined(nodeVisitor(node.name, visitor, isPropertyName)), nodeVisitor(node.initializer, visitor, isExpression)); }, @@ -1409,7 +1495,7 @@ const visitEachChildTable: VisitEachChildTable = { // Transformation nodes [SyntaxKind.PartiallyEmittedExpression]: function visitEachChildOfPartiallyEmittedExpression(node, visitor, context, _nodesVisitor, nodeVisitor, _tokenVisitor) { return context.factory.updatePartiallyEmittedExpression(node, - nodeVisitor(node.expression, visitor, isExpression)); + Debug.checkDefined(nodeVisitor(node.expression, visitor, isExpression))); }, [SyntaxKind.CommaListExpression]: function visitEachChildOfCommaListExpression(node, visitor, context, nodesVisitor, _nodeVisitor, _tokenVisitor) { diff --git a/src/compiler/watch.ts b/src/compiler/watch.ts index db7527fa004ea..da469f33dfb02 100644 --- a/src/compiler/watch.ts +++ b/src/compiler/watch.ts @@ -234,7 +234,11 @@ export function getFilesInErrorForSummary(diagnostics: readonly Diagnostic[]): ( if (errorDiagnostic.file === undefined) return; return `${errorDiagnostic.file.fileName}`; }); - return filesInError.map((fileName: string) => { + return filesInError.map((fileName) => { + if (fileName === undefined) { + return undefined; + } + const diagnosticForFileName = find(diagnostics, diagnostic => diagnostic.file !== undefined && diagnostic.file.fileName === fileName ); diff --git a/src/compiler/watchPublic.ts b/src/compiler/watchPublic.ts index 7701797d9c8a5..a6d7ad08de955 100644 --- a/src/compiler/watchPublic.ts +++ b/src/compiler/watchPublic.ts @@ -378,6 +378,11 @@ interface ParsedConfig { reloadLevel?: ConfigFileProgramReloadLevel.Partial | ConfigFileProgramReloadLevel.Full; } +// All of one and partial of the other, or vice versa. +type WatchCompilerHostOfFilesAndCompilerOptionsOrConfigFile = + | WatchCompilerHostOfFilesAndCompilerOptions & Partial> + | WatchCompilerHostOfConfigFile & Partial>; + /** * Creates the watch from the host for root files and compiler options */ @@ -386,7 +391,7 @@ export function createWatchProgram(host: WatchCompiler * Creates the watch from the host for config file */ export function createWatchProgram(host: WatchCompilerHostOfConfigFile): WatchOfConfigFile; -export function createWatchProgram(host: WatchCompilerHostOfFilesAndCompilerOptions & WatchCompilerHostOfConfigFile): WatchOfFilesAndCompilerOptions | WatchOfConfigFile { +export function createWatchProgram(host: WatchCompilerHostOfFilesAndCompilerOptionsOrConfigFile): WatchOfFilesAndCompilerOptions | WatchOfConfigFile { interface FilePresentOnHost { version: string; sourceFile: SourceFile; @@ -442,6 +447,9 @@ export function createWatchProgram(host: WatchCompiler newLine = updateNewLine(); } + Debug.assert(compilerOptions); + Debug.assert(rootFileNames); + const { watchFile, watchDirectory, writeLog } = createWatchFactory(host, compilerOptions); const getCanonicalFileName = createGetCanonicalFileName(useCaseSensitiveFileNames); @@ -451,7 +459,7 @@ export function createWatchProgram(host: WatchCompiler configFileWatcher = watchFile(configFileName, scheduleProgramReload, PollingInterval.High, watchOptions, WatchType.ConfigFile); } - const compilerHost = createCompilerHostFromProgramHost(host, () => compilerOptions, directoryStructureHost) as CompilerHost & ResolutionCacheHost; + const compilerHost = createCompilerHostFromProgramHost(host, () => compilerOptions!, directoryStructureHost) as CompilerHost & ResolutionCacheHost; setGetSourceFileAsHashVersioned(compilerHost); // Members for CompilerHost const getNewSourceFile = compilerHost.getSourceFile; @@ -463,7 +471,7 @@ export function createWatchProgram(host: WatchCompiler compilerHost.onReleaseParsedCommandLine = onReleaseParsedCommandLine; // Members for ResolutionCacheHost compilerHost.toPath = toPath; - compilerHost.getCompilationSettings = () => compilerOptions; + compilerHost.getCompilationSettings = () => compilerOptions!; compilerHost.useSourceOfProjectReferenceRedirect = maybeBind(host, host.useSourceOfProjectReferenceRedirect); compilerHost.watchDirectoryOfFailedLookupLocation = (dir, cb, flags) => watchDirectory(dir, cb, flags, watchOptions, WatchType.FailedLookupLocations); compilerHost.watchAffectingFileLocation = (file, cb) => watchFile(file, cb, PollingInterval.High, watchOptions, WatchType.AffectingFileLocation); @@ -566,6 +574,10 @@ export function createWatchProgram(host: WatchCompiler function synchronizeProgram() { writeLog(`Synchronizing program`); + + Debug.assert(compilerOptions); + Debug.assert(rootFileNames); + clearInvalidateResolutionsOfFailedLookupLocations(); const program = getCurrentBuilderProgram(); @@ -849,6 +861,10 @@ export function createWatchProgram(host: WatchCompiler function reloadFileNamesFromConfigFile() { writeLog("Reloading new file names and options"); + + Debug.assert(compilerOptions); + Debug.assert(configFileName); + reloadLevel = ConfigFileProgramReloadLevel.None; rootFileNames = getFileNamesFromConfigSpecs(compilerOptions.configFile!.configFileSpecs!, getNormalizedAbsolutePath(getDirectoryPath(configFileName), currentDirectory), compilerOptions, parseConfigFileHost, extraFileExtensions); if (updateErrorForNoInputFiles(rootFileNames, getNormalizedAbsolutePath(configFileName, currentDirectory), compilerOptions.configFile!.configFileSpecs!, configFileParsingDiagnostics!, canConfigFileJsonReportNoInputFiles)) { @@ -860,6 +876,7 @@ export function createWatchProgram(host: WatchCompiler } function reloadConfigFile() { + Debug.assert(configFileName); writeLog(`Reloading config file: ${configFileName}`); reloadLevel = ConfigFileProgramReloadLevel.None; @@ -878,6 +895,7 @@ export function createWatchProgram(host: WatchCompiler } function parseConfigFile() { + Debug.assert(configFileName); setConfigFileParsingResult(getParsedCommandLineOfConfigFile( configFileName, optionsToExtendForConfigFile, @@ -907,6 +925,7 @@ export function createWatchProgram(host: WatchCompiler // With host implementing getParsedCommandLine we cant just update file names if (config.parsedCommandLine && config.reloadLevel === ConfigFileProgramReloadLevel.Partial && !host.getParsedCommandLine) { writeLog("Reloading new file names and options"); + Debug.assert(compilerOptions); const fileNames = getFileNamesFromConfigSpecs( config.parsedCommandLine.options.configFile!.configFileSpecs!, getNormalizedAbsolutePath(getDirectoryPath(configFileName), currentDirectory), @@ -1029,7 +1048,8 @@ export function createWatchProgram(host: WatchCompiler return watchDirectory( directory, fileOrDirectory => { - Debug.assert(!!configFileName); + Debug.assert(configFileName); + Debug.assert(compilerOptions); const fileOrDirectoryPath = toPath(fileOrDirectory); @@ -1068,6 +1088,7 @@ export function createWatchProgram(host: WatchCompiler } function updateExtendedConfigFilesWatches(forProjectPath: Path, options: CompilerOptions | undefined, watchOptions: WatchOptions | undefined, watchType: WatchTypeRegistry["ExtendedConfigFile"] | WatchTypeRegistry["ExtendedConfigOfReferencedProject"]) { + Debug.assert(configFileName); updateSharedExtendedConfigFileWatcher( forProjectPath, options, diff --git a/src/harness/fakesHosts.ts b/src/harness/fakesHosts.ts index 8bafb0a902934..42bf1f0f6ccba 100644 --- a/src/harness/fakesHosts.ts +++ b/src/harness/fakesHosts.ts @@ -546,7 +546,7 @@ export class SolutionBuilderHost extends CompilerHost implements ts.SolutionBuil private constructor(sys: System | vfs.FileSystem, options?: ts.CompilerOptions, setParentNodes?: boolean, createProgram?: ts.CreateProgram) { super(sys, options, setParentNodes); - this.createProgram = createProgram || ts.createEmitAndSemanticDiagnosticsBuilderProgram; + this.createProgram = createProgram || ts.createEmitAndSemanticDiagnosticsBuilderProgram as unknown as ts.CreateProgram; } static create(sys: System | vfs.FileSystem, options?: ts.CompilerOptions, setParentNodes?: boolean, createProgram?: ts.CreateProgram) { diff --git a/src/harness/fourslashImpl.ts b/src/harness/fourslashImpl.ts index a0d32959563f9..fffce12a88419 100644 --- a/src/harness/fourslashImpl.ts +++ b/src/harness/fourslashImpl.ts @@ -524,7 +524,7 @@ export class TestState { public verifyErrorExistsBetweenMarkers(startMarkerName: string, endMarkerName: string, shouldExist: boolean) { const startMarker = this.getMarkerByName(startMarkerName); const endMarker = this.getMarkerByName(endMarkerName); - const predicate = (errorMinChar: number, errorLimChar: number, startPos: number, endPos: number) => + const predicate = (errorMinChar: number, errorLimChar: number, startPos: number, endPos: number | undefined) => ((errorMinChar === startPos) && (errorLimChar === endPos)) ? true : false; const exists = this.anyErrorInRange(predicate, startMarker, endMarker); @@ -578,7 +578,7 @@ export class TestState { public verifyErrorExistsAfterMarker(markerName: string, shouldExist: boolean, after: boolean) { const marker: Marker = this.getMarkerByName(markerName); - let predicate: (errorMinChar: number, errorLimChar: number, startPos: number, endPos: number) => boolean; + let predicate: (errorMinChar: number, errorLimChar: number, startPos: number, endPos: number | undefined) => boolean; if (after) { predicate = (errorMinChar: number, errorLimChar: number, startPos: number) => @@ -867,7 +867,8 @@ export class TestState { const hints = this.languageService.provideInlayHints(this.activeFile.fileName, span, preference); assert.equal(hints.length, expected.length, "Number of hints"); - const sortHints = (a: ts.InlayHint, b: ts.InlayHint) => { + interface HasPosition { position: number; } + const sortHints = (a: HasPosition, b: HasPosition) => { return a.position - b.position; }; ts.zipWith(hints.sort(sortHints), [...expected].sort(sortHints), (actual, expected) => { diff --git a/src/harness/harnessLanguageService.ts b/src/harness/harnessLanguageService.ts index 7ce7ba241864a..d9dba842411c0 100644 --- a/src/harness/harnessLanguageService.ts +++ b/src/harness/harnessLanguageService.ts @@ -3,7 +3,6 @@ import * as fakes from "./_namespaces/fakes"; import * as vfs from "./_namespaces/vfs"; import * as collections from "./_namespaces/collections"; import * as vpath from "./_namespaces/vpath"; -import * as Utils from "./_namespaces/Utils"; import { Compiler, harnessNewLine, @@ -1015,7 +1014,7 @@ export class ServerLanguageServiceAdapter implements LanguageServiceAdapter { useSingleInferredProject: false, useInferredProjectPerProjectRoot: false, typingsInstaller: { ...ts.server.nullTypingsInstaller, globalTypingsCacheLocation: "/Library/Caches/typescript" }, - byteLength: Utils.byteLength, + byteLength: Buffer.byteLength, hrtime: process.hrtime, logger: serverHost, canUseEvents: true diff --git a/src/harness/harnessUtils.ts b/src/harness/harnessUtils.ts index f4d006e05aa4a..b3732966c26d2 100644 --- a/src/harness/harnessUtils.ts +++ b/src/harness/harnessUtils.ts @@ -5,11 +5,6 @@ export function encodeString(s: string): string { return ts.sys.bufferFrom!(s).toString("utf8"); } -export function byteLength(s: string, encoding?: string): number { - // stub implementation if Buffer is not available (in-browser case) - return Buffer.byteLength(s, encoding as ts.BufferEncoding | undefined); -} - export function evalFile(fileContents: string, fileName: string, nodeContext?: any) { const vm = require("vm"); if (nodeContext) { diff --git a/src/server/editorServices.ts b/src/server/editorServices.ts index 31c3a4c03ad1b..2180a095b6ef3 100644 --- a/src/server/editorServices.ts +++ b/src/server/editorServices.ts @@ -733,7 +733,7 @@ function forEachResolvedProjectReferenceProjectWorker( function forEachPotentialProjectReference( project: ConfiguredProject, - cb: (potentialProjectReference: Path) => T | undefined + cb: (potentialProjectReference: NormalizedPath) => T | undefined ): T | undefined { return project.potentialProjectReferences && forEachKey(project.potentialProjectReferences, cb); @@ -743,7 +743,7 @@ function forEachAnyProjectReferenceKind( project: ConfiguredProject, cb: (resolvedProjectReference: ResolvedProjectReference) => T | undefined, cbProjectRef: (projectReference: ProjectReference) => T | undefined, - cbPotentialProjectRef: (potentialProjectReference: Path) => T | undefined + cbPotentialProjectRef: (potentialProjectReference: NormalizedPath) => T | undefined ): T | undefined { return project.getCurrentProgram() ? project.forEachResolvedProjectReference(cb) : @@ -752,10 +752,10 @@ function forEachAnyProjectReferenceKind( forEach(project.getProjectReferences(), cbProjectRef); } -function callbackRefProject( +function callbackRefProject( project: ConfiguredProject, cb: (refProj: ConfiguredProject) => T | undefined, - refPath: Path | undefined + refPath: P | undefined ) { const refProject = refPath && project.projectService.configuredProjects.get(refPath); return refProject && cb(refProject); diff --git a/src/server/project.ts b/src/server/project.ts index ab2a5252cd749..b795df1c82d5d 100644 --- a/src/server/project.ts +++ b/src/server/project.ts @@ -2548,7 +2548,7 @@ export class ConfiguredProject extends Project { * * @internal */ - potentialProjectReferences: Set | undefined; + potentialProjectReferences: Set | undefined; /** @internal */ projectOptions?: ProjectOptions | true; diff --git a/src/server/session.ts b/src/server/session.ts index a2c16033d6ebf..92861478a0e2c 100644 --- a/src/server/session.ts +++ b/src/server/session.ts @@ -1,6 +1,7 @@ import { arrayFrom, arrayReverseIterator, + BufferEncoding, CallHierarchyIncomingCall, CallHierarchyItem, CallHierarchyOutgoingCall, @@ -194,7 +195,7 @@ export const nullCancellationToken: ServerCancellationToken = { resetRequest: () => void 0 }; -function hrTimeToMilliseconds(time: number[]): number { +function hrTimeToMilliseconds(time: [number, number]): number { const seconds = time[0]; const nanoseconds = time[1]; return ((1e9 * seconds) + nanoseconds) / 1000000.0; @@ -307,7 +308,7 @@ function allEditsBeforePos(edits: readonly TextChange[], pos: number): boolean { export type CommandNames = protocol.CommandTypes; export const CommandNames = (protocol as any).CommandTypes; -export function formatMessage(msg: T, logger: Logger, byteLength: (s: string, encoding: string) => number, newLine: string): string { +export function formatMessage(msg: T, logger: Logger, byteLength: (s: string, encoding: BufferEncoding) => number, newLine: string): string { const verboseLogging = logger.hasLevel(LogLevel.verbose); const json = JSON.stringify(msg); @@ -915,8 +916,8 @@ export interface SessionOptions { useSingleInferredProject: boolean; useInferredProjectPerProjectRoot: boolean; typingsInstaller: ITypingsInstaller; - byteLength: (buf: string, encoding?: string) => number; - hrtime: (start?: number[]) => number[]; + byteLength: (buf: string, encoding?: BufferEncoding) => number; + hrtime: (start?: [number, number]) => [number, number]; logger: Logger; /** * If falsy, all events are suppressed. @@ -950,8 +951,8 @@ export class Session implements EventSender { protected host: ServerHost; private readonly cancellationToken: ServerCancellationToken; protected readonly typingsInstaller: ITypingsInstaller; - protected byteLength: (buf: string, encoding?: string) => number; - private hrtime: (start?: number[]) => number[]; + protected byteLength: (buf: string, encoding?: BufferEncoding) => number; + private hrtime: (start?: [number, number]) => [number, number]; protected logger: Logger; protected canUseEvents: boolean; @@ -3099,7 +3100,7 @@ export class Session implements EventSender { return { response, responseRequired: true }; } - private handlers = new Map(Object.entries<(request: protocol.Request) => HandlerResponse>({ + private handlers = new Map(Object.entries<(request: any) => HandlerResponse>({ // TODO(jakebailey): correctly type the handlers [CommandNames.Status]: () => { const response: protocol.StatusResponseBody = { version }; return this.requiredResponse(response); @@ -3544,7 +3545,7 @@ export class Session implements EventSender { this.performanceData = undefined; - let start: number[] | undefined; + let start: [number, number] | undefined; if (this.logger.hasLevel(LogLevel.requestTime)) { start = this.hrtime(); if (this.logger.hasLevel(LogLevel.verbose)) { diff --git a/src/services/codefixes/annotateWithTypeFromJSDoc.ts b/src/services/codefixes/annotateWithTypeFromJSDoc.ts index 292c609bc720c..a2cfc5e97224c 100644 --- a/src/services/codefixes/annotateWithTypeFromJSDoc.ts +++ b/src/services/codefixes/annotateWithTypeFromJSDoc.ts @@ -17,6 +17,7 @@ import { isJSDocIndexSignature, isOptionalJSDocPropertyLikeTag, isParameter, + isTypeNode, JSDocFunctionType, JSDocNonNullableType, JSDocNullableType, @@ -35,7 +36,6 @@ import { SyntaxKind, textChanges, tryCast, - TypeNode, TypeReferenceNode, VariableDeclaration, visitEachChild, @@ -100,19 +100,19 @@ function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, de for (const param of decl.parameters) { if (!param.type) { const paramType = getJSDocType(param); - if (paramType) changes.tryInsertTypeAnnotation(sourceFile, param, transformJSDocType(paramType)); + if (paramType) changes.tryInsertTypeAnnotation(sourceFile, param, visitNode(paramType, transformJSDocType, isTypeNode)); } } if (needParens) changes.insertNodeAfter(sourceFile, last(decl.parameters), factory.createToken(SyntaxKind.CloseParenToken)); if (!decl.type) { const returnType = getJSDocReturnType(decl); - if (returnType) changes.tryInsertTypeAnnotation(sourceFile, decl, transformJSDocType(returnType)); + if (returnType) changes.tryInsertTypeAnnotation(sourceFile, decl, visitNode(returnType, transformJSDocType, isTypeNode)); } } else { const jsdocType = Debug.checkDefined(getJSDocType(decl), "A JSDocType for this declaration should exist"); // If not defined, shouldn't have been an error to fix Debug.assert(!decl.type, "The JSDocType decl should have a type"); // If defined, shouldn't have been an error to fix. - changes.tryInsertTypeAnnotation(sourceFile, decl, transformJSDocType(jsdocType)); + changes.tryInsertTypeAnnotation(sourceFile, decl, visitNode(jsdocType, transformJSDocType, isTypeNode)); } } @@ -123,7 +123,7 @@ function isDeclarationWithType(node: Node): node is DeclarationWithType { node.kind === SyntaxKind.PropertyDeclaration; } -function transformJSDocType(node: TypeNode): TypeNode { +function transformJSDocType(node: Node): Node { switch (node.kind) { case SyntaxKind.JSDocAllType: case SyntaxKind.JSDocUnknownType: @@ -155,21 +155,21 @@ function transformJSDocTypeLiteral(node: JSDocTypeLiteral) { /*modifiers*/ undefined, isIdentifier(tag.name) ? tag.name : tag.name.right, isOptionalJSDocPropertyLikeTag(tag) ? factory.createToken(SyntaxKind.QuestionToken) : undefined, - tag.typeExpression && visitNode(tag.typeExpression.type, transformJSDocType) || factory.createKeywordTypeNode(SyntaxKind.AnyKeyword)))); + tag.typeExpression && visitNode(tag.typeExpression.type, transformJSDocType, isTypeNode) || factory.createKeywordTypeNode(SyntaxKind.AnyKeyword)))); setEmitFlags(typeNode, EmitFlags.SingleLine); return typeNode; } function transformJSDocOptionalType(node: JSDocOptionalType) { - return factory.createUnionTypeNode([visitNode(node.type, transformJSDocType), factory.createTypeReferenceNode("undefined", emptyArray)]); + return factory.createUnionTypeNode([visitNode(node.type, transformJSDocType, isTypeNode), factory.createTypeReferenceNode("undefined", emptyArray)]); } function transformJSDocNullableType(node: JSDocNullableType) { - return factory.createUnionTypeNode([visitNode(node.type, transformJSDocType), factory.createTypeReferenceNode("null", emptyArray)]); + return factory.createUnionTypeNode([visitNode(node.type, transformJSDocType, isTypeNode), factory.createTypeReferenceNode("null", emptyArray)]); } function transformJSDocVariadicType(node: JSDocVariadicType) { - return factory.createArrayTypeNode(visitNode(node.type, transformJSDocType)); + return factory.createArrayTypeNode(visitNode(node.type, transformJSDocType, isTypeNode)); } function transformJSDocFunctionType(node: JSDocFunctionType) { @@ -183,7 +183,7 @@ function transformJSDocParameter(node: ParameterDeclaration) { const isRest = node.type!.kind === SyntaxKind.JSDocVariadicType && index === node.parent.parameters.length - 1; // TODO: GH#18217 const name = node.name || (isRest ? "rest" : "arg" + index); const dotdotdot = isRest ? factory.createToken(SyntaxKind.DotDotDotToken) : node.dotDotDotToken; - return factory.createParameterDeclaration(node.modifiers, dotdotdot, name, node.questionToken, visitNode(node.type, transformJSDocType), node.initializer); + return factory.createParameterDeclaration(node.modifiers, dotdotdot, name, node.questionToken, visitNode(node.type, transformJSDocType, isTypeNode), node.initializer); } function transformJSDocTypeReference(node: TypeReferenceNode) { @@ -212,7 +212,7 @@ function transformJSDocTypeReference(node: TypeReferenceNode) { args = factory.createNodeArray([factory.createTypeReferenceNode("any", emptyArray)]); } else { - args = visitNodes(node.typeArguments, transformJSDocType); + args = visitNodes(node.typeArguments, transformJSDocType, isTypeNode); } } return factory.createTypeReferenceNode(name, args); diff --git a/src/services/codefixes/helpers.ts b/src/services/codefixes/helpers.ts index 493b1aaa6ba31..2a30b8d289ac8 100644 --- a/src/services/codefixes/helpers.ts +++ b/src/services/codefixes/helpers.ts @@ -51,6 +51,7 @@ import { isPropertyAssignment, isSetAccessorDeclaration, isStringLiteral, + isTypeNode, isYieldExpression, LanguageServiceHost, length, @@ -100,6 +101,7 @@ import { UserPreferences, visitEachChild, visitNode, + visitNodes, } from "../_namespaces/ts"; import { ImportAdder } from "../_namespaces/ts.codefix"; @@ -852,12 +854,11 @@ export function findJsonProperty(obj: ObjectLiteralExpression, name: string): Pr */ export function tryGetAutoImportableReferenceFromTypeNode(importTypeNode: TypeNode | undefined, scriptTarget: ScriptTarget) { let symbols: Symbol[] | undefined; - const typeNode = visitNode(importTypeNode, visit); + const typeNode = visitNode(importTypeNode, visit, isTypeNode); if (symbols && typeNode) { return { typeNode, symbols }; } - function visit(node: TypeNode): TypeNode; function visit(node: Node): Node { if (isLiteralImportTypeNode(node) && node.qualifier) { // Symbol for the left-most thing after the dot @@ -868,7 +869,7 @@ export function tryGetAutoImportableReferenceFromTypeNode(importTypeNode: TypeNo : node.qualifier; symbols = append(symbols, firstIdentifier.symbol); - const typeArguments = node.typeArguments?.map(visit); + const typeArguments = visitNodes(node.typeArguments, visit, isTypeNode); return factory.createTypeReferenceNode(qualifier, typeArguments); } return visitEachChild(node, visit, nullTransformationContext); diff --git a/src/services/codefixes/importFixes.ts b/src/services/codefixes/importFixes.ts index e6f21c8ca1790..5b8cef4f560ce 100644 --- a/src/services/codefixes/importFixes.ts +++ b/src/services/codefixes/importFixes.ts @@ -1002,9 +1002,13 @@ function getUmdSymbol(token: Node, checker: TypeChecker): Symbol | undefined { // The error wasn't for the symbolAtLocation, it was for the JSX tag itself, which needs access to e.g. `React`. const { parent } = token; - return (isJsxOpeningLikeElement(parent) && parent.tagName === token) || isJsxOpeningFragment(parent) - ? tryCast(checker.resolveName(checker.getJsxNamespace(parent), isJsxOpeningLikeElement(parent) ? token : parent, SymbolFlags.Value, /*excludeGlobals*/ false), isUMDExportSymbol) - : undefined; + if ((isJsxOpeningLikeElement(parent) && parent.tagName === token) || isJsxOpeningFragment(parent)) { + const parentSymbol = checker.resolveName(checker.getJsxNamespace(parent), isJsxOpeningLikeElement(parent) ? token : parent, SymbolFlags.Value, /*excludeGlobals*/ false); + if (isUMDExportSymbol(parentSymbol)) { + return parentSymbol; + } + } + return undefined; } /** diff --git a/src/services/refactors/extractSymbol.ts b/src/services/refactors/extractSymbol.ts index 3a0339a357bdf..e353589a07c4b 100644 --- a/src/services/refactors/extractSymbol.ts +++ b/src/services/refactors/extractSymbol.ts @@ -1595,7 +1595,7 @@ function transformFunctionBody(body: Node, exposedVariableDeclarations: readonly const statements = factory.createNodeArray(isBlock(body) ? body.statements.slice(0) : [isStatement(body) ? body : factory.createReturnStatement(skipParentheses(body as Expression))]); // rewrite body if either there are writes that should be propagated back via return statements or there are substitutions if (hasWritesOrVariableDeclarations || substitutions.size) { - const rewrittenStatements = visitNodes(statements, visitor).slice(); + const rewrittenStatements = visitNodes(statements, visitor, isStatement).slice(); if (hasWritesOrVariableDeclarations && !hasReturn && isStatement(body)) { // add return at the end to propagate writes back in case if control flow falls out of the function body // it is ok to know that range has at least one return since it we only allow unconditional returns @@ -1620,7 +1620,7 @@ function transformFunctionBody(body: Node, exposedVariableDeclarations: readonly if (!returnValueProperty) { returnValueProperty = "__return"; } - assignments.unshift(factory.createPropertyAssignment(returnValueProperty, visitNode(node.expression, visitor))); + assignments.unshift(factory.createPropertyAssignment(returnValueProperty, visitNode(node.expression, visitor, isExpression))); } if (assignments.length === 1) { return factory.createReturnStatement(assignments[0].name as Expression); diff --git a/src/services/textChanges.ts b/src/services/textChanges.ts index 63378707036bb..50621f641601d 100644 --- a/src/services/textChanges.ts +++ b/src/services/textChanges.ts @@ -1342,11 +1342,18 @@ export function assignPositionsToNode(node: Node): Node { return newNode; } -function assignPositionsToNodeArray(nodes: NodeArray, visitor: Visitor, test?: (node: Node) => boolean, start?: number, count?: number) { +function assignPositionsToNodeArray( + nodes: NodeArray | undefined, + visitor: Visitor, + test?: (node: Node) => boolean, + start?: number, + count?: number, +): NodeArray | undefined { const visited = visitNodes(nodes, visitor, test, start, count); if (!visited) { return visited; } + Debug.assert(nodes); // clone nodearray if necessary const nodeArray = visited === nodes ? factory.createNodeArray(visited.slice(0)) : visited; setTextRangePosEnd(nodeArray, getPos(nodes), getEnd(nodes)); diff --git a/src/services/utilities.ts b/src/services/utilities.ts index 0eca9e34446c3..553ef7d5281a5 100644 --- a/src/services/utilities.ts +++ b/src/services/utilities.ts @@ -3069,10 +3069,10 @@ export function getSynthesizedDeepCloneWithReplacements( } function getSynthesizedDeepCloneWorker(node: T, replaceNode?: (node: Node) => Node | undefined): T { - const nodeClone: (n: T) => T = replaceNode + const nodeClone: (n: T) => T = replaceNode ? n => getSynthesizedDeepCloneWithReplacements(n, /*includeTrivia*/ true, replaceNode) : getSynthesizedDeepClone; - const nodesClone: (ns: NodeArray) => NodeArray = replaceNode + const nodesClone: (ns: NodeArray | undefined) => NodeArray | undefined = replaceNode ? ns => ns && getSynthesizedDeepClonesWithReplacements(ns, /*includeTrivia*/ true, replaceNode) : ns => ns && getSynthesizedDeepClones(ns); const visited = @@ -3964,7 +3964,7 @@ export function isNonGlobalDeclaration(declaration: Declaration) { return false; } // If the file is a module written in TypeScript, it still might be in a `declare global` augmentation - return isInJSFile(declaration) || !findAncestor(declaration, isGlobalScopeAugmentation); + return isInJSFile(declaration) || !findAncestor(declaration, d => isModuleDeclaration(d) && isGlobalScopeAugmentation(d)); } /** @internal */ diff --git a/src/testRunner/unittests/compilerCore.ts b/src/testRunner/unittests/compilerCore.ts index 1b7f82118016f..ed2415eb6aec5 100644 --- a/src/testRunner/unittests/compilerCore.ts +++ b/src/testRunner/unittests/compilerCore.ts @@ -22,7 +22,7 @@ describe("unittests:: compilerCore", () => { assert.isFalse(ts.equalOwnProperties({}, { a: 0 }, trythyTest), "missing left falsey property"); assert.isFalse(ts.equalOwnProperties({ a: 1 }, {}, trythyTest), "missing right truthy property"); assert.isFalse(ts.equalOwnProperties({ a: 0 }, {}, trythyTest), "missing right falsey property"); - assert.isTrue(ts.equalOwnProperties({ a: 1 }, { a: "foo" }, trythyTest), "valid equality"); + assert.isTrue(ts.equalOwnProperties({ a: 1 }, { a: "foo" as any }, trythyTest), "valid equality"); }); it("all equal", () => { assert.isFalse(ts.equalOwnProperties({}, { a: 1 }, () => true), "missing left property"); diff --git a/src/testRunner/unittests/customTransforms.ts b/src/testRunner/unittests/customTransforms.ts index a16d2c2a4794b..ce8e1cb97e99e 100644 --- a/src/testRunner/unittests/customTransforms.ts +++ b/src/testRunner/unittests/customTransforms.ts @@ -91,7 +91,7 @@ describe("unittests:: customTransforms", () => { context => node => ts.visitNode(node, function visitor(node: ts.Node): ts.Node { if (ts.isStringLiteral(node) && node.text === "change") return ts.factory.createStringLiteral("changed"); return ts.visitEachChild(node, visitor, context); - }) + }, ts.isSourceFile) ]}, { target: ts.ScriptTarget.ES5, module: ts.ModuleKind.ES2015, @@ -126,7 +126,7 @@ describe("unittests:: customTransforms", () => { return node; } return ts.visitEachChild(node, visitor, context); - }) + }, ts.isSourceFile) ] }, { sourceMap: true } @@ -155,7 +155,7 @@ describe("unittests:: customTransforms", () => { return newNode; } return ts.visitEachChild(node, visitor, context); - }); + }, ts.isSourceFile); return { transformSourceFile, transformBundle: node => ts.factory.createBundle(ts.map(node.sourceFiles, transformSourceFile), node.prepends), diff --git a/src/testRunner/unittests/services/textChanges.ts b/src/testRunner/unittests/services/textChanges.ts index a761083145999..5013a5d994ad1 100644 --- a/src/testRunner/unittests/services/textChanges.ts +++ b/src/testRunner/unittests/services/textChanges.ts @@ -330,7 +330,7 @@ namespace M { function findConstructor(sourceFile: ts.SourceFile): ts.ConstructorDeclaration { const classDecl = sourceFile.statements[0] as ts.ClassDeclaration; - return ts.find(classDecl.members, (m): m is ts.ConstructorDeclaration => ts.isConstructorDeclaration(m) && !!m.body)!; + return ts.find(classDecl.members, (m): m is ts.ConstructorDeclaration => ts.isConstructorDeclaration(m) && !!m.body)!; } function createTestSuperCall() { const superCall = ts.factory.createCallExpression( diff --git a/src/testRunner/unittests/transform.ts b/src/testRunner/unittests/transform.ts index 00af9287364ef..4087553e46900 100644 --- a/src/testRunner/unittests/transform.ts +++ b/src/testRunner/unittests/transform.ts @@ -30,10 +30,10 @@ describe("unittests:: TransformAPI", () => { } return ts.visitEachChild(node, visitor, context); } - return (file: ts.SourceFile) => ts.visitNode(file, visitor); + return (file: ts.SourceFile) => ts.visitNode(file, visitor, ts.isSourceFile); } - function replaceIdentifiersNamedOldNameWithNewName(context: ts.TransformationContext) { + function replaceIdentifiersNamedOldNameWithNewName(context: ts.TransformationContext) { const previousOnSubstituteNode = context.onSubstituteNode; context.enableSubstitution(ts.SyntaxKind.Identifier); context.onSubstituteNode = (hint, node) => { @@ -43,17 +43,17 @@ describe("unittests:: TransformAPI", () => { } return node; }; - return (file: ts.SourceFile) => file; + return (file: T) => file; } function replaceIdentifiersNamedOldNameWithNewName2(context: ts.TransformationContext) { - const visitor: ts.Visitor = (node) => { + const visitor = (node: ts.Node): ts.Node => { if (ts.isIdentifier(node) && node.text === "oldName") { return ts.factory.createIdentifier("newName"); } return ts.visitEachChild(node, visitor, context); }; - return (node: ts.SourceFile) => ts.visitNode(node, visitor); + return (node: ts.SourceFile) => ts.visitNode(node, visitor, ts.isSourceFile); } function createTaggedTemplateLiteral(): ts.Transformer { @@ -109,7 +109,7 @@ describe("unittests:: TransformAPI", () => { return transformSourceFile(`let a: () => void`, [ context => file => ts.visitNode(file, function visitor(node: ts.Node): ts.VisitResult { return ts.visitEachChild(node, visitor, context); - }) + }, ts.isSourceFile) ]); }); @@ -120,7 +120,7 @@ describe("unittests:: TransformAPI", () => { return ts.factory.createKeywordTypeNode(ts.SyntaxKind.UndefinedKeyword); } return ts.visitEachChild(node, visitor, context); - }) + }, ts.isSourceFile) ]); }); @@ -557,7 +557,7 @@ module MyModule { return host.readFile("source.js")!.toString(); function transformSourceFile(context: ts.TransformationContext) { - const visitor: ts.Visitor = (node) => { + const visitor = (node: ts.Node): ts.Node => { if (ts.isMethodDeclaration(node)) { return ts.factory.updateMethodDeclaration( node, @@ -573,7 +573,7 @@ module MyModule { } return ts.visitEachChild(node, visitor, context); }; - return (node: ts.SourceFile) => ts.visitNode(node, visitor); + return (node: ts.SourceFile) => ts.visitNode(node, visitor, ts.isSourceFile); } }); diff --git a/src/testRunner/unittests/tsserver/cachingFileSystemInformation.ts b/src/testRunner/unittests/tsserver/cachingFileSystemInformation.ts index ba1451d3edfb5..12e650e4d84cd 100644 --- a/src/testRunner/unittests/tsserver/cachingFileSystemInformation.ts +++ b/src/testRunner/unittests/tsserver/cachingFileSystemInformation.ts @@ -2,6 +2,7 @@ import * as ts from "../../_namespaces/ts"; import { createServerHost, File, + Folder, libFile, SymLink, TestServerHost, @@ -366,7 +367,7 @@ describe("unittests:: tsserver:: CachingFileSystemInformation:: tsserverProjectS describe("Verify npm install in directory with tsconfig file works when", () => { function verifyNpmInstall(timeoutDuringPartialInstallation: boolean) { const root = "/user/username/rootfolder/otherfolder"; - const getRootedFileOrFolder = (fileOrFolder: File) => { + const getRootedFileOrFolder = (fileOrFolder: T) => { fileOrFolder.path = root + fileOrFolder.path; return fileOrFolder; }; @@ -411,7 +412,7 @@ describe("unittests:: tsserver:: CachingFileSystemInformation:: tsserverProjectS let npmInstallComplete = false; // Simulate npm install - const filesAndFoldersToAdd: File[] = [ + const filesAndFoldersToAdd: (File | Folder)[] = [ { path: "/a/b/node_modules" }, { path: "/a/b/node_modules/.staging/@types" }, { path: "/a/b/node_modules/.staging/lodash-b0733faa" }, diff --git a/src/testRunner/unittests/tsserver/helpers.ts b/src/testRunner/unittests/tsserver/helpers.ts index 62ae117c734bd..f58065db9392b 100644 --- a/src/testRunner/unittests/tsserver/helpers.ts +++ b/src/testRunner/unittests/tsserver/helpers.ts @@ -1,6 +1,5 @@ import * as ts from "../../_namespaces/ts"; import * as Harness from "../../_namespaces/Harness"; -import * as Utils from "../../_namespaces/Utils"; import { changeToHostTrackingWrittenFiles, createServerHost, @@ -473,7 +472,7 @@ export function createSession(host: ts.server.ServerHost, opts: Partial { useSingleInferredProject: false, useInferredProjectPerProjectRoot: false, typingsInstaller: undefined!, // TODO: GH#18217 - byteLength: Utils.byteLength, + byteLength: Buffer.byteLength, hrtime: process.hrtime, logger: nullLogger(), canUseEvents: true @@ -352,7 +351,7 @@ describe("unittests:: tsserver:: Session:: General functionality", () => { it("is an overrideable handle which sends protocol messages over the wire", () => { const msg: ts.server.protocol.Request = { seq: 0, type: "request", command: "" }; const strmsg = JSON.stringify(msg); - const len = 1 + Utils.byteLength(strmsg, "utf8"); + const len = 1 + Buffer.byteLength(strmsg, "utf8"); const resultMsg = `Content-Length: ${len}\r\n\r\n${strmsg}\n`; session.send = ts.server.Session.prototype.send; @@ -475,7 +474,7 @@ describe("unittests:: tsserver:: Session:: exceptions", () => { useSingleInferredProject: false, useInferredProjectPerProjectRoot: false, typingsInstaller: undefined!, // TODO: GH#18217 - byteLength: Utils.byteLength, + byteLength: Buffer.byteLength, hrtime: process.hrtime, logger: nullLogger(), canUseEvents: true @@ -522,7 +521,7 @@ describe("unittests:: tsserver:: Session:: how Session is extendable via subclas useSingleInferredProject: false, useInferredProjectPerProjectRoot: false, typingsInstaller: undefined!, // TODO: GH#18217 - byteLength: Utils.byteLength, + byteLength: Buffer.byteLength, hrtime: process.hrtime, logger: createHasErrorMessageLogger(), canUseEvents: true @@ -590,7 +589,7 @@ describe("unittests:: tsserver:: Session:: an example of using the Session API t useSingleInferredProject: false, useInferredProjectPerProjectRoot: false, typingsInstaller: undefined!, // TODO: GH#18217 - byteLength: Utils.byteLength, + byteLength: Buffer.byteLength, hrtime: process.hrtime, logger: createHasErrorMessageLogger(), canUseEvents: true diff --git a/src/tsconfig-base.json b/src/tsconfig-base.json index d0efb21a159c0..053c85b5e4cf8 100644 --- a/src/tsconfig-base.json +++ b/src/tsconfig-base.json @@ -16,12 +16,13 @@ "noEmitOnError": true, "emitDeclarationOnly": true, - "strictNullChecks": true, - "noImplicitAny": true, - "noImplicitThis": true, - "strictPropertyInitialization": true, + "strict": true, + "strictBindCallApply": false, + "useUnknownInCatchVariables": false, + "noUnusedLocals": true, "noUnusedParameters": true, + "allowUnusedLabels": false, "skipLibCheck": true, diff --git a/src/typingsInstallerCore/typingsInstaller.ts b/src/typingsInstallerCore/typingsInstaller.ts index 3300603c6ccfa..f65e735ffe6db 100644 --- a/src/typingsInstallerCore/typingsInstaller.ts +++ b/src/typingsInstallerCore/typingsInstaller.ts @@ -136,8 +136,8 @@ const enum ProjectWatcherType { type ProjectWatchers = Map & { isInvoked?: boolean; }; -function getDetailWatchInfo(projectName: string, watchers: ProjectWatchers) { - return `Project: ${projectName} watcher already invoked: ${watchers.isInvoked}`; +function getDetailWatchInfo(projectName: string, watchers: ProjectWatchers | undefined) { + return `Project: ${projectName} watcher already invoked: ${watchers?.isInvoked}`; } export abstract class TypingsInstaller { diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index 695ea34540129..35d7f3eab8a10 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -3729,7 +3729,7 @@ declare namespace ts { private enableRequestedPluginsForProjectAsync; configurePlugin(args: protocol.ConfigurePluginRequestArguments): void; } - function formatMessage(msg: T, logger: Logger, byteLength: (s: string, encoding: string) => number, newLine: string): string; + function formatMessage(msg: T, logger: Logger, byteLength: (s: string, encoding: BufferEncoding) => number, newLine: string): string; interface ServerCancellationToken extends HostCancellationToken { setRequest(requestId: number): void; resetRequest(requestId: number): void; @@ -3751,8 +3751,14 @@ declare namespace ts { useSingleInferredProject: boolean; useInferredProjectPerProjectRoot: boolean; typingsInstaller: ITypingsInstaller; - byteLength: (buf: string, encoding?: string) => number; - hrtime: (start?: number[]) => number[]; + byteLength: (buf: string, encoding?: BufferEncoding) => number; + hrtime: (start?: [ + number, + number + ]) => [ + number, + number + ]; logger: Logger; /** * If falsy, all events are suppressed. @@ -3781,7 +3787,7 @@ declare namespace ts { protected host: ServerHost; private readonly cancellationToken; protected readonly typingsInstaller: ITypingsInstaller; - protected byteLength: (buf: string, encoding?: string) => number; + protected byteLength: (buf: string, encoding?: BufferEncoding) => number; private hrtime; protected logger: Logger; protected canUseEvents: boolean; @@ -7822,10 +7828,10 @@ declare namespace ts { updateJSDocReadonlyTag(node: JSDocReadonlyTag, tagName: Identifier | undefined, comment: string | NodeArray | undefined): JSDocReadonlyTag; createJSDocUnknownTag(tagName: Identifier, comment?: string | NodeArray): JSDocUnknownTag; updateJSDocUnknownTag(node: JSDocUnknownTag, tagName: Identifier, comment: string | NodeArray | undefined): JSDocUnknownTag; - createJSDocDeprecatedTag(tagName: Identifier, comment?: string | NodeArray): JSDocDeprecatedTag; - updateJSDocDeprecatedTag(node: JSDocDeprecatedTag, tagName: Identifier, comment?: string | NodeArray): JSDocDeprecatedTag; - createJSDocOverrideTag(tagName: Identifier, comment?: string | NodeArray): JSDocOverrideTag; - updateJSDocOverrideTag(node: JSDocOverrideTag, tagName: Identifier, comment?: string | NodeArray): JSDocOverrideTag; + createJSDocDeprecatedTag(tagName: Identifier | undefined, comment?: string | NodeArray): JSDocDeprecatedTag; + updateJSDocDeprecatedTag(node: JSDocDeprecatedTag, tagName: Identifier | undefined, comment?: string | NodeArray): JSDocDeprecatedTag; + createJSDocOverrideTag(tagName: Identifier | undefined, comment?: string | NodeArray): JSDocOverrideTag; + updateJSDocOverrideTag(node: JSDocOverrideTag, tagName: Identifier | undefined, comment?: string | NodeArray): JSDocOverrideTag; createJSDocThrowsTag(tagName: Identifier, typeExpression: JSDocTypeExpression | undefined, comment?: string | NodeArray): JSDocThrowsTag; updateJSDocThrowsTag(node: JSDocThrowsTag, tagName: Identifier | undefined, typeExpression: JSDocTypeExpression | undefined, comment?: string | NodeArray | undefined): JSDocThrowsTag; createJSDocSatisfiesTag(tagName: Identifier | undefined, typeExpression: JSDocTypeExpression, comment?: string | NodeArray): JSDocSatisfiesTag; @@ -8192,16 +8198,39 @@ declare namespace ts { /** * A function that accepts and possibly transforms a node. */ - type Visitor = (node: Node) => VisitResult; + type Visitor = (node: TIn) => VisitResult; + /** + * A function that walks a node using the given visitor, lifting node arrays into single nodes, + * returning an node which satisfies the test. + * + * - If the input node is undefined, then the output is undefined. + * - If the visitor returns undefined, then the output is undefined. + * - If the output node is not undefined, then it will satisfy the test function. + * - In order to obtain a return type that is more specific than `Node`, a test + * function _must_ be provided, and that function must be a type predicate. + * + * For the canonical implementation of this type, @see {visitNode}. + */ interface NodeVisitor { - (nodes: T, visitor: Visitor | undefined, test?: (node: Node) => boolean, lift?: (node: readonly Node[]) => T): T; - (nodes: T | undefined, visitor: Visitor | undefined, test?: (node: Node) => boolean, lift?: (node: readonly Node[]) => T): T | undefined; + (node: TIn, visitor: Visitor, TVisited>, test: (node: Node) => node is TOut, lift?: (node: readonly Node[]) => Node): TOut | (TIn & undefined) | (TVisited & undefined); + (node: TIn, visitor: Visitor, TVisited>, test?: (node: Node) => boolean, lift?: (node: readonly Node[]) => Node): Node | (TIn & undefined) | (TVisited & undefined); } + /** + * A function that walks a node array using the given visitor, returning an array whose contents satisfy the test. + * + * - If the input node array is undefined, the output is undefined. + * - If the visitor can return undefined, the node it visits in the array will be reused. + * - If the output node array is not undefined, then its contents will satisfy the test. + * - In order to obtain a return type that is more specific than `NodeArray`, a test + * function _must_ be provided, and that function must be a type predicate. + * + * For the canonical implementation of this type, @see {visitNodes}. + */ interface NodesVisitor { - (nodes: NodeArray, visitor: Visitor | undefined, test?: (node: Node) => boolean, start?: number, count?: number): NodeArray; - (nodes: NodeArray | undefined, visitor: Visitor | undefined, test?: (node: Node) => boolean, start?: number, count?: number): NodeArray | undefined; + | undefined, TOut extends Node>(nodes: TInArray, visitor: Visitor, test: (node: Node) => node is TOut, start?: number, count?: number): NodeArray | (TInArray & undefined); + | undefined>(nodes: TInArray, visitor: Visitor, test?: (node: Node) => boolean, start?: number, count?: number): NodeArray | (TInArray & undefined); } - type VisitResult = T | readonly T[] | undefined; + type VisitResult = T | readonly Node[]; interface Printer { /** * Print a node and its subtree as-is, without any emit transformations. @@ -8415,6 +8444,7 @@ declare namespace ts { } type FileWatcherCallback = (fileName: string, eventKind: FileWatcherEventKind, modifiedTime?: Date) => void; type DirectoryWatcherCallback = (fileName: string) => void; + type BufferEncoding = "ascii" | "utf8" | "utf-8" | "utf16le" | "ucs2" | "ucs-2" | "base64" | "latin1" | "binary" | "hex"; interface System { args: string[]; newLine: string; @@ -8473,8 +8503,8 @@ declare namespace ts { function forEachLeadingCommentRange(text: string, pos: number, cb: (pos: number, end: number, kind: CommentKind, hasTrailingNewLine: boolean, state: T) => U, state: T): U | undefined; function forEachTrailingCommentRange(text: string, pos: number, cb: (pos: number, end: number, kind: CommentKind, hasTrailingNewLine: boolean) => U): U | undefined; function forEachTrailingCommentRange(text: string, pos: number, cb: (pos: number, end: number, kind: CommentKind, hasTrailingNewLine: boolean, state: T) => U, state: T): U | undefined; - function reduceEachLeadingCommentRange(text: string, pos: number, cb: (pos: number, end: number, kind: CommentKind, hasTrailingNewLine: boolean, state: T, memo: U) => U, state: T, initial: U): U | undefined; - function reduceEachTrailingCommentRange(text: string, pos: number, cb: (pos: number, end: number, kind: CommentKind, hasTrailingNewLine: boolean, state: T, memo: U) => U, state: T, initial: U): U | undefined; + function reduceEachLeadingCommentRange(text: string, pos: number, cb: (pos: number, end: number, kind: CommentKind, hasTrailingNewLine: boolean, state: T) => U, state: T, initial: U): U | undefined; + function reduceEachTrailingCommentRange(text: string, pos: number, cb: (pos: number, end: number, kind: CommentKind, hasTrailingNewLine: boolean, state: T) => U, state: T, initial: U): U | undefined; function getLeadingCommentRanges(text: string, pos: number): CommentRange[] | undefined; function getTrailingCommentRanges(text: string, pos: number): CommentRange[] | undefined; /** Optionally, get the shebang */ @@ -8553,7 +8583,7 @@ declare namespace ts { function getTypeParameterOwner(d: Declaration): Declaration | undefined; function isParameterPropertyDeclaration(node: Node, parent: Node): node is ParameterPropertyDeclaration; function isEmptyBindingPattern(node: BindingName): node is BindingPattern; - function isEmptyBindingElement(node: BindingElement): boolean; + function isEmptyBindingElement(node: BindingElement | ArrayBindingElement): boolean; function walkUpBindingElementsAndPatterns(binding: BindingElement): VariableDeclaration | ParameterDeclaration; function getCombinedModifierFlags(node: Declaration): ModifierFlags; function getCombinedNodeFlags(node: Node): NodeFlags; @@ -8570,7 +8600,7 @@ declare namespace ts { function getOriginalNode(node: Node): Node; function getOriginalNode(node: Node, nodeTest: (node: Node) => node is T): T; function getOriginalNode(node: Node | undefined): Node | undefined; - function getOriginalNode(node: Node | undefined, nodeTest: (node: Node | undefined) => node is T): T | undefined; + function getOriginalNode(node: Node | undefined, nodeTest: (node: Node) => node is T): T | undefined; /** * Iterates through the parent chain of a node and performs the callback on each parent until the callback * returns a truthy value, then returns that value. @@ -9288,41 +9318,65 @@ declare namespace ts { /** * Visits a Node using the supplied visitor, possibly returning a new Node in its place. * + * - If the input node is undefined, then the output is undefined. + * - If the visitor returns undefined, then the output is undefined. + * - If the output node is not undefined, then it will satisfy the test function. + * - In order to obtain a return type that is more specific than `Node`, a test + * function _must_ be provided, and that function must be a type predicate. + * * @param node The Node to visit. * @param visitor The callback used to visit the Node. * @param test A callback to execute to verify the Node is valid. * @param lift An optional callback to execute to lift a NodeArray into a valid Node. */ - function visitNode(node: T, visitor: Visitor | undefined, test?: (node: Node) => boolean, lift?: (node: readonly Node[]) => T): T; + function visitNode(node: TIn, visitor: Visitor, TVisited>, test: (node: Node) => node is TOut, lift?: (node: readonly Node[]) => Node): TOut | (TIn & undefined) | (TVisited & undefined); /** * Visits a Node using the supplied visitor, possibly returning a new Node in its place. * + * - If the input node is undefined, then the output is undefined. + * - If the visitor returns undefined, then the output is undefined. + * - If the output node is not undefined, then it will satisfy the test function. + * - In order to obtain a return type that is more specific than `Node`, a test + * function _must_ be provided, and that function must be a type predicate. + * * @param node The Node to visit. * @param visitor The callback used to visit the Node. * @param test A callback to execute to verify the Node is valid. * @param lift An optional callback to execute to lift a NodeArray into a valid Node. */ - function visitNode(node: T | undefined, visitor: Visitor | undefined, test?: (node: Node) => boolean, lift?: (node: readonly Node[]) => T): T | undefined; + function visitNode(node: TIn, visitor: Visitor, TVisited>, test?: (node: Node) => boolean, lift?: (node: readonly Node[]) => Node): Node | (TIn & undefined) | (TVisited & undefined); /** * Visits a NodeArray using the supplied visitor, possibly returning a new NodeArray in its place. * + * - If the input node array is undefined, the output is undefined. + * - If the visitor can return undefined, the node it visits in the array will be reused. + * - If the output node array is not undefined, then its contents will satisfy the test. + * - In order to obtain a return type that is more specific than `NodeArray`, a test + * function _must_ be provided, and that function must be a type predicate. + * * @param nodes The NodeArray to visit. * @param visitor The callback used to visit a Node. * @param test A node test to execute for each node. * @param start An optional value indicating the starting offset at which to start visiting. * @param count An optional value indicating the maximum number of nodes to visit. */ - function visitNodes(nodes: NodeArray, visitor: Visitor | undefined, test?: (node: Node) => boolean, start?: number, count?: number): NodeArray; + function visitNodes | undefined, TOut extends Node>(nodes: TInArray, visitor: Visitor, test: (node: Node) => node is TOut, start?: number, count?: number): NodeArray | (TInArray & undefined); /** * Visits a NodeArray using the supplied visitor, possibly returning a new NodeArray in its place. * + * - If the input node array is undefined, the output is undefined. + * - If the visitor can return undefined, the node it visits in the array will be reused. + * - If the output node array is not undefined, then its contents will satisfy the test. + * - In order to obtain a return type that is more specific than `NodeArray`, a test + * function _must_ be provided, and that function must be a type predicate. + * * @param nodes The NodeArray to visit. * @param visitor The callback used to visit a Node. * @param test A node test to execute for each node. * @param start An optional value indicating the starting offset at which to start visiting. * @param count An optional value indicating the maximum number of nodes to visit. */ - function visitNodes(nodes: NodeArray | undefined, visitor: Visitor | undefined, test?: (node: Node) => boolean, start?: number, count?: number): NodeArray | undefined; + function visitNodes | undefined>(nodes: TInArray, visitor: Visitor, test?: (node: Node) => boolean, start?: number, count?: number): NodeArray | (TInArray & undefined); /** * Starts a new lexical environment and visits a statement list, ending the lexical environment * and merging hoisted declarations upon completion. diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index 32b2585c29f7e..6c4dd8cf96b43 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -3887,10 +3887,10 @@ declare namespace ts { updateJSDocReadonlyTag(node: JSDocReadonlyTag, tagName: Identifier | undefined, comment: string | NodeArray | undefined): JSDocReadonlyTag; createJSDocUnknownTag(tagName: Identifier, comment?: string | NodeArray): JSDocUnknownTag; updateJSDocUnknownTag(node: JSDocUnknownTag, tagName: Identifier, comment: string | NodeArray | undefined): JSDocUnknownTag; - createJSDocDeprecatedTag(tagName: Identifier, comment?: string | NodeArray): JSDocDeprecatedTag; - updateJSDocDeprecatedTag(node: JSDocDeprecatedTag, tagName: Identifier, comment?: string | NodeArray): JSDocDeprecatedTag; - createJSDocOverrideTag(tagName: Identifier, comment?: string | NodeArray): JSDocOverrideTag; - updateJSDocOverrideTag(node: JSDocOverrideTag, tagName: Identifier, comment?: string | NodeArray): JSDocOverrideTag; + createJSDocDeprecatedTag(tagName: Identifier | undefined, comment?: string | NodeArray): JSDocDeprecatedTag; + updateJSDocDeprecatedTag(node: JSDocDeprecatedTag, tagName: Identifier | undefined, comment?: string | NodeArray): JSDocDeprecatedTag; + createJSDocOverrideTag(tagName: Identifier | undefined, comment?: string | NodeArray): JSDocOverrideTag; + updateJSDocOverrideTag(node: JSDocOverrideTag, tagName: Identifier | undefined, comment?: string | NodeArray): JSDocOverrideTag; createJSDocThrowsTag(tagName: Identifier, typeExpression: JSDocTypeExpression | undefined, comment?: string | NodeArray): JSDocThrowsTag; updateJSDocThrowsTag(node: JSDocThrowsTag, tagName: Identifier | undefined, typeExpression: JSDocTypeExpression | undefined, comment?: string | NodeArray | undefined): JSDocThrowsTag; createJSDocSatisfiesTag(tagName: Identifier | undefined, typeExpression: JSDocTypeExpression, comment?: string | NodeArray): JSDocSatisfiesTag; @@ -4257,16 +4257,39 @@ declare namespace ts { /** * A function that accepts and possibly transforms a node. */ - type Visitor = (node: Node) => VisitResult; + type Visitor = (node: TIn) => VisitResult; + /** + * A function that walks a node using the given visitor, lifting node arrays into single nodes, + * returning an node which satisfies the test. + * + * - If the input node is undefined, then the output is undefined. + * - If the visitor returns undefined, then the output is undefined. + * - If the output node is not undefined, then it will satisfy the test function. + * - In order to obtain a return type that is more specific than `Node`, a test + * function _must_ be provided, and that function must be a type predicate. + * + * For the canonical implementation of this type, @see {visitNode}. + */ interface NodeVisitor { - (nodes: T, visitor: Visitor | undefined, test?: (node: Node) => boolean, lift?: (node: readonly Node[]) => T): T; - (nodes: T | undefined, visitor: Visitor | undefined, test?: (node: Node) => boolean, lift?: (node: readonly Node[]) => T): T | undefined; + (node: TIn, visitor: Visitor, TVisited>, test: (node: Node) => node is TOut, lift?: (node: readonly Node[]) => Node): TOut | (TIn & undefined) | (TVisited & undefined); + (node: TIn, visitor: Visitor, TVisited>, test?: (node: Node) => boolean, lift?: (node: readonly Node[]) => Node): Node | (TIn & undefined) | (TVisited & undefined); } + /** + * A function that walks a node array using the given visitor, returning an array whose contents satisfy the test. + * + * - If the input node array is undefined, the output is undefined. + * - If the visitor can return undefined, the node it visits in the array will be reused. + * - If the output node array is not undefined, then its contents will satisfy the test. + * - In order to obtain a return type that is more specific than `NodeArray`, a test + * function _must_ be provided, and that function must be a type predicate. + * + * For the canonical implementation of this type, @see {visitNodes}. + */ interface NodesVisitor { - (nodes: NodeArray, visitor: Visitor | undefined, test?: (node: Node) => boolean, start?: number, count?: number): NodeArray; - (nodes: NodeArray | undefined, visitor: Visitor | undefined, test?: (node: Node) => boolean, start?: number, count?: number): NodeArray | undefined; + | undefined, TOut extends Node>(nodes: TInArray, visitor: Visitor, test: (node: Node) => node is TOut, start?: number, count?: number): NodeArray | (TInArray & undefined); + | undefined>(nodes: TInArray, visitor: Visitor, test?: (node: Node) => boolean, start?: number, count?: number): NodeArray | (TInArray & undefined); } - type VisitResult = T | readonly T[] | undefined; + type VisitResult = T | readonly Node[]; interface Printer { /** * Print a node and its subtree as-is, without any emit transformations. @@ -4480,6 +4503,7 @@ declare namespace ts { } type FileWatcherCallback = (fileName: string, eventKind: FileWatcherEventKind, modifiedTime?: Date) => void; type DirectoryWatcherCallback = (fileName: string) => void; + type BufferEncoding = "ascii" | "utf8" | "utf-8" | "utf16le" | "ucs2" | "ucs-2" | "base64" | "latin1" | "binary" | "hex"; interface System { args: string[]; newLine: string; @@ -4538,8 +4562,8 @@ declare namespace ts { function forEachLeadingCommentRange(text: string, pos: number, cb: (pos: number, end: number, kind: CommentKind, hasTrailingNewLine: boolean, state: T) => U, state: T): U | undefined; function forEachTrailingCommentRange(text: string, pos: number, cb: (pos: number, end: number, kind: CommentKind, hasTrailingNewLine: boolean) => U): U | undefined; function forEachTrailingCommentRange(text: string, pos: number, cb: (pos: number, end: number, kind: CommentKind, hasTrailingNewLine: boolean, state: T) => U, state: T): U | undefined; - function reduceEachLeadingCommentRange(text: string, pos: number, cb: (pos: number, end: number, kind: CommentKind, hasTrailingNewLine: boolean, state: T, memo: U) => U, state: T, initial: U): U | undefined; - function reduceEachTrailingCommentRange(text: string, pos: number, cb: (pos: number, end: number, kind: CommentKind, hasTrailingNewLine: boolean, state: T, memo: U) => U, state: T, initial: U): U | undefined; + function reduceEachLeadingCommentRange(text: string, pos: number, cb: (pos: number, end: number, kind: CommentKind, hasTrailingNewLine: boolean, state: T) => U, state: T, initial: U): U | undefined; + function reduceEachTrailingCommentRange(text: string, pos: number, cb: (pos: number, end: number, kind: CommentKind, hasTrailingNewLine: boolean, state: T) => U, state: T, initial: U): U | undefined; function getLeadingCommentRanges(text: string, pos: number): CommentRange[] | undefined; function getTrailingCommentRanges(text: string, pos: number): CommentRange[] | undefined; /** Optionally, get the shebang */ @@ -4618,7 +4642,7 @@ declare namespace ts { function getTypeParameterOwner(d: Declaration): Declaration | undefined; function isParameterPropertyDeclaration(node: Node, parent: Node): node is ParameterPropertyDeclaration; function isEmptyBindingPattern(node: BindingName): node is BindingPattern; - function isEmptyBindingElement(node: BindingElement): boolean; + function isEmptyBindingElement(node: BindingElement | ArrayBindingElement): boolean; function walkUpBindingElementsAndPatterns(binding: BindingElement): VariableDeclaration | ParameterDeclaration; function getCombinedModifierFlags(node: Declaration): ModifierFlags; function getCombinedNodeFlags(node: Node): NodeFlags; @@ -4635,7 +4659,7 @@ declare namespace ts { function getOriginalNode(node: Node): Node; function getOriginalNode(node: Node, nodeTest: (node: Node) => node is T): T; function getOriginalNode(node: Node | undefined): Node | undefined; - function getOriginalNode(node: Node | undefined, nodeTest: (node: Node | undefined) => node is T): T | undefined; + function getOriginalNode(node: Node | undefined, nodeTest: (node: Node) => node is T): T | undefined; /** * Iterates through the parent chain of a node and performs the callback on each parent until the callback * returns a truthy value, then returns that value. @@ -5353,41 +5377,65 @@ declare namespace ts { /** * Visits a Node using the supplied visitor, possibly returning a new Node in its place. * + * - If the input node is undefined, then the output is undefined. + * - If the visitor returns undefined, then the output is undefined. + * - If the output node is not undefined, then it will satisfy the test function. + * - In order to obtain a return type that is more specific than `Node`, a test + * function _must_ be provided, and that function must be a type predicate. + * * @param node The Node to visit. * @param visitor The callback used to visit the Node. * @param test A callback to execute to verify the Node is valid. * @param lift An optional callback to execute to lift a NodeArray into a valid Node. */ - function visitNode(node: T, visitor: Visitor | undefined, test?: (node: Node) => boolean, lift?: (node: readonly Node[]) => T): T; + function visitNode(node: TIn, visitor: Visitor, TVisited>, test: (node: Node) => node is TOut, lift?: (node: readonly Node[]) => Node): TOut | (TIn & undefined) | (TVisited & undefined); /** * Visits a Node using the supplied visitor, possibly returning a new Node in its place. * + * - If the input node is undefined, then the output is undefined. + * - If the visitor returns undefined, then the output is undefined. + * - If the output node is not undefined, then it will satisfy the test function. + * - In order to obtain a return type that is more specific than `Node`, a test + * function _must_ be provided, and that function must be a type predicate. + * * @param node The Node to visit. * @param visitor The callback used to visit the Node. * @param test A callback to execute to verify the Node is valid. * @param lift An optional callback to execute to lift a NodeArray into a valid Node. */ - function visitNode(node: T | undefined, visitor: Visitor | undefined, test?: (node: Node) => boolean, lift?: (node: readonly Node[]) => T): T | undefined; + function visitNode(node: TIn, visitor: Visitor, TVisited>, test?: (node: Node) => boolean, lift?: (node: readonly Node[]) => Node): Node | (TIn & undefined) | (TVisited & undefined); /** * Visits a NodeArray using the supplied visitor, possibly returning a new NodeArray in its place. * + * - If the input node array is undefined, the output is undefined. + * - If the visitor can return undefined, the node it visits in the array will be reused. + * - If the output node array is not undefined, then its contents will satisfy the test. + * - In order to obtain a return type that is more specific than `NodeArray`, a test + * function _must_ be provided, and that function must be a type predicate. + * * @param nodes The NodeArray to visit. * @param visitor The callback used to visit a Node. * @param test A node test to execute for each node. * @param start An optional value indicating the starting offset at which to start visiting. * @param count An optional value indicating the maximum number of nodes to visit. */ - function visitNodes(nodes: NodeArray, visitor: Visitor | undefined, test?: (node: Node) => boolean, start?: number, count?: number): NodeArray; + function visitNodes | undefined, TOut extends Node>(nodes: TInArray, visitor: Visitor, test: (node: Node) => node is TOut, start?: number, count?: number): NodeArray | (TInArray & undefined); /** * Visits a NodeArray using the supplied visitor, possibly returning a new NodeArray in its place. * + * - If the input node array is undefined, the output is undefined. + * - If the visitor can return undefined, the node it visits in the array will be reused. + * - If the output node array is not undefined, then its contents will satisfy the test. + * - In order to obtain a return type that is more specific than `NodeArray`, a test + * function _must_ be provided, and that function must be a type predicate. + * * @param nodes The NodeArray to visit. * @param visitor The callback used to visit a Node. * @param test A node test to execute for each node. * @param start An optional value indicating the starting offset at which to start visiting. * @param count An optional value indicating the maximum number of nodes to visit. */ - function visitNodes(nodes: NodeArray | undefined, visitor: Visitor | undefined, test?: (node: Node) => boolean, start?: number, count?: number): NodeArray | undefined; + function visitNodes | undefined>(nodes: TInArray, visitor: Visitor, test?: (node: Node) => boolean, start?: number, count?: number): NodeArray | (TInArray & undefined); /** * Starts a new lexical environment and visits a statement list, ending the lexical environment * and merging hoisted declarations upon completion.