@form8ion/javascript 15.5.0 → 15.6.1

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 (259) hide show
  1. package/lib/index.js +2 -2
  2. package/lib/index.js.map +1 -1
  3. package/package.json +4 -3
  4. package/src/code-style/index.js +3 -0
  5. package/src/code-style/lifter.js +6 -0
  6. package/src/code-style/lifter.test.js +25 -0
  7. package/src/code-style/remark/index.js +3 -0
  8. package/src/code-style/remark/lifter.js +10 -0
  9. package/src/code-style/remark/lifter.test.js +28 -0
  10. package/src/code-style/remark/scaffolder.js +38 -0
  11. package/src/code-style/remark/scaffolder.test.js +102 -0
  12. package/src/code-style/remark/tester.js +11 -0
  13. package/src/code-style/remark/tester.test.js +46 -0
  14. package/src/code-style/scaffolder.js +26 -0
  15. package/src/code-style/scaffolder.test.js +87 -0
  16. package/src/code-style/tester.js +5 -0
  17. package/src/code-style/tester.test.js +23 -0
  18. package/src/corepack/index.js +1 -0
  19. package/src/corepack/lifter.js +5 -0
  20. package/src/corepack/lifter.test.js +22 -0
  21. package/src/coverage/index.js +3 -0
  22. package/src/coverage/lifter.js +31 -0
  23. package/src/coverage/lifter.test.js +58 -0
  24. package/src/coverage/nyc/index.js +2 -0
  25. package/src/coverage/nyc/remover.js +16 -0
  26. package/src/coverage/nyc/remover.test.js +24 -0
  27. package/src/coverage/nyc/tester.js +5 -0
  28. package/src/coverage/nyc/tester.test.js +29 -0
  29. package/src/coverage/scaffolder.js +7 -0
  30. package/src/coverage/scaffolder.test.js +32 -0
  31. package/src/coverage/tester.js +10 -0
  32. package/src/coverage/tester.test.js +50 -0
  33. package/src/dependencies/index.js +3 -0
  34. package/src/dependencies/installer.js +25 -0
  35. package/src/dependencies/installer.test.js +77 -0
  36. package/src/dependencies/package-managers.js +32 -0
  37. package/src/dependencies/package-managers.test.js +46 -0
  38. package/src/dependencies/processor.js +30 -0
  39. package/src/dependencies/processor.test.js +75 -0
  40. package/src/dependencies/remover.js +10 -0
  41. package/src/dependencies/remover.test.js +28 -0
  42. package/src/dialects/babel/config/ignore-adder.js +10 -0
  43. package/src/dialects/babel/config/ignore-adder.test.js +33 -0
  44. package/src/dialects/babel/config/index.js +3 -0
  45. package/src/dialects/babel/config/loader.js +5 -0
  46. package/src/dialects/babel/config/loader.test.js +21 -0
  47. package/src/dialects/babel/config/writer.js +6 -0
  48. package/src/dialects/babel/config/writer.test.js +20 -0
  49. package/src/dialects/babel/index.js +3 -0
  50. package/src/dialects/babel/lifter.js +7 -0
  51. package/src/dialects/babel/lifter.test.js +17 -0
  52. package/src/dialects/babel/predicate.js +5 -0
  53. package/src/dialects/babel/predicate.test.js +25 -0
  54. package/src/dialects/babel/scaffolder.js +14 -0
  55. package/src/dialects/babel/scaffolder.test.js +28 -0
  56. package/src/dialects/index.js +2 -0
  57. package/src/dialects/prompt-choices.js +10 -0
  58. package/src/dialects/prompt-choices.test.js +28 -0
  59. package/src/dialects/scaffolder.js +15 -0
  60. package/src/dialects/scaffolder.test.js +49 -0
  61. package/src/dialects/typescript/index.js +1 -0
  62. package/src/dialects/typescript/scaffolder.js +31 -0
  63. package/src/dialects/typescript/scaffolder.test.js +95 -0
  64. package/src/documentation/generation-command.js +11 -0
  65. package/src/documentation/generation-command.test.js +25 -0
  66. package/src/documentation/index.js +1 -0
  67. package/src/documentation/scaffolder.js +20 -0
  68. package/src/documentation/scaffolder.test.js +49 -0
  69. package/src/engines/index.js +2 -0
  70. package/src/engines/lifter.js +7 -0
  71. package/src/engines/lifter.test.js +18 -0
  72. package/src/engines/tester.js +7 -0
  73. package/src/engines/tester.test.js +37 -0
  74. package/src/index.js +9 -0
  75. package/src/lifter.js +55 -0
  76. package/src/lifter.test.js +96 -0
  77. package/src/linting/index.js +1 -0
  78. package/src/linting/scaffolder.js +5 -0
  79. package/src/linting/scaffolder.test.js +31 -0
  80. package/src/lockfile-lint/allowed-hosts-builder.js +6 -0
  81. package/src/lockfile-lint/allowed-hosts-builder.test.js +35 -0
  82. package/src/lockfile-lint/config.js +12 -0
  83. package/src/lockfile-lint/config.test.js +37 -0
  84. package/src/lockfile-lint/index.js +3 -0
  85. package/src/lockfile-lint/scaffolder.js +38 -0
  86. package/src/lockfile-lint/scaffolder.test.js +85 -0
  87. package/src/lockfile-lint/tester.js +5 -0
  88. package/src/lockfile-lint/tester.test.js +25 -0
  89. package/src/node-version/index.js +2 -0
  90. package/src/node-version/scaffolder.js +19 -0
  91. package/src/node-version/scaffolder.test.js +33 -0
  92. package/src/node-version/tasks.js +25 -0
  93. package/src/node-version/tasks.test.js +43 -0
  94. package/src/node-version/tester.js +5 -0
  95. package/src/node-version/tester.test.js +29 -0
  96. package/src/npm-config/index.js +5 -0
  97. package/src/npm-config/lifter.js +14 -0
  98. package/src/npm-config/lifter.test.js +23 -0
  99. package/src/npm-config/reader.js +11 -0
  100. package/src/npm-config/reader.test.js +33 -0
  101. package/src/npm-config/scaffolder.js +16 -0
  102. package/src/npm-config/scaffolder.test.js +54 -0
  103. package/src/npm-config/tester.js +5 -0
  104. package/src/npm-config/tester.test.js +29 -0
  105. package/src/npm-config/writer.js +6 -0
  106. package/src/npm-config/writer.test.js +24 -0
  107. package/src/options/schemas.js +14 -0
  108. package/src/options/schemas.test.js +147 -0
  109. package/src/options/validator.js +45 -0
  110. package/src/options/validator.test.js +79 -0
  111. package/src/package/details.js +18 -0
  112. package/src/package/details.test.js +51 -0
  113. package/src/package/index.js +2 -0
  114. package/src/package/lifter.js +47 -0
  115. package/src/package/lifter.test.js +100 -0
  116. package/src/package/package-name.js +13 -0
  117. package/src/package/package-name.test.js +52 -0
  118. package/src/package/property-sorter.js +38 -0
  119. package/src/package/property-sorter.test.js +56 -0
  120. package/src/package/scaffolder.js +32 -0
  121. package/src/package/scaffolder.test.js +46 -0
  122. package/src/package/scripts/index.js +1 -0
  123. package/src/package/scripts/lifter.js +14 -0
  124. package/src/package/scripts/lifter.test.js +31 -0
  125. package/src/package/scripts/script-comparator.js +46 -0
  126. package/src/package/scripts/script-comparator.test.js +119 -0
  127. package/src/package/scripts/scripts-sorter.js +7 -0
  128. package/src/package/scripts/scripts-sorter.test.js +20 -0
  129. package/src/package/scripts/test-script-updater.js +15 -0
  130. package/src/package/scripts/test-script-updater.test.js +32 -0
  131. package/src/package/vcs-host-details.js +12 -0
  132. package/src/package/vcs-host-details.test.js +16 -0
  133. package/src/package-managers/current-manager-resolver.js +21 -0
  134. package/src/package-managers/current-manager-resolver.test.js +51 -0
  135. package/src/package-managers/index.js +5 -0
  136. package/src/package-managers/lifter.js +7 -0
  137. package/src/package-managers/lifter.test.js +18 -0
  138. package/src/package-managers/lockfile-path-resolver.js +10 -0
  139. package/src/package-managers/lockfile-path-resolver.test.js +15 -0
  140. package/src/package-managers/npm/index.js +2 -0
  141. package/src/package-managers/npm/scaffolder.js +19 -0
  142. package/src/package-managers/npm/scaffolder.test.js +33 -0
  143. package/src/package-managers/npm/tester.js +11 -0
  144. package/src/package-managers/npm/tester.test.js +33 -0
  145. package/src/package-managers/scaffolder.js +11 -0
  146. package/src/package-managers/scaffolder.test.js +27 -0
  147. package/src/package-managers/tester.js +11 -0
  148. package/src/package-managers/tester.test.js +33 -0
  149. package/src/package-managers/yarn/index.js +2 -0
  150. package/src/package-managers/yarn/scaffolder.js +19 -0
  151. package/src/package-managers/yarn/scaffolder.test.js +33 -0
  152. package/src/package-managers/yarn/tester.js +11 -0
  153. package/src/package-managers/yarn/tester.test.js +33 -0
  154. package/src/plugins-schemas.js +4 -0
  155. package/src/plugins-schemas.test.js +28 -0
  156. package/src/project-type/application/index.js +2 -0
  157. package/src/project-type/application/predicate.js +3 -0
  158. package/src/project-type/application/predicate.test.js +14 -0
  159. package/src/project-type/application/scaffolder.js +24 -0
  160. package/src/project-type/application/scaffolder.test.js +35 -0
  161. package/src/project-type/cli/index.js +3 -0
  162. package/src/project-type/cli/lifter.js +5 -0
  163. package/src/project-type/cli/lifter.test.js +20 -0
  164. package/src/project-type/cli/scaffolder.js +52 -0
  165. package/src/project-type/cli/scaffolder.test.js +103 -0
  166. package/src/project-type/cli/tester.js +3 -0
  167. package/src/project-type/cli/tester.test.js +14 -0
  168. package/src/project-type/index.js +3 -0
  169. package/src/project-type/lifter.js +23 -0
  170. package/src/project-type/lifter.test.js +69 -0
  171. package/src/project-type/monorepo/index.js +1 -0
  172. package/src/project-type/monorepo/scaffolder.js +16 -0
  173. package/src/project-type/monorepo/scaffolder.test.js +27 -0
  174. package/src/project-type/package/build-details.js +56 -0
  175. package/src/project-type/package/build-details.test.js +111 -0
  176. package/src/project-type/package/documentation.js +34 -0
  177. package/src/project-type/package/documentation.test.js +106 -0
  178. package/src/project-type/package/index.js +3 -0
  179. package/src/project-type/package/lifter.js +5 -0
  180. package/src/project-type/package/lifter.test.js +20 -0
  181. package/src/project-type/package/scaffolder.js +84 -0
  182. package/src/project-type/package/scaffolder.test.js +267 -0
  183. package/src/project-type/package/tester.js +5 -0
  184. package/src/project-type/package/tester.test.js +28 -0
  185. package/src/project-type/publishable/access-level.js +3 -0
  186. package/src/project-type/publishable/access-level.test.js +13 -0
  187. package/src/project-type/publishable/badges.js +20 -0
  188. package/src/project-type/publishable/badges.test.js +29 -0
  189. package/src/project-type/publishable/bundler/index.js +1 -0
  190. package/src/project-type/publishable/bundler/prompt.js +16 -0
  191. package/src/project-type/publishable/bundler/prompt.test.js +35 -0
  192. package/src/project-type/publishable/bundler/scaffolder.js +8 -0
  193. package/src/project-type/publishable/bundler/scaffolder.test.js +33 -0
  194. package/src/project-type/publishable/index.js +2 -0
  195. package/src/project-type/publishable/lifter.js +24 -0
  196. package/src/project-type/publishable/lifter.test.js +49 -0
  197. package/src/project-type/publishable/provenance/index.js +1 -0
  198. package/src/project-type/publishable/provenance/lifter.js +15 -0
  199. package/src/project-type/publishable/provenance/lifter.test.js +56 -0
  200. package/src/project-type/publishable/provenance/slsa.js +17 -0
  201. package/src/project-type/publishable/provenance/slsa.test.js +21 -0
  202. package/src/project-type/publishable/registry-resolver.js +15 -0
  203. package/src/project-type/publishable/registry-resolver.test.js +60 -0
  204. package/src/project-type/publishable/scaffolder.js +7 -0
  205. package/src/project-type/publishable/scaffolder.test.js +23 -0
  206. package/src/project-type/scaffolder.js +56 -0
  207. package/src/project-type/scaffolder.test.js +115 -0
  208. package/src/project-type/tester.js +9 -0
  209. package/src/project-type/tester.test.js +51 -0
  210. package/src/project-type-plugin/index.js +1 -0
  211. package/src/project-type-plugin/prompt.js +16 -0
  212. package/src/project-type-plugin/prompt.test.js +39 -0
  213. package/src/project-type-plugin/scaffolder.js +28 -0
  214. package/src/project-type-plugin/scaffolder.test.js +70 -0
  215. package/src/prompts/conditionals.js +39 -0
  216. package/src/prompts/conditionals.test.js +95 -0
  217. package/src/prompts/question-names.js +17 -0
  218. package/src/prompts/questions.js +158 -0
  219. package/src/prompts/questions.test.js +247 -0
  220. package/src/prompts/validators.js +9 -0
  221. package/src/prompts/validators.test.js +19 -0
  222. package/src/registries/index.js +2 -0
  223. package/src/registries/lifter.js +43 -0
  224. package/src/registries/lifter.test.js +63 -0
  225. package/src/registries/npm-config/list-builder.js +9 -0
  226. package/src/registries/npm-config/list-builder.test.js +43 -0
  227. package/src/registries/tester.js +3 -0
  228. package/src/registries/tester.test.js +9 -0
  229. package/src/runkit/badge/index.js +1 -0
  230. package/src/runkit/badge/scaffolder.js +13 -0
  231. package/src/runkit/badge/scaffolder.test.js +22 -0
  232. package/src/runkit/index.js +4 -0
  233. package/src/runkit/lifter.js +5 -0
  234. package/src/runkit/lifter.test.js +17 -0
  235. package/src/runkit/remover.js +3 -0
  236. package/src/runkit/remover.test.js +9 -0
  237. package/src/runkit/scaffolder.js +11 -0
  238. package/src/runkit/scaffolder.test.js +35 -0
  239. package/src/runkit/tester.js +3 -0
  240. package/src/runkit/tester.test.js +16 -0
  241. package/src/scaffolder.js +155 -0
  242. package/src/scaffolder.test.js +239 -0
  243. package/src/tester.js +17 -0
  244. package/src/tester.test.js +37 -0
  245. package/src/testing/index.js +1 -0
  246. package/src/testing/scaffolder.js +31 -0
  247. package/src/testing/scaffolder.test.js +63 -0
  248. package/src/testing/unit/index.js +1 -0
  249. package/src/testing/unit/prompt.js +15 -0
  250. package/src/testing/unit/prompt.test.js +33 -0
  251. package/src/testing/unit/scaffolder.js +30 -0
  252. package/src/testing/unit/scaffolder.test.js +54 -0
  253. package/src/vcs/ignore-lists-builder.js +6 -0
  254. package/src/vcs/ignore-lists-builder.test.js +25 -0
  255. package/src/vcs/schema.js +7 -0
  256. package/src/vcs/schema.test.js +40 -0
  257. package/src/verification/index.js +1 -0
  258. package/src/verification/scaffolder.js +35 -0
  259. package/src/verification/scaffolder.test.js +56 -0
@@ -0,0 +1,35 @@
1
+ import {expect, it, describe} from 'vitest';
2
+ import any from '@travi/any';
3
+
4
+ import buildAllowedHostsList from './allowed-hosts-builder.js';
5
+
6
+ describe('allowed-hosts builder', () => {
7
+ const packageManager = any.word();
8
+
9
+ it('should list the package-manager in the allowed list', () => {
10
+ expect(buildAllowedHostsList({packageManager, registries: {}})).toEqual([packageManager]);
11
+ });
12
+
13
+ it('should list the package-manager in the allowed list, even when no registries are provided', () => {
14
+ expect(buildAllowedHostsList({packageManager, registries: undefined})).toEqual([packageManager]);
15
+ });
16
+
17
+ it('should allow additional registries when provided', () => {
18
+ const registries = any.simpleObject();
19
+
20
+ expect(buildAllowedHostsList({packageManager, registries}))
21
+ .toEqual([packageManager, ...Object.values(registries)]);
22
+ });
23
+
24
+ it('should not list the package-manager if the provided registries override the official registry', () => {
25
+ const registry = any.url();
26
+
27
+ expect(buildAllowedHostsList({packageManager, registries: {registry}})).toEqual([registry]);
28
+ });
29
+
30
+ it('should not list the publish registry as an allowed installation registry', () => {
31
+ const publishRegistry = any.url();
32
+
33
+ expect(buildAllowedHostsList({packageManager, registries: {publish: publishRegistry}})).toEqual([packageManager]);
34
+ });
35
+ });
@@ -0,0 +1,12 @@
1
+ import {fileTypes, loadConfigFile} from '@form8ion/core';
2
+ import {write as writeConfig} from '@form8ion/config-file';
3
+
4
+ const configName = 'lockfile-lint';
5
+
6
+ export function read({projectRoot}) {
7
+ return loadConfigFile({name: `.${configName}rc`, format: fileTypes.JSON, path: projectRoot});
8
+ }
9
+
10
+ export function write({projectRoot, config}) {
11
+ return writeConfig({name: configName, format: fileTypes.JSON, path: projectRoot, config});
12
+ }
@@ -0,0 +1,37 @@
1
+ import {fileTypes, loadConfigFile} from '@form8ion/core';
2
+ import {write as writeConfig} from '@form8ion/config-file';
3
+
4
+ import {when} from 'vitest-when';
5
+ import any from '@travi/any';
6
+ import {describe, expect, it, vi} from 'vitest';
7
+
8
+ import {read, write} from './config.js';
9
+
10
+ vi.mock('@form8ion/core');
11
+ vi.mock('@form8ion/config-file');
12
+
13
+ describe('lockfile-lint config', () => {
14
+ const projectRoot = any.string();
15
+
16
+ it('should read the config file', async () => {
17
+ const config = any.simpleObject();
18
+ when(loadConfigFile)
19
+ .calledWith({name: '.lockfile-lintrc', format: fileTypes.JSON, path: projectRoot})
20
+ .thenResolve(config);
21
+
22
+ expect(await read({projectRoot})).toEqual(config);
23
+ });
24
+
25
+ it('should write the config file', async () => {
26
+ const config = any.simpleObject();
27
+
28
+ await write({projectRoot, config});
29
+
30
+ expect(writeConfig).toHaveBeenCalledWith({
31
+ name: 'lockfile-lint',
32
+ format: fileTypes.JSON,
33
+ path: projectRoot,
34
+ config
35
+ });
36
+ });
37
+ });
@@ -0,0 +1,3 @@
1
+ export {default as scaffold} from './scaffolder.js';
2
+ export {default as test} from './tester.js';
3
+ export * from './config.js';
@@ -0,0 +1,38 @@
1
+ import {fileTypes} from '@form8ion/core';
2
+ import {packageManagers} from '@form8ion/javascript-core';
3
+ import {write} from '@form8ion/config-file';
4
+
5
+ import buildAllowedHostsList from './allowed-hosts-builder.js';
6
+ import {defineLockfilePath as determineLockfilePathFor} from '../package-managers/index.js';
7
+
8
+ const lockfileLintSupportedPackageManagers = [packageManagers.NPM, packageManagers.YARN];
9
+
10
+ function lockfileLintSupports(packageManager) {
11
+ return lockfileLintSupportedPackageManagers.includes(packageManager);
12
+ }
13
+
14
+ export default async function scaffoldLockfileLint({projectRoot, packageManager, registries}) {
15
+ if (!lockfileLintSupports(packageManager)) {
16
+ throw new Error(
17
+ `The ${packageManager} package manager is currently not supported by lockfile-lint. `
18
+ + `Only ${lockfileLintSupportedPackageManagers.join(' and ')} are currently supported.`
19
+ );
20
+ }
21
+
22
+ await write({
23
+ name: 'lockfile-lint',
24
+ format: fileTypes.JSON,
25
+ path: projectRoot,
26
+ config: {
27
+ path: determineLockfilePathFor(packageManager),
28
+ type: packageManager,
29
+ 'validate-https': true,
30
+ 'allowed-hosts': buildAllowedHostsList({packageManager, registries})
31
+ }
32
+ });
33
+
34
+ return {
35
+ dependencies: {javascript: {development: ['lockfile-lint']}},
36
+ scripts: {'lint:lockfile': 'lockfile-lint'}
37
+ };
38
+ }
@@ -0,0 +1,85 @@
1
+ import {fileTypes} from '@form8ion/core';
2
+ import {packageManagers} from '@form8ion/javascript-core';
3
+ import {write as writeConfigFile} from '@form8ion/config-file';
4
+
5
+ import {afterEach, vi, expect, it, describe} from 'vitest';
6
+ import any from '@travi/any';
7
+ import {when} from 'vitest-when';
8
+
9
+ import buildAllowedHosts from './allowed-hosts-builder.js';
10
+ import scaffoldLockfileLint from './scaffolder.js';
11
+
12
+ vi.mock('@form8ion/config-file');
13
+ vi.mock('./allowed-hosts-builder');
14
+
15
+ const lockfileLintSupportedPackageManagers = [packageManagers.NPM, packageManagers.YARN];
16
+
17
+ describe('lockfile linting scaffolder', () => {
18
+ const projectRoot = any.string();
19
+ const registries = any.simpleObject();
20
+
21
+ afterEach(() => {
22
+ vi.clearAllMocks();
23
+ });
24
+
25
+ it('should be configured properly for npm', async () => {
26
+ const allowedHosts = any.listOf(any.url);
27
+ when(buildAllowedHosts).calledWith({packageManager: packageManagers.NPM, registries}).thenReturn(allowedHosts);
28
+
29
+ const {dependencies, scripts} = await scaffoldLockfileLint({
30
+ projectRoot,
31
+ packageManager: packageManagers.NPM,
32
+ registries
33
+ });
34
+
35
+ expect(writeConfigFile).toHaveBeenCalledWith({
36
+ name: 'lockfile-lint',
37
+ format: fileTypes.JSON,
38
+ path: projectRoot,
39
+ config: {
40
+ path: 'package-lock.json',
41
+ type: packageManagers.NPM,
42
+ 'validate-https': true,
43
+ 'allowed-hosts': allowedHosts
44
+ }
45
+ });
46
+ expect(dependencies.javascript.development).toEqual(['lockfile-lint']);
47
+ expect(scripts['lint:lockfile']).toEqual('lockfile-lint');
48
+ });
49
+
50
+ it('should be configured properly for yarn', async () => {
51
+ const allowedHosts = any.listOf(any.url);
52
+ when(buildAllowedHosts)
53
+ .calledWith({packageManager: packageManagers.YARN, registries})
54
+ .thenReturn(allowedHosts);
55
+
56
+ const {dependencies, scripts} = await scaffoldLockfileLint({
57
+ projectRoot,
58
+ packageManager: packageManagers.YARN,
59
+ registries
60
+ });
61
+
62
+ expect(writeConfigFile).toHaveBeenCalledWith({
63
+ name: 'lockfile-lint',
64
+ format: fileTypes.JSON,
65
+ path: projectRoot,
66
+ config: {
67
+ path: 'yarn.lock',
68
+ type: packageManagers.YARN,
69
+ 'validate-https': true,
70
+ 'allowed-hosts': allowedHosts
71
+ }
72
+ });
73
+ expect(dependencies.javascript.development).toEqual(['lockfile-lint']);
74
+ expect(scripts['lint:lockfile']).toEqual('lockfile-lint');
75
+ });
76
+
77
+ it('should throw an error for unsupported package managers', async () => {
78
+ const packageManager = any.word();
79
+
80
+ await expect(() => scaffoldLockfileLint({projectRoot, packageManager})).rejects.toThrowError(
81
+ `The ${packageManager} package manager is currently not supported by lockfile-lint. `
82
+ + `Only ${lockfileLintSupportedPackageManagers.join(' and ')} are currently supported.`
83
+ );
84
+ });
85
+ });
@@ -0,0 +1,5 @@
1
+ import {fileExists} from '@form8ion/core';
2
+
3
+ export default function lockfileLintInUse({projectRoot}) {
4
+ return fileExists(`${projectRoot}/.lockfile-lintrc.json`);
5
+ }
@@ -0,0 +1,25 @@
1
+ import {fileExists} from '@form8ion/core';
2
+
3
+ import any from '@travi/any';
4
+ import {describe, it, expect, vi} from 'vitest';
5
+ import {when} from 'vitest-when';
6
+
7
+ import lockfileLintIsUsed from './tester.js';
8
+
9
+ vi.mock('@form8ion/core');
10
+
11
+ describe('lockfile-lint predicate', () => {
12
+ const projectRoot = any.string();
13
+
14
+ it('should return `true` when a config file is present', async () => {
15
+ when(fileExists).calledWith(`${projectRoot}/.lockfile-lintrc.json`).thenResolve(true);
16
+
17
+ expect(await lockfileLintIsUsed({projectRoot})).toBe(true);
18
+ });
19
+
20
+ it('should return `false` when no config file is present', async () => {
21
+ when(fileExists).calledWith(`${projectRoot}/.lockfile-lintrc.json`).thenResolve(false);
22
+
23
+ expect(await lockfileLintIsUsed({projectRoot})).toBe(false);
24
+ });
25
+ });
@@ -0,0 +1,2 @@
1
+ export {default as scaffold} from './scaffolder.js';
2
+ export {default as test} from './tester.js';
@@ -0,0 +1,19 @@
1
+ import {promises as fs} from 'node:fs';
2
+ import {info} from '@travi/cli-messages';
3
+
4
+ import {determineLatestVersionOf, install as installNodeVersion} from './tasks.js';
5
+
6
+ export default async function scaffoldNodeVersion({projectRoot, nodeVersionCategory}) {
7
+ if (!nodeVersionCategory) return undefined;
8
+
9
+ const lowerCaseCategory = nodeVersionCategory.toLowerCase();
10
+ info(`Configuring ${lowerCaseCategory} version of node`);
11
+
12
+ const version = await determineLatestVersionOf(nodeVersionCategory);
13
+
14
+ await fs.writeFile(`${projectRoot}/.nvmrc`, version);
15
+
16
+ await installNodeVersion(nodeVersionCategory);
17
+
18
+ return version;
19
+ }
@@ -0,0 +1,33 @@
1
+ import {promises as fs} from 'node:fs';
2
+
3
+ import {vi, it, expect, describe, afterEach} from 'vitest';
4
+ import any from '@travi/any';
5
+ import {when} from 'vitest-when';
6
+
7
+ import {determineLatestVersionOf, install as installNodeVersion} from './tasks.js';
8
+ import {scaffold as scaffoldNodeVersion} from './index.js';
9
+
10
+ vi.mock('node:fs');
11
+ vi.mock('./tasks.js');
12
+
13
+ describe('node-version scaffolder', () => {
14
+ const projectRoot = any.string();
15
+
16
+ afterEach(() => {
17
+ vi.clearAllMocks();
18
+ });
19
+
20
+ it('should configure nvm with the desired version', async () => {
21
+ const nodeVersionCategory = any.word();
22
+ const version = any.word();
23
+ when(determineLatestVersionOf).calledWith(nodeVersionCategory).thenResolve(version);
24
+
25
+ expect(await scaffoldNodeVersion({projectRoot, nodeVersionCategory})).toEqual(version);
26
+ expect(installNodeVersion).toHaveBeenCalledWith(nodeVersionCategory);
27
+ expect(fs.writeFile).toHaveBeenCalledWith(`${projectRoot}/.nvmrc`, version);
28
+ });
29
+
30
+ it('should return `undefined` when a category is not defined', async () => {
31
+ expect(await scaffoldNodeVersion({projectRoot})).toBe(undefined);
32
+ });
33
+ });
@@ -0,0 +1,25 @@
1
+ import {info} from '@travi/cli-messages';
2
+
3
+ import {execa} from 'execa';
4
+
5
+ export async function determineLatestVersionOf(nodeVersionCategory) {
6
+ info('Determining version of node', {level: 'secondary'});
7
+
8
+ const {stdout: nvmLsOutput} = await execa(
9
+ `. ~/.nvm/nvm.sh && nvm ls-remote${('LTS' === nodeVersionCategory) ? ' --lts' : ''}`,
10
+ {shell: true}
11
+ );
12
+
13
+ const lsLines = nvmLsOutput.split('\n');
14
+ const lsLine = lsLines[lsLines.length - 2];
15
+
16
+ return lsLine.match(/(v[0-9]+)\.[0-9]+\.[0-9]+/)[1];
17
+ }
18
+
19
+ export function install(nodeVersionCategory) {
20
+ info(`Installing ${nodeVersionCategory} version of node using nvm`, {level: 'secondary'});
21
+
22
+ const subprocess = execa('. ~/.nvm/nvm.sh && nvm install', {shell: true});
23
+ subprocess.stdout.pipe(process.stdout);
24
+ return subprocess;
25
+ }
@@ -0,0 +1,43 @@
1
+ import {execa} from 'execa';
2
+
3
+ import {it, expect, describe, afterEach, vi} from 'vitest';
4
+ import {when} from 'vitest-when';
5
+ import any from '@travi/any';
6
+
7
+ import {determineLatestVersionOf, install} from './tasks.js';
8
+
9
+ vi.mock('execa');
10
+
11
+ describe('node-version tasks', () => {
12
+ const majorVersion = any.integer();
13
+ const version = `v${majorVersion}.${any.integer()}.${any.integer()}`;
14
+
15
+ afterEach(() => {
16
+ vi.clearAllMocks();
17
+ });
18
+
19
+ it('should return the latest node version when latest is requested', async () => {
20
+ when(execa)
21
+ .calledWith('. ~/.nvm/nvm.sh && nvm ls-remote', {shell: true})
22
+ .thenResolve({stdout: [...any.listOf(any.word), version, ''].join('\n')});
23
+
24
+ expect(await determineLatestVersionOf(any.word())).toEqual(`v${majorVersion}`);
25
+ });
26
+
27
+ it('should return the latest LTS node version when LTS is requested', async () => {
28
+ when(execa)
29
+ .calledWith('. ~/.nvm/nvm.sh && nvm ls-remote --lts', {shell: true})
30
+ .thenResolve({stdout: [...any.listOf(any.word), version, ''].join('\n')});
31
+
32
+ expect(await determineLatestVersionOf('LTS')).toEqual(`v${majorVersion}`);
33
+ });
34
+
35
+ it('should install the node version', async () => {
36
+ const pipe = vi.fn();
37
+ when(execa).calledWith('. ~/.nvm/nvm.sh && nvm install', {shell: true}).thenReturn({stdout: {pipe}});
38
+
39
+ await install();
40
+
41
+ expect(pipe).toHaveBeenCalledWith(process.stdout);
42
+ });
43
+ });
@@ -0,0 +1,5 @@
1
+ import {fileExists} from '@form8ion/core';
2
+
3
+ export default function nodeVersionMangerInUse({projectRoot}) {
4
+ return fileExists(`${projectRoot}/.nvmrc`);
5
+ }
@@ -0,0 +1,29 @@
1
+ import {fileExists} from '@form8ion/core';
2
+
3
+ import {expect, describe, it, vi, afterEach} from 'vitest';
4
+ import any from '@travi/any';
5
+ import {when} from 'vitest-when';
6
+
7
+ import npmIsUsed from './tester.js';
8
+
9
+ vi.mock('@form8ion/core');
10
+
11
+ describe('nvm predicate', () => {
12
+ const projectRoot = any.string();
13
+
14
+ afterEach(() => {
15
+ vi.clearAllMocks();
16
+ });
17
+
18
+ it('should return `true` is a `.nvmrc` exists', async () => {
19
+ when(fileExists).calledWith(`${projectRoot}/.nvmrc`).thenResolve(true);
20
+
21
+ expect(await npmIsUsed({projectRoot})).toBe(true);
22
+ });
23
+
24
+ it('should return `false` is a `.nvmrc` does not exist', async () => {
25
+ when(fileExists).calledWith(`${projectRoot}/.nvmrc`).thenResolve(false);
26
+
27
+ expect(await npmIsUsed({projectRoot})).toBe(false);
28
+ });
29
+ });
@@ -0,0 +1,5 @@
1
+ export {default as scaffold} from './scaffolder.js';
2
+ export {default as test} from './tester.js';
3
+ export {default as lift} from './lifter.js';
4
+ export {default as read} from './reader.js';
5
+ export {default as write} from './writer.js';
@@ -0,0 +1,14 @@
1
+ import read from './reader.js';
2
+ import write from './writer.js';
3
+
4
+ export default async function liftNpmConfig({projectRoot}) {
5
+ const {
6
+ provenance,
7
+ 'engines-strict': enginesStrict,
8
+ ...remainingProperties
9
+ } = await read({projectRoot});
10
+
11
+ await write({projectRoot, config: remainingProperties});
12
+
13
+ return {};
14
+ }
@@ -0,0 +1,23 @@
1
+ import {describe, expect, it, vi} from 'vitest';
2
+ import any from '@travi/any';
3
+ import {when} from 'vitest-when';
4
+
5
+ import read from './reader.js';
6
+ import write from './writer.js';
7
+ import liftNpmConfig from './lifter.js';
8
+
9
+ vi.mock('./reader.js');
10
+ vi.mock('./writer.js');
11
+
12
+ describe('npm config lifter', () => {
13
+ it('should remove `provenance` and `engines-strict` properties from the config', async () => {
14
+ const projectRoot = any.string();
15
+ const desiredProperties = any.simpleObject();
16
+ when(read)
17
+ .calledWith({projectRoot})
18
+ .thenResolve({...desiredProperties, provenance: true, 'engines-strict': true});
19
+
20
+ expect(await liftNpmConfig({projectRoot})).toEqual({});
21
+ expect(write).toHaveBeenCalledWith({projectRoot, config: desiredProperties});
22
+ });
23
+ });
@@ -0,0 +1,11 @@
1
+ import {parse} from 'ini';
2
+ import {promises as fs} from 'node:fs';
3
+ import {fileExists} from '@form8ion/core';
4
+
5
+ export default async function readNpmConfig({projectRoot}) {
6
+ const pathToConfig = `${projectRoot}/.npmrc`;
7
+
8
+ if (!(await fileExists(pathToConfig))) return {};
9
+
10
+ return parse(await fs.readFile(pathToConfig, 'utf-8'));
11
+ }
@@ -0,0 +1,33 @@
1
+ import {promises as fs} from 'node:fs';
2
+ import {stringify} from 'ini';
3
+ import {fileExists} from '@form8ion/core';
4
+
5
+ import {describe, expect, it, vi} from 'vitest';
6
+ import {when} from 'vitest-when';
7
+ import any from '@travi/any';
8
+
9
+ import readConfig from './reader.js';
10
+
11
+ vi.mock('node:fs');
12
+ vi.mock('@form8ion/core');
13
+
14
+ describe('npm config reader', () => {
15
+ const projectRoot = any.string();
16
+ const pathToConfig = `${projectRoot}/.npmrc`;
17
+
18
+ it('should read the .npmrc file', async () => {
19
+ const existingProperties = any.simpleObject();
20
+ when(fileExists).calledWith(pathToConfig).thenResolve(true);
21
+ when(fs.readFile)
22
+ .calledWith(pathToConfig, 'utf-8')
23
+ .thenReturn(stringify(existingProperties));
24
+
25
+ expect(await readConfig({projectRoot})).toEqual(existingProperties);
26
+ });
27
+
28
+ it('should return empty when the file does not exist', async () => {
29
+ when(fileExists).calledWith(pathToConfig).thenResolve(false);
30
+
31
+ expect(await readConfig({projectRoot})).toEqual({});
32
+ });
33
+ });
@@ -0,0 +1,16 @@
1
+ import {projectTypes} from '@form8ion/javascript-core';
2
+
3
+ import write from './writer.js';
4
+
5
+ function projectWillNotBeConsumed(projectType) {
6
+ return projectTypes.APPLICATION === projectType || projectTypes.CLI === projectType;
7
+ }
8
+
9
+ export default async function scaffoldNpmConfiguration({projectRoot, projectType}) {
10
+ await write({
11
+ projectRoot,
12
+ config: {'update-notifier': false, ...projectWillNotBeConsumed(projectType) && {'save-exact': true}}
13
+ });
14
+
15
+ return {scripts: {'lint:peer': 'npm ls >/dev/null'}};
16
+ }
@@ -0,0 +1,54 @@
1
+ import {projectTypes} from '@form8ion/javascript-core';
2
+
3
+ import {describe, vi, it, expect, afterEach} from 'vitest';
4
+ import any from '@travi/any';
5
+
6
+ import write from './writer.js';
7
+ import scaffoldNpmConfig from './scaffolder.js';
8
+
9
+ vi.mock('node:fs');
10
+ vi.mock('./writer.js');
11
+
12
+ describe('npm config scaffolder', () => {
13
+ const projectRoot = any.string();
14
+
15
+ afterEach(() => {
16
+ vi.clearAllMocks();
17
+ });
18
+
19
+ it('should save exact versions of dependencies for applications', async () => {
20
+ await scaffoldNpmConfig({projectRoot, projectType: projectTypes.APPLICATION});
21
+
22
+ expect(write).toHaveBeenCalledWith({
23
+ projectRoot,
24
+ config: {
25
+ 'update-notifier': false,
26
+ 'save-exact': true
27
+ }
28
+ });
29
+ });
30
+
31
+ it('should save exact versions of dependencies for cli applications', async () => {
32
+ await scaffoldNpmConfig({projectRoot, projectType: projectTypes.CLI});
33
+
34
+ expect(write).toHaveBeenCalledWith({
35
+ projectRoot,
36
+ config: {
37
+ 'update-notifier': false,
38
+ 'save-exact': true
39
+ }
40
+ });
41
+ });
42
+
43
+ it('should allow semver ranges for dependencies of packages', async () => {
44
+ await scaffoldNpmConfig({projectRoot, projectType: projectTypes.PACKAGE});
45
+
46
+ expect(write).toHaveBeenCalledWith({projectRoot, config: {'update-notifier': false}});
47
+ });
48
+
49
+ it('should define the script to enforce peer-dependency compatibility', async () => {
50
+ const results = await scaffoldNpmConfig({projectRoot, projectType: any.word(), registries: {}});
51
+
52
+ expect(results.scripts['lint:peer']).toEqual('npm ls >/dev/null');
53
+ });
54
+ });
@@ -0,0 +1,5 @@
1
+ import {fileExists} from '@form8ion/core';
2
+
3
+ export default function npmConfigExists({projectRoot}) {
4
+ return fileExists(`${projectRoot}/.npmrc`);
5
+ }
@@ -0,0 +1,29 @@
1
+ import {fileExists} from '@form8ion/core';
2
+
3
+ import {describe, vi, it, expect, afterEach} from 'vitest';
4
+ import any from '@travi/any';
5
+ import {when} from 'vitest-when';
6
+
7
+ import testForNpmConfig from './tester.js';
8
+
9
+ vi.mock('@form8ion/core');
10
+
11
+ describe('npm config predicate', () => {
12
+ const projectRoot = any.string();
13
+
14
+ afterEach(() => {
15
+ vi.clearAllMocks();
16
+ });
17
+
18
+ it('should return `true` when an `.npmrc` file exists', async () => {
19
+ when(fileExists).calledWith(`${projectRoot}/.npmrc`).thenResolve(true);
20
+
21
+ expect(await testForNpmConfig({projectRoot})).toBe(true);
22
+ });
23
+
24
+ it('should return `false` when an `.npmrc` file does not exists', async () => {
25
+ when(fileExists).calledWith(`${projectRoot}/.npmrc`).thenResolve(false);
26
+
27
+ expect(await testForNpmConfig({projectRoot})).toBe(false);
28
+ });
29
+ });
@@ -0,0 +1,6 @@
1
+ import {promises as fs} from 'node:fs';
2
+ import {stringify} from 'ini';
3
+
4
+ export default async function writeNpmConfig({projectRoot, config}) {
5
+ await fs.writeFile(`${projectRoot}/.npmrc`, stringify(config));
6
+ }
@@ -0,0 +1,24 @@
1
+ import {promises as fs} from 'node:fs';
2
+ import {stringify} from 'ini';
3
+
4
+ import {describe, expect, vi, it} from 'vitest';
5
+ import any from '@travi/any';
6
+ import {when} from 'vitest-when';
7
+
8
+ import write from './writer.js';
9
+
10
+ vi.mock('node:fs');
11
+ vi.mock('ini');
12
+
13
+ describe('npm config writer', () => {
14
+ it('should write the .npmrc file', async () => {
15
+ const projectRoot = any.string();
16
+ const config = any.simpleObject();
17
+ const stringifiedIniConfig = any.string();
18
+ when(stringify).calledWith(config).thenReturn(stringifiedIniConfig);
19
+
20
+ await write({projectRoot, config});
21
+
22
+ expect(fs.writeFile).toHaveBeenCalledWith(`${projectRoot}/.npmrc`, stringifiedIniConfig);
23
+ });
24
+ });
@@ -0,0 +1,14 @@
1
+ import joi from 'joi';
2
+
3
+ export const scopeBasedConfigSchema = joi.object({scope: joi.string().regex(/^@[a-z0-9-]+$/i, 'scope').required()});
4
+
5
+ export const nameBasedConfigSchema = joi.object({
6
+ packageName: joi.string().required(),
7
+ name: joi.string().required()
8
+ });
9
+
10
+ export const registriesSchema = joi.object().pattern(joi.string(), joi.string().uri()).default({});
11
+
12
+ export const visibilitySchema = joi.string().valid('Public', 'Private').required();
13
+
14
+ export const projectNameSchema = joi.string().regex(/^@\w*\//, {invert: true}).required();