mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
Don’t filter when there’s no package.json, fix scoped package imports
This commit is contained in:
6 files changed
+157
-23
No files matched your search
@@ -571,37 +571,33 @@ namespace ts.codefix {
|
||||
const packageJsons = findPackageJsons(getDirectoryPath(from.fileName), host);
|
||||
const dependencyIterator = readPackageJsonDependencies();
|
||||
forEachExternalModule(checker, allSourceFiles, (module, sourceFile) => {
|
||||
if (sourceFile === undefined || sourceFile !== from && isImportablePath(from.fileName, sourceFile.fileName) && packageJsonAllowsImporting(sourceFile.fileName)) {
|
||||
if (sourceFile === undefined) {
|
||||
const maybeSourceFile = module.valueDeclaration.getSourceFile();
|
||||
if (!maybeSourceFile || packageJsonAllowsImporting(maybeSourceFile.fileName)) {
|
||||
cb(module);
|
||||
}
|
||||
}
|
||||
else if (sourceFile && sourceFile !== from && isImportablePath(from.fileName, sourceFile.fileName) && packageJsonAllowsImporting(sourceFile.fileName)) {
|
||||
cb(module);
|
||||
}
|
||||
});
|
||||
|
||||
let seenDeps: Map<true> | undefined;
|
||||
function packageJsonAllowsImporting(fileName: string): Ternary {
|
||||
const pathComponents = getPathComponents(getDirectoryPath(fileName));
|
||||
const nodeModulesIndex = pathComponents.lastIndexOf("node_modules");
|
||||
if (nodeModulesIndex === -1) {
|
||||
return Ternary.Maybe;
|
||||
}
|
||||
const moduleSpecifier = pathComponents[nodeModulesIndex + 1] === "@types"
|
||||
? pathComponents[nodeModulesIndex + 2]
|
||||
: pathComponents[nodeModulesIndex + 1];
|
||||
if (!moduleSpecifier) {
|
||||
return Ternary.Maybe;
|
||||
}
|
||||
|
||||
if (seenDeps && seenDeps.has(moduleSpecifier)) {
|
||||
return Ternary.True;
|
||||
function packageJsonAllowsImporting(fileName: string): boolean {
|
||||
const moduleSpecifier = getModuleSpecifierFromFileName(fileName);
|
||||
if (!moduleSpecifier || !packageJsons.length || seenDeps && seenDeps.has(moduleSpecifier)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
let packageName: string;
|
||||
while (packageName = dependencyIterator.next().value) {
|
||||
(seenDeps || (seenDeps = createMap())).set(packageName, true);
|
||||
if (packageName === moduleSpecifier) {
|
||||
return Ternary.True;
|
||||
const nameWithoutTypes = getPackageNameFromTypesPackageName(packageName);
|
||||
(seenDeps || (seenDeps = createMap())).set(nameWithoutTypes, true);
|
||||
if (nameWithoutTypes === moduleSpecifier) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return Ternary.False;
|
||||
return false;
|
||||
}
|
||||
|
||||
type PackageJson = Record<string, Record<string, string> | undefined>;
|
||||
@@ -620,6 +616,24 @@ namespace ts.codefix {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getModuleSpecifierFromFileName(fileName: string): string | undefined {
|
||||
const pathComponents = getPathComponents(getDirectoryPath(fileName));
|
||||
const nodeModulesIndex = pathComponents.lastIndexOf("node_modules");
|
||||
if (nodeModulesIndex === -1) {
|
||||
return undefined;
|
||||
}
|
||||
const firstComponent = pathComponents[nodeModulesIndex + 1];
|
||||
const moduleSpecifier = firstComponent &&
|
||||
firstComponent === "@types" ? pathComponents[nodeModulesIndex + 2] :
|
||||
startsWith(firstComponent, "@") ? `${firstComponent}/${pathComponents[nodeModulesIndex + 2]}` :
|
||||
firstComponent;
|
||||
|
||||
if (!moduleSpecifier) {
|
||||
return undefined;
|
||||
}
|
||||
return moduleSpecifier;
|
||||
}
|
||||
}
|
||||
|
||||
function forEachExternalModule(checker: TypeChecker, allSourceFiles: ReadonlyArray<SourceFile>, cb: (module: Symbol, sourceFile: SourceFile | undefined) => void) {
|
||||
|
||||
+2
-2
@@ -14,7 +14,7 @@
|
||||
|
||||
//@Filename: /node_modules/@types/react/package.json
|
||||
////{
|
||||
//// "name": "react"
|
||||
//// "name": "@types/react"
|
||||
////}
|
||||
|
||||
//@Filename: /node_modules/@types/fake-react/index.d.ts
|
||||
@@ -22,7 +22,7 @@
|
||||
|
||||
//@Filename: /node_modules/@types/fake-react/package.json
|
||||
////{
|
||||
//// "name": "fake-react"
|
||||
//// "name": "@types/fake-react"
|
||||
////}
|
||||
|
||||
//@Filename: /src/index.ts
|
||||
@@ -0,0 +1,44 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
|
||||
//@noEmit: true
|
||||
|
||||
//@Filename: /package.json
|
||||
////{
|
||||
//// "devDependencies": {
|
||||
//// "@types/react": "*"
|
||||
//// }
|
||||
////}
|
||||
|
||||
//@Filename: /node_modules/@types/react/index.d.ts
|
||||
////export declare var React: any;
|
||||
|
||||
//@Filename: /node_modules/@types/react/package.json
|
||||
////{
|
||||
//// "name": "@types/react"
|
||||
////}
|
||||
|
||||
//@Filename: /node_modules/@types/fake-react/index.d.ts
|
||||
////export declare var ReactFake: any;
|
||||
|
||||
//@Filename: /node_modules/@types/fake-react/package.json
|
||||
////{
|
||||
//// "name": "@types/fake-react"
|
||||
////}
|
||||
|
||||
//@Filename: /src/index.ts
|
||||
////const x = Re/**/
|
||||
|
||||
verify.completions({
|
||||
marker: test.marker(""),
|
||||
isNewIdentifierLocation: true,
|
||||
includes: {
|
||||
name: "React",
|
||||
hasAction: true,
|
||||
source: "/node_modules/@types/react/index",
|
||||
sortText: completion.SortText.AutoImportSuggestions
|
||||
},
|
||||
excludes: "ReactFake",
|
||||
preferences: {
|
||||
includeCompletionsForModuleExports: true
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,30 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
|
||||
//@noEmit: true
|
||||
|
||||
//@Filename: /package.json
|
||||
////{
|
||||
//// "dependencies": {
|
||||
//// }
|
||||
////}
|
||||
|
||||
//@Filename: /node_modules/@types/node/timers.d.ts
|
||||
////declare module "timers" {
|
||||
//// function setTimeout(callback: (...args: any[]) => void, ms: number, ...args: any[]): NodeJS.Timeout;
|
||||
////}
|
||||
|
||||
//@Filename: /node_modules/@types/node/package.json
|
||||
////{
|
||||
//// "name": "@types/node",
|
||||
////}
|
||||
|
||||
//@Filename: /src/index.ts
|
||||
////setTimeo/**/
|
||||
|
||||
verify.completions({
|
||||
marker: test.marker(""),
|
||||
exact: completion.globals,
|
||||
preferences: {
|
||||
includeCompletionsForModuleExports: true
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,46 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
|
||||
//@noEmit: true
|
||||
|
||||
//@Filename: /package.json
|
||||
////{
|
||||
//// "dependencies": {
|
||||
//// "react": "*"
|
||||
//// }
|
||||
////}
|
||||
|
||||
//@Filename: /node_modules/react/index.d.ts
|
||||
////export declare var React: any;
|
||||
|
||||
//@Filename: /node_modules/react/package.json
|
||||
////{
|
||||
//// "name": "react",
|
||||
//// "types": "./index.d.ts"
|
||||
////}
|
||||
|
||||
//@Filename: /node_modules/fake-react/index.d.ts
|
||||
////export declare var ReactFake: any;
|
||||
|
||||
//@Filename: /node_modules/fake-react/package.json
|
||||
////{
|
||||
//// "name": "fake-react",
|
||||
//// "types": "./index.d.ts"
|
||||
////}
|
||||
|
||||
//@Filename: /src/index.ts
|
||||
////const x = Re/**/
|
||||
|
||||
verify.completions({
|
||||
marker: test.marker(""),
|
||||
isNewIdentifierLocation: true,
|
||||
includes: {
|
||||
name: "React",
|
||||
hasAction: true,
|
||||
source: "/node_modules/react/index",
|
||||
sortText: completion.SortText.AutoImportSuggestions
|
||||
},
|
||||
excludes: "ReactFake",
|
||||
preferences: {
|
||||
includeCompletionsForModuleExports: true
|
||||
}
|
||||
});
|
||||
@@ -3,7 +3,7 @@
|
||||
//// [|f1/*0*/('');|]
|
||||
|
||||
// @Filename: package.json
|
||||
//// { "dependencies": { "package-name": "latest" } }
|
||||
//// { "dependencies": { "@scope/package-name": "latest" } }
|
||||
|
||||
// @Filename: node_modules/@scope/package-name/bin/lib/index.d.ts
|
||||
//// export function f1(text: string): string;
|
||||
|
||||
Reference in new issue
Block a user