diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index a570a61248952..3f8a22ffa8608 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -4092,7 +4092,15 @@ namespace ts { // ambient module, just use declaration/symbol name (fallthrough) } else { - return `"${getResolvedExternalModuleName(context.tracker.moduleResolverHost, file, getSourceFileOfNode(getOriginalNode(context.enclosingDeclaration)))}"`; + const contextFile = getSourceFileOfNode(getOriginalNode(context!.enclosingDeclaration))!; + return `"${file.moduleName || moduleSpecifiers.getModuleSpecifiers( + symbol, + compilerOptions, + contextFile, + context!.tracker.moduleResolverHost!, + context!.tracker.moduleResolverHost!.getSourceFiles!(), + { importModuleSpecifierPreference: "non-relative" } + )[0]}"`; } } const declaration = symbol.declarations[0]; diff --git a/src/compiler/moduleNameResolver.ts b/src/compiler/moduleNameResolver.ts index 510fc096297a7..442f1c8221f18 100644 --- a/src/compiler/moduleNameResolver.ts +++ b/src/compiler/moduleNameResolver.ts @@ -132,10 +132,6 @@ namespace ts { } } - export interface GetEffectiveTypeRootsHost { - directoryExists?(directoryName: string): boolean; - getCurrentDirectory?(): string; - } export function getEffectiveTypeRoots(options: CompilerOptions, host: GetEffectiveTypeRootsHost): string[] | undefined { if (options.typeRoots) { return options.typeRoots; diff --git a/src/services/codefixes/moduleSpecifiers.ts b/src/compiler/moduleSpecifiers.ts similarity index 75% rename from src/services/codefixes/moduleSpecifiers.ts rename to src/compiler/moduleSpecifiers.ts index 42b438f7ccc05..404bd192217e9 100644 --- a/src/services/codefixes/moduleSpecifiers.ts +++ b/src/compiler/moduleSpecifiers.ts @@ -1,10 +1,13 @@ // Used by importFixes to synthesize import module specifiers. /* @internal */ namespace ts.moduleSpecifiers { + export interface ModuleSpecifierPreferences { + importModuleSpecifierPreference?: "relative" | "non-relative"; + } + // Note: fromSourceFile is just for usesJsExtensionOnImports - export function getModuleSpecifier(program: Program, fromSourceFile: SourceFile, fromSourceFileName: string, toFileName: string, host: LanguageServiceHost, preferences: UserPreferences) { - const info = getInfo(program.getCompilerOptions(), fromSourceFile, fromSourceFileName, host); - const compilerOptions = program.getCompilerOptions(); + export function getModuleSpecifier(compilerOptions: CompilerOptions, fromSourceFile: SourceFile, fromSourceFileName: string, toFileName: string, host: ModuleSpecifierResolutionHost, preferences: ModuleSpecifierPreferences = {}) { + const info = getInfo(compilerOptions, fromSourceFile, fromSourceFileName, host); return getGlobalModuleSpecifier(toFileName, info, host, compilerOptions) || first(getLocalModuleSpecifiers(toFileName, info, compilerOptions, preferences)); } @@ -12,17 +15,20 @@ namespace ts.moduleSpecifiers { // For each symlink/original for a module, returns a list of ways to import that file. export function getModuleSpecifiers( moduleSymbol: Symbol, - program: Program, + compilerOptions: CompilerOptions, importingSourceFile: SourceFile, - host: LanguageServiceHost, - preferences: UserPreferences, + host: ModuleSpecifierResolutionHost, + files: ReadonlyArray, + preferences: ModuleSpecifierPreferences, ): ReadonlyArray> { const ambient = tryGetModuleNameFromAmbientModule(moduleSymbol); if (ambient) return [[ambient]]; - const compilerOptions = program.getCompilerOptions(); - const info = getInfo(compilerOptions, importingSourceFile, importingSourceFile.fileName, host); - const modulePaths = getAllModulePaths(program, moduleSymbol.valueDeclaration.getSourceFile()); + const info = getInfo(compilerOptions, importingSourceFile, importingSourceFile.path, host); + if (!files) { + return Debug.fail("Files list must be present to resolve symlinks in specifier resolution"); + } + const modulePaths = getAllModulePaths(files, getSourceFileOfNode(moduleSymbol.valueDeclaration), info.getCanonicalFileName, host); const global = mapDefined(modulePaths, moduleFileName => getGlobalModuleSpecifier(moduleFileName, info, host, compilerOptions)); return global.length ? global.map(g => [g]) : modulePaths.map(moduleFileName => @@ -36,10 +42,10 @@ namespace ts.moduleSpecifiers { readonly sourceDirectory: string; } // importingSourceFileName is separate because getEditsForFileRename may need to specify an updated path - function getInfo(compilerOptions: CompilerOptions, importingSourceFile: SourceFile, importingSourceFileName: string, host: LanguageServiceHost): Info { + function getInfo(compilerOptions: CompilerOptions, importingSourceFile: SourceFile, importingSourceFileName: string, host: ModuleSpecifierResolutionHost): Info { const moduleResolutionKind = getEmitModuleResolutionKind(compilerOptions); const addJsExtension = usesJsExtensionOnImports(importingSourceFile); - const getCanonicalFileName = hostGetCanonicalFileName(host); + const getCanonicalFileName = createGetCanonicalFileName(host.useCaseSensitiveFileNames ? host.useCaseSensitiveFileNames() : true); const sourceDirectory = getDirectoryPath(importingSourceFileName); return { moduleResolutionKind, addJsExtension, getCanonicalFileName, sourceDirectory }; } @@ -47,7 +53,7 @@ namespace ts.moduleSpecifiers { function getGlobalModuleSpecifier( moduleFileName: string, { addJsExtension, getCanonicalFileName, sourceDirectory }: Info, - host: LanguageServiceHost, + host: ModuleSpecifierResolutionHost, compilerOptions: CompilerOptions, ) { return tryGetModuleNameFromTypeRoots(compilerOptions, host, getCanonicalFileName, moduleFileName, addJsExtension) @@ -59,7 +65,7 @@ namespace ts.moduleSpecifiers { moduleFileName: string, { moduleResolutionKind, addJsExtension, getCanonicalFileName, sourceDirectory }: Info, compilerOptions: CompilerOptions, - preferences: UserPreferences, + preferences: ModuleSpecifierPreferences, ) { const { baseUrl, paths } = compilerOptions; @@ -127,15 +133,57 @@ namespace ts.moduleSpecifiers { return firstDefined(imports, ({ text }) => pathIsRelative(text) ? fileExtensionIs(text, Extension.Js) : undefined) || false; } + function discoverProbableSymlinks(files: ReadonlyArray) { + const symlinks = mapDefined(files, sf => + sf.resolvedModules && firstDefinedIterator(sf.resolvedModules.values(), res => + res && res.originalPath && res.resolvedFileName !== res.originalPath ? [res.resolvedFileName, res.originalPath] : undefined)); + const result = createMap(); + if (symlinks) { + for (const [resolvedPath, originalPath] of symlinks) { + const resolvedParts = getPathComponents(resolvedPath); + const originalParts = getPathComponents(originalPath); + while (resolvedParts[resolvedParts.length - 1] === originalParts[originalParts.length - 1]) { + resolvedParts.pop(); + originalParts.pop(); + } + result.set(getPathFromPathComponents(originalParts), getPathFromPathComponents(resolvedParts)); + } + } + return result; + } + + function getAllModulePathsUsingIndirectSymlinks(files: ReadonlyArray, target: string, getCanonicalFileName: (file: string) => string, host: ModuleSpecifierResolutionHost) { + const links = discoverProbableSymlinks(files); + const paths = arrayFrom(links.keys()); + let options: string[] | undefined; + for (const path of paths) { + const resolved = links.get(path)!; + if (startsWith(target, resolved + "/")) { + const relative = getRelativePathFromDirectory(resolved, target, getCanonicalFileName); + const option = resolvePath(path, relative); + if (!host.fileExists || host.fileExists(option)) { + if (!options) options = []; + options.push(option); + } + } + } + const resolvedtarget = host.getCurrentDirectory ? resolvePath(host.getCurrentDirectory(), target) : target; + if (options) { + options.push(resolvedtarget); // Since these are speculative, we also include the original resolved name as a possibility + return options; + } + return [resolvedtarget]; + } + /** * Looks for a existing imports that use symlinks to this module. * Only if no symlink is available, the real path will be used. */ - function getAllModulePaths(program: Program, { fileName }: SourceFile): ReadonlyArray { - const symlinks = mapDefined(program.getSourceFiles(), sf => + function getAllModulePaths(files: ReadonlyArray, { fileName }: SourceFile, getCanonicalFileName: (file: string) => string, host: ModuleSpecifierResolutionHost): ReadonlyArray { + const symlinks = mapDefined(files, sf => sf.resolvedModules && firstDefinedIterator(sf.resolvedModules.values(), res => res && res.resolvedFileName === fileName ? res.originalPath : undefined)); - return symlinks.length === 0 ? [fileName] : symlinks; + return symlinks.length === 0 ? getAllModulePathsUsingIndirectSymlinks(files, fileName, getCanonicalFileName, host) : symlinks; } function getRelativePathNParents(relativePath: string): number { @@ -210,7 +258,7 @@ namespace ts.moduleSpecifiers { function tryGetModuleNameAsNodeModule( options: CompilerOptions, moduleFileName: string, - host: LanguageServiceHost, + host: ModuleSpecifierResolutionHost, getCanonicalFileName: (file: string) => string, sourceDirectory: string, ): string | undefined { @@ -255,7 +303,8 @@ namespace ts.moduleSpecifiers { const fullModulePathWithoutExtension = removeFileExtension(path); // If the file is /index, it can be imported by its directory name - if (getCanonicalFileName(fullModulePathWithoutExtension.substring(parts.fileNameIndex)) === "/index") { + // IFF there is not _also_ a file by the same name + if (getCanonicalFileName(fullModulePathWithoutExtension.substring(parts.fileNameIndex)) === "/index" && !tryGetAnyFileFromPath(host, fullModulePathWithoutExtension.substring(0, parts.fileNameIndex))) { return fullModulePathWithoutExtension.substring(0, parts.fileNameIndex); } @@ -274,6 +323,17 @@ namespace ts.moduleSpecifiers { } } + function tryGetAnyFileFromPath(host: ModuleSpecifierResolutionHost, path: string) { + // We check all js, `node` and `json` extensions in addition to TS, since node module resolution would also choose those over the directory + const extensions = getSupportedExtensions({ allowJs: true }, [{ extension: "node", isMixedContent: false }, { extension: "json", isMixedContent: false, scriptKind: ScriptKind.JSON }]); + for (const e of extensions) { + const fullPath = path + e; + if (host.fileExists!(fullPath)) { // TODO: GH#18217 + return fullPath; + } + } + } + function getNodeModulePathParts(fullPath: string) { // If fullPath can't be valid module file within node_modules, returns undefined. // Example of expected pattern: /base/path/node_modules/[@scope/otherpackage/@otherscope/node_modules/]package/[subdirectory/]file.js diff --git a/src/compiler/program.ts b/src/compiler/program.ts index 1e0ebf1d5525f..baa277ee2c5b9 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -1168,6 +1168,9 @@ namespace ts { writeFile: writeFileCallback || ( (fileName, data, writeByteOrderMark, onError, sourceFiles) => host.writeFile(fileName, data, writeByteOrderMark, onError, sourceFiles)), isEmitBlocked, + readFile: f => host.readFile(f), + fileExists: f => host.fileExists(f), + ...(host.directoryExists ? { directoryExists: f => host.directoryExists!(f) } : {}), }; } diff --git a/src/compiler/tsconfig.json b/src/compiler/tsconfig.json index 46e5384434a01..5716a2a417d56 100644 --- a/src/compiler/tsconfig.json +++ b/src/compiler/tsconfig.json @@ -44,6 +44,7 @@ "builderState.ts", "builder.ts", "resolutionCache.ts", + "moduleSpecifiers.ts", "watch.ts", "commandLineParser.ts", "tsc.ts" diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 7ef6f6a9dada1..d36516a9d3820 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -5011,8 +5011,9 @@ namespace ts { } /* @internal */ - export interface EmitHost extends ScriptReferenceHost { + export interface EmitHost extends ScriptReferenceHost, ModuleSpecifierResolutionHost { getSourceFiles(): ReadonlyArray; + getCurrentDirectory(): string; /* @internal */ isSourceFileFromExternalLibrary(file: SourceFile): boolean; @@ -5274,11 +5275,16 @@ namespace ts { isAtStartOfLine(): boolean; } - /* @internal */ - export interface ModuleNameResolverHost { - getCanonicalFileName(f: string): string; - getCommonSourceDirectory(): string; - getCurrentDirectory(): string; + export interface GetEffectiveTypeRootsHost { + directoryExists?(directoryName: string): boolean; + getCurrentDirectory?(): string; + } + /** @internal */ + export interface ModuleSpecifierResolutionHost extends GetEffectiveTypeRootsHost { + useCaseSensitiveFileNames?(): boolean; + fileExists?(path: string): boolean; + readFile?(path: string): string | undefined; + getSourceFiles?(): ReadonlyArray; // Used for cached resolutions to find symlinks without traversing the fs (again) } /** @deprecated See comment on SymbolWriter */ @@ -5292,7 +5298,7 @@ namespace ts { reportPrivateInBaseOfClassExpression?(propertyName: string): void; reportInaccessibleUniqueSymbolError?(): void; /* @internal */ - moduleResolverHost?: ModuleNameResolverHost; + moduleResolverHost?: ModuleSpecifierResolutionHost; /* @internal */ trackReferencedAmbientModule?(decl: ModuleDeclaration): void; } diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 55413600921de..fbba818fe111f 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -2893,11 +2893,11 @@ namespace ts { }; } - export function getResolvedExternalModuleName(host: ModuleNameResolverHost, file: SourceFile, referenceFile?: SourceFile): string { + export function getResolvedExternalModuleName(host: EmitHost, file: SourceFile, referenceFile?: SourceFile): string { return file.moduleName || getExternalModuleNameFromPath(host, file.fileName, referenceFile && referenceFile.fileName); } - export function getExternalModuleNameFromDeclaration(host: ModuleNameResolverHost, resolver: EmitResolver, declaration: ImportEqualsDeclaration | ImportDeclaration | ExportDeclaration | ModuleDeclaration | ImportTypeNode): string { + export function getExternalModuleNameFromDeclaration(host: EmitHost, resolver: EmitResolver, declaration: ImportEqualsDeclaration | ImportDeclaration | ExportDeclaration | ModuleDeclaration | ImportTypeNode): string | undefined { const file = resolver.getExternalModuleFileFromDeclaration(declaration); if (!file || file.isDeclarationFile) { return undefined; @@ -2908,7 +2908,7 @@ namespace ts { /** * Resolves a local path to a path which is absolute to the base of the emit */ - export function getExternalModuleNameFromPath(host: ModuleNameResolverHost, fileName: string, referencePath?: string): string { + export function getExternalModuleNameFromPath(host: EmitHost, fileName: string, referencePath?: string): string { const getCanonicalFileName = (f: string) => host.getCanonicalFileName(f); const dir = toPath(referencePath ? getDirectoryPath(referencePath) : host.getCommonSourceDirectory(), host.getCurrentDirectory(), getCanonicalFileName); const filePath = getNormalizedAbsolutePath(fileName, host.getCurrentDirectory()); diff --git a/src/harness/compilerRunner.ts b/src/harness/compilerRunner.ts index b899f3107c578..5d8454b2ef407 100644 --- a/src/harness/compilerRunner.ts +++ b/src/harness/compilerRunner.ts @@ -187,7 +187,9 @@ class CompilerTest { this.otherFiles, this.harnessSettings, /*options*/ tsConfigOptions, - /*currentDirectory*/ this.harnessSettings.currentDirectory); + /*currentDirectory*/ this.harnessSettings.currentDirectory, + testCaseContent.symlinks + ); this.options = this.result.options; } diff --git a/src/harness/harness.ts b/src/harness/harness.ts index f894a377ad737..7d0e2875f5b45 100644 --- a/src/harness/harness.ts +++ b/src/harness/harness.ts @@ -1138,6 +1138,7 @@ namespace Harness { { name: "noImplicitReferences", type: "boolean" }, { name: "currentDirectory", type: "string" }, { name: "symlink", type: "string" }, + { name: "link", type: "string" }, // Emitted js baseline will print full paths for every output file { name: "fullEmitPaths", type: "boolean" } ]; @@ -1209,7 +1210,9 @@ namespace Harness { harnessSettings: TestCaseParser.CompilerSettings, compilerOptions: ts.CompilerOptions, // Current directory is needed for rwcRunner to be able to use currentDirectory defined in json file - currentDirectory: string): compiler.CompilationResult { + currentDirectory: string | undefined, + symlinks?: vfs.FileSet + ): compiler.CompilationResult { const options: ts.CompilerOptions & HarnessOptions = compilerOptions ? ts.cloneCompilerOptions(compilerOptions) : { noResolve: false }; options.target = options.target || ts.ScriptTarget.ES3; options.newLine = options.newLine || ts.NewLineKind.CarriageReturnLineFeed; @@ -1246,6 +1249,9 @@ namespace Harness { const docs = inputFiles.concat(otherFiles).map(documents.TextDocument.fromTestFile); const fs = vfs.createFromFileSystem(IO, !useCaseSensitiveFileNames, { documents: docs, cwd: currentDirectory }); + if (symlinks) { + fs.apply(symlinks); + } const host = new fakes.CompilerHost(fs, options); return compiler.compileFiles(host, programFileNames, options); } @@ -1858,6 +1864,7 @@ namespace Harness { // Regex for parsing options in the format "@Alpha: Value of any sort" const optionRegex = /^[\/]{2}\s*@(\w+)\s*:\s*([^\r\n]*)/gm; // multiple matches on multiple lines + const linkRegex = /^[\/]{2}\s*@link\s*:\s*([^\r\n]*)\s*->\s*([^\r\n]*)/gm; // multiple matches on multiple lines export function extractCompilerSettings(content: string): CompilerSettings { const opts: CompilerSettings = {}; @@ -1875,8 +1882,9 @@ namespace Harness { export interface TestCaseContent { settings: CompilerSettings; testUnitData: TestUnitData[]; - tsConfig: ts.ParsedCommandLine; - tsConfigFileUnitData: TestUnitData; + tsConfig: ts.ParsedCommandLine | undefined; + tsConfigFileUnitData: TestUnitData | undefined; + symlinks?: vfs.FileSet; } /** Given a test file containing // @FileName directives, return an array of named units of code to be added to an existing compiler instance */ @@ -1891,10 +1899,16 @@ namespace Harness { let currentFileOptions: any = {}; let currentFileName: any; let refs: string[] = []; + let symlinks: vfs.FileSet | undefined; for (const line of lines) { - const testMetaData = optionRegex.exec(line); - if (testMetaData) { + let testMetaData: RegExpExecArray | null; + const linkMetaData = linkRegex.exec(line); + if (linkMetaData) { + if (!symlinks) symlinks = {}; + symlinks[linkMetaData[2].trim()] = new vfs.Symlink(linkMetaData[1].trim()); + } + else if (testMetaData = optionRegex.exec(line)) { // Comment line, check for global/file @options and record them optionRegex.lastIndex = 0; const metaDataName = testMetaData[1].toLowerCase(); @@ -1983,7 +1997,7 @@ namespace Harness { break; } } - return { settings, testUnitData, tsConfig, tsConfigFileUnitData }; + return { settings, testUnitData, tsConfig, tsConfigFileUnitData, symlinks }; } } diff --git a/src/harness/tsconfig.json b/src/harness/tsconfig.json index e8cebb5e2b959..3ef32b961b497 100644 --- a/src/harness/tsconfig.json +++ b/src/harness/tsconfig.json @@ -51,6 +51,7 @@ "../compiler/builderState.ts", "../compiler/builder.ts", "../compiler/resolutionCache.ts", + "../compiler/moduleSpecifiers.ts", "../compiler/watch.ts", "../compiler/commandLineParser.ts", @@ -115,7 +116,6 @@ "../services/codefixes/inferFromUsage.ts", "../services/codefixes/fixInvalidImportSyntax.ts", "../services/codefixes/fixStrictClassInitialization.ts", - "../services/codefixes/moduleSpecifiers.ts", "../services/codefixes/requireInTs.ts", "../services/codefixes/useDefaultImport.ts", "../services/codefixes/fixAddModuleReferTypeMissingTypeof.ts", diff --git a/src/harness/vfs.ts b/src/harness/vfs.ts index 34a48f5909104..1285e867f9e28 100644 --- a/src/harness/vfs.ts +++ b/src/harness/vfs.ts @@ -883,7 +883,7 @@ namespace vfs { if (this.stringComparer(vpath.dirname(path), path) === 0) { throw new TypeError("Roots cannot be symbolic links."); } - this.symlinkSync(entry.symlink, path); + this.symlinkSync(vpath.resolve(dirname, entry.symlink), path); this._applyFileExtendedOptions(path, entry); } else if (entry instanceof Link) { @@ -1050,8 +1050,7 @@ namespace vfs { if (symlink) { for (const link of symlink.split(",").map(link => link.trim())) { fs.mkdirpSync(vpath.dirname(link)); - fs.symlinkSync(document.file, link); - fs.filemeta(link).set("document", document); + fs.symlinkSync(vpath.resolve(fs.cwd(), document.file), link); } } } diff --git a/src/server/tsconfig.json b/src/server/tsconfig.json index f8ea769d92c08..8b4ac15a64e5f 100644 --- a/src/server/tsconfig.json +++ b/src/server/tsconfig.json @@ -47,6 +47,7 @@ "../compiler/builderState.ts", "../compiler/builder.ts", "../compiler/resolutionCache.ts", + "../compiler/moduleSpecifiers.ts", "../compiler/watch.ts", "../compiler/commandLineParser.ts", @@ -111,7 +112,6 @@ "../services/codefixes/inferFromUsage.ts", "../services/codefixes/fixInvalidImportSyntax.ts", "../services/codefixes/fixStrictClassInitialization.ts", - "../services/codefixes/moduleSpecifiers.ts", "../services/codefixes/requireInTs.ts", "../services/codefixes/useDefaultImport.ts", "../services/codefixes/fixAddModuleReferTypeMissingTypeof.ts", diff --git a/src/server/tsconfig.library.json b/src/server/tsconfig.library.json index 8ba0a6edf624b..73ebc7019b381 100644 --- a/src/server/tsconfig.library.json +++ b/src/server/tsconfig.library.json @@ -53,6 +53,7 @@ "../compiler/builderState.ts", "../compiler/builder.ts", "../compiler/resolutionCache.ts", + "../compiler/moduleSpecifiers.ts", "../compiler/watch.ts", "../compiler/commandLineParser.ts", @@ -117,7 +118,6 @@ "../services/codefixes/inferFromUsage.ts", "../services/codefixes/fixInvalidImportSyntax.ts", "../services/codefixes/fixStrictClassInitialization.ts", - "../services/codefixes/moduleSpecifiers.ts", "../services/codefixes/requireInTs.ts", "../services/codefixes/useDefaultImport.ts", "../services/codefixes/fixAddModuleReferTypeMissingTypeof.ts", diff --git a/src/services/codefixes/importFixes.ts b/src/services/codefixes/importFixes.ts index 8d87a707c920a..077276670cad2 100644 --- a/src/services/codefixes/importFixes.ts +++ b/src/services/codefixes/importFixes.ts @@ -237,7 +237,7 @@ namespace ts.codefix { preferences: UserPreferences, ): ReadonlyArray { const choicesForEachExportingModule = flatMap(moduleSymbols, ({ moduleSymbol, importKind }) => { - const modulePathsGroups = moduleSpecifiers.getModuleSpecifiers(moduleSymbol, program, sourceFile, host, preferences); + const modulePathsGroups = moduleSpecifiers.getModuleSpecifiers(moduleSymbol, program.getCompilerOptions(), sourceFile, host, program.getSourceFiles(), preferences); return modulePathsGroups.map(group => group.map(moduleSpecifier => ({ moduleSpecifier, importKind }))); }); // Sort to keep the shortest paths first, but keep [relativePath, importRelativeToBaseUrl] groups together diff --git a/src/services/getEditsForFileRename.ts b/src/services/getEditsForFileRename.ts index 4bac4a2516dc9..a7e41d2014f31 100644 --- a/src/services/getEditsForFileRename.ts +++ b/src/services/getEditsForFileRename.ts @@ -123,7 +123,7 @@ namespace ts { // TODO:GH#18217 ? getSourceFileToImportFromResolved(resolveModuleName(importLiteral.text, oldImportFromPath, program.getCompilerOptions(), host as ModuleResolutionHost), oldToNew, program) : getSourceFileToImport(importLiteral, sourceFile, program, host, oldToNew); - return toImport === undefined ? undefined : moduleSpecifiers.getModuleSpecifier(program, sourceFile, newImportFromPath, toImport, host, preferences); + return toImport === undefined ? undefined : moduleSpecifiers.getModuleSpecifier(program.getCompilerOptions(), sourceFile, newImportFromPath, toImport, host, preferences); }); } } diff --git a/src/services/tsconfig.json b/src/services/tsconfig.json index 05d4831b08f2c..248422925be9a 100644 --- a/src/services/tsconfig.json +++ b/src/services/tsconfig.json @@ -44,6 +44,7 @@ "../compiler/builderState.ts", "../compiler/builder.ts", "../compiler/resolutionCache.ts", + "../compiler/moduleSpecifiers.ts", "../compiler/watch.ts", "../compiler/commandLineParser.ts", @@ -108,7 +109,6 @@ "codefixes/inferFromUsage.ts", "codefixes/fixInvalidImportSyntax.ts", "codefixes/fixStrictClassInitialization.ts", - "codefixes/moduleSpecifiers.ts", "codefixes/requireInTs.ts", "codefixes/useDefaultImport.ts", "codefixes/fixAddModuleReferTypeMissingTypeof.ts", diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index cee465384614a..d1db7480e57dc 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -2876,6 +2876,10 @@ declare namespace ts { omitTrailingSemicolon?: boolean; noEmitHelpers?: boolean; } + interface GetEffectiveTypeRootsHost { + directoryExists?(directoryName: string): boolean; + getCurrentDirectory?(): string; + } /** @deprecated See comment on SymbolWriter */ interface SymbolTracker { trackSymbol?(symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags): void; @@ -3463,10 +3467,6 @@ declare namespace ts { function updateSourceFile(sourceFile: SourceFile, newText: string, textChangeRange: TextChangeRange, aggressiveChecks?: boolean): SourceFile; } declare namespace ts { - interface GetEffectiveTypeRootsHost { - directoryExists?(directoryName: string): boolean; - getCurrentDirectory?(): string; - } function getEffectiveTypeRoots(options: CompilerOptions, host: GetEffectiveTypeRootsHost): string[] | undefined; /** * @param {string | undefined} containingFile - file that contains type reference directive, can be undefined if containing file is unknown. diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index 8685c813ffc89..433a59b940426 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -2876,6 +2876,10 @@ declare namespace ts { omitTrailingSemicolon?: boolean; noEmitHelpers?: boolean; } + interface GetEffectiveTypeRootsHost { + directoryExists?(directoryName: string): boolean; + getCurrentDirectory?(): string; + } /** @deprecated See comment on SymbolWriter */ interface SymbolTracker { trackSymbol?(symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags): void; @@ -3463,10 +3467,6 @@ declare namespace ts { function updateSourceFile(sourceFile: SourceFile, newText: string, textChangeRange: TextChangeRange, aggressiveChecks?: boolean): SourceFile; } declare namespace ts { - interface GetEffectiveTypeRootsHost { - directoryExists?(directoryName: string): boolean; - getCurrentDirectory?(): string; - } function getEffectiveTypeRoots(options: CompilerOptions, host: GetEffectiveTypeRootsHost): string[] | undefined; /** * @param {string | undefined} containingFile - file that contains type reference directive, can be undefined if containing file is unknown. diff --git a/tests/baselines/reference/declarationEmitCommonJsModuleReferencedType.js b/tests/baselines/reference/declarationEmitCommonJsModuleReferencedType.js new file mode 100644 index 0000000000000..1e32c5c4c262b --- /dev/null +++ b/tests/baselines/reference/declarationEmitCommonJsModuleReferencedType.js @@ -0,0 +1,38 @@ +//// [tests/cases/compiler/declarationEmitCommonJsModuleReferencedType.ts] //// + +//// [index.d.ts] +export interface NestedProps {} +//// [index.d.ts] +export interface OtherIndexProps {} +//// [other.d.ts] +export interface OtherProps {} +//// [index.d.ts] +import { OtherProps } from "./other"; +import { OtherIndexProps } from "./other/index"; +import { NestedProps } from "nested"; +export interface SomeProps {} + +export function foo(): [SomeProps, OtherProps, OtherIndexProps, NestedProps]; +//// [index.d.ts] +export interface RootProps {} + +export function bar(): RootProps; +//// [entry.ts] +import { foo } from "foo"; +import { bar } from "root"; +export const x = foo(); +export const y = bar(); + + +//// [entry.js] +"use strict"; +exports.__esModule = true; +var foo_1 = require("foo"); +var root_1 = require("root"); +exports.x = foo_1.foo(); +exports.y = root_1.bar(); + + +//// [entry.d.ts] +export declare const x: [import("foo").SomeProps, import("foo/other").OtherProps, import("foo/other/index").OtherIndexProps, import("foo/node_modules/nested").NestedProps]; +export declare const y: import("root").RootProps; diff --git a/tests/baselines/reference/declarationEmitCommonJsModuleReferencedType.symbols b/tests/baselines/reference/declarationEmitCommonJsModuleReferencedType.symbols new file mode 100644 index 0000000000000..c9c0f98baeef2 --- /dev/null +++ b/tests/baselines/reference/declarationEmitCommonJsModuleReferencedType.symbols @@ -0,0 +1,55 @@ +=== tests/cases/compiler/r/node_modules/foo/node_modules/nested/index.d.ts === +export interface NestedProps {} +>NestedProps : Symbol(NestedProps, Decl(index.d.ts, 0, 0)) + +=== tests/cases/compiler/r/node_modules/foo/other/index.d.ts === +export interface OtherIndexProps {} +>OtherIndexProps : Symbol(OtherIndexProps, Decl(index.d.ts, 0, 0)) + +=== tests/cases/compiler/r/node_modules/foo/other.d.ts === +export interface OtherProps {} +>OtherProps : Symbol(OtherProps, Decl(other.d.ts, 0, 0)) + +=== tests/cases/compiler/r/node_modules/foo/index.d.ts === +import { OtherProps } from "./other"; +>OtherProps : Symbol(OtherProps, Decl(index.d.ts, 0, 8)) + +import { OtherIndexProps } from "./other/index"; +>OtherIndexProps : Symbol(OtherIndexProps, Decl(index.d.ts, 1, 8)) + +import { NestedProps } from "nested"; +>NestedProps : Symbol(NestedProps, Decl(index.d.ts, 2, 8)) + +export interface SomeProps {} +>SomeProps : Symbol(SomeProps, Decl(index.d.ts, 2, 37)) + +export function foo(): [SomeProps, OtherProps, OtherIndexProps, NestedProps]; +>foo : Symbol(foo, Decl(index.d.ts, 3, 29)) +>SomeProps : Symbol(SomeProps, Decl(index.d.ts, 2, 37)) +>OtherProps : Symbol(OtherProps, Decl(index.d.ts, 0, 8)) +>OtherIndexProps : Symbol(OtherIndexProps, Decl(index.d.ts, 1, 8)) +>NestedProps : Symbol(NestedProps, Decl(index.d.ts, 2, 8)) + +=== tests/cases/compiler/node_modules/root/index.d.ts === +export interface RootProps {} +>RootProps : Symbol(RootProps, Decl(index.d.ts, 0, 0)) + +export function bar(): RootProps; +>bar : Symbol(bar, Decl(index.d.ts, 0, 29)) +>RootProps : Symbol(RootProps, Decl(index.d.ts, 0, 0)) + +=== tests/cases/compiler/r/entry.ts === +import { foo } from "foo"; +>foo : Symbol(foo, Decl(entry.ts, 0, 8)) + +import { bar } from "root"; +>bar : Symbol(bar, Decl(entry.ts, 1, 8)) + +export const x = foo(); +>x : Symbol(x, Decl(entry.ts, 2, 12)) +>foo : Symbol(foo, Decl(entry.ts, 0, 8)) + +export const y = bar(); +>y : Symbol(y, Decl(entry.ts, 3, 12)) +>bar : Symbol(bar, Decl(entry.ts, 1, 8)) + diff --git a/tests/baselines/reference/declarationEmitCommonJsModuleReferencedType.types b/tests/baselines/reference/declarationEmitCommonJsModuleReferencedType.types new file mode 100644 index 0000000000000..77c252679da0d --- /dev/null +++ b/tests/baselines/reference/declarationEmitCommonJsModuleReferencedType.types @@ -0,0 +1,57 @@ +=== tests/cases/compiler/r/node_modules/foo/node_modules/nested/index.d.ts === +export interface NestedProps {} +>NestedProps : NestedProps + +=== tests/cases/compiler/r/node_modules/foo/other/index.d.ts === +export interface OtherIndexProps {} +>OtherIndexProps : OtherIndexProps + +=== tests/cases/compiler/r/node_modules/foo/other.d.ts === +export interface OtherProps {} +>OtherProps : OtherProps + +=== tests/cases/compiler/r/node_modules/foo/index.d.ts === +import { OtherProps } from "./other"; +>OtherProps : any + +import { OtherIndexProps } from "./other/index"; +>OtherIndexProps : any + +import { NestedProps } from "nested"; +>NestedProps : any + +export interface SomeProps {} +>SomeProps : SomeProps + +export function foo(): [SomeProps, OtherProps, OtherIndexProps, NestedProps]; +>foo : () => [SomeProps, OtherProps, OtherIndexProps, NestedProps] +>SomeProps : SomeProps +>OtherProps : OtherProps +>OtherIndexProps : OtherIndexProps +>NestedProps : NestedProps + +=== tests/cases/compiler/node_modules/root/index.d.ts === +export interface RootProps {} +>RootProps : RootProps + +export function bar(): RootProps; +>bar : () => RootProps +>RootProps : RootProps + +=== tests/cases/compiler/r/entry.ts === +import { foo } from "foo"; +>foo : () => [import("tests/cases/compiler/r/node_modules/foo/index").SomeProps, import("tests/cases/compiler/r/node_modules/foo/other").OtherProps, import("tests/cases/compiler/r/node_modules/foo/other/index").OtherIndexProps, import("tests/cases/compiler/r/node_modules/foo/node_modules/nested/index").NestedProps] + +import { bar } from "root"; +>bar : () => import("tests/cases/compiler/node_modules/root/index").RootProps + +export const x = foo(); +>x : [import("tests/cases/compiler/r/node_modules/foo/index").SomeProps, import("tests/cases/compiler/r/node_modules/foo/other").OtherProps, import("tests/cases/compiler/r/node_modules/foo/other/index").OtherIndexProps, import("tests/cases/compiler/r/node_modules/foo/node_modules/nested/index").NestedProps] +>foo() : [import("tests/cases/compiler/r/node_modules/foo/index").SomeProps, import("tests/cases/compiler/r/node_modules/foo/other").OtherProps, import("tests/cases/compiler/r/node_modules/foo/other/index").OtherIndexProps, import("tests/cases/compiler/r/node_modules/foo/node_modules/nested/index").NestedProps] +>foo : () => [import("tests/cases/compiler/r/node_modules/foo/index").SomeProps, import("tests/cases/compiler/r/node_modules/foo/other").OtherProps, import("tests/cases/compiler/r/node_modules/foo/other/index").OtherIndexProps, import("tests/cases/compiler/r/node_modules/foo/node_modules/nested/index").NestedProps] + +export const y = bar(); +>y : import("tests/cases/compiler/node_modules/root/index").RootProps +>bar() : import("tests/cases/compiler/node_modules/root/index").RootProps +>bar : () => import("tests/cases/compiler/node_modules/root/index").RootProps + diff --git a/tests/baselines/reference/importShouldNotBeElidedInDeclarationEmit.js b/tests/baselines/reference/importShouldNotBeElidedInDeclarationEmit.js index bb453e398b28b..65da71910619c 100644 --- a/tests/baselines/reference/importShouldNotBeElidedInDeclarationEmit.js +++ b/tests/baselines/reference/importShouldNotBeElidedInDeclarationEmit.js @@ -21,4 +21,4 @@ exports.thing = umd_1.makeThing(); //// [index.d.ts] -export declare const thing: import("./node_modules/umd").Thing; +export declare const thing: import("umd").Thing; diff --git a/tests/baselines/reference/symbolLinkDeclarationEmitModuleNames.js b/tests/baselines/reference/symbolLinkDeclarationEmitModuleNames.js new file mode 100644 index 0000000000000..59eb99f24952a --- /dev/null +++ b/tests/baselines/reference/symbolLinkDeclarationEmitModuleNames.js @@ -0,0 +1,116 @@ +//// [tests/cases/compiler/symbolLinkDeclarationEmitModuleNames.ts] //// + +//// [application.ts] +import { Constructor } from "@loopback/context"; +export type ControllerClass = Constructor; +//// [usage.ts] +import { ControllerClass } from './application'; +import { BindingKey } from '@loopback/context'; + +export const CONTROLLER_CLASS = BindingKey.create(null as any); // line in question +//// [value-promise.ts] +export type Constructor = (...args: any[]) => T; +//// [bindingkey.ts] +import { Constructor } from "@loopback/context" +export class BindingKey { + readonly __type: T; + static create>(ctor: T) { + return new BindingKey(); + } +} + +//// [index.ts] +export * from "./src/value-promise"; +export * from "./src/bindingkey"; + + +//// [value-promise.js] +"use strict"; +exports.__esModule = true; +//// [bindingkey.js] +"use strict"; +exports.__esModule = true; +var BindingKey = /** @class */ (function () { + function BindingKey() { + } + BindingKey.create = function (ctor) { + return new BindingKey(); + }; + return BindingKey; +}()); +exports.BindingKey = BindingKey; +//// [index.js] +"use strict"; +function __export(m) { + for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p]; +} +exports.__esModule = true; +__export(require("./src/bindingkey")); +//// [application.js] +"use strict"; +exports.__esModule = true; +//// [usage.js] +"use strict"; +exports.__esModule = true; +var context_1 = require("@loopback/context"); +exports.CONTROLLER_CLASS = context_1.BindingKey.create(null); // line in question + + +//// [value-promise.d.ts] +export declare type Constructor = (...args: any[]) => T; +//// [bindingkey.d.ts] +import { Constructor } from "@loopback/context"; +export declare class BindingKey { + readonly __type: T; + static create>(ctor: T): BindingKey; +} +//// [index.d.ts] +export * from "./src/value-promise"; +export * from "./src/bindingkey"; +//// [application.d.ts] +import { Constructor } from "@loopback/context"; +export declare type ControllerClass = Constructor; +//// [usage.d.ts] +import { BindingKey } from '@loopback/context'; +export declare const CONTROLLER_CLASS: BindingKey>; + + +//// [DtsFileErrors] + + +tests/cases/compiler/monorepo/context/src/bindingkey.d.ts(1,29): error TS2307: Cannot find module '@loopback/context'. +tests/cases/compiler/monorepo/core/src/application.d.ts(1,29): error TS2307: Cannot find module '@loopback/context'. +tests/cases/compiler/monorepo/core/src/usage.d.ts(1,28): error TS2307: Cannot find module '@loopback/context'. +tests/cases/compiler/monorepo/core/src/usage.d.ts(2,51): error TS2307: Cannot find module '@loopback/context/src/value-promise'. + + +==== tests/cases/compiler/monorepo/core/src/application.d.ts (1 errors) ==== + import { Constructor } from "@loopback/context"; + ~~~~~~~~~~~~~~~~~~~ +!!! error TS2307: Cannot find module '@loopback/context'. + export declare type ControllerClass = Constructor; + +==== tests/cases/compiler/monorepo/core/src/usage.d.ts (2 errors) ==== + import { BindingKey } from '@loopback/context'; + ~~~~~~~~~~~~~~~~~~~ +!!! error TS2307: Cannot find module '@loopback/context'. + export declare const CONTROLLER_CLASS: BindingKey>; + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2307: Cannot find module '@loopback/context/src/value-promise'. + +==== /.src/tests/cases/compiler/monorepo/context/src/value-promise.d.ts (0 errors) ==== + export declare type Constructor = (...args: any[]) => T; + +==== /.src/tests/cases/compiler/monorepo/context/src/bindingkey.d.ts (1 errors) ==== + import { Constructor } from "@loopback/context"; + ~~~~~~~~~~~~~~~~~~~ +!!! error TS2307: Cannot find module '@loopback/context'. + export declare class BindingKey { + readonly __type: T; + static create>(ctor: T): BindingKey; + } + +==== /.src/tests/cases/compiler/monorepo/context/index.d.ts (0 errors) ==== + export * from "./src/value-promise"; + export * from "./src/bindingkey"; + \ No newline at end of file diff --git a/tests/baselines/reference/symbolLinkDeclarationEmitModuleNames.symbols b/tests/baselines/reference/symbolLinkDeclarationEmitModuleNames.symbols new file mode 100644 index 0000000000000..15b88cbe0bf19 --- /dev/null +++ b/tests/baselines/reference/symbolLinkDeclarationEmitModuleNames.symbols @@ -0,0 +1,59 @@ +=== tests/cases/compiler/monorepo/core/src/application.ts === +import { Constructor } from "@loopback/context"; +>Constructor : Symbol(Constructor, Decl(application.ts, 0, 8)) + +export type ControllerClass = Constructor; +>ControllerClass : Symbol(ControllerClass, Decl(application.ts, 0, 48)) +>Constructor : Symbol(Constructor, Decl(application.ts, 0, 8)) + +=== tests/cases/compiler/monorepo/core/src/usage.ts === +import { ControllerClass } from './application'; +>ControllerClass : Symbol(ControllerClass, Decl(usage.ts, 0, 8)) + +import { BindingKey } from '@loopback/context'; +>BindingKey : Symbol(BindingKey, Decl(usage.ts, 1, 8)) + +export const CONTROLLER_CLASS = BindingKey.create(null as any); // line in question +>CONTROLLER_CLASS : Symbol(CONTROLLER_CLASS, Decl(usage.ts, 3, 12)) +>BindingKey.create : Symbol(BindingKey.create, Decl(bindingkey.ts, 2, 21)) +>BindingKey : Symbol(BindingKey, Decl(usage.ts, 1, 8)) +>create : Symbol(BindingKey.create, Decl(bindingkey.ts, 2, 21)) +>ControllerClass : Symbol(ControllerClass, Decl(usage.ts, 0, 8)) + +=== tests/cases/compiler/monorepo/context/src/value-promise.ts === +export type Constructor = (...args: any[]) => T; +>Constructor : Symbol(Constructor, Decl(value-promise.ts, 0, 0)) +>T : Symbol(T, Decl(value-promise.ts, 0, 24)) +>args : Symbol(args, Decl(value-promise.ts, 0, 30)) +>T : Symbol(T, Decl(value-promise.ts, 0, 24)) + +=== tests/cases/compiler/monorepo/context/src/bindingkey.ts === +import { Constructor } from "@loopback/context" +>Constructor : Symbol(Constructor, Decl(bindingkey.ts, 0, 8)) + +export class BindingKey { +>BindingKey : Symbol(BindingKey, Decl(bindingkey.ts, 0, 47)) +>T : Symbol(T, Decl(bindingkey.ts, 1, 24)) + + readonly __type: T; +>__type : Symbol(BindingKey.__type, Decl(bindingkey.ts, 1, 28)) +>T : Symbol(T, Decl(bindingkey.ts, 1, 24)) + + static create>(ctor: T) { +>create : Symbol(BindingKey.create, Decl(bindingkey.ts, 2, 21)) +>T : Symbol(T, Decl(bindingkey.ts, 3, 16)) +>Constructor : Symbol(Constructor, Decl(bindingkey.ts, 0, 8)) +>ctor : Symbol(ctor, Decl(bindingkey.ts, 3, 44)) +>T : Symbol(T, Decl(bindingkey.ts, 3, 16)) + + return new BindingKey(); +>BindingKey : Symbol(BindingKey, Decl(bindingkey.ts, 0, 47)) +>T : Symbol(T, Decl(bindingkey.ts, 3, 16)) + } +} + +=== tests/cases/compiler/monorepo/context/index.ts === +export * from "./src/value-promise"; +No type information for this code.export * from "./src/bindingkey"; +No type information for this code. +No type information for this code. \ No newline at end of file diff --git a/tests/baselines/reference/symbolLinkDeclarationEmitModuleNames.types b/tests/baselines/reference/symbolLinkDeclarationEmitModuleNames.types new file mode 100644 index 0000000000000..a83fe0d650ce3 --- /dev/null +++ b/tests/baselines/reference/symbolLinkDeclarationEmitModuleNames.types @@ -0,0 +1,63 @@ +=== tests/cases/compiler/monorepo/core/src/application.ts === +import { Constructor } from "@loopback/context"; +>Constructor : any + +export type ControllerClass = Constructor; +>ControllerClass : Constructor +>Constructor : Constructor + +=== tests/cases/compiler/monorepo/core/src/usage.ts === +import { ControllerClass } from './application'; +>ControllerClass : any + +import { BindingKey } from '@loopback/context'; +>BindingKey : typeof BindingKey + +export const CONTROLLER_CLASS = BindingKey.create(null as any); // line in question +>CONTROLLER_CLASS : BindingKey> +>BindingKey.create(null as any) : BindingKey> +>BindingKey.create : >(ctor: T) => BindingKey +>BindingKey : typeof BindingKey +>create : >(ctor: T) => BindingKey +>ControllerClass : import("tests/cases/compiler/monorepo/context/src/value-promise").Constructor +>null as any : any +>null : null + +=== tests/cases/compiler/monorepo/context/src/value-promise.ts === +export type Constructor = (...args: any[]) => T; +>Constructor : Constructor +>T : T +>args : any[] +>T : T + +=== tests/cases/compiler/monorepo/context/src/bindingkey.ts === +import { Constructor } from "@loopback/context" +>Constructor : any + +export class BindingKey { +>BindingKey : BindingKey +>T : T + + readonly __type: T; +>__type : T +>T : T + + static create>(ctor: T) { +>create : >(ctor: T) => BindingKey +>T : T +>Constructor : Constructor +>ctor : T +>T : T + + return new BindingKey(); +>new BindingKey() : BindingKey +>BindingKey : typeof BindingKey +>T : T + } +} + +=== tests/cases/compiler/monorepo/context/index.ts === +export * from "./src/value-promise"; +No type information for this code.export * from "./src/bindingkey"; +No type information for this code. +No type information for this code. \ No newline at end of file diff --git a/tests/cases/compiler/declarationEmitCommonJsModuleReferencedType.ts b/tests/cases/compiler/declarationEmitCommonJsModuleReferencedType.ts new file mode 100644 index 0000000000000..5207d655037fd --- /dev/null +++ b/tests/cases/compiler/declarationEmitCommonJsModuleReferencedType.ts @@ -0,0 +1,23 @@ +// @declaration: true +// @filename: r/node_modules/foo/node_modules/nested/index.d.ts +export interface NestedProps {} +// @filename: r/node_modules/foo/other/index.d.ts +export interface OtherIndexProps {} +// @filename: r/node_modules/foo/other.d.ts +export interface OtherProps {} +// @filename: r/node_modules/foo/index.d.ts +import { OtherProps } from "./other"; +import { OtherIndexProps } from "./other/index"; +import { NestedProps } from "nested"; +export interface SomeProps {} + +export function foo(): [SomeProps, OtherProps, OtherIndexProps, NestedProps]; +// @filename: node_modules/root/index.d.ts +export interface RootProps {} + +export function bar(): RootProps; +// @filename: r/entry.ts +import { foo } from "foo"; +import { bar } from "root"; +export const x = foo(); +export const y = bar(); diff --git a/tests/cases/compiler/symbolLinkDeclarationEmitModuleNames.ts b/tests/cases/compiler/symbolLinkDeclarationEmitModuleNames.ts new file mode 100644 index 0000000000000..95defd4ecc768 --- /dev/null +++ b/tests/cases/compiler/symbolLinkDeclarationEmitModuleNames.ts @@ -0,0 +1,25 @@ +// @declaration: true +// @filename: monorepo/core/src/application.ts +import { Constructor } from "@loopback/context"; +export type ControllerClass = Constructor; +// @filename: monorepo/core/src/usage.ts +import { ControllerClass } from './application'; +import { BindingKey } from '@loopback/context'; + +export const CONTROLLER_CLASS = BindingKey.create(null as any); // line in question +// @filename: monorepo/context/src/value-promise.ts +export type Constructor = (...args: any[]) => T; +// @filename: monorepo/context/src/bindingkey.ts +import { Constructor } from "@loopback/context" +export class BindingKey { + readonly __type: T; + static create>(ctor: T) { + return new BindingKey(); + } +} + +// @filename: monorepo/context/index.ts +export * from "./src/value-promise"; +export * from "./src/bindingkey"; + +// @link: tests/cases/compiler/monorepo/context -> tests/cases/compiler/monorepo/core/node_modules/@loopback/context \ No newline at end of file