Skip to content

Commit

Permalink
fix(typescript-estree): add default value for `parserOptions.projectF…
Browse files Browse the repository at this point in the history
…olderIgnoreList` and deduplicate resolved projects (#2819)

In #2418 I introduced a regression - I forgot to add in the default value for `projectFolderIgnoreList`.
This means that globs have been matching `node_modules` since the v4.0 release! Oops :(

This PR fixes that.
It also hoists the tsconfig path canonicalisation up so that we can deduplicate early.
Previously if you provided a config like `projects: ['./tsconfig.json', './**/tsconfig.json']`, then we would resolve this to `./tsconfig.json` and `tsconfig.json`, then later canonicalise them.
This meant we'd check that same tsconfig twice!
By hoisting the canonicalisation, we can deduplicate this early.

Fixes #2814
  • Loading branch information
bradzacher committed Nov 26, 2020
1 parent 14758d2 commit bf904ec
Show file tree
Hide file tree
Showing 5 changed files with 39 additions and 32 deletions.
Expand Up @@ -4,7 +4,7 @@ import * as ts from 'typescript';
import { Extra } from '../parser-options';
import {
ASTAndProgram,
getTsconfigPath,
CanonicalPath,
createDefaultCompilerOptionsFromExtra,
} from './shared';

Expand All @@ -27,7 +27,7 @@ function createDefaultProgram(
return undefined;
}

const tsconfigPath = getTsconfigPath(extra.projects[0], extra);
const tsconfigPath: CanonicalPath = extra.projects[0];

const commandLine = ts.getParsedCommandLineOfConfigFile(
tsconfigPath,
Expand Down
Expand Up @@ -9,7 +9,6 @@ import {
CanonicalPath,
createDefaultCompilerOptionsFromExtra,
getCanonicalFileName,
getTsconfigPath,
} from './shared';

const log = debug('typescript-eslint:typescript-estree:createWatchProgram');
Expand Down Expand Up @@ -197,9 +196,7 @@ function getProgramsForProjects(
* - the required program hasn't been created yet, or
* - the file is new/renamed, and the program hasn't been updated.
*/
for (const rawTsconfigPath of extra.projects) {
const tsconfigPath = getTsconfigPath(rawTsconfigPath, extra);

for (const tsconfigPath of extra.projects) {
const existingWatch = knownWatchProgramMap.get(tsconfigPath);

if (existingWatch) {
Expand Down
5 changes: 0 additions & 5 deletions packages/typescript-estree/src/create-program/shared.ts
Expand Up @@ -60,10 +60,6 @@ function ensureAbsolutePath(p: string, extra: Extra): string {
: path.join(extra.tsconfigRootDir || process.cwd(), p);
}

function getTsconfigPath(tsconfigPath: string, extra: Extra): CanonicalPath {
return getCanonicalFileName(ensureAbsolutePath(tsconfigPath, extra));
}

function canonicalDirname(p: CanonicalPath): CanonicalPath {
return path.dirname(p) as CanonicalPath;
}
Expand Down Expand Up @@ -105,5 +101,4 @@ export {
ensureAbsolutePath,
getCanonicalFileName,
getScriptKind,
getTsconfigPath,
};
3 changes: 2 additions & 1 deletion packages/typescript-estree/src/parser-options.ts
@@ -1,6 +1,7 @@
import { DebugLevel } from '@typescript-eslint/types';
import { Program } from 'typescript';
import { TSESTree, TSNode, TSESTreeToTSNode, TSToken } from './ts-estree';
import { CanonicalPath } from './create-program/shared';

type DebugModule = 'typescript-eslint' | 'eslint' | 'typescript';

Expand All @@ -19,7 +20,7 @@ export interface Extra {
loc: boolean;
log: (message: string) => void;
preserveNodeMaps?: boolean;
projects: string[];
projects: CanonicalPath[];
range: boolean;
strict: boolean;
tokens: null | TSESTree.Token[];
Expand Down
54 changes: 34 additions & 20 deletions packages/typescript-estree/src/parser.ts
Expand Up @@ -12,7 +12,12 @@ import { createSourceFile } from './create-program/createSourceFile';
import { Extra, TSESTreeOptions, ParserServices } from './parser-options';
import { getFirstSemanticOrSyntacticError } from './semantic-or-syntactic-errors';
import { TSESTree } from './ts-estree';
import { ASTAndProgram, ensureAbsolutePath } from './create-program/shared';
import {
ASTAndProgram,
CanonicalPath,
ensureAbsolutePath,
getCanonicalFileName,
} from './create-program/shared';

const log = debug('typescript-eslint:typescript-estree:parser');

Expand Down Expand Up @@ -109,46 +114,53 @@ function resetExtra(): void {
};
}

function getTsconfigPath(tsconfigPath: string, extra: Extra): CanonicalPath {
return getCanonicalFileName(ensureAbsolutePath(tsconfigPath, extra));
}

/**
* Normalizes, sanitizes, resolves and filters the provided
* Normalizes, sanitizes, resolves and filters the provided project paths
*/
function prepareAndTransformProjects(
projectsInput: string | string[] | undefined,
ignoreListInput: string[],
): string[] {
let projects: string[] = [];
): CanonicalPath[] {
const sanitizedProjects: string[] = [];

// Normalize and sanitize the project paths
if (typeof projectsInput === 'string') {
projects.push(projectsInput);
sanitizedProjects.push(projectsInput);
} else if (Array.isArray(projectsInput)) {
for (const project of projectsInput) {
if (typeof project === 'string') {
projects.push(project);
sanitizedProjects.push(project);
}
}
}

if (projects.length === 0) {
return projects;
if (sanitizedProjects.length === 0) {
return [];
}

// Transform glob patterns into paths
const globbedProjects = projects.filter(project => isGlob(project));
projects = projects
.filter(project => !isGlob(project))
.concat(
globSync([...globbedProjects, ...ignoreListInput], {
cwd: extra.tsconfigRootDir,
}),
);
const nonGlobProjects = sanitizedProjects.filter(project => !isGlob(project));
const globProjects = sanitizedProjects.filter(project => isGlob(project));
const uniqueCanonicalProjectPaths = new Set(
nonGlobProjects
.concat(
globSync([...globProjects, ...ignoreListInput], {
cwd: extra.tsconfigRootDir,
}),
)
.map(project => getTsconfigPath(project, extra)),
);

log(
'parserOptions.project (excluding ignored) matched projects: %s',
projects,
uniqueCanonicalProjectPaths,
);

return projects;
return Array.from(uniqueCanonicalProjectPaths);
}

function applyParserOptionsToExtra(options: TSESTreeOptions): void {
Expand Down Expand Up @@ -252,8 +264,9 @@ function applyParserOptionsToExtra(options: TSESTreeOptions): void {
// NOTE - ensureAbsolutePath relies upon having the correct tsconfigRootDir in extra
extra.filePath = ensureAbsolutePath(extra.filePath, extra);

// NOTE - prepareAndTransformProjects relies upon having the correct tsconfigRootDir in extra
const projectFolderIgnoreList = (options.projectFolderIgnoreList ?? [])
const projectFolderIgnoreList = (
options.projectFolderIgnoreList ?? ['**/node_modules/**']
)
.reduce<string[]>((acc, folder) => {
if (typeof folder === 'string') {
acc.push(folder);
Expand All @@ -262,6 +275,7 @@ function applyParserOptionsToExtra(options: TSESTreeOptions): void {
}, [])
// prefix with a ! for not match glob
.map(folder => (folder.startsWith('!') ? folder : `!${folder}`));
// NOTE - prepareAndTransformProjects relies upon having the correct tsconfigRootDir in extra
extra.projects = prepareAndTransformProjects(
options.project,
projectFolderIgnoreList,
Expand Down

0 comments on commit bf904ec

Please sign in to comment.