From ec6b6e027d0270c2520e5ca86faaabf5ec5ba432 Mon Sep 17 00:00:00 2001 From: Andrew Branch Date: Thu, 21 Dec 2023 10:29:24 -0800 Subject: [PATCH 1/5] Let AutoImportProvider find non-declaration files in wildcard exports --- src/compiler/moduleNameResolver.ts | 4 +- .../autoImportProvider_wildcardExports1.js | 16 +- .../autoImportProvider_wildcardExports3.js | 628 ++++++++++++++++++ .../autoImportProvider_wildcardExports1.ts | 1 + .../autoImportProvider_wildcardExports3.ts | 55 ++ 5 files changed, 698 insertions(+), 6 deletions(-) create mode 100644 tests/baselines/reference/tsserver/fourslashServer/autoImportProvider_wildcardExports3.js create mode 100644 tests/cases/fourslash/server/autoImportProvider_wildcardExports3.ts diff --git a/src/compiler/moduleNameResolver.ts b/src/compiler/moduleNameResolver.ts index 4f128f1e6aa11..0d0c31e8b2008 100644 --- a/src/compiler/moduleNameResolver.ts +++ b/src/compiler/moduleNameResolver.ts @@ -2292,8 +2292,8 @@ function loadEntrypointsFromExportMap( /*excludes*/ undefined, [ isDeclarationFileName(target) - ? replaceFirstStar(target, "**/*") - : changeAnyExtension(replaceFirstStar(target, "**/*"), getDeclarationEmitExtensionForPath(target)), + ? changeAnyExtension(replaceFirstStar(target, "**/*"), ".*", supportedDeclarationExtensions, /*ignoreCase*/ true) + : changeAnyExtension(replaceFirstStar(target, "**/*"), ".*"), ], ).forEach(entry => { entrypoints = appendIfUnique(entrypoints, { diff --git a/tests/baselines/reference/tsserver/fourslashServer/autoImportProvider_wildcardExports1.js b/tests/baselines/reference/tsserver/fourslashServer/autoImportProvider_wildcardExports1.js index c20647bf14fc7..9fedb1abdc436 100644 --- a/tests/baselines/reference/tsserver/fourslashServer/autoImportProvider_wildcardExports1.js +++ b/tests/baselines/reference/tsserver/fourslashServer/autoImportProvider_wildcardExports1.js @@ -171,9 +171,10 @@ Info seq [hh:mm:ss:mss] Files (4) Info seq [hh:mm:ss:mss] ----------------------------------------------- Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /package.json 250 undefined WatchType: package.json file -Info seq [hh:mm:ss:mss] AutoImportProviderProject: found 5 root files in 1 dependencies in * ms +Info seq [hh:mm:ss:mss] AutoImportProviderProject: found 6 root files in 1 dependencies in * ms Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /node_modules/pkg/a/a1.d.ts 500 undefined WatchType: Closed Script info Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /node_modules/pkg/b/b1.d.ts 500 undefined WatchType: Closed Script info +Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /node_modules/pkg/b/b2.d.mts 500 undefined WatchType: Closed Script info Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /node_modules/pkg/c/c1.d.ts 500 undefined WatchType: Closed Script info Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /node_modules/pkg/c/subfolder/c2.d.mts 500 undefined WatchType: Closed Script info Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /node_modules/pkg/d/d1.d.mts 500 undefined WatchType: Closed Script info @@ -183,9 +184,10 @@ Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /node_modules/pkg/b/pa Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /node_modules/pkg/c/package.json 2000 undefined Project: /dev/null/autoImportProviderProject1* WatchType: File location affecting resolution Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /dev/null/autoImportProviderProject1* Version: 1 structureChanged: true structureIsReused:: Not Elapsed:: *ms Info seq [hh:mm:ss:mss] Project '/dev/null/autoImportProviderProject1*' (AutoImportProvider) -Info seq [hh:mm:ss:mss] Files (5) +Info seq [hh:mm:ss:mss] Files (6) /node_modules/pkg/a/a1.d.ts Text-1 "export const a1: number;" /node_modules/pkg/b/b1.d.ts Text-1 "export const b1: number;" + /node_modules/pkg/b/b2.d.mts Text-1 "export const NOT_REACHABLE: number;" /node_modules/pkg/c/c1.d.ts Text-1 "export const c1: number;" /node_modules/pkg/c/subfolder/c2.d.mts Text-1 "export const c2: number;" /node_modules/pkg/d/d1.d.mts Text-1 "export const d1: number;" @@ -197,6 +199,8 @@ Info seq [hh:mm:ss:mss] Files (5) node_modules/pkg/b/b1.d.ts Root file specified for compilation File is CommonJS module because 'node_modules/pkg/package.json' does not have field "type" + node_modules/pkg/b/b2.d.mts + Root file specified for compilation node_modules/pkg/c/c1.d.ts Root file specified for compilation File is CommonJS module because 'node_modules/pkg/package.json' does not have field "type" @@ -231,7 +235,7 @@ Info seq [hh:mm:ss:mss] Files (4) Info seq [hh:mm:ss:mss] ----------------------------------------------- Info seq [hh:mm:ss:mss] Project '/dev/null/autoImportProviderProject1*' (AutoImportProvider) -Info seq [hh:mm:ss:mss] Files (5) +Info seq [hh:mm:ss:mss] Files (6) Info seq [hh:mm:ss:mss] ----------------------------------------------- Info seq [hh:mm:ss:mss] Project '/dev/null/inferredProject1*' (Inferred) @@ -257,6 +261,8 @@ watchedFiles:: {"pollingInterval":2000} /node_modules/pkg/b/b1.d.ts: *new* {"pollingInterval":500} +/node_modules/pkg/b/b2.d.mts: *new* + {"pollingInterval":500} /node_modules/pkg/b/package.json: *new* {"pollingInterval":2000} /node_modules/pkg/c/c1.d.ts: *new* @@ -315,7 +321,7 @@ Info seq [hh:mm:ss:mss] forEachExternalModuleToImportFrom autoImportProvider: * Info seq [hh:mm:ss:mss] getExportInfoMap: done in * ms Info seq [hh:mm:ss:mss] DirectoryWatcher:: Added:: WatchInfo: /node_modules 1 undefined WatchType: node_modules for closed script infos and package.jsons affecting module specifier cache Info seq [hh:mm:ss:mss] Elapsed:: *ms DirectoryWatcher:: Added:: WatchInfo: /node_modules 1 undefined WatchType: node_modules for closed script infos and package.jsons affecting module specifier cache -Info seq [hh:mm:ss:mss] collectAutoImports: resolved 5 module specifiers, plus 0 ambient and 0 from cache +Info seq [hh:mm:ss:mss] collectAutoImports: resolved 5 module specifiers, plus 0 ambient and 1 from cache Info seq [hh:mm:ss:mss] collectAutoImports: response is complete Info seq [hh:mm:ss:mss] collectAutoImports: * Info seq [hh:mm:ss:mss] getCompletionData: Semantic work: * @@ -1108,6 +1114,8 @@ watchedFiles:: {"pollingInterval":2000} /node_modules/pkg/b/b1.d.ts: {"pollingInterval":500} +/node_modules/pkg/b/b2.d.mts: + {"pollingInterval":500} /node_modules/pkg/b/package.json: {"pollingInterval":2000} /node_modules/pkg/c/c1.d.ts: diff --git a/tests/baselines/reference/tsserver/fourslashServer/autoImportProvider_wildcardExports3.js b/tests/baselines/reference/tsserver/fourslashServer/autoImportProvider_wildcardExports3.js new file mode 100644 index 0000000000000..5d8219f48ec76 --- /dev/null +++ b/tests/baselines/reference/tsserver/fourslashServer/autoImportProvider_wildcardExports3.js @@ -0,0 +1,628 @@ +currentDirectory:: / useCaseSensitiveFileNames: false +Info seq [hh:mm:ss:mss] Provided types map file "/typesMap.json" doesn't exist +//// [/lib.d.ts] +lib.d.ts-Text + +//// [/lib.decorators.d.ts] +lib.decorators.d.ts-Text + +//// [/lib.decorators.legacy.d.ts] +lib.decorators.legacy.d.ts-Text + +//// [/project/apps/web/app/index.tsx] +(); + +//// [/project/apps/web/node_modules/@repo/ui] symlink(/project/packages/ui) +//// [/project/apps/web/package.json] +{ + "name": "web", + "version": "1.0.0", + "dependencies": { + "@repo/ui": "workspace:*" + } +} + +//// [/project/apps/web/tsconfig.json] +{ + "compilerOptions": { + "module": "esnext", + "moduleResolution": "bundler", + "noEmit": true, + "jsx": "preserve" + }, + "include": ["app"] +} + +//// [/project/packages/ui/package.json] +{ + "name": "@repo/ui", + "version": "1.0.0", + "exports": { + "./*": "./src/*.tsx" + } +} + +//// [/project/packages/ui/src/Card.tsx] +export const Card = () => null; + + +Info seq [hh:mm:ss:mss] request: + { + "seq": 0, + "type": "request", + "arguments": { + "file": "/project/packages/ui/package.json" + }, + "command": "open" + } +Info seq [hh:mm:ss:mss] Search path: /project/packages/ui +Info seq [hh:mm:ss:mss] For info: /project/packages/ui/package.json :: No config files found. +Info seq [hh:mm:ss:mss] Starting updateGraphWorker: Project: /dev/null/inferredProject1* +Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /lib.d.ts 500 undefined WatchType: Closed Script info +Info seq [hh:mm:ss:mss] DirectoryWatcher:: Added:: WatchInfo: /project/packages/ui/node_modules 1 undefined Project: /dev/null/inferredProject1* WatchType: Failed Lookup Locations +Info seq [hh:mm:ss:mss] Elapsed:: *ms DirectoryWatcher:: Added:: WatchInfo: /project/packages/ui/node_modules 1 undefined Project: /dev/null/inferredProject1* WatchType: Failed Lookup Locations +Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /lib.decorators.d.ts 500 undefined WatchType: Closed Script info +Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /lib.decorators.legacy.d.ts 500 undefined WatchType: Closed Script info +Info seq [hh:mm:ss:mss] DirectoryWatcher:: Added:: WatchInfo: /project/packages/ui/node_modules/@types 1 undefined Project: /dev/null/inferredProject1* WatchType: Type roots +Info seq [hh:mm:ss:mss] Elapsed:: *ms DirectoryWatcher:: Added:: WatchInfo: /project/packages/ui/node_modules/@types 1 undefined Project: /dev/null/inferredProject1* WatchType: Type roots +Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /dev/null/inferredProject1* Version: 1 structureChanged: true structureIsReused:: Not Elapsed:: *ms +Info seq [hh:mm:ss:mss] Project '/dev/null/inferredProject1*' (Inferred) +Info seq [hh:mm:ss:mss] Files (4) + /lib.d.ts Text-1 lib.d.ts-Text + /lib.decorators.d.ts Text-1 lib.decorators.d.ts-Text + /lib.decorators.legacy.d.ts Text-1 lib.decorators.legacy.d.ts-Text + /project/packages/ui/package.json SVC-1-0 "{\n \"name\": \"@repo/ui\",\n \"version\": \"1.0.0\",\n \"exports\": {\n \"./*\": \"./src/*.tsx\"\n }\n}" + + + ../../../lib.d.ts + Default library for target 'es5' + ../../../lib.decorators.d.ts + Library referenced via 'decorators' from file '../../../lib.d.ts' + ../../../lib.decorators.legacy.d.ts + Library referenced via 'decorators.legacy' from file '../../../lib.d.ts' + package.json + Root file specified for compilation + +Info seq [hh:mm:ss:mss] ----------------------------------------------- +Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /project/packages/ui/package.json 250 undefined WatchType: package.json file +Info seq [hh:mm:ss:mss] Project '/dev/null/inferredProject1*' (Inferred) +Info seq [hh:mm:ss:mss] Files (4) + +Info seq [hh:mm:ss:mss] ----------------------------------------------- +Info seq [hh:mm:ss:mss] Open files: +Info seq [hh:mm:ss:mss] FileName: /project/packages/ui/package.json ProjectRootPath: undefined +Info seq [hh:mm:ss:mss] Projects: /dev/null/inferredProject1* +After Request +watchedFiles:: +/lib.d.ts: *new* + {"pollingInterval":500} +/lib.decorators.d.ts: *new* + {"pollingInterval":500} +/lib.decorators.legacy.d.ts: *new* + {"pollingInterval":500} +/project/packages/ui/package.json: *new* + {"pollingInterval":250} + +watchedDirectoriesRecursive:: +/project/packages/ui/node_modules: *new* + {} +/project/packages/ui/node_modules/@types: *new* + {} + +Info seq [hh:mm:ss:mss] request: + { + "seq": 1, + "type": "request", + "arguments": { + "file": "/project/apps/web/app/index.tsx" + }, + "command": "open" + } +Info seq [hh:mm:ss:mss] Search path: /project/apps/web/app +Info seq [hh:mm:ss:mss] For info: /project/apps/web/app/index.tsx :: Config file name: /project/apps/web/tsconfig.json +Info seq [hh:mm:ss:mss] Creating configuration project /project/apps/web/tsconfig.json +Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /project/apps/web/tsconfig.json 2000 undefined Project: /project/apps/web/tsconfig.json WatchType: Config file +Info seq [hh:mm:ss:mss] event: + { + "seq": 0, + "type": "event", + "event": "projectLoadingStart", + "body": { + "projectName": "/project/apps/web/tsconfig.json", + "reason": "Creating possible configured project for /project/apps/web/app/index.tsx to open" + } + } +Info seq [hh:mm:ss:mss] Config: /project/apps/web/tsconfig.json : { + "rootNames": [ + "/project/apps/web/app/index.tsx" + ], + "options": { + "module": 99, + "moduleResolution": 100, + "noEmit": true, + "jsx": 1, + "configFilePath": "/project/apps/web/tsconfig.json" + } +} +Info seq [hh:mm:ss:mss] DirectoryWatcher:: Added:: WatchInfo: /project/apps/web/app 1 undefined Config: /project/apps/web/tsconfig.json WatchType: Wild card directory +Info seq [hh:mm:ss:mss] Elapsed:: *ms DirectoryWatcher:: Added:: WatchInfo: /project/apps/web/app 1 undefined Config: /project/apps/web/tsconfig.json WatchType: Wild card directory +Info seq [hh:mm:ss:mss] Starting updateGraphWorker: Project: /project/apps/web/tsconfig.json +Info seq [hh:mm:ss:mss] DirectoryWatcher:: Added:: WatchInfo: /project/apps/web/node_modules 1 undefined Project: /project/apps/web/tsconfig.json WatchType: Failed Lookup Locations +Info seq [hh:mm:ss:mss] Elapsed:: *ms DirectoryWatcher:: Added:: WatchInfo: /project/apps/web/node_modules 1 undefined Project: /project/apps/web/tsconfig.json WatchType: Failed Lookup Locations +Info seq [hh:mm:ss:mss] DirectoryWatcher:: Added:: WatchInfo: /project/apps/web/node_modules/@types 1 undefined Project: /project/apps/web/tsconfig.json WatchType: Type roots +Info seq [hh:mm:ss:mss] Elapsed:: *ms DirectoryWatcher:: Added:: WatchInfo: /project/apps/web/node_modules/@types 1 undefined Project: /project/apps/web/tsconfig.json WatchType: Type roots +Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /project/apps/web/tsconfig.json Version: 1 structureChanged: true structureIsReused:: Not Elapsed:: *ms +Info seq [hh:mm:ss:mss] Project '/project/apps/web/tsconfig.json' (Configured) +Info seq [hh:mm:ss:mss] Files (4) + /lib.d.ts Text-1 lib.d.ts-Text + /lib.decorators.d.ts Text-1 lib.decorators.d.ts-Text + /lib.decorators.legacy.d.ts Text-1 lib.decorators.legacy.d.ts-Text + /project/apps/web/app/index.tsx SVC-1-0 "();" + + + ../../../lib.d.ts + Default library for target 'es5' + ../../../lib.decorators.d.ts + Library referenced via 'decorators' from file '../../../lib.d.ts' + ../../../lib.decorators.legacy.d.ts + Library referenced via 'decorators.legacy' from file '../../../lib.d.ts' + app/index.tsx + Matched by include pattern 'app' in 'tsconfig.json' + +Info seq [hh:mm:ss:mss] ----------------------------------------------- +Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /project/apps/web/package.json 250 undefined WatchType: package.json file +Info seq [hh:mm:ss:mss] AutoImportProviderProject: found 1 root files in 1 dependencies in * ms +Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /project/packages/ui/src/Card.tsx 500 undefined WatchType: Closed Script info +Info seq [hh:mm:ss:mss] Starting updateGraphWorker: Project: /dev/null/autoImportProviderProject1* +Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /dev/null/autoImportProviderProject1* Version: 1 structureChanged: true structureIsReused:: Not Elapsed:: *ms +Info seq [hh:mm:ss:mss] Project '/dev/null/autoImportProviderProject1*' (AutoImportProvider) +Info seq [hh:mm:ss:mss] Files (1) + /project/packages/ui/src/Card.tsx Text-1 "export const Card = () => null;" + + + ../../packages/ui/src/Card.tsx + Root file specified for compilation + +Info seq [hh:mm:ss:mss] ----------------------------------------------- +Info seq [hh:mm:ss:mss] event: + { + "seq": 0, + "type": "event", + "event": "projectLoadingFinish", + "body": { + "projectName": "/project/apps/web/tsconfig.json" + } + } +Info seq [hh:mm:ss:mss] event: + { + "seq": 0, + "type": "event", + "event": "configFileDiag", + "body": { + "triggerFile": "/project/apps/web/app/index.tsx", + "configFile": "/project/apps/web/tsconfig.json", + "diagnostics": [] + } + } +Info seq [hh:mm:ss:mss] Project '/project/apps/web/tsconfig.json' (Configured) +Info seq [hh:mm:ss:mss] Files (4) + +Info seq [hh:mm:ss:mss] ----------------------------------------------- +Info seq [hh:mm:ss:mss] Project '/dev/null/autoImportProviderProject1*' (AutoImportProvider) +Info seq [hh:mm:ss:mss] Files (1) + +Info seq [hh:mm:ss:mss] ----------------------------------------------- +Info seq [hh:mm:ss:mss] Project '/dev/null/inferredProject1*' (Inferred) +Info seq [hh:mm:ss:mss] Files (4) + +Info seq [hh:mm:ss:mss] ----------------------------------------------- +Info seq [hh:mm:ss:mss] Open files: +Info seq [hh:mm:ss:mss] FileName: /project/packages/ui/package.json ProjectRootPath: undefined +Info seq [hh:mm:ss:mss] Projects: /dev/null/inferredProject1* +Info seq [hh:mm:ss:mss] FileName: /project/apps/web/app/index.tsx ProjectRootPath: undefined +Info seq [hh:mm:ss:mss] Projects: /project/apps/web/tsconfig.json +After Request +watchedFiles:: +/lib.d.ts: + {"pollingInterval":500} +/lib.decorators.d.ts: + {"pollingInterval":500} +/lib.decorators.legacy.d.ts: + {"pollingInterval":500} +/project/apps/web/package.json: *new* + {"pollingInterval":250} +/project/apps/web/tsconfig.json: *new* + {"pollingInterval":2000} +/project/packages/ui/package.json: + {"pollingInterval":250} +/project/packages/ui/src/Card.tsx: *new* + {"pollingInterval":500} + +watchedDirectoriesRecursive:: +/project/apps/web/app: *new* + {} +/project/apps/web/node_modules: *new* + {} +/project/apps/web/node_modules/@types: *new* + {} +/project/packages/ui/node_modules: + {} +/project/packages/ui/node_modules/@types: + {} + +Info seq [hh:mm:ss:mss] request: + { + "seq": 2, + "type": "request", + "arguments": { + "preferences": { + "includeCompletionsForModuleExports": true, + "allowIncompleteCompletions": true + } + }, + "command": "configure" + } +Info seq [hh:mm:ss:mss] response: + { + "seq": 0, + "type": "response", + "command": "configure", + "request_seq": 2, + "success": true + } +Info seq [hh:mm:ss:mss] request: + { + "seq": 3, + "type": "request", + "arguments": { + "file": "/project/apps/web/app/index.tsx", + "line": 1, + "offset": 7 + }, + "command": "completionInfo" + } +Info seq [hh:mm:ss:mss] getCompletionData: Get current token: * +Info seq [hh:mm:ss:mss] getCompletionData: Is inside comment: * +Info seq [hh:mm:ss:mss] getCompletionData: Get previous token: * +Info seq [hh:mm:ss:mss] getCompletionsAtPosition: isCompletionListBlocker: * +Info seq [hh:mm:ss:mss] getExportInfoMap: cache miss or empty; calculating new results +Info seq [hh:mm:ss:mss] forEachExternalModuleToImportFrom autoImportProvider: * +Info seq [hh:mm:ss:mss] getExportInfoMap: done in * ms +Info seq [hh:mm:ss:mss] DirectoryWatcher:: Added:: WatchInfo: /project/apps/web/node_modules 1 undefined WatchType: node_modules for closed script infos and package.jsons affecting module specifier cache +Info seq [hh:mm:ss:mss] Elapsed:: *ms DirectoryWatcher:: Added:: WatchInfo: /project/apps/web/node_modules 1 undefined WatchType: node_modules for closed script infos and package.jsons affecting module specifier cache +Info seq [hh:mm:ss:mss] collectAutoImports: resolved 1 module specifiers, plus 0 ambient and 0 from cache +Info seq [hh:mm:ss:mss] collectAutoImports: response is complete +Info seq [hh:mm:ss:mss] collectAutoImports: * +Info seq [hh:mm:ss:mss] getCompletionData: Semantic work: * +Info seq [hh:mm:ss:mss] getCompletionsAtPosition: getCompletionEntriesFromSymbols: * +Info seq [hh:mm:ss:mss] response: + { + "seq": 0, + "type": "response", + "command": "completionInfo", + "request_seq": 3, + "success": true, + "body": { + "flags": 9, + "isGlobalCompletion": false, + "isMemberCompletion": false, + "isNewIdentifierLocation": false, + "entries": [ + { + "name": "Array", + "kind": "var", + "kindModifiers": "declare", + "sortText": "15" + }, + { + "name": "ArrayBuffer", + "kind": "var", + "kindModifiers": "declare", + "sortText": "15" + }, + { + "name": "Boolean", + "kind": "var", + "kindModifiers": "declare", + "sortText": "15" + }, + { + "name": "DataView", + "kind": "var", + "kindModifiers": "declare", + "sortText": "15" + }, + { + "name": "Date", + "kind": "var", + "kindModifiers": "declare", + "sortText": "15" + }, + { + "name": "decodeURI", + "kind": "function", + "kindModifiers": "declare", + "sortText": "15" + }, + { + "name": "decodeURIComponent", + "kind": "function", + "kindModifiers": "declare", + "sortText": "15" + }, + { + "name": "encodeURI", + "kind": "function", + "kindModifiers": "declare", + "sortText": "15" + }, + { + "name": "encodeURIComponent", + "kind": "function", + "kindModifiers": "declare", + "sortText": "15" + }, + { + "name": "Error", + "kind": "var", + "kindModifiers": "declare", + "sortText": "15" + }, + { + "name": "eval", + "kind": "function", + "kindModifiers": "declare", + "sortText": "15" + }, + { + "name": "EvalError", + "kind": "var", + "kindModifiers": "declare", + "sortText": "15" + }, + { + "name": "Float32Array", + "kind": "var", + "kindModifiers": "declare", + "sortText": "15" + }, + { + "name": "Float64Array", + "kind": "var", + "kindModifiers": "declare", + "sortText": "15" + }, + { + "name": "Function", + "kind": "var", + "kindModifiers": "declare", + "sortText": "15" + }, + { + "name": "globalThis", + "kind": "module", + "kindModifiers": "", + "sortText": "15" + }, + { + "name": "Infinity", + "kind": "var", + "kindModifiers": "declare", + "sortText": "15" + }, + { + "name": "Int16Array", + "kind": "var", + "kindModifiers": "declare", + "sortText": "15" + }, + { + "name": "Int32Array", + "kind": "var", + "kindModifiers": "declare", + "sortText": "15" + }, + { + "name": "Int8Array", + "kind": "var", + "kindModifiers": "declare", + "sortText": "15" + }, + { + "name": "Intl", + "kind": "module", + "kindModifiers": "declare", + "sortText": "15" + }, + { + "name": "isFinite", + "kind": "function", + "kindModifiers": "declare", + "sortText": "15" + }, + { + "name": "isNaN", + "kind": "function", + "kindModifiers": "declare", + "sortText": "15" + }, + { + "name": "JSON", + "kind": "var", + "kindModifiers": "declare", + "sortText": "15" + }, + { + "name": "Math", + "kind": "var", + "kindModifiers": "declare", + "sortText": "15" + }, + { + "name": "NaN", + "kind": "var", + "kindModifiers": "declare", + "sortText": "15" + }, + { + "name": "Number", + "kind": "var", + "kindModifiers": "declare", + "sortText": "15" + }, + { + "name": "Object", + "kind": "var", + "kindModifiers": "declare", + "sortText": "15" + }, + { + "name": "parseFloat", + "kind": "function", + "kindModifiers": "declare", + "sortText": "15" + }, + { + "name": "parseInt", + "kind": "function", + "kindModifiers": "declare", + "sortText": "15" + }, + { + "name": "RangeError", + "kind": "var", + "kindModifiers": "declare", + "sortText": "15" + }, + { + "name": "ReferenceError", + "kind": "var", + "kindModifiers": "declare", + "sortText": "15" + }, + { + "name": "RegExp", + "kind": "var", + "kindModifiers": "declare", + "sortText": "15" + }, + { + "name": "String", + "kind": "var", + "kindModifiers": "declare", + "sortText": "15" + }, + { + "name": "SyntaxError", + "kind": "var", + "kindModifiers": "declare", + "sortText": "15" + }, + { + "name": "TypeError", + "kind": "var", + "kindModifiers": "declare", + "sortText": "15" + }, + { + "name": "Uint16Array", + "kind": "var", + "kindModifiers": "declare", + "sortText": "15" + }, + { + "name": "Uint32Array", + "kind": "var", + "kindModifiers": "declare", + "sortText": "15" + }, + { + "name": "Uint8Array", + "kind": "var", + "kindModifiers": "declare", + "sortText": "15" + }, + { + "name": "Uint8ClampedArray", + "kind": "var", + "kindModifiers": "declare", + "sortText": "15" + }, + { + "name": "undefined", + "kind": "var", + "kindModifiers": "", + "sortText": "15" + }, + { + "name": "URIError", + "kind": "var", + "kindModifiers": "declare", + "sortText": "15" + }, + { + "name": "Card", + "kind": "const", + "kindModifiers": "export", + "sortText": "16", + "hasAction": true, + "source": "@repo/ui/Card", + "sourceDisplay": [ + { + "text": "@repo/ui/Card", + "kind": "text" + } + ], + "isPackageJsonImport": true, + "data": { + "exportName": "Card", + "exportMapKey": "4 * Card ", + "moduleSpecifier": "@repo/ui/Card", + "fileName": "/project/packages/ui/src/Card.tsx", + "isPackageJsonImport": true + } + }, + { + "name": "escape", + "kind": "function", + "kindModifiers": "deprecated,declare", + "sortText": "z15" + }, + { + "name": "unescape", + "kind": "function", + "kindModifiers": "deprecated,declare", + "sortText": "z15" + } + ] + } + } +After Request +watchedFiles:: +/lib.d.ts: + {"pollingInterval":500} +/lib.decorators.d.ts: + {"pollingInterval":500} +/lib.decorators.legacy.d.ts: + {"pollingInterval":500} +/project/apps/web/package.json: + {"pollingInterval":250} +/project/apps/web/tsconfig.json: + {"pollingInterval":2000} +/project/packages/ui/package.json: + {"pollingInterval":250} +/project/packages/ui/src/Card.tsx: + {"pollingInterval":500} + +watchedDirectoriesRecursive:: +/project/apps/web/app: + {} +/project/apps/web/node_modules: + {} + {} *new* +/project/apps/web/node_modules/@types: + {} +/project/packages/ui/node_modules: + {} +/project/packages/ui/node_modules/@types: + {} diff --git a/tests/cases/fourslash/server/autoImportProvider_wildcardExports1.ts b/tests/cases/fourslash/server/autoImportProvider_wildcardExports1.ts index 1c1f30f6ca509..d18e6cead0a1e 100644 --- a/tests/cases/fourslash/server/autoImportProvider_wildcardExports1.ts +++ b/tests/cases/fourslash/server/autoImportProvider_wildcardExports1.ts @@ -89,6 +89,7 @@ verify.completions({ sortText: completion.SortText.AutoImportSuggestions } ], + excludes: ["NOT_REACHABLE"], preferences: { includeCompletionsForModuleExports: true, allowIncompleteCompletions: true diff --git a/tests/cases/fourslash/server/autoImportProvider_wildcardExports3.ts b/tests/cases/fourslash/server/autoImportProvider_wildcardExports3.ts new file mode 100644 index 0000000000000..f5aa9020e0be8 --- /dev/null +++ b/tests/cases/fourslash/server/autoImportProvider_wildcardExports3.ts @@ -0,0 +1,55 @@ +/// + +// @Filename: /project/packages/ui/package.json +//// { +//// "name": "@repo/ui", +//// "version": "1.0.0", +//// "exports": { +//// "./*": "./src/*.tsx" +//// } +//// } + +// @Filename: /project/packages/ui/src/Card.tsx +//// export const Card = () => null; + +// @Filename: /project/apps/web/package.json +//// { +//// "name": "web", +//// "version": "1.0.0", +//// "dependencies": { +//// "@repo/ui": "workspace:*" +//// } +//// } + +// @Filename: /project/apps/web/tsconfig.json +//// { +//// "compilerOptions": { +//// "module": "esnext", +//// "moduleResolution": "bundler", +//// "noEmit": true, +//// "jsx": "preserve" +//// }, +//// "include": ["app"] +//// } + +// @Filename: /project/apps/web/app/index.tsx +//// (); + +// @link: /project/packages/ui -> /project/apps/web/node_modules/@repo/ui + +goTo.marker(""); +verify.completions({ + includes: [ + { + name: "Card", + source: "@repo/ui/Card", + sourceDisplay: "@repo/ui/Card", + hasAction: true, + sortText: completion.SortText.AutoImportSuggestions + }, + ], + preferences: { + includeCompletionsForModuleExports: true, + allowIncompleteCompletions: true + } +}); From 437d1c71462ad65bbfd341b3edbb859f5de294fb Mon Sep 17 00:00:00 2001 From: Andrew Branch Date: Thu, 21 Dec 2023 10:34:56 -0800 Subject: [PATCH 2/5] Fix lint --- src/compiler/moduleNameResolver.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/compiler/moduleNameResolver.ts b/src/compiler/moduleNameResolver.ts index 0d0c31e8b2008..b75e7b51f099e 100644 --- a/src/compiler/moduleNameResolver.ts +++ b/src/compiler/moduleNameResolver.ts @@ -41,7 +41,6 @@ import { GetCanonicalFileName, getCommonSourceDirectory, getCompilerOptionValue, - getDeclarationEmitExtensionForPath, getDirectoryPath, GetEffectiveTypeRootsHost, getEmitModuleKind, From d77d452c7f25ed63f2cc4fd496fc146e20f93476 Mon Sep 17 00:00:00 2001 From: Andrew Branch Date: Wed, 3 Jan 2024 21:42:54 +0000 Subject: [PATCH 3/5] Add helper for changing full extension --- src/compiler/moduleNameResolver.ts | 5 ++--- src/compiler/parser.ts | 19 +++++++++++++++++-- src/compiler/path.ts | 19 +++++++++++++++++++ 3 files changed, 38 insertions(+), 5 deletions(-) diff --git a/src/compiler/moduleNameResolver.ts b/src/compiler/moduleNameResolver.ts index b75e7b51f099e..19714503230c6 100644 --- a/src/compiler/moduleNameResolver.ts +++ b/src/compiler/moduleNameResolver.ts @@ -3,6 +3,7 @@ import { appendIfUnique, arrayIsEqualTo, changeAnyExtension, + changeFullExtension, CharacterCodes, combinePaths, CommandLineOption, @@ -2290,9 +2291,7 @@ function loadEntrypointsFromExportMap( extensionsToExtensionsArray(extensions), /*excludes*/ undefined, [ - isDeclarationFileName(target) - ? changeAnyExtension(replaceFirstStar(target, "**/*"), ".*", supportedDeclarationExtensions, /*ignoreCase*/ true) - : changeAnyExtension(replaceFirstStar(target, "**/*"), ".*"), + changeFullExtension(replaceFirstStar(target, "**/*"), ".*"), ], ).forEach(entry => { entrypoints = appendIfUnique(entrypoints, { diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 4f68271ccb728..2f411c435492a 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -85,7 +85,6 @@ import { Extension, ExternalModuleReference, fileExtensionIs, - fileExtensionIsOneOf, findIndex, firstOrUndefined, forEach, @@ -99,6 +98,7 @@ import { FunctionOrConstructorTypeNode, FunctionTypeNode, GetAccessorDeclaration, + getAnyExtensionFromPath, getBaseFileName, getBinaryOperatorPrecedence, getFullWidth, @@ -10433,7 +10433,22 @@ namespace IncrementalParser { /** @internal */ export function isDeclarationFileName(fileName: string): boolean { - return fileExtensionIsOneOf(fileName, supportedDeclarationExtensions) || (fileExtensionIs(fileName, Extension.Ts) && getBaseFileName(fileName).includes(".d.")); + return getDeclarationFileExtension(fileName) !== undefined; +} + +/** @internal */ +export function getDeclarationFileExtension(fileName: string): string | undefined { + const standardExtension = getAnyExtensionFromPath(fileName, supportedDeclarationExtensions, /*ignoreCase*/ false); + if (standardExtension) { + return standardExtension; + } + if (fileExtensionIs(fileName, Extension.Ts)) { + const index = getBaseFileName(fileName).lastIndexOf(".d."); + if (index >= 0) { + return fileName.substring(index); + } + } + return undefined; } function parseResolutionMode(mode: string | undefined, pos: number, end: number, reportDiagnostic: PragmaDiagnosticReporter): ResolutionMode { diff --git a/src/compiler/path.ts b/src/compiler/path.ts index 685f28158901a..6076a80e667a8 100644 --- a/src/compiler/path.ts +++ b/src/compiler/path.ts @@ -9,6 +9,7 @@ import { equateStringsCaseInsensitive, equateStringsCaseSensitive, GetCanonicalFileName, + getDeclarationFileExtension, getStringComparer, identity, lastOrUndefined, @@ -756,6 +757,24 @@ export function changeAnyExtension(path: string, ext: string, extensions?: strin return pathext ? path.slice(0, path.length - pathext.length) + (startsWith(ext, ".") ? ext : "." + ext) : path; } +/** + * @internal + * Like `changeAnyExtension`, but declaration file extensions are recognized + * and replaced starting from the `.d`. + * + * ```ts + * changeAnyExtension("file.d.ts", ".js") === "file.d.js" + * changeFullExtension("file.d.ts", ".js") === "file.js" + * ``` + */ +export function changeFullExtension(path: string, newExtension: string) { + const declarationExtension = getDeclarationFileExtension(path); + if (declarationExtension) { + return path.slice(0, path.length - declarationExtension.length) + newExtension; + } + return changeAnyExtension(path, newExtension); +} + //// Path Comparisons // check path for these segments: '', '.'. '..' From 775554fad4960924cd947addcfd84a49ebc0ab2e Mon Sep 17 00:00:00 2001 From: Andrew Branch Date: Wed, 3 Jan 2024 22:22:45 +0000 Subject: [PATCH 4/5] Handle when `newExtension` does not start with . --- src/compiler/path.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/compiler/path.ts b/src/compiler/path.ts index 6076a80e667a8..abacb8bb1de9b 100644 --- a/src/compiler/path.ts +++ b/src/compiler/path.ts @@ -770,7 +770,8 @@ export function changeAnyExtension(path: string, ext: string, extensions?: strin export function changeFullExtension(path: string, newExtension: string) { const declarationExtension = getDeclarationFileExtension(path); if (declarationExtension) { - return path.slice(0, path.length - declarationExtension.length) + newExtension; + return path.slice(0, path.length - declarationExtension.length) + + startsWith(newExtension, ".") ? newExtension : ("." + newExtension); } return changeAnyExtension(path, newExtension); } From a9c9548d8bdc64b63bed841fe3e48bb818c6933c Mon Sep 17 00:00:00 2001 From: Andrew Branch Date: Wed, 3 Jan 2024 22:35:22 +0000 Subject: [PATCH 5/5] Fix ternary/addition precedence --- src/compiler/path.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/path.ts b/src/compiler/path.ts index abacb8bb1de9b..8c7f75f816a8b 100644 --- a/src/compiler/path.ts +++ b/src/compiler/path.ts @@ -771,7 +771,7 @@ export function changeFullExtension(path: string, newExtension: string) { const declarationExtension = getDeclarationFileExtension(path); if (declarationExtension) { return path.slice(0, path.length - declarationExtension.length) + - startsWith(newExtension, ".") ? newExtension : ("." + newExtension); + (startsWith(newExtension, ".") ? newExtension : ("." + newExtension)); } return changeAnyExtension(path, newExtension); }