Skip to content

Commit a864584

Browse files
authored
Add support for TS project not located at the root of the repo. (#45)
* add arg fowarding to call to `tsc --showConfig` * add utility helper to get project path * update util function naming * add project path from args to isFileOnPath * add / update e2e tests * v2.1.0
1 parent 5aeb696 commit a864584

File tree

13 files changed

+179
-5
lines changed

13 files changed

+179
-5
lines changed

CHANGELOG.md

+6
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project
66
adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [2.1.0] - 2022-10-14
9+
10+
### Added
11+
12+
- Support for projects not located at root of repository using `tsc`'s `--project` flag.
13+
814
## [2.0.2] - 2022-07-28
915

1016
### Fixed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
// @ts-strict-ignore
2+
const text: string = null;
3+
4+
export {};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
const text: string = null;
2+
3+
export {};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
"compilerOptions": {
3+
"target": "es2018",
4+
"module": "commonjs",
5+
"lib": ["es2018"],
6+
"baseUrl": "./",
7+
"outDir": "./dist",
8+
"strict": false,
9+
"pretty": true,
10+
"esModuleInterop": true,
11+
"noImplicitAny": true,
12+
"plugins": [
13+
{
14+
"name": "../../dist/plugin"
15+
}
16+
]
17+
}
18+
}

e2e/fixtures/paths.ts

+9
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,12 @@ export const fixtureWithPathConfig = {
1818
excludedWithStrictComment: 'excluded/excludedWithStrictComment.ts',
1919
},
2020
};
21+
22+
export const fixtureWithNonRootConfig = {
23+
projectPath: path.resolve(__dirname, 'non-root-config'),
24+
filePaths: {
25+
strict: 'strict.ts',
26+
ignored: 'ignored.ts',
27+
},
28+
args: ['--project', './nested/tsconfig.json'],
29+
};

e2e/plugin/singleFile.spec.ts

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
import { getDiagnostics } from './utils/getDiagnostics';
2-
import { fixtureWithDefaultConfig, fixtureWithPathConfig } from '../fixtures/paths';
2+
import {
3+
fixtureWithDefaultConfig,
4+
fixtureWithNonRootConfig,
5+
fixtureWithPathConfig,
6+
} from '../fixtures/paths';
37

48
describe('single file diagnostics', () => {
59
it('should enable strict mode by default in project without config', async () => {

e2e/tsc-strict/tsc-strict.spec.ts

+20-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
import execa from 'execa';
22
import { join } from 'path';
3-
import { fixtureWithDefaultConfig, fixtureWithPathConfig } from '../fixtures/paths';
3+
import {
4+
fixtureWithDefaultConfig,
5+
fixtureWithNonRootConfig,
6+
fixtureWithPathConfig,
7+
} from '../fixtures/paths';
48

59
const runInPath = async (
610
path: string,
@@ -67,3 +71,18 @@ it('should enable strict mode with a relative path config', async () => {
6771
expect(stdout).toEqual(expect.stringContaining(filePaths.included));
6872
expect(stdout).toMatch(/error TS2322: Type 'null' is not assignable to type 'string'\./i);
6973
});
74+
75+
it('should enable strict mode with a non-root path config', async () => {
76+
//given
77+
const { projectPath, filePaths, args } = fixtureWithNonRootConfig;
78+
79+
//when
80+
const stdout = await runInPath(projectPath, args);
81+
82+
// then
83+
expect(stdout).toEqual(expect.stringContaining(filePaths.strict));
84+
expect(stdout).not.toEqual(expect.stringContaining(filePaths.ignored));
85+
expect(stdout).toMatch(/error TS2322: Type 'null' is not assignable to type 'string'\./i);
86+
expect(stdout).toMatch(/Found 1 strict file/i);
87+
expect(stdout).toMatch(/Found 1 error/i);
88+
});

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "typescript-strict-plugin",
3-
"version": "2.0.2",
3+
"version": "2.1.0",
44
"description": "Typescript tools that help with migration to the strict mode",
55
"author": "Allegro",
66
"contributors": [

src/cli/typescript/typescript.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import execa, { ExecaError } from 'execa';
22

33
export const showConfig = async (): Promise<string> => {
4-
const output = await execa('tsc', ['--showConfig'], {
4+
const output = await execa('tsc', [...process.argv.slice(2), '--showConfig'], {
55
all: true,
66
preferLocal: true,
77
});
+65
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
import { getProjectPathFromArgs } from '../utils';
2+
import { getAbsolutePath } from '../getAbsolutePath';
3+
import { mocked } from 'jest-mock';
4+
import { isFileOnPath } from '../isFileOnPath';
5+
6+
jest.mock('../utils', () => ({
7+
...jest.requireActual('../utils'),
8+
getProjectPathFromArgs: jest.fn(),
9+
}));
10+
11+
jest.mock('../getAbsolutePath', () => ({
12+
getAbsolutePath: jest.fn(),
13+
}));
14+
15+
const getProjectPathFromArgsMock = mocked(getProjectPathFromArgs);
16+
const getAbsolutePathMock = mocked(getAbsolutePath);
17+
18+
const projectPathFromArgs = './defined_project_path';
19+
20+
describe('isFileOnPath', () => {
21+
beforeEach(() => {
22+
jest.resetAllMocks();
23+
getProjectPathFromArgsMock.mockReturnValue(projectPathFromArgs);
24+
getAbsolutePathMock.mockReturnValue('/some_file_path/lib_dir');
25+
});
26+
27+
it('when projectPath argument used, prefer argument value', () => {
28+
// given
29+
const projectPath = '/some_path';
30+
31+
// when
32+
isFileOnPath({
33+
filePath: '/some_file_path/lib_dir/file.ts',
34+
targetPath: './lib_dir',
35+
projectPath,
36+
});
37+
38+
// then
39+
expect(getAbsolutePathMock).toHaveBeenCalledTimes(1);
40+
expect(getAbsolutePathMock).toHaveBeenCalledWith(projectPath, './lib_dir');
41+
});
42+
43+
it('when getProjectPathFromArgs is defined, use defined value', () => {
44+
//when
45+
isFileOnPath({ filePath: '/some_file_path/lib_dir/file.ts', targetPath: './lib_dir' });
46+
47+
// then
48+
expect(getAbsolutePathMock).toHaveBeenCalledTimes(1);
49+
expect(getAbsolutePathMock).toHaveBeenCalledWith(projectPathFromArgs, './lib_dir');
50+
expect(projectPathFromArgs).not.toEqual(process.cwd());
51+
});
52+
53+
it('when getProjectPathFromArgs is undefined, fallback to current working directory to match', () => {
54+
// given
55+
getProjectPathFromArgsMock.mockReturnValue(undefined);
56+
const cwd = process.cwd();
57+
58+
// when
59+
isFileOnPath({ filePath: '/some_file_path/lib_dir/file.ts', targetPath: './lib_dir' });
60+
61+
// then
62+
expect(getAbsolutePathMock).toHaveBeenCalledTimes(1);
63+
expect(getAbsolutePathMock).toHaveBeenCalledWith(cwd, './lib_dir');
64+
});
65+
});

src/common/__tests__/utils.spec.ts

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import { getProjectPathFromArgs } from '../utils';
2+
3+
let globalProcessArgv: string[];
4+
5+
describe('utils', () => {
6+
describe('getProjectPathFromArgs', () => {
7+
beforeEach(() => {
8+
globalProcessArgv = process.argv;
9+
});
10+
11+
afterEach(() => {
12+
process.argv = globalProcessArgv;
13+
});
14+
15+
it('should return undefined if --project not present in path', () => {
16+
process.argv = [
17+
'/usr/bin/nodejs/18.7.0/bin/node',
18+
'/home/neenjaw/typescript-strict-plugin/node_modules/.bin/update-strict-comments',
19+
];
20+
21+
expect(getProjectPathFromArgs()).toEqual(undefined);
22+
});
23+
24+
it('should return undefined if --project not present in path', () => {
25+
process.argv = [
26+
'/usr/bin/nodejs/18.7.0/bin/node',
27+
'/home/neenjaw/typescript-strict-plugin/node_modules/.bin/update-strict-comments',
28+
'--project',
29+
'./some/inner/project/tsconfig.json',
30+
];
31+
32+
expect(getProjectPathFromArgs()).toEqual('./some/inner/project');
33+
});
34+
});
35+
});

src/common/isFileOnPath.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { getPosixFilePath } from './utils';
22
import { getAbsolutePath } from './getAbsolutePath';
3+
import { getProjectPathFromArgs } from './utils';
34

45
interface IsFileOnPathParams {
56
filePath: string;
@@ -10,7 +11,7 @@ interface IsFileOnPathParams {
1011
export function isFileOnPath({
1112
filePath,
1213
targetPath,
13-
projectPath = process.cwd(),
14+
projectPath = getProjectPathFromArgs() ?? process.cwd(),
1415
}: IsFileOnPathParams): boolean {
1516
const absolutePathToStrictFiles = getAbsolutePath(projectPath, targetPath);
1617

src/common/utils.ts

+10
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,13 @@ export function isFile(path: string) {
1818
return false;
1919
}
2020
}
21+
22+
export function getProjectPathFromArgs(): string | undefined {
23+
const args = process.argv.slice(2);
24+
for (let index = 0; index < args.length; index++) {
25+
const arg = args[index];
26+
if (arg === '--project') {
27+
return path.dirname(args[index + 1]);
28+
}
29+
}
30+
}

0 commit comments

Comments
 (0)