Skip to content

Commit

Permalink
fix(typescript-estree): check for relative/root paths in printing fil…
Browse files Browse the repository at this point in the history
…e path errors (#6491)

* fix(typescript-estree): check for relative/root paths in printing file path errors

* Missing slash in a test case

* Update packages/typescript-estree/src/create-program/createProjectProgram.ts

Co-authored-by: Armano <armano2@users.noreply.github.com>

* Post-suggestion format

---------

Co-authored-by: Armano <armano2@users.noreply.github.com>
  • Loading branch information
JoshuaKGoldberg and armano2 committed Feb 21, 2023
1 parent 06b96ad commit dc14242
Show file tree
Hide file tree
Showing 4 changed files with 249 additions and 12 deletions.
Expand Up @@ -4,6 +4,7 @@ import * as ts from 'typescript';

import { firstDefined } from '../node-utils';
import type { ParseSettings } from '../parseSettings';
import { describeFilePath } from './describeFilePath';
import { getWatchProgramsForProjects } from './getWatchProgramsForProjects';
import type { ASTAndProgram } from './shared';
import { getAstFromProgram } from './shared';
Expand Down Expand Up @@ -40,19 +41,14 @@ function createProjectProgram(
return astAndProgram;
}

const describeFilePath = (filePath: string): string => {
const relative = path.relative(
parseSettings.tsconfigRootDir || process.cwd(),
filePath,
);
if (parseSettings.tsconfigRootDir) {
return `<tsconfigRootDir>/${relative}`;
}
return `<cwd>/${relative}`;
};
const describeProjectFilePath = (projectFile: string): string =>
describeFilePath(projectFile, parseSettings.tsconfigRootDir);

const describedFilePath = describeFilePath(parseSettings.filePath);
const relativeProjects = parseSettings.projects.map(describeFilePath);
const describedFilePath = describeFilePath(
parseSettings.filePath,
parseSettings.tsconfigRootDir,
);
const relativeProjects = parseSettings.projects.map(describeProjectFilePath);
const describedPrograms =
relativeProjects.length === 1
? relativeProjects[0]
Expand Down
31 changes: 31 additions & 0 deletions packages/typescript-estree/src/create-program/describeFilePath.ts
@@ -0,0 +1,31 @@
import path from 'path';

export function describeFilePath(
filePath: string,
tsconfigRootDir: string,
): string {
// If the TSConfig root dir is a parent of the filePath, use
// `<tsconfigRootDir>` as a prefix for the path.
const relative = path.relative(tsconfigRootDir, filePath);
if (relative && !relative.startsWith('..') && !path.isAbsolute(relative)) {
return `<tsconfigRootDir>/${relative}`;
}

// Root-like Mac/Linux (~/*, ~*) or Windows (C:/*, /) paths that aren't
// relative to the TSConfig root dir should be fully described.
// This avoids strings like <tsconfigRootDir>/../../../../repo/file.ts.
// https://github.com/typescript-eslint/typescript-eslint/issues/6289
if (/^[(\w+:)\\/~]/.test(filePath)) {
return filePath;
}

// Similarly, if the relative path would contain a lot of ../.., then
// ignore it and print the file path directly.
if (/\.\.[/\\]\.\./.test(relative)) {
return filePath;
}

// Lastly, since we've eliminated all special cases, we know the cleanest
// path to print is probably the prefixed relative one.
return `<tsconfigRootDir>/${relative}`;
}
@@ -0,0 +1,169 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`describeFilePath tsconfigRootDir ./repos/repo filePath ./elsewhere/repo/file.ts 1`] = `"./elsewhere/repo/file.ts"`;

exports[`describeFilePath tsconfigRootDir ./repos/repo filePath ./elsewhere/repo/nested/file.ts 1`] = `"./elsewhere/repo/nested/file.ts"`;

exports[`describeFilePath tsconfigRootDir ./repos/repo filePath ./repos/file.ts 1`] = `"<tsconfigRootDir>/../file.ts"`;
exports[`describeFilePath tsconfigRootDir ./repos/repo filePath ./repos/other/file.ts 1`] = `"<tsconfigRootDir>/../other/file.ts"`;
exports[`describeFilePath tsconfigRootDir ./repos/repo filePath ./repos/repo/file.ts 1`] = `"<tsconfigRootDir>/file.ts"`;
exports[`describeFilePath tsconfigRootDir ./repos/repo filePath ./repos/repo/nested/file.ts 1`] = `"<tsconfigRootDir>/nested/file.ts"`;
exports[`describeFilePath tsconfigRootDir ./repos/repo filePath /elsewhere/repo/file.ts 1`] = `"/elsewhere/repo/file.ts"`;
exports[`describeFilePath tsconfigRootDir ./repos/repo filePath /elsewhere/repo/nested/file.ts 1`] = `"/elsewhere/repo/nested/file.ts"`;
exports[`describeFilePath tsconfigRootDir ./repos/repo filePath /file.ts 1`] = `"/file.ts"`;
exports[`describeFilePath tsconfigRootDir ./repos/repo filePath /nested/file.ts 1`] = `"/nested/file.ts"`;
exports[`describeFilePath tsconfigRootDir ./repos/repo filePath /repos/repo/file.ts 1`] = `"/repos/repo/file.ts"`;
exports[`describeFilePath tsconfigRootDir ./repos/repo filePath /repos/repo/nested/file.ts 1`] = `"/repos/repo/nested/file.ts"`;
exports[`describeFilePath tsconfigRootDir ./repos/repo filePath ~/file.ts 1`] = `"~/file.ts"`;
exports[`describeFilePath tsconfigRootDir ./repos/repo filePath ~/nested/file.ts 1`] = `"~/nested/file.ts"`;
exports[`describeFilePath tsconfigRootDir ./repos/repo filePath ~/nested/file.ts 2`] = `"~/nested/file.ts"`;
exports[`describeFilePath tsconfigRootDir ./repos/repo filePath ~/other/nested/path/to/file.ts 1`] = `"~/other/nested/path/to/file.ts"`;
exports[`describeFilePath tsconfigRootDir ./repos/repo filePath ~/other/repo/file.ts 1`] = `"~/other/repo/file.ts"`;
exports[`describeFilePath tsconfigRootDir ./repos/repo filePath ~/repos/file.ts 1`] = `"~/repos/file.ts"`;
exports[`describeFilePath tsconfigRootDir ./repos/repo filePath ~/repos/other/file.ts 1`] = `"~/repos/other/file.ts"`;
exports[`describeFilePath tsconfigRootDir ./repos/repo filePath ~/repos/other/nested/file.ts 1`] = `"~/repos/other/nested/file.ts"`;
exports[`describeFilePath tsconfigRootDir ./repos/repo filePath ~/repos/repo/file.ts 1`] = `"~/repos/repo/file.ts"`;
exports[`describeFilePath tsconfigRootDir ./repos/repo filePath ~/repos/repo/nested/file.ts 1`] = `"~/repos/repo/nested/file.ts"`;
exports[`describeFilePath tsconfigRootDir ./repos/repo filePath A:/file.ts 1`] = `"A:/file.ts"`;
exports[`describeFilePath tsconfigRootDir ./repos/repo filePath A:/nested/file.ts 1`] = `"A:/nested/file.ts"`;
exports[`describeFilePath tsconfigRootDir ./repos/repo filePath ABC:/file.ts 1`] = `"ABC:/file.ts"`;
exports[`describeFilePath tsconfigRootDir ./repos/repo filePath C:/file.ts 1`] = `"C:/file.ts"`;
exports[`describeFilePath tsconfigRootDir ./repos/repo filePath file.ts 1`] = `"file.ts"`;
exports[`describeFilePath tsconfigRootDir ./repos/repo filePath nested/file.ts 1`] = `"nested/file.ts"`;
exports[`describeFilePath tsconfigRootDir /repos/repo filePath ./elsewhere/repo/file.ts 1`] = `"./elsewhere/repo/file.ts"`;
exports[`describeFilePath tsconfigRootDir /repos/repo filePath ./elsewhere/repo/nested/file.ts 1`] = `"./elsewhere/repo/nested/file.ts"`;
exports[`describeFilePath tsconfigRootDir /repos/repo filePath ./repos/file.ts 1`] = `"./repos/file.ts"`;
exports[`describeFilePath tsconfigRootDir /repos/repo filePath ./repos/other/file.ts 1`] = `"./repos/other/file.ts"`;
exports[`describeFilePath tsconfigRootDir /repos/repo filePath ./repos/repo/file.ts 1`] = `"./repos/repo/file.ts"`;
exports[`describeFilePath tsconfigRootDir /repos/repo filePath ./repos/repo/nested/file.ts 1`] = `"./repos/repo/nested/file.ts"`;
exports[`describeFilePath tsconfigRootDir /repos/repo filePath /elsewhere/repo/file.ts 1`] = `"/elsewhere/repo/file.ts"`;
exports[`describeFilePath tsconfigRootDir /repos/repo filePath /elsewhere/repo/nested/file.ts 1`] = `"/elsewhere/repo/nested/file.ts"`;
exports[`describeFilePath tsconfigRootDir /repos/repo filePath /file.ts 1`] = `"/file.ts"`;
exports[`describeFilePath tsconfigRootDir /repos/repo filePath /nested/file.ts 1`] = `"/nested/file.ts"`;
exports[`describeFilePath tsconfigRootDir /repos/repo filePath /repos/repo/file.ts 1`] = `"<tsconfigRootDir>/file.ts"`;
exports[`describeFilePath tsconfigRootDir /repos/repo filePath /repos/repo/nested/file.ts 1`] = `"<tsconfigRootDir>/nested/file.ts"`;
exports[`describeFilePath tsconfigRootDir /repos/repo filePath ~/file.ts 1`] = `"~/file.ts"`;
exports[`describeFilePath tsconfigRootDir /repos/repo filePath ~/nested/file.ts 1`] = `"~/nested/file.ts"`;
exports[`describeFilePath tsconfigRootDir /repos/repo filePath ~/nested/file.ts 2`] = `"~/nested/file.ts"`;
exports[`describeFilePath tsconfigRootDir /repos/repo filePath ~/other/nested/path/to/file.ts 1`] = `"~/other/nested/path/to/file.ts"`;
exports[`describeFilePath tsconfigRootDir /repos/repo filePath ~/other/repo/file.ts 1`] = `"~/other/repo/file.ts"`;
exports[`describeFilePath tsconfigRootDir /repos/repo filePath ~/repos/file.ts 1`] = `"~/repos/file.ts"`;
exports[`describeFilePath tsconfigRootDir /repos/repo filePath ~/repos/other/file.ts 1`] = `"~/repos/other/file.ts"`;
exports[`describeFilePath tsconfigRootDir /repos/repo filePath ~/repos/other/nested/file.ts 1`] = `"~/repos/other/nested/file.ts"`;
exports[`describeFilePath tsconfigRootDir /repos/repo filePath ~/repos/repo/file.ts 1`] = `"~/repos/repo/file.ts"`;
exports[`describeFilePath tsconfigRootDir /repos/repo filePath ~/repos/repo/nested/file.ts 1`] = `"~/repos/repo/nested/file.ts"`;
exports[`describeFilePath tsconfigRootDir /repos/repo filePath A:/file.ts 1`] = `"A:/file.ts"`;
exports[`describeFilePath tsconfigRootDir /repos/repo filePath A:/nested/file.ts 1`] = `"A:/nested/file.ts"`;
exports[`describeFilePath tsconfigRootDir /repos/repo filePath ABC:/file.ts 1`] = `"ABC:/file.ts"`;
exports[`describeFilePath tsconfigRootDir /repos/repo filePath C:/file.ts 1`] = `"C:/file.ts"`;
exports[`describeFilePath tsconfigRootDir /repos/repo filePath file.ts 1`] = `"file.ts"`;
exports[`describeFilePath tsconfigRootDir /repos/repo filePath nested/file.ts 1`] = `"nested/file.ts"`;
exports[`describeFilePath tsconfigRootDir ~/repos/repo filePath ./elsewhere/repo/file.ts 1`] = `"./elsewhere/repo/file.ts"`;
exports[`describeFilePath tsconfigRootDir ~/repos/repo filePath ./elsewhere/repo/nested/file.ts 1`] = `"./elsewhere/repo/nested/file.ts"`;
exports[`describeFilePath tsconfigRootDir ~/repos/repo filePath ./repos/file.ts 1`] = `"./repos/file.ts"`;
exports[`describeFilePath tsconfigRootDir ~/repos/repo filePath ./repos/other/file.ts 1`] = `"./repos/other/file.ts"`;
exports[`describeFilePath tsconfigRootDir ~/repos/repo filePath ./repos/repo/file.ts 1`] = `"./repos/repo/file.ts"`;
exports[`describeFilePath tsconfigRootDir ~/repos/repo filePath ./repos/repo/nested/file.ts 1`] = `"./repos/repo/nested/file.ts"`;
exports[`describeFilePath tsconfigRootDir ~/repos/repo filePath /elsewhere/repo/file.ts 1`] = `"/elsewhere/repo/file.ts"`;
exports[`describeFilePath tsconfigRootDir ~/repos/repo filePath /elsewhere/repo/nested/file.ts 1`] = `"/elsewhere/repo/nested/file.ts"`;
exports[`describeFilePath tsconfigRootDir ~/repos/repo filePath /file.ts 1`] = `"/file.ts"`;
exports[`describeFilePath tsconfigRootDir ~/repos/repo filePath /nested/file.ts 1`] = `"/nested/file.ts"`;
exports[`describeFilePath tsconfigRootDir ~/repos/repo filePath /repos/repo/file.ts 1`] = `"/repos/repo/file.ts"`;
exports[`describeFilePath tsconfigRootDir ~/repos/repo filePath /repos/repo/nested/file.ts 1`] = `"/repos/repo/nested/file.ts"`;
exports[`describeFilePath tsconfigRootDir ~/repos/repo filePath ~/file.ts 1`] = `"~/file.ts"`;
exports[`describeFilePath tsconfigRootDir ~/repos/repo filePath ~/nested/file.ts 1`] = `"~/nested/file.ts"`;
exports[`describeFilePath tsconfigRootDir ~/repos/repo filePath ~/nested/file.ts 2`] = `"~/nested/file.ts"`;
exports[`describeFilePath tsconfigRootDir ~/repos/repo filePath ~/other/nested/path/to/file.ts 1`] = `"~/other/nested/path/to/file.ts"`;
exports[`describeFilePath tsconfigRootDir ~/repos/repo filePath ~/other/repo/file.ts 1`] = `"~/other/repo/file.ts"`;
exports[`describeFilePath tsconfigRootDir ~/repos/repo filePath ~/repos/file.ts 1`] = `"~/repos/file.ts"`;
exports[`describeFilePath tsconfigRootDir ~/repos/repo filePath ~/repos/other/file.ts 1`] = `"~/repos/other/file.ts"`;
exports[`describeFilePath tsconfigRootDir ~/repos/repo filePath ~/repos/other/nested/file.ts 1`] = `"~/repos/other/nested/file.ts"`;
exports[`describeFilePath tsconfigRootDir ~/repos/repo filePath ~/repos/repo/file.ts 1`] = `"<tsconfigRootDir>/file.ts"`;
exports[`describeFilePath tsconfigRootDir ~/repos/repo filePath ~/repos/repo/nested/file.ts 1`] = `"<tsconfigRootDir>/nested/file.ts"`;
exports[`describeFilePath tsconfigRootDir ~/repos/repo filePath A:/file.ts 1`] = `"A:/file.ts"`;
exports[`describeFilePath tsconfigRootDir ~/repos/repo filePath A:/nested/file.ts 1`] = `"A:/nested/file.ts"`;
exports[`describeFilePath tsconfigRootDir ~/repos/repo filePath ABC:/file.ts 1`] = `"ABC:/file.ts"`;
exports[`describeFilePath tsconfigRootDir ~/repos/repo filePath C:/file.ts 1`] = `"C:/file.ts"`;
exports[`describeFilePath tsconfigRootDir ~/repos/repo filePath file.ts 1`] = `"file.ts"`;
exports[`describeFilePath tsconfigRootDir ~/repos/repo filePath nested/file.ts 1`] = `"nested/file.ts"`;
41 changes: 41 additions & 0 deletions packages/typescript-estree/tests/lib/describeFilePath.test.ts
@@ -0,0 +1,41 @@
import { describeFilePath } from '../../src/create-program/describeFilePath';

describe('describeFilePath', () => {
describe.each(['./repos/repo', '/repos/repo', '~/repos/repo'])(
'tsconfigRootDir %s',
tsconfigRootDir => {
test.each([
'./elsewhere/repo/file.ts',
'./elsewhere/repo/nested/file.ts',
'./repos/file.ts',
'./repos/other/file.ts',
'./repos/repo/file.ts',
'./repos/repo/nested/file.ts',
'/elsewhere/repo/file.ts',
'/elsewhere/repo/nested/file.ts',
'/file.ts',
'/nested/file.ts',
'/repos/repo/file.ts',
'/repos/repo/nested/file.ts',
'~/file.ts',
'~/nested/file.ts',
'~/nested/file.ts',
'~/other/nested/path/to/file.ts',
'~/other/repo/file.ts',
'~/repos/file.ts',
'~/repos/other/file.ts',
'~/repos/other/nested/file.ts',
'~/repos/repo/file.ts',
'~/repos/repo/nested/file.ts',
'A:/file.ts',
'A:/nested/file.ts',
'ABC:/file.ts',
'C:/file.ts',
'file.ts',
'nested/file.ts',
])('filePath %s', filePath => {
expect(describeFilePath(filePath, tsconfigRootDir)).toMatchSnapshot();
});
},
);
});

0 comments on commit dc14242

Please sign in to comment.