@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
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@servicetitan/startup",
3
- "version": "32.2.0",
3
+ "version": "32.3.0",
4
4
  "description": "",
5
5
  "homepage": "https://docs.st.dev/docs/frontend/startup",
6
6
  "repository": {
@@ -25,6 +25,7 @@
25
25
  "bin": "./bin/index.js",
26
26
  "devDependencies": {
27
27
  "@types/cpx": "~1.5.5",
28
+ "@types/debug": "^4.1.12",
28
29
  "@types/eslint": "~9.6.1",
29
30
  "@types/less": "~3.0.8",
30
31
  "@types/lodash.memoize": "^4.1.9",
@@ -33,26 +34,26 @@
33
34
  "@types/yargs": "~17.0.24"
34
35
  },
35
36
  "dependencies": {
36
- "@babel/preset-env": "~7.28.3",
37
+ "@babel/preset-env": "~7.28.5",
37
38
  "@jest/core": "~29.7.0",
38
39
  "@jest/types": "~29.6.3",
39
40
  "@jsdevtools/coverage-istanbul-loader": "^3.0.5",
40
- "@servicetitan/eslint-config": "32.2.0",
41
- "@servicetitan/stylelint-config": "32.2.0",
41
+ "@servicetitan/eslint-config": "32.3.0",
42
+ "@servicetitan/stylelint-config": "32.3.0",
42
43
  "@svgr/webpack": "^8.1.0",
43
44
  "@swc/cli": "^0.5.0",
44
45
  "@swc/core": "1.13.5",
45
- "@types/debug": "^4.1.12",
46
46
  "@types/jest": "~29.5.12",
47
47
  "@vitest/coverage-v8": "^3.2.4",
48
48
  "chalk": "~4.1.2",
49
+ "cli-table3": "^0.6.5",
49
50
  "cpx2": "8.0.0",
50
51
  "css-loader": "~7.1.2",
51
52
  "css-minimizer-webpack-plugin": "^7.0.2",
52
53
  "debounce": "^2.2.0",
53
54
  "debug": "^4.4.3",
54
55
  "deepmerge": "~4.3.1",
55
- "eslint": "~9.37.0",
56
+ "eslint": "~9.38.0",
56
57
  "execa": "~5.1.1",
57
58
  "glob": "~11.0.3",
58
59
  "html-webpack-plugin": "~5.6.4",
@@ -77,7 +78,7 @@
77
78
  "postcss": "~8.5.6",
78
79
  "prettier": "~3.6.2",
79
80
  "sass": "~1.93.2",
80
- "sass-loader": "~16.0.5",
81
+ "sass-loader": "~16.0.6",
81
82
  "semver": "~7.7.3",
82
83
  "source-map-loader": "~5.0.0",
83
84
  "style-loader": "~4.0.0",
@@ -125,5 +126,5 @@
125
126
  "cli": {
126
127
  "webpack": false
127
128
  },
128
- "gitHead": "76a83fea33e04809b97c72720751878b1e3002d7"
129
+ "gitHead": "201392862b3cb12500b3c8c4f6310b101b87201b"
129
130
  }
@@ -61,7 +61,7 @@ describe(`[startup] ${Build.name}`, () => {
61
61
  }
62
62
 
63
63
  test('command is greedy', () => {
64
- expect(new Build(args).greedy).toBe(true);
64
+ expect(Build.greedy).toBe(true);
65
65
  });
66
66
 
67
67
  test('selects TSC and Webpack packages', async () => {
@@ -46,6 +46,16 @@ describe(`[startup] ${BundlePackage.name}`, () => {
46
46
  });
47
47
  });
48
48
 
49
+ describe('with "code-coverage"', () => {
50
+ beforeEach(() => (args.codeCoverage = true));
51
+
52
+ test('bundles with code coverage', async () => {
53
+ await subject();
54
+
55
+ expect(bundle).toHaveBeenCalledWith(expect.objectContaining({ codeCoverage: true }));
56
+ });
57
+ });
58
+
49
59
  describe('with "config"', () => {
50
60
  beforeEach(() => (args.config = 'foo.config.js'));
51
61
 
@@ -56,7 +66,7 @@ describe(`[startup] ${BundlePackage.name}`, () => {
56
66
  });
57
67
 
58
68
  describe('with "exposed-dependencies"', () => {
59
- beforeEach(() => (args['exposed-dependencies'] = true));
69
+ beforeEach(() => (args.exposedDependencies = true));
60
70
 
61
71
  test('ignores config file', async () => {
62
72
  await subject();
@@ -69,7 +79,7 @@ describe(`[startup] ${BundlePackage.name}`, () => {
69
79
  });
70
80
 
71
81
  describe('with "exposed-dependencies"', () => {
72
- beforeEach(() => (args['exposed-dependencies'] = true));
82
+ beforeEach(() => (args.exposedDependencies = true));
73
83
 
74
84
  test('bundles exposed dependencies', async () => {
75
85
  await subject();
@@ -102,6 +112,16 @@ describe(`[startup] ${BundlePackage.name}`, () => {
102
112
  });
103
113
  });
104
114
 
115
+ describe('with "use-watch-config"', () => {
116
+ beforeEach(() => (args.useWatchConfig = true));
117
+
118
+ test('bundles package with useWatchConfig', async () => {
119
+ await subject();
120
+
121
+ expect(bundle).toHaveBeenCalledWith(expect.objectContaining({ useWatchConfig: true }));
122
+ });
123
+ });
124
+
105
125
  describe('when tsconfig\'s compilerOptions.module is not "esnext"', () => {
106
126
  beforeEach(() => {
107
127
  vol.fromJSON({
@@ -1,7 +1,7 @@
1
1
  import { vol, fs } from 'memfs';
2
2
  import { execSync } from 'child_process';
3
3
  import { getStartupVersion, log } from '../../../utils';
4
- import { gitCloneRepo, isCI } from '../../utils';
4
+ import { gitCloneRepo, isCI, npmWhoAmI } from '../../utils';
5
5
 
6
6
  import { Install } from '../install';
7
7
 
@@ -11,6 +11,7 @@ jest.mock('../../utils', () => ({
11
11
  ...jest.requireActual('../../utils'),
12
12
  gitCloneRepo: jest.fn(),
13
13
  isCI: jest.fn(),
14
+ npmWhoAmI: jest.fn(),
14
15
  }));
15
16
  jest.mock('../../../utils', () => ({
16
17
  ...jest.requireActual('../../../utils'),
@@ -37,11 +38,12 @@ describe(`${Install.name}`, () => {
37
38
  }
38
39
 
39
40
  beforeEach(() => {
40
- args = undefined;
41
+ args = {};
41
42
  jest.clearAllMocks();
42
43
  jest.mocked(gitCloneRepo).mockResolvedValue(true);
43
44
  jest.mocked(getStartupVersion).mockReturnValue(startupVersion);
44
45
  jest.mocked(isCI).mockReturnValue(false);
46
+ jest.mocked(npmWhoAmI).mockReturnValue(undefined);
45
47
  jest.spyOn(fs, 'mkdtempSync').mockImplementation(() => tempDirPath);
46
48
  volFromJSON();
47
49
  });
@@ -105,7 +107,11 @@ describe(`${Install.name}`, () => {
105
107
  test('does not configure NPM token', async () => {
106
108
  await subject();
107
109
 
108
- expect(execSync).not.toHaveBeenCalledWith(expect.stringMatching(/npm config/));
110
+ expect(gitCloneRepo).not.toHaveBeenCalled();
111
+ expect(execSync).not.toHaveBeenCalledWith(
112
+ expect.stringMatching(/npm config/),
113
+ expect.anything()
114
+ );
109
115
  });
110
116
  }
111
117
 
@@ -113,10 +119,29 @@ describe(`${Install.name}`, () => {
113
119
  test('does not delete project token', async () => {
114
120
  await subject();
115
121
 
116
- expect(execSync).not.toHaveBeenCalledWith(expect.stringMatching(/npm config delete/));
122
+ expect(execSync).not.toHaveBeenCalledWith(
123
+ expect.stringMatching(/npm config delete/),
124
+ expect.anything()
125
+ );
117
126
  });
118
127
  }
119
128
 
129
+ describe('when "st-team" is already logged in', () => {
130
+ beforeEach(() => jest.mocked(npmWhoAmI).mockReturnValue('st-team'));
131
+
132
+ itDoesNotConfigureNpmToken();
133
+
134
+ describe('with --token', () => {
135
+ beforeEach(() => (args = { token: true }));
136
+
137
+ test('configures NPM token', async () => {
138
+ await subject();
139
+
140
+ expect(execSync).toHaveBeenCalledWith(expect.stringMatching(/npm config set/));
141
+ });
142
+ });
143
+ });
144
+
120
145
  describe('when .npmrc uses an environment variable', () => {
121
146
  beforeEach(() => {
122
147
  volFromJSON({
@@ -195,6 +220,19 @@ describe(`${Install.name}`, () => {
195
220
  itDoesNotConfigureNpmToken();
196
221
  });
197
222
 
223
+ describe('with --token', () => {
224
+ beforeEach(() => (args = { token: true }));
225
+
226
+ test('does not run "npm i"', async () => {
227
+ await subject();
228
+
229
+ expect(execSync).not.toHaveBeenCalledWith(
230
+ expect.stringMatching(/npm i/),
231
+ expect.anything()
232
+ );
233
+ });
234
+ });
235
+
198
236
  function itLogsError(message: string | RegExp) {
199
237
  test('logs error', async () => {
200
238
  await subject();
@@ -39,7 +39,7 @@ describe(`[startup] ${Lint.name}`, () => {
39
39
  });
40
40
 
41
41
  test('command is greedy', () => {
42
- expect(new Lint(args).greedy).toBe(true);
42
+ expect(Lint.greedy).toBe(true);
43
43
  });
44
44
 
45
45
  test('runs eslint directly', async () => {
@@ -0,0 +1,394 @@
1
+ import chalk from 'chalk';
2
+ import Table from 'cli-table3';
3
+ import { fs, vol } from 'memfs';
4
+ import { createInterface } from 'readline/promises';
5
+ import { formatRelativeDate, toArray } from '../../../utils';
6
+ import { isTTY, npmView, npmWhoAmI, runCommand } from '../../utils';
7
+ import { MFEList } from '../mfe-list';
8
+
9
+ jest.mock('cli-table3');
10
+ jest.mock('fs', () => fs);
11
+ jest.mock('readline/promises', () => ({
12
+ createInterface: jest.fn(),
13
+ }));
14
+ jest.mock('../../utils', () => ({
15
+ ...jest.requireActual('../../utils'),
16
+ isTTY: jest.fn(),
17
+ npmView: jest.fn(),
18
+ npmWhoAmI: jest.fn(),
19
+ runCommand: jest.fn(),
20
+ }));
21
+
22
+ describe(`[startup] ${MFEList.name}`, () => {
23
+ const DEFAULT_LIMIT = 20;
24
+ const TOTAL_VERSIONS = DEFAULT_LIMIT + 1;
25
+ const mfeName = 'foo';
26
+ let distTags: Record<string, string>;
27
+ let time: Record<string, string>;
28
+ let args: ConstructorParameters<typeof MFEList>[0];
29
+
30
+ function volFromJSON(overrides: Record<string, any> = {}) {
31
+ vol.fromJSON({
32
+ 'package.json': JSON.stringify({ workspaces: ['packages/*'] }),
33
+ 'packages/lib/package.json': JSON.stringify({ name: 'lib' }),
34
+ 'packages/mfe/package.json': JSON.stringify({
35
+ name: mfeName,
36
+ cli: { 'web-component': true },
37
+ }),
38
+ ...overrides,
39
+ });
40
+ }
41
+
42
+ beforeEach(() => {
43
+ const versions = Array.from(new Array(TOTAL_VERSIONS), makeVersion);
44
+ time = versions.reduce<Record<string, string>>((result, version, index) => {
45
+ result[version] = hourAgo(index + 1).toISOString();
46
+ return result;
47
+ }, {});
48
+ distTags = {
49
+ dev: versions[0],
50
+ other: versions[0], // version with multiple tags
51
+ qa: versions[5],
52
+ stage: versions[10],
53
+ prod: versions[15],
54
+ latest: versions[DEFAULT_LIMIT],
55
+ };
56
+ args = { _: [] }; // eslint-disable-line @typescript-eslint/naming-convention
57
+ jest.clearAllMocks();
58
+ jest.spyOn(process.stdout, 'write').mockImplementation(jest.fn()); // suppress output
59
+ jest.mocked(npmWhoAmI).mockReturnValue('Foo');
60
+ jest.mocked(npmView).mockImplementation(({ packageName }) => ({
61
+ 'name': packageName,
62
+ 'version': distTags?.latest,
63
+ 'dist-tags': distTags,
64
+ 'time': {
65
+ created: hourAgo(24).toDateString(),
66
+ modified: new Date().toISOString(),
67
+ ...time,
68
+ },
69
+ }));
70
+ volFromJSON();
71
+ });
72
+
73
+ afterEach(() => vol.reset());
74
+
75
+ const subject = () => new MFEList(args).execute();
76
+
77
+ function hourAgo(count: number) {
78
+ const date = new Date();
79
+ date.setHours(date.getHours() - count);
80
+ return date;
81
+ }
82
+
83
+ function makeVersion() {
84
+ const hash = Math.floor(Math.random() * 1e8).toString(16);
85
+ return `0.0.0-master.${hash}`;
86
+ }
87
+
88
+ interface ExpectTableInfo {
89
+ name: string;
90
+ tags: Record<string, string>;
91
+ versions: [string, string][];
92
+ }
93
+
94
+ function expectCaption({
95
+ name,
96
+ version,
97
+ total,
98
+ }: {
99
+ name: string;
100
+ version?: string;
101
+ total: number;
102
+ }) {
103
+ const caption = [
104
+ chalk.bold.cyan(name),
105
+ version && `version: ${version}`,
106
+ `versions: ${total}`,
107
+ ]
108
+ .filter(el => !!el)
109
+ .join(' | ');
110
+
111
+ expect(jest.mocked(process.stdout.write)).toHaveBeenCalledWith(caption + '\n');
112
+ }
113
+
114
+ function expectTable(info: ExpectTableInfo | ExpectTableInfo[]) {
115
+ if (Array.isArray(info) && info.length === 0) {
116
+ expect(jest.mocked(Table).mock.instances).toHaveLength(0);
117
+ return;
118
+ }
119
+
120
+ toArray(info).forEach(({ name, tags, versions }, index) => {
121
+ const table = jest.mocked(Table).mock.instances[index];
122
+ const pushes = jest.mocked(table.push).mock.calls.map((...args) => args[0][0]);
123
+
124
+ const versionTags = Object.entries(tags).reduce<Record<string, string[]>>(
125
+ (result, [tag, version]) => {
126
+ result[version] = [...(result[version] ?? []), tag];
127
+ return result;
128
+ },
129
+ {}
130
+ );
131
+
132
+ expectCaption({ name, version: tags.latest, total: TOTAL_VERSIONS });
133
+
134
+ expect(pushes).toEqual([
135
+ ...versions.map(([version, when]) => [
136
+ version,
137
+ versionTags[version] ? chalk.bold.cyan(versionTags[version].join(', ')) : '',
138
+ formatRelativeDate(when),
139
+ ]),
140
+ ]);
141
+ });
142
+ }
143
+
144
+ function itOmitsTable() {
145
+ test('omits table', async () => {
146
+ await subject();
147
+
148
+ expectTable([]);
149
+ });
150
+ }
151
+
152
+ test(`outputs table with last ${DEFAULT_LIMIT} published versions`, async () => {
153
+ await subject();
154
+
155
+ expect(Table).toHaveBeenCalledWith({
156
+ head: ['Version', 'Tag', 'When'].map(title => chalk.bold.cyan(title)),
157
+ style: { head: [] },
158
+ });
159
+
160
+ expectTable({
161
+ name: mfeName,
162
+ tags: distTags,
163
+ versions: Object.entries(time).slice(0, DEFAULT_LIMIT),
164
+ });
165
+ });
166
+
167
+ describe('when MFE has no versions', () => {
168
+ beforeEach(() => {
169
+ jest.mocked(npmView).mockImplementation(
170
+ ({ packageName }) => ({ name: packageName }) as any
171
+ );
172
+ });
173
+
174
+ itOmitsTable();
175
+ });
176
+
177
+ describe('when MFE has no "latest" tag', () => {
178
+ beforeEach(() => delete distTags.latest);
179
+
180
+ test('outputs table', async () => {
181
+ await subject();
182
+
183
+ expectTable({
184
+ name: mfeName,
185
+ tags: distTags,
186
+ versions: Object.entries(time).slice(0, DEFAULT_LIMIT),
187
+ });
188
+ });
189
+ });
190
+
191
+ describe('with --tagged', () => {
192
+ beforeEach(() => (args.tagged = true));
193
+
194
+ test('outputs only tagged versions', async () => {
195
+ await subject();
196
+
197
+ expectTable({
198
+ name: mfeName,
199
+ tags: distTags,
200
+ versions: [...new Set(Object.values(distTags))].map(version => [
201
+ version,
202
+ time[version],
203
+ ]),
204
+ });
205
+ });
206
+
207
+ describe('when MFE has no tags', () => {
208
+ beforeEach(() => ((distTags as any) = undefined));
209
+
210
+ itOmitsTable();
211
+ });
212
+ });
213
+
214
+ describe('with --registry', () => {
215
+ beforeEach(() => (args.registry = 'https://verdaccio.st.dev'));
216
+
217
+ test('passes registry to npmView', async () => {
218
+ await subject();
219
+
220
+ expect(npmView).toHaveBeenCalledWith({
221
+ packageName: mfeName,
222
+ registry: args.registry,
223
+ });
224
+ });
225
+ });
226
+
227
+ describe('with --all', () => {
228
+ beforeEach(() => (args.all = true));
229
+
230
+ test('outputs all published versions', async () => {
231
+ await subject();
232
+
233
+ expectTable([
234
+ {
235
+ name: mfeName,
236
+ tags: distTags,
237
+ versions: Object.entries(time),
238
+ },
239
+ ]);
240
+ });
241
+ });
242
+
243
+ describe('with --limit', () => {
244
+ beforeEach(() => (args.limit = 5));
245
+
246
+ test('outputs specified number of versions', async () => {
247
+ await subject();
248
+
249
+ expectTable([
250
+ {
251
+ name: mfeName,
252
+ tags: distTags,
253
+ versions: Object.entries(time).slice(0, args.limit),
254
+ },
255
+ ]);
256
+ });
257
+ });
258
+
259
+ describe('when workspace has no MFEs', () => {
260
+ beforeEach(() => vol.reset());
261
+
262
+ itOmitsTable();
263
+ });
264
+
265
+ describe('when workspace has multiple MFEs', () => {
266
+ const otherMfeName = `${mfeName}2`; // ensure sorts after first name
267
+
268
+ beforeEach(() => {
269
+ volFromJSON({
270
+ 'packages/mfe2/package.json': JSON.stringify({
271
+ name: otherMfeName,
272
+ cli: { 'web-component': true },
273
+ }),
274
+ });
275
+ });
276
+
277
+ test('outputs published versions for all MFEs', async () => {
278
+ await subject();
279
+
280
+ expectTable([
281
+ {
282
+ name: mfeName,
283
+ tags: distTags,
284
+ versions: Object.entries(time).slice(0, DEFAULT_LIMIT),
285
+ },
286
+ {
287
+ name: otherMfeName,
288
+ tags: distTags,
289
+ versions: Object.entries(time).slice(0, DEFAULT_LIMIT),
290
+ },
291
+ ]);
292
+ });
293
+
294
+ describe('with MFE name', () => {
295
+ beforeEach(() => (args._ = [otherMfeName]));
296
+
297
+ test('outputs only specified MFE', async () => {
298
+ await subject();
299
+
300
+ expectTable({
301
+ name: otherMfeName,
302
+ tags: distTags,
303
+ versions: Object.entries(time).slice(0, DEFAULT_LIMIT),
304
+ });
305
+ });
306
+ });
307
+
308
+ describe('with --ignore', () => {
309
+ beforeEach(() => (args.ignore = mfeName));
310
+
311
+ test('omits specified MFE', async () => {
312
+ await subject();
313
+
314
+ expectTable({
315
+ name: otherMfeName,
316
+ tags: distTags,
317
+ versions: Object.entries(time).slice(0, DEFAULT_LIMIT),
318
+ });
319
+ });
320
+ });
321
+
322
+ describe('with non-existent MFE name', () => {
323
+ beforeEach(() => {
324
+ jest.mocked(npmView).mockReturnValue(undefined);
325
+ });
326
+
327
+ itOmitsTable();
328
+ });
329
+ });
330
+
331
+ describe('when machine is not authorized', () => {
332
+ const readline = { question: jest.fn(), close: jest.fn() };
333
+ let answer: string;
334
+
335
+ beforeEach(() => {
336
+ answer = 'Y';
337
+ jest.mocked(readline.question).mockImplementation(() => Promise.resolve(answer));
338
+ jest.mocked(createInterface).mockReturnValue(readline as any);
339
+ jest.mocked(npmWhoAmI).mockReturnValue(undefined);
340
+ jest.mocked(isTTY).mockReturnValue(true);
341
+ });
342
+
343
+ test('prompts and authorizes machine', async () => {
344
+ await subject();
345
+
346
+ expect(readline.question).toHaveBeenCalledWith(
347
+ expect.stringMatching(/machine is not authorized.*Authorize\? \[Y\/n\]/)
348
+ );
349
+ expect(readline.close).toHaveBeenCalled();
350
+ expect(runCommand).toHaveBeenCalledWith(
351
+ 'npx --yes verdaccio-okta-oauth@latest --registry=https://verdaccio.servicetitan.com',
352
+ { quiet: true }
353
+ );
354
+ });
355
+
356
+ describe('when user does not answer', () => {
357
+ beforeEach(() => (answer = ''));
358
+
359
+ test('authorizes machine', async () => {
360
+ await subject();
361
+
362
+ expect(runCommand).toHaveBeenCalled();
363
+ });
364
+ });
365
+
366
+ describe('when user declines', () => {
367
+ beforeEach(() => (answer = 'n'));
368
+
369
+ test('throws error', async () => {
370
+ await expect(subject()).rejects.toThrow(/Not authorized/);
371
+ });
372
+ });
373
+
374
+ describe('when terminal is not interactive', () => {
375
+ beforeEach(() => jest.mocked(isTTY).mockReturnValue(false));
376
+
377
+ test('skips prompt and throws error', async () => {
378
+ await expect(subject()).rejects.toThrow(/machine is not authorized/);
379
+
380
+ expect(readline.question).not.toHaveBeenCalled();
381
+ });
382
+ });
383
+
384
+ describe('with --registry', () => {
385
+ beforeEach(() => (args.registry = 'https://verdaccio.st.dev'));
386
+
387
+ test('skips check whether machine is authorized', async () => {
388
+ await subject();
389
+
390
+ expect(npmWhoAmI).not.toHaveBeenCalled();
391
+ });
392
+ });
393
+ });
394
+ });
@@ -3,6 +3,8 @@ import { lernaExec } from '../../utils';
3
3
  import { Package, PackageType, getPackages } from '../../../utils';
4
4
  import { createPackage } from '../../../__mocks__';
5
5
 
6
+ import { MFEPackageClean } from '../mfe-package-clean';
7
+ import { MFEPackagePublish } from '../mfe-package-publish';
6
8
  import { MFEPublish } from '../mfe-publish';
7
9
 
8
10
  jest.mock('fs', () => fs);
@@ -209,4 +211,27 @@ describe(`[startup] ${MFEPublish.name}`, () => {
209
211
  });
210
212
  });
211
213
  });
214
+
215
+ describe('options', () => {
216
+ const subject = () => MFEPublish.options;
217
+
218
+ test('groups publish and clean options', () => {
219
+ expect(subject()).toEqual(
220
+ expect.objectContaining({
221
+ ...Object.fromEntries(
222
+ Object.entries(MFEPackagePublish.options).map(([key, value]) => [
223
+ key,
224
+ { group: 'Publish Options:', ...value },
225
+ ])
226
+ ),
227
+ ...Object.fromEntries(
228
+ Object.entries(MFEPackageClean.options).map(([key, value]) => [
229
+ Object.hasOwn(MFEPackagePublish.options, key) ? `${key}\u00A0` : key,
230
+ { group: 'Clean Options:', ...value },
231
+ ])
232
+ ),
233
+ })
234
+ );
235
+ });
236
+ });
212
237
  });
@@ -83,7 +83,7 @@ describe(`[startup] ${Start.name}`, () => {
83
83
  }
84
84
 
85
85
  test('command is greedy', () => {
86
- expect(new Start(args).greedy).toBe(true);
86
+ expect(Start.greedy).toBe(true);
87
87
  });
88
88
 
89
89
  describe('with TSC package', () => {