@flarum/cli 1.0.0 → 2.0.0-beta.12

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 (193) hide show
  1. package/README.md +2 -2
  2. package/bin/run +5 -3
  3. package/boilerplate/skeleton/extension/.gitattributes +17 -3
  4. package/boilerplate/skeleton/extension/.github/workflows/backend.yml +15 -0
  5. package/boilerplate/skeleton/extension/.github/workflows/frontend.yml +20 -0
  6. package/boilerplate/skeleton/extension/.styleci.yml +14 -0
  7. package/boilerplate/skeleton/extension/LICENSE.md +1 -0
  8. package/boilerplate/skeleton/extension/README.md +7 -7
  9. package/boilerplate/skeleton/extension/composer.json +11 -9
  10. package/boilerplate/skeleton/extension/extend.php +10 -10
  11. package/boilerplate/skeleton/extension/gitignore +12 -0
  12. package/boilerplate/skeleton/extension/js/.bundlewatch.config.json +8 -0
  13. package/boilerplate/skeleton/extension/js/admin.js +2 -1
  14. package/boilerplate/skeleton/extension/js/admin.ts +2 -0
  15. package/boilerplate/skeleton/extension/js/forum.js +2 -1
  16. package/boilerplate/skeleton/extension/js/forum.ts +2 -0
  17. package/boilerplate/skeleton/extension/js/gitignore +9 -0
  18. package/boilerplate/skeleton/extension/js/package.json +13 -9
  19. package/boilerplate/skeleton/extension/js/src/admin/index.js +4 -2
  20. package/boilerplate/skeleton/extension/js/src/admin/index.ts +5 -0
  21. package/boilerplate/skeleton/extension/js/src/common/index.js +5 -0
  22. package/boilerplate/skeleton/extension/js/src/common/index.ts +5 -0
  23. package/boilerplate/skeleton/extension/js/src/forum/index.js +4 -2
  24. package/boilerplate/skeleton/extension/js/src/forum/index.ts +5 -0
  25. package/boilerplate/skeleton/extension/js/tsconfig.json +6 -1
  26. package/boilerplate/skeleton/extension/locale/en.yml +1 -1
  27. package/boilerplate/stubs/migration.php +1 -1
  28. package/lib/base-command.d.ts +29 -6
  29. package/lib/base-command.js +145 -59
  30. package/lib/boilersmith/exposed-param-manager.d.ts +8 -0
  31. package/lib/boilersmith/exposed-param-manager.js +31 -0
  32. package/lib/boilersmith/io.d.ts +54 -0
  33. package/lib/boilersmith/io.js +97 -0
  34. package/lib/boilersmith/paths.d.ts +22 -0
  35. package/lib/boilersmith/paths.js +29 -0
  36. package/lib/boilersmith/scaffolding/audit-step-factory.d.ts +5 -0
  37. package/lib/boilersmith/scaffolding/audit-step-factory.js +61 -0
  38. package/lib/boilersmith/scaffolding/infra-step-factory.d.ts +5 -0
  39. package/lib/boilersmith/scaffolding/infra-step-factory.js +34 -0
  40. package/lib/boilersmith/scaffolding/init-step-factory.d.ts +5 -0
  41. package/lib/boilersmith/scaffolding/init-step-factory.js +34 -0
  42. package/lib/boilersmith/scaffolding/module.d.ts +82 -0
  43. package/lib/boilersmith/scaffolding/module.js +116 -0
  44. package/lib/boilersmith/scaffolding/scaffolder.d.ts +32 -0
  45. package/lib/boilersmith/scaffolding/scaffolder.js +203 -0
  46. package/lib/boilersmith/scaffolding/template-param.d.ts +23 -0
  47. package/lib/boilersmith/scaffolding/template-param.js +46 -0
  48. package/lib/boilersmith/step-manager.d.ts +85 -0
  49. package/lib/boilersmith/step-manager.js +234 -0
  50. package/lib/boilersmith/steps/stub-base.d.ts +53 -0
  51. package/lib/boilersmith/steps/stub-base.js +54 -0
  52. package/lib/{utils → boilersmith/utils}/clone-and-fill.d.ts +0 -0
  53. package/lib/{utils → boilersmith/utils}/clone-and-fill.js +2 -2
  54. package/lib/boilersmith/utils/cond-format.d.ts +1 -0
  55. package/lib/boilersmith/utils/cond-format.js +8 -0
  56. package/lib/boilersmith/utils/json-leaf-paths.d.ts +7 -0
  57. package/lib/boilersmith/utils/json-leaf-paths.js +17 -0
  58. package/lib/boilersmith/utils/read-tpl.d.ts +2 -0
  59. package/lib/boilersmith/utils/read-tpl.js +10 -0
  60. package/lib/boilersmith/utils/rename-keys.d.ts +1 -0
  61. package/lib/boilersmith/utils/rename-keys.js +7 -0
  62. package/lib/commands/audit/infra.d.ts +16 -0
  63. package/lib/commands/audit/infra.js +27 -0
  64. package/lib/commands/infra.d.ts +20 -0
  65. package/lib/commands/infra.js +55 -0
  66. package/lib/commands/init.d.ts +4 -3
  67. package/lib/commands/init.js +8 -6
  68. package/lib/commands/make/backend/api-controller.d.ts +4 -3
  69. package/lib/commands/make/backend/api-controller.js +3 -2
  70. package/lib/commands/make/backend/api-serializer-attributes.d.ts +4 -3
  71. package/lib/commands/make/backend/api-serializer-attributes.js +1 -1
  72. package/lib/commands/make/backend/api-serializer.d.ts +4 -3
  73. package/lib/commands/make/backend/api-serializer.js +3 -2
  74. package/lib/commands/make/backend/command.d.ts +4 -3
  75. package/lib/commands/make/backend/command.js +3 -2
  76. package/lib/commands/make/backend/event-listener.d.ts +4 -3
  77. package/lib/commands/make/backend/event-listener.js +3 -2
  78. package/lib/commands/make/backend/handler.d.ts +4 -3
  79. package/lib/commands/make/backend/handler.js +4 -3
  80. package/lib/commands/make/backend/integration-test.d.ts +4 -3
  81. package/lib/commands/make/backend/integration-test.js +3 -2
  82. package/lib/commands/make/backend/job.d.ts +4 -3
  83. package/lib/commands/make/backend/job.js +3 -2
  84. package/lib/commands/make/backend/migration.d.ts +4 -3
  85. package/lib/commands/make/backend/migration.js +3 -2
  86. package/lib/commands/make/backend/model.d.ts +4 -3
  87. package/lib/commands/make/backend/model.js +22 -21
  88. package/lib/commands/make/backend/policy.d.ts +4 -3
  89. package/lib/commands/make/backend/policy.js +3 -2
  90. package/lib/commands/make/backend/repository.d.ts +4 -3
  91. package/lib/commands/make/backend/repository.js +3 -2
  92. package/lib/commands/make/backend/route.d.ts +4 -3
  93. package/lib/commands/make/backend/route.js +1 -1
  94. package/lib/commands/make/backend/service-provider.d.ts +4 -3
  95. package/lib/commands/make/backend/service-provider.js +3 -2
  96. package/lib/commands/make/backend/validator.d.ts +4 -3
  97. package/lib/commands/make/backend/validator.js +3 -2
  98. package/lib/commands/make/frontend/component.d.ts +4 -3
  99. package/lib/commands/make/frontend/component.js +3 -2
  100. package/lib/commands/make/frontend/modal.d.ts +4 -3
  101. package/lib/commands/make/frontend/modal.js +3 -2
  102. package/lib/commands/make/frontend/model.d.ts +4 -3
  103. package/lib/commands/make/frontend/model.js +3 -2
  104. package/lib/commands/update/js-imports.d.ts +4 -3
  105. package/lib/commands/update/js-imports.js +1 -1
  106. package/lib/help.d.ts +5 -6
  107. package/lib/help.js +5 -4
  108. package/lib/index.d.ts +1 -1
  109. package/lib/index.js +3 -2
  110. package/lib/providers/index.d.ts +5 -0
  111. package/lib/providers/index.js +2 -0
  112. package/lib/{provider → providers}/php-provider.d.ts +0 -0
  113. package/lib/{provider → providers}/php-provider.js +2 -2
  114. package/lib/steps/extenders/api-serializer.js +2 -3
  115. package/lib/steps/extenders/base.d.ts +10 -10
  116. package/lib/steps/extenders/base.js +11 -11
  117. package/lib/steps/extenders/console-command.js +2 -3
  118. package/lib/steps/extenders/event.js +2 -3
  119. package/lib/steps/extenders/policy.js +2 -3
  120. package/lib/steps/extenders/route.js +2 -3
  121. package/lib/steps/extenders/service-provider.js +2 -3
  122. package/lib/steps/gen-ext-scaffolder.d.ts +6 -0
  123. package/lib/steps/gen-ext-scaffolder.js +594 -0
  124. package/lib/steps/js/base.d.ts +9 -9
  125. package/lib/steps/js/base.js +13 -12
  126. package/lib/steps/js/model.d.ts +5 -5
  127. package/lib/steps/js/model.js +8 -13
  128. package/lib/steps/misc/composer.d.ts +5 -6
  129. package/lib/steps/misc/composer.js +3 -3
  130. package/lib/steps/misc/git.d.ts +11 -0
  131. package/lib/steps/misc/git.js +20 -0
  132. package/lib/steps/misc/yarn.d.ts +5 -6
  133. package/lib/steps/misc/yarn.js +3 -3
  134. package/lib/steps/stubs/backend/api-controller.d.ts +1 -8
  135. package/lib/steps/stubs/backend/api-controller.js +2 -3
  136. package/lib/steps/stubs/backend/api-serializer.d.ts +4 -9
  137. package/lib/steps/stubs/backend/api-serializer.js +4 -4
  138. package/lib/steps/stubs/backend/command.d.ts +0 -5
  139. package/lib/steps/stubs/backend/command.js +1 -1
  140. package/lib/steps/stubs/backend/event-listener.d.ts +0 -5
  141. package/lib/steps/stubs/backend/event-listener.js +1 -1
  142. package/lib/steps/stubs/backend/handler-command.js +1 -1
  143. package/lib/steps/stubs/backend/handler.js +1 -1
  144. package/lib/steps/stubs/backend/migration.d.ts +4 -5
  145. package/lib/steps/stubs/backend/migration.js +8 -8
  146. package/lib/steps/stubs/backend/model.d.ts +4 -4
  147. package/lib/steps/stubs/backend/model.js +4 -4
  148. package/lib/steps/stubs/backend/policy.d.ts +0 -5
  149. package/lib/steps/stubs/backend/policy.js +1 -1
  150. package/lib/steps/stubs/backend/repository.d.ts +0 -5
  151. package/lib/steps/stubs/backend/repository.js +1 -1
  152. package/lib/steps/stubs/flarum-base.d.ts +9 -0
  153. package/lib/steps/stubs/flarum-base.js +10 -0
  154. package/lib/steps/stubs/frontend/component.js +0 -1
  155. package/lib/steps/stubs/frontend/modal.js +0 -1
  156. package/lib/steps/stubs/frontend/model.d.ts +4 -4
  157. package/lib/steps/stubs/frontend/model.js +3 -3
  158. package/lib/steps/stubs/js-base.d.ts +6 -7
  159. package/lib/steps/stubs/js-base.js +11 -16
  160. package/lib/steps/stubs/php-base.d.ts +7 -8
  161. package/lib/steps/stubs/php-base.js +12 -20
  162. package/lib/steps/update/js-imports.d.ts +5 -6
  163. package/lib/steps/update/js-imports.js +16 -19
  164. package/lib/utils/composer.d.ts +64 -0
  165. package/lib/utils/composer.js +8 -0
  166. package/lib/utils/migration.js +3 -3
  167. package/lib/utils/model-name.js +6 -6
  168. package/lib/utils/validation.d.ts +10 -7
  169. package/lib/utils/validation.js +9 -6
  170. package/oclif.manifest.json +1 -1
  171. package/package.json +55 -36
  172. package/php-subsystem/src/NodeVisitors/AddExtender.php +2 -1
  173. package/boilerplate/skeleton/extension/.github/workflows/build.yml +0 -32
  174. package/boilerplate/skeleton/extension/.github/workflows/lint.yml +0 -32
  175. package/boilerplate/skeleton/extension/.github/workflows/test.yml +0 -78
  176. package/lib/commands/infra/backend-testing.d.ts +0 -14
  177. package/lib/commands/infra/backend-testing.js +0 -26
  178. package/lib/provider/param-provider.d.ts +0 -15
  179. package/lib/provider/param-provider.js +0 -39
  180. package/lib/provider/path-provider.d.ts +0 -19
  181. package/lib/provider/path-provider.js +0 -24
  182. package/lib/steps/infra/backend-testing.d.ts +0 -8
  183. package/lib/steps/infra/backend-testing.js +0 -22
  184. package/lib/steps/infra/base.d.ts +0 -20
  185. package/lib/steps/infra/base.js +0 -36
  186. package/lib/steps/init/extension-skeleton.d.ts +0 -12
  187. package/lib/steps/init/extension-skeleton.js +0 -142
  188. package/lib/steps/step-manager.d.ts +0 -71
  189. package/lib/steps/step-manager.js +0 -173
  190. package/lib/steps/stubs/base.d.ts +0 -49
  191. package/lib/steps/stubs/base.js +0 -58
  192. package/lib/utils/extension-metadata.d.ts +0 -2
  193. package/lib/utils/extension-metadata.js +0 -21
@@ -0,0 +1,234 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AtomicStepManager = exports.StepManager = void 0;
4
+ /* eslint-disable no-await-in-loop */
5
+ const mem_fs_1 = require("mem-fs");
6
+ const mem_fs_editor_1 = require("mem-fs-editor");
7
+ const exposed_param_manager_1 = require("./exposed-param-manager");
8
+ const formatDependencies = (strings) => strings.map(s => `"${s}"`).join(', ');
9
+ class StepManager {
10
+ constructor() {
11
+ this.steps = [];
12
+ this.namedSteps = new Map();
13
+ this.exposedParams = new exposed_param_manager_1.ExposedParamManager();
14
+ }
15
+ /**
16
+ * A step is an incremental operation that updates the filesystem.
17
+ */
18
+ step(step, shouldRun = {}, dependencies = [], predefinedParams = {}, mapPaths = []) {
19
+ this.validateDependencies(step, dependencies, mapPaths);
20
+ this.steps = [...this.steps, { step, shouldRun, dependencies, predefinedParams, mapPaths }];
21
+ return this;
22
+ }
23
+ namedStep(name, step, shouldRun = {}, dependencies = [], predefinedParams = {}, mapPaths = []) {
24
+ if (this.namedSteps.has(name)) {
25
+ throw new Error(`Named steps must have unique names. A step with name "${name}" already exists.`);
26
+ }
27
+ this.validateDependencies(step, dependencies, mapPaths);
28
+ const newStep = { name, step, shouldRun, dependencies, predefinedParams, mapPaths };
29
+ this.steps = [...this.steps, newStep];
30
+ this.namedSteps.set(name, newStep);
31
+ return this;
32
+ }
33
+ atomicGroup(callback) {
34
+ const atomicCollection = new AtomicStepManager(this.namedSteps, this.exposedParams);
35
+ callback(atomicCollection);
36
+ this.steps = [...this.steps, atomicCollection];
37
+ return this;
38
+ }
39
+ validateDependencies(step, dependencies, mapPaths) {
40
+ const missingDependencySteps = dependencies.map(dep => dep.sourceStep).filter(stepName => !this.namedSteps.has(stepName));
41
+ if (missingDependencySteps.length > 0) {
42
+ throw new Error(`Step of type "${step.type}" depends on nonexistent named steps ${formatDependencies(missingDependencySteps)}`);
43
+ }
44
+ const missingDependencyParams = [];
45
+ const missingDependencyParamSteps = [];
46
+ for (const dependency of dependencies) {
47
+ const sourceStep = this.namedSteps.get(dependency.sourceStep);
48
+ if (!(sourceStep === null || sourceStep === void 0 ? void 0 : sourceStep.step.exposes.includes(dependency.exposedName)) && dependency.exposedName !== '__succeeded') {
49
+ missingDependencyParamSteps.push(sourceStep === null || sourceStep === void 0 ? void 0 : sourceStep.name);
50
+ missingDependencyParams.push(dependency.exposedName);
51
+ }
52
+ if (mapPaths.length === 0 && (sourceStep === null || sourceStep === void 0 ? void 0 : sourceStep.mapPaths.length)) {
53
+ throw new Error(`Non path-mapped step of type "${step.type}" may not depend on path-mapped step "${sourceStep === null || sourceStep === void 0 ? void 0 : sourceStep.name}".`);
54
+ }
55
+ const missingMapPathsDeps = mapPaths.filter(p => sourceStep && !sourceStep.mapPaths.includes(p));
56
+ if (sourceStep && (missingMapPathsDeps === null || missingMapPathsDeps === void 0 ? void 0 : missingMapPathsDeps.length) && sourceStep.mapPaths.length > 0) {
57
+ throw new Error(`Step of type "${step.type}" (A) depends on named step: "${sourceStep.name}" (B), but is mapped across some paths that (B) is not: "${missingMapPathsDeps.join(', ')}"`);
58
+ }
59
+ }
60
+ if (missingDependencyParamSteps.length > 0) {
61
+ throw new Error(`Step of type "${step.type}" depends on nonexistent exposed params ${formatDependencies(missingDependencyParams)} from named steps ${formatDependencies(missingDependencyParamSteps)}`);
62
+ }
63
+ }
64
+ async run(paths, io, providers, dry = false) {
65
+ if (dry && this.steps.some(s => !(s instanceof AtomicStepManager) && !s.step.composable)) {
66
+ throw new Error('Cannot dry run, as this step manager has non-composable steps.');
67
+ }
68
+ const stepNames = [];
69
+ const checkAndRun = async (step, packagePath) => {
70
+ const shouldRun = await this.stepShouldRun(step, io, packagePath);
71
+ if (!shouldRun)
72
+ return;
73
+ const fs = await this.runStep(step, paths, io, providers, packagePath);
74
+ if (!dry) {
75
+ await this.commit(fs);
76
+ }
77
+ stepNames.push(packagePath ? `${step.step.type} (${packagePath})` : step.step.type);
78
+ };
79
+ try {
80
+ for (const storedStep of this.steps) {
81
+ if (storedStep instanceof AtomicStepManager) {
82
+ const res = await storedStep.run(paths, io, providers);
83
+ if (!res.succeeded) {
84
+ throw new Error(res.error);
85
+ }
86
+ stepNames.push(...res.stepsRan);
87
+ }
88
+ else if (storedStep.mapPaths.length > 0) {
89
+ for (const path of storedStep.mapPaths) {
90
+ await checkAndRun(storedStep, path);
91
+ }
92
+ }
93
+ else {
94
+ await checkAndRun(storedStep);
95
+ }
96
+ }
97
+ }
98
+ catch (error) {
99
+ return {
100
+ succeeded: false,
101
+ error: error instanceof Error ? error.message : String(error),
102
+ errorTrace: error instanceof Error ? error.stack : undefined,
103
+ stepsRan: stepNames,
104
+ messages: io.getOutput(),
105
+ };
106
+ }
107
+ return {
108
+ succeeded: true,
109
+ stepsRan: stepNames,
110
+ messages: io.getOutput(),
111
+ };
112
+ }
113
+ async stepShouldRun(storedStep, io, packagePath) {
114
+ let allDependenciesRan = true;
115
+ let noRequiredNonFalsyDependenciesAreFalsy = true;
116
+ for (const dep of storedStep.dependencies) {
117
+ const sourceStep = this.namedSteps.get(dep.sourceStep);
118
+ const sourcePackagePath = (sourceStep === null || sourceStep === void 0 ? void 0 : sourceStep.mapPaths.length) ? packagePath : undefined;
119
+ if (!this.exposedParams.stepRan(dep.sourceStep, sourcePackagePath))
120
+ allDependenciesRan = false;
121
+ if (dep.exposedName !== '__succeeded' && dep.dontRunIfFalsy && !this.exposedParams.get(dep.sourceStep, dep.exposedName, sourcePackagePath)) {
122
+ noRequiredNonFalsyDependenciesAreFalsy = false;
123
+ }
124
+ }
125
+ if (!allDependenciesRan || !noRequiredNonFalsyDependenciesAreFalsy)
126
+ return false;
127
+ if (!storedStep.shouldRun.optional)
128
+ return true;
129
+ const promptConfirm = await io.newInstance({ context: 'Confirm Step' }, []).getParam({
130
+ name: 'execute_step',
131
+ message: storedStep.shouldRun.confirmationMessage || `Run step of type "${storedStep.step.type}"?`,
132
+ initial: storedStep.shouldRun.default || false,
133
+ type: 'confirm',
134
+ });
135
+ return promptConfirm;
136
+ }
137
+ async runStep(storedStep, paths, io, providers, packagePath, fs = (0, mem_fs_1.create)()) {
138
+ const initial = storedStep.dependencies.reduce((initial, dep) => {
139
+ const sourceStep = this.namedSteps.get(dep.sourceStep);
140
+ let depValue;
141
+ depValue =
142
+ dep.exposedName === '__succeeded' ?
143
+ this.exposedParams.stepRan(dep.sourceStep, packagePath) :
144
+ this.exposedParams.get(dep.sourceStep, dep.exposedName, (sourceStep === null || sourceStep === void 0 ? void 0 : sourceStep.mapPaths.length) ? packagePath : undefined);
145
+ if (dep.modifier) {
146
+ depValue = dep.modifier(depValue);
147
+ }
148
+ initial[dep.consumedName || dep.exposedName] = depValue;
149
+ return initial;
150
+ }, {});
151
+ const cloned = io.newInstance(Object.assign(Object.assign({}, initial), storedStep.predefinedParams), io.getOutput());
152
+ const stepPaths = packagePath ? paths.onMonorepoSub(packagePath) : paths;
153
+ const newFs = await storedStep.step.run(fs, stepPaths, cloned, providers);
154
+ if (storedStep.name) {
155
+ this.exposedParams.add(storedStep.name, storedStep.step.getExposed(stepPaths, io), packagePath);
156
+ }
157
+ return newFs;
158
+ }
159
+ async commit(fs) {
160
+ return new Promise((resolve, _reject) => {
161
+ (0, mem_fs_editor_1.create)(fs).commit(err => {
162
+ if (err) {
163
+ throw new Error(err);
164
+ }
165
+ resolve(true);
166
+ });
167
+ });
168
+ }
169
+ }
170
+ exports.StepManager = StepManager;
171
+ class AtomicStepManager extends StepManager {
172
+ constructor(parentNamedSteps = new Map(), parentExposedParams = new exposed_param_manager_1.ExposedParamManager()) {
173
+ super();
174
+ this.steps = [];
175
+ this.namedSteps = parentNamedSteps;
176
+ this.exposedParams = parentExposedParams;
177
+ }
178
+ step(step, shouldRun = {}, dependencies = [], predefinedParams = {}, mapPaths = []) {
179
+ if (!step.composable) {
180
+ throw new Error(`Step of type "${step.type}" is not composable, and cannot be added to an atomic group.`);
181
+ }
182
+ return super.step(step, shouldRun, dependencies, predefinedParams, mapPaths);
183
+ }
184
+ namedStep(name, step, shouldRun = {}, dependencies = [], predefinedParams = {}, mapPaths = []) {
185
+ if (!step.composable) {
186
+ throw new Error(`Step of type "${step.type}" is not composable, and cannot be added to an atomic group.`);
187
+ }
188
+ return super.namedStep(name, step, shouldRun, dependencies, predefinedParams, mapPaths);
189
+ }
190
+ atomicGroup(_callback) {
191
+ throw new Error("Atomic groups can't be nested.");
192
+ }
193
+ async run(paths, io, providers, dry = false) {
194
+ let fs = (0, mem_fs_1.create)();
195
+ const checkAndRun = async (step, packagePath) => {
196
+ const shouldRun = await this.stepShouldRun(step, io, packagePath);
197
+ if (!shouldRun)
198
+ return;
199
+ fs = await this.runStep(step, paths, io, providers, packagePath, fs);
200
+ stepNames.push(packagePath ? `${step.step.type} (${packagePath})` : step.step.type);
201
+ };
202
+ const stepNames = [];
203
+ try {
204
+ for (const storedStep of this.steps) {
205
+ if (storedStep.mapPaths.length > 0) {
206
+ for (const path of storedStep.mapPaths) {
207
+ await checkAndRun(storedStep, path);
208
+ }
209
+ }
210
+ else {
211
+ await checkAndRun(storedStep);
212
+ }
213
+ }
214
+ }
215
+ catch (error) {
216
+ return {
217
+ error: error instanceof Error ? error.message : String(error),
218
+ errorTrace: error instanceof Error ? error.stack : undefined,
219
+ succeeded: false,
220
+ stepsRan: [],
221
+ messages: io.getOutput(),
222
+ };
223
+ }
224
+ if (!dry) {
225
+ await this.commit(fs);
226
+ }
227
+ return {
228
+ succeeded: true,
229
+ stepsRan: stepNames,
230
+ messages: io.getOutput(),
231
+ };
232
+ }
233
+ }
234
+ exports.AtomicStepManager = AtomicStepManager;
@@ -0,0 +1,53 @@
1
+ import { Store } from 'mem-fs';
2
+ import { ParamDef, IO } from 'boilersmith/io';
3
+ import { Paths } from 'boilersmith/paths';
4
+ import { DefaultProviders, Step } from 'boilersmith/step-manager';
5
+ import { Scaffolder } from 'boilersmith/scaffolding/scaffolder';
6
+ interface UserProvidedParam extends Omit<ParamDef, 'type'> {
7
+ type: string;
8
+ }
9
+ export interface StubGenerationSchema {
10
+ /**
11
+ * A period-delimited subdirectory for where the stub should be
12
+ * located relative to the package root (IE `schema.root`).
13
+ */
14
+ recommendedSubdir: string;
15
+ /**
16
+ * Create the file in the recommended subdir regardless
17
+ * of the current requested dir.
18
+ */
19
+ forceRecommendedSubdir?: boolean;
20
+ /**
21
+ * Where should the file be created in relation to the extension root?
22
+ *
23
+ * Defaults to `./src`.
24
+ */
25
+ root?: string;
26
+ /**
27
+ * The relative path to the stub's source file relative to the
28
+ * `stubs` directory.
29
+ */
30
+ sourceFile: string;
31
+ params: UserProvidedParam[];
32
+ }
33
+ export declare abstract class BaseStubStep<Providers extends DefaultProviders, PN extends string = string, MN extends string = string> implements Step<Providers> {
34
+ protected stubDir: string;
35
+ protected scaffolder: Scaffolder<PN, MN>;
36
+ constructor(stubDir: string, scaffolder: Scaffolder<PN, MN>);
37
+ abstract type: string;
38
+ protected abstract defaultRoot: string;
39
+ protected abstract schema: StubGenerationSchema;
40
+ composable: boolean;
41
+ get exposes(): string[];
42
+ protected additionalExposes: string[];
43
+ get implicitParams(): string[];
44
+ protected additionalImplicitParams: string[];
45
+ protected params: Record<string, unknown>;
46
+ protected subdir: string;
47
+ run(fs: Store, paths: Paths, io: IO, _providers: Providers): Promise<Store>;
48
+ getExposed(_paths: Paths, _paramProvider: IO): Record<string, unknown>;
49
+ protected precompileParams(_fs: Store, _paths: Paths, _paramProvider: IO): Promise<Record<string, unknown>>;
50
+ protected compileParams(fs: Store, paths: Paths, io: IO): Promise<Record<string, unknown>>;
51
+ protected abstract getFileName(_fs: Store, _paths: Paths, io: IO): Promise<string>;
52
+ }
53
+ export {};
@@ -0,0 +1,54 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.BaseStubStep = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const pick_deep_1 = (0, tslib_1.__importDefault)(require("pick-deep"));
6
+ const mem_fs_editor_1 = require("mem-fs-editor");
7
+ const clone_and_fill_1 = require("../utils/clone-and-fill");
8
+ const node_path_1 = require("node:path");
9
+ class BaseStubStep {
10
+ constructor(stubDir, scaffolder) {
11
+ this.composable = true;
12
+ this.additionalExposes = [];
13
+ this.additionalImplicitParams = [];
14
+ this.params = {};
15
+ this.stubDir = stubDir;
16
+ this.scaffolder = scaffolder;
17
+ }
18
+ get exposes() {
19
+ return this.additionalExposes;
20
+ }
21
+ get implicitParams() {
22
+ return [...this.additionalImplicitParams, 'extensionId'];
23
+ }
24
+ async run(fs, paths, io, _providers) {
25
+ const fsEditor = (0, mem_fs_editor_1.create)(fs);
26
+ this.params = await this.compileParams(fs, paths, io);
27
+ const newFileName = await this.getFileName(fs, paths, io);
28
+ const newFilePath = paths.package(this.schema.root || this.defaultRoot, this.subdir, newFileName);
29
+ const stub = (0, clone_and_fill_1.cloneAndFill)(this.schema.sourceFile, this.params);
30
+ fsEditor.copyTpl((0, node_path_1.resolve)(this.stubDir, stub), newFilePath, this.params);
31
+ return fs;
32
+ }
33
+ getExposed(_paths, _paramProvider) {
34
+ return (0, pick_deep_1.default)(this.params, this.exposes);
35
+ }
36
+ async precompileParams(_fs, _paths, _paramProvider) {
37
+ return {};
38
+ }
39
+ async compileParams(fs, paths, io) {
40
+ const params = await this.precompileParams(fs, paths, io);
41
+ const paramDefs = this.schema.params.filter(param => !this.implicitParams.includes(param.name) && !Object.keys(params).includes(param.name));
42
+ for (const paramDef of paramDefs) {
43
+ // eslint-disable-next-line no-await-in-loop
44
+ params[paramDef.name] = await io.getParam(paramDef);
45
+ }
46
+ for (const implicitParam of this.implicitParams) {
47
+ if (!params[implicitParam] && io.hasCached(implicitParam)) {
48
+ params[implicitParam] = io.cached()[implicitParam];
49
+ }
50
+ }
51
+ return params;
52
+ }
53
+ }
54
+ exports.BaseStubStep = BaseStubStep;
@@ -16,10 +16,10 @@ function cloneAndFill(obj, params) {
16
16
  if (obj !== new Object(obj))
17
17
  return obj;
18
18
  const newObj = {};
19
- Object.keys(obj).forEach(key => {
19
+ for (const key of Object.keys(obj)) {
20
20
  const value = obj[key];
21
21
  newObj[key] = recursiveCopyAndFill(value, params);
22
- });
22
+ }
23
23
  return newObj;
24
24
  };
25
25
  return recursiveCopyAndFill(obj, params);
@@ -0,0 +1 @@
1
+ export declare function condFormat(condition: boolean, format: (...args: string[]) => string, message: string | string[]): string;
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.condFormat = void 0;
4
+ function condFormat(condition, format, message) {
5
+ const args = Array.isArray(message) ? message : [message];
6
+ return condition ? format(...args) : args.join(' ');
7
+ }
8
+ exports.condFormat = condFormat;
@@ -0,0 +1,7 @@
1
+ declare type JSONSchema = string | number | boolean | JSONSchemaObject | JSONSchemaArray | null;
2
+ interface JSONSchemaObject {
3
+ [key: string]: JSONSchema;
4
+ }
5
+ declare type JSONSchemaArray = Array<JSONSchema>;
6
+ export declare function jsonLeafPaths(obj: JSONSchema): string[];
7
+ export {};
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.jsonLeafPaths = void 0;
4
+ function inner(o, prefix) {
5
+ if (Array.isArray(o)) {
6
+ // Placed separately in case we eventually decide to support leaves in arrays.
7
+ return [prefix.join('.')];
8
+ }
9
+ if (o && typeof o === 'object') {
10
+ return Object.entries(o).flatMap(([k, v]) => inner(v, [...prefix, k]));
11
+ }
12
+ return [prefix.join('.')];
13
+ }
14
+ function jsonLeafPaths(obj) {
15
+ return inner(obj, []);
16
+ }
17
+ exports.jsonLeafPaths = jsonLeafPaths;
@@ -0,0 +1,2 @@
1
+ import { Data, Options } from 'ejs';
2
+ export declare function readTpl(path: string, data: Data, options?: Options): string;
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.readTpl = void 0;
4
+ const ejs_1 = require("ejs");
5
+ const node_fs_1 = require("node:fs");
6
+ function readTpl(path, data, options) {
7
+ const template = (0, node_fs_1.readFileSync)(path, 'utf8');
8
+ return (0, ejs_1.render)(template, data, Object.assign(Object.assign({ filename: path }, options), { async: false }));
9
+ }
10
+ exports.readTpl = readTpl;
@@ -0,0 +1 @@
1
+ export declare function renameKeys(obj: Record<string, unknown>, func: (key: string, val: unknown) => string): Record<string, unknown>;
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.renameKeys = void 0;
4
+ function renameKeys(obj, func) {
5
+ return Object.fromEntries(Object.entries(obj).map(([key, val]) => [func(key, val), val]));
6
+ }
7
+ exports.renameKeys = renameKeys;
@@ -0,0 +1,16 @@
1
+ import { StepManager } from 'boilersmith/step-manager';
2
+ import BaseCommand from '../../base-command';
3
+ import { FlarumProviders } from '../../providers';
4
+ export default class AuditInfra extends BaseCommand {
5
+ static description: string;
6
+ static flags: {
7
+ fix: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
8
+ monorepo: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
9
+ };
10
+ static args: {
11
+ name: string;
12
+ description: string;
13
+ }[];
14
+ protected steps(stepManager: StepManager<FlarumProviders>): StepManager<FlarumProviders>;
15
+ protected additionalPreRunChecks(extRoot: string): Promise<void>;
16
+ }
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const tslib_1 = require("tslib");
4
+ const base_command_1 = (0, tslib_1.__importDefault)(require("../../base-command"));
5
+ const gen_ext_scaffolder_1 = require("../../steps/gen-ext-scaffolder");
6
+ const core_1 = require("@oclif/core");
7
+ class AuditInfra extends base_command_1.default {
8
+ steps(stepManager) {
9
+ this.dry = !this.flags.fix;
10
+ const mapPaths = this.flags.monorepo ? this.monorepoPaths({
11
+ includeCore: true,
12
+ includeExtensions: true,
13
+ includePhpPackages: false,
14
+ includeJSPackages: false,
15
+ }) : [];
16
+ stepManager.step((0, gen_ext_scaffolder_1.genExtScaffolder)().genAuditStep(!this.flags.fix), {}, [], {}, mapPaths);
17
+ return stepManager;
18
+ }
19
+ async additionalPreRunChecks(extRoot) {
20
+ const files = (0, gen_ext_scaffolder_1.genExtScaffolder)().moduleFiles(this.args.module);
21
+ await this.confirmOverrideFiles(extRoot, files, 'Infrastructure files already exist. Overwrite with the latest version?');
22
+ }
23
+ }
24
+ exports.default = AuditInfra;
25
+ AuditInfra.description = 'Check for outdated config files, infrastructure, setup, etc.';
26
+ AuditInfra.flags = Object.assign({ fix: core_1.Flags.boolean({ char: 'f', default: false }), monorepo: core_1.Flags.boolean({ char: 'm', default: false }) }, base_command_1.default.flags);
27
+ AuditInfra.args = [...base_command_1.default.args];
@@ -0,0 +1,20 @@
1
+ import { StepManager } from 'boilersmith/step-manager';
2
+ import BaseCommand from '../base-command';
3
+ import { FlarumProviders } from '../providers';
4
+ export default class Infra extends BaseCommand {
5
+ static description: string;
6
+ static flags: {
7
+ monorepo: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
8
+ };
9
+ static args: ({
10
+ name: string;
11
+ description: string;
12
+ } | {
13
+ name: string;
14
+ description: string;
15
+ required: boolean;
16
+ options: ("core" | "icon" | "admin" | "forum" | "js" | "jsCommon" | "css" | "locale" | "gitConf" | "githubActions" | "prettier" | "typescript" | "bundlewatch" | "backendTesting" | "editorConfig" | "styleci")[];
17
+ })[];
18
+ protected steps(stepManager: StepManager<FlarumProviders>): StepManager<FlarumProviders>;
19
+ protected additionalPreRunChecks(extRoot: string): Promise<void>;
20
+ }
@@ -0,0 +1,55 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const tslib_1 = require("tslib");
4
+ const composer_1 = require("../steps/misc/composer");
5
+ const base_command_1 = (0, tslib_1.__importDefault)(require("../base-command"));
6
+ const gen_ext_scaffolder_1 = require("../steps/gen-ext-scaffolder");
7
+ const yarn_1 = require("../steps/misc/yarn");
8
+ const core_1 = require("@oclif/core");
9
+ class Infra extends base_command_1.default {
10
+ steps(stepManager) {
11
+ const module = this.args.module;
12
+ const mapPaths = this.flags.monorepo ? this.monorepoPaths({
13
+ includeCore: true,
14
+ includeExtensions: true,
15
+ includePhpPackages: false,
16
+ includeJSPackages: false,
17
+ }) : [];
18
+ stepManager
19
+ .namedStep('infra', (0, gen_ext_scaffolder_1.genExtScaffolder)().genInfraStep(this.args.module), {}, [], {}, mapPaths);
20
+ const JS_MODULES = ['js', 'prettier', 'typescript'];
21
+ const PHP_MODULES = ['backendTesting'];
22
+ if (!this.flags.monorepo && JS_MODULES.includes(module)) {
23
+ stepManager.step(new yarn_1.YarnInstall(), { optional: true, confirmationMessage: 'Run `yarn`? (recommended)', default: true }, [
24
+ {
25
+ sourceStep: 'infra',
26
+ exposedName: '__succeeded',
27
+ dontRunIfFalsy: true,
28
+ },
29
+ ]);
30
+ }
31
+ if (!this.flags.monorepo && PHP_MODULES.includes(module)) {
32
+ stepManager.step(new composer_1.ComposerInstall(), { optional: true, confirmationMessage: 'Run `composer update`? (recommended)', default: true }, [
33
+ {
34
+ sourceStep: 'infra',
35
+ exposedName: '__succeeded',
36
+ dontRunIfFalsy: true,
37
+ },
38
+ ]);
39
+ }
40
+ return stepManager;
41
+ }
42
+ async additionalPreRunChecks(extRoot) {
43
+ const files = (0, gen_ext_scaffolder_1.genExtScaffolder)().moduleFiles(this.args.module);
44
+ await this.confirmOverrideFiles(extRoot, files, 'Infrastructure files already exist. Overwrite with the latest version?');
45
+ }
46
+ }
47
+ exports.default = Infra;
48
+ Infra.description = 'Add/Update infrastructure to the latest scaffolding for some module in an extension. For example, you can use this to add/update TypeScript, backend testing, GitHub Actions, and other features.';
49
+ Infra.flags = Object.assign({ monorepo: core_1.Flags.boolean({ char: 'm', default: false }) }, base_command_1.default.flags);
50
+ Infra.args = [{
51
+ name: 'module',
52
+ description: 'The name of the module to enable/update.',
53
+ required: true,
54
+ options: [...gen_ext_scaffolder_1.EXTENSION_MODULES],
55
+ }, ...base_command_1.default.args];
@@ -1,16 +1,17 @@
1
- import { StepManager } from '../steps/step-manager';
1
+ import { StepManager } from 'boilersmith/step-manager';
2
2
  import BaseCommand from '../base-command';
3
+ import { FlarumProviders } from '../providers';
3
4
  export default class Init extends BaseCommand {
4
5
  static description: string;
5
6
  static flags: {
6
- [x: string]: import("@oclif/command/lib/flags").IFlag<any>;
7
+ [x: string]: import("@oclif/core/lib/interfaces").CompletableFlag<any>;
7
8
  };
8
9
  static args: {
9
10
  name: string;
10
11
  description: string;
11
12
  }[];
12
13
  protected requireExistingExtension: boolean;
13
- protected steps(stepManager: StepManager): StepManager;
14
+ protected steps(stepManager: StepManager<FlarumProviders>): StepManager<FlarumProviders>;
14
15
  protected welcomeMessage(): string;
15
16
  protected goodbyeMessage(): string;
16
17
  protected additionalPreRunChecks(extRoot: string): Promise<void>;
@@ -1,11 +1,12 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const tslib_1 = require("tslib");
4
- const extension_skeleton_1 = require("../steps/init/extension-skeleton");
5
4
  const composer_1 = require("../steps/misc/composer");
6
5
  const yarn_1 = require("../steps/misc/yarn");
7
- const base_command_1 = tslib_1.__importDefault(require("../base-command"));
8
- const yosay_1 = tslib_1.__importDefault(require("yosay"));
6
+ const base_command_1 = (0, tslib_1.__importDefault)(require("../base-command"));
7
+ const yosay_1 = (0, tslib_1.__importDefault)(require("yosay"));
8
+ const gen_ext_scaffolder_1 = require("../steps/gen-ext-scaffolder");
9
+ const git_1 = require("../steps/misc/git");
9
10
  class Init extends base_command_1.default {
10
11
  constructor() {
11
12
  super(...arguments);
@@ -13,18 +14,19 @@ class Init extends base_command_1.default {
13
14
  }
14
15
  steps(stepManager) {
15
16
  return stepManager
16
- .namedStep('skeleton', new extension_skeleton_1.ExtensionSkeleton(), {})
17
+ .namedStep('gitInit', new git_1.GitInit(), { optional: true, confirmationMessage: 'Run `git init`? (recommended)', default: true })
18
+ .namedStep('skeleton', (0, gen_ext_scaffolder_1.genExtScaffolder)().genInitStep())
17
19
  .step(new composer_1.ComposerInstall(), { optional: true, confirmationMessage: 'Run `composer install`? (recommended)', default: true })
18
20
  .step(new yarn_1.YarnInstall(), { optional: true, confirmationMessage: 'Run `yarn install`? (recommended)', default: true }, [
19
21
  {
20
22
  sourceStep: 'skeleton',
21
- exposedName: 'useJs',
23
+ exposedName: 'modules.js',
22
24
  dontRunIfFalsy: true,
23
25
  },
24
26
  ]);
25
27
  }
26
28
  welcomeMessage() {
27
- return yosay_1.default('Welcome to a Flarum extension generator\n\n- Flarum Team');
29
+ return (0, yosay_1.default)('Welcome to a Flarum extension generator\n\n- Flarum Team');
28
30
  }
29
31
  goodbyeMessage() {
30
32
  return 'Extension generation complete! Visit https://docs.flarum.org/extend to learn more about Flarum extension development.';
@@ -1,13 +1,14 @@
1
- import { StepManager } from '../../../steps/step-manager';
1
+ import { StepManager } from 'boilersmith/step-manager';
2
2
  import BaseCommand from '../../../base-command';
3
+ import { FlarumProviders } from '../../../providers';
3
4
  export default class ApiController extends BaseCommand {
4
5
  static description: string;
5
6
  static flags: {
6
- [x: string]: import("@oclif/command/lib/flags").IFlag<any>;
7
+ [x: string]: import("@oclif/core/lib/interfaces").CompletableFlag<any>;
7
8
  };
8
9
  static args: {
9
10
  name: string;
10
11
  description: string;
11
12
  }[];
12
- protected steps(stepManager: StepManager): StepManager;
13
+ protected steps(stepManager: StepManager<FlarumProviders>): StepManager<FlarumProviders>;
13
14
  }
@@ -1,15 +1,16 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const tslib_1 = require("tslib");
4
- const base_command_1 = tslib_1.__importDefault(require("../../../base-command"));
4
+ const base_command_1 = (0, tslib_1.__importDefault)(require("../../../base-command"));
5
5
  const api_controller_1 = require("../../../steps/stubs/backend/api-controller");
6
6
  const route_1 = require("../../../steps/extenders/route");
7
+ const gen_ext_scaffolder_1 = require("../../../steps/gen-ext-scaffolder");
7
8
  class ApiController extends base_command_1.default {
8
9
  steps(stepManager) {
9
10
  return stepManager
10
11
  .atomicGroup(stepManager => {
11
12
  stepManager
12
- .namedStep('apiController', new api_controller_1.GenerateApiControllerStub())
13
+ .namedStep('apiController', new api_controller_1.GenerateApiControllerStub(this.STUB_PATH, (0, gen_ext_scaffolder_1.genExtScaffolder)()))
13
14
  .step(new route_1.GenerateRoutesExtender(), { optional: true, confirmationMessage: 'Generate corresponding extender?', default: true }, [
14
15
  {
15
16
  sourceStep: 'apiController',