@servicetitan/startup 32.2.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 (239) 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/tests.d.ts +14 -5
  81. package/dist/cli/commands/test/tests.d.ts.map +1 -1
  82. package/dist/cli/commands/test/tests.js +26 -13
  83. package/dist/cli/commands/test/tests.js.map +1 -1
  84. package/dist/cli/commands/types.d.ts +13 -4
  85. package/dist/cli/commands/types.d.ts.map +1 -1
  86. package/dist/cli/commands/types.js +28 -0
  87. package/dist/cli/commands/types.js.map +1 -1
  88. package/dist/cli/commands/upload-sourcemaps.d.ts +3 -5
  89. package/dist/cli/commands/upload-sourcemaps.d.ts.map +1 -1
  90. package/dist/cli/commands/upload-sourcemaps.js +5 -20
  91. package/dist/cli/commands/upload-sourcemaps.js.map +1 -1
  92. package/dist/cli/index.js +48 -39
  93. package/dist/cli/index.js.map +1 -1
  94. package/dist/cli/tasks/swc-compile-package.d.ts +2 -2
  95. package/dist/cli/tasks/swc-compile-package.d.ts.map +1 -1
  96. package/dist/cli/tasks/swc-compile-package.js.map +1 -1
  97. package/dist/cli/tasks/tsc-compile-package.d.ts +2 -2
  98. package/dist/cli/tasks/tsc-compile-package.d.ts.map +1 -1
  99. package/dist/cli/tasks/tsc-compile-package.js +1 -1
  100. package/dist/cli/tasks/tsc-compile-package.js.map +1 -1
  101. package/dist/cli/tasks/tsc-compile.d.ts +2 -2
  102. package/dist/cli/tasks/tsc-compile.d.ts.map +1 -1
  103. package/dist/cli/tasks/tsc-compile.js.map +1 -1
  104. package/dist/cli/utils/bundle.js +1 -1
  105. package/dist/cli/utils/bundle.js.map +1 -1
  106. package/dist/cli/utils/cli-npm.d.ts +14 -0
  107. package/dist/cli/utils/cli-npm.d.ts.map +1 -1
  108. package/dist/cli/utils/cli-npm.js +44 -0
  109. package/dist/cli/utils/cli-npm.js.map +1 -1
  110. package/dist/cli/utils/cli-os.d.ts +2 -2
  111. package/dist/cli/utils/cli-os.d.ts.map +1 -1
  112. package/dist/cli/utils/cli-os.js +13 -9
  113. package/dist/cli/utils/cli-os.js.map +1 -1
  114. package/dist/cli/utils/eslint.d.ts +2 -1
  115. package/dist/cli/utils/eslint.d.ts.map +1 -1
  116. package/dist/cli/utils/eslint.js.map +1 -1
  117. package/dist/cli/utils/index.d.ts +1 -0
  118. package/dist/cli/utils/index.d.ts.map +1 -1
  119. package/dist/cli/utils/index.js +1 -0
  120. package/dist/cli/utils/index.js.map +1 -1
  121. package/dist/cli/utils/is-tty.d.ts +2 -0
  122. package/dist/cli/utils/is-tty.d.ts.map +1 -0
  123. package/dist/cli/utils/is-tty.js +15 -0
  124. package/dist/cli/utils/is-tty.js.map +1 -0
  125. package/dist/cli/utils/maybe-create-git-folder.d.ts +1 -1
  126. package/dist/cli/utils/maybe-create-git-folder.d.ts.map +1 -1
  127. package/dist/cli/utils/maybe-create-git-folder.js +5 -5
  128. package/dist/cli/utils/maybe-create-git-folder.js.map +1 -1
  129. package/dist/cli/utils/process-tree.d.ts.map +1 -1
  130. package/dist/cli/utils/process-tree.js +2 -2
  131. package/dist/cli/utils/process-tree.js.map +1 -1
  132. package/dist/cli/utils/set-node-options.d.ts.map +1 -1
  133. package/dist/cli/utils/set-node-options.js +2 -1
  134. package/dist/cli/utils/set-node-options.js.map +1 -1
  135. package/dist/utils/find-packages.d.ts +1 -0
  136. package/dist/utils/find-packages.d.ts.map +1 -1
  137. package/dist/utils/find-packages.js.map +1 -1
  138. package/dist/utils/format-relative-date.d.ts +2 -0
  139. package/dist/utils/format-relative-date.d.ts.map +1 -0
  140. package/dist/utils/format-relative-date.js +60 -0
  141. package/dist/utils/format-relative-date.js.map +1 -0
  142. package/dist/utils/get-configuration.d.ts +1 -0
  143. package/dist/utils/get-configuration.d.ts.map +1 -1
  144. package/dist/utils/get-configuration.js +1 -0
  145. package/dist/utils/get-configuration.js.map +1 -1
  146. package/dist/utils/get-packages.d.ts +3 -5
  147. package/dist/utils/get-packages.d.ts.map +1 -1
  148. package/dist/utils/get-packages.js +1 -4
  149. package/dist/utils/get-packages.js.map +1 -1
  150. package/dist/utils/get-startup-version.d.ts.map +1 -1
  151. package/dist/utils/get-startup-version.js +1 -1
  152. package/dist/utils/get-startup-version.js.map +1 -1
  153. package/dist/utils/index.d.ts +1 -0
  154. package/dist/utils/index.d.ts.map +1 -1
  155. package/dist/utils/index.js +1 -0
  156. package/dist/utils/index.js.map +1 -1
  157. package/dist/webpack/configs/loaders/style-loader.d.ts +1 -1
  158. package/dist/webpack/configs/loaders/style-loader.d.ts.map +1 -1
  159. package/dist/webpack/configs/loaders/style-loader.js +2 -2
  160. package/dist/webpack/configs/loaders/style-loader.js.map +1 -1
  161. package/dist/webpack/configs/optimization-config.js +5 -5
  162. package/dist/webpack/configs/optimization-config.js.map +1 -1
  163. package/dist/webpack/configs/output-config.d.ts.map +1 -1
  164. package/dist/webpack/configs/output-config.js +14 -7
  165. package/dist/webpack/configs/output-config.js.map +1 -1
  166. package/dist/webpack/configs/plugins/assets-manifest-plugin.d.ts.map +1 -1
  167. package/dist/webpack/configs/plugins/assets-manifest-plugin.js +10 -3
  168. package/dist/webpack/configs/plugins/assets-manifest-plugin.js.map +1 -1
  169. package/package.json +9 -8
  170. package/src/cli/commands/__tests__/build.test.ts +1 -1
  171. package/src/cli/commands/__tests__/bundle-package.test.ts +22 -2
  172. package/src/cli/commands/__tests__/install.test.ts +42 -4
  173. package/src/cli/commands/__tests__/lint.test.ts +1 -1
  174. package/src/cli/commands/__tests__/mfe-list.test.ts +394 -0
  175. package/src/cli/commands/__tests__/mfe-publish.test.ts +25 -0
  176. package/src/cli/commands/__tests__/start.test.ts +1 -1
  177. package/src/cli/commands/build.ts +14 -10
  178. package/src/cli/commands/bundle-package.ts +19 -13
  179. package/src/cli/commands/clean.ts +2 -4
  180. package/src/cli/commands/convert-eslint-config.ts +3 -5
  181. package/src/cli/commands/eslint.ts +3 -5
  182. package/src/cli/commands/get-command.ts +2 -0
  183. package/src/cli/commands/index.ts +0 -1
  184. package/src/cli/commands/init.ts +7 -8
  185. package/src/cli/commands/install.ts +24 -11
  186. package/src/cli/commands/kendo-ui-license.ts +4 -6
  187. package/src/cli/commands/lint.ts +19 -19
  188. package/src/cli/commands/mfe-list.ts +173 -0
  189. package/src/cli/commands/mfe-package-clean.ts +25 -4
  190. package/src/cli/commands/mfe-package-publish.ts +33 -4
  191. package/src/cli/commands/mfe-publish.ts +37 -6
  192. package/src/cli/commands/prepare-package.ts +3 -5
  193. package/src/cli/commands/review/review.ts +9 -9
  194. package/src/cli/commands/run-task.ts +15 -11
  195. package/src/cli/commands/start.ts +12 -10
  196. package/src/cli/commands/styles-check.ts +2 -2
  197. package/src/cli/commands/test/__tests__/tests.test.ts +1 -1
  198. package/src/cli/commands/test/tests.ts +20 -10
  199. package/src/cli/commands/types.ts +14 -4
  200. package/src/cli/commands/upload-sourcemaps.ts +3 -5
  201. package/src/cli/index.ts +59 -36
  202. package/src/cli/tasks/swc-compile-package.ts +2 -2
  203. package/src/cli/tasks/tsc-compile-package.ts +4 -3
  204. package/src/cli/tasks/tsc-compile.ts +2 -2
  205. package/src/cli/utils/__tests__/bundle.test.ts +13 -0
  206. package/src/cli/utils/__tests__/cli-npm.test.ts +89 -0
  207. package/src/cli/utils/__tests__/is-tty.test.ts +17 -0
  208. package/src/cli/utils/__tests__/maybe-create-git-folder.test.ts +10 -17
  209. package/src/cli/utils/__tests__/set-node-options.test.ts +10 -10
  210. package/src/cli/utils/bundle.ts +1 -1
  211. package/src/cli/utils/cli-npm.ts +34 -0
  212. package/src/cli/utils/cli-os.ts +12 -25
  213. package/src/cli/utils/eslint.ts +2 -1
  214. package/src/cli/utils/index.ts +1 -0
  215. package/src/cli/utils/is-tty.ts +3 -0
  216. package/src/cli/utils/maybe-create-git-folder.ts +4 -7
  217. package/src/cli/utils/process-tree.ts +4 -2
  218. package/src/cli/utils/set-node-options.ts +2 -1
  219. package/src/utils/__tests__/format-relative-date.test.ts +61 -0
  220. package/src/utils/__tests__/get-packages.test.ts +3 -0
  221. package/src/utils/find-packages.ts +1 -0
  222. package/src/utils/format-relative-date.ts +33 -0
  223. package/src/utils/get-configuration.ts +1 -0
  224. package/src/utils/get-packages.ts +3 -9
  225. package/src/utils/get-startup-version.ts +1 -3
  226. package/src/utils/index.ts +1 -0
  227. package/src/webpack/__mocks__/style-rules.ts +3 -3
  228. package/src/webpack/__tests__/create-webpack-config-shared-dependencies.test.ts +6 -14
  229. package/src/webpack/__tests__/create-webpack-config-web-component.test.ts +52 -29
  230. package/src/webpack/configs/loaders/style-loader.ts +5 -2
  231. package/src/webpack/configs/optimization-config.ts +5 -5
  232. package/src/webpack/configs/output-config.ts +10 -5
  233. package/src/webpack/configs/plugins/assets-manifest-plugin.ts +11 -4
  234. package/dist/cli/commands/get-user-commands.d.ts +0 -7
  235. package/dist/cli/commands/get-user-commands.d.ts.map +0 -1
  236. package/dist/cli/commands/get-user-commands.js +0 -27
  237. package/dist/cli/commands/get-user-commands.js.map +0 -1
  238. package/src/cli/commands/__tests__/get-user-commands.test.ts +0 -27
  239. package/src/cli/commands/get-user-commands.ts +0 -19
@@ -1,6 +1,6 @@
1
1
  import { getPackages, isWebComponent, logErrors, PackageType } from '../../utils';
2
- import { Args as CleanArgs } from './mfe-package-clean';
3
- import { Args as PublishArgs } from './mfe-package-publish';
2
+ import { Args as CleanArgs, MFEPackageClean } from './mfe-package-clean';
3
+ import { Args as PublishArgs, MFEPackagePublish } from './mfe-package-publish';
4
4
  import { Command } from './types';
5
5
  import { lernaExec } from '../utils';
6
6
 
@@ -10,11 +10,42 @@ interface Args extends PublishArgs, CleanArgs {
10
10
  scope?: string | string[];
11
11
  }
12
12
 
13
- export class MFEPublish implements Command {
14
- constructor(private readonly args: Args) {}
13
+ export class MFEPublish extends Command<Args> {
14
+ static readonly description = 'Publish or unpublish MFE packages';
15
+ static get options() {
16
+ const publishOptions = Object.entries(MFEPackagePublish.options).reduce(
17
+ (result, [key, value]) => {
18
+ result[key] = { group: 'Publish Options:', ...value };
19
+ return result;
20
+ },
21
+ {} as NonNullable<typeof Command.options>
22
+ );
23
+
24
+ const cleanOptions = Object.entries(MFEPackageClean.options).reduce(
25
+ (result, [key, value]) => {
26
+ result[Object.hasOwn(publishOptions, key) ? `${key}\u00A0` : key] = {
27
+ group: 'Clean Options:',
28
+ ...value,
29
+ };
30
+ return result;
31
+ },
32
+ {} as NonNullable<typeof Command.options>
33
+ );
15
34
 
16
- description() {
17
- return 'publish or unpublish MFE packages';
35
+ return {
36
+ clean: { boolean: true, description: 'Unpublish old versions' },
37
+ concurrency: {
38
+ number: true,
39
+ description: 'Publish/unpublish the specified number of packages concurrently',
40
+ defaultDescription: '1',
41
+ },
42
+ scope: {
43
+ array: true,
44
+ description: 'Publish/unpublish only the specified packages',
45
+ },
46
+ ...publishOptions,
47
+ ...cleanOptions,
48
+ };
18
49
  }
19
50
 
20
51
  @logErrors
@@ -1,14 +1,12 @@
1
1
  import { logErrors } from '../../utils';
2
2
  import { copyFiles } from '../utils';
3
- import { Command } from './types';
3
+ import { Command, CommandArgs } from './types';
4
4
 
5
- interface Args {
5
+ interface Args extends CommandArgs {
6
6
  watch?: boolean;
7
7
  }
8
8
 
9
- export class PreparePackage implements Command {
10
- constructor(private readonly args: Args) {}
11
-
9
+ export class PreparePackage extends Command<Args> {
12
10
  @logErrors
13
11
  execute() {
14
12
  return copyFiles({ watch: this.args.watch });
@@ -9,7 +9,7 @@ import {
9
9
  readJsonSafe,
10
10
  toArray,
11
11
  } from '../../../utils';
12
- import { Command } from '../types';
12
+ import { Command, CommandArgs } from '../types';
13
13
 
14
14
  import {
15
15
  ErrorSeverity,
@@ -33,12 +33,18 @@ import { rules } from './rules';
33
33
 
34
34
  const collator = new Intl.Collator();
35
35
 
36
- interface Args {
36
+ interface Args extends CommandArgs {
37
37
  fix?: boolean;
38
38
  rule?: string | string[];
39
39
  }
40
40
 
41
- export class Review implements Command {
41
+ export class Review extends Command<Args> {
42
+ static readonly description = 'Check project for configuration errors';
43
+ static readonly options = {
44
+ fix: { boolean: true, description: 'Fix detected problems' },
45
+ rule: { array: true, description: 'Limit checks to specified rule(s)' },
46
+ };
47
+
42
48
  private readonly severityToLabel: Record<ErrorSeverity, string> = {
43
49
  [ErrorSeverity.warning]: chalk.yellow('warning'),
44
50
  [ErrorSeverity.error]: chalk.red('error'),
@@ -49,12 +55,6 @@ export class Review implements Command {
49
55
  error: ErrorSeverity.error,
50
56
  };
51
57
 
52
- constructor(private readonly args: Args) {}
53
-
54
- description() {
55
- return 'check project for configuration errors';
56
- }
57
-
58
58
  @logErrors
59
59
  async execute() {
60
60
  const errors = this.args.fix ? this.fixErrors() : this.findErrors();
@@ -1,33 +1,37 @@
1
+ /* eslint-disable @typescript-eslint/naming-convention */
1
2
  import { log, logErrors } from '../../utils';
2
- import { Command } from './types';
3
3
  import { SwcCompilePackage } from '../tasks/swc-compile-package';
4
4
  import { TscCompilePackage } from '../tasks/tsc-compile-package';
5
5
  import { TscCompile } from '../tasks/tsc-compile';
6
6
  import { Task } from '../tasks/task';
7
+ import { Command, CommandArgs } from './types';
7
8
 
8
- interface Args {
9
- [key: string]: unknown;
10
- // eslint-disable-next-line @typescript-eslint/naming-convention
9
+ interface Args extends CommandArgs {
11
10
  _: string[];
11
+ taskName?: string;
12
+ taskArgs?: string[];
12
13
  }
13
14
 
14
- const tasks: Record<string, new (args: Args) => Task> = {
15
+ const tasks: Record<string, new (args: { [key: string]: unknown }) => Task> = {
15
16
  'tsc-compile-package': TscCompilePackage,
16
17
  'swc-compile-package': SwcCompilePackage,
17
18
  'tsc-compile': TscCompile,
18
19
  };
19
20
 
20
- export class RunTask implements Command {
21
- constructor(private readonly args: Args) {}
21
+ export class RunTask extends Command<Args> {
22
+ static readonly options = {
23
+ _: { description: '<taskName> [taskArgs...]' },
24
+ };
22
25
 
23
26
  @logErrors
24
27
  async execute() {
25
- const taskName = this.args._[0];
28
+ const { _, taskName = this.args._[0], taskArgs = [], ...restOptions } = this.args;
26
29
 
27
30
  if (taskName in tasks) {
28
- // eslint-disable-next-line @typescript-eslint/naming-convention
29
- const trimArgs = { ...this.args, _: this.args._.slice(1) };
30
- await new tasks[taskName](trimArgs).execute();
31
+ await new tasks[taskName]({
32
+ _: [..._, ...taskArgs],
33
+ ...restOptions,
34
+ }).execute();
31
35
  return;
32
36
  }
33
37
 
@@ -8,9 +8,9 @@ import {
8
8
  watchStdout,
9
9
  ProcessTree,
10
10
  } from '../utils';
11
- import { Command } from './types';
11
+ import { Command, CommandArgs } from './types';
12
12
 
13
- interface Args {
13
+ interface Args extends CommandArgs {
14
14
  'config'?: string;
15
15
  'code-coverage'?: boolean;
16
16
  'ignore'?: string | string[];
@@ -28,14 +28,16 @@ enum StartProcesses {
28
28
  BundlePackage,
29
29
  }
30
30
 
31
- export class Start implements Command {
32
- readonly greedy = true;
33
-
34
- constructor(private readonly args: Args) {}
35
-
36
- description() {
37
- return 'run project in development mode';
38
- }
31
+ export class Start extends Command<Args> {
32
+ static readonly description = 'Run project in development mode';
33
+ static readonly greedy = true;
34
+ static readonly options = {
35
+ 'config': { string: true, hidden: true, description: 'Use specified configuration' },
36
+ 'code-coverage': { boolean: true, description: 'Instrument code for coverage analysis?' },
37
+ 'ignore': { array: true, description: 'Packages to skip' },
38
+ 'scope': { array: true, description: 'Packages to run and watch' },
39
+ 'use-tsc': { boolean: true, description: 'Use tsc to compile packages?' },
40
+ };
39
41
 
40
42
  @logErrors
41
43
  async execute() {
@@ -2,7 +2,7 @@ import fs from 'fs';
2
2
  import { glob } from 'glob';
3
3
  import path from 'path';
4
4
  import { getFolders, isBundle, isLegacy, isStyleCheckDisabled, log, logErrors } from '../../utils';
5
- import { Command } from './index';
5
+ import { Command } from './types';
6
6
 
7
7
  const patterns = [
8
8
  "@import '~@servicetitan/tokens/core/tokens.css';",
@@ -10,7 +10,7 @@ const patterns = [
10
10
  "@import '~@servicetitan/design-system/dist/system.min.css';",
11
11
  ];
12
12
 
13
- export class StylesCheck implements Command {
13
+ export class StylesCheck extends Command {
14
14
  @logErrors
15
15
  async execute() {
16
16
  if (isLegacy() || !isBundle()) {
@@ -23,7 +23,7 @@ describe(`[startup] ${Tests.name}`, () => {
23
23
  const subject = async () => new Tests(args).execute();
24
24
 
25
25
  test('command is greedy', () => {
26
- expect(new Tests(args).greedy).toBe(true);
26
+ expect(Tests.greedy).toBe(true);
27
27
  });
28
28
 
29
29
  function itRunsJest() {
@@ -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', { recursive: true });
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
  });