Skip to content

Commit e8ab993

Browse files
committed
Add new tsc command that automatically filters tests
1 parent a09ebf6 commit e8ab993

File tree

62 files changed

+206
-81
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

62 files changed

+206
-81
lines changed

.github/workflows/pages-deploy.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,14 @@ jobs:
2020
- name: Use Node.js 💻
2121
uses: actions/setup-node@v4
2222
with:
23-
node-version: 20
23+
node-version: 22
2424
cache: yarn
2525

2626
- name: Install Dependencies 📦
2727
run: yarn install --immutable
2828

2929
- name: Build Modules 🔧
30-
run: yarn build --tsc --lint
30+
run: yarn workspaces foreach -j 5 -ptW --from "./src/{bundles,tsc}/*" run build --tsc --lint
3131

3232
- name: include java json
3333
run: cp -r src/java build

.github/workflows/pull-request.yml

Lines changed: 8 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ on:
66

77
jobs:
88
paths-filter:
9-
name: Determine which files are changed
9+
name: Determine which files have changed
1010
runs-on: ubuntu-latest
1111
steps:
1212
- name: Check out source code
@@ -19,25 +19,19 @@ jobs:
1919
id: filter
2020
with:
2121
filters: |
22+
workflows:
23+
- .github/workflows/**
2224
devserver:
2325
- 'devserver/**'
2426
libraries:
2527
- 'lib/**'
2628
modules:
2729
- src/{bundles,tabs}/**
28-
29-
- if: steps.filter.outputs.devserver == 'true'
30-
run: echo "Changes detected in devserver"
31-
32-
- if: steps.filter.outputs.libraries == 'true'
33-
run: echo "Changes detected in libraries"
34-
35-
- if: steps.filter.outputs.modules == 'true'
36-
run: echo "Changes detected in modules"
3730
outputs:
38-
devserver: ${{ steps.filter.outputs.devserver }}
39-
modules: ${{ steps.filter.outputs.modules }}
40-
libraries: ${{ steps.filter.outputs.libraries }}
31+
# if the workflow file was modified, then we rerun the entire job
32+
devserver: ${{ steps.filter.outputs.devserver || steps.filter.outputs.workflows }}
33+
modules: ${{ steps.filter.outputs.modules || steps.filter.outputs.workflows }}
34+
libraries: ${{ steps.filter.outputs.libraries || steps.filter.outputs.workflows }}
4135

4236
test:
4337
name: Verify all tests pass and build success
@@ -77,11 +71,7 @@ jobs:
7771

7872
- name: Build, lint and run tsc for bundles and tabs
7973
if: needs.paths-filter.outputs.modules == 'true'
80-
run: yarn workspaces foreach -ptW --from "./src/{bundles,tsc}/*" run build --tsc --lint
81-
82-
- name: Lint bundles and tabs
83-
if: needs.paths-filter.outputs.modules == 'true'
84-
run: yarn lint:modules
74+
run: yarn workspaces foreach -j 5 -ptW --from "./src/{bundles,tsc}/*" run build --tsc --lint
8575

8676
- name: Test bundles and tabs
8777
if: needs.paths-filter.outputs.modules == 'true'

lib/buildtools/src/__test_mocks__/bundles/test0/src/__tests__/test0.test.ts

Whitespace-only changes.
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
{
2-
"include": ["src/index.ts"],
2+
"include": ["src"],
33
"extends": ["../tsconfig.json"]
44
}

lib/buildtools/src/__test_mocks__/bundles/tsconfig.json

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,6 @@
1414
"module": "esnext",
1515
/* Specify the module resolution strategy: 'node' (Node.js) or 'classic' (used in TypeScript before the release of 1.6). */
1616
"moduleResolution": "node",
17-
/* Do not emit compiler output files like JavaScript source code, source-maps or declarations. */
18-
"noEmit": true,
1917
/* Allows importing modules with a ‘.json’ extension, which is a common practice in node projects. */
2018
"resolveJsonModule": true,
2119
/* The longest common path of all non-declaration input files. */

lib/buildtools/src/commands/__tests__/lint.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { ESLint } from 'eslint';
22
import { beforeEach, vi, expect, describe, test } from 'vitest';
33
import * as manifest from '../../build/manifest.js';
44
import * as utils from '../../getGitRoot.js';
5-
import { getLintCommand } from '../lint.js';
5+
import { getLintCommand } from '../prebuild.js';
66
import { getCommandRunner } from './testingUtils.js';
77

88
const lintFilesMock = vi.hoisted(() => vi.fn());
Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { Command } from '@commander-js/extra-typings';
22
import { getBuildCommand } from './build.js';
3-
import { getLintCommand } from './lint.js';
43
import { getListCommand } from './list.js';
4+
import { getLintCommand, getTscCommand } from './prebuild.js';
55
import getTemplateCommand from './template.js';
66
import { getTestCommand } from './testing.js';
77

@@ -10,4 +10,5 @@ export const getMainCommand = () => new Command()
1010
.addCommand(getLintCommand())
1111
.addCommand(getListCommand())
1212
.addCommand(getTemplateCommand())
13-
.addCommand(getTestCommand());
13+
.addCommand(getTestCommand())
14+
.addCommand(getTscCommand());

lib/buildtools/src/commands/lint.ts renamed to lib/buildtools/src/commands/prebuild.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import pathlib from 'path';
77
import { Command } from '@commander-js/extra-typings';
88
import { resolveEitherBundleOrTab } from '../build/manifest.js';
99
import { formatLintResult, runEslint } from '../prebuild/lint.js';
10+
import { formatTscResult, runTsc } from '../prebuild/tsc.js';
1011
import { logCommandErrorAndExit } from './commandUtils.js';
1112

1213
export const getLintCommand = () => new Command('lint')
@@ -34,3 +35,31 @@ export const getLintCommand = () => new Command('lint')
3435
}
3536
}
3637
});
38+
39+
// This command is provided as an augmented way to run tsc, automatically
40+
// filtering out test files
41+
export const getTscCommand = () => new Command('tsc')
42+
.description('Run tsc for the given directory, or the current directory if no directory is specified')
43+
.argument('[directory]', 'Directory to run tsc in', process.cwd())
44+
.option('--no-emit', 'Prevent the typescript compiler from outputting files regardless of the tsconfig setting')
45+
.option('--ci')
46+
.action(async (directory, { emit, ci }) => {
47+
const fullyResolved = pathlib.resolve(directory);
48+
const asset = await resolveEitherBundleOrTab(fullyResolved);
49+
50+
if (!asset) {
51+
logCommandErrorAndExit(`No tab or bundle found at ${fullyResolved}`);
52+
}
53+
54+
const result = await runTsc(asset, !emit);
55+
console.log(formatTscResult(result));
56+
57+
switch (result.severity) {
58+
case 'warn': {
59+
if (!ci) return;
60+
}
61+
case 'error': {
62+
process.exit(1);
63+
}
64+
}
65+
});
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
import ts from 'typescript';
2+
import { describe, expect, test, vi } from 'vitest';
3+
import { testMocksDir } from '../../__tests__/fixtures.js';
4+
import { runTsc } from '../tsc.js';
5+
6+
const mockedWriteFile = vi.hoisted(() => vi.fn<(arg0: string, arg1: string) => void>(() => undefined));
7+
8+
vi.mock(import('typescript'), async importOriginal => {
9+
const { default: original } = await importOriginal();
10+
11+
// @ts-expect-error createProgram has two overloads but we can only really define 1
12+
const createProgram: typeof original.createProgram = vi.fn((opts: ts.CreateProgramOptions) => {
13+
const program = original.createProgram(opts);
14+
const emit: typeof program.emit = (sourceFile, _, cancelToken, emitDts, transformers) => {
15+
return program.emit(sourceFile, mockedWriteFile, cancelToken, emitDts, transformers);
16+
};
17+
18+
return {
19+
...program,
20+
emit
21+
};
22+
});
23+
24+
return {
25+
default: {
26+
...original,
27+
createProgram,
28+
}
29+
};
30+
});
31+
32+
describe('Test the augmented tsc functionality', () => {
33+
test('tsc on a bundle', async () => {
34+
await runTsc({
35+
type: 'bundle',
36+
directory: `${testMocksDir}/bundles/test0`,
37+
name: 'test0',
38+
manifest: {}
39+
}, false);
40+
41+
expect(ts.createProgram).toHaveBeenCalledTimes(2);
42+
expect(mockedWriteFile).toHaveBeenCalledTimes(1);
43+
const [[writePath]] = mockedWriteFile.mock.calls;
44+
45+
expect(writePath).not.toEqual(`${testMocksDir}/bundles/test0/__tests__/test0.test.js`,);
46+
});
47+
48+
test('tsc on a bundle with --noEmit', async () => {
49+
await runTsc({
50+
type: 'bundle',
51+
directory: `${testMocksDir}/bundles/test0`,
52+
name: 'test0',
53+
manifest: {}
54+
}, true);
55+
56+
expect(ts.createProgram).toHaveBeenCalledTimes(1);
57+
expect(mockedWriteFile).not.toBeCalled();
58+
});
59+
60+
test('tsc on a bundle with noEmit in its tsconfig', async () => {
61+
const originalTs: typeof ts = await vi.importActual('typescript');
62+
63+
vi.spyOn(ts, 'parseJsonConfigFileContent').mockImplementationOnce((...args) => {
64+
const rawResult = originalTs.parseJsonConfigFileContent(...args);
65+
rawResult.options.noEmit = true;
66+
return rawResult;
67+
});
68+
69+
await runTsc({
70+
type: 'bundle',
71+
directory: `${testMocksDir}/bundles/test0`,
72+
name: 'test0',
73+
manifest: {}
74+
}, false);
75+
76+
expect(ts.createProgram).toHaveBeenCalledTimes(1);
77+
expect(mockedWriteFile).not.toBeCalled();
78+
});
79+
80+
test('tsc on a tab', async () => {
81+
await runTsc({
82+
type: 'tab',
83+
directory: `${testMocksDir}/tabs/tab0`,
84+
entryPoint: `${testMocksDir}/tabs/tab0/src/index.tsx`,
85+
name: 'tab0'
86+
}, false);
87+
88+
expect(ts.createProgram).toHaveBeenCalledTimes(1);
89+
expect(mockedWriteFile).not.toBeCalled();
90+
});
91+
});

lib/buildtools/src/prebuild/tsc.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ async function getTsconfig(srcDir: string): Promise<TsconfigResult> {
6868
export const {
6969
builder: runTsc,
7070
formatter: formatTscResult
71-
} = createPrebuilder<TscResult>(async input => {
71+
} = createPrebuilder<TscResult, [noEmit: boolean]>(async (input, noEmit) => {
7272
const tsconfigRes = await getTsconfig(input.directory);
7373
if (tsconfigRes.severity === 'error') {
7474
return {
@@ -101,7 +101,8 @@ export const {
101101
}
102102
});
103103

104-
if (severity !== 'error' && !tsconfig.noEmit) {
104+
noEmit = tsconfig.noEmit ?? noEmit;
105+
if (severity !== 'error' && !noEmit ) {
105106
// If noEmit isn't specified, then run tsc again without including test
106107
// files and actually output the files
107108
const filesWithoutTests = fileNames.filter(p => {

0 commit comments

Comments
 (0)