1/*@internal*/ 2namespace ts { 3 export function getDeclarationDiagnostics(host: EmitHost, resolver: EmitResolver, file: SourceFile | undefined): DiagnosticWithLocation[] | undefined { 4 const compilerOptions = host.getCompilerOptions(); 5 const result = transformNodes(resolver, host, factory, compilerOptions, file ? [file] : filter(host.getSourceFiles(), isSourceFileNotJson), [transformDeclarations], /*allowDtsFiles*/ false); 6 return result.diagnostics; 7 } 8 9 function hasInternalAnnotation(range: CommentRange, currentSourceFile: SourceFile) { 10 const comment = currentSourceFile.text.substring(range.pos, range.end); 11 return stringContains(comment, "@internal"); 12 } 13 14 export function isInternalDeclaration(node: Node, currentSourceFile: SourceFile) { 15 const parseTreeNode = getParseTreeNode(node); 16 if (parseTreeNode && parseTreeNode.kind === SyntaxKind.Parameter) { 17 const paramIdx = (parseTreeNode.parent as SignatureDeclaration).parameters.indexOf(parseTreeNode as ParameterDeclaration); 18 const previousSibling = paramIdx > 0 ? (parseTreeNode.parent as SignatureDeclaration).parameters[paramIdx - 1] : undefined; 19 const text = currentSourceFile.text; 20 const commentRanges = previousSibling 21 ? concatenate( 22 // to handle 23 // ... parameters, /* @internal */ 24 // public param: string 25 getTrailingCommentRanges(text, skipTrivia(text, previousSibling.end + 1, /* stopAfterLineBreak */ false, /* stopAtComments */ true)), 26 getLeadingCommentRanges(text, node.pos) 27 ) 28 : getTrailingCommentRanges(text, skipTrivia(text, node.pos, /* stopAfterLineBreak */ false, /* stopAtComments */ true)); 29 return commentRanges && commentRanges.length && hasInternalAnnotation(last(commentRanges), currentSourceFile); 30 } 31 const leadingCommentRanges = parseTreeNode && getLeadingCommentRangesOfNode(parseTreeNode, currentSourceFile); 32 return !!forEach(leadingCommentRanges, range => { 33 return hasInternalAnnotation(range, currentSourceFile); 34 }); 35 } 36 37 const declarationEmitNodeBuilderFlags = 38 NodeBuilderFlags.MultilineObjectLiterals | 39 NodeBuilderFlags.WriteClassExpressionAsTypeLiteral | 40 NodeBuilderFlags.UseTypeOfFunction | 41 NodeBuilderFlags.UseStructuralFallback | 42 NodeBuilderFlags.AllowEmptyTuple | 43 NodeBuilderFlags.GenerateNamesForShadowedTypeParams | 44 NodeBuilderFlags.NoTruncation; 45 46 /** 47 * Transforms a ts file into a .d.ts or .d.ets file 48 * This process requires type information, which is retrieved through the emit resolver. Because of this, 49 * in many places this transformer assumes it will be operating on parse tree nodes directly. 50 * This means that _no transforms should be allowed to occur before this one_. 51 */ 52 53 export function transformDeclarations(context: TransformationContext) { 54 const throwDiagnostic = () => Debug.fail("Diagnostic emitted without context"); 55 let getSymbolAccessibilityDiagnostic: GetSymbolAccessibilityDiagnostic = throwDiagnostic; 56 let needsDeclare = true; 57 let isBundledEmit = false; 58 let resultHasExternalModuleIndicator = false; 59 let needsScopeFixMarker = false; 60 let resultHasScopeMarker = false; 61 let enclosingDeclaration: Node; 62 let necessaryTypeReferences: Set<[specifier: string, mode: SourceFile["impliedNodeFormat"] | undefined]> | undefined; 63 let lateMarkedStatements: LateVisibilityPaintedStatement[] | undefined; 64 let lateStatementReplacementMap: ESMap<NodeId, VisitResult<LateVisibilityPaintedStatement | ExportAssignment>>; 65 let suppressNewDiagnosticContexts: boolean; 66 let exportedModulesFromDeclarationEmit: Symbol[] | undefined; 67 68 const { factory } = context; 69 const host = context.getEmitHost(); 70 const symbolTracker: SymbolTracker = { 71 trackSymbol, 72 reportInaccessibleThisError, 73 reportInaccessibleUniqueSymbolError, 74 reportCyclicStructureError, 75 reportPrivateInBaseOfClassExpression, 76 reportLikelyUnsafeImportRequiredError, 77 reportTruncationError, 78 moduleResolverHost: host, 79 trackReferencedAmbientModule, 80 trackExternalModuleSymbolOfImportTypeNode, 81 reportNonlocalAugmentation, 82 reportNonSerializableProperty, 83 reportImportTypeNodeResolutionModeOverride, 84 }; 85 let errorNameNode: DeclarationName | undefined; 86 let errorFallbackNode: Declaration | undefined; 87 88 let currentSourceFile: SourceFile; 89 let refs: ESMap<NodeId, SourceFile>; 90 let libs: ESMap<string, boolean>; 91 let emittedImports: readonly AnyImportSyntax[] | undefined; // must be declared in container so it can be `undefined` while transformer's first pass 92 const resolver = context.getEmitResolver(); 93 const options = context.getCompilerOptions(); 94 const { noResolve, stripInternal } = options; 95 return transformRoot; 96 97 function recordTypeReferenceDirectivesIfNecessary(typeReferenceDirectives: readonly [specifier: string, mode: SourceFile["impliedNodeFormat"] | undefined][] | undefined): void { 98 if (!typeReferenceDirectives) { 99 return; 100 } 101 necessaryTypeReferences = necessaryTypeReferences || new Set(); 102 for (const ref of typeReferenceDirectives) { 103 necessaryTypeReferences.add(ref); 104 } 105 } 106 107 function trackReferencedAmbientModule(node: ModuleDeclaration, symbol: Symbol) { 108 // If it is visible via `// <reference types="..."/>`, then we should just use that 109 const directives = resolver.getTypeReferenceDirectivesForSymbol(symbol, SymbolFlags.All); 110 if (length(directives)) { 111 return recordTypeReferenceDirectivesIfNecessary(directives); 112 } 113 // Otherwise we should emit a path-based reference 114 const container = getSourceFileOfNode(node); 115 refs.set(getOriginalNodeId(container), container); 116 } 117 118 function handleSymbolAccessibilityError(symbolAccessibilityResult: SymbolAccessibilityResult) { 119 if (symbolAccessibilityResult.accessibility === SymbolAccessibility.Accessible) { 120 // Add aliases back onto the possible imports list if they're not there so we can try them again with updated visibility info 121 if (symbolAccessibilityResult && symbolAccessibilityResult.aliasesToMakeVisible) { 122 if (!lateMarkedStatements) { 123 lateMarkedStatements = symbolAccessibilityResult.aliasesToMakeVisible; 124 } 125 else { 126 for (const ref of symbolAccessibilityResult.aliasesToMakeVisible) { 127 pushIfUnique(lateMarkedStatements, ref); 128 } 129 } 130 } 131 132 // TODO: Do all these accessibility checks inside/after the first pass in the checker when declarations are enabled, if possible 133 } 134 else { 135 // Report error 136 const errorInfo = getSymbolAccessibilityDiagnostic(symbolAccessibilityResult); 137 if (errorInfo) { 138 if (errorInfo.typeName) { 139 context.addDiagnostic(createDiagnosticForNode(symbolAccessibilityResult.errorNode || errorInfo.errorNode, 140 errorInfo.diagnosticMessage, 141 getTextOfNode(errorInfo.typeName), 142 symbolAccessibilityResult.errorSymbolName, 143 symbolAccessibilityResult.errorModuleName)); 144 } 145 else { 146 context.addDiagnostic(createDiagnosticForNode(symbolAccessibilityResult.errorNode || errorInfo.errorNode, 147 errorInfo.diagnosticMessage, 148 symbolAccessibilityResult.errorSymbolName, 149 symbolAccessibilityResult.errorModuleName)); 150 } 151 return true; 152 } 153 } 154 return false; 155 } 156 157 function trackExternalModuleSymbolOfImportTypeNode(symbol: Symbol) { 158 if (!isBundledEmit) { 159 (exportedModulesFromDeclarationEmit || (exportedModulesFromDeclarationEmit = [])).push(symbol); 160 } 161 } 162 163 function trackSymbol(symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags) { 164 if (symbol.flags & SymbolFlags.TypeParameter) return false; 165 const issuedDiagnostic = handleSymbolAccessibilityError(resolver.isSymbolAccessible(symbol, enclosingDeclaration, meaning, /*shouldComputeAliasesToMakeVisible*/ true)); 166 recordTypeReferenceDirectivesIfNecessary(resolver.getTypeReferenceDirectivesForSymbol(symbol, meaning)); 167 return issuedDiagnostic; 168 } 169 170 function reportPrivateInBaseOfClassExpression(propertyName: string) { 171 if (errorNameNode || errorFallbackNode) { 172 context.addDiagnostic( 173 createDiagnosticForNode((errorNameNode || errorFallbackNode)!, Diagnostics.Property_0_of_exported_class_expression_may_not_be_private_or_protected, propertyName)); 174 } 175 } 176 177 function errorDeclarationNameWithFallback() { 178 return errorNameNode ? declarationNameToString(errorNameNode) : 179 errorFallbackNode && getNameOfDeclaration(errorFallbackNode) ? declarationNameToString(getNameOfDeclaration(errorFallbackNode)) : 180 errorFallbackNode && isExportAssignment(errorFallbackNode) ? errorFallbackNode.isExportEquals ? "export=" : "default" : 181 "(Missing)"; // same fallback declarationNameToString uses when node is zero-width (ie, nameless) 182 } 183 184 function reportInaccessibleUniqueSymbolError() { 185 if (errorNameNode || errorFallbackNode) { 186 context.addDiagnostic(createDiagnosticForNode((errorNameNode || errorFallbackNode)!, Diagnostics.The_inferred_type_of_0_references_an_inaccessible_1_type_A_type_annotation_is_necessary, 187 errorDeclarationNameWithFallback(), 188 "unique symbol")); 189 } 190 } 191 192 function reportCyclicStructureError() { 193 if (errorNameNode || errorFallbackNode) { 194 context.addDiagnostic(createDiagnosticForNode((errorNameNode || errorFallbackNode)!, Diagnostics.The_inferred_type_of_0_references_a_type_with_a_cyclic_structure_which_cannot_be_trivially_serialized_A_type_annotation_is_necessary, 195 errorDeclarationNameWithFallback())); 196 } 197 } 198 199 function reportInaccessibleThisError() { 200 if (errorNameNode || errorFallbackNode) { 201 context.addDiagnostic(createDiagnosticForNode((errorNameNode || errorFallbackNode)!, Diagnostics.The_inferred_type_of_0_references_an_inaccessible_1_type_A_type_annotation_is_necessary, 202 errorDeclarationNameWithFallback(), 203 "this")); 204 } 205 } 206 207 function reportLikelyUnsafeImportRequiredError(specifier: string) { 208 if (errorNameNode || errorFallbackNode) { 209 context.addDiagnostic(createDiagnosticForNode((errorNameNode || errorFallbackNode)!, Diagnostics.The_inferred_type_of_0_cannot_be_named_without_a_reference_to_1_This_is_likely_not_portable_A_type_annotation_is_necessary, 210 errorDeclarationNameWithFallback(), 211 specifier)); 212 } 213 } 214 215 function reportTruncationError() { 216 if (errorNameNode || errorFallbackNode) { 217 context.addDiagnostic(createDiagnosticForNode((errorNameNode || errorFallbackNode)!, Diagnostics.The_inferred_type_of_this_node_exceeds_the_maximum_length_the_compiler_will_serialize_An_explicit_type_annotation_is_needed)); 218 } 219 } 220 221 function reportNonlocalAugmentation(containingFile: SourceFile, parentSymbol: Symbol, symbol: Symbol) { 222 const primaryDeclaration = parentSymbol.declarations?.find(d => getSourceFileOfNode(d) === containingFile); 223 const augmentingDeclarations = filter(symbol.declarations, d => getSourceFileOfNode(d) !== containingFile); 224 if (primaryDeclaration && augmentingDeclarations) { 225 for (const augmentations of augmentingDeclarations) { 226 context.addDiagnostic(addRelatedInfo( 227 createDiagnosticForNode(augmentations, Diagnostics.Declaration_augments_declaration_in_another_file_This_cannot_be_serialized), 228 createDiagnosticForNode(primaryDeclaration, Diagnostics.This_is_the_declaration_being_augmented_Consider_moving_the_augmenting_declaration_into_the_same_file) 229 )); 230 } 231 } 232 } 233 234 function reportNonSerializableProperty(propertyName: string) { 235 if (errorNameNode || errorFallbackNode) { 236 context.addDiagnostic(createDiagnosticForNode((errorNameNode || errorFallbackNode)!, Diagnostics.The_type_of_this_node_cannot_be_serialized_because_its_property_0_cannot_be_serialized, propertyName)); 237 } 238 } 239 240 function reportImportTypeNodeResolutionModeOverride() { 241 if (!isNightly() && (errorNameNode || errorFallbackNode)) { 242 context.addDiagnostic(createDiagnosticForNode((errorNameNode || errorFallbackNode)!, Diagnostics.The_type_of_this_expression_cannot_be_named_without_a_resolution_mode_assertion_which_is_an_unstable_feature_Use_nightly_TypeScript_to_silence_this_error_Try_updating_with_npm_install_D_typescript_next)); 243 } 244 } 245 246 function transformDeclarationsForJS(sourceFile: SourceFile, bundled?: boolean) { 247 const oldDiag = getSymbolAccessibilityDiagnostic; 248 getSymbolAccessibilityDiagnostic = (s) => (s.errorNode && canProduceDiagnostics(s.errorNode) ? createGetSymbolAccessibilityDiagnosticForNode(s.errorNode)(s) : ({ 249 diagnosticMessage: s.errorModuleName 250 ? Diagnostics.Declaration_emit_for_this_file_requires_using_private_name_0_from_module_1_An_explicit_type_annotation_may_unblock_declaration_emit 251 : Diagnostics.Declaration_emit_for_this_file_requires_using_private_name_0_An_explicit_type_annotation_may_unblock_declaration_emit, 252 errorNode: s.errorNode || sourceFile 253 })); 254 const result = resolver.getDeclarationStatementsForSourceFile(sourceFile, declarationEmitNodeBuilderFlags, symbolTracker, bundled); 255 getSymbolAccessibilityDiagnostic = oldDiag; 256 return result; 257 } 258 259 function transformRoot(node: Bundle): Bundle; 260 function transformRoot(node: SourceFile): SourceFile; 261 function transformRoot(node: SourceFile | Bundle): SourceFile | Bundle; 262 function transformRoot(node: SourceFile | Bundle) { 263 if (node.kind === SyntaxKind.SourceFile && node.isDeclarationFile) { 264 return node; 265 } 266 267 if (node.kind === SyntaxKind.Bundle) { 268 isBundledEmit = true; 269 refs = new Map(); 270 libs = new Map(); 271 let hasNoDefaultLib = false; 272 const bundle = factory.createBundle(map(node.sourceFiles, 273 sourceFile => { 274 if (sourceFile.isDeclarationFile) return undefined!; // Omit declaration files from bundle results, too // TODO: GH#18217 275 hasNoDefaultLib = hasNoDefaultLib || sourceFile.hasNoDefaultLib; 276 currentSourceFile = sourceFile; 277 enclosingDeclaration = sourceFile; 278 lateMarkedStatements = undefined; 279 suppressNewDiagnosticContexts = false; 280 lateStatementReplacementMap = new Map(); 281 getSymbolAccessibilityDiagnostic = throwDiagnostic; 282 needsScopeFixMarker = false; 283 resultHasScopeMarker = false; 284 collectReferences(sourceFile, refs); 285 collectLibs(sourceFile, libs); 286 if (isExternalOrCommonJsModule(sourceFile) || isJsonSourceFile(sourceFile)) { 287 resultHasExternalModuleIndicator = false; // unused in external module bundle emit (all external modules are within module blocks, therefore are known to be modules) 288 needsDeclare = false; 289 const statements = isSourceFileJS(sourceFile) ? factory.createNodeArray(transformDeclarationsForJS(sourceFile, /*bundled*/ true)) : visitNodes(sourceFile.statements, visitDeclarationStatements); 290 const newFile = factory.updateSourceFile(sourceFile, [factory.createModuleDeclaration( 291 [factory.createModifier(SyntaxKind.DeclareKeyword)], 292 factory.createStringLiteral(getResolvedExternalModuleName(context.getEmitHost(), sourceFile)), 293 factory.createModuleBlock(setTextRange(factory.createNodeArray(transformAndReplaceLatePaintedStatements(statements)), sourceFile.statements)) 294 )], /*isDeclarationFile*/ true, /*referencedFiles*/ [], /*typeReferences*/ [], /*hasNoDefaultLib*/ false, /*libReferences*/ []); 295 return newFile; 296 } 297 needsDeclare = true; 298 const updated = isSourceFileJS(sourceFile) ? factory.createNodeArray(transformDeclarationsForJS(sourceFile)) : visitNodes(sourceFile.statements, visitDeclarationStatements); 299 return factory.updateSourceFile(sourceFile, transformAndReplaceLatePaintedStatements(updated), /*isDeclarationFile*/ true, /*referencedFiles*/ [], /*typeReferences*/ [], /*hasNoDefaultLib*/ false, /*libReferences*/ []); 300 } 301 ), mapDefined(node.prepends, prepend => { 302 if (prepend.kind === SyntaxKind.InputFiles) { 303 const sourceFile = createUnparsedSourceFile(prepend, "dts", stripInternal); 304 hasNoDefaultLib = hasNoDefaultLib || !!sourceFile.hasNoDefaultLib; 305 collectReferences(sourceFile, refs); 306 recordTypeReferenceDirectivesIfNecessary(map(sourceFile.typeReferenceDirectives, ref => [ref.fileName, ref.resolutionMode])); 307 collectLibs(sourceFile, libs); 308 return sourceFile; 309 } 310 return prepend; 311 })); 312 bundle.syntheticFileReferences = []; 313 bundle.syntheticTypeReferences = getFileReferencesForUsedTypeReferences(); 314 bundle.syntheticLibReferences = getLibReferences(); 315 bundle.hasNoDefaultLib = hasNoDefaultLib; 316 const outputFilePath = getDirectoryPath(normalizeSlashes(getOutputPathsFor(node, host, /*forceDtsPaths*/ true).declarationFilePath!)); 317 const referenceVisitor = mapReferencesIntoArray(bundle.syntheticFileReferences as FileReference[], outputFilePath); 318 refs.forEach(referenceVisitor); 319 return bundle; 320 } 321 322 // Single source file 323 needsDeclare = true; 324 needsScopeFixMarker = false; 325 resultHasScopeMarker = false; 326 enclosingDeclaration = node; 327 currentSourceFile = node; 328 getSymbolAccessibilityDiagnostic = throwDiagnostic; 329 isBundledEmit = false; 330 resultHasExternalModuleIndicator = false; 331 suppressNewDiagnosticContexts = false; 332 lateMarkedStatements = undefined; 333 lateStatementReplacementMap = new Map(); 334 necessaryTypeReferences = undefined; 335 refs = collectReferences(currentSourceFile, new Map()); 336 libs = collectLibs(currentSourceFile, new Map()); 337 const references: FileReference[] = []; 338 const outputFilePath = getDirectoryPath(normalizeSlashes(getOutputPathsFor(node, host, /*forceDtsPaths*/ true).declarationFilePath!)); 339 const referenceVisitor = mapReferencesIntoArray(references, outputFilePath); 340 let combinedStatements: NodeArray<Statement>; 341 if (isSourceFileJS(currentSourceFile)) { 342 combinedStatements = factory.createNodeArray(transformDeclarationsForJS(node)); 343 refs.forEach(referenceVisitor); 344 emittedImports = filter(combinedStatements, isAnyImportSyntax); 345 } 346 else { 347 const statements = visitNodes(node.statements, visitDeclarationStatements); 348 combinedStatements = setTextRange(factory.createNodeArray(transformAndReplaceLatePaintedStatements(statements)), node.statements); 349 refs.forEach(referenceVisitor); 350 emittedImports = filter(combinedStatements, isAnyImportSyntax); 351 if (isExternalModule(node) && (!resultHasExternalModuleIndicator || (needsScopeFixMarker && !resultHasScopeMarker))) { 352 combinedStatements = setTextRange(factory.createNodeArray([...combinedStatements, createEmptyExports(factory)]), combinedStatements); 353 } 354 } 355 const updated = factory.updateSourceFile(node, combinedStatements, /*isDeclarationFile*/ true, references, getFileReferencesForUsedTypeReferences(), node.hasNoDefaultLib, getLibReferences()); 356 updated.exportedModulesFromDeclarationEmit = exportedModulesFromDeclarationEmit; 357 return updated; 358 359 function getLibReferences() { 360 return map(arrayFrom(libs.keys()), lib => ({ fileName: lib, pos: -1, end: -1 })); 361 } 362 363 function getFileReferencesForUsedTypeReferences() { 364 return necessaryTypeReferences ? mapDefined(arrayFrom(necessaryTypeReferences.keys()), getFileReferenceForSpecifierModeTuple) : []; 365 } 366 367 function getFileReferenceForSpecifierModeTuple([typeName, mode]: [specifier: string, mode: SourceFile["impliedNodeFormat"] | undefined]): FileReference | undefined { 368 // Elide type references for which we have imports 369 if (emittedImports) { 370 for (const importStatement of emittedImports) { 371 if (isImportEqualsDeclaration(importStatement) && isExternalModuleReference(importStatement.moduleReference)) { 372 const expr = importStatement.moduleReference.expression; 373 if (isStringLiteralLike(expr) && expr.text === typeName) { 374 return undefined; 375 } 376 } 377 else if (isImportDeclaration(importStatement) && isStringLiteral(importStatement.moduleSpecifier) && importStatement.moduleSpecifier.text === typeName) { 378 return undefined; 379 } 380 } 381 } 382 return { fileName: typeName, pos: -1, end: -1, ...(mode ? { resolutionMode: mode } : undefined) }; 383 } 384 385 function mapReferencesIntoArray(references: FileReference[], outputFilePath: string): (file: SourceFile) => void { 386 return file => { 387 let declFileName: string; 388 if (file.isDeclarationFile) { // Neither decl files or js should have their refs changed 389 declFileName = file.fileName; 390 } 391 else { 392 if (isBundledEmit && contains((node as Bundle).sourceFiles, file)) return; // Omit references to files which are being merged 393 const paths = getOutputPathsFor(file, host, /*forceDtsPaths*/ true); 394 declFileName = paths.declarationFilePath || paths.jsFilePath || file.fileName; 395 } 396 397 if (declFileName) { 398 const specifier = moduleSpecifiers.getModuleSpecifier( 399 options, 400 currentSourceFile, 401 toPath(outputFilePath, host.getCurrentDirectory(), host.getCanonicalFileName), 402 toPath(declFileName, host.getCurrentDirectory(), host.getCanonicalFileName), 403 host, 404 ); 405 if (!pathIsRelative(specifier)) { 406 // If some compiler option/symlink/whatever allows access to the file containing the ambient module declaration 407 // via a non-relative name, emit a type reference directive to that non-relative name, rather than 408 // a relative path to the declaration file 409 recordTypeReferenceDirectivesIfNecessary([[specifier, /*mode*/ undefined]]); 410 return; 411 } 412 413 let fileName = getRelativePathToDirectoryOrUrl( 414 outputFilePath, 415 declFileName, 416 host.getCurrentDirectory(), 417 host.getCanonicalFileName, 418 /*isAbsolutePathAnUrl*/ false 419 ); 420 if (startsWith(fileName, "./") && hasExtension(fileName)) { 421 fileName = fileName.substring(2); 422 } 423 424 // omit references to files from node_modules or oh_modules (npm may disambiguate module 425 // references when installing this package, making the path is unreliable). 426 if (isNodeModulesReference(fileName) || (isOhpm(options.packageManagerType) && isOHModulesReference(fileName))) { 427 return; 428 } 429 430 references.push({ pos: -1, end: -1, fileName }); 431 } 432 }; 433 } 434 } 435 436 function isNodeModulesReference(fileName: string): boolean { 437 return startsWith(fileName, "node_modules/") || pathContainsNodeModules(fileName); 438 } 439 440 function collectReferences(sourceFile: SourceFile | UnparsedSource, ret: ESMap<NodeId, SourceFile>) { 441 if (noResolve || (!isUnparsedSource(sourceFile) && isSourceFileJS(sourceFile))) return ret; 442 forEach(sourceFile.referencedFiles, f => { 443 const elem = host.getSourceFileFromReference(sourceFile, f); 444 if (elem) { 445 ret.set(getOriginalNodeId(elem), elem); 446 } 447 }); 448 return ret; 449 } 450 451 function collectLibs(sourceFile: SourceFile | UnparsedSource, ret: ESMap<string, boolean>) { 452 forEach(sourceFile.libReferenceDirectives, ref => { 453 const lib = host.getLibFileFromReference(ref); 454 if (lib) { 455 ret.set(toFileNameLowerCase(ref.fileName), true); 456 } 457 }); 458 return ret; 459 } 460 461 function filterBindingPatternInitializersAndRenamings(name: BindingName) { 462 if (name.kind === SyntaxKind.Identifier) { 463 return name; 464 } 465 else { 466 if (name.kind === SyntaxKind.ArrayBindingPattern) { 467 return factory.updateArrayBindingPattern(name, visitNodes(name.elements, visitBindingElement)); 468 } 469 else { 470 return factory.updateObjectBindingPattern(name, visitNodes(name.elements, visitBindingElement)); 471 } 472 } 473 474 function visitBindingElement<T extends ArrayBindingElement>(elem: T): T; 475 function visitBindingElement(elem: ArrayBindingElement): ArrayBindingElement { 476 if (elem.kind === SyntaxKind.OmittedExpression) { 477 return elem; 478 } 479 if (elem.propertyName && isIdentifier(elem.propertyName) && isIdentifier(elem.name) && !elem.symbol.isReferenced) { 480 // Unnecessary property renaming is forbidden in types, so remove renaming 481 return factory.updateBindingElement( 482 elem, 483 elem.dotDotDotToken, 484 /* propertyName */ undefined, 485 elem.propertyName, 486 shouldPrintWithInitializer(elem) ? elem.initializer : undefined 487 ); 488 } 489 return factory.updateBindingElement( 490 elem, 491 elem.dotDotDotToken, 492 elem.propertyName, 493 filterBindingPatternInitializersAndRenamings(elem.name), 494 shouldPrintWithInitializer(elem) ? elem.initializer : undefined 495 ); 496 } 497 } 498 499 function ensureParameter(p: ParameterDeclaration, modifierMask?: ModifierFlags, type?: TypeNode): ParameterDeclaration { 500 let oldDiag: typeof getSymbolAccessibilityDiagnostic | undefined; 501 if (!suppressNewDiagnosticContexts) { 502 oldDiag = getSymbolAccessibilityDiagnostic; 503 getSymbolAccessibilityDiagnostic = createGetSymbolAccessibilityDiagnosticForNode(p); 504 } 505 const newParam = factory.updateParameterDeclaration( 506 p, 507 maskModifiers(p, modifierMask), 508 p.dotDotDotToken, 509 filterBindingPatternInitializersAndRenamings(p.name), 510 resolver.isOptionalParameter(p) ? (p.questionToken || factory.createToken(SyntaxKind.QuestionToken)) : undefined, 511 ensureType(p, type || p.type, /*ignorePrivate*/ true), // Ignore private param props, since this type is going straight back into a param 512 ensureNoInitializer(p) 513 ); 514 if (!suppressNewDiagnosticContexts) { 515 getSymbolAccessibilityDiagnostic = oldDiag!; 516 } 517 return newParam; 518 } 519 520 function shouldPrintWithInitializer(node: Node) { 521 return canHaveLiteralInitializer(node) && resolver.isLiteralConstDeclaration(getParseTreeNode(node) as CanHaveLiteralInitializer); // TODO: Make safe 522 } 523 524 function ensureNoInitializer(node: CanHaveLiteralInitializer) { 525 if (shouldPrintWithInitializer(node)) { 526 return resolver.createLiteralConstValue(getParseTreeNode(node) as CanHaveLiteralInitializer, symbolTracker); // TODO: Make safe 527 } 528 return undefined; 529 } 530 531 type HasInferredType = 532 | FunctionDeclaration 533 | MethodDeclaration 534 | GetAccessorDeclaration 535 | SetAccessorDeclaration 536 | BindingElement 537 | ConstructSignatureDeclaration 538 | VariableDeclaration 539 | MethodSignature 540 | CallSignatureDeclaration 541 | ParameterDeclaration 542 | PropertyDeclaration 543 | PropertySignature; 544 545 function ensureType(node: HasInferredType, type: TypeNode | undefined, ignorePrivate?: boolean): TypeNode | undefined { 546 if (!ignorePrivate && hasEffectiveModifier(node, ModifierFlags.Private)) { 547 // Private nodes emit no types (except private parameter properties, whose parameter types are actually visible) 548 return; 549 } 550 if (shouldPrintWithInitializer(node)) { 551 // Literal const declarations will have an initializer ensured rather than a type 552 return; 553 } 554 if (type !== undefined && isTypeReferenceNode(type) && type.typeName.virtual) { 555 return; 556 } 557 const shouldUseResolverType = node.kind === SyntaxKind.Parameter && 558 (resolver.isRequiredInitializedParameter(node) || 559 resolver.isOptionalUninitializedParameterProperty(node)); 560 if (type && !shouldUseResolverType) { 561 return visitNode(type, visitDeclarationSubtree); 562 } 563 if (!getParseTreeNode(node)) { 564 return type ? visitNode(type, visitDeclarationSubtree) : factory.createKeywordTypeNode(SyntaxKind.AnyKeyword); 565 } 566 if (node.kind === SyntaxKind.SetAccessor) { 567 // 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 568 // (The inferred type here will be void, but the old declaration emitter printed `any`, so this replicates that) 569 return factory.createKeywordTypeNode(SyntaxKind.AnyKeyword); 570 } 571 errorNameNode = node.name; 572 let oldDiag: typeof getSymbolAccessibilityDiagnostic; 573 if (!suppressNewDiagnosticContexts) { 574 oldDiag = getSymbolAccessibilityDiagnostic; 575 getSymbolAccessibilityDiagnostic = createGetSymbolAccessibilityDiagnosticForNode(node); 576 } 577 if (node.kind === SyntaxKind.VariableDeclaration || node.kind === SyntaxKind.BindingElement) { 578 return cleanup(resolver.createTypeOfDeclaration(node, enclosingDeclaration, declarationEmitNodeBuilderFlags, symbolTracker)); 579 } 580 if (node.kind === SyntaxKind.Parameter 581 || node.kind === SyntaxKind.PropertyDeclaration 582 || node.kind === SyntaxKind.PropertySignature) { 583 if (isPropertySignature(node) || !node.initializer) return cleanup(resolver.createTypeOfDeclaration(node, enclosingDeclaration, declarationEmitNodeBuilderFlags, symbolTracker, shouldUseResolverType)); 584 return cleanup(resolver.createTypeOfDeclaration(node, enclosingDeclaration, declarationEmitNodeBuilderFlags, symbolTracker, shouldUseResolverType) || resolver.createTypeOfExpression(node.initializer, enclosingDeclaration, declarationEmitNodeBuilderFlags, symbolTracker)); 585 } 586 return cleanup(resolver.createReturnTypeOfSignatureDeclaration(node, enclosingDeclaration, declarationEmitNodeBuilderFlags, symbolTracker)); 587 588 function cleanup(returnValue: TypeNode | undefined) { 589 errorNameNode = undefined; 590 if (!suppressNewDiagnosticContexts) { 591 getSymbolAccessibilityDiagnostic = oldDiag; 592 } 593 return returnValue || factory.createKeywordTypeNode(SyntaxKind.AnyKeyword); 594 } 595 } 596 597 function isDeclarationAndNotVisible(node: NamedDeclaration) { 598 node = getParseTreeNode(node) as NamedDeclaration; 599 switch (node.kind) { 600 case SyntaxKind.FunctionDeclaration: 601 case SyntaxKind.ModuleDeclaration: 602 case SyntaxKind.InterfaceDeclaration: 603 case SyntaxKind.ClassDeclaration: 604 case SyntaxKind.StructDeclaration: 605 case SyntaxKind.TypeAliasDeclaration: 606 case SyntaxKind.EnumDeclaration: 607 return !resolver.isDeclarationVisible(node); 608 // The following should be doing their own visibility checks based on filtering their members 609 case SyntaxKind.VariableDeclaration: 610 return !getBindingNameVisible(node as VariableDeclaration); 611 case SyntaxKind.ImportEqualsDeclaration: 612 case SyntaxKind.ImportDeclaration: 613 case SyntaxKind.ExportDeclaration: 614 case SyntaxKind.ExportAssignment: 615 return false; 616 case SyntaxKind.ClassStaticBlockDeclaration: 617 return true; 618 } 619 return false; 620 } 621 622 // If the ExpandoFunctionDeclaration have multiple overloads, then we only need to emit properties for the last one. 623 function shouldEmitFunctionProperties(input: FunctionDeclaration) { 624 if (input.body) { 625 return true; 626 } 627 628 const overloadSignatures = input.symbol.declarations?.filter(decl => isFunctionDeclaration(decl) && !decl.body); 629 return !overloadSignatures || overloadSignatures.indexOf(input) === overloadSignatures.length - 1; 630 } 631 632 function getBindingNameVisible(elem: BindingElement | VariableDeclaration | OmittedExpression): boolean { 633 if (isOmittedExpression(elem)) { 634 return false; 635 } 636 if (isBindingPattern(elem.name)) { 637 // If any child binding pattern element has been marked visible (usually by collect linked aliases), then this is visible 638 return some(elem.name.elements, getBindingNameVisible); 639 } 640 else { 641 return resolver.isDeclarationVisible(elem); 642 } 643 } 644 645 function updateParamsList(node: Node, params: NodeArray<ParameterDeclaration>, modifierMask?: ModifierFlags) { 646 if (hasEffectiveModifier(node, ModifierFlags.Private)) { 647 return undefined!; // TODO: GH#18217 648 } 649 const newParams = map(params, p => ensureParameter(p, modifierMask)); 650 if (!newParams) { 651 return undefined!; // TODO: GH#18217 652 } 653 return factory.createNodeArray(newParams, params.hasTrailingComma); 654 } 655 656 function updateAccessorParamsList(input: AccessorDeclaration, isPrivate: boolean) { 657 let newParams: ParameterDeclaration[] | undefined; 658 if (!isPrivate) { 659 const thisParameter = getThisParameter(input); 660 if (thisParameter) { 661 newParams = [ensureParameter(thisParameter)]; 662 } 663 } 664 if (isSetAccessorDeclaration(input)) { 665 let newValueParameter: ParameterDeclaration | undefined; 666 if (!isPrivate) { 667 const valueParameter = getSetAccessorValueParameter(input); 668 if (valueParameter) { 669 const accessorType = getTypeAnnotationFromAllAccessorDeclarations(input, resolver.getAllAccessorDeclarations(input)); 670 newValueParameter = ensureParameter(valueParameter, /*modifierMask*/ undefined, accessorType); 671 } 672 } 673 if (!newValueParameter) { 674 newValueParameter = factory.createParameterDeclaration( 675 /*modifiers*/ undefined, 676 /*dotDotDotToken*/ undefined, 677 "value" 678 ); 679 } 680 newParams = append(newParams, newValueParameter); 681 } 682 return factory.createNodeArray(newParams || emptyArray); 683 } 684 685 function ensureTypeParams(node: Node, params: NodeArray<TypeParameterDeclaration> | undefined) { 686 return hasEffectiveModifier(node, ModifierFlags.Private) ? undefined : visitNodes(params, visitDeclarationSubtree); 687 } 688 689 function isEnclosingDeclaration(node: Node) { 690 return isSourceFile(node) 691 || isTypeAliasDeclaration(node) 692 || isModuleDeclaration(node) 693 || isClassDeclaration(node) 694 || isStructDeclaration(node) 695 || isInterfaceDeclaration(node) 696 || isFunctionLike(node) 697 || isIndexSignatureDeclaration(node) 698 || isMappedTypeNode(node); 699 } 700 701 function checkEntityNameVisibility(entityName: EntityNameOrEntityNameExpression, enclosingDeclaration: Node) { 702 const visibilityResult = resolver.isEntityNameVisible(entityName, enclosingDeclaration); 703 handleSymbolAccessibilityError(visibilityResult); 704 recordTypeReferenceDirectivesIfNecessary(resolver.getTypeReferenceDirectivesForEntityName(entityName)); 705 } 706 707 function preserveJsDoc<T extends Node>(updated: T, original: Node): T { 708 if (hasJSDocNodes(updated) && hasJSDocNodes(original)) { 709 updated.jsDoc = original.jsDoc; 710 } 711 return setCommentRange(updated, getCommentRange(original)); 712 } 713 714 function rewriteModuleSpecifier<T extends Node>(parent: ImportEqualsDeclaration | ImportDeclaration | ExportDeclaration | ModuleDeclaration | ImportTypeNode, input: T | undefined): T | StringLiteral { 715 if (!input) return undefined!; // TODO: GH#18217 716 resultHasExternalModuleIndicator = resultHasExternalModuleIndicator || (parent.kind !== SyntaxKind.ModuleDeclaration && parent.kind !== SyntaxKind.ImportType); 717 if (isStringLiteralLike(input)) { 718 if (isBundledEmit) { 719 const newName = getExternalModuleNameFromDeclaration(context.getEmitHost(), resolver, parent); 720 if (newName) { 721 return factory.createStringLiteral(newName); 722 } 723 } 724 else { 725 const symbol = resolver.getSymbolOfExternalModuleSpecifier(input); 726 if (symbol) { 727 (exportedModulesFromDeclarationEmit || (exportedModulesFromDeclarationEmit = [])).push(symbol); 728 } 729 } 730 } 731 return input; 732 } 733 734 function transformImportEqualsDeclaration(decl: ImportEqualsDeclaration) { 735 if (!resolver.isDeclarationVisible(decl)) return; 736 if (decl.moduleReference.kind === SyntaxKind.ExternalModuleReference) { 737 // Rewrite external module names if necessary 738 const specifier = getExternalModuleImportEqualsDeclarationExpression(decl); 739 return factory.updateImportEqualsDeclaration( 740 decl, 741 decl.modifiers, 742 decl.isTypeOnly, 743 decl.name, 744 factory.updateExternalModuleReference(decl.moduleReference, rewriteModuleSpecifier(decl, specifier)) 745 ); 746 } 747 else { 748 const oldDiag = getSymbolAccessibilityDiagnostic; 749 getSymbolAccessibilityDiagnostic = createGetSymbolAccessibilityDiagnosticForNode(decl); 750 checkEntityNameVisibility(decl.moduleReference, enclosingDeclaration); 751 getSymbolAccessibilityDiagnostic = oldDiag; 752 return decl; 753 } 754 } 755 756 function transformImportDeclaration(decl: ImportDeclaration) { 757 if (!decl.importClause) { 758 // import "mod" - possibly needed for side effects? (global interface patches, module augmentations, etc) 759 return factory.updateImportDeclaration( 760 decl, 761 decl.modifiers, 762 decl.importClause, 763 rewriteModuleSpecifier(decl, decl.moduleSpecifier), 764 getResolutionModeOverrideForClauseInNightly(decl.assertClause) 765 ); 766 } 767 // The `importClause` visibility corresponds to the default's visibility. 768 const visibleDefaultBinding = decl.importClause && decl.importClause.name && resolver.isDeclarationVisible(decl.importClause) ? decl.importClause.name : undefined; 769 if (!decl.importClause.namedBindings) { 770 // No named bindings (either namespace or list), meaning the import is just default or should be elided 771 return visibleDefaultBinding && factory.updateImportDeclaration(decl, decl.modifiers, factory.updateImportClause( 772 decl.importClause, 773 decl.importClause.isTypeOnly, 774 visibleDefaultBinding, 775 /*namedBindings*/ undefined, 776 ), rewriteModuleSpecifier(decl, decl.moduleSpecifier), getResolutionModeOverrideForClauseInNightly(decl.assertClause)); 777 } 778 if (decl.importClause.namedBindings.kind === SyntaxKind.NamespaceImport) { 779 // Namespace import (optionally with visible default) 780 const namedBindings = resolver.isDeclarationVisible(decl.importClause.namedBindings) ? decl.importClause.namedBindings : /*namedBindings*/ undefined; 781 return visibleDefaultBinding || namedBindings ? factory.updateImportDeclaration(decl, decl.modifiers, factory.updateImportClause( 782 decl.importClause, 783 decl.importClause.isTypeOnly, 784 visibleDefaultBinding, 785 namedBindings, 786 ), rewriteModuleSpecifier(decl, decl.moduleSpecifier), getResolutionModeOverrideForClauseInNightly(decl.assertClause)) : undefined; 787 } 788 // Named imports (optionally with visible default) 789 const bindingList = mapDefined(decl.importClause.namedBindings.elements, b => resolver.isDeclarationVisible(b) ? b : undefined); 790 if ((bindingList && bindingList.length) || visibleDefaultBinding) { 791 return factory.updateImportDeclaration( 792 decl, 793 decl.modifiers, 794 factory.updateImportClause( 795 decl.importClause, 796 decl.importClause.isTypeOnly, 797 visibleDefaultBinding, 798 bindingList && bindingList.length ? factory.updateNamedImports(decl.importClause.namedBindings, bindingList) : undefined, 799 ), 800 rewriteModuleSpecifier(decl, decl.moduleSpecifier), 801 getResolutionModeOverrideForClauseInNightly(decl.assertClause) 802 ); 803 } 804 // Augmentation of export depends on import 805 if (resolver.isImportRequiredByAugmentation(decl)) { 806 return factory.updateImportDeclaration( 807 decl, 808 decl.modifiers, 809 /*importClause*/ undefined, 810 rewriteModuleSpecifier(decl, decl.moduleSpecifier), 811 getResolutionModeOverrideForClauseInNightly(decl.assertClause) 812 ); 813 } 814 // Nothing visible 815 } 816 817 function getResolutionModeOverrideForClauseInNightly(assertClause: AssertClause | undefined) { 818 const mode = getResolutionModeOverrideForClause(assertClause); 819 if (mode !== undefined) { 820 if (!isNightly()) { 821 context.addDiagnostic(createDiagnosticForNode(assertClause!, Diagnostics.resolution_mode_assertions_are_unstable_Use_nightly_TypeScript_to_silence_this_error_Try_updating_with_npm_install_D_typescript_next)); 822 } 823 return assertClause; 824 } 825 return undefined; 826 } 827 828 function transformAndReplaceLatePaintedStatements(statements: NodeArray<Statement>): NodeArray<Statement> { 829 // This is a `while` loop because `handleSymbolAccessibilityError` can see additional import aliases marked as visible during 830 // error handling which must now be included in the output and themselves checked for errors. 831 // For example: 832 // ``` 833 // module A { 834 // export module Q {} 835 // import B = Q; 836 // import C = B; 837 // export import D = C; 838 // } 839 // ``` 840 // In such a scenario, only Q and D are initially visible, but we don't consider imports as private names - instead we say they if they are referenced they must 841 // be recorded. So while checking D's visibility we mark C as visible, then we must check C which in turn marks B, completing the chain of 842 // dependent imports and allowing a valid declaration file output. Today, this dependent alias marking only happens for internal import aliases. 843 while (length(lateMarkedStatements)) { 844 const i = lateMarkedStatements!.shift()!; 845 if (!isLateVisibilityPaintedStatement(i)) { 846 return Debug.fail(`Late replaced statement was found which is not handled by the declaration transformer!: ${Debug.formatSyntaxKind((i as Node).kind)}`); 847 } 848 const priorNeedsDeclare = needsDeclare; 849 needsDeclare = i.parent && isSourceFile(i.parent) && !(isExternalModule(i.parent) && isBundledEmit); 850 const result = transformTopLevelDeclaration(i); 851 needsDeclare = priorNeedsDeclare; 852 lateStatementReplacementMap.set(getOriginalNodeId(i), result); 853 } 854 855 // And lastly, we need to get the final form of all those indetermine import declarations from before and add them to the output list 856 // (and remove them from the set to examine for outter declarations) 857 return visitNodes(statements, visitLateVisibilityMarkedStatements); 858 859 function visitLateVisibilityMarkedStatements(statement: Statement) { 860 if (isLateVisibilityPaintedStatement(statement)) { 861 const key = getOriginalNodeId(statement); 862 if (lateStatementReplacementMap.has(key)) { 863 const result = lateStatementReplacementMap.get(key); 864 lateStatementReplacementMap.delete(key); 865 if (result) { 866 if (isArray(result) ? some(result, needsScopeMarker) : needsScopeMarker(result)) { 867 // Top-level declarations in .d.ts files are always considered exported even without a modifier unless there's an export assignment or specifier 868 needsScopeFixMarker = true; 869 } 870 if (isSourceFile(statement.parent) && (isArray(result) ? some(result, isExternalModuleIndicator) : isExternalModuleIndicator(result))) { 871 resultHasExternalModuleIndicator = true; 872 } 873 } 874 return result; 875 } 876 } 877 return statement; 878 } 879 } 880 881 function visitDeclarationSubtree(input: Node): VisitResult<Node> { 882 if (shouldStripInternal(input)) return; 883 if (isDeclaration(input)) { 884 if (isDeclarationAndNotVisible(input)) return; 885 if (hasDynamicName(input) && !resolver.isLateBound(getParseTreeNode(input) as Declaration)) { 886 return; 887 } 888 } 889 890 // Elide implementation signatures from overload sets 891 if (isFunctionLike(input) && resolver.isImplementationOfOverload(input)) return; 892 893 // Elide semicolon class statements 894 if (isSemicolonClassElement(input)) return; 895 896 let previousEnclosingDeclaration: typeof enclosingDeclaration; 897 if (isEnclosingDeclaration(input)) { 898 previousEnclosingDeclaration = enclosingDeclaration; 899 enclosingDeclaration = input as Declaration; 900 } 901 const oldDiag = getSymbolAccessibilityDiagnostic; 902 903 // Setup diagnostic-related flags before first potential `cleanup` call, otherwise 904 // We'd see a TDZ violation at runtime 905 const canProduceDiagnostic = canProduceDiagnostics(input); 906 const oldWithinObjectLiteralType = suppressNewDiagnosticContexts; 907 let shouldEnterSuppressNewDiagnosticsContextContext = ((input.kind === SyntaxKind.TypeLiteral || input.kind === SyntaxKind.MappedType) && input.parent.kind !== SyntaxKind.TypeAliasDeclaration); 908 909 // Emit methods which are private as properties with no type information 910 if (isMethodDeclaration(input) || isMethodSignature(input)) { 911 if (hasEffectiveModifier(input, ModifierFlags.Private)) { 912 if (input.symbol && input.symbol.declarations && input.symbol.declarations[0] !== input) return; // Elide all but the first overload 913 return cleanup(factory.createPropertyDeclaration(ensureModifiers(input), input.name, /*questionToken*/ undefined, /*type*/ undefined, /*initializer*/ undefined)); 914 } 915 } 916 917 if (canProduceDiagnostic && !suppressNewDiagnosticContexts) { 918 getSymbolAccessibilityDiagnostic = createGetSymbolAccessibilityDiagnosticForNode(input); 919 } 920 921 if (isTypeQueryNode(input)) { 922 checkEntityNameVisibility(input.exprName, enclosingDeclaration); 923 } 924 925 if (shouldEnterSuppressNewDiagnosticsContextContext) { 926 // We stop making new diagnostic contexts within object literal types. Unless it's an object type on the RHS of a type alias declaration. Then we do. 927 suppressNewDiagnosticContexts = true; 928 } 929 930 if (isProcessedComponent(input)) { 931 switch (input.kind) { 932 case SyntaxKind.ExpressionWithTypeArguments: { 933 if ((isEntityName(input.expression) || isEntityNameExpression(input.expression))) { 934 checkEntityNameVisibility(input.expression, enclosingDeclaration); 935 } 936 const node = visitEachChild(input, visitDeclarationSubtree, context); 937 return cleanup(factory.updateExpressionWithTypeArguments(node, node.expression, node.typeArguments)); 938 } 939 case SyntaxKind.TypeReference: { 940 checkEntityNameVisibility(input.typeName, enclosingDeclaration); 941 const node = visitEachChild(input, visitDeclarationSubtree, context); 942 return cleanup(factory.updateTypeReferenceNode(node, node.typeName, node.typeArguments)); 943 } 944 case SyntaxKind.ConstructSignature: 945 return cleanup(factory.updateConstructSignature( 946 input, 947 ensureTypeParams(input, input.typeParameters), 948 updateParamsList(input, input.parameters), 949 ensureType(input, input.type) 950 )); 951 case SyntaxKind.Constructor: { 952 // A constructor declaration may not have a type annotation 953 const ctor = factory.createConstructorDeclaration( 954 /*modifiers*/ ensureModifiers(input), 955 updateParamsList(input, input.parameters, ModifierFlags.None), 956 /*body*/ undefined 957 ); 958 return cleanup(ctor); 959 } 960 case SyntaxKind.MethodDeclaration: { 961 if (isPrivateIdentifier(input.name)) { 962 return cleanup(/*returnValue*/ undefined); 963 } 964 let reservedDecorators = getReservedDecoratorsOfStructDeclaration(input, host); 965 966 const sig = factory.createMethodDeclaration( 967 concatenateDecoratorsAndModifiers(reservedDecorators, ensureModifiers(input)), 968 /*asteriskToken*/ undefined, 969 input.name, 970 input.questionToken, 971 inEtsStylesContext(input, host) ? undefined : ensureTypeParams(input, input.typeParameters), 972 updateParamsList(input, input.parameters), 973 ensureType(input, input.type), 974 /*body*/ undefined 975 ); 976 return cleanup(sig); 977 } 978 case SyntaxKind.GetAccessor: { 979 if (isPrivateIdentifier(input.name)) { 980 return cleanup(/*returnValue*/ undefined); 981 } 982 const accessorType = getTypeAnnotationFromAllAccessorDeclarations(input, resolver.getAllAccessorDeclarations(input)); 983 return cleanup(factory.updateGetAccessorDeclaration( 984 input, 985 ensureModifiers(input), 986 input.name, 987 updateAccessorParamsList(input, hasEffectiveModifier(input, ModifierFlags.Private)), 988 ensureType(input, accessorType), 989 /*body*/ undefined)); 990 } 991 case SyntaxKind.SetAccessor: { 992 if (isPrivateIdentifier(input.name)) { 993 return cleanup(/*returnValue*/ undefined); 994 } 995 return cleanup(factory.updateSetAccessorDeclaration( 996 input, 997 ensureModifiers(input), 998 input.name, 999 updateAccessorParamsList(input, hasEffectiveModifier(input, ModifierFlags.Private)), 1000 /*body*/ undefined)); 1001 } 1002 case SyntaxKind.PropertyDeclaration: 1003 if (isPrivateIdentifier(input.name)) { 1004 return cleanup(/*returnValue*/ undefined); 1005 } 1006 let reservedDecorators = getReservedDecoratorsOfStructDeclaration(input, host); 1007 1008 return cleanup(factory.updatePropertyDeclaration( 1009 input, 1010 concatenateDecoratorsAndModifiers(reservedDecorators, ensureModifiers(input)), 1011 input.name, 1012 input.questionToken, 1013 ensureType(input, input.type), 1014 ensureNoInitializer(input) 1015 )); 1016 case SyntaxKind.PropertySignature: 1017 if (isPrivateIdentifier(input.name)) { 1018 return cleanup(/*returnValue*/ undefined); 1019 } 1020 return cleanup(factory.updatePropertySignature( 1021 input, 1022 ensureModifiers(input), 1023 input.name, 1024 input.questionToken, 1025 ensureType(input, input.type) 1026 )); 1027 case SyntaxKind.MethodSignature: { 1028 if (isPrivateIdentifier(input.name)) { 1029 return cleanup(/*returnValue*/ undefined); 1030 } 1031 return cleanup(factory.updateMethodSignature( 1032 input, 1033 ensureModifiers(input), 1034 input.name, 1035 input.questionToken, 1036 ensureTypeParams(input, input.typeParameters), 1037 updateParamsList(input, input.parameters), 1038 ensureType(input, input.type) 1039 )); 1040 } 1041 case SyntaxKind.CallSignature: { 1042 return cleanup(factory.updateCallSignature( 1043 input, 1044 ensureTypeParams(input, input.typeParameters), 1045 updateParamsList(input, input.parameters), 1046 ensureType(input, input.type) 1047 )); 1048 } 1049 case SyntaxKind.IndexSignature: { 1050 return cleanup(factory.updateIndexSignature( 1051 input, 1052 ensureModifiers(input), 1053 updateParamsList(input, input.parameters), 1054 visitNode(input.type, visitDeclarationSubtree) || factory.createKeywordTypeNode(SyntaxKind.AnyKeyword) 1055 )); 1056 } 1057 case SyntaxKind.VariableDeclaration: { 1058 if (isBindingPattern(input.name)) { 1059 return recreateBindingPattern(input.name); 1060 } 1061 shouldEnterSuppressNewDiagnosticsContextContext = true; 1062 suppressNewDiagnosticContexts = true; // Variable declaration types also suppress new diagnostic contexts, provided the contexts wouldn't be made for binding pattern types 1063 return cleanup(factory.updateVariableDeclaration(input, input.name, /*exclamationToken*/ undefined, ensureType(input, input.type), ensureNoInitializer(input))); 1064 } 1065 case SyntaxKind.TypeParameter: { 1066 if (isPrivateMethodTypeParameter(input) && (input.default || input.constraint)) { 1067 return cleanup(factory.updateTypeParameterDeclaration(input, input.modifiers, input.name, /*constraint*/ undefined, /*defaultType*/ undefined)); 1068 } 1069 return cleanup(visitEachChild(input, visitDeclarationSubtree, context)); 1070 } 1071 case SyntaxKind.ConditionalType: { 1072 // We have to process conditional types in a special way because for visibility purposes we need to push a new enclosingDeclaration 1073 // just for the `infer` types in the true branch. It's an implicit declaration scope that only applies to _part_ of the type. 1074 const checkType = visitNode(input.checkType, visitDeclarationSubtree); 1075 const extendsType = visitNode(input.extendsType, visitDeclarationSubtree); 1076 const oldEnclosingDecl = enclosingDeclaration; 1077 enclosingDeclaration = input.trueType; 1078 const trueType = visitNode(input.trueType, visitDeclarationSubtree); 1079 enclosingDeclaration = oldEnclosingDecl; 1080 const falseType = visitNode(input.falseType, visitDeclarationSubtree); 1081 return cleanup(factory.updateConditionalTypeNode(input, checkType, extendsType, trueType, falseType)); 1082 } 1083 case SyntaxKind.FunctionType: { 1084 return cleanup(factory.updateFunctionTypeNode(input, visitNodes(input.typeParameters, visitDeclarationSubtree), updateParamsList(input, input.parameters), visitNode(input.type, visitDeclarationSubtree))); 1085 } 1086 case SyntaxKind.ConstructorType: { 1087 return cleanup(factory.updateConstructorTypeNode(input, ensureModifiers(input), visitNodes(input.typeParameters, visitDeclarationSubtree), updateParamsList(input, input.parameters), visitNode(input.type, visitDeclarationSubtree))); 1088 } 1089 case SyntaxKind.ImportType: { 1090 if (!isLiteralImportTypeNode(input)) return cleanup(input); 1091 return cleanup(factory.updateImportTypeNode( 1092 input, 1093 factory.updateLiteralTypeNode(input.argument, rewriteModuleSpecifier(input, input.argument.literal)), 1094 input.assertions, 1095 input.qualifier, 1096 visitNodes(input.typeArguments, visitDeclarationSubtree, isTypeNode), 1097 input.isTypeOf 1098 )); 1099 } 1100 default: Debug.assertNever(input, `Attempted to process unhandled node kind: ${Debug.formatSyntaxKind((input as Node).kind)}`); 1101 } 1102 } 1103 1104 if (isTupleTypeNode(input) && (getLineAndCharacterOfPosition(currentSourceFile, input.pos).line === getLineAndCharacterOfPosition(currentSourceFile, input.end).line)) { 1105 setEmitFlags(input, EmitFlags.SingleLine); 1106 } 1107 1108 return cleanup(visitEachChild(input, visitDeclarationSubtree, context)); 1109 1110 function cleanup<T extends Node>(returnValue: T | undefined): T | undefined { 1111 if (returnValue && canProduceDiagnostic && hasDynamicName(input as Declaration)) { 1112 checkName(input); 1113 } 1114 if (isEnclosingDeclaration(input)) { 1115 enclosingDeclaration = previousEnclosingDeclaration; 1116 } 1117 if (canProduceDiagnostic && !suppressNewDiagnosticContexts) { 1118 getSymbolAccessibilityDiagnostic = oldDiag; 1119 } 1120 if (shouldEnterSuppressNewDiagnosticsContextContext) { 1121 suppressNewDiagnosticContexts = oldWithinObjectLiteralType; 1122 } 1123 if (returnValue === input) { 1124 return returnValue; 1125 } 1126 return returnValue && setOriginalNode(preserveJsDoc(returnValue, input), input); 1127 } 1128 } 1129 1130 function isPrivateMethodTypeParameter(node: TypeParameterDeclaration) { 1131 return node.parent.kind === SyntaxKind.MethodDeclaration && hasEffectiveModifier(node.parent, ModifierFlags.Private); 1132 } 1133 1134 function visitDeclarationStatements(input: Node): VisitResult<Node> { 1135 if (!isPreservedDeclarationStatement(input)) { 1136 // return undefined for unmatched kinds to omit them from the tree 1137 return; 1138 } 1139 if (shouldStripInternal(input)) return; 1140 1141 switch (input.kind) { 1142 case SyntaxKind.ExportDeclaration: { 1143 if (isSourceFile(input.parent)) { 1144 resultHasExternalModuleIndicator = true; 1145 } 1146 resultHasScopeMarker = true; 1147 // Always visible if the parent node isn't dropped for being not visible 1148 // Rewrite external module names if necessary 1149 return factory.updateExportDeclaration( 1150 input, 1151 input.modifiers, 1152 input.isTypeOnly, 1153 input.exportClause, 1154 rewriteModuleSpecifier(input, input.moduleSpecifier), 1155 getResolutionModeOverrideForClause(input.assertClause) ? input.assertClause : undefined 1156 ); 1157 } 1158 case SyntaxKind.ExportAssignment: { 1159 // Always visible if the parent node isn't dropped for being not visible 1160 if (isSourceFile(input.parent)) { 1161 resultHasExternalModuleIndicator = true; 1162 } 1163 resultHasScopeMarker = true; 1164 if (input.expression.kind === SyntaxKind.Identifier) { 1165 return input; 1166 } 1167 else { 1168 const newId = factory.createUniqueName("_default", GeneratedIdentifierFlags.Optimistic); 1169 getSymbolAccessibilityDiagnostic = () => ({ 1170 diagnosticMessage: Diagnostics.Default_export_of_the_module_has_or_is_using_private_name_0, 1171 errorNode: input 1172 }); 1173 errorFallbackNode = input; 1174 const varDecl = factory.createVariableDeclaration(newId, /*exclamationToken*/ undefined, resolver.createTypeOfExpression(input.expression, input, declarationEmitNodeBuilderFlags, symbolTracker), /*initializer*/ undefined); 1175 errorFallbackNode = undefined; 1176 const statement = factory.createVariableStatement(needsDeclare ? [factory.createModifier(SyntaxKind.DeclareKeyword)] : [], factory.createVariableDeclarationList([varDecl], NodeFlags.Const)); 1177 1178 preserveJsDoc(statement, input); 1179 removeAllComments(input); 1180 return [statement, factory.updateExportAssignment(input, input.modifiers, newId)]; 1181 } 1182 } 1183 } 1184 1185 const result = transformTopLevelDeclaration(input); 1186 // Don't actually transform yet; just leave as original node - will be elided/swapped by late pass 1187 lateStatementReplacementMap.set(getOriginalNodeId(input), result); 1188 return input; 1189 } 1190 1191 function stripExportModifiers(statement: Statement): Statement { 1192 if (isImportEqualsDeclaration(statement) || hasEffectiveModifier(statement, ModifierFlags.Default) || !canHaveModifiers(statement)) { 1193 // `export import` statements should remain as-is, as imports are _not_ implicitly exported in an ambient namespace 1194 // Likewise, `export default` classes and the like and just be `default`, so we preserve their `export` modifiers, too 1195 return statement; 1196 } 1197 1198 const modifiers = factory.createModifiersFromModifierFlags(getEffectiveModifierFlags(statement) & (ModifierFlags.All ^ ModifierFlags.Export)); 1199 return factory.updateModifiers(statement, modifiers); 1200 } 1201 1202 function transformTopLevelDeclaration(input: LateVisibilityPaintedStatement) { 1203 if (lateMarkedStatements) { 1204 while (orderedRemoveItem(lateMarkedStatements, input)); 1205 } 1206 if (shouldStripInternal(input)) return; 1207 switch (input.kind) { 1208 case SyntaxKind.ImportEqualsDeclaration: { 1209 return transformImportEqualsDeclaration(input); 1210 } 1211 case SyntaxKind.ImportDeclaration: { 1212 return transformImportDeclaration(input); 1213 } 1214 } 1215 if (isDeclaration(input) && isDeclarationAndNotVisible(input)) return; 1216 1217 // Elide implementation signatures from overload sets 1218 if (isFunctionLike(input) && resolver.isImplementationOfOverload(input)) return; 1219 1220 let previousEnclosingDeclaration: typeof enclosingDeclaration; 1221 if (isEnclosingDeclaration(input)) { 1222 previousEnclosingDeclaration = enclosingDeclaration; 1223 enclosingDeclaration = input as Declaration; 1224 } 1225 1226 const canProdiceDiagnostic = canProduceDiagnostics(input); 1227 const oldDiag = getSymbolAccessibilityDiagnostic; 1228 if (canProdiceDiagnostic) { 1229 getSymbolAccessibilityDiagnostic = createGetSymbolAccessibilityDiagnosticForNode(input as DeclarationDiagnosticProducing); 1230 } 1231 1232 const previousNeedsDeclare = needsDeclare; 1233 switch (input.kind) { 1234 case SyntaxKind.TypeAliasDeclaration: { 1235 needsDeclare = false; 1236 const clean = cleanup(factory.updateTypeAliasDeclaration( 1237 input, 1238 ensureModifiers(input), 1239 input.name, 1240 visitNodes(input.typeParameters, visitDeclarationSubtree, isTypeParameterDeclaration), 1241 visitNode(input.type, visitDeclarationSubtree, isTypeNode) 1242 )); 1243 needsDeclare = previousNeedsDeclare; 1244 return clean; 1245 } 1246 case SyntaxKind.InterfaceDeclaration: { 1247 return cleanup(factory.updateInterfaceDeclaration( 1248 input, 1249 ensureModifiers(input), 1250 input.name, 1251 ensureTypeParams(input, input.typeParameters), 1252 transformHeritageClauses(input.heritageClauses), 1253 visitNodes(input.members, visitDeclarationSubtree) 1254 )); 1255 } 1256 case SyntaxKind.FunctionDeclaration: { 1257 // Generators lose their generator-ness, excepting their return type 1258 const clean = cleanup(factory.updateFunctionDeclaration( 1259 input, 1260 ensureModifiers(input), 1261 /*asteriskToken*/ undefined, 1262 input.name, 1263 inEtsStylesContext(input, host) ? undefined : ensureTypeParams(input, input.typeParameters), 1264 updateParamsList(input, input.parameters), 1265 ensureType(input, input.type), 1266 /*body*/ undefined 1267 )); 1268 if (isInEtsFile(input)) { 1269 const reservedDecorators = getEffectiveDecorators(input.illegalDecorators, host); 1270 (clean as Mutable<FunctionDeclaration>).illegalDecorators = factory.createNodeArray(reservedDecorators); 1271 } 1272 if (clean && resolver.isExpandoFunctionDeclaration(input) && shouldEmitFunctionProperties(input)) { 1273 const props = resolver.getPropertiesOfContainerFunction(input); 1274 // Use parseNodeFactory so it is usable as an enclosing declaration 1275 const fakespace = parseNodeFactory.createModuleDeclaration(/*modifiers*/ undefined, clean.name || factory.createIdentifier("_default"), factory.createModuleBlock([]), NodeFlags.Namespace); 1276 setParent(fakespace, enclosingDeclaration as SourceFile | NamespaceDeclaration); 1277 fakespace.locals = createSymbolTable(props); 1278 fakespace.symbol = props[0].parent!; 1279 const exportMappings: [Identifier, string][] = []; 1280 let declarations: (VariableStatement | ExportDeclaration)[] = mapDefined(props, p => { 1281 if (!p.valueDeclaration || !isPropertyAccessExpression(p.valueDeclaration)) { 1282 return undefined; // TODO GH#33569: Handle element access expressions that created late bound names (rather than silently omitting them) 1283 } 1284 getSymbolAccessibilityDiagnostic = createGetSymbolAccessibilityDiagnosticForNode(p.valueDeclaration); 1285 const type = resolver.createTypeOfDeclaration(p.valueDeclaration, fakespace, declarationEmitNodeBuilderFlags, symbolTracker); 1286 getSymbolAccessibilityDiagnostic = oldDiag; 1287 const nameStr = unescapeLeadingUnderscores(p.escapedName); 1288 const isNonContextualKeywordName = isStringANonContextualKeyword(nameStr); 1289 const name = isNonContextualKeywordName ? factory.getGeneratedNameForNode(p.valueDeclaration) : factory.createIdentifier(nameStr); 1290 if (isNonContextualKeywordName) { 1291 exportMappings.push([name, nameStr]); 1292 } 1293 const varDecl = factory.createVariableDeclaration(name, /*exclamationToken*/ undefined, type, /*initializer*/ undefined); 1294 return factory.createVariableStatement(isNonContextualKeywordName ? undefined : [factory.createToken(SyntaxKind.ExportKeyword)], factory.createVariableDeclarationList([varDecl])); 1295 }); 1296 if (!exportMappings.length) { 1297 declarations = mapDefined(declarations, declaration => factory.updateModifiers(declaration, ModifierFlags.None)); 1298 } 1299 else { 1300 declarations.push(factory.createExportDeclaration( 1301 /*modifiers*/ undefined, 1302 /*isTypeOnly*/ false, 1303 factory.createNamedExports(map(exportMappings, ([gen, exp]) => { 1304 return factory.createExportSpecifier(/*isTypeOnly*/ false, gen, exp); 1305 })) 1306 )); 1307 } 1308 const namespaceDecl = factory.createModuleDeclaration(ensureModifiers(input), input.name!, factory.createModuleBlock(declarations), NodeFlags.Namespace); 1309 if (!hasEffectiveModifier(clean, ModifierFlags.Default)) { 1310 return [clean, namespaceDecl]; 1311 } 1312 1313 const modifiers = factory.createModifiersFromModifierFlags((getEffectiveModifierFlags(clean) & ~ModifierFlags.ExportDefault) | ModifierFlags.Ambient); 1314 1315 const cleanDeclaration = factory.updateFunctionDeclaration( 1316 clean, 1317 modifiers, 1318 /*asteriskToken*/ undefined, 1319 clean.name, 1320 clean.typeParameters, 1321 clean.parameters, 1322 clean.type, 1323 /*body*/ undefined 1324 ); 1325 if (isInEtsFile(input)) { 1326 const reservedDecorators = getEffectiveDecorators(clean.illegalDecorators, host); 1327 (cleanDeclaration as Mutable<FunctionDeclaration>).illegalDecorators = factory.createNodeArray(reservedDecorators); 1328 } 1329 const namespaceDeclaration = factory.updateModuleDeclaration( 1330 namespaceDecl, 1331 modifiers, 1332 namespaceDecl.name, 1333 namespaceDecl.body 1334 ); 1335 1336 const exportDefaultDeclaration = factory.createExportAssignment( 1337 /*modifiers*/ undefined, 1338 /*isExportEquals*/ false, 1339 namespaceDecl.name 1340 ); 1341 1342 if (isSourceFile(input.parent)) { 1343 resultHasExternalModuleIndicator = true; 1344 } 1345 resultHasScopeMarker = true; 1346 1347 return [cleanDeclaration, namespaceDeclaration, exportDefaultDeclaration]; 1348 } 1349 else { 1350 return clean; 1351 } 1352 } 1353 case SyntaxKind.ModuleDeclaration: { 1354 needsDeclare = false; 1355 const inner = input.body; 1356 if (inner && inner.kind === SyntaxKind.ModuleBlock) { 1357 const oldNeedsScopeFix = needsScopeFixMarker; 1358 const oldHasScopeFix = resultHasScopeMarker; 1359 resultHasScopeMarker = false; 1360 needsScopeFixMarker = false; 1361 const statements = visitNodes(inner.statements, visitDeclarationStatements); 1362 let lateStatements = transformAndReplaceLatePaintedStatements(statements); 1363 if (input.flags & NodeFlags.Ambient) { 1364 needsScopeFixMarker = false; // If it was `declare`'d everything is implicitly exported already, ignore late printed "privates" 1365 } 1366 // With the final list of statements, there are 3 possibilities: 1367 // 1. There's an export assignment or export declaration in the namespace - do nothing 1368 // 2. Everything is exported and there are no export assignments or export declarations - strip all export modifiers 1369 // 3. Some things are exported, some are not, and there's no marker - add an empty marker 1370 if (!isGlobalScopeAugmentation(input) && !hasScopeMarker(lateStatements) && !resultHasScopeMarker) { 1371 if (needsScopeFixMarker) { 1372 lateStatements = factory.createNodeArray([...lateStatements, createEmptyExports(factory)]); 1373 } 1374 else { 1375 lateStatements = visitNodes(lateStatements, stripExportModifiers); 1376 } 1377 } 1378 const body = factory.updateModuleBlock(inner, lateStatements); 1379 needsDeclare = previousNeedsDeclare; 1380 needsScopeFixMarker = oldNeedsScopeFix; 1381 resultHasScopeMarker = oldHasScopeFix; 1382 const mods = ensureModifiers(input); 1383 return cleanup(factory.updateModuleDeclaration( 1384 input, 1385 mods, 1386 isExternalModuleAugmentation(input) ? rewriteModuleSpecifier(input, input.name) : input.name, 1387 body 1388 )); 1389 } 1390 else { 1391 needsDeclare = previousNeedsDeclare; 1392 const mods = ensureModifiers(input); 1393 needsDeclare = false; 1394 visitNode(inner, visitDeclarationStatements); 1395 // eagerly transform nested namespaces (the nesting doesn't need any elision or painting done) 1396 const id = getOriginalNodeId(inner!); // TODO: GH#18217 1397 const body = lateStatementReplacementMap.get(id); 1398 lateStatementReplacementMap.delete(id); 1399 return cleanup(factory.updateModuleDeclaration( 1400 input, 1401 mods, 1402 input.name, 1403 body as ModuleBody 1404 )); 1405 } 1406 } 1407 case SyntaxKind.StructDeclaration: { 1408 errorNameNode = input.name; 1409 errorFallbackNode = input; 1410 1411 const decorators = ensureEtsDecorators(input, host); 1412 const modifiers = factory.createNodeArray(ensureModifiers(input)); 1413 const typeParameters = ensureTypeParams(input, input.typeParameters); 1414 const memberNodes = visitNodes(input.members, visitDeclarationSubtree, undefined, 1); 1415 const members = factory.createNodeArray(memberNodes); 1416 1417 return cleanup(factory.updateStructDeclaration( 1418 input, 1419 concatenateDecoratorsAndModifiers(decorators, modifiers), 1420 input.name, 1421 typeParameters, 1422 /*heritageClauses*/ undefined, 1423 members 1424 )); 1425 } 1426 case SyntaxKind.ClassDeclaration: { 1427 errorNameNode = input.name; 1428 errorFallbackNode = input; 1429 const modifiers = factory.createNodeArray(ensureModifiers(input)); 1430 const typeParameters = ensureTypeParams(input, input.typeParameters); 1431 const ctor = getFirstConstructorWithBody(input); 1432 let parameterProperties: readonly PropertyDeclaration[] | undefined; 1433 if (ctor) { 1434 const oldDiag = getSymbolAccessibilityDiagnostic; 1435 parameterProperties = compact(flatMap(ctor.parameters, (param) => { 1436 if (!hasSyntacticModifier(param, ModifierFlags.ParameterPropertyModifier) || shouldStripInternal(param)) return; 1437 getSymbolAccessibilityDiagnostic = createGetSymbolAccessibilityDiagnosticForNode(param); 1438 if (param.name.kind === SyntaxKind.Identifier) { 1439 return preserveJsDoc(factory.createPropertyDeclaration( 1440 ensureModifiers(param), 1441 param.name, 1442 param.questionToken, 1443 ensureType(param, param.type), 1444 ensureNoInitializer(param)), param); 1445 } 1446 else { 1447 // Pattern - this is currently an error, but we emit declarations for it somewhat correctly 1448 return walkBindingPattern(param.name); 1449 } 1450 1451 function walkBindingPattern(pattern: BindingPattern) { 1452 let elems: PropertyDeclaration[] | undefined; 1453 for (const elem of pattern.elements) { 1454 if (isOmittedExpression(elem)) continue; 1455 if (isBindingPattern(elem.name)) { 1456 elems = concatenate(elems, walkBindingPattern(elem.name)); 1457 } 1458 elems = elems || []; 1459 elems.push(factory.createPropertyDeclaration( 1460 ensureModifiers(param), 1461 elem.name as Identifier, 1462 /*questionToken*/ undefined, 1463 ensureType(elem, /*type*/ undefined), 1464 /*initializer*/ undefined 1465 )); 1466 } 1467 return elems; 1468 } 1469 })); 1470 getSymbolAccessibilityDiagnostic = oldDiag; 1471 } 1472 1473 const hasPrivateIdentifier = some(input.members, member => !!member.name && isPrivateIdentifier(member.name)); 1474 // When the class has at least one private identifier, create a unique constant identifier to retain the nominal typing behavior 1475 // Prevents other classes with the same public members from being used in place of the current class 1476 const privateIdentifier = hasPrivateIdentifier ? [ 1477 factory.createPropertyDeclaration( 1478 /*modifiers*/ undefined, 1479 factory.createPrivateIdentifier("#private"), 1480 /*questionToken*/ undefined, 1481 /*type*/ undefined, 1482 /*initializer*/ undefined 1483 ) 1484 ] : undefined; 1485 const memberNodes = concatenate(concatenate(privateIdentifier, parameterProperties), visitNodes(input.members, visitDeclarationSubtree)); 1486 const members = factory.createNodeArray(memberNodes); 1487 1488 const extendsClause = getEffectiveBaseTypeNode(input); 1489 if (extendsClause && !isEntityNameExpression(extendsClause.expression) && extendsClause.expression.kind !== SyntaxKind.NullKeyword) { 1490 // We must add a temporary declaration for the extends clause expression 1491 1492 const oldId = input.name ? unescapeLeadingUnderscores(input.name.escapedText) : "default"; 1493 const newId = factory.createUniqueName(`${oldId}_base`, GeneratedIdentifierFlags.Optimistic); 1494 getSymbolAccessibilityDiagnostic = () => ({ 1495 diagnosticMessage: Diagnostics.extends_clause_of_exported_class_0_has_or_is_using_private_name_1, 1496 errorNode: extendsClause, 1497 typeName: input.name 1498 }); 1499 const varDecl = factory.createVariableDeclaration(newId, /*exclamationToken*/ undefined, resolver.createTypeOfExpression(extendsClause.expression, input, declarationEmitNodeBuilderFlags, symbolTracker), /*initializer*/ undefined); 1500 const statement = factory.createVariableStatement(needsDeclare ? [factory.createModifier(SyntaxKind.DeclareKeyword)] : [], factory.createVariableDeclarationList([varDecl], NodeFlags.Const)); 1501 const heritageClauses = factory.createNodeArray(map(input.heritageClauses, clause => { 1502 if (clause.token === SyntaxKind.ExtendsKeyword) { 1503 const oldDiag = getSymbolAccessibilityDiagnostic; 1504 getSymbolAccessibilityDiagnostic = createGetSymbolAccessibilityDiagnosticForNode(clause.types[0]); 1505 const newClause = factory.updateHeritageClause(clause, map(clause.types, t => factory.updateExpressionWithTypeArguments(t, newId, visitNodes(t.typeArguments, visitDeclarationSubtree)))); 1506 getSymbolAccessibilityDiagnostic = oldDiag; 1507 return newClause; 1508 } 1509 return factory.updateHeritageClause(clause, visitNodes(factory.createNodeArray(filter(clause.types, t => isEntityNameExpression(t.expression) || t.expression.kind === SyntaxKind.NullKeyword)), visitDeclarationSubtree)); 1510 })); 1511 let reservedDecorators = getReservedDecoratorsOfEtsFile(input, host); 1512 1513 return [statement, cleanup(factory.updateClassDeclaration( 1514 input, 1515 concatenateDecoratorsAndModifiers(reservedDecorators, modifiers), 1516 input.name, 1517 typeParameters, 1518 heritageClauses, 1519 members 1520 ))!]; // TODO: GH#18217 1521 } 1522 else { 1523 const heritageClauses = transformHeritageClauses(input.heritageClauses); 1524 let reservedDecorators = getReservedDecoratorsOfEtsFile(input, host);; 1525 1526 return cleanup(factory.updateClassDeclaration( 1527 input, 1528 concatenateDecoratorsAndModifiers(reservedDecorators, modifiers), 1529 input.name, 1530 typeParameters, 1531 heritageClauses, 1532 members 1533 )); 1534 } 1535 } 1536 case SyntaxKind.VariableStatement: { 1537 return cleanup(transformVariableStatement(input)); 1538 } 1539 case SyntaxKind.EnumDeclaration: { 1540 return cleanup(factory.updateEnumDeclaration(input, factory.createNodeArray(ensureModifiers(input)), input.name, factory.createNodeArray(mapDefined(input.members, m => { 1541 if (shouldStripInternal(m)) return; 1542 // Rewrite enum values to their constants, if available 1543 const constValue = resolver.getConstantValue(m); 1544 return preserveJsDoc(factory.updateEnumMember(m, m.name, constValue !== undefined ? typeof constValue === "string" ? factory.createStringLiteral(constValue) : factory.createNumericLiteral(constValue) : undefined), m); 1545 })))); 1546 } 1547 } 1548 1549 function cleanup<T extends Node>(node: T | undefined): T | undefined { 1550 if (isEnclosingDeclaration(input)) { 1551 enclosingDeclaration = previousEnclosingDeclaration; 1552 } 1553 if (canProdiceDiagnostic) { 1554 getSymbolAccessibilityDiagnostic = oldDiag; 1555 } 1556 if (input.kind === SyntaxKind.ModuleDeclaration) { 1557 needsDeclare = previousNeedsDeclare; 1558 } 1559 if (node as Node === input) { 1560 return node; 1561 } 1562 errorFallbackNode = undefined; 1563 errorNameNode = undefined; 1564 return node && setOriginalNode(preserveJsDoc(node, input), input); 1565 } 1566 } 1567 1568 function transformVariableStatement(input: VariableStatement) { 1569 if (!forEach(input.declarationList.declarations, getBindingNameVisible)) return; 1570 const nodes = visitNodes(input.declarationList.declarations, visitDeclarationSubtree); 1571 if (!length(nodes)) return; 1572 return factory.updateVariableStatement(input, factory.createNodeArray(ensureModifiers(input)), factory.updateVariableDeclarationList(input.declarationList, nodes)); 1573 } 1574 1575 function recreateBindingPattern(d: BindingPattern): VariableDeclaration[] { 1576 return flatten<VariableDeclaration>(mapDefined(d.elements, e => recreateBindingElement(e))); 1577 } 1578 1579 function recreateBindingElement(e: ArrayBindingElement) { 1580 if (e.kind === SyntaxKind.OmittedExpression) { 1581 return; 1582 } 1583 if (e.name) { 1584 if (!getBindingNameVisible(e)) return; 1585 if (isBindingPattern(e.name)) { 1586 return recreateBindingPattern(e.name); 1587 } 1588 else { 1589 return factory.createVariableDeclaration(e.name, /*exclamationToken*/ undefined, ensureType(e, /*type*/ undefined), /*initializer*/ undefined); 1590 } 1591 } 1592 } 1593 1594 function checkName(node: DeclarationDiagnosticProducing) { 1595 let oldDiag: typeof getSymbolAccessibilityDiagnostic | undefined; 1596 if (!suppressNewDiagnosticContexts) { 1597 oldDiag = getSymbolAccessibilityDiagnostic; 1598 getSymbolAccessibilityDiagnostic = createGetSymbolAccessibilityDiagnosticForNodeName(node); 1599 } 1600 errorNameNode = (node as NamedDeclaration).name; 1601 Debug.assert(resolver.isLateBound(getParseTreeNode(node) as Declaration)); // Should only be called with dynamic names 1602 const decl = node as NamedDeclaration as LateBoundDeclaration; 1603 const entityName = decl.name.expression; 1604 checkEntityNameVisibility(entityName, enclosingDeclaration); 1605 if (!suppressNewDiagnosticContexts) { 1606 getSymbolAccessibilityDiagnostic = oldDiag!; 1607 } 1608 errorNameNode = undefined; 1609 } 1610 1611 function shouldStripInternal(node: Node) { 1612 return !!stripInternal && !!node && isInternalDeclaration(node, currentSourceFile); 1613 } 1614 1615 function isScopeMarker(node: Node) { 1616 return isExportAssignment(node) || isExportDeclaration(node); 1617 } 1618 1619 function hasScopeMarker(statements: readonly Statement[]) { 1620 return some(statements, isScopeMarker); 1621 } 1622 1623 function ensureModifiers<T extends HasModifiers>(node: T): readonly Modifier[] | undefined { 1624 const currentFlags = getEffectiveModifierFlags(node); 1625 const newFlags = ensureModifierFlags(node); 1626 if (currentFlags === newFlags) { 1627 return visitArray(node.modifiers, n => tryCast(n, isModifier), isModifier); 1628 } 1629 return factory.createModifiersFromModifierFlags(newFlags); 1630 } 1631 1632 function ensureModifierFlags(node: Node): ModifierFlags { 1633 let mask = ModifierFlags.All ^ (ModifierFlags.Public | ModifierFlags.Async | ModifierFlags.Override); // No async and override modifiers in declaration files 1634 let additions = (needsDeclare && !isAlwaysType(node)) ? ModifierFlags.Ambient : ModifierFlags.None; 1635 const parentIsFile = node.parent.kind === SyntaxKind.SourceFile; 1636 if (!parentIsFile || (isBundledEmit && parentIsFile && isExternalModule(node.parent as SourceFile))) { 1637 mask ^= ModifierFlags.Ambient; 1638 additions = ModifierFlags.None; 1639 } 1640 return maskModifierFlags(node, mask, additions); 1641 } 1642 1643 function getTypeAnnotationFromAllAccessorDeclarations(node: AccessorDeclaration, accessors: AllAccessorDeclarations) { 1644 let accessorType = getTypeAnnotationFromAccessor(node); 1645 if (!accessorType && node !== accessors.firstAccessor) { 1646 accessorType = getTypeAnnotationFromAccessor(accessors.firstAccessor); 1647 // If we end up pulling the type from the second accessor, we also need to change the diagnostic context to get the expected error message 1648 getSymbolAccessibilityDiagnostic = createGetSymbolAccessibilityDiagnosticForNode(accessors.firstAccessor); 1649 } 1650 if (!accessorType && accessors.secondAccessor && node !== accessors.secondAccessor) { 1651 accessorType = getTypeAnnotationFromAccessor(accessors.secondAccessor); 1652 // If we end up pulling the type from the second accessor, we also need to change the diagnostic context to get the expected error message 1653 getSymbolAccessibilityDiagnostic = createGetSymbolAccessibilityDiagnosticForNode(accessors.secondAccessor); 1654 } 1655 return accessorType; 1656 } 1657 1658 function transformHeritageClauses(nodes: NodeArray<HeritageClause> | undefined) { 1659 return factory.createNodeArray(filter(map(nodes, clause => factory.updateHeritageClause(clause, visitNodes(factory.createNodeArray(filter(clause.types, t => { 1660 return isEntityNameExpression(t.expression) || (clause.token === SyntaxKind.ExtendsKeyword && t.expression.kind === SyntaxKind.NullKeyword); 1661 })), visitDeclarationSubtree))), clause => clause.types && !!clause.types.length)); 1662 } 1663 } 1664 1665 function isAlwaysType(node: Node) { 1666 if (node.kind === SyntaxKind.InterfaceDeclaration) { 1667 return true; 1668 } 1669 return false; 1670 } 1671 1672 // Elide "public" modifier, as it is the default 1673 function maskModifiers(node: Node, modifierMask?: ModifierFlags, modifierAdditions?: ModifierFlags): Modifier[] | undefined { 1674 return factory.createModifiersFromModifierFlags(maskModifierFlags(node, modifierMask, modifierAdditions)); 1675 } 1676 1677 function maskModifierFlags(node: Node, modifierMask: ModifierFlags = ModifierFlags.All ^ ModifierFlags.Public, modifierAdditions: ModifierFlags = ModifierFlags.None): ModifierFlags { 1678 let flags = (getEffectiveModifierFlags(node) & modifierMask) | modifierAdditions; 1679 if (flags & ModifierFlags.Default && !(flags & ModifierFlags.Export)) { 1680 // A non-exported default is a nonsequitor - we usually try to remove all export modifiers 1681 // from statements in ambient declarations; but a default export must retain its export modifier to be syntactically valid 1682 flags ^= ModifierFlags.Export; 1683 } 1684 if (flags & ModifierFlags.Default && flags & ModifierFlags.Ambient) { 1685 flags ^= ModifierFlags.Ambient; // `declare` is never required alongside `default` (and would be an error if printed) 1686 } 1687 return flags; 1688 } 1689 1690 function getTypeAnnotationFromAccessor(accessor: AccessorDeclaration): TypeNode | undefined { 1691 if (accessor) { 1692 return accessor.kind === SyntaxKind.GetAccessor 1693 ? accessor.type // Getter - return type 1694 : accessor.parameters.length > 0 1695 ? accessor.parameters[0].type // Setter parameter type 1696 : undefined; 1697 } 1698 } 1699 1700 type CanHaveLiteralInitializer = VariableDeclaration | PropertyDeclaration | PropertySignature | ParameterDeclaration; 1701 function canHaveLiteralInitializer(node: Node): boolean { 1702 switch (node.kind) { 1703 case SyntaxKind.PropertyDeclaration: 1704 case SyntaxKind.PropertySignature: 1705 return !hasEffectiveModifier(node, ModifierFlags.Private); 1706 case SyntaxKind.Parameter: 1707 case SyntaxKind.VariableDeclaration: 1708 return true; 1709 } 1710 return false; 1711 } 1712 1713 type ProcessedDeclarationStatement = 1714 | FunctionDeclaration 1715 | ModuleDeclaration 1716 | ImportEqualsDeclaration 1717 | InterfaceDeclaration 1718 | ClassDeclaration 1719 | TypeAliasDeclaration 1720 | EnumDeclaration 1721 | VariableStatement 1722 | ImportDeclaration 1723 | ExportDeclaration 1724 | ExportAssignment; 1725 1726 function isPreservedDeclarationStatement(node: Node): node is ProcessedDeclarationStatement { 1727 switch (node.kind) { 1728 case SyntaxKind.FunctionDeclaration: 1729 case SyntaxKind.ModuleDeclaration: 1730 case SyntaxKind.ImportEqualsDeclaration: 1731 case SyntaxKind.InterfaceDeclaration: 1732 case SyntaxKind.ClassDeclaration: 1733 case SyntaxKind.StructDeclaration: 1734 case SyntaxKind.TypeAliasDeclaration: 1735 case SyntaxKind.EnumDeclaration: 1736 case SyntaxKind.VariableStatement: 1737 case SyntaxKind.ImportDeclaration: 1738 case SyntaxKind.ExportDeclaration: 1739 case SyntaxKind.ExportAssignment: 1740 return true; 1741 } 1742 return false; 1743 } 1744 1745 type ProcessedComponent = 1746 | ConstructSignatureDeclaration 1747 | ConstructorDeclaration 1748 | MethodDeclaration 1749 | GetAccessorDeclaration 1750 | SetAccessorDeclaration 1751 | PropertyDeclaration 1752 | PropertySignature 1753 | MethodSignature 1754 | CallSignatureDeclaration 1755 | IndexSignatureDeclaration 1756 | VariableDeclaration 1757 | TypeParameterDeclaration 1758 | ExpressionWithTypeArguments 1759 | TypeReferenceNode 1760 | ConditionalTypeNode 1761 | FunctionTypeNode 1762 | ConstructorTypeNode 1763 | ImportTypeNode; 1764 1765 function isProcessedComponent(node: Node): node is ProcessedComponent { 1766 switch (node.kind) { 1767 case SyntaxKind.ConstructSignature: 1768 case SyntaxKind.Constructor: 1769 case SyntaxKind.MethodDeclaration: 1770 case SyntaxKind.GetAccessor: 1771 case SyntaxKind.SetAccessor: 1772 case SyntaxKind.PropertyDeclaration: 1773 case SyntaxKind.PropertySignature: 1774 case SyntaxKind.MethodSignature: 1775 case SyntaxKind.CallSignature: 1776 case SyntaxKind.IndexSignature: 1777 case SyntaxKind.VariableDeclaration: 1778 case SyntaxKind.TypeParameter: 1779 case SyntaxKind.ExpressionWithTypeArguments: 1780 case SyntaxKind.TypeReference: 1781 case SyntaxKind.ConditionalType: 1782 case SyntaxKind.FunctionType: 1783 case SyntaxKind.ConstructorType: 1784 case SyntaxKind.ImportType: 1785 return true; 1786 } 1787 return false; 1788 } 1789} 1790