@form8ion/javascript 15.6.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 (257) hide show
  1. package/package.json +4 -3
  2. package/src/code-style/index.js +3 -0
  3. package/src/code-style/lifter.js +6 -0
  4. package/src/code-style/lifter.test.js +25 -0
  5. package/src/code-style/remark/index.js +3 -0
  6. package/src/code-style/remark/lifter.js +10 -0
  7. package/src/code-style/remark/lifter.test.js +28 -0
  8. package/src/code-style/remark/scaffolder.js +38 -0
  9. package/src/code-style/remark/scaffolder.test.js +102 -0
  10. package/src/code-style/remark/tester.js +11 -0
  11. package/src/code-style/remark/tester.test.js +46 -0
  12. package/src/code-style/scaffolder.js +26 -0
  13. package/src/code-style/scaffolder.test.js +87 -0
  14. package/src/code-style/tester.js +5 -0
  15. package/src/code-style/tester.test.js +23 -0
  16. package/src/corepack/index.js +1 -0
  17. package/src/corepack/lifter.js +5 -0
  18. package/src/corepack/lifter.test.js +22 -0
  19. package/src/coverage/index.js +3 -0
  20. package/src/coverage/lifter.js +31 -0
  21. package/src/coverage/lifter.test.js +58 -0
  22. package/src/coverage/nyc/index.js +2 -0
  23. package/src/coverage/nyc/remover.js +16 -0
  24. package/src/coverage/nyc/remover.test.js +24 -0
  25. package/src/coverage/nyc/tester.js +5 -0
  26. package/src/coverage/nyc/tester.test.js +29 -0
  27. package/src/coverage/scaffolder.js +7 -0
  28. package/src/coverage/scaffolder.test.js +32 -0
  29. package/src/coverage/tester.js +10 -0
  30. package/src/coverage/tester.test.js +50 -0
  31. package/src/dependencies/index.js +3 -0
  32. package/src/dependencies/installer.js +25 -0
  33. package/src/dependencies/installer.test.js +77 -0
  34. package/src/dependencies/package-managers.js +32 -0
  35. package/src/dependencies/package-managers.test.js +46 -0
  36. package/src/dependencies/processor.js +30 -0
  37. package/src/dependencies/processor.test.js +75 -0
  38. package/src/dependencies/remover.js +10 -0
  39. package/src/dependencies/remover.test.js +28 -0
  40. package/src/dialects/babel/config/ignore-adder.js +10 -0
  41. package/src/dialects/babel/config/ignore-adder.test.js +33 -0
  42. package/src/dialects/babel/config/index.js +3 -0
  43. package/src/dialects/babel/config/loader.js +5 -0
  44. package/src/dialects/babel/config/loader.test.js +21 -0
  45. package/src/dialects/babel/config/writer.js +6 -0
  46. package/src/dialects/babel/config/writer.test.js +20 -0
  47. package/src/dialects/babel/index.js +3 -0
  48. package/src/dialects/babel/lifter.js +7 -0
  49. package/src/dialects/babel/lifter.test.js +17 -0
  50. package/src/dialects/babel/predicate.js +5 -0
  51. package/src/dialects/babel/predicate.test.js +25 -0
  52. package/src/dialects/babel/scaffolder.js +14 -0
  53. package/src/dialects/babel/scaffolder.test.js +28 -0
  54. package/src/dialects/index.js +2 -0
  55. package/src/dialects/prompt-choices.js +10 -0
  56. package/src/dialects/prompt-choices.test.js +28 -0
  57. package/src/dialects/scaffolder.js +15 -0
  58. package/src/dialects/scaffolder.test.js +49 -0
  59. package/src/dialects/typescript/index.js +1 -0
  60. package/src/dialects/typescript/scaffolder.js +31 -0
  61. package/src/dialects/typescript/scaffolder.test.js +95 -0
  62. package/src/documentation/generation-command.js +11 -0
  63. package/src/documentation/generation-command.test.js +25 -0
  64. package/src/documentation/index.js +1 -0
  65. package/src/documentation/scaffolder.js +20 -0
  66. package/src/documentation/scaffolder.test.js +49 -0
  67. package/src/engines/index.js +2 -0
  68. package/src/engines/lifter.js +7 -0
  69. package/src/engines/lifter.test.js +18 -0
  70. package/src/engines/tester.js +7 -0
  71. package/src/engines/tester.test.js +37 -0
  72. package/src/index.js +9 -0
  73. package/src/lifter.js +55 -0
  74. package/src/lifter.test.js +96 -0
  75. package/src/linting/index.js +1 -0
  76. package/src/linting/scaffolder.js +5 -0
  77. package/src/linting/scaffolder.test.js +31 -0
  78. package/src/lockfile-lint/allowed-hosts-builder.js +6 -0
  79. package/src/lockfile-lint/allowed-hosts-builder.test.js +35 -0
  80. package/src/lockfile-lint/config.js +12 -0
  81. package/src/lockfile-lint/config.test.js +37 -0
  82. package/src/lockfile-lint/index.js +3 -0
  83. package/src/lockfile-lint/scaffolder.js +38 -0
  84. package/src/lockfile-lint/scaffolder.test.js +85 -0
  85. package/src/lockfile-lint/tester.js +5 -0
  86. package/src/lockfile-lint/tester.test.js +25 -0
  87. package/src/node-version/index.js +2 -0
  88. package/src/node-version/scaffolder.js +19 -0
  89. package/src/node-version/scaffolder.test.js +33 -0
  90. package/src/node-version/tasks.js +25 -0
  91. package/src/node-version/tasks.test.js +43 -0
  92. package/src/node-version/tester.js +5 -0
  93. package/src/node-version/tester.test.js +29 -0
  94. package/src/npm-config/index.js +5 -0
  95. package/src/npm-config/lifter.js +14 -0
  96. package/src/npm-config/lifter.test.js +23 -0
  97. package/src/npm-config/reader.js +11 -0
  98. package/src/npm-config/reader.test.js +33 -0
  99. package/src/npm-config/scaffolder.js +16 -0
  100. package/src/npm-config/scaffolder.test.js +54 -0
  101. package/src/npm-config/tester.js +5 -0
  102. package/src/npm-config/tester.test.js +29 -0
  103. package/src/npm-config/writer.js +6 -0
  104. package/src/npm-config/writer.test.js +24 -0
  105. package/src/options/schemas.js +14 -0
  106. package/src/options/schemas.test.js +147 -0
  107. package/src/options/validator.js +45 -0
  108. package/src/options/validator.test.js +79 -0
  109. package/src/package/details.js +18 -0
  110. package/src/package/details.test.js +51 -0
  111. package/src/package/index.js +2 -0
  112. package/src/package/lifter.js +47 -0
  113. package/src/package/lifter.test.js +100 -0
  114. package/src/package/package-name.js +13 -0
  115. package/src/package/package-name.test.js +52 -0
  116. package/src/package/property-sorter.js +38 -0
  117. package/src/package/property-sorter.test.js +56 -0
  118. package/src/package/scaffolder.js +32 -0
  119. package/src/package/scaffolder.test.js +46 -0
  120. package/src/package/scripts/index.js +1 -0
  121. package/src/package/scripts/lifter.js +14 -0
  122. package/src/package/scripts/lifter.test.js +31 -0
  123. package/src/package/scripts/script-comparator.js +46 -0
  124. package/src/package/scripts/script-comparator.test.js +119 -0
  125. package/src/package/scripts/scripts-sorter.js +7 -0
  126. package/src/package/scripts/scripts-sorter.test.js +20 -0
  127. package/src/package/scripts/test-script-updater.js +15 -0
  128. package/src/package/scripts/test-script-updater.test.js +32 -0
  129. package/src/package/vcs-host-details.js +12 -0
  130. package/src/package/vcs-host-details.test.js +16 -0
  131. package/src/package-managers/current-manager-resolver.js +21 -0
  132. package/src/package-managers/current-manager-resolver.test.js +51 -0
  133. package/src/package-managers/index.js +5 -0
  134. package/src/package-managers/lifter.js +7 -0
  135. package/src/package-managers/lifter.test.js +18 -0
  136. package/src/package-managers/lockfile-path-resolver.js +10 -0
  137. package/src/package-managers/lockfile-path-resolver.test.js +15 -0
  138. package/src/package-managers/npm/index.js +2 -0
  139. package/src/package-managers/npm/scaffolder.js +19 -0
  140. package/src/package-managers/npm/scaffolder.test.js +33 -0
  141. package/src/package-managers/npm/tester.js +11 -0
  142. package/src/package-managers/npm/tester.test.js +33 -0
  143. package/src/package-managers/scaffolder.js +11 -0
  144. package/src/package-managers/scaffolder.test.js +27 -0
  145. package/src/package-managers/tester.js +11 -0
  146. package/src/package-managers/tester.test.js +33 -0
  147. package/src/package-managers/yarn/index.js +2 -0
  148. package/src/package-managers/yarn/scaffolder.js +19 -0
  149. package/src/package-managers/yarn/scaffolder.test.js +33 -0
  150. package/src/package-managers/yarn/tester.js +11 -0
  151. package/src/package-managers/yarn/tester.test.js +33 -0
  152. package/src/plugins-schemas.js +4 -0
  153. package/src/plugins-schemas.test.js +28 -0
  154. package/src/project-type/application/index.js +2 -0
  155. package/src/project-type/application/predicate.js +3 -0
  156. package/src/project-type/application/predicate.test.js +14 -0
  157. package/src/project-type/application/scaffolder.js +24 -0
  158. package/src/project-type/application/scaffolder.test.js +35 -0
  159. package/src/project-type/cli/index.js +3 -0
  160. package/src/project-type/cli/lifter.js +5 -0
  161. package/src/project-type/cli/lifter.test.js +20 -0
  162. package/src/project-type/cli/scaffolder.js +52 -0
  163. package/src/project-type/cli/scaffolder.test.js +103 -0
  164. package/src/project-type/cli/tester.js +3 -0
  165. package/src/project-type/cli/tester.test.js +14 -0
  166. package/src/project-type/index.js +3 -0
  167. package/src/project-type/lifter.js +23 -0
  168. package/src/project-type/lifter.test.js +69 -0
  169. package/src/project-type/monorepo/index.js +1 -0
  170. package/src/project-type/monorepo/scaffolder.js +16 -0
  171. package/src/project-type/monorepo/scaffolder.test.js +27 -0
  172. package/src/project-type/package/build-details.js +56 -0
  173. package/src/project-type/package/build-details.test.js +111 -0
  174. package/src/project-type/package/documentation.js +34 -0
  175. package/src/project-type/package/documentation.test.js +106 -0
  176. package/src/project-type/package/index.js +3 -0
  177. package/src/project-type/package/lifter.js +5 -0
  178. package/src/project-type/package/lifter.test.js +20 -0
  179. package/src/project-type/package/scaffolder.js +84 -0
  180. package/src/project-type/package/scaffolder.test.js +267 -0
  181. package/src/project-type/package/tester.js +5 -0
  182. package/src/project-type/package/tester.test.js +28 -0
  183. package/src/project-type/publishable/access-level.js +3 -0
  184. package/src/project-type/publishable/access-level.test.js +13 -0
  185. package/src/project-type/publishable/badges.js +20 -0
  186. package/src/project-type/publishable/badges.test.js +29 -0
  187. package/src/project-type/publishable/bundler/index.js +1 -0
  188. package/src/project-type/publishable/bundler/prompt.js +16 -0
  189. package/src/project-type/publishable/bundler/prompt.test.js +35 -0
  190. package/src/project-type/publishable/bundler/scaffolder.js +8 -0
  191. package/src/project-type/publishable/bundler/scaffolder.test.js +33 -0
  192. package/src/project-type/publishable/index.js +2 -0
  193. package/src/project-type/publishable/lifter.js +24 -0
  194. package/src/project-type/publishable/lifter.test.js +49 -0
  195. package/src/project-type/publishable/provenance/index.js +1 -0
  196. package/src/project-type/publishable/provenance/lifter.js +15 -0
  197. package/src/project-type/publishable/provenance/lifter.test.js +56 -0
  198. package/src/project-type/publishable/provenance/slsa.js +17 -0
  199. package/src/project-type/publishable/provenance/slsa.test.js +21 -0
  200. package/src/project-type/publishable/registry-resolver.js +15 -0
  201. package/src/project-type/publishable/registry-resolver.test.js +60 -0
  202. package/src/project-type/publishable/scaffolder.js +7 -0
  203. package/src/project-type/publishable/scaffolder.test.js +23 -0
  204. package/src/project-type/scaffolder.js +56 -0
  205. package/src/project-type/scaffolder.test.js +115 -0
  206. package/src/project-type/tester.js +9 -0
  207. package/src/project-type/tester.test.js +51 -0
  208. package/src/project-type-plugin/index.js +1 -0
  209. package/src/project-type-plugin/prompt.js +16 -0
  210. package/src/project-type-plugin/prompt.test.js +39 -0
  211. package/src/project-type-plugin/scaffolder.js +28 -0
  212. package/src/project-type-plugin/scaffolder.test.js +70 -0
  213. package/src/prompts/conditionals.js +39 -0
  214. package/src/prompts/conditionals.test.js +95 -0
  215. package/src/prompts/question-names.js +17 -0
  216. package/src/prompts/questions.js +158 -0
  217. package/src/prompts/questions.test.js +247 -0
  218. package/src/prompts/validators.js +9 -0
  219. package/src/prompts/validators.test.js +19 -0
  220. package/src/registries/index.js +2 -0
  221. package/src/registries/lifter.js +43 -0
  222. package/src/registries/lifter.test.js +63 -0
  223. package/src/registries/npm-config/list-builder.js +9 -0
  224. package/src/registries/npm-config/list-builder.test.js +43 -0
  225. package/src/registries/tester.js +3 -0
  226. package/src/registries/tester.test.js +9 -0
  227. package/src/runkit/badge/index.js +1 -0
  228. package/src/runkit/badge/scaffolder.js +13 -0
  229. package/src/runkit/badge/scaffolder.test.js +22 -0
  230. package/src/runkit/index.js +4 -0
  231. package/src/runkit/lifter.js +5 -0
  232. package/src/runkit/lifter.test.js +17 -0
  233. package/src/runkit/remover.js +3 -0
  234. package/src/runkit/remover.test.js +9 -0
  235. package/src/runkit/scaffolder.js +11 -0
  236. package/src/runkit/scaffolder.test.js +35 -0
  237. package/src/runkit/tester.js +3 -0
  238. package/src/runkit/tester.test.js +16 -0
  239. package/src/scaffolder.js +155 -0
  240. package/src/scaffolder.test.js +239 -0
  241. package/src/tester.js +17 -0
  242. package/src/tester.test.js +37 -0
  243. package/src/testing/index.js +1 -0
  244. package/src/testing/scaffolder.js +31 -0
  245. package/src/testing/scaffolder.test.js +63 -0
  246. package/src/testing/unit/index.js +1 -0
  247. package/src/testing/unit/prompt.js +15 -0
  248. package/src/testing/unit/prompt.test.js +33 -0
  249. package/src/testing/unit/scaffolder.js +30 -0
  250. package/src/testing/unit/scaffolder.test.js +54 -0
  251. package/src/vcs/ignore-lists-builder.js +6 -0
  252. package/src/vcs/ignore-lists-builder.test.js +25 -0
  253. package/src/vcs/schema.js +7 -0
  254. package/src/vcs/schema.test.js +40 -0
  255. package/src/verification/index.js +1 -0
  256. package/src/verification/scaffolder.js +35 -0
  257. package/src/verification/scaffolder.test.js +56 -0
@@ -0,0 +1,56 @@
1
+ import {promises as fs} from 'node:fs';
2
+ import deepmerge from 'deepmerge';
3
+ import touch from 'touch';
4
+ import {dialects, projectTypes} from '@form8ion/javascript-core';
5
+ import {scaffold as scaffoldBundler} from '../publishable/bundler/index.js';
6
+
7
+ const defaultBuildDirectory = 'lib';
8
+
9
+ async function createExample(projectRoot) {
10
+ return fs.writeFile(`${projectRoot}/example.js`, "import {} from './lib/index.js';\n");
11
+ }
12
+
13
+ async function buildDetailsForCommonJsProject({projectRoot, provideExample}) {
14
+ await Promise.all([
15
+ touch(`${projectRoot}/index.js`),
16
+ provideExample
17
+ ? fs.writeFile(`${projectRoot}/example.js`, "const {} = require('.');\n")
18
+ : Promise.resolve()
19
+ ]);
20
+
21
+ return {};
22
+ }
23
+
24
+ export default async function buildDetails({
25
+ projectRoot,
26
+ projectName,
27
+ packageBundlers,
28
+ dialect,
29
+ provideExample,
30
+ decisions
31
+ }) {
32
+ if (dialects.COMMON_JS === dialect) return buildDetailsForCommonJsProject({projectRoot, provideExample});
33
+
34
+ await fs.mkdir(`${projectRoot}/src`, {recursive: true});
35
+ const [bundlerResults] = await Promise.all([
36
+ scaffoldBundler({bundlers: packageBundlers, projectRoot, dialect, decisions, projectType: projectTypes.PACKAGE}),
37
+ provideExample ? await createExample(projectRoot, projectName, dialect) : Promise.resolve,
38
+ touch(`${projectRoot}/src/index.js`)
39
+ ]);
40
+
41
+ return deepmerge(
42
+ bundlerResults,
43
+ {
44
+ dependencies: {javascript: {development: ['rimraf']}},
45
+ scripts: {
46
+ clean: `rimraf ./${defaultBuildDirectory}`,
47
+ prebuild: 'run-s clean',
48
+ build: 'npm-run-all --print-label --parallel build:*',
49
+ prepack: 'run-s build',
50
+ ...provideExample && {'pregenerate:md': 'run-s build'}
51
+ },
52
+ vcsIgnore: {directories: [`/${defaultBuildDirectory}/`]},
53
+ buildDirectory: defaultBuildDirectory
54
+ }
55
+ );
56
+ }
@@ -0,0 +1,111 @@
1
+ import {promises as fs} from 'node:fs';
2
+ import touch from 'touch';
3
+ import {dialects, projectTypes} from '@form8ion/javascript-core';
4
+
5
+ import {describe, expect, it, vi} from 'vitest';
6
+ import any from '@travi/any';
7
+ import {when} from 'vitest-when';
8
+
9
+ import {scaffold as scaffoldBundler} from '../publishable/bundler/index.js';
10
+ import buildDetails from './build-details.js';
11
+
12
+ vi.mock('node:fs');
13
+ vi.mock('make-dir');
14
+ vi.mock('touch');
15
+ vi.mock('../publishable/bundler');
16
+
17
+ describe('package build details', () => {
18
+ const projectRoot = any.string();
19
+ const projectName = any.word();
20
+ const pathToExample = `${projectRoot}/example.js`;
21
+ const bundlerResults = any.simpleObject();
22
+ const packageBundlers = any.simpleObject();
23
+ const decisions = any.simpleObject();
24
+
25
+ it('should correctly define a common-js project', async () => {
26
+ const results = await buildDetails({
27
+ dialect: dialects.COMMON_JS,
28
+ projectRoot,
29
+ projectName,
30
+ provideExample: true
31
+ });
32
+
33
+ expect(results).toEqual({});
34
+ expect(fs.writeFile).toHaveBeenCalledWith(pathToExample, "const {} = require('.');\n");
35
+ expect(touch).toHaveBeenCalledWith(`${projectRoot}/index.js`);
36
+ });
37
+
38
+ it('should not create the example file for a common-js project if `provideExample` is `false`', async () => {
39
+ await buildDetails({
40
+ dialect: dialects.COMMON_JS,
41
+ projectRoot,
42
+ projectName,
43
+ provideExample: false
44
+ });
45
+
46
+ expect(fs.writeFile).not.toHaveBeenCalled();
47
+ });
48
+
49
+ it('should define a modern-js project correctly', async () => {
50
+ const dialect = dialects.BABEL;
51
+ when(scaffoldBundler)
52
+ .calledWith({bundlers: packageBundlers, decisions, projectRoot, dialect, projectType: projectTypes.PACKAGE})
53
+ .thenResolve(bundlerResults);
54
+
55
+ const results = await buildDetails({
56
+ dialect,
57
+ projectRoot,
58
+ projectName,
59
+ packageBundlers,
60
+ decisions,
61
+ provideExample: true
62
+ });
63
+
64
+ expect(results).toEqual({
65
+ ...bundlerResults,
66
+ dependencies: {javascript: {development: ['rimraf']}},
67
+ scripts: {
68
+ clean: 'rimraf ./lib',
69
+ prebuild: 'run-s clean',
70
+ build: 'npm-run-all --print-label --parallel build:*',
71
+ prepack: 'run-s build',
72
+ 'pregenerate:md': 'run-s build'
73
+ },
74
+ vcsIgnore: {directories: ['/lib/']},
75
+ buildDirectory: 'lib'
76
+ });
77
+ expect(fs.mkdir).toHaveBeenCalledWith(`${projectRoot}/src`, {recursive: true});
78
+ expect(touch).toHaveBeenCalledWith(`${projectRoot}/src/index.js`);
79
+ expect(fs.writeFile).toHaveBeenCalledWith(pathToExample, "import {} from './lib/index.js';\n");
80
+ });
81
+
82
+ it('should not create the example file for a modern-js project when `provideExample` is `false`', async () => {
83
+ const dialect = dialects.BABEL;
84
+ when(scaffoldBundler)
85
+ .calledWith({bundlers: packageBundlers, decisions, projectRoot, dialect, projectType: projectTypes.PACKAGE})
86
+ .thenResolve(bundlerResults);
87
+
88
+ const results = await buildDetails({
89
+ dialect,
90
+ projectRoot,
91
+ projectName,
92
+ packageBundlers,
93
+ decisions,
94
+ provideExample: false
95
+ });
96
+
97
+ expect(results).toEqual({
98
+ ...bundlerResults,
99
+ dependencies: {javascript: {development: ['rimraf']}},
100
+ scripts: {
101
+ clean: 'rimraf ./lib',
102
+ prebuild: 'run-s clean',
103
+ build: 'npm-run-all --print-label --parallel build:*',
104
+ prepack: 'run-s build'
105
+ },
106
+ vcsIgnore: {directories: ['/lib/']},
107
+ buildDirectory: 'lib'
108
+ });
109
+ expect(fs.writeFile).not.toHaveBeenCalled();
110
+ });
111
+ });
@@ -0,0 +1,34 @@
1
+ import {packageManagers} from '@form8ion/javascript-core';
2
+
3
+ import buildGenerationCommand from '../../documentation/generation-command.js';
4
+
5
+ function getInstallationCommand(packageManager) {
6
+ if (packageManagers.NPM === packageManager) return 'npm install';
7
+ if (packageManagers.YARN === packageManager) return 'yarn add';
8
+
9
+ throw new Error(
10
+ `The ${packageManager} package manager is currently not supported. `
11
+ + `Only ${Object.values(packageManagers).join(' and ')} are currently supported.`
12
+ );
13
+ }
14
+
15
+ export default function scaffoldPackageDocumentation({scope, packageName, packageManager, visibility, provideExample}) {
16
+ return {
17
+ usage: `### Installation
18
+ ${'Private' === visibility ? `
19
+ :warning: this is a private package, so you will need to use an npm token with
20
+ access to private packages under \`@${scope}\`
21
+ ` : ''
22
+ }
23
+ \`\`\`sh
24
+ $ ${getInstallationCommand(packageManager)} ${packageName}
25
+ \`\`\`${provideExample
26
+ ? `
27
+
28
+ ### Example
29
+
30
+ run \`${buildGenerationCommand(packageManager)}\` to inject the usage example`
31
+ : ''
32
+ }`
33
+ };
34
+ }
@@ -0,0 +1,106 @@
1
+ import {packageManagers} 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 buildDocumentationCommand from '../../documentation/generation-command.js';
8
+ import scaffoldDocumentation from './documentation.js';
9
+
10
+ vi.mock('../../documentation/generation-command.js');
11
+
12
+ describe('package documentation', () => {
13
+ const packageName = any.string();
14
+ const documentationGenerationCommand = any.string();
15
+
16
+ it('should provide `npm install` instructions for packages when the package manager is npm', () => {
17
+ when(buildDocumentationCommand).calledWith(packageManagers.NPM).thenReturn(documentationGenerationCommand);
18
+
19
+ const documentation = scaffoldDocumentation({
20
+ packageName,
21
+ packageManager: packageManagers.NPM,
22
+ provideExample: true
23
+ });
24
+
25
+ expect(documentation.usage).toEqual(`### Installation
26
+
27
+ \`\`\`sh
28
+ $ npm install ${packageName}
29
+ \`\`\`
30
+
31
+ ### Example
32
+
33
+ run \`${documentationGenerationCommand}\` to inject the usage example`);
34
+ });
35
+
36
+ it('should not include the example section when `provideExample` is `false`', () => {
37
+ when(buildDocumentationCommand).calledWith(packageManagers.NPM).thenReturn(documentationGenerationCommand);
38
+
39
+ const documentation = scaffoldDocumentation({
40
+ packageName,
41
+ packageManager: packageManagers.NPM,
42
+ provideExample: false
43
+ });
44
+
45
+ expect(documentation.usage).toEqual(`### Installation
46
+
47
+ \`\`\`sh
48
+ $ npm install ${packageName}
49
+ \`\`\``);
50
+ });
51
+
52
+ it('should provide `yarn add` instructions for packages when the package manager is yarn', () => {
53
+ when(buildDocumentationCommand).calledWith(packageManagers.YARN).thenReturn(documentationGenerationCommand);
54
+
55
+ const documentation = scaffoldDocumentation({
56
+ packageName,
57
+ packageManager: packageManagers.YARN,
58
+ provideExample: true
59
+ });
60
+
61
+ expect(documentation.usage).toEqual(`### Installation
62
+
63
+ \`\`\`sh
64
+ $ yarn add ${packageName}
65
+ \`\`\`
66
+
67
+ ### Example
68
+
69
+ run \`${documentationGenerationCommand}\` to inject the usage example`);
70
+ });
71
+
72
+ it('should throw an error for unsupported package managers', () => {
73
+ const packageManager = any.word();
74
+
75
+ expect(() => scaffoldDocumentation({packageName, packageManager})).toThrowError(
76
+ `The ${packageManager} package manager is currently not supported. `
77
+ + `Only ${Object.values(packageManagers).join(' and ')} are currently supported.`
78
+ );
79
+ });
80
+
81
+ it('should provide an access note for private packages', () => {
82
+ const scope = any.word();
83
+ when(buildDocumentationCommand).calledWith(packageManagers.NPM).thenReturn(documentationGenerationCommand);
84
+
85
+ const documentation = scaffoldDocumentation({
86
+ packageName,
87
+ packageManager: packageManagers.NPM,
88
+ visibility: 'Private',
89
+ scope,
90
+ provideExample: true
91
+ });
92
+
93
+ expect(documentation.usage).toEqual(`### Installation
94
+
95
+ :warning: this is a private package, so you will need to use an npm token with
96
+ access to private packages under \`@${scope}\`
97
+
98
+ \`\`\`sh
99
+ $ npm install ${packageName}
100
+ \`\`\`
101
+
102
+ ### Example
103
+
104
+ run \`${documentationGenerationCommand}\` to inject the usage example`);
105
+ });
106
+ });
@@ -0,0 +1,3 @@
1
+ export {default as scaffold} from './scaffolder.js';
2
+ export {default as lift} from './lifter.js';
3
+ export {default as test} from './tester.js';
@@ -0,0 +1,5 @@
1
+ import {lift as liftPublishable} from '../publishable/index.js';
2
+
3
+ export default function liftPackage({projectRoot, packageDetails, configs}) {
4
+ return liftPublishable({projectRoot, packageDetails, configs});
5
+ }
@@ -0,0 +1,20 @@
1
+ import {describe, expect, it, vi} from 'vitest';
2
+ import any from '@travi/any';
3
+ import {when} from 'vitest-when';
4
+
5
+ import {lift as liftPublishable} from '../publishable/index.js';
6
+ import lift from './lifter.js';
7
+
8
+ vi.mock('../publishable/lifter');
9
+
10
+ describe('package project-type lifter', () => {
11
+ it('should leverage the publishable lifter', async () => {
12
+ const projectRoot = any.string();
13
+ const packageDetails = any.simpleObject();
14
+ const configs = any.simpleObject();
15
+ const publishableResults = any.simpleObject();
16
+ when(liftPublishable).calledWith({projectRoot, packageDetails, configs}).thenResolve(publishableResults);
17
+
18
+ expect(await lift({projectRoot, packageDetails, configs})).toEqual(publishableResults);
19
+ });
20
+ });
@@ -0,0 +1,84 @@
1
+ import deepmerge from 'deepmerge';
2
+ import {info} from '@travi/cli-messages';
3
+ import {dialects, mergeIntoExistingPackageJson} from '@form8ion/javascript-core';
4
+
5
+ import determinePackageAccessLevelFromProjectVisibility from '../publishable/access-level.js';
6
+ import {scaffold as scaffoldPublishable} from '../publishable/index.js';
7
+ import scaffoldPackageDocumentation from './documentation.js';
8
+ import buildDetails from './build-details.js';
9
+
10
+ export default async function scaffoldPackageProjectType({
11
+ projectRoot,
12
+ projectName,
13
+ packageName,
14
+ packageManager,
15
+ visibility,
16
+ scope,
17
+ packageBundlers,
18
+ decisions,
19
+ dialect,
20
+ provideExample,
21
+ publishRegistry
22
+ }) {
23
+ info('Scaffolding Package Details');
24
+
25
+ const packageAccessLevel = determinePackageAccessLevelFromProjectVisibility({projectVisibility: visibility});
26
+ const [detailsForBuild, publishableResults] = await Promise.all([
27
+ buildDetails({
28
+ projectRoot,
29
+ projectName,
30
+ packageBundlers,
31
+ dialect,
32
+ provideExample,
33
+ decisions
34
+ }),
35
+ scaffoldPublishable({packageName, packageAccessLevel}),
36
+ mergeIntoExistingPackageJson({
37
+ projectRoot,
38
+ config: {
39
+ files: ['example.js', ...dialects.COMMON_JS === dialect ? ['index.js'] : ['lib/', 'src/']],
40
+ publishConfig: {
41
+ access: packageAccessLevel,
42
+ ...publishRegistry && {registry: publishRegistry}
43
+ },
44
+ sideEffects: false,
45
+ ...dialects.BABEL === dialect && {
46
+ main: './lib/index.js',
47
+ module: './lib/index.mjs',
48
+ exports: {
49
+ module: './lib/index.mjs',
50
+ require: './lib/index.js',
51
+ import: './lib/index.mjs'
52
+ }
53
+ },
54
+ ...dialects.ESM === dialect && {
55
+ main: './lib/index.js',
56
+ exports: './lib/index.js'
57
+ },
58
+ ...dialects.TYPESCRIPT === dialect && {
59
+ main: './lib/index.js',
60
+ module: './lib/index.mjs',
61
+ types: './lib/index.d.ts',
62
+ exports: {
63
+ types: './lib/index.d.ts',
64
+ require: './lib/index.js',
65
+ import: './lib/index.mjs'
66
+ }
67
+ }
68
+ }
69
+ })
70
+ ]);
71
+
72
+ return deepmerge.all([
73
+ publishableResults,
74
+ {
75
+ documentation: scaffoldPackageDocumentation({packageName, visibility, scope, packageManager, provideExample}),
76
+ nextSteps: [
77
+ {summary: 'Add the appropriate `save` flag to the installation instructions in the README'},
78
+ {summary: 'Define supported node.js versions as `engines.node` in the `package.json` file'},
79
+ {summary: 'Publish pre-release versions to npm until package is stable enough to publish v1.0.0'}
80
+ ]
81
+ },
82
+ detailsForBuild
83
+ ]);
84
+ }
@@ -0,0 +1,267 @@
1
+ import {dialects, mergeIntoExistingPackageJson} from '@form8ion/javascript-core';
2
+
3
+ import {beforeEach, describe, expect, it, vi} from 'vitest';
4
+ import any from '@travi/any';
5
+ import {when} from 'vitest-when';
6
+
7
+ import determinePackageAccessLevelFromProjectVisibility from '../publishable/access-level.js';
8
+ import {scaffold as scaffoldPublishable} from '../publishable/index.js';
9
+ import * as buildDetails from './build-details.js';
10
+ import * as documentationScaffolder from './documentation.js';
11
+ import scaffoldPackage from './scaffolder.js';
12
+
13
+ vi.mock('@form8ion/javascript-core');
14
+ vi.mock('../publishable/access-level.js');
15
+ vi.mock('../publishable/index.js');
16
+ vi.mock('./build-details.js');
17
+ vi.mock('./documentation.js');
18
+
19
+ describe('package project-type scaffolder', () => {
20
+ const projectRoot = any.string();
21
+ const packageBundlers = any.simpleObject();
22
+ const projectName = any.word();
23
+ const packageName = any.word();
24
+ const packageManager = any.word();
25
+ const visibility = any.word();
26
+ const packageAccessLevel = any.word();
27
+ const scope = any.word();
28
+ const provideExample = any.boolean();
29
+ const publishableResults = any.simpleObject();
30
+ const commonNextSteps = [
31
+ {summary: 'Add the appropriate `save` flag to the installation instructions in the README'},
32
+ {summary: 'Define supported node.js versions as `engines.node` in the `package.json` file'},
33
+ {summary: 'Publish pre-release versions to npm until package is stable enough to publish v1.0.0'}
34
+ ];
35
+ const documentation = any.simpleObject();
36
+ const decisions = any.simpleObject();
37
+ const buildDetailsResults = any.simpleObject();
38
+
39
+ beforeEach(() => {
40
+ when(documentationScaffolder.default)
41
+ .calledWith({scope, packageName, visibility, packageManager, provideExample})
42
+ .thenReturn(documentation);
43
+ when(determinePackageAccessLevelFromProjectVisibility)
44
+ .calledWith({projectVisibility: visibility})
45
+ .thenReturn(packageAccessLevel);
46
+ });
47
+
48
+ it('should scaffold details specific to a modern-js package', async () => {
49
+ const dialect = dialects.BABEL;
50
+ when(scaffoldPublishable).calledWith({packageName, packageAccessLevel}).thenReturn(publishableResults);
51
+ when(buildDetails.default).calledWith({
52
+ projectRoot,
53
+ projectName,
54
+ packageBundlers,
55
+ dialect,
56
+ provideExample,
57
+ decisions
58
+ }).thenResolve(buildDetailsResults);
59
+
60
+ expect(await scaffoldPackage({
61
+ projectRoot,
62
+ projectName,
63
+ packageName,
64
+ packageManager,
65
+ visibility,
66
+ scope,
67
+ packageBundlers,
68
+ decisions,
69
+ dialect,
70
+ provideExample
71
+ })).toEqual({
72
+ ...publishableResults,
73
+ ...buildDetailsResults,
74
+ documentation,
75
+ nextSteps: commonNextSteps
76
+ });
77
+ expect(mergeIntoExistingPackageJson).toHaveBeenCalledWith({
78
+ projectRoot,
79
+ config: {
80
+ sideEffects: false,
81
+ main: './lib/index.js',
82
+ module: './lib/index.mjs',
83
+ exports: {
84
+ module: './lib/index.mjs',
85
+ require: './lib/index.js',
86
+ import: './lib/index.mjs'
87
+ },
88
+ files: ['example.js', 'lib/', 'src/'],
89
+ publishConfig: {access: packageAccessLevel}
90
+ }
91
+ });
92
+ });
93
+
94
+ it('should scaffold details specific to an esm-only package', async () => {
95
+ const dialect = dialects.ESM;
96
+ when(scaffoldPublishable).calledWith({packageName, packageAccessLevel}).thenReturn(publishableResults);
97
+ when(buildDetails.default).calledWith({
98
+ projectRoot,
99
+ projectName,
100
+ packageBundlers,
101
+ dialect,
102
+ provideExample,
103
+ decisions
104
+ }).thenResolve(buildDetailsResults);
105
+
106
+ expect(await scaffoldPackage({
107
+ projectRoot,
108
+ projectName,
109
+ packageName,
110
+ visibility,
111
+ dialect,
112
+ scope,
113
+ packageManager,
114
+ packageBundlers,
115
+ decisions,
116
+ provideExample
117
+ })).toEqual({
118
+ ...publishableResults,
119
+ ...buildDetailsResults,
120
+ documentation,
121
+ nextSteps: commonNextSteps
122
+ });
123
+ expect(mergeIntoExistingPackageJson).toHaveBeenCalledWith({
124
+ projectRoot,
125
+ config: {
126
+ main: './lib/index.js',
127
+ exports: './lib/index.js',
128
+ files: ['example.js', 'lib/', 'src/'],
129
+ sideEffects: false,
130
+ publishConfig: {access: packageAccessLevel}
131
+ }
132
+ });
133
+ });
134
+
135
+ it('should scaffold details specific to a typescript package', async () => {
136
+ const dialect = dialects.TYPESCRIPT;
137
+ when(scaffoldPublishable).calledWith({packageName, packageAccessLevel}).thenReturn(publishableResults);
138
+ when(buildDetails.default).calledWith({
139
+ projectRoot,
140
+ projectName,
141
+ packageBundlers,
142
+ dialect,
143
+ provideExample,
144
+ decisions
145
+ }).thenResolve(buildDetailsResults);
146
+
147
+ expect(await scaffoldPackage({
148
+ projectRoot,
149
+ projectName,
150
+ packageName,
151
+ packageManager,
152
+ visibility,
153
+ scope,
154
+ packageBundlers,
155
+ decisions,
156
+ dialect,
157
+ provideExample
158
+ })).toEqual({
159
+ ...publishableResults,
160
+ ...buildDetailsResults,
161
+ documentation,
162
+ nextSteps: commonNextSteps
163
+ });
164
+ expect(mergeIntoExistingPackageJson).toHaveBeenCalledWith({
165
+ projectRoot,
166
+ config: {
167
+ sideEffects: false,
168
+ main: './lib/index.js',
169
+ module: './lib/index.mjs',
170
+ types: './lib/index.d.ts',
171
+ exports: {
172
+ types: './lib/index.d.ts',
173
+ require: './lib/index.js',
174
+ import: './lib/index.mjs'
175
+ },
176
+ files: ['example.js', 'lib/', 'src/'],
177
+ publishConfig: {access: packageAccessLevel}
178
+ }
179
+ });
180
+ });
181
+
182
+ it('should not include build details when the project will not be scaffolded', async () => {
183
+ const dialect = dialects.COMMON_JS;
184
+ when(scaffoldPublishable).calledWith({packageName, packageAccessLevel}).thenReturn(publishableResults);
185
+ when(buildDetails.default).calledWith({
186
+ projectRoot,
187
+ projectName,
188
+ packageBundlers,
189
+ dialect,
190
+ provideExample,
191
+ decisions
192
+ }).thenResolve(buildDetailsResults);
193
+
194
+ expect(await scaffoldPackage({
195
+ projectRoot,
196
+ packageName,
197
+ projectName,
198
+ packageManager,
199
+ visibility,
200
+ scope,
201
+ decisions,
202
+ packageBundlers,
203
+ dialect,
204
+ provideExample
205
+ })).toEqual({
206
+ ...publishableResults,
207
+ ...buildDetailsResults,
208
+ documentation,
209
+ nextSteps: commonNextSteps
210
+ });
211
+ expect(mergeIntoExistingPackageJson).toHaveBeenCalledWith({
212
+ projectRoot,
213
+ config: {
214
+ files: ['example.js', 'index.js'],
215
+ publishConfig: {access: packageAccessLevel},
216
+ sideEffects: false
217
+ }
218
+ });
219
+ });
220
+
221
+ it('should define the registry to publish to when provided', async () => {
222
+ const publishRegistry = any.url();
223
+ const dialect = dialects.BABEL;
224
+ when(scaffoldPublishable).calledWith({packageName, packageAccessLevel}).thenReturn(publishableResults);
225
+ when(buildDetails.default).calledWith({
226
+ projectRoot,
227
+ projectName,
228
+ packageBundlers,
229
+ dialect,
230
+ provideExample,
231
+ decisions
232
+ }).thenResolve(buildDetailsResults);
233
+
234
+ await scaffoldPackage({
235
+ projectRoot,
236
+ packageName,
237
+ projectName,
238
+ packageManager,
239
+ visibility,
240
+ scope,
241
+ decisions,
242
+ publishRegistry,
243
+ dialect,
244
+ provideExample,
245
+ packageBundlers
246
+ });
247
+
248
+ expect(mergeIntoExistingPackageJson).toHaveBeenCalledWith({
249
+ projectRoot,
250
+ config: {
251
+ sideEffects: false,
252
+ main: './lib/index.js',
253
+ module: './lib/index.mjs',
254
+ exports: {
255
+ module: './lib/index.mjs',
256
+ require: './lib/index.js',
257
+ import: './lib/index.mjs'
258
+ },
259
+ files: ['example.js', 'lib/', 'src/'],
260
+ publishConfig: {
261
+ access: packageAccessLevel,
262
+ registry: publishRegistry
263
+ }
264
+ }
265
+ });
266
+ });
267
+ });
@@ -0,0 +1,5 @@
1
+ export default async function projectIsPackage({
2
+ packageDetails: {exports, publishConfig, bin, private: projectMarkedPrivate}
3
+ }) {
4
+ return !projectMarkedPrivate && (!!exports || (!!publishConfig && !bin));
5
+ }