@servicetitan/startup 29.0.0 → 30.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/index.js +1 -1
- package/dist/cli/commands/convert-eslint-config.d.ts +21 -0
- package/dist/cli/commands/convert-eslint-config.d.ts.map +1 -0
- package/dist/cli/commands/convert-eslint-config.js +235 -0
- package/dist/cli/commands/convert-eslint-config.js.map +1 -0
- package/dist/cli/commands/get-command.d.ts.map +1 -1
- package/dist/cli/commands/get-command.js +6 -0
- package/dist/cli/commands/get-command.js.map +1 -1
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/init.js +4 -3
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/cli/commands/lint.d.ts +1 -1
- package/dist/cli/commands/lint.js +2 -2
- package/dist/cli/commands/run-task.d.ts +13 -0
- package/dist/cli/commands/run-task.d.ts.map +1 -0
- package/dist/cli/commands/run-task.js +53 -0
- package/dist/cli/commands/run-task.js.map +1 -0
- package/dist/cli/index.js +13 -4
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/tasks/cli-task.d.ts +16 -0
- package/dist/cli/tasks/cli-task.d.ts.map +1 -0
- package/dist/cli/tasks/cli-task.js +58 -0
- package/dist/cli/tasks/cli-task.js.map +1 -0
- package/dist/cli/tasks/swc-compile-package.d.ts +12 -0
- package/dist/cli/tasks/swc-compile-package.d.ts.map +1 -0
- package/dist/cli/tasks/swc-compile-package.js +66 -0
- package/dist/cli/tasks/swc-compile-package.js.map +1 -0
- package/dist/cli/tasks/task.d.ts +42 -0
- package/dist/cli/tasks/task.d.ts.map +1 -0
- package/dist/cli/tasks/task.js +113 -0
- package/dist/cli/tasks/task.js.map +1 -0
- package/dist/cli/tasks/tsc-compile-package.d.ts +12 -0
- package/dist/cli/tasks/tsc-compile-package.d.ts.map +1 -0
- package/dist/cli/tasks/tsc-compile-package.js +42 -0
- package/dist/cli/tasks/tsc-compile-package.js.map +1 -0
- package/dist/cli/tasks/tsc-compile.d.ts +16 -0
- package/dist/cli/tasks/tsc-compile.d.ts.map +1 -0
- package/dist/cli/tasks/tsc-compile.js +48 -0
- package/dist/cli/tasks/tsc-compile.js.map +1 -0
- package/dist/cli/utils/bundle.js +1 -1
- package/dist/cli/utils/bundle.js.map +1 -1
- package/dist/cli/utils/cli-os.js +2 -2
- package/dist/cli/utils/cli-os.js.map +1 -1
- package/dist/cli/utils/eslint.d.ts.map +1 -1
- package/dist/cli/utils/eslint.js +13 -12
- package/dist/cli/utils/eslint.js.map +1 -1
- package/dist/cli/utils/is-module-installed.js +1 -1
- package/dist/cli/utils/is-module-installed.js.map +1 -1
- package/dist/cli/utils/tsc.d.ts +3 -2
- package/dist/cli/utils/tsc.d.ts.map +1 -1
- package/dist/cli/utils/tsc.js +20 -16
- package/dist/cli/utils/tsc.js.map +1 -1
- package/dist/utils/get-configuration.d.ts +3 -1
- package/dist/utils/get-configuration.d.ts.map +1 -1
- package/dist/utils/get-configuration.js +2 -0
- package/dist/utils/get-configuration.js.map +1 -1
- package/dist/utils/get-destination-folders.d.ts.map +1 -1
- package/dist/utils/get-destination-folders.js +9 -13
- package/dist/utils/get-destination-folders.js.map +1 -1
- package/dist/utils/get-folders.js +2 -2
- package/dist/utils/get-folders.js.map +1 -1
- package/dist/utils/log.d.ts +1 -0
- package/dist/utils/log.d.ts.map +1 -1
- package/dist/utils/log.js +3 -0
- package/dist/utils/log.js.map +1 -1
- package/dist/webpack/configs/plugins/assets-manifest-plugin.d.ts +1 -1
- package/dist/webpack/configs/plugins/assets-manifest-plugin.d.ts.map +1 -1
- package/dist/webpack/configs/plugins/assets-manifest-plugin.js +4 -6
- package/dist/webpack/configs/plugins/assets-manifest-plugin.js.map +1 -1
- package/dist/webpack/configs/plugins/ignore-plugin/check-resource.js +1 -1
- package/dist/webpack/configs/plugins/ignore-plugin/check-resource.js.map +1 -1
- package/dist/webpack/configs/plugins/moment-locales-plugin.d.ts +1 -2
- package/dist/webpack/configs/plugins/moment-locales-plugin.d.ts.map +1 -1
- package/dist/webpack/configs/plugins/moment-locales-plugin.js +13 -7
- package/dist/webpack/configs/plugins/moment-locales-plugin.js.map +1 -1
- package/dist/webpack/utils/testing/normalize-errors.d.ts +1 -2
- package/dist/webpack/utils/testing/normalize-errors.d.ts.map +1 -1
- package/dist/webpack/utils/testing/normalize-errors.js.map +1 -1
- package/package.json +34 -21
- package/src/cli/commands/__tests__/convert-eslint-config.test.ts +455 -0
- package/src/cli/commands/__tests__/lint.test.ts +2 -2
- package/src/cli/commands/convert-eslint-config.ts +289 -0
- package/src/cli/commands/get-command.ts +6 -0
- package/src/cli/commands/init.ts +4 -3
- package/src/cli/commands/lint.ts +3 -3
- package/src/cli/commands/run-task.ts +41 -0
- package/src/cli/index.ts +16 -4
- package/src/cli/tasks/__tests__/cli-task.test.ts +115 -0
- package/src/cli/tasks/__tests__/swc-compile.test.ts +192 -0
- package/src/cli/tasks/__tests__/task.test.ts +88 -0
- package/src/cli/tasks/__tests__/tsc-compile-package.test.ts +72 -0
- package/src/cli/tasks/__tests__/tsc-compile.test.ts +156 -0
- package/src/cli/tasks/cli-task.ts +64 -0
- package/src/cli/tasks/swc-cli.d.ts +3 -0
- package/src/cli/tasks/swc-compile-package.ts +70 -0
- package/src/cli/tasks/task.ts +112 -0
- package/src/cli/tasks/tsc-compile-package.ts +47 -0
- package/src/cli/tasks/tsc-compile.ts +64 -0
- package/src/cli/utils/__tests__/assets-copy.test.ts +1 -1
- package/src/cli/utils/__tests__/bundle.test.ts +6 -1
- package/src/cli/utils/__tests__/cli-os.test.ts +2 -2
- package/src/cli/utils/__tests__/eslint.test.ts +37 -8
- package/src/cli/utils/__tests__/styles-copy.test.ts +1 -1
- package/src/cli/utils/__tests__/tsc.test.ts +34 -55
- package/src/cli/utils/bundle.ts +1 -1
- package/src/cli/utils/cli-os.ts +2 -2
- package/src/cli/utils/eslint.ts +16 -13
- package/src/cli/utils/is-module-installed.ts +1 -1
- package/src/cli/utils/tsc.ts +25 -20
- package/src/utils/__tests__/get-destination-folders.test.ts +1 -1
- package/src/utils/__tests__/get-folders.test.ts +6 -18
- package/src/utils/__tests__/log.test.ts +6 -0
- package/src/utils/get-configuration.ts +2 -0
- package/src/utils/get-destination-folders.ts +11 -17
- package/src/utils/get-folders.ts +2 -2
- package/src/utils/log.ts +4 -0
- package/src/webpack/__tests__/create-webpack-config-web-component.test.ts +2 -2
- package/src/webpack/__tests__/create-webpack-config.test.ts +1 -1
- package/src/webpack/configs/plugins/assets-manifest-plugin.ts +3 -2
- package/src/webpack/configs/plugins/ignore-plugin/check-resource.ts +1 -1
- package/src/webpack/configs/plugins/moment-locales-plugin.ts +17 -4
- package/src/webpack/utils/testing/normalize-errors.ts +1 -3
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { log, readJsonSafe } from '../../utils';
|
|
2
|
+
|
|
3
|
+
class TaskTimer {
|
|
4
|
+
private counter = 0;
|
|
5
|
+
|
|
6
|
+
private get currentMarkName() {
|
|
7
|
+
return `${this.name}[${this.counter}]`;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
private get currentMarkList() {
|
|
11
|
+
return globalThis.performance.getEntriesByName(this.currentMarkName, 'mark');
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
constructor(private readonly name: string) {
|
|
15
|
+
this.start();
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
start() {
|
|
19
|
+
if (this.currentMarkList.length > 0) {
|
|
20
|
+
this.cancel();
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
globalThis.performance.mark(this.currentMarkName);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
end() {
|
|
27
|
+
if (this.currentMarkList.length === 0) {
|
|
28
|
+
throw new Error(`There are no tasks in progress for ${this.currentMarkName}`);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const measure = globalThis.performance.measure(this.currentMarkName, this.currentMarkName);
|
|
32
|
+
return { measure, counter: this.counter++ };
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
cancel() {
|
|
36
|
+
if (this.currentMarkList.length === 0) {
|
|
37
|
+
throw new Error(`There are no tasks in progress for ${this.currentMarkName}`);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const measure = globalThis.performance.measure(this.currentMarkName, {
|
|
41
|
+
start: this.currentMarkName,
|
|
42
|
+
detail: {
|
|
43
|
+
status: 'cancelled',
|
|
44
|
+
},
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
return { measure, counter: this.counter++ };
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
add(duration: number) {
|
|
51
|
+
const measure = globalThis.performance.measure(this.currentMarkName, {
|
|
52
|
+
duration,
|
|
53
|
+
end: globalThis.performance.now(),
|
|
54
|
+
});
|
|
55
|
+
return { measure, counter: this.counter++ };
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export interface TaskParameters {
|
|
60
|
+
name: string;
|
|
61
|
+
watch?: boolean;
|
|
62
|
+
global: boolean;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export abstract class Task {
|
|
66
|
+
protected readonly watch: boolean;
|
|
67
|
+
protected readonly taskTimer: TaskTimer;
|
|
68
|
+
private readonly name: string;
|
|
69
|
+
private readonly global: boolean;
|
|
70
|
+
|
|
71
|
+
constructor({ name, watch, global }: TaskParameters) {
|
|
72
|
+
this.name = name;
|
|
73
|
+
this.watch = !!watch;
|
|
74
|
+
this.global = global;
|
|
75
|
+
this.taskTimer = new TaskTimer(name);
|
|
76
|
+
this.checkRunLocation();
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
protected logCompletionResults({
|
|
80
|
+
measure,
|
|
81
|
+
counter,
|
|
82
|
+
}: {
|
|
83
|
+
measure: PerformanceMeasure;
|
|
84
|
+
counter: number;
|
|
85
|
+
}) {
|
|
86
|
+
const enumerator = counter === 0 ? 'Initial ' : 'Subsequent ';
|
|
87
|
+
log.info(
|
|
88
|
+
`${this.watch ? enumerator : ''}${this.name} task completed in ${this.formatDuration(measure.duration)}`
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
private formatDuration(duration: number) {
|
|
93
|
+
if (duration < 1000) {
|
|
94
|
+
return `${duration.toFixed(0)}ms`;
|
|
95
|
+
}
|
|
96
|
+
return `${(duration / 1000).toFixed(2)}s`;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
private checkRunLocation() {
|
|
100
|
+
const packageJson = readJsonSafe('package.json');
|
|
101
|
+
if (!packageJson?.workspaces && this.global) {
|
|
102
|
+
throw new Error(`Task ${this.name} has to run inside the workspace root directory`);
|
|
103
|
+
}
|
|
104
|
+
if ((!packageJson || packageJson.workspaces) && !this.global) {
|
|
105
|
+
throw new Error(`Task ${this.name} has to run inside the package directory`);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
abstract description(): string;
|
|
110
|
+
|
|
111
|
+
abstract execute(): Promise<void>;
|
|
112
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { CliTask } from './cli-task';
|
|
2
|
+
import { getTsConfig } from '../../utils';
|
|
3
|
+
interface Args {
|
|
4
|
+
[key: string]: unknown;
|
|
5
|
+
watch?: boolean;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export class TscCompilePackage extends CliTask {
|
|
9
|
+
constructor({ watch }: Args) {
|
|
10
|
+
super({
|
|
11
|
+
name: 'tsc-compile-package',
|
|
12
|
+
global: false,
|
|
13
|
+
indicators: {
|
|
14
|
+
end: 'Watching for file changes.',
|
|
15
|
+
watchStart: 'Starting incremental compilation.',
|
|
16
|
+
},
|
|
17
|
+
watch,
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
description() {
|
|
22
|
+
return 'Compiles TypeScript files to JavaScript with TSC within package folder';
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
async execute() {
|
|
26
|
+
const tsConfig = getTsConfig();
|
|
27
|
+
await this.runChildProcess(
|
|
28
|
+
'tsc',
|
|
29
|
+
[
|
|
30
|
+
this.watch ? '-w' : undefined,
|
|
31
|
+
'--pretty',
|
|
32
|
+
'--preserveWatchOutput',
|
|
33
|
+
'--noCheck',
|
|
34
|
+
'--composite',
|
|
35
|
+
'false',
|
|
36
|
+
'--declaration',
|
|
37
|
+
'false',
|
|
38
|
+
'--declarationMap',
|
|
39
|
+
'false',
|
|
40
|
+
'--tsBuildInfoFile',
|
|
41
|
+
'tsconfig.compile.tsbuildinfo',
|
|
42
|
+
'--project',
|
|
43
|
+
tsConfig,
|
|
44
|
+
].filter(i => i !== undefined)
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getPackages,
|
|
3
|
+
getPackagesGraph,
|
|
4
|
+
getTsConfig,
|
|
5
|
+
Package,
|
|
6
|
+
PackageType,
|
|
7
|
+
splitPackagesByType,
|
|
8
|
+
} from '../../utils';
|
|
9
|
+
import { CliTask } from './cli-task';
|
|
10
|
+
|
|
11
|
+
interface Args {
|
|
12
|
+
[key: string]: unknown;
|
|
13
|
+
ignore?: string | string[];
|
|
14
|
+
scope?: string | string[];
|
|
15
|
+
watch?: boolean;
|
|
16
|
+
typeCheckOnly?: boolean;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export class TscCompile extends CliTask {
|
|
20
|
+
constructor(private readonly args: Args) {
|
|
21
|
+
super({
|
|
22
|
+
name: 'tsc-compile',
|
|
23
|
+
watch: args.watch,
|
|
24
|
+
global: true,
|
|
25
|
+
indicators: {
|
|
26
|
+
end: 'Watching for file changes.',
|
|
27
|
+
watchStart: 'Starting incremental compilation.',
|
|
28
|
+
},
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
description() {
|
|
33
|
+
return 'Compiles one or more TypeScript projects with optional type checking';
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
async execute() {
|
|
37
|
+
const packages = splitPackagesByType(
|
|
38
|
+
getPackages({ scope: this.args.scope, ignore: this.args.ignore })
|
|
39
|
+
)[PackageType.TSC];
|
|
40
|
+
const tsConfigs = collapsePackages(packages).map(({ location }) => getTsConfig(location));
|
|
41
|
+
await this.runChildProcess(
|
|
42
|
+
'tsc',
|
|
43
|
+
[
|
|
44
|
+
'-b',
|
|
45
|
+
this.watch ? '-w' : undefined,
|
|
46
|
+
'--pretty',
|
|
47
|
+
'--preserveWatchOutput',
|
|
48
|
+
this.args.typeCheckOnly ? '--emitDeclarationOnly' : undefined,
|
|
49
|
+
...tsConfigs,
|
|
50
|
+
].filter(i => i !== undefined)
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Exclude dependant packages as they will be built through project references
|
|
57
|
+
*/
|
|
58
|
+
function collapsePackages(packages: Package[]) {
|
|
59
|
+
const dependencies = new Set(
|
|
60
|
+
Object.values(getPackagesGraph({ scope: packages.map(({ name }) => name) })).flat()
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
return packages.filter(({ name }) => !dependencies.has(name));
|
|
64
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { fs, vol } from 'memfs';
|
|
2
2
|
import path from 'path';
|
|
3
|
+
import { getPortPromise } from 'portfinder';
|
|
3
4
|
import webpack from 'webpack';
|
|
4
5
|
import WebpackDevServer from 'webpack-dev-server';
|
|
5
6
|
import {
|
|
@@ -19,6 +20,7 @@ import {
|
|
|
19
20
|
} from '../bundle';
|
|
20
21
|
|
|
21
22
|
jest.mock('fs', () => fs);
|
|
23
|
+
jest.mock('portfinder');
|
|
22
24
|
jest.mock('webpack', () => jest.fn());
|
|
23
25
|
jest.mock('webpack-dev-server');
|
|
24
26
|
jest.mock('../../../utils', () => ({
|
|
@@ -39,6 +41,9 @@ describe('[startup] Cli Utils', () => {
|
|
|
39
41
|
jest.resetAllMocks();
|
|
40
42
|
jest.mocked(createWebpackConfig).mockReturnValue(createWebpackResult);
|
|
41
43
|
jest.mocked(webpack).mockImplementation((): any => compiler);
|
|
44
|
+
jest.mocked(getPortPromise).mockImplementation(options =>
|
|
45
|
+
Promise.resolve(options?.port ?? 0)
|
|
46
|
+
);
|
|
42
47
|
compiler = { close: jest.fn(callback => callback(null)) };
|
|
43
48
|
});
|
|
44
49
|
|
|
@@ -106,7 +111,7 @@ describe('[startup] Cli Utils', () => {
|
|
|
106
111
|
|
|
107
112
|
test('returns errors', () => {
|
|
108
113
|
const toStringSpy = jest.spyOn(stats, 'toString');
|
|
109
|
-
expect(subject).rejects.
|
|
114
|
+
expect(subject).rejects.toThrow(stats.toString());
|
|
110
115
|
expect(toStringSpy).toHaveBeenCalledWith('errors-only');
|
|
111
116
|
});
|
|
112
117
|
});
|
|
@@ -57,13 +57,13 @@ describe('[startup] Cli Utils (OS)', () => {
|
|
|
57
57
|
beforeEach(() => (exitCode = 2));
|
|
58
58
|
|
|
59
59
|
test('rejects promise', () => {
|
|
60
|
-
expect(subject('foo')).rejects.
|
|
60
|
+
expect(subject('foo')).rejects.toThrow(`command exited with code: ${exitCode}`);
|
|
61
61
|
});
|
|
62
62
|
});
|
|
63
63
|
|
|
64
64
|
['', [], ['']].forEach(command =>
|
|
65
65
|
test(`rejects promise when called with ${JSON.stringify(command)}`, () => {
|
|
66
|
-
expect(subject(command)).rejects.
|
|
66
|
+
expect(subject(command)).rejects.toThrow('invalid command');
|
|
67
67
|
})
|
|
68
68
|
);
|
|
69
69
|
|
|
@@ -2,11 +2,12 @@ import { fs, vol } from 'memfs';
|
|
|
2
2
|
import { ESLint } from 'eslint';
|
|
3
3
|
|
|
4
4
|
import { eslint } from '../eslint';
|
|
5
|
+
import { getDestinationFolders } from '../../../utils/get-destination-folders';
|
|
5
6
|
|
|
6
7
|
jest.mock('fs', () => fs);
|
|
7
8
|
jest.mock('eslint');
|
|
8
9
|
jest.mock('../../../utils/get-destination-folders', () => ({
|
|
9
|
-
getDestinationFolders: ()
|
|
10
|
+
getDestinationFolders: jest.fn(),
|
|
10
11
|
}));
|
|
11
12
|
|
|
12
13
|
describe(`[startup] utils:${eslint.name}`, () => {
|
|
@@ -37,19 +38,30 @@ describe(`[startup] utils:${eslint.name}`, () => {
|
|
|
37
38
|
eslintArgs = { paths: ['foo', 'bar'] };
|
|
38
39
|
eslintResults = [mockResult];
|
|
39
40
|
eslintErrors = [];
|
|
41
|
+
jest.mocked(getDestinationFolders).mockReturnValue([]);
|
|
40
42
|
});
|
|
41
43
|
|
|
42
44
|
const subject = async () => eslint(eslintArgs);
|
|
43
45
|
|
|
44
|
-
test('
|
|
46
|
+
test.each(['.vscode/', '**/.yalc/', '**/*.css.d.ts', '**/*.scss.d.ts', '**/*.less.d.ts'])(
|
|
47
|
+
'ignores %s',
|
|
48
|
+
async pattern => {
|
|
49
|
+
await subject();
|
|
50
|
+
|
|
51
|
+
const ignorePatterns = jest.mocked(ESLint).mock.calls[0][0]?.ignorePatterns;
|
|
52
|
+
expect(ignorePatterns).toContain(pattern);
|
|
53
|
+
}
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
test('ignores output folders', async () => {
|
|
57
|
+
const outputFolders = ['../foo/out/', 'dist/', 'packages/bar/out/', 'packages/foo/dist/'];
|
|
58
|
+
|
|
59
|
+
jest.mocked(getDestinationFolders).mockReturnValue(outputFolders);
|
|
60
|
+
|
|
45
61
|
await subject();
|
|
46
62
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
extensions: ['.ts', '.tsx'],
|
|
50
|
-
})
|
|
51
|
-
);
|
|
52
|
-
expect(mockESLint.lintFiles).toHaveBeenCalledWith(eslintArgs.paths);
|
|
63
|
+
const ignorePatterns = jest.mocked(ESLint).mock.calls[0][0]?.ignorePatterns;
|
|
64
|
+
outputFolders.forEach(dir => expect(ignorePatterns).toContain(dir));
|
|
53
65
|
});
|
|
54
66
|
|
|
55
67
|
describe('when instructed to fix issues', () => {
|
|
@@ -58,6 +70,7 @@ describe(`[startup] utils:${eslint.name}`, () => {
|
|
|
58
70
|
test('applies fixes', async () => {
|
|
59
71
|
await subject();
|
|
60
72
|
|
|
73
|
+
expect(ESLint).toHaveBeenCalledWith(expect.objectContaining({ fix: true }));
|
|
61
74
|
expect(ESLint.outputFixes).toHaveBeenCalledWith(eslintResults);
|
|
62
75
|
});
|
|
63
76
|
});
|
|
@@ -99,4 +112,20 @@ describe(`[startup] utils:${eslint.name}`, () => {
|
|
|
99
112
|
expect(mockESLint.lintFiles).not.toHaveBeenCalled();
|
|
100
113
|
});
|
|
101
114
|
});
|
|
115
|
+
|
|
116
|
+
describe('with custom ESLint config', () => {
|
|
117
|
+
const eslintConfig: any = { foo: 'bar' };
|
|
118
|
+
|
|
119
|
+
const config = JSON.stringify({
|
|
120
|
+
cli: { lint: { eslint: { ...eslintConfig } } },
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
beforeEach(() => vol.fromJSON({ 'package.json': config }));
|
|
124
|
+
|
|
125
|
+
test('passes through custom config', async () => {
|
|
126
|
+
await subject();
|
|
127
|
+
|
|
128
|
+
expect(ESLint).toHaveBeenCalledWith(expect.objectContaining(eslintConfig));
|
|
129
|
+
});
|
|
130
|
+
});
|
|
102
131
|
});
|
|
@@ -1,84 +1,63 @@
|
|
|
1
1
|
import execa from 'execa';
|
|
2
|
-
import {
|
|
3
|
-
import { Package, getPackagesGraph, getTsConfig } from '../../../utils';
|
|
4
|
-
import { createPackage } from '../../../__mocks__';
|
|
2
|
+
import { lernaExec } from '../lerna-exec';
|
|
5
3
|
|
|
6
4
|
import { tsc, tscWatch } from '../tsc';
|
|
5
|
+
import { createPackage } from '../../../__mocks__';
|
|
7
6
|
|
|
8
|
-
jest.mock('fs', () => fs);
|
|
9
7
|
jest.mock('execa', () => jest.fn());
|
|
10
|
-
jest.mock('
|
|
11
|
-
|
|
12
|
-
log: { info: jest.fn(), debug: jest.fn() }, // suppress test output
|
|
13
|
-
getPackagesGraph: jest.fn(),
|
|
8
|
+
jest.mock('../lerna-exec', () => ({
|
|
9
|
+
lernaExec: jest.fn(),
|
|
14
10
|
}));
|
|
15
11
|
|
|
16
12
|
describe('[startup] Cli Utils', () => {
|
|
17
|
-
|
|
13
|
+
const packages = ['foo', 'bar'].map(name => createPackage({ name }));
|
|
18
14
|
|
|
19
15
|
beforeEach(() => {
|
|
20
|
-
jest.
|
|
21
|
-
jest.mocked(getPackagesGraph).mockReturnValue({});
|
|
22
|
-
packages = [
|
|
23
|
-
createPackage({ name: 'foo', location: 'packages/foo' }),
|
|
24
|
-
createPackage({ name: 'bar', location: 'packages/bar' }),
|
|
25
|
-
];
|
|
26
|
-
vol.fromJSON({
|
|
27
|
-
'packages/foo/tsconfig.json': JSON.stringify({}),
|
|
28
|
-
'packages/bar/tsconfig.json': JSON.stringify({}),
|
|
29
|
-
});
|
|
16
|
+
jest.clearAllMocks();
|
|
30
17
|
});
|
|
31
18
|
|
|
32
|
-
|
|
19
|
+
function itRunsTscCompile(watch = false, typeCheckOnly = false) {
|
|
20
|
+
expect(execa).toHaveBeenCalledWith(
|
|
21
|
+
'startup',
|
|
22
|
+
[
|
|
23
|
+
'task',
|
|
24
|
+
'tsc-compile',
|
|
25
|
+
...packages.map(({ name }) => `--scope=${name}`),
|
|
26
|
+
watch ? '--watch' : undefined,
|
|
27
|
+
typeCheckOnly ? '--type-check-only' : undefined,
|
|
28
|
+
].filter(i => i !== undefined),
|
|
29
|
+
{ stdio: 'inherit' }
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function itRunsTscCompilePackage(watch = false) {
|
|
34
|
+
expect(lernaExec).toHaveBeenCalledWith({
|
|
35
|
+
cmd: 'startup task tsc-compile-package',
|
|
36
|
+
scope: packages.map(({ name }) => name),
|
|
37
|
+
parallel: true,
|
|
38
|
+
stream: true,
|
|
39
|
+
...(watch ? { '--': ['--watch'] } : {}),
|
|
40
|
+
});
|
|
41
|
+
}
|
|
33
42
|
|
|
34
43
|
describe(`${tsc.name}`, () => {
|
|
35
44
|
const subject = async () => tsc(packages);
|
|
36
45
|
|
|
37
|
-
test('
|
|
46
|
+
test('compiles and type checks packages', async () => {
|
|
38
47
|
await subject();
|
|
39
48
|
|
|
40
|
-
|
|
41
|
-
'tsc',
|
|
42
|
-
['-b', ...packages.map(({ location }) => getTsConfig(location))],
|
|
43
|
-
{ stdio: 'inherit' }
|
|
44
|
-
);
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
describe('when package is dependency of another', () => {
|
|
48
|
-
beforeEach(() => {
|
|
49
|
-
jest.mocked(getPackagesGraph).mockReturnValue({
|
|
50
|
-
[packages[0].name]: [packages[1].name], // packages[0] depends on packages[1]
|
|
51
|
-
});
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
test('transpiles only parent packages', async () => {
|
|
55
|
-
await subject();
|
|
56
|
-
|
|
57
|
-
expect(execa).toHaveBeenCalledWith(
|
|
58
|
-
expect.anything(),
|
|
59
|
-
['-b', getTsConfig(packages[0].location)],
|
|
60
|
-
expect.anything()
|
|
61
|
-
);
|
|
62
|
-
});
|
|
49
|
+
itRunsTscCompile();
|
|
63
50
|
});
|
|
64
51
|
});
|
|
65
52
|
|
|
66
53
|
describe(`${tscWatch.name}`, () => {
|
|
67
54
|
const subject = async () => tscWatch(packages);
|
|
68
55
|
|
|
69
|
-
test('
|
|
56
|
+
test('compiles and type checks packages in watch mode', async () => {
|
|
70
57
|
await subject();
|
|
71
58
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
[
|
|
75
|
-
'-b',
|
|
76
|
-
'-w',
|
|
77
|
-
'--preserveWatchOutput',
|
|
78
|
-
...packages.map(({ location }) => getTsConfig(location)),
|
|
79
|
-
],
|
|
80
|
-
{ stdio: 'inherit' }
|
|
81
|
-
);
|
|
59
|
+
itRunsTscCompilePackage(true);
|
|
60
|
+
itRunsTscCompile(true, true);
|
|
82
61
|
});
|
|
83
62
|
});
|
|
84
63
|
});
|
package/src/cli/utils/bundle.ts
CHANGED
package/src/cli/utils/cli-os.ts
CHANGED
|
@@ -25,7 +25,7 @@ export const runCommand = (
|
|
|
25
25
|
const commandName = commandArray.shift();
|
|
26
26
|
|
|
27
27
|
if (!commandName) {
|
|
28
|
-
reject();
|
|
28
|
+
reject(new Error('invalid command'));
|
|
29
29
|
|
|
30
30
|
return;
|
|
31
31
|
}
|
|
@@ -48,7 +48,7 @@ export const runCommand = (
|
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
if (code) {
|
|
51
|
-
reject();
|
|
51
|
+
reject(new Error(`command exited with code: ${code}`));
|
|
52
52
|
} else {
|
|
53
53
|
resolve();
|
|
54
54
|
}
|
package/src/cli/utils/eslint.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ESLint } from 'eslint';
|
|
2
2
|
|
|
3
|
-
import { getDestinationFolders, getESLintConfiguration } from '../../utils';
|
|
3
|
+
import { getDestinationFolders, getESLintConfiguration, log } from '../../utils';
|
|
4
4
|
|
|
5
5
|
interface Args {
|
|
6
6
|
fix?: boolean;
|
|
@@ -14,21 +14,24 @@ export async function eslint({ fix, paths }: Args) {
|
|
|
14
14
|
return;
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
const
|
|
17
|
+
const options: ESLint.Options = {
|
|
18
18
|
errorOnUnmatchedPattern: false,
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
},
|
|
19
|
+
ignorePatterns: [
|
|
20
|
+
// **/node_modules/ is excluded by default
|
|
21
|
+
'.vscode/',
|
|
22
|
+
'**/.yalc/',
|
|
23
|
+
'**/*.css.d.ts',
|
|
24
|
+
'**/*.scss.d.ts',
|
|
25
|
+
'**/*.less.d.ts',
|
|
26
|
+
...getDestinationFolders(),
|
|
27
|
+
],
|
|
29
28
|
fix,
|
|
30
29
|
...config,
|
|
31
|
-
}
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
log.debug('eslint-options', () => JSON.stringify(options, null, 2));
|
|
33
|
+
|
|
34
|
+
const eslint = new ESLint(options);
|
|
32
35
|
|
|
33
36
|
let files = paths;
|
|
34
37
|
if (files.length === 0) {
|
package/src/cli/utils/tsc.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import execa from 'execa';
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import { log, Package } from '../../utils';
|
|
4
|
+
import { lernaExec } from './lerna-exec';
|
|
4
5
|
|
|
5
6
|
export function tsc(packages: Package[]) {
|
|
6
7
|
log.info('Building TypeScript files...');
|
|
@@ -8,26 +9,30 @@ export function tsc(packages: Package[]) {
|
|
|
8
9
|
}
|
|
9
10
|
|
|
10
11
|
export function tscWatch(packages: Package[]) {
|
|
11
|
-
return transpile(packages,
|
|
12
|
+
return transpile(packages, true);
|
|
12
13
|
}
|
|
13
14
|
|
|
14
|
-
async function transpile(packages: Package[],
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
15
|
+
async function transpile(packages: Package[], watch = false) {
|
|
16
|
+
const packageNames = packages.map(({ name }) => name);
|
|
17
|
+
const packageScopes = packageNames.map(name => `--scope=${name}`);
|
|
18
|
+
if (watch) {
|
|
19
|
+
return Promise.all([
|
|
20
|
+
lernaExec({
|
|
21
|
+
'cmd': 'startup task tsc-compile-package',
|
|
22
|
+
'scope': packageNames,
|
|
23
|
+
'parallel': true,
|
|
24
|
+
'stream': true,
|
|
25
|
+
'--': ['--watch'],
|
|
26
|
+
}),
|
|
27
|
+
execa(
|
|
28
|
+
'startup',
|
|
29
|
+
['task', 'tsc-compile', ...packageScopes, '--watch', '--type-check-only'],
|
|
30
|
+
{ stdio: 'inherit' }
|
|
31
|
+
),
|
|
32
|
+
]);
|
|
33
|
+
}
|
|
31
34
|
|
|
32
|
-
return
|
|
35
|
+
return execa('startup', ['task', 'tsc-compile', ...packageScopes], {
|
|
36
|
+
stdio: 'inherit',
|
|
37
|
+
});
|
|
33
38
|
}
|
|
@@ -35,7 +35,7 @@ describe('[startup] Utils', () => {
|
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
function expectedOutDirs(locations: string[]) {
|
|
38
|
-
return locations.map(location =>
|
|
38
|
+
return locations.map(location => `packages/${location}/${location}outDir/`);
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
test('returns outDir path for all packages', () => {
|