@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,10 @@
1
+ import {dialects} from '@form8ion/javascript-core';
2
+
3
+ export default function gatherDialectInput({babelPreset, typescript}) {
4
+ return [
5
+ {name: 'Common JS (no transpilation)', value: dialects.COMMON_JS, short: 'cjs'},
6
+ ...babelPreset ? [{name: 'Modern JavaScript (transpiled)', value: dialects.BABEL, short: 'modern'}] : [],
7
+ {name: 'ESM-only (no transpilation)', value: dialects.ESM, short: 'esm'},
8
+ ...typescript ? [{name: 'TypeScript', value: dialects.TYPESCRIPT, short: 'ts'}] : []
9
+ ];
10
+ }
@@ -0,0 +1,28 @@
1
+ import {dialects} from '@form8ion/javascript-core';
2
+
3
+ import any from '@travi/any';
4
+ import {describe, expect, it} from 'vitest';
5
+
6
+ import buildDialectChoices from './prompt-choices.js';
7
+
8
+ describe('dialect prompt questions', () => {
9
+ it('should list available dialects', () => {
10
+ expect(buildDialectChoices({
11
+ ...any.simpleObject(),
12
+ babelPreset: any.simpleObject(),
13
+ typescript: any.simpleObject()
14
+ })).toEqual([
15
+ {name: 'Common JS (no transpilation)', value: dialects.COMMON_JS, short: 'cjs'},
16
+ {name: 'Modern JavaScript (transpiled)', value: dialects.BABEL, short: 'modern'},
17
+ {name: 'ESM-only (no transpilation)', value: dialects.ESM, short: 'esm'},
18
+ {name: 'TypeScript', value: dialects.TYPESCRIPT, short: 'ts'}
19
+ ]);
20
+ });
21
+
22
+ it('should not include babel or typescript in the choices list when configs are not provided', () => {
23
+ expect(buildDialectChoices(any.simpleObject())).toEqual([
24
+ {name: 'Common JS (no transpilation)', value: dialects.COMMON_JS, short: 'cjs'},
25
+ {name: 'ESM-only (no transpilation)', value: dialects.ESM, short: 'esm'}
26
+ ]);
27
+ });
28
+ });
@@ -0,0 +1,15 @@
1
+ import {dialects} from '@form8ion/javascript-core';
2
+
3
+ import {scaffold as scaffoldBabel} from './babel/index.js';
4
+ import {scaffold as scaffoldTypescript} from './typescript/index.js';
5
+
6
+ export default function scaffoldDialect({dialect, projectType, projectRoot, configs, testFilenamePattern}) {
7
+ switch (dialect) {
8
+ case dialects.BABEL:
9
+ return scaffoldBabel({preset: configs.babelPreset, projectRoot});
10
+ case dialects.TYPESCRIPT:
11
+ return scaffoldTypescript({config: configs.typescript, projectType, projectRoot, testFilenamePattern});
12
+ default:
13
+ return {};
14
+ }
15
+ }
@@ -0,0 +1,49 @@
1
+ import {dialects} from '@form8ion/javascript-core';
2
+
3
+ import any from '@travi/any';
4
+ import {describe, expect, it, vi} from 'vitest';
5
+ import {when} from 'vitest-when';
6
+
7
+ import {scaffold as scaffoldBabel} from './babel/index.js';
8
+ import {scaffold as scaffoldTypescript} from './typescript/index.js';
9
+ import scaffoldDialect from './scaffolder.js';
10
+
11
+ vi.mock('./babel/index.js');
12
+ vi.mock('./typescript/index.js');
13
+
14
+ describe('dialect scaffolder', () => {
15
+ const projectRoot = any.string();
16
+
17
+ it('should not scaffold babel or typescript when not chosen', async () => {
18
+ expect(await scaffoldDialect({dialect: any.word()})).toEqual({});
19
+ expect(scaffoldBabel).not.toHaveBeenCalled();
20
+ expect(scaffoldTypescript).not.toHaveBeenCalled();
21
+ });
22
+
23
+ it('should scaffold babel when chosen', async () => {
24
+ const babelPreset = any.word();
25
+ const babelResults = any.simpleObject();
26
+ when(scaffoldBabel).calledWith({preset: babelPreset, projectRoot}).thenResolve(babelResults);
27
+
28
+ expect(await scaffoldDialect({dialect: dialects.BABEL, configs: {babelPreset}, projectRoot}))
29
+ .toEqual(babelResults);
30
+ });
31
+
32
+ it('should scaffold typescript when chosen', async () => {
33
+ const typescriptConfigs = any.simpleObject();
34
+ const typescriptResults = any.simpleObject();
35
+ const testFilenamePattern = any.string();
36
+ const projectType = any.word();
37
+ when(scaffoldTypescript)
38
+ .calledWith({config: typescriptConfigs, projectType, projectRoot, testFilenamePattern})
39
+ .thenResolve(typescriptResults);
40
+
41
+ expect(await scaffoldDialect({
42
+ dialect: dialects.TYPESCRIPT,
43
+ projectType,
44
+ configs: {typescript: typescriptConfigs},
45
+ projectRoot,
46
+ testFilenamePattern
47
+ })).toEqual(typescriptResults);
48
+ });
49
+ });
@@ -0,0 +1 @@
1
+ export {default as scaffold} from './scaffolder.js';
@@ -0,0 +1,31 @@
1
+ import {fileTypes, writeConfigFile} from '@form8ion/core';
2
+ import {projectTypes} from '@form8ion/javascript-core';
3
+
4
+ export default async function scaffoldTypescript({config, projectType, projectRoot, testFilenamePattern}) {
5
+ const shareableTsConfigPackage = `${config.scope}/tsconfig`;
6
+
7
+ await writeConfigFile({
8
+ path: projectRoot,
9
+ name: 'tsconfig',
10
+ format: fileTypes.JSON,
11
+ config: {
12
+ $schema: 'https://json.schemastore.org/tsconfig',
13
+ extends: shareableTsConfigPackage,
14
+ compilerOptions: {
15
+ rootDir: 'src',
16
+ ...projectTypes.PACKAGE === projectType && {
17
+ outDir: 'lib',
18
+ declaration: true
19
+ }
20
+ },
21
+ include: ['src/**/*.ts'],
22
+ ...testFilenamePattern && {exclude: [testFilenamePattern]}
23
+ }
24
+ });
25
+
26
+ return {
27
+ eslint: {configs: ['typescript']},
28
+ dependencies: {javascript: {development: ['typescript', shareableTsConfigPackage]}},
29
+ vcsIgnore: {files: ['tsconfig.tsbuildinfo']}
30
+ };
31
+ }
@@ -0,0 +1,95 @@
1
+ import {fileTypes, writeConfigFile} from '@form8ion/core';
2
+ import {projectTypes} from '@form8ion/javascript-core';
3
+
4
+ import {describe, vi, afterEach, it, expect} from 'vitest';
5
+ import any from '@travi/any';
6
+
7
+ import scaffoldTypescriptDialect from './scaffolder.js';
8
+
9
+ vi.mock('@form8ion/core');
10
+
11
+ describe('typescript dialect scaffolder', () => {
12
+ const scope = `@${any.word()}`;
13
+
14
+ afterEach(() => {
15
+ vi.clearAllMocks();
16
+ });
17
+
18
+ it('should define the eslint config', async () => {
19
+ const {eslint: {configs}} = await scaffoldTypescriptDialect({config: {}});
20
+
21
+ expect(configs).toEqual(['typescript']);
22
+ });
23
+
24
+ it('should extend the scoped package in the tsconfig', async () => {
25
+ const projectRoot = any.string();
26
+
27
+ await scaffoldTypescriptDialect({config: {scope}, projectRoot});
28
+
29
+ expect(writeConfigFile).toHaveBeenCalledWith({
30
+ path: projectRoot,
31
+ name: 'tsconfig',
32
+ format: fileTypes.JSON,
33
+ config: {
34
+ $schema: 'https://json.schemastore.org/tsconfig',
35
+ extends: `${scope}/tsconfig`,
36
+ compilerOptions: {rootDir: 'src'},
37
+ include: ['src/**/*.ts']
38
+ }
39
+ });
40
+ });
41
+
42
+ it('should define package specific details when the project is a package', async () => {
43
+ const projectRoot = any.string();
44
+
45
+ await scaffoldTypescriptDialect({config: {scope}, projectType: projectTypes.PACKAGE, projectRoot});
46
+
47
+ expect(writeConfigFile).toHaveBeenCalledWith({
48
+ path: projectRoot,
49
+ name: 'tsconfig',
50
+ format: fileTypes.JSON,
51
+ config: {
52
+ $schema: 'https://json.schemastore.org/tsconfig',
53
+ extends: `${scope}/tsconfig`,
54
+ compilerOptions: {
55
+ rootDir: 'src',
56
+ outDir: 'lib',
57
+ declaration: true
58
+ },
59
+ include: ['src/**/*.ts']
60
+ }
61
+ });
62
+ });
63
+
64
+ it('should include the testFilenamePattern as an `exclude` when provided', async () => {
65
+ const projectRoot = any.string();
66
+ const testFilenamePattern = any.string();
67
+
68
+ await scaffoldTypescriptDialect({config: {scope}, projectRoot, testFilenamePattern});
69
+
70
+ expect(writeConfigFile).toHaveBeenCalledWith({
71
+ path: projectRoot,
72
+ name: 'tsconfig',
73
+ format: fileTypes.JSON,
74
+ config: {
75
+ $schema: 'https://json.schemastore.org/tsconfig',
76
+ extends: `${scope}/tsconfig`,
77
+ compilerOptions: {rootDir: 'src'},
78
+ include: ['src/**/*.ts'],
79
+ exclude: [testFilenamePattern]
80
+ }
81
+ });
82
+ });
83
+
84
+ it('should define dev dependencies', async () => {
85
+ const {dependencies} = await scaffoldTypescriptDialect({config: {scope}});
86
+
87
+ expect(dependencies.javascript.development).toEqual(['typescript', `${scope}/tsconfig`]);
88
+ });
89
+
90
+ it('should ignore files from version control', async () => {
91
+ const {vcsIgnore: {files}} = await scaffoldTypescriptDialect({config: {}});
92
+
93
+ expect(files).toEqual(['tsconfig.tsbuildinfo']);
94
+ });
95
+ });
@@ -0,0 +1,11 @@
1
+ import {packageManagers} from '@form8ion/javascript-core';
2
+
3
+ export default function scaffoldGenerationCommand(packageManager) {
4
+ if (packageManagers.NPM === packageManager) return 'npm run generate:md';
5
+ if (packageManagers.YARN === packageManager) return 'yarn generate:md';
6
+
7
+ throw new Error(
8
+ `The ${packageManager} package manager is currently not supported. `
9
+ + `Only ${Object.values(packageManagers).join(' and ')} are currently supported.`
10
+ );
11
+ }
@@ -0,0 +1,25 @@
1
+ import {packageManagers} from '@form8ion/javascript-core';
2
+
3
+ import {describe, expect, it} from 'vitest';
4
+ import any from '@travi/any';
5
+
6
+ import buildCommand from './generation-command.js';
7
+
8
+ describe('documentation generation command', () => {
9
+ it('should return the npm variation of the command', () => {
10
+ expect(buildCommand(packageManagers.NPM)).toEqual('npm run generate:md');
11
+ });
12
+
13
+ it('should return the yarn variation of the command', () => {
14
+ expect(buildCommand(packageManagers.YARN)).toEqual('yarn generate:md');
15
+ });
16
+
17
+ it('should throw an error for unsupported package managers', () => {
18
+ const packageManager = any.word();
19
+
20
+ expect(() => buildCommand(packageManager)).toThrowError(
21
+ `The ${packageManager} package manager is currently not supported. `
22
+ + `Only ${Object.values(packageManagers).join(' and ')} are currently supported.`
23
+ );
24
+ });
25
+ });
@@ -0,0 +1 @@
1
+ export {default} from './scaffolder.js';
@@ -0,0 +1,20 @@
1
+ import buildGenerationCommand from './generation-command.js';
2
+
3
+ export default function scaffoldDocumentation({projectTypeResults, packageManager}) {
4
+ return {
5
+ toc: `Run \`${buildGenerationCommand(packageManager)}\` to generate a table of contents`,
6
+ ...projectTypeResults.documentation,
7
+ contributing: `### Dependencies
8
+
9
+ \`\`\`sh
10
+ $ nvm install
11
+ $ ${packageManager} install
12
+ \`\`\`
13
+
14
+ ### Verification
15
+
16
+ \`\`\`sh
17
+ $ ${packageManager} test
18
+ \`\`\``
19
+ };
20
+ }
@@ -0,0 +1,49 @@
1
+ import any from '@travi/any';
2
+ import {beforeEach, describe, expect, it, vi} from 'vitest';
3
+ import {when} from 'vitest-when';
4
+
5
+ import buildDocumentationCommand from './generation-command.js';
6
+ import scaffoldDocumentation from './scaffolder.js';
7
+
8
+ vi.mock('./generation-command.js');
9
+
10
+ describe('documentation scaffolder', () => {
11
+ const packageManager = any.word();
12
+ const documentationGenerationCommand = any.string();
13
+ const tocMessage = `Run \`${documentationGenerationCommand}\` to generate a table of contents`;
14
+ const contributionDocumentation = `### Dependencies
15
+
16
+ \`\`\`sh
17
+ $ nvm install
18
+ $ ${packageManager} install
19
+ \`\`\`
20
+
21
+ ### Verification
22
+
23
+ \`\`\`sh
24
+ $ ${packageManager} test
25
+ \`\`\``;
26
+
27
+ beforeEach(() => {
28
+ when(buildDocumentationCommand).calledWith(packageManager).thenReturn(documentationGenerationCommand);
29
+ });
30
+
31
+ it('should provide project-type documentation and contribution details', () => {
32
+ const projectTypeResults = {documentation: any.simpleObject()};
33
+
34
+ expect(scaffoldDocumentation({projectTypeResults, packageManager})).toEqual({
35
+ toc: tocMessage,
36
+ ...projectTypeResults.documentation,
37
+ contributing: contributionDocumentation
38
+ });
39
+ });
40
+
41
+ it('should not include project-type documentation when not provided', () => {
42
+ const projectTypeResults = {documentation: undefined};
43
+
44
+ expect(scaffoldDocumentation({projectTypeResults, packageManager})).toEqual({
45
+ toc: tocMessage,
46
+ contributing: contributionDocumentation
47
+ });
48
+ });
49
+ });
@@ -0,0 +1,2 @@
1
+ export {default as test} from './tester.js';
2
+ export {default as lift} from './lifter.js';
@@ -0,0 +1,7 @@
1
+ export default async function liftEngines({packageDetails: {name}}) {
2
+ return {
3
+ dependencies: {javascript: {development: ['ls-engines']}},
4
+ scripts: {'lint:engines': 'ls-engines'},
5
+ badges: {consumer: {node: {img: `https://img.shields.io/node/v/${name}?logo=node.js`, text: 'node'}}}
6
+ };
7
+ }
@@ -0,0 +1,18 @@
1
+ import {describe, it, expect} from 'vitest';
2
+ import any from '@travi/any';
3
+
4
+ import liftEngines from './lifter.js';
5
+
6
+ describe('engines lifter', () => {
7
+ it('should return the details for linting and communicating engines restrictions', async () => {
8
+ const packageName = any.word();
9
+ const packageDetails = {...any.simpleObject(), name: packageName};
10
+
11
+ const {scripts, badges, dependencies} = await liftEngines({packageDetails});
12
+
13
+ expect(scripts['lint:engines']).toEqual('ls-engines');
14
+ expect(dependencies.javascript.development).toEqual(['ls-engines']);
15
+ expect(badges.consumer.node)
16
+ .toEqual({img: `https://img.shields.io/node/v/${packageName}?logo=node.js`, text: 'node'});
17
+ });
18
+ });
@@ -0,0 +1,7 @@
1
+ import {promises as fs} from 'fs';
2
+
3
+ export default async function testEngines({projectRoot}) {
4
+ const {engines} = JSON.parse(await fs.readFile(`${projectRoot}/package.json`, 'utf8'));
5
+
6
+ return !!engines?.node;
7
+ }
@@ -0,0 +1,37 @@
1
+ import {promises as fs} from 'node:fs';
2
+
3
+ import {describe, it, expect, vi, afterEach} from 'vitest';
4
+ import any from '@travi/any';
5
+ import {when} from 'vitest-when';
6
+
7
+ import testEngines from './tester.js';
8
+
9
+ vi.mock('node:fs');
10
+
11
+ describe('engines tester', () => {
12
+ const projectRoot = any.string();
13
+
14
+ afterEach(() => {
15
+ vi.clearAllMocks();
16
+ });
17
+
18
+ it('should return `true` when `engines.node` is defined', async () => {
19
+ when(fs.readFile)
20
+ .calledWith(`${projectRoot}/package.json`, 'utf8')
21
+ .thenResolve(JSON.stringify({engines: {node: any.word()}}));
22
+
23
+ expect(await testEngines({projectRoot})).toBe(true);
24
+ });
25
+
26
+ it('should return `false` when `engines.node` is not defined', async () => {
27
+ when(fs.readFile).calledWith(`${projectRoot}/package.json`, 'utf8').thenReturn(JSON.stringify({engines: {}}));
28
+
29
+ expect(await testEngines({projectRoot})).toBe(false);
30
+ });
31
+
32
+ it('should return `false` when `engines` is not defined', async () => {
33
+ when(fs.readFile).calledWith(`${projectRoot}/package.json`, 'utf8').thenReturn(JSON.stringify({}));
34
+
35
+ expect(await testEngines({projectRoot})).toBe(false);
36
+ });
37
+ });
package/src/index.js ADDED
@@ -0,0 +1,9 @@
1
+ import {questionNames as languageScaffolderPromptsQuestionNames} from '@travi/language-scaffolder-prompts';
2
+
3
+ import {questionNames as jsScaffolderQuestionNames} from './prompts/question-names.js';
4
+
5
+ export {scaffold as scaffoldUnitTesting} from './testing/unit/index.js';
6
+ export {default as scaffold} from './scaffolder.js';
7
+ export {default as lift} from './lifter.js';
8
+ export {default as test} from './tester.js';
9
+ export const questionNames = {...languageScaffolderPromptsQuestionNames, ...jsScaffolderQuestionNames};
package/src/lifter.js ADDED
@@ -0,0 +1,55 @@
1
+ import {promises as fs} from 'node:fs';
2
+ import deepmerge from 'deepmerge';
3
+ import {info} from '@travi/cli-messages';
4
+ import {applyEnhancers} from '@form8ion/core';
5
+ import * as huskyPlugin from '@form8ion/husky';
6
+ import * as commitConventionPlugin from '@form8ion/commit-convention';
7
+
8
+ import * as registriesPlugin from './registries/index.js';
9
+ import * as coveragePlugin from './coverage/index.js';
10
+ import * as codeStylePlugin from './code-style/index.js';
11
+ import * as npmConfigPlugin from './npm-config/index.js';
12
+ import * as enginesEnhancer from './engines/index.js';
13
+ import * as projectTypes from './project-type/index.js';
14
+ import * as dialects from './dialects/index.js';
15
+ import {lift as liftPackage} from './package/index.js';
16
+ import * as packageManagers from './package-managers/index.js';
17
+ import {determineCurrent as resolvePackageManager} from './package-managers/index.js';
18
+
19
+ export default async function liftJavaScript({
20
+ projectRoot,
21
+ vcs,
22
+ results,
23
+ pathWithinParent,
24
+ enhancers = {},
25
+ configs = {}
26
+ }) {
27
+ info('Lifting JavaScript-specific details');
28
+
29
+ const [packageManager, packageContents] = await Promise.all([
30
+ resolvePackageManager({projectRoot, packageManager: results.packageManager}),
31
+ fs.readFile(`${projectRoot}/package.json`, 'utf8')
32
+ ]);
33
+
34
+ const enhancerResults = await applyEnhancers({
35
+ results,
36
+ enhancers: {
37
+ ...enhancers,
38
+ huskyPlugin,
39
+ enginesEnhancer,
40
+ coveragePlugin,
41
+ commitConventionPlugin,
42
+ dialects,
43
+ codeStylePlugin,
44
+ npmConfigPlugin,
45
+ projectTypes,
46
+ packageManagers,
47
+ registriesPlugin
48
+ },
49
+ options: {packageManager, projectRoot, vcs, packageDetails: JSON.parse(packageContents), configs}
50
+ });
51
+
52
+ await liftPackage(deepmerge.all([{projectRoot, packageManager, vcs, pathWithinParent}, enhancerResults]));
53
+
54
+ return enhancerResults;
55
+ }
@@ -0,0 +1,96 @@
1
+ import {promises as fs} from 'node:fs';
2
+ import deepmerge from 'deepmerge';
3
+ import * as core from '@form8ion/core';
4
+ import * as huskyPlugin from '@form8ion/husky';
5
+ import * as commitConventionPlugin from '@form8ion/commit-convention';
6
+
7
+ import {beforeEach, describe, expect, it, vi} from 'vitest';
8
+ import any from '@travi/any';
9
+ import {when} from 'vitest-when';
10
+
11
+ import * as registriesPlugin from './registries/index.js';
12
+ import * as coveragePlugin from './coverage/index.js';
13
+ import * as codeStylePlugin from './code-style/index.js';
14
+ import * as npmConfigPlugin from './npm-config/index.js';
15
+ import * as enginesEnhancer from './engines/index.js';
16
+ import * as projectTypes from './project-type/index.js';
17
+ import * as dialects from './dialects/index.js';
18
+ import liftPackage from './package/lifter.js';
19
+ import * as packageManagers from './package-managers/index.js';
20
+ import {determineCurrent as packageManagerResolver} from './package-managers/index.js';
21
+ import lift from './lifter.js';
22
+
23
+ vi.mock('node:fs');
24
+ vi.mock('@form8ion/core');
25
+ vi.mock('./package/lifter.js');
26
+ vi.mock('./package-managers/index.js');
27
+
28
+ describe('lift', () => {
29
+ const projectRoot = any.string();
30
+ const scripts = any.simpleObject();
31
+ const tags = any.listOf(any.word);
32
+ const dependencies = any.simpleObject();
33
+ const devDependencies = any.simpleObject();
34
+ const packageManager = any.word();
35
+ const manager = any.word();
36
+ const enhancerResults = any.simpleObject();
37
+ const vcsDetails = any.simpleObject();
38
+ const results = {...any.simpleObject(), scripts, tags, dependencies, devDependencies, packageManager: manager};
39
+ const pathWithinParent = any.string();
40
+ const packageDetails = any.simpleObject();
41
+ const internalEnhancers = {
42
+ huskyPlugin,
43
+ enginesEnhancer,
44
+ coveragePlugin,
45
+ commitConventionPlugin,
46
+ dialects,
47
+ codeStylePlugin,
48
+ npmConfigPlugin,
49
+ projectTypes,
50
+ packageManagers,
51
+ registriesPlugin
52
+ };
53
+
54
+ beforeEach(() => {
55
+ when(packageManagerResolver)
56
+ .calledWith({projectRoot, packageManager: manager})
57
+ .thenResolve(packageManager);
58
+ when(fs.readFile)
59
+ .calledWith(`${projectRoot}/package.json`, 'utf8')
60
+ .thenResolve(JSON.stringify(packageDetails));
61
+ });
62
+
63
+ it('should lift results that are specific to js projects', async () => {
64
+ const configs = any.simpleObject();
65
+ when(core.applyEnhancers)
66
+ .calledWith({
67
+ results,
68
+ enhancers: internalEnhancers,
69
+ options: {projectRoot, packageManager, vcs: vcsDetails, packageDetails, configs}
70
+ })
71
+ .thenResolve(enhancerResults);
72
+
73
+ const liftResults = await lift({projectRoot, vcs: vcsDetails, results, pathWithinParent, configs});
74
+
75
+ expect(liftResults).toEqual(enhancerResults);
76
+ expect(liftPackage).toHaveBeenCalledWith(deepmerge.all([
77
+ {projectRoot, packageManager, vcs: vcsDetails, pathWithinParent},
78
+ enhancerResults
79
+ ]));
80
+ });
81
+
82
+ it('should apply provided enhancers', async () => {
83
+ const enhancers = any.simpleObject();
84
+ when(core.applyEnhancers)
85
+ .calledWith({
86
+ results,
87
+ enhancers: {...enhancers, ...internalEnhancers},
88
+ options: {projectRoot, packageManager, vcs: vcsDetails, packageDetails, configs: {}}
89
+ })
90
+ .thenResolve(enhancerResults);
91
+
92
+ const liftResults = await lift({projectRoot, vcs: vcsDetails, results, pathWithinParent, enhancers});
93
+
94
+ expect(liftResults).toEqual(enhancerResults);
95
+ });
96
+ });
@@ -0,0 +1 @@
1
+ export {default as scaffold} from './scaffolder.js';
@@ -0,0 +1,5 @@
1
+ import {scaffold as scaffoldLockfileLint} from '../lockfile-lint/index.js';
2
+
3
+ export default async function scaffoldLinting({projectRoot, packageManager, registries}) {
4
+ return scaffoldLockfileLint({projectRoot, packageManager, registries});
5
+ }
@@ -0,0 +1,31 @@
1
+ import {describe, expect, it, vi} from 'vitest';
2
+ import any from '@travi/any';
3
+ import {when} from 'vitest-when';
4
+
5
+ import {scaffold as scaffoldLockfileLint} from '../lockfile-lint/index.js';
6
+ import {scaffold} from './index.js';
7
+
8
+ vi.mock('../lockfile-lint');
9
+
10
+ describe('linting scaffolder', () => {
11
+ const pathWithinParent = any.string();
12
+ const projectRoot = any.string();
13
+ const packageManager = any.word();
14
+ const vcs = any.simpleObject();
15
+ const registries = any.simpleObject();
16
+
17
+ it('should configure linters when config definitions are provided', async () => {
18
+ const lockfileLintResults = any.simpleObject();
19
+ when(scaffoldLockfileLint)
20
+ .calledWith({projectRoot, packageManager, registries})
21
+ .thenResolve(lockfileLintResults);
22
+
23
+ expect(await scaffold({
24
+ projectRoot,
25
+ vcs,
26
+ packageManager,
27
+ pathWithinParent,
28
+ registries
29
+ })).toEqual(lockfileLintResults);
30
+ });
31
+ });
@@ -0,0 +1,6 @@
1
+ export default function buildAllowedHosts({packageManager, registries = {}}) {
2
+ return [
3
+ ...!registries.registry ? [packageManager] : [],
4
+ ...Object.values(Object.fromEntries(Object.entries(registries).filter(([scope]) => 'publish' !== scope)))
5
+ ];
6
+ }