@servicetitan/startup 28.5.0 → 30.0.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/mfe-package-clean.d.ts +5 -1
- package/dist/cli/commands/mfe-package-clean.d.ts.map +1 -1
- package/dist/cli/commands/mfe-package-clean.js +46 -36
- package/dist/cli/commands/mfe-package-clean.js.map +1 -1
- package/dist/cli/commands/mfe-package-publish.d.ts +1 -1
- package/dist/cli/commands/mfe-package-publish.d.ts.map +1 -1
- package/dist/cli/commands/mfe-package-publish.js +3 -13
- package/dist/cli/commands/mfe-package-publish.js.map +1 -1
- package/dist/cli/commands/mfe-publish.d.ts.map +1 -1
- package/dist/cli/commands/mfe-publish.js +6 -5
- package/dist/cli/commands/mfe-publish.js.map +1 -1
- 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-npm.d.ts +10 -3
- package/dist/cli/utils/cli-npm.d.ts.map +1 -1
- package/dist/cli/utils/cli-npm.js +13 -15
- package/dist/cli/utils/cli-npm.js.map +1 -1
- package/dist/cli/utils/cli-os.d.ts.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/publish.d.ts.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/get-jest-config.d.ts.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/ignore-plugin/check-resource.d.ts.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/utils/hash-mod.d.ts.map +1 -1
- package/dist/webpack/utils/testing/execute.d.ts.map +1 -1
- package/dist/webpack/utils/testing/get-compiler.d.ts.map +1 -1
- package/package.json +28 -24
- 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/__tests__/mfe-package-clean.test.ts +143 -73
- package/src/cli/commands/__tests__/mfe-package-publish.test.ts +27 -20
- package/src/cli/commands/__tests__/mfe-publish.test.ts +18 -7
- 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/mfe-package-clean.ts +53 -52
- package/src/cli/commands/mfe-package-publish.ts +7 -21
- package/src/cli/commands/mfe-publish.ts +6 -5
- 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 +1 -1
- package/src/cli/utils/__tests__/cli-npm.test.ts +39 -26
- 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-npm.ts +25 -16
- 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/configs/plugins/ignore-plugin/check-resource.ts +1 -1
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
import execa from 'execa';
|
|
2
|
+
import fs from 'fs';
|
|
3
|
+
import { globSync } from 'glob';
|
|
4
|
+
import JSON5 from 'json5';
|
|
5
|
+
|
|
6
|
+
import { log, logErrors, toArray } from '../../utils';
|
|
7
|
+
import { Command } from './types';
|
|
8
|
+
|
|
9
|
+
const oldConfigFile = '.eslintrc.json';
|
|
10
|
+
const newConfigFile = 'eslint.config.mjs';
|
|
11
|
+
const eslintIgnoreFile = '.eslintignore';
|
|
12
|
+
|
|
13
|
+
interface Override {
|
|
14
|
+
[key: string]: unknown;
|
|
15
|
+
files?: string[];
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
interface V8Config {
|
|
19
|
+
extends?: string | string[];
|
|
20
|
+
ignorePatterns?: string[];
|
|
21
|
+
overrides?: Override[];
|
|
22
|
+
plugins?: string[];
|
|
23
|
+
parserOptions?: Record<string, unknown>;
|
|
24
|
+
rules?: Record<string, unknown>;
|
|
25
|
+
settings?: Record<string, unknown>;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
interface Context {
|
|
29
|
+
flatConfigs: string[];
|
|
30
|
+
imports: {
|
|
31
|
+
[key: string]: string | string[];
|
|
32
|
+
'eslint/config': string[];
|
|
33
|
+
};
|
|
34
|
+
source: V8Config;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
interface Recipe {
|
|
38
|
+
config: string;
|
|
39
|
+
files?: string[];
|
|
40
|
+
import: { as: string; from?: string };
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export class ConvertEslintConfig implements Command {
|
|
44
|
+
private static readonly recipes: Record<string, Recipe | null> = {
|
|
45
|
+
'@servicetitan/eslint-config/mono': {
|
|
46
|
+
import: { as: 'mono' },
|
|
47
|
+
config: 'mono',
|
|
48
|
+
},
|
|
49
|
+
'@servicetitan/eslint-config/single': {
|
|
50
|
+
import: { as: 'single' },
|
|
51
|
+
config: 'single',
|
|
52
|
+
},
|
|
53
|
+
'plugin:chai-friendly/recommended': {
|
|
54
|
+
import: { as: 'pluginChaiFriendly', from: 'eslint-plugin-chai-friendly' },
|
|
55
|
+
config: 'pluginChaiFriendly.configs.recommendedFlat',
|
|
56
|
+
},
|
|
57
|
+
'plugin:cypress/recommended': {
|
|
58
|
+
import: { as: 'pluginCypress', from: 'eslint-plugin-cypress/flat' },
|
|
59
|
+
config: 'pluginCypress.configs.recommended',
|
|
60
|
+
},
|
|
61
|
+
'plugin:mocha/recommended': {
|
|
62
|
+
import: { as: 'pluginMocha', from: 'eslint-plugin-mocha' },
|
|
63
|
+
config: 'pluginMocha.configs.flat.recommended',
|
|
64
|
+
},
|
|
65
|
+
'plugin:storybook/recommended': {
|
|
66
|
+
import: { as: 'storybook', from: 'eslint-plugin-storybook' },
|
|
67
|
+
config: "storybook.configs['flat/recommended']",
|
|
68
|
+
},
|
|
69
|
+
'plugin:testing-library/react': {
|
|
70
|
+
import: { as: 'pluginTestingLibrary', from: 'eslint-plugin-testing-library' },
|
|
71
|
+
config: "pluginTestingLibrary.configs['flat/react']",
|
|
72
|
+
files: ['**/*.test.*'],
|
|
73
|
+
},
|
|
74
|
+
'prettier': null,
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
description() {
|
|
78
|
+
return 'convert v8.x eslintrc.json to v9.x flat config';
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
@logErrors
|
|
82
|
+
async execute() {
|
|
83
|
+
if (!fs.existsSync(oldConfigFile)) {
|
|
84
|
+
throw new Error(`${oldConfigFile} not found`);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const configFiles = globSync('eslint.config.{js,cjs,mjs}');
|
|
88
|
+
if (configFiles.length > 0) {
|
|
89
|
+
throw new Error(`flat config "${configFiles[0]}" already exists`);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
log.info(`Processing ${oldConfigFile}`);
|
|
93
|
+
|
|
94
|
+
const json = this.readJson(oldConfigFile);
|
|
95
|
+
fs.writeFileSync(newConfigFile, this.convert(json), 'utf-8');
|
|
96
|
+
await this.prettify(newConfigFile);
|
|
97
|
+
|
|
98
|
+
log.success(`Created ${newConfigFile}`);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
private convert(source: V8Config) {
|
|
102
|
+
const context: Context = {
|
|
103
|
+
flatConfigs: [],
|
|
104
|
+
imports: { 'eslint/config': ['defineConfig'] },
|
|
105
|
+
source,
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
const handlers: { [K in keyof V8Config]: (context: Context) => void } = {
|
|
109
|
+
extends: this.handleExtends.bind(this),
|
|
110
|
+
overrides: this.handleOverrides.bind(this),
|
|
111
|
+
parserOptions: this.handleParserOptions.bind(this),
|
|
112
|
+
plugins: this.handlePlugins.bind(this),
|
|
113
|
+
rules: this.handleRules.bind(this),
|
|
114
|
+
settings: this.handleSettings.bind(this),
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
// Don't limit handleIgnores to a specific key because it also reads .eslintignore.rc
|
|
118
|
+
this.handleIgnores(context);
|
|
119
|
+
|
|
120
|
+
// Run handlers in key order to preserve ordering of configs
|
|
121
|
+
Object.keys(context.source).forEach((key: keyof V8Config) => {
|
|
122
|
+
handlers[key]?.(context);
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
return this.format(context);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
private format(context: Context) {
|
|
129
|
+
return `${this.formatImports(context)}\n\n${this.formatConfigs(context)}`;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
private formatConfigs(context: Context) {
|
|
133
|
+
return `export default defineConfig([
|
|
134
|
+
${context.flatConfigs.join()}
|
|
135
|
+
]);`;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
private formatImports({ imports }: Context) {
|
|
139
|
+
return Object.entries(imports)
|
|
140
|
+
.map(([pkg, itemOrItems]) => {
|
|
141
|
+
if (typeof itemOrItems === 'string') {
|
|
142
|
+
return `import ${itemOrItems} from '${pkg}';`;
|
|
143
|
+
}
|
|
144
|
+
return `import { ${itemOrItems.join()} } from '${pkg}';`;
|
|
145
|
+
})
|
|
146
|
+
.join('\n');
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
private handleExtends({ flatConfigs, imports, source }: Context) {
|
|
150
|
+
const unrecognized: string[] = [];
|
|
151
|
+
const extendsArray = toArray(source.extends);
|
|
152
|
+
|
|
153
|
+
extendsArray.forEach(entry => {
|
|
154
|
+
const recipe = ConvertEslintConfig.recipes[entry];
|
|
155
|
+
if (recipe) {
|
|
156
|
+
imports[recipe.import.from ?? entry] = recipe.import.as;
|
|
157
|
+
if (recipe.files) {
|
|
158
|
+
flatConfigs.push(`{
|
|
159
|
+
files: ${JSON.stringify(recipe.files)},
|
|
160
|
+
...${recipe.config}
|
|
161
|
+
}`);
|
|
162
|
+
} else {
|
|
163
|
+
flatConfigs.push(recipe.config);
|
|
164
|
+
}
|
|
165
|
+
} else if (recipe !== null) {
|
|
166
|
+
unrecognized.push(entry);
|
|
167
|
+
}
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
/*
|
|
171
|
+
* Use extends workaround for anything we didn't recognized
|
|
172
|
+
* https://eslint.org/blog/2025/03/flat-config-extends-define-config-global-ignores/#bringing-back-extends
|
|
173
|
+
*/
|
|
174
|
+
|
|
175
|
+
if (unrecognized.length) {
|
|
176
|
+
flatConfigs.push(JSON.stringify({ extends: unrecognized }));
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
private handleIgnores({ flatConfigs, imports, source: { ignorePatterns = [] } }: Context) {
|
|
181
|
+
const globs = ignorePatterns.filter(glob => !!glob);
|
|
182
|
+
|
|
183
|
+
if (fs.existsSync(eslintIgnoreFile)) {
|
|
184
|
+
const fileGlobs = fs
|
|
185
|
+
.readFileSync(eslintIgnoreFile, 'utf-8')
|
|
186
|
+
.split('\n')
|
|
187
|
+
.map(line => line.trim())
|
|
188
|
+
.filter(line => !!line);
|
|
189
|
+
globs.push(...fileGlobs);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
if (globs.length === 0) {
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
const normalized = globs.map(normalizeGlob);
|
|
197
|
+
|
|
198
|
+
imports['eslint/config'].push('globalIgnores');
|
|
199
|
+
flatConfigs.push(`globalIgnores(${JSON.stringify(normalized)})`);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
private handleOverrides({
|
|
203
|
+
flatConfigs,
|
|
204
|
+
source: { overrides },
|
|
205
|
+
}: Context & { source: { overrides: NonNullable<Context['source']['overrides']> } }) {
|
|
206
|
+
overrides.forEach(override => {
|
|
207
|
+
flatConfigs.push(JSON.stringify(this.handleOverride(override), null, 2));
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
private handleOverride({ parserOptions, ...rest }: Override) {
|
|
212
|
+
rest.files = rest.files?.map(normalizeGlob);
|
|
213
|
+
const languageOptions = parserOptions ? { parserOptions } : undefined;
|
|
214
|
+
return { ...rest, languageOptions };
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
private handlePlugins({
|
|
218
|
+
flatConfigs,
|
|
219
|
+
imports,
|
|
220
|
+
source,
|
|
221
|
+
}: Context & { source: { plugins: NonNullable<Context['source']['plugins']> } }) {
|
|
222
|
+
const plugins: Record<string, string> = {};
|
|
223
|
+
|
|
224
|
+
source.plugins.forEach(name => {
|
|
225
|
+
const camelized = toCamelCase(name);
|
|
226
|
+
imports[`eslint-plugin-${name}`] = camelized;
|
|
227
|
+
plugins[name] = camelized;
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
flatConfigs.push(`{
|
|
231
|
+
plugins: {
|
|
232
|
+
${Object.entries(plugins)
|
|
233
|
+
.map(([key, value]) => `'${key}': ${value}`)
|
|
234
|
+
.join(',\n')}
|
|
235
|
+
}
|
|
236
|
+
}`);
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
private handleParserOptions({ flatConfigs, source: { parserOptions } }: Context) {
|
|
240
|
+
flatConfigs.push(JSON.stringify({ languageOptions: { parserOptions } }));
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
private handleRules({
|
|
244
|
+
flatConfigs,
|
|
245
|
+
source: { rules },
|
|
246
|
+
}: Context & { source: { rules: NonNullable<Context['source']['rules']> } }) {
|
|
247
|
+
const tsPrefix = '@typescript-eslint/';
|
|
248
|
+
const nonTsRules = Object.fromEntries(
|
|
249
|
+
Object.entries(rules).filter(([key]) => !key.startsWith(tsPrefix))
|
|
250
|
+
);
|
|
251
|
+
if (Object.keys(nonTsRules).length) {
|
|
252
|
+
flatConfigs.push(JSON.stringify({ rules: nonTsRules }, null, 2));
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
const tsRules = Object.fromEntries(
|
|
256
|
+
Object.entries(rules).filter(([key]) => key.startsWith(tsPrefix))
|
|
257
|
+
);
|
|
258
|
+
if (Object.keys(tsRules).length) {
|
|
259
|
+
flatConfigs.push(JSON.stringify({ files: ['**/*.ts{,x}'], rules: tsRules }, null, 2));
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
private handleSettings({
|
|
264
|
+
flatConfigs,
|
|
265
|
+
source: { settings },
|
|
266
|
+
}: Context & { source: { settings: NonNullable<Context['source']['settings']> } }) {
|
|
267
|
+
flatConfigs.push(JSON.stringify({ settings }));
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
private async prettify(filename: string) {
|
|
271
|
+
try {
|
|
272
|
+
await execa('npx', ['prettier', '-w', filename], { stdout: 'ignore' });
|
|
273
|
+
} catch (error: any) {
|
|
274
|
+
throw new Error(`prettier failed with exit code ${error.exitCode}`);
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
private readJson(filename: string) {
|
|
279
|
+
return JSON5.parse(fs.readFileSync(filename, 'utf8'));
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
function toCamelCase(str: string) {
|
|
284
|
+
return str.replace(/(-[a-z])/g, ([, letter]) => letter.toUpperCase());
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
function normalizeGlob(glob: string) {
|
|
288
|
+
return glob.includes('/') ? glob.replace(/^(!)?\//, '$1') : `**/${glob}`;
|
|
289
|
+
}
|
|
@@ -2,6 +2,7 @@ import { CommandName } from '../../utils';
|
|
|
2
2
|
|
|
3
3
|
import { Build } from './build';
|
|
4
4
|
import { BundlePackage } from './bundle-package';
|
|
5
|
+
import { ConvertEslintConfig } from './convert-eslint-config';
|
|
5
6
|
import { ESLintCommand } from './eslint';
|
|
6
7
|
import { Init } from './init';
|
|
7
8
|
import { Install } from './install';
|
|
@@ -13,6 +14,7 @@ import { MFEPublish } from './mfe-publish';
|
|
|
13
14
|
import { PreparePackage } from './prepare-package';
|
|
14
15
|
import { Start } from './start';
|
|
15
16
|
import { StylesCheck } from './styles-check';
|
|
17
|
+
import { RunTask } from './run-task';
|
|
16
18
|
import { Tests } from './tests';
|
|
17
19
|
import { Command, Newable } from './types';
|
|
18
20
|
|
|
@@ -22,6 +24,8 @@ export function getCommand(name: CommandName): Newable<Command> | undefined {
|
|
|
22
24
|
return Build;
|
|
23
25
|
case CommandName['bundle-package']:
|
|
24
26
|
return BundlePackage;
|
|
27
|
+
case CommandName['convert-eslint-config']:
|
|
28
|
+
return ConvertEslintConfig;
|
|
25
29
|
case CommandName.eslint:
|
|
26
30
|
return ESLintCommand;
|
|
27
31
|
case CommandName.init:
|
|
@@ -46,5 +50,7 @@ export function getCommand(name: CommandName): Newable<Command> | undefined {
|
|
|
46
50
|
return StylesCheck;
|
|
47
51
|
case CommandName.test:
|
|
48
52
|
return Tests;
|
|
53
|
+
case CommandName.task:
|
|
54
|
+
return RunTask;
|
|
49
55
|
}
|
|
50
56
|
}
|
package/src/cli/commands/init.ts
CHANGED
|
@@ -37,7 +37,8 @@ export class Init implements Command {
|
|
|
37
37
|
);
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
-
for
|
|
40
|
+
for (const url of gitUrls) {
|
|
41
|
+
// eslint-disable-next-line no-await-in-loop
|
|
41
42
|
if (await cloneRepo(url, destination)) {
|
|
42
43
|
log.info(`copied example project to ${destination}`);
|
|
43
44
|
return;
|
|
@@ -53,7 +54,7 @@ export class Init implements Command {
|
|
|
53
54
|
async function cloneRepo(url: string, destination: string) {
|
|
54
55
|
try {
|
|
55
56
|
await runCommand(`git clone -q ${url} ${destination}`, { quiet: true });
|
|
56
|
-
} catch
|
|
57
|
+
} catch {
|
|
57
58
|
return false;
|
|
58
59
|
}
|
|
59
60
|
fs.rmSync(path.join(destination, '.git'), { recursive: true, force: true });
|
|
@@ -65,7 +66,7 @@ async function cloneRepo(url: string, destination: string) {
|
|
|
65
66
|
function isReachable(url: string) {
|
|
66
67
|
try {
|
|
67
68
|
runCommandOutput(`git ls-remote -qt ${url}`, { quiet: true });
|
|
68
|
-
} catch
|
|
69
|
+
} catch {
|
|
69
70
|
return false;
|
|
70
71
|
}
|
|
71
72
|
return true;
|
package/src/cli/commands/lint.ts
CHANGED
|
@@ -22,7 +22,7 @@ interface Args {
|
|
|
22
22
|
/** Packages to skip */
|
|
23
23
|
ignore?: string | string[];
|
|
24
24
|
/** Run eslint separately for each package? */
|
|
25
|
-
|
|
25
|
+
parallel?: boolean;
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
export class Lint implements Command {
|
|
@@ -44,10 +44,10 @@ export class Lint implements Command {
|
|
|
44
44
|
|
|
45
45
|
@logErrors
|
|
46
46
|
private async eslint() {
|
|
47
|
-
const { fix, ignore,
|
|
47
|
+
const { fix, ignore, parallel, scope } = this.args;
|
|
48
48
|
const { paths } = this;
|
|
49
49
|
|
|
50
|
-
const useESLint = !
|
|
50
|
+
const useESLint = !parallel && !scope?.length && !ignore?.length;
|
|
51
51
|
if (this.paths.length || useESLint) {
|
|
52
52
|
log.info('Running eslint...');
|
|
53
53
|
await eslint({ fix, paths });
|
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
import { isWebComponent, log, logErrors, readJson } from '../../utils';
|
|
2
|
-
import { gitGetBranch } from '../utils/cli-git';
|
|
3
|
-
import { npmGetPackageVersionDates, npmUnpublish } from '../utils/cli-npm';
|
|
4
2
|
import { getBranchesConfigs } from '../../utils/get-branch-configs';
|
|
3
|
+
import { gitGetBranch } from '../utils/cli-git';
|
|
4
|
+
import { Version, npmGetPackageVersionsDetails, npmUnpublish } from '../utils/cli-npm';
|
|
5
5
|
import { Command } from './types';
|
|
6
6
|
|
|
7
7
|
export interface ArgsPackageClean {
|
|
8
|
-
|
|
8
|
+
all?: true;
|
|
9
|
+
branch?: string;
|
|
9
10
|
count?: number;
|
|
11
|
+
dry?: boolean;
|
|
12
|
+
registry?: string;
|
|
10
13
|
}
|
|
11
14
|
|
|
12
15
|
export class MFEPackageClean implements Command {
|
|
@@ -23,37 +26,34 @@ export class MFEPackageClean implements Command {
|
|
|
23
26
|
}
|
|
24
27
|
|
|
25
28
|
const data = this.getCleanData();
|
|
26
|
-
const
|
|
27
|
-
const packageName = packageJson.name;
|
|
29
|
+
const packageName = readJson('package.json').name;
|
|
28
30
|
const branchedVersions = this.getBranchedVersions(packageName, data.registry);
|
|
29
31
|
|
|
30
|
-
log.info(
|
|
31
|
-
`branched versions (${data.count}):`,
|
|
32
|
-
JSON.stringify(branchedVersions, undefined, 4)
|
|
33
|
-
);
|
|
34
|
-
|
|
35
|
-
const branchedVersionsToClean: Record<string, [string, Date][]> = {};
|
|
32
|
+
log.info(`branched versions (${data.count}):`, JSON.stringify(branchedVersions, null, 2));
|
|
36
33
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
34
|
+
const branchedVersionsToClean: Record<string, Version[]> = {};
|
|
35
|
+
for (const [branch, versions] of Object.entries(branchedVersions)) {
|
|
36
|
+
// Limit branches for now
|
|
37
|
+
if (!data.branches.includes(branch)) {
|
|
38
|
+
log.info(`ignoring unrecognized branch "${branch}"`);
|
|
40
39
|
continue;
|
|
41
40
|
}
|
|
42
41
|
|
|
43
|
-
|
|
44
|
-
|
|
42
|
+
branchedVersionsToClean[branch] = this.excludeTagged(versions)
|
|
43
|
+
.sort(({ date: adt }, { date: bdt }) => (adt > bdt ? -1 : 1))
|
|
44
|
+
.slice(data.count);
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
-
log.info(
|
|
48
|
-
'found versions for unpublish:',
|
|
49
|
-
JSON.stringify(branchedVersionsToClean, undefined, 4)
|
|
50
|
-
);
|
|
51
|
-
|
|
47
|
+
log.info('found versions for unpublish:', JSON.stringify(branchedVersionsToClean, null, 2));
|
|
52
48
|
const unVersions = Object.keys(branchedVersionsToClean).reduce(
|
|
53
|
-
(out, br) => [...out, ...branchedVersionsToClean[br].map((
|
|
49
|
+
(out, br) => [...out, ...branchedVersionsToClean[br].map(({ name }) => name)],
|
|
54
50
|
[]
|
|
55
51
|
);
|
|
56
52
|
|
|
53
|
+
if (this.args.dry) {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
57
|
for (const version of unVersions) {
|
|
58
58
|
try {
|
|
59
59
|
// eslint-disable-next-line no-await-in-loop
|
|
@@ -64,6 +64,16 @@ export class MFEPackageClean implements Command {
|
|
|
64
64
|
}
|
|
65
65
|
}
|
|
66
66
|
|
|
67
|
+
private excludeTagged(versions: Version[]) {
|
|
68
|
+
return versions.filter(({ name, tag }) => {
|
|
69
|
+
if (tag) {
|
|
70
|
+
log.info(`ignoring version ${name} tagged "${tag}"`);
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
73
|
+
return true;
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
|
|
67
77
|
private getCleanData(): {
|
|
68
78
|
count: number;
|
|
69
79
|
registry: string;
|
|
@@ -76,66 +86,57 @@ export class MFEPackageClean implements Command {
|
|
|
76
86
|
|
|
77
87
|
let branches: string[];
|
|
78
88
|
|
|
79
|
-
if (this.args.
|
|
80
|
-
branches =
|
|
89
|
+
if (this.args.all === true) {
|
|
90
|
+
branches = Object.keys(getBranchesConfigs());
|
|
81
91
|
} else if (typeof this.args.branch === 'string') {
|
|
82
92
|
branches = [this.args.branch];
|
|
83
93
|
} else {
|
|
84
|
-
branches =
|
|
94
|
+
branches = [gitGetBranch()];
|
|
85
95
|
}
|
|
86
96
|
|
|
87
|
-
const registry = 'https://verdaccio.servicetitan.com';
|
|
97
|
+
const registry = this.args.registry ?? 'https://verdaccio.servicetitan.com';
|
|
88
98
|
|
|
89
99
|
return { count, registry, branches };
|
|
90
100
|
}
|
|
91
101
|
|
|
92
102
|
private getBranchedVersions(packageName: string, registry: string) {
|
|
93
|
-
const versions =
|
|
94
|
-
const branchedVersions: Record<string, [
|
|
95
|
-
const unknownVersions: string[] = [];
|
|
96
|
-
|
|
97
|
-
const addVersion = (branch: string, version: string, dt: Date) => {
|
|
98
|
-
if (!branchedVersions[branch]) {
|
|
99
|
-
branchedVersions[branch] = [];
|
|
100
|
-
}
|
|
103
|
+
const versions = npmGetPackageVersionsDetails(registry, packageName);
|
|
104
|
+
const branchedVersions: Record<string, Version[]> = {};
|
|
101
105
|
|
|
102
|
-
|
|
103
|
-
|
|
106
|
+
function addVersion(branch: string, version: Version) {
|
|
107
|
+
branchedVersions[branch] ??= [];
|
|
108
|
+
branchedVersions[branch].push(version);
|
|
109
|
+
}
|
|
104
110
|
|
|
105
|
-
for (const
|
|
106
|
-
|
|
111
|
+
for (const version of versions) {
|
|
112
|
+
const { name } = version;
|
|
113
|
+
if (!name.startsWith('0.0.0-')) {
|
|
107
114
|
continue;
|
|
108
115
|
}
|
|
109
116
|
|
|
110
|
-
const buildVersion =
|
|
117
|
+
const buildVersion = name.replace('0.0.0-', '');
|
|
111
118
|
|
|
119
|
+
// master version generated by nerdbank versioning
|
|
112
120
|
if (/^(\d+)\.(\d+)\.(\d+)$/.test(buildVersion)) {
|
|
113
|
-
|
|
114
|
-
addVersion('master', version, dt);
|
|
121
|
+
addVersion('master', version);
|
|
115
122
|
continue;
|
|
116
123
|
}
|
|
117
124
|
|
|
125
|
+
// branch version generated by nerdbank versioning
|
|
118
126
|
const match1 = buildVersion.match(/^(\d+)\.(\d+)\.(\d+)-([\dA-Za-z-]+).([\dA-Za-z]+)$/);
|
|
119
|
-
|
|
120
127
|
if (match1?.length) {
|
|
121
|
-
|
|
122
|
-
addVersion(match1[4], version, dt);
|
|
128
|
+
addVersion(match1[4], version);
|
|
123
129
|
continue;
|
|
124
130
|
}
|
|
125
131
|
|
|
132
|
+
// branch version generated by mfe-publisher versioning
|
|
126
133
|
const match2 = buildVersion.match(/^([\dA-Za-z-]+).([\dA-Za-z]+)$/);
|
|
127
|
-
|
|
128
134
|
if (match2?.length) {
|
|
129
|
-
|
|
130
|
-
addVersion(match2[1], version, dt);
|
|
135
|
+
addVersion(match2[1], version);
|
|
131
136
|
continue;
|
|
132
137
|
}
|
|
133
138
|
|
|
134
|
-
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
if (unknownVersions.length) {
|
|
138
|
-
log.info('unknown versions:', unknownVersions.join());
|
|
139
|
+
log.info(`skipping unrecognized version: ${name}`);
|
|
139
140
|
}
|
|
140
141
|
|
|
141
142
|
return branchedVersions;
|
|
@@ -2,13 +2,7 @@ import path from 'path';
|
|
|
2
2
|
import fs from 'fs';
|
|
3
3
|
import { getFolders, isWebComponent, log, logErrors, readJson } from '../../utils';
|
|
4
4
|
import { gitGetBranch, gitGetCommitHash } from '../utils/cli-git';
|
|
5
|
-
import {
|
|
6
|
-
npmGetPackageVersions,
|
|
7
|
-
npmPackageSet,
|
|
8
|
-
npmPublish,
|
|
9
|
-
npmPublishDry,
|
|
10
|
-
npmTagVersion,
|
|
11
|
-
} from '../utils/cli-npm';
|
|
5
|
+
import { npmGetPackageVersions, npmPackageSet, npmPublish, npmTagVersion } from '../utils/cli-npm';
|
|
12
6
|
import { getBranchesConfigs } from '../../utils/get-branch-configs';
|
|
13
7
|
import { getDefaultBuildVersion } from '../utils/publish';
|
|
14
8
|
import { EntryPoint, EntryPoints, Metadata } from '../../webpack/configs';
|
|
@@ -20,7 +14,7 @@ export interface ArgsPackagePublish {
|
|
|
20
14
|
dry?: boolean;
|
|
21
15
|
force?: boolean;
|
|
22
16
|
registry?: string;
|
|
23
|
-
tag?: string
|
|
17
|
+
tag?: string;
|
|
24
18
|
}
|
|
25
19
|
|
|
26
20
|
export class MFEPackagePublish implements Command {
|
|
@@ -92,11 +86,7 @@ export class MFEPackagePublish implements Command {
|
|
|
92
86
|
await npmPackageSet('files[1]', 'package.json');
|
|
93
87
|
}
|
|
94
88
|
|
|
95
|
-
|
|
96
|
-
await npmPublishDry();
|
|
97
|
-
} else {
|
|
98
|
-
await npmPublish(data.tag);
|
|
99
|
-
}
|
|
89
|
+
await npmPublish({ dry: data.dry, tag: data.tag || data.fallbackTag });
|
|
100
90
|
|
|
101
91
|
log.info(`${dryRunPrefix}published ${packageName} version ${data.version}`);
|
|
102
92
|
}
|
|
@@ -104,11 +94,12 @@ export class MFEPackagePublish implements Command {
|
|
|
104
94
|
private getPublishData(): {
|
|
105
95
|
version: string;
|
|
106
96
|
buildVersion: string;
|
|
107
|
-
tag
|
|
97
|
+
tag: string;
|
|
108
98
|
registry: string;
|
|
109
99
|
dry: boolean;
|
|
110
100
|
force: boolean;
|
|
111
101
|
isBranchConfigured: boolean;
|
|
102
|
+
fallbackTag: string;
|
|
112
103
|
} {
|
|
113
104
|
const cli = this.args;
|
|
114
105
|
const branch = cli.branch ?? gitGetBranch();
|
|
@@ -119,15 +110,9 @@ export class MFEPackagePublish implements Command {
|
|
|
119
110
|
buildVersion = getDefaultBuildVersion(branch, gitGetCommitHash());
|
|
120
111
|
}
|
|
121
112
|
|
|
122
|
-
if (!buildVersion) {
|
|
123
|
-
throw new Error('build version is not set');
|
|
124
|
-
}
|
|
125
|
-
|
|
126
113
|
let tag: string;
|
|
127
114
|
|
|
128
|
-
if (cli.tag
|
|
129
|
-
tag = '';
|
|
130
|
-
} else if (cli.tag) {
|
|
115
|
+
if (cli.tag) {
|
|
131
116
|
tag = cli.tag;
|
|
132
117
|
} else {
|
|
133
118
|
tag = branchConfig?.publishTag ?? '';
|
|
@@ -143,6 +128,7 @@ export class MFEPackagePublish implements Command {
|
|
|
143
128
|
dry: !!cli.dry,
|
|
144
129
|
force: !!cli.force,
|
|
145
130
|
isBranchConfigured: !!branchConfig,
|
|
131
|
+
fallbackTag: 'latest',
|
|
146
132
|
};
|
|
147
133
|
}
|
|
148
134
|
|
|
@@ -58,17 +58,18 @@ export class MFEPublish implements Command {
|
|
|
58
58
|
...[dry && '--dry'],
|
|
59
59
|
...[force && '--force'],
|
|
60
60
|
...[registry && `--registry ${registry}`],
|
|
61
|
-
...[tag && `--tag ${tag}`],
|
|
62
|
-
...[tag === false && `--no-tag`],
|
|
61
|
+
...[typeof tag === 'string' && `--tag ${tag}`],
|
|
63
62
|
].filter(item => !!item) as string[];
|
|
64
63
|
}
|
|
65
64
|
|
|
66
65
|
getCleanOptions() {
|
|
67
|
-
const { branch, count } = this.args as ArgsPackageClean;
|
|
66
|
+
const { all, branch, count, dry, registry } = this.args as ArgsPackageClean;
|
|
68
67
|
return [
|
|
69
|
-
...[
|
|
70
|
-
...[
|
|
68
|
+
...[all && '--all'],
|
|
69
|
+
...[typeof branch === 'string' && `--branch ${branch}`],
|
|
71
70
|
...[count && `--count ${count}`],
|
|
71
|
+
...[dry && '--dry'],
|
|
72
|
+
...[registry && `--registry ${registry}`],
|
|
72
73
|
].filter(item => !!item) as string[];
|
|
73
74
|
}
|
|
74
75
|
}
|