@servicetitan/startup 32.1.0 → 32.3.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.
Files changed (253) hide show
  1. package/dist/cli/commands/build.d.ts +36 -7
  2. package/dist/cli/commands/build.d.ts.map +1 -1
  3. package/dist/cli/commands/build.js +35 -10
  4. package/dist/cli/commands/build.js.map +1 -1
  5. package/dist/cli/commands/bundle-package.d.ts +9 -10
  6. package/dist/cli/commands/bundle-package.d.ts.map +1 -1
  7. package/dist/cli/commands/bundle-package.js +6 -22
  8. package/dist/cli/commands/bundle-package.js.map +1 -1
  9. package/dist/cli/commands/clean.d.ts +2 -2
  10. package/dist/cli/commands/clean.d.ts.map +1 -1
  11. package/dist/cli/commands/clean.js +16 -4
  12. package/dist/cli/commands/clean.js.map +1 -1
  13. package/dist/cli/commands/convert-eslint-config.d.ts +2 -2
  14. package/dist/cli/commands/convert-eslint-config.d.ts.map +1 -1
  15. package/dist/cli/commands/convert-eslint-config.js +3 -4
  16. package/dist/cli/commands/convert-eslint-config.js.map +1 -1
  17. package/dist/cli/commands/eslint.d.ts +3 -5
  18. package/dist/cli/commands/eslint.d.ts.map +1 -1
  19. package/dist/cli/commands/eslint.js +2 -18
  20. package/dist/cli/commands/eslint.js.map +1 -1
  21. package/dist/cli/commands/get-command.d.ts.map +1 -1
  22. package/dist/cli/commands/get-command.js +2 -0
  23. package/dist/cli/commands/get-command.js.map +1 -1
  24. package/dist/cli/commands/index.d.ts +0 -1
  25. package/dist/cli/commands/index.d.ts.map +1 -1
  26. package/dist/cli/commands/index.js +0 -1
  27. package/dist/cli/commands/index.js.map +1 -1
  28. package/dist/cli/commands/init.d.ts +10 -6
  29. package/dist/cli/commands/init.d.ts.map +1 -1
  30. package/dist/cli/commands/init.js +9 -8
  31. package/dist/cli/commands/init.js.map +1 -1
  32. package/dist/cli/commands/install.d.ts +21 -7
  33. package/dist/cli/commands/install.d.ts.map +1 -1
  34. package/dist/cli/commands/install.js +33 -11
  35. package/dist/cli/commands/install.js.map +1 -1
  36. package/dist/cli/commands/kendo-ui-license.d.ts +3 -3
  37. package/dist/cli/commands/kendo-ui-license.d.ts.map +1 -1
  38. package/dist/cli/commands/kendo-ui-license.js +17 -5
  39. package/dist/cli/commands/kendo-ui-license.js.map +1 -1
  40. package/dist/cli/commands/lint.d.ts +31 -12
  41. package/dist/cli/commands/lint.d.ts.map +1 -1
  42. package/dist/cli/commands/lint.js +34 -13
  43. package/dist/cli/commands/lint.js.map +1 -1
  44. package/dist/cli/commands/mfe-list.d.ts +46 -0
  45. package/dist/cli/commands/mfe-list.d.ts.map +1 -0
  46. package/dist/cli/commands/mfe-list.js +200 -0
  47. package/dist/cli/commands/mfe-list.js.map +1 -0
  48. package/dist/cli/commands/mfe-package-clean.d.ts +29 -5
  49. package/dist/cli/commands/mfe-package-clean.d.ts.map +1 -1
  50. package/dist/cli/commands/mfe-package-clean.js +28 -5
  51. package/dist/cli/commands/mfe-package-clean.js.map +1 -1
  52. package/dist/cli/commands/mfe-package-publish.d.ts +37 -5
  53. package/dist/cli/commands/mfe-package-publish.d.ts.map +1 -1
  54. package/dist/cli/commands/mfe-package-publish.js +36 -5
  55. package/dist/cli/commands/mfe-package-publish.js.map +1 -1
  56. package/dist/cli/commands/mfe-publish.d.ts +17 -4
  57. package/dist/cli/commands/mfe-publish.d.ts.map +1 -1
  58. package/dist/cli/commands/mfe-publish.js +37 -7
  59. package/dist/cli/commands/mfe-publish.js.map +1 -1
  60. package/dist/cli/commands/prepare-package.d.ts +3 -5
  61. package/dist/cli/commands/prepare-package.d.ts.map +1 -1
  62. package/dist/cli/commands/prepare-package.js +2 -18
  63. package/dist/cli/commands/prepare-package.js.map +1 -1
  64. package/dist/cli/commands/review/review.d.ts +14 -6
  65. package/dist/cli/commands/review/review.d.ts.map +1 -1
  66. package/dist/cli/commands/review/review.js +27 -23
  67. package/dist/cli/commands/review/review.js.map +1 -1
  68. package/dist/cli/commands/run-task.d.ts +10 -6
  69. package/dist/cli/commands/run-task.d.ts.map +1 -1
  70. package/dist/cli/commands/run-task.js +16 -13
  71. package/dist/cli/commands/run-task.js.map +1 -1
  72. package/dist/cli/commands/start.d.ts +28 -7
  73. package/dist/cli/commands/start.d.ts.map +1 -1
  74. package/dist/cli/commands/start.js +27 -10
  75. package/dist/cli/commands/start.js.map +1 -1
  76. package/dist/cli/commands/styles-check.d.ts +2 -2
  77. package/dist/cli/commands/styles-check.d.ts.map +1 -1
  78. package/dist/cli/commands/styles-check.js +2 -1
  79. package/dist/cli/commands/styles-check.js.map +1 -1
  80. package/dist/cli/commands/test/runners/vitest.js +2 -1
  81. package/dist/cli/commands/test/runners/vitest.js.map +1 -1
  82. package/dist/cli/commands/test/tests.d.ts +14 -5
  83. package/dist/cli/commands/test/tests.d.ts.map +1 -1
  84. package/dist/cli/commands/test/tests.js +26 -13
  85. package/dist/cli/commands/test/tests.js.map +1 -1
  86. package/dist/cli/commands/types.d.ts +13 -4
  87. package/dist/cli/commands/types.d.ts.map +1 -1
  88. package/dist/cli/commands/types.js +28 -0
  89. package/dist/cli/commands/types.js.map +1 -1
  90. package/dist/cli/commands/upload-sourcemaps.d.ts +3 -5
  91. package/dist/cli/commands/upload-sourcemaps.d.ts.map +1 -1
  92. package/dist/cli/commands/upload-sourcemaps.js +5 -20
  93. package/dist/cli/commands/upload-sourcemaps.js.map +1 -1
  94. package/dist/cli/index.js +48 -39
  95. package/dist/cli/index.js.map +1 -1
  96. package/dist/cli/tasks/swc-compile-package.d.ts +2 -2
  97. package/dist/cli/tasks/swc-compile-package.d.ts.map +1 -1
  98. package/dist/cli/tasks/swc-compile-package.js.map +1 -1
  99. package/dist/cli/tasks/tsc-compile-package.d.ts +2 -2
  100. package/dist/cli/tasks/tsc-compile-package.d.ts.map +1 -1
  101. package/dist/cli/tasks/tsc-compile-package.js +1 -1
  102. package/dist/cli/tasks/tsc-compile-package.js.map +1 -1
  103. package/dist/cli/tasks/tsc-compile.d.ts +2 -2
  104. package/dist/cli/tasks/tsc-compile.d.ts.map +1 -1
  105. package/dist/cli/tasks/tsc-compile.js.map +1 -1
  106. package/dist/cli/utils/bundle.js +2 -2
  107. package/dist/cli/utils/bundle.js.map +1 -1
  108. package/dist/cli/utils/cli-npm.d.ts +14 -0
  109. package/dist/cli/utils/cli-npm.d.ts.map +1 -1
  110. package/dist/cli/utils/cli-npm.js +44 -0
  111. package/dist/cli/utils/cli-npm.js.map +1 -1
  112. package/dist/cli/utils/cli-os.d.ts +2 -2
  113. package/dist/cli/utils/cli-os.d.ts.map +1 -1
  114. package/dist/cli/utils/cli-os.js +13 -9
  115. package/dist/cli/utils/cli-os.js.map +1 -1
  116. package/dist/cli/utils/eslint.d.ts +2 -1
  117. package/dist/cli/utils/eslint.d.ts.map +1 -1
  118. package/dist/cli/utils/eslint.js.map +1 -1
  119. package/dist/cli/utils/index.d.ts +1 -0
  120. package/dist/cli/utils/index.d.ts.map +1 -1
  121. package/dist/cli/utils/index.js +1 -0
  122. package/dist/cli/utils/index.js.map +1 -1
  123. package/dist/cli/utils/is-tty.d.ts +2 -0
  124. package/dist/cli/utils/is-tty.d.ts.map +1 -0
  125. package/dist/cli/utils/is-tty.js +15 -0
  126. package/dist/cli/utils/is-tty.js.map +1 -0
  127. package/dist/cli/utils/maybe-create-git-folder.d.ts +1 -1
  128. package/dist/cli/utils/maybe-create-git-folder.d.ts.map +1 -1
  129. package/dist/cli/utils/maybe-create-git-folder.js +12 -6
  130. package/dist/cli/utils/maybe-create-git-folder.js.map +1 -1
  131. package/dist/cli/utils/process-tree.d.ts.map +1 -1
  132. package/dist/cli/utils/process-tree.js +2 -2
  133. package/dist/cli/utils/process-tree.js.map +1 -1
  134. package/dist/cli/utils/set-node-options.d.ts.map +1 -1
  135. package/dist/cli/utils/set-node-options.js +2 -1
  136. package/dist/cli/utils/set-node-options.js.map +1 -1
  137. package/dist/utils/find-packages.d.ts +1 -0
  138. package/dist/utils/find-packages.d.ts.map +1 -1
  139. package/dist/utils/find-packages.js.map +1 -1
  140. package/dist/utils/format-relative-date.d.ts +2 -0
  141. package/dist/utils/format-relative-date.d.ts.map +1 -0
  142. package/dist/utils/format-relative-date.js +60 -0
  143. package/dist/utils/format-relative-date.js.map +1 -0
  144. package/dist/utils/get-configuration.d.ts +10 -3
  145. package/dist/utils/get-configuration.d.ts.map +1 -1
  146. package/dist/utils/get-configuration.js +1 -0
  147. package/dist/utils/get-configuration.js.map +1 -1
  148. package/dist/utils/get-jest-config.d.ts.map +1 -1
  149. package/dist/utils/get-jest-config.js +20 -9
  150. package/dist/utils/get-jest-config.js.map +1 -1
  151. package/dist/utils/get-packages.d.ts +3 -5
  152. package/dist/utils/get-packages.d.ts.map +1 -1
  153. package/dist/utils/get-packages.js +1 -4
  154. package/dist/utils/get-packages.js.map +1 -1
  155. package/dist/utils/get-startup-version.d.ts.map +1 -1
  156. package/dist/utils/get-startup-version.js +1 -1
  157. package/dist/utils/get-startup-version.js.map +1 -1
  158. package/dist/utils/index.d.ts +2 -0
  159. package/dist/utils/index.d.ts.map +1 -1
  160. package/dist/utils/index.js +2 -0
  161. package/dist/utils/index.js.map +1 -1
  162. package/dist/utils/omit.d.ts +2 -0
  163. package/dist/utils/omit.d.ts.map +1 -0
  164. package/dist/utils/omit.js +28 -0
  165. package/dist/utils/omit.js.map +1 -0
  166. package/dist/webpack/configs/loaders/style-loader.d.ts +1 -1
  167. package/dist/webpack/configs/loaders/style-loader.d.ts.map +1 -1
  168. package/dist/webpack/configs/loaders/style-loader.js +2 -2
  169. package/dist/webpack/configs/loaders/style-loader.js.map +1 -1
  170. package/dist/webpack/configs/optimization-config.js +5 -5
  171. package/dist/webpack/configs/optimization-config.js.map +1 -1
  172. package/dist/webpack/configs/output-config.d.ts.map +1 -1
  173. package/dist/webpack/configs/output-config.js +14 -7
  174. package/dist/webpack/configs/output-config.js.map +1 -1
  175. package/dist/webpack/configs/plugins/assets-manifest-plugin.d.ts.map +1 -1
  176. package/dist/webpack/configs/plugins/assets-manifest-plugin.js +10 -3
  177. package/dist/webpack/configs/plugins/assets-manifest-plugin.js.map +1 -1
  178. package/package.json +26 -20
  179. package/src/cli/commands/__tests__/build.test.ts +1 -1
  180. package/src/cli/commands/__tests__/bundle-package.test.ts +22 -2
  181. package/src/cli/commands/__tests__/install.test.ts +42 -4
  182. package/src/cli/commands/__tests__/lint.test.ts +1 -1
  183. package/src/cli/commands/__tests__/mfe-list.test.ts +394 -0
  184. package/src/cli/commands/__tests__/mfe-publish.test.ts +25 -0
  185. package/src/cli/commands/__tests__/start.test.ts +1 -1
  186. package/src/cli/commands/build.ts +14 -10
  187. package/src/cli/commands/bundle-package.ts +19 -13
  188. package/src/cli/commands/clean.ts +2 -4
  189. package/src/cli/commands/convert-eslint-config.ts +3 -5
  190. package/src/cli/commands/eslint.ts +3 -5
  191. package/src/cli/commands/get-command.ts +2 -0
  192. package/src/cli/commands/index.ts +0 -1
  193. package/src/cli/commands/init.ts +7 -8
  194. package/src/cli/commands/install.ts +24 -11
  195. package/src/cli/commands/kendo-ui-license.ts +4 -6
  196. package/src/cli/commands/lint.ts +19 -19
  197. package/src/cli/commands/mfe-list.ts +173 -0
  198. package/src/cli/commands/mfe-package-clean.ts +25 -4
  199. package/src/cli/commands/mfe-package-publish.ts +33 -4
  200. package/src/cli/commands/mfe-publish.ts +37 -6
  201. package/src/cli/commands/prepare-package.ts +3 -5
  202. package/src/cli/commands/review/review.ts +9 -9
  203. package/src/cli/commands/run-task.ts +15 -11
  204. package/src/cli/commands/start.ts +12 -10
  205. package/src/cli/commands/styles-check.ts +2 -2
  206. package/src/cli/commands/test/__tests__/tests.test.ts +1 -1
  207. package/src/cli/commands/test/runners/__tests__/vitest.test.ts +82 -13
  208. package/src/cli/commands/test/runners/vitest.ts +4 -2
  209. package/src/cli/commands/test/tests.ts +20 -10
  210. package/src/cli/commands/types.ts +14 -4
  211. package/src/cli/commands/upload-sourcemaps.ts +3 -5
  212. package/src/cli/index.ts +59 -36
  213. package/src/cli/tasks/swc-compile-package.ts +2 -2
  214. package/src/cli/tasks/tsc-compile-package.ts +4 -3
  215. package/src/cli/tasks/tsc-compile.ts +2 -2
  216. package/src/cli/utils/__tests__/bundle.test.ts +13 -0
  217. package/src/cli/utils/__tests__/cli-npm.test.ts +89 -0
  218. package/src/cli/utils/__tests__/is-tty.test.ts +17 -0
  219. package/src/cli/utils/__tests__/maybe-create-git-folder.test.ts +10 -17
  220. package/src/cli/utils/__tests__/set-node-options.test.ts +10 -10
  221. package/src/cli/utils/bundle.ts +2 -2
  222. package/src/cli/utils/cli-npm.ts +34 -0
  223. package/src/cli/utils/cli-os.ts +12 -25
  224. package/src/cli/utils/eslint.ts +2 -1
  225. package/src/cli/utils/index.ts +1 -0
  226. package/src/cli/utils/is-tty.ts +3 -0
  227. package/src/cli/utils/maybe-create-git-folder.ts +10 -8
  228. package/src/cli/utils/process-tree.ts +4 -2
  229. package/src/cli/utils/set-node-options.ts +2 -1
  230. package/src/utils/__tests__/format-relative-date.test.ts +61 -0
  231. package/src/utils/__tests__/get-jest-config.test.ts +44 -0
  232. package/src/utils/__tests__/get-packages.test.ts +3 -0
  233. package/src/utils/find-packages.ts +1 -0
  234. package/src/utils/format-relative-date.ts +33 -0
  235. package/src/utils/get-configuration.ts +7 -2
  236. package/src/utils/get-jest-config.ts +36 -18
  237. package/src/utils/get-packages.ts +3 -9
  238. package/src/utils/get-startup-version.ts +1 -3
  239. package/src/utils/index.ts +2 -0
  240. package/src/utils/omit.ts +12 -0
  241. package/src/webpack/__mocks__/style-rules.ts +3 -3
  242. package/src/webpack/__tests__/create-webpack-config-shared-dependencies.test.ts +6 -14
  243. package/src/webpack/__tests__/create-webpack-config-web-component.test.ts +52 -29
  244. package/src/webpack/configs/loaders/style-loader.ts +5 -2
  245. package/src/webpack/configs/optimization-config.ts +5 -5
  246. package/src/webpack/configs/output-config.ts +10 -5
  247. package/src/webpack/configs/plugins/assets-manifest-plugin.ts +11 -4
  248. package/dist/cli/commands/get-user-commands.d.ts +0 -7
  249. package/dist/cli/commands/get-user-commands.d.ts.map +0 -1
  250. package/dist/cli/commands/get-user-commands.js +0 -27
  251. package/dist/cli/commands/get-user-commands.js.map +0 -1
  252. package/src/cli/commands/__tests__/get-user-commands.test.ts +0 -27
  253. package/src/cli/commands/get-user-commands.ts +0 -19
@@ -66,6 +66,10 @@ describe(`[startup] Test ${Vitest.name}`, () => {
66
66
  expect(vitest.close).toHaveBeenCalled();
67
67
  });
68
68
 
69
+ function expectCallsVitestWithConfig(config: Record<string, any>) {
70
+ expect(startVitest).toHaveBeenCalledWith('test', [], {}, { test: config });
71
+ }
72
+
69
73
  describe('with package.json config', () => {
70
74
  const packageJSONConfig: ViteUserConfig['test'] = { bail: 1, globals: false };
71
75
 
@@ -78,19 +82,40 @@ describe(`[startup] Test ${Vitest.name}`, () => {
78
82
  test('merges package.json config with default config', async () => {
79
83
  await subject();
80
84
 
81
- expect(startVitest).toHaveBeenCalledWith(
82
- 'test',
83
- [],
84
- {},
85
- { test: { ...defaultConfig, ...packageJSONConfig } }
86
- );
85
+ expectCallsVitestWithConfig({ ...defaultConfig, ...packageJSONConfig });
86
+ });
87
+
88
+ describe('with omitDefault', () => {
89
+ beforeEach(() => {
90
+ vol.fromJSON({
91
+ 'package.json': JSON.stringify({
92
+ cli: {
93
+ vitest: {
94
+ ...packageJSONConfig,
95
+ omitDefault: ['coverage.include', 'environment'],
96
+ },
97
+ },
98
+ }),
99
+ });
100
+ });
101
+
102
+ test('omits specified defaults', async () => {
103
+ await subject();
104
+
105
+ const { environment, coverage, ...restDefault } = defaultConfig;
106
+ const { include, ...restCoverage } = coverage as any;
107
+ const defaultSansOmitted = { coverage: restCoverage, ...restDefault };
108
+
109
+ expectCallsVitestWithConfig({ ...defaultSansOmitted, ...packageJSONConfig });
110
+ });
87
111
  });
88
112
  });
89
113
 
90
114
  describe('with vite test config', () => {
91
- const viteTestConfig: ViteUserConfig['test'] = { name: 'foo', watch: false };
115
+ let viteTestConfig: NonNullable<ViteUserConfig['test']>;
92
116
 
93
117
  beforeEach(() => {
118
+ viteTestConfig = { name: 'foo', watch: false };
94
119
  jest.mocked(resolveConfig).mockResolvedValue({
95
120
  viteConfig: { test: viteTestConfig },
96
121
  } as any);
@@ -99,13 +124,57 @@ describe(`[startup] Test ${Vitest.name}`, () => {
99
124
  test('merges vite test config with default config', async () => {
100
125
  await subject();
101
126
 
102
- expect(startVitest).toHaveBeenCalledWith(
103
- 'test',
104
- [],
105
- {},
106
- { test: { ...defaultConfig, ...viteTestConfig } }
107
- );
127
+ expectCallsVitestWithConfig({ ...defaultConfig, ...viteTestConfig });
108
128
  });
129
+
130
+ describe('with "coverage.include"', () => {
131
+ const defaultCoverageInclude = (defaultConfig.coverage as any).include;
132
+ const include = ['packages/foo'];
133
+
134
+ beforeEach(() => {
135
+ Object.assign(viteTestConfig, {
136
+ coverage: { include },
137
+ });
138
+ });
139
+
140
+ test('merges default and custom "coverage.include"', async () => {
141
+ await subject();
142
+
143
+ expectCallsVitestWithConfig(
144
+ expect.objectContaining({
145
+ coverage: {
146
+ ...defaultConfig.coverage,
147
+ include: [...defaultCoverageInclude, ...include],
148
+ },
149
+ })
150
+ );
151
+ });
152
+
153
+ describe('when omitDefault contains "coverage.include"', () => {
154
+ beforeEach(() => {
155
+ vol.fromJSON({
156
+ 'package.json': JSON.stringify({
157
+ cli: { vitest: { omitDefault: ['coverage.include'] } },
158
+ }),
159
+ });
160
+ });
161
+
162
+ test('omits default "coverage.include"', async () => {
163
+ await subject();
164
+
165
+ expectCallsVitestWithConfig(
166
+ expect.objectContaining({
167
+ coverage: {
168
+ ...defaultConfig.coverage,
169
+ include,
170
+ },
171
+ })
172
+ );
173
+ });
174
+ });
175
+ });
176
+
177
+ test('can use omitDefault to replace coverage.include', () => {});
109
178
  });
110
179
 
111
180
  describe('with command line options', () => {
@@ -1,6 +1,6 @@
1
1
  import { configDefaults, coverageConfigDefaults, mergeConfig, ViteUserConfig } from 'vitest/config';
2
2
  import { startVitest, parseCLI, resolveConfig } from 'vitest/node';
3
- import { getVitestConfiguration, log } from '../../../../utils';
3
+ import { getVitestConfiguration, log, omit } from '../../../../utils';
4
4
 
5
5
  type VitestConfig = NonNullable<ViteUserConfig['test']>;
6
6
 
@@ -58,8 +58,10 @@ function getDefaultConfig(): VitestConfig {
58
58
  async function getUserConfig(): Promise<ViteUserConfig> {
59
59
  const { viteConfig } = await resolveConfig();
60
60
 
61
+ const { omitDefault = [], ...config } = getVitestConfiguration();
62
+
61
63
  const result = mergeConfig(
62
- mergeConfig(getDefaultConfig(), getVitestConfiguration()),
64
+ mergeConfig(omit(getDefaultConfig(), omitDefault), config),
63
65
  viteConfig.test ?? {}
64
66
  );
65
67
 
@@ -1,3 +1,4 @@
1
+ /* eslint-disable @typescript-eslint/naming-convention */
1
2
  import { Config } from '@jest/types';
2
3
  import { getConfiguration, logErrors } from '../../../utils';
3
4
  import { Command } from '../types';
@@ -5,26 +6,35 @@ import { Jest, Vitest } from './runners';
5
6
 
6
7
  type Args = Config.Argv & {
7
8
  runner?: 'jest' | 'vitest';
9
+ runnerArgs?: string[];
8
10
  };
9
11
 
10
12
  /**
11
13
  * This class is named "Tests" instead of "Test" because the corresponding
12
14
  * "test.ts" would be interpreted as a test file.
13
15
  */
14
- export class Tests implements Command {
15
- readonly greedy = true;
16
-
17
- constructor(private readonly args: Args) {}
18
-
19
- description() {
20
- return 'run tests';
21
- }
16
+ export class Tests extends Command<Args> {
17
+ static readonly description = 'Run tests';
18
+ static readonly greedy = true;
19
+ static readonly options = {
20
+ _: { description: '[runnerArgs...]' },
21
+ runner: {
22
+ choices: ['jest', 'vitest'],
23
+ description: 'Test runner',
24
+ defaultDescription: 'jest',
25
+ },
26
+ };
22
27
 
23
28
  @logErrors
24
29
  async execute() {
25
- const { runner = getConfiguration().testRunner ?? 'jest', ...restArgs } = this.args;
30
+ const {
31
+ _,
32
+ runner = getConfiguration().testRunner ?? 'jest',
33
+ runnerArgs = [],
34
+ ...restOptions
35
+ } = this.args;
26
36
  if (runner === 'jest') {
27
- await new Jest(restArgs).run();
37
+ await new Jest({ _: [..._, ...runnerArgs], ...restOptions }).run();
28
38
  } else if (runner === 'vitest') {
29
39
  await new Vitest().run();
30
40
  } else {
@@ -1,7 +1,17 @@
1
- export interface Command {
2
- greedy?: boolean;
3
- execute(): Promise<void>;
4
- description?(): string;
1
+ import type { Options } from 'yargs';
2
+
3
+ export interface CommandArgs {
4
+ [key: string]: unknown;
5
+ }
6
+
7
+ export abstract class Command<T extends CommandArgs = CommandArgs> {
8
+ static readonly description?: string;
9
+ static readonly greedy?: boolean;
10
+ static readonly options?: { [key: string]: Options };
11
+
12
+ constructor(protected readonly args: T) {}
13
+
14
+ abstract execute(): Promise<void>;
5
15
  }
6
16
 
7
17
  export type Newable<T> = new (...args: any[]) => T;
@@ -2,9 +2,9 @@ import path from 'path';
2
2
  import { execSync } from 'child_process';
3
3
  import { getTsConfig, isWebComponent, log, logErrors, readJson } from '../../utils';
4
4
  import { isCI, TSConfig } from '../utils';
5
- import { Command } from './types';
5
+ import { Command, CommandArgs } from './types';
6
6
 
7
- interface Args {
7
+ interface Args extends CommandArgs {
8
8
  dry?: boolean;
9
9
  releaseVersion: string;
10
10
  }
@@ -13,12 +13,10 @@ interface PackageJson {
13
13
  name: string;
14
14
  }
15
15
 
16
- export class UploadSourcemaps implements Command {
16
+ export class UploadSourcemaps extends Command<Args> {
17
17
  #outDir?: string;
18
18
  #packageJson?: PackageJson;
19
19
 
20
- constructor(private readonly args: Args) {}
21
-
22
20
  @logErrors
23
21
  // eslint-disable-next-line @typescript-eslint/require-await
24
22
  async execute() {
package/src/cli/index.ts CHANGED
@@ -1,49 +1,72 @@
1
+ import chalk from 'chalk';
1
2
  import execa from 'execa';
2
3
  import path from 'path';
3
- import { argv, Arguments } from 'yargs';
4
+ import yargs from 'yargs';
5
+ import { hideBin } from 'yargs/helpers';
4
6
  import { CommandName, getStartupVersion, log } from '../utils';
5
- import { getCommand, getUserCommands } from './commands';
7
+ import { Command, getCommand } from './commands';
6
8
  import { maybeCreateGitFolder, setNodeOptions } from './utils';
7
9
 
8
- const argvSync = argv as Arguments;
9
- const name = argvSync._[0]?.toString() as CommandName;
10
- if (!name) {
11
- log.info(`startup cli v${getStartupVersion()}`);
12
- usage();
13
- process.exit(0);
14
- }
10
+ Object.values(CommandName)
11
+ .reduce((y, name) => addCommand(name, y), yargs(hideBin(process.argv)))
12
+ .usage('Usage: startup <command> [options]')
13
+ .epilogue(
14
+ chalk.bold.cyan(`startup cli v${getStartupVersion()}\n`) +
15
+ `Run ${chalk.bold.cyan('startup <command> --help')} to see command options.\n` +
16
+ `For detailed documentation, see ${chalk.bold.cyan('https://docs.st.dev/docs/frontend/uikit/startup')}.\n`
17
+ )
18
+ .demandCommand(1, '')
19
+ .strictCommands()
20
+ .updateStrings({
21
+ 'Unknown command: %s': {
22
+ one: chalk.bold.red('Unknown command: %s'),
23
+ other: chalk.bold.red('Unknown command: %s'),
24
+ } as any,
25
+ })
26
+ .version()
27
+ .wrap(Math.min(100, yargs.terminalWidth()))
28
+ .help()
29
+ .parse();
15
30
 
16
- const Command = getCommand(name);
17
- if (!Command) {
18
- log.error(`Unknown command: "${name}"`);
19
- usage();
20
- process.exit(127);
31
+ function addCommand(name: CommandName, y: typeof yargs) {
32
+ const klass = getCommand(name)! as typeof Command;
33
+ // eslint-disable-next-line @typescript-eslint/naming-convention
34
+ const { description, options: { _, ...options } = {} } = klass;
35
+ const nameWithArgs = name + (_?.description ? ` ${_.description}` : '');
36
+ const groupedOptions = Object.entries(options).reduce(
37
+ (result, [key, value]) => {
38
+ result[key] = { group: 'Command Options:', ...value };
39
+ return result;
40
+ },
41
+ {} as NonNullable<typeof klass.options>
42
+ );
43
+ const handler = (argv: any) => handleCommand(name, argv);
44
+ if (description) {
45
+ y.command(nameWithArgs, description, groupedOptions, handler);
46
+ } else {
47
+ y.command(nameWithArgs, false, groupedOptions, handler);
48
+ }
49
+ return y;
21
50
  }
22
51
 
23
- checkNodeVersion();
24
- maybeCreateGitFolder(Command);
52
+ function handleCommand(name: CommandName, argv: any) {
53
+ const Command = getCommand(name)!;
25
54
 
26
- // eslint-disable-next-line @typescript-eslint/naming-convention
27
- const command = new Command({ ...argvSync, _: argvSync._.slice(1) });
28
- if (setNodeOptions(name, command)) {
29
- log.debug('run', `Running ${name} in child process with amended NODE_OPTIONS`);
30
- execa(process.argv[0], process.argv.slice(1), { stdio: 'inherit' }).catch(reason => {
31
- process.exit(reason.exitCode);
32
- });
33
- } else {
34
- command.execute().catch(() => {
35
- process.exit(1);
36
- });
37
- }
38
-
39
- function usage() {
40
- log.text('\nUsage:');
55
+ checkNodeVersion();
56
+ maybeCreateGitFolder(Command);
41
57
 
42
- const commands = getUserCommands().filter(({ name }) => !!name);
43
- const maxNameLength = commands.reduce((result, { name }) => Math.max(result, name.length), 0);
44
- commands.forEach(({ name, description }) => {
45
- log.text(`startup ${name.padEnd(maxNameLength, ' ')} ${description}`);
46
- });
58
+ // eslint-disable-next-line @typescript-eslint/naming-convention
59
+ const command = new Command({ ...argv, _: argv._.slice(1) });
60
+ if (setNodeOptions(name, command)) {
61
+ log.debug('run', `Running ${name} in child process with amended NODE_OPTIONS`);
62
+ execa(process.argv[0], process.argv.slice(1), { stdio: 'inherit' }).catch(reason => {
63
+ process.exit(reason.exitCode);
64
+ });
65
+ } else {
66
+ command.execute().catch(() => {
67
+ process.exit(1);
68
+ });
69
+ }
47
70
  }
48
71
 
49
72
  function checkNodeVersion() {
@@ -3,11 +3,11 @@ import debounce from 'debounce';
3
3
  import deepmerge from 'deepmerge';
4
4
 
5
5
  import { getFolders, getSwcCompilePackageConfiguration, getTsConfig, log } from '../../utils';
6
+ import { CommandArgs } from '../commands';
6
7
  import { TSConfig } from '../utils';
7
8
  import { Task } from './task';
8
9
 
9
- interface Args {
10
- [key: string]: unknown;
10
+ interface Args extends CommandArgs {
11
11
  watch?: boolean;
12
12
  }
13
13
 
@@ -1,7 +1,8 @@
1
- import { CliTask } from './cli-task';
2
1
  import { getTsConfig } from '../../utils';
3
- interface Args {
4
- [key: string]: unknown;
2
+ import { CommandArgs } from '../commands';
3
+ import { CliTask } from './cli-task';
4
+
5
+ interface Args extends CommandArgs {
5
6
  watch?: boolean;
6
7
  }
7
8
 
@@ -1,8 +1,8 @@
1
1
  import { getPackages, getPackagesGraph, getTsConfig, log, Package, PackageType } from '../../utils';
2
+ import { CommandArgs } from '../commands';
2
3
  import { CliTask } from './cli-task';
3
4
 
4
- interface Args {
5
- [key: string]: unknown;
5
+ interface Args extends CommandArgs {
6
6
  ignore?: string | string[];
7
7
  scope?: string | string[];
8
8
  watch?: boolean;
@@ -368,6 +368,19 @@ describe('[startup] Cli Utils', () => {
368
368
  });
369
369
  });
370
370
  });
371
+
372
+ describe('with "useWatchConfig"', () => {
373
+ beforeEach(() => (options = { useWatchConfig: true }));
374
+
375
+ test('sets mode to "development"', async () => {
376
+ await subject();
377
+
378
+ expect(createWebpackConfig).toHaveBeenCalledWith(
379
+ { configuration: { mode: 'development' } },
380
+ expect.anything()
381
+ );
382
+ });
383
+ });
371
384
  });
372
385
 
373
386
  describe(`${bundle.name} (watch mode)`, () => {
@@ -7,6 +7,8 @@ import {
7
7
  npmPublish,
8
8
  npmTagVersion,
9
9
  npmUnpublish,
10
+ npmView,
11
+ npmWhoAmI,
10
12
  } from '../cli-npm';
11
13
 
12
14
  jest.mock('../cli-os', () => ({
@@ -202,4 +204,91 @@ describe('[startup] Cli Utils (Npm)', () => {
202
204
  );
203
205
  });
204
206
  });
207
+
208
+ describe(npmView.name, () => {
209
+ const packageInfo = { name: 'foo', version: '1.0.0', versions: [], time: {} };
210
+ let args: Parameters<typeof npmView>[0];
211
+
212
+ beforeEach(() => {
213
+ args = { packageName: '{packageName}' };
214
+ jest.mocked(runCommandOutput).mockReturnValue(JSON.stringify(packageInfo));
215
+ });
216
+
217
+ const subject = () => npmView(args);
218
+
219
+ itRunsCommandOutput(subject, 'npm view --json {packageName}', {
220
+ quiet: true,
221
+ timeout: 10000,
222
+ });
223
+
224
+ test('returns package info', () => {
225
+ expect(subject()).toEqual(packageInfo);
226
+ });
227
+
228
+ describe('with a registry', () => {
229
+ beforeEach(() => (args.registry = '{registry}'));
230
+
231
+ itRunsCommandOutput(
232
+ subject,
233
+ 'npm view --json --registry={registry} {packageName}',
234
+ expect.anything()
235
+ );
236
+ });
237
+
238
+ describe('when command fails', () => {
239
+ const error = new Error('Oops!');
240
+
241
+ beforeEach(() => {
242
+ jest.mocked(runCommandOutput).mockImplementation(() => {
243
+ throw error;
244
+ });
245
+ });
246
+
247
+ test('returns undefined', () => {
248
+ expect(subject()).toBeUndefined();
249
+ });
250
+ });
251
+ });
252
+
253
+ describe(npmWhoAmI.name, () => {
254
+ const username = 'Foo\n';
255
+ let args: Parameters<typeof npmWhoAmI>[0];
256
+
257
+ beforeEach(() => {
258
+ args = undefined;
259
+ jest.mocked(runCommandOutput).mockReturnValue(username);
260
+ });
261
+
262
+ const subject = () => npmWhoAmI(args);
263
+
264
+ itRunsCommandOutput(subject, 'npm whoami', {
265
+ quiet: true,
266
+ stdio: ['pipe', 'pipe', 'ignore'],
267
+ timeout: 10000,
268
+ });
269
+
270
+ test('returns trimmed username ', () => {
271
+ expect(subject()).toEqual(username.trim());
272
+ });
273
+
274
+ describe('with registry', () => {
275
+ beforeEach(() => (args = { registry: '{registry}' }));
276
+
277
+ itRunsCommandOutput(subject, 'npm whoami --registry={registry}', expect.anything());
278
+ });
279
+
280
+ describe('when command fails', () => {
281
+ const error = new Error('Oops');
282
+
283
+ beforeEach(() => {
284
+ jest.mocked(runCommandOutput).mockImplementation(() => {
285
+ throw error;
286
+ });
287
+ });
288
+
289
+ test('ignores error and returns undefined', () => {
290
+ expect(subject()).toBeUndefined();
291
+ });
292
+ });
293
+ });
205
294
  });
@@ -0,0 +1,17 @@
1
+ import { isTTY } from '../is-tty';
2
+
3
+ describe(`[startup] Utils ${isTTY.name}`, () => {
4
+ const originalIsTTY = process.stdin.isTTY;
5
+
6
+ afterAll(() => process.stdin.isTTY === originalIsTTY);
7
+
8
+ const subject = () => isTTY();
9
+
10
+ describe.each([true, false])('when process.stdin.isTTY is %s', value => {
11
+ beforeEach(() => (process.stdin.isTTY = value));
12
+
13
+ test(`returns ${value}`, () => {
14
+ expect(subject()).toBe(value);
15
+ });
16
+ });
17
+ });
@@ -2,6 +2,7 @@ import { fs, vol } from 'memfs';
2
2
 
3
3
  import { maybeCreateGitFolder } from '../maybe-create-git-folder';
4
4
  import { Init } from '../../commands/init';
5
+ import { Install } from '../../commands/install';
5
6
  import { Start } from '../../commands/start';
6
7
 
7
8
  jest.mock('fs', () => fs);
@@ -28,28 +29,20 @@ describe(`[startup] Utils`, () => {
28
29
  });
29
30
  }
30
31
 
31
- describe('when running on Windows', () => {
32
- beforeEach(() => {
33
- Object.defineProperty(process, 'platform', { value: 'win32' });
34
- });
35
-
36
- test('creates .git folder', () => {
37
- subject();
32
+ test('creates .git folder', () => {
33
+ subject();
38
34
 
39
- expect(mkdirSpy).toHaveBeenCalledWith('.git');
40
- });
35
+ expect(mkdirSpy).toHaveBeenCalledWith('.git', { recursive: true });
36
+ });
41
37
 
42
- describe('when command is Init', () => {
43
- beforeEach(() => (command = Init));
38
+ describe('when command is Init', () => {
39
+ beforeEach(() => (command = Init));
44
40
 
45
- itDoesNotCreateGitFolder();
46
- });
41
+ itDoesNotCreateGitFolder();
47
42
  });
48
43
 
49
- describe('when not running on Windows', () => {
50
- beforeEach(() => {
51
- Object.defineProperty(process, 'platform', { value: 'linux' });
52
- });
44
+ describe('when command is Install', () => {
45
+ beforeEach(() => (command = Install));
53
46
 
54
47
  itDoesNotCreateGitFolder();
55
48
  });
@@ -1,6 +1,6 @@
1
1
  import os from 'os';
2
2
  import { getConfigurationSafe } from '../../../utils';
3
- import { Command } from '../../commands';
3
+ import { Command } from '../../commands/types';
4
4
 
5
5
  import { setNodeOptions } from '../set-node-options';
6
6
 
@@ -13,15 +13,11 @@ jest.mock('../../../utils', () => ({
13
13
  getConfigurationSafe: jest.fn(() => ({})),
14
14
  }));
15
15
 
16
- class MockCommand implements Command {
17
- get greedy() {
16
+ class MockCommand extends Command {
17
+ static get greedy() {
18
18
  return true;
19
19
  }
20
20
 
21
- description() {
22
- return 'mock command';
23
- }
24
-
25
21
  async execute() {
26
22
  return Promise.resolve();
27
23
  }
@@ -33,12 +29,16 @@ describe(`[startup] utils:${setNodeOptions.name}`, () => {
33
29
  const originalNodeOptions = process.env.NODE_OPTIONS;
34
30
  const maxOldSpaceSize = `--max_old_space_size=${DEFAULT_SIZE}`;
35
31
  const commandName: any = 'mock';
36
- const command = new MockCommand();
32
+ const command = new MockCommand({});
33
+ let greedy: boolean;
37
34
 
38
35
  beforeEach(() => {
36
+ greedy = true;
39
37
  delete process.env.NODE_OPTIONS;
40
38
  (os.totalmem as jest.Mock).mockReturnValue(16384 * MB);
41
- jest.spyOn(command, 'greedy', 'get').mockReturnValue(true);
39
+ jest.spyOn(command.constructor as typeof Command, 'greedy', 'get').mockImplementation(
40
+ () => greedy
41
+ );
42
42
  });
43
43
 
44
44
  afterAll(() => (process.env.NODE_OPTIONS = originalNodeOptions));
@@ -52,7 +52,7 @@ describe(`[startup] utils:${setNodeOptions.name}`, () => {
52
52
  });
53
53
 
54
54
  describe('when the command is not greedy', () => {
55
- beforeEach(() => jest.spyOn(command, 'greedy', 'get').mockReturnValue(false));
55
+ beforeEach(() => (greedy = false));
56
56
 
57
57
  test('returns false and does not set NODE_OPTIONS', () => {
58
58
  expect(subject()).toBe(false);
@@ -52,7 +52,7 @@ export async function bundle(options: Options = {}) {
52
52
 
53
53
  log.info(`Bundling ${emitExposedDependencies ? 'exposed dependencies' : 'package'}...`);
54
54
 
55
- const mode = watch ? 'development' : 'production';
55
+ const mode = watch || useWatchConfig ? 'development' : 'production';
56
56
  const fallback = watch || useWatchConfig ? webpackDevConfigFileName : webpackProdConfigFileName;
57
57
  const customConfig = readWebpackConfig({ ...options, fallback });
58
58
  const webpackOptions = getWebpackOptions(options, customConfig);
@@ -180,7 +180,7 @@ async function runWatch(config: Configuration) {
180
180
  return new Promise<void>((_0, reject) => {
181
181
  const watching = compiler.watch({}, e => {
182
182
  if (e) {
183
- watching.close(() => {
183
+ watching?.close(() => {
184
184
  reject(e);
185
185
  });
186
186
  }