Skip to content
This repository has been archived by the owner on Oct 10, 2018. It is now read-only.

fix: Correctly ignore glob patterns from file search #339

Merged
merged 22 commits into from
Nov 8, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@
"--extensionDevelopmentPath=${workspaceRoot}",
"--extensionTestsPath=${workspaceRoot}/out/test/single-workspace-tests/"
],
"env": {
"CI": "true"
},
"stopOnEntry": false,
"sourceMaps": true,
"outFiles": [
Expand All @@ -63,6 +66,9 @@
"--extensionDevelopmentPath=${workspaceRoot}",
"--extensionTestsPath=${workspaceRoot}/out/test/multi-root-workspace-tests/"
],
"env": {
"CI": "true"
},
"stopOnEntry": false,
"sourceMaps": true,
"outFiles": [
Expand Down
35 changes: 18 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,30 +82,31 @@ The following settings do have the prefix `codeCompletion`. So an example settin
`typescriptHero.codeCompletion.completionSortOrder`.

| Setting | Description |
| ------------------- | ------------------------------------------------------------------------------|
| ------------------- | ----------------------------------------------------------------------------- |
| completionSortOrder | The order of import completions in suggestion list, `bottom` pushes them down |

### Import resolver

The following settings do have the prefix `resolver`. So an example setting could be
`typescriptHero.resolver.stringQuoteStyle`.

| Setting | Description |
| ------------------------------------- | ------------------------------------------------------------------------------------ |
| stringQuoteStyle | The string delimiter to use for the imports (`'` or `"`) |
| ignorePatterns | If any of these strings is part of a file path, the file is ignored |
| insertSpaceBeforeAndAfterImportBraces | If the extension should place spaces into import braces (`{Symbol}` vs `{ Symbol }`) |
| insertSemicolons | If the extension should add a semicolon to the end of a statement |
| multiLineWrapThreshold | The threshold, when imports are converted into multiline imports |
| multiLineTrailingComma | When multiline imports are created, `true` inserts a trailing comma to the last line |
| disableImportSorting | Disable sorting during organize imports action |
| disableImportRemovalOnOrganize | Disable removal unsed imports during organize imports action |
| importGroups | The groups that are used for sorting the imports (description below) |
| ignoreImportsForOrganize | Imports that are never removed during organize import (e.g. react) |
| resolverMode | Which files should be considered to index for TypeScript Hero |
| organizeOnSave | Enable or disable the `organizeImports` action on a save of a document |
| organizeSortsByFirstSpecifier | When organizing runs, sort by first specifier/alias (if any) instead of module path |
| promptForSpecifiers | If the extension should ask the user for aliases and duplicate specifiers |
| Setting | Description |
| ------------------------------------- | --------------------------------------------------------------------------------------------- |
| stringQuoteStyle | The string delimiter to use for the imports (`'` or `"`) |
| workspaceIgnorePatterns | If any of these strings is part of a file path, the file is ignored during workspace indexing |
| moduleIgnorePatterns | If any of these strings is part of a file path, the file is ignored during module indexing |
| insertSpaceBeforeAndAfterImportBraces | If the extension should place spaces into import braces (`{Symbol}` vs `{ Symbol }`) |
| insertSemicolons | If the extension should add a semicolon to the end of a statement |
| multiLineWrapThreshold | The threshold, when imports are converted into multiline imports |
| multiLineTrailingComma | When multiline imports are created, `true` inserts a trailing comma to the last line |
| disableImportSorting | Disable sorting during organize imports action |
| disableImportRemovalOnOrganize | Disable removal unsed imports during organize imports action |
| importGroups | The groups that are used for sorting the imports (description below) |
| ignoreImportsForOrganize | Imports that are never removed during organize import (e.g. react) |
| resolverMode | Which files should be considered to index for TypeScript Hero |
| organizeOnSave | Enable or disable the `organizeImports` action on a save of a document |
| organizeSortsByFirstSpecifier | When organizing runs, sort by first specifier/alias (if any) instead of module path |
| promptForSpecifiers | If the extension should ask the user for aliases and duplicate specifiers |

### Code outline view

Expand Down
22 changes: 17 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -208,18 +208,30 @@
"description": "Defines if single or double quotes should be used.",
"scope": "resource"
},
"typescriptHero.resolver.ignorePatterns": {
"typescriptHero.resolver.workspaceIgnorePatterns": {
"type": "array",
"items": {
"type": "string"
},
"uniqueItems": true,
"default": [
"build",
"out",
"dist"
"**/build/**/*",
"**/out/**/*",
"**/dist/**/*"
],
"description": "Defines partial pathes that are ignored during indexing (e.g. 'node_modules' would exclude all modules).",
"description": "Defines partial pathes (globs) that are ignored during indexing of the **workspace** (e.g. 'node_modules/**/*' would exclude all modules).",
"scope": "resource"
},
"typescriptHero.resolver.moduleIgnorePatterns": {
"type": "array",
"items": {
"type": "string"
},
"uniqueItems": true,
"default": [
"**/node_modules/**/*"
],
"description": "Defines partial pathes (globs) that are ignored during indexing of the **node_modules**. This patterns are attached to the node_module/<name> of each found module.",
"scope": "resource"
},
"typescriptHero.resolver.multiLineWrapThreshold": {
Expand Down
18 changes: 15 additions & 3 deletions src/common/config/ResolverConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,14 +50,26 @@ export interface ResolverConfig {
stringQuoteStyle: string;

/**
* Array of string that are excluded from indexing (e.g. build, out, node_modules).
* If those parts are found after the workspace path is striped away, the file is ignored.
* Array of string that are excluded from indexing of the workspace (e.g. build, out, dist).
* This patterns are ignored during indexing of the files found in the workspace.
* To exclude other files that are found in the node_modules, use moduleIgnorePatterns.
*
* @readonly
* @type {string[]}
* @memberof ResolverConfig
*/
ignorePatterns: string[];
workspaceIgnorePatterns: string[];

/**
* Array of string that are excluded from indexing of the modules (e.g. further node_modules).
* This patterns are ignored during indexing of the files found in the workspace.
* To exclude other files that are found in the node_modules, use moduleIgnorePatterns.
*
* @readonly
* @type {string[]}
* @memberof ResolverConfig
*/
moduleIgnorePatterns: string[];

/**
* A length number after which the import is transformed into a multiline import.
Expand Down
97 changes: 50 additions & 47 deletions src/common/helpers/DeclarationIndexHelpers.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
import { existsSync } from 'fs';
import { join, normalize, parse, relative } from 'path';
import { DeclarationInfo, ExternalModuleImport, Import, NamedImport, NamespaceImport } from 'typescript-parser';
import {
DeclarationInfo,
DefaultDeclaration,
ExternalModuleImport,
Import,
NamedImport,
NamespaceImport,
} from 'typescript-parser';
import { toPosix } from 'typescript-parser/utilities/PathHelpers';
import { RelativePattern, Uri, workspace, WorkspaceFolder } from 'vscode';

Expand Down Expand Up @@ -30,10 +37,14 @@ export function getDeclarationsFilteredByImports(

if (tsImport instanceof NamedImport) {
declarations = declarations.filter(
o => o.from !== importedLib ||
!tsImport.specifiers.some(s => s.specifier === o.declaration.name),
// || tsImport.defaultAlias !== o.declaration.name,
d => d.from !== importedLib ||
!tsImport.specifiers.some(s => s.specifier === d.declaration.name),
);
if (tsImport.defaultAlias) {
declarations = declarations.filter(
d => !(tsImport.defaultAlias && d.declaration instanceof DefaultDeclaration && d.from === importedLib),
);
}
} else if (tsImport instanceof NamespaceImport || tsImport instanceof ExternalModuleImport) {
declarations = declarations.filter(o => o.from !== tsImport.libraryName);
}
Expand Down Expand Up @@ -94,50 +105,56 @@ export function getRelativeLibraryName(library: string, actualFilePath: string,
* This function searches for files in a specific workspace folder. The files are relative to the given
* workspace folder and the searched type is determined by the configuration of the extension (TS, JS or Both mode).
*
* If a node_modules folder is present, but NO package.json, the node_modules are ignored completely.
* (For performance and memory reasons)
*
* @export
* @param {ExtensionConfig} config
* @param {WorkspaceFolder} workspaceFolder
* @returns {Promise<string[]>}
*/
export async function findFiles(config: ExtensionConfig, workspaceFolder: WorkspaceFolder): Promise<string[]> {
const workspaceExcludes = [
...config.resolver.workspaceIgnorePatterns,
'node_modules/**/*',
'typings/**/*',
];
const moduleExcludes = config.resolver.moduleIgnorePatterns;
const searches: PromiseLike<Uri[]>[] = [
workspace.findFiles(
new RelativePattern(workspaceFolder, `{${config.resolver.resolverModeFileGlobs.join(',')}}`),
new RelativePattern(workspaceFolder, '{**/node_modules/**,**/typings/**}'),
new RelativePattern(workspaceFolder, `{${workspaceExcludes.join(',')}}`),
),
];

// TODO: check the package json and index javascript file in node_modules (?)

let globs: string[] = [];
let ignores = ['**/typings/**'];
const excludePatterns = config.resolver.ignorePatterns;
let globs: string[] = ['typings/**/*.d.ts'];
let ignores: string[] = [];
const rootPath = workspaceFolder.uri.fsPath;
const hasPackageJson = existsSync(join(rootPath, 'package.json'));

if (rootPath && existsSync(join(rootPath, 'package.json'))) {
if (rootPath && hasPackageJson) {
const packageJson = require(join(rootPath, 'package.json'));
if (packageJson['dependencies']) {
globs = globs.concat(
Object.keys(packageJson['dependencies']).filter(o => excludePatterns.indexOf(o) < 0)
.map(o => `**/node_modules/${o}/**/*.d.ts`),
);
ignores = ignores.concat(
Object.keys(packageJson['dependencies']).filter(o => excludePatterns.indexOf(o) < 0)
.map(o => `**/node_modules/${o}/node_modules/**`),
);
}
if (packageJson['devDependencies']) {
globs = globs.concat(
Object.keys(packageJson['devDependencies']).filter(o => excludePatterns.indexOf(o) < 0)
.map(o => `**/node_modules/${o}/**/*.d.ts`),
);
ignores = ignores.concat(
Object.keys(packageJson['devDependencies']).filter(o => excludePatterns.indexOf(o) < 0)
.map(o => `**/node_modules/${o}/node_modules/**`),
);
for (const folder of ['dependencies', 'devDependencies']) {
if (packageJson[folder]) {
globs = globs.concat(
Object.keys(packageJson[folder]).map(o => `node_modules/${o}/**/*.d.ts`),
);
ignores = ignores.concat(
Object.keys(packageJson[folder]).reduce(
(all, pkg) => {
return all.concat(
moduleExcludes.map(exclude => `node_modules/${pkg}/${exclude}`),
);
},
[] as string[],
),
);
}
}
} else {
globs.push('**/node_modules/**/*.d.ts');
ignores.push('node_modules/**/*');
}

searches.push(
Expand All @@ -147,22 +164,8 @@ export async function findFiles(config: ExtensionConfig, workspaceFolder: Worksp
),
);

searches.push(
workspace.findFiles(
new RelativePattern(workspaceFolder, '**/typings/**/*.d.ts'),
new RelativePattern(workspaceFolder, '**/node_modules/**'),
),
);

let uris = await Promise.all(searches);

uris = uris.map((o, idx) => idx === 0 ?
o.filter(
f => f.fsPath
.replace(rootPath || '', '')
.split(/[\\/]/)
.every(p => excludePatterns.indexOf(p) < 0)) :
o,
);
return uris.reduce((all, cur) => all.concat(cur), []).map(o => o.fsPath);
const uris = await Promise.all(searches);
return uris
.reduce((all, cur) => all.concat(cur), [])
.map(o => o.fsPath);
}
33 changes: 26 additions & 7 deletions src/extension/config/VscodeResolverConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,20 +53,39 @@ export class VscodeResolverConfig implements ResolverConfig {
}

/**
* Array of string that are excluded from indexing (e.g. build, out, node_modules).
* If those parts are found after the workspace path is striped away, the file is ignored.
* Array of string that are excluded from indexing of the workspace (e.g. build, out, dist).
* This patterns are ignored during indexing of the files found in the workspace.
* To exclude other files that are found in the node_modules, use moduleIgnorePatterns.
*
* @readonly
* @type {string[]}
* @memberof VscodeResolverConfig
*/
public get ignorePatterns(): string[] {
public get workspaceIgnorePatterns(): string[] {
return this.workspaceSection.get(
'ignorePatterns',
'workspaceIgnorePatterns',
[
'build',
'out',
'dist',
'**/build/**/*',
'**/out/**/*',
'**/dist/**/*',
],
);
}

/**
* Array of string that are excluded from indexing of the modules (e.g. further node_modules).
* This patterns are ignored during indexing of the files found in the workspace.
* To exclude other files that are found in the node_modules, use moduleIgnorePatterns.
*
* @readonly
* @type {string[]}
* @memberof VscodeResolverConfig
*/
public get moduleIgnorePatterns(): string[] {
return this.workspaceSection.get(
'moduleIgnorePatterns',
[
'**/node_modules/**/*',
],
);
}
Expand Down
Loading