@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,594 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.genExtScaffolder = exports.EXTENSION_MODULES = exports.EXTENSION_PARAMS = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const scaffolder_1 = require("boilersmith/scaffolding/scaffolder");
6
+ const chalk_1 = (0, tslib_1.__importDefault)(require("chalk"));
7
+ const mem_fs_editor_1 = require("mem-fs-editor");
8
+ const node_fs_1 = require("node:fs");
9
+ const node_path_1 = require("node:path");
10
+ const simple_git_1 = (0, tslib_1.__importDefault)(require("simple-git"));
11
+ const simple_1 = (0, tslib_1.__importDefault)(require("spdx-license-list/simple"));
12
+ const composer_1 = require("../utils/composer");
13
+ function assertUnreachable(_x) {
14
+ throw new Error("Didn't expect to get here");
15
+ }
16
+ exports.EXTENSION_PARAMS = [
17
+ 'packageName',
18
+ 'packageDescription',
19
+ 'packageNamespace',
20
+ 'authorName',
21
+ 'authorEmail',
22
+ 'extensionName',
23
+ 'licenseType',
24
+ 'mainGitBranch',
25
+ 'licenseText',
26
+ 'packageNamespaceEscapedSlash',
27
+ 'extensionId',
28
+ 'year',
29
+ 'backendDirectory',
30
+ 'frontendDirectory',
31
+ ];
32
+ function paramNamesToDef(name) {
33
+ switch (name) {
34
+ case 'packageName':
35
+ return {
36
+ prompt: {
37
+ name,
38
+ type: 'text',
39
+ message: `Package ${chalk_1.default.dim('(vendor/extension-name)')}`,
40
+ validate: s => /^([\dA-Za-z-]{2,})\/([\dA-Za-z-]{2,})$/.test(s.trim()) || 'Invalid package name format',
41
+ format: s => s.toLowerCase(),
42
+ },
43
+ getCurrVal: async (fs, paths) => {
44
+ const json = (0, composer_1.getComposerJson)(fs, paths);
45
+ return json === null || json === void 0 ? void 0 : json.name;
46
+ },
47
+ };
48
+ case 'packageDescription':
49
+ return {
50
+ prompt: {
51
+ name,
52
+ type: 'text',
53
+ message: 'Package description',
54
+ },
55
+ getCurrVal: async (fs, paths) => {
56
+ var _a;
57
+ const json = (0, composer_1.getComposerJson)(fs, paths);
58
+ return (_a = json === null || json === void 0 ? void 0 : json.description) !== null && _a !== void 0 ? _a : '';
59
+ },
60
+ };
61
+ case 'packageNamespace':
62
+ return {
63
+ prompt: {
64
+ name,
65
+ type: 'text',
66
+ message: `Package namespace ${chalk_1.default.dim('(Vendor\\ExtensionName)')}`,
67
+ validate: s => /^([\dA-Za-z]+)\\([\dA-Za-z]+)$/.test(s.trim()) || 'Invalid namespace format',
68
+ format: (str) => str &&
69
+ str
70
+ .split('\\')
71
+ .map(s => s[0].toUpperCase() + s.slice(1))
72
+ .join('\\'),
73
+ },
74
+ getCurrVal: async (fs, paths) => {
75
+ var _a, _b, _c, _d, _e;
76
+ const json = (0, composer_1.getComposerJson)(fs, paths);
77
+ const namespace = (_e = ((_d = (_c = Object.keys((_b = (_a = json === null || json === void 0 ? void 0 : json.autoload) === null || _a === void 0 ? void 0 : _a['psr-4']) !== null && _b !== void 0 ? _b : {})) === null || _c === void 0 ? void 0 : _c[0]) !== null && _d !== void 0 ? _d : '')) === null || _e === void 0 ? void 0 : _e.slice(0, -1);
78
+ return namespace || '';
79
+ },
80
+ };
81
+ case 'authorName':
82
+ return {
83
+ prompt: {
84
+ name,
85
+ type: 'text',
86
+ message: 'Author name',
87
+ },
88
+ getCurrVal: async (fs, paths) => {
89
+ var _a, _b, _c;
90
+ const json = (0, composer_1.getComposerJson)(fs, paths);
91
+ return (_c = (_b = (_a = json.authors) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.name) !== null && _c !== void 0 ? _c : '';
92
+ },
93
+ };
94
+ case 'authorEmail':
95
+ return {
96
+ prompt: {
97
+ name,
98
+ type: 'text',
99
+ message: 'Author email',
100
+ validate: s => !s || /^[\w!#$%&*+./=?^`{|}~’-]+@[\dA-Za-z-]+(?:\.[\dA-Za-z-]+)*$/.test(s) || 'Invalid email format',
101
+ },
102
+ getCurrVal: async (fs, paths) => {
103
+ var _a, _b, _c;
104
+ const json = (0, composer_1.getComposerJson)(fs, paths);
105
+ return (_c = (_b = (_a = json.authors) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.email) !== null && _c !== void 0 ? _c : '';
106
+ },
107
+ };
108
+ case 'extensionName':
109
+ return {
110
+ prompt: {
111
+ name,
112
+ type: 'text',
113
+ message: 'Extension name',
114
+ validate: str => Boolean(str.trim()) || 'The extension name is required',
115
+ format: str => str
116
+ .split(' ')
117
+ .map((s) => (s.length > 3 ? s[0].toUpperCase() + s.slice(1) : s))
118
+ .join(' '),
119
+ },
120
+ getCurrVal: async (fs, paths) => {
121
+ var _a, _b, _c;
122
+ const json = (0, composer_1.getComposerJson)(fs, paths);
123
+ if (json.name === 'flarum/core')
124
+ return 'Core';
125
+ return (_c = (_b = (_a = json === null || json === void 0 ? void 0 : json.extra) === null || _a === void 0 ? void 0 : _a['flarum-extension']) === null || _b === void 0 ? void 0 : _b.title) !== null && _c !== void 0 ? _c : '';
126
+ },
127
+ };
128
+ case 'licenseType':
129
+ return {
130
+ prompt: {
131
+ name,
132
+ type: 'autocomplete',
133
+ message: 'License',
134
+ choices: [...simple_1.default].map(e => ({ title: e, value: e })),
135
+ },
136
+ getCurrVal: async (fs, paths) => {
137
+ var _a;
138
+ const json = (0, composer_1.getComposerJson)(fs, paths);
139
+ return (_a = json === null || json === void 0 ? void 0 : json.license) !== null && _a !== void 0 ? _a : '';
140
+ },
141
+ };
142
+ case 'licenseText':
143
+ return {
144
+ name,
145
+ uses: ['licenseType'],
146
+ compute: async (_paths, licenseType) => (licenseType ? require(`spdx-license-list/licenses/${licenseType}`).licenseText : ''),
147
+ };
148
+ case 'packageNamespaceEscapedSlash':
149
+ return {
150
+ name,
151
+ uses: ['packageNamespace'],
152
+ compute: async (_paths, packageNamespace) => packageNamespace.replace('\\', '\\\\'),
153
+ };
154
+ case 'extensionId':
155
+ return {
156
+ name,
157
+ uses: ['packageName'],
158
+ compute: async (_paths, packageName) => packageName.replace(/(flarum-ext-)|(flarum-)/, '').replace('/', '-'),
159
+ };
160
+ case 'year':
161
+ return {
162
+ name,
163
+ uses: [],
164
+ compute: async () => new Date().getFullYear().toString(),
165
+ };
166
+ case 'mainGitBranch':
167
+ return {
168
+ prompt: {
169
+ name,
170
+ type: 'text',
171
+ message: `Main git branch ${chalk_1.default.dim('(JS will automatically build when changes are pushed to GitHub on this branch)')}`,
172
+ // See https://stackoverflow.com/a/12093994/11091039
173
+ validate: s => /^(?!.*\/\.)(?!.*\.\.)(?!\/)(?!.*\/\/)(?!.*@{)(?!.*\\)[^\000-\037 *:?[^~\177]+(?<!\.lock)(?<!\/)(?<!\.)$/.test(s.trim()) || 'Invalid git branch',
174
+ initial: 'main',
175
+ },
176
+ getCurrVal: async () => {
177
+ var _a;
178
+ return (_a = (await (0, simple_git_1.default)().getConfig('init.defaultBranch')).value) !== null && _a !== void 0 ? _a : 'main';
179
+ },
180
+ };
181
+ case 'backendDirectory':
182
+ return {
183
+ name,
184
+ uses: [],
185
+ compute: async (paths) => {
186
+ const monorepoPath = paths.monorepo();
187
+ return monorepoPath ? paths.package().replace(monorepoPath, '.') : '.';
188
+ },
189
+ };
190
+ case 'frontendDirectory':
191
+ return {
192
+ name,
193
+ uses: [],
194
+ compute: async (paths) => {
195
+ const monorepoPath = paths.monorepo();
196
+ return monorepoPath ? paths.package().replace(monorepoPath, '.') + '/js' : './js';
197
+ },
198
+ };
199
+ }
200
+ return assertUnreachable(name);
201
+ }
202
+ exports.EXTENSION_MODULES = [
203
+ 'core',
204
+ 'icon',
205
+ 'admin',
206
+ 'forum',
207
+ 'js',
208
+ 'jsCommon',
209
+ 'css',
210
+ 'locale',
211
+ 'gitConf',
212
+ 'githubActions',
213
+ 'prettier',
214
+ 'typescript',
215
+ 'bundlewatch',
216
+ 'backendTesting',
217
+ 'editorConfig',
218
+ 'styleci',
219
+ ];
220
+ function moduleNameToDef(name) {
221
+ switch (name) {
222
+ case 'core':
223
+ return {
224
+ name,
225
+ updatable: false,
226
+ togglable: false,
227
+ shortDescription: 'Core Functionality',
228
+ filesToReplace: [
229
+ 'extend.php',
230
+ 'README.md',
231
+ 'LICENSE.md',
232
+ { path: 'js/src/admin/index.js', moduleDeps: ['js', 'admin', { module: 'typescript', enabled: false }] },
233
+ { path: 'js/src/forum/index.js', moduleDeps: ['js', 'forum', { module: 'typescript', enabled: false }] },
234
+ { path: 'js/src/common/index.js', moduleDeps: ['js', 'jsCommon', { module: 'typescript', enabled: false }] },
235
+ { path: 'js/src/admin/index.ts', moduleDeps: ['js', 'admin', { module: 'typescript', enabled: true }] },
236
+ { path: 'js/src/forum/index.ts', moduleDeps: ['js', 'forum', { module: 'typescript', enabled: true }] },
237
+ { path: 'js/src/common/index.ts', moduleDeps: ['js', 'jsCommon', { module: 'typescript', enabled: true }] },
238
+ ],
239
+ jsonToAugment: {
240
+ 'composer.json': [
241
+ 'name',
242
+ 'description',
243
+ 'keywords',
244
+ 'type',
245
+ 'license',
246
+ 'require.flarum/core',
247
+ 'authors',
248
+ 'autoload.psr-4.${params.packageNamespaceEscapedSlash}\\',
249
+ 'extra.flarum-extension.title',
250
+ 'extra.flarum-extension.category',
251
+ ],
252
+ },
253
+ needsTemplateParams: [
254
+ 'packageName',
255
+ 'packageNamespace',
256
+ 'packageNamespaceEscapedSlash',
257
+ 'packageDescription',
258
+ 'extensionName',
259
+ 'licenseType',
260
+ 'licenseText',
261
+ 'authorName',
262
+ 'authorEmail',
263
+ 'extensionId',
264
+ 'year',
265
+ ],
266
+ };
267
+ case 'icon':
268
+ return {
269
+ name,
270
+ updatable: false,
271
+ togglable: false,
272
+ shortDescription: 'Extension Icon',
273
+ filesToReplace: [],
274
+ jsonToAugment: {
275
+ 'composer.json': ['extra.flarum-extension.icon.name', 'extra.flarum-extension.icon.color', 'extra.flarum-extension.icon.backgroundColor'],
276
+ },
277
+ needsTemplateParams: [],
278
+ };
279
+ case 'admin':
280
+ return {
281
+ name,
282
+ updatable: true,
283
+ defaultEnabled: true,
284
+ dependsOn: [],
285
+ togglable: true,
286
+ shortDescription: 'Admin Frontend',
287
+ filesToReplace: [
288
+ { path: 'js/admin.js', moduleDeps: ['js', { module: 'typescript', enabled: false }] },
289
+ { path: 'js/admin.ts', moduleDeps: ['js', { module: 'typescript', enabled: true }] },
290
+ ],
291
+ jsonToAugment: {},
292
+ needsTemplateParams: [],
293
+ inferEnabled: async (_fs, paths) => {
294
+ if (!(0, node_fs_1.existsSync)(paths.package('js')))
295
+ undefined;
296
+ return (0, node_fs_1.existsSync)(paths.package('js/src/admin'));
297
+ },
298
+ };
299
+ case 'forum':
300
+ return {
301
+ name,
302
+ updatable: true,
303
+ defaultEnabled: true,
304
+ dependsOn: [],
305
+ togglable: true,
306
+ shortDescription: 'Forum Frontend',
307
+ filesToReplace: [
308
+ { path: 'js/forum.js', moduleDeps: ['js', { module: 'typescript', enabled: false }] },
309
+ { path: 'js/forum.ts', moduleDeps: ['js', { module: 'typescript', enabled: true }] },
310
+ ],
311
+ jsonToAugment: {},
312
+ needsTemplateParams: [],
313
+ inferEnabled: async (_fs, paths) => {
314
+ if (!(0, node_fs_1.existsSync)(paths.package('js')))
315
+ undefined;
316
+ return (0, node_fs_1.existsSync)(paths.package('js/src/forum'));
317
+ },
318
+ };
319
+ case 'js':
320
+ return {
321
+ name,
322
+ updatable: true,
323
+ togglable: true,
324
+ defaultEnabled: true,
325
+ shortDescription: 'Javascript',
326
+ longDescription: "Files, tools, and scripts to build Flarum's frontend.",
327
+ dependsOn: [],
328
+ filesToReplace: [
329
+ 'js/webpack.config.js',
330
+ { path: 'js/admin.js', moduleDeps: ['admin', { module: 'typescript', enabled: false }] },
331
+ { path: 'js/forum.js', moduleDeps: ['forum', { module: 'typescript', enabled: false }] },
332
+ { path: 'js/admin.ts', moduleDeps: ['admin', { module: 'typescript', enabled: true }] },
333
+ { path: 'js/forum.ts', moduleDeps: ['forum', { module: 'typescript', enabled: true }] },
334
+ ],
335
+ jsonToAugment: {
336
+ 'js/package.json': [
337
+ 'name',
338
+ 'private',
339
+ 'devDependencies.flarum-webpack-config',
340
+ 'devDependencies.webpack',
341
+ 'devDependencies.webpack-cli',
342
+ 'scripts.dev',
343
+ 'scripts.build',
344
+ 'scripts.analyze',
345
+ ],
346
+ },
347
+ needsTemplateParams: ['packageName'],
348
+ inferEnabled: async (_fs, paths) => {
349
+ return (0, node_fs_1.existsSync)(paths.package('js'));
350
+ },
351
+ };
352
+ case 'jsCommon':
353
+ return {
354
+ name,
355
+ updatable: true,
356
+ togglable: true,
357
+ defaultEnabled: true,
358
+ shortDescription: 'JS common code',
359
+ longDescription: 'Shared code between the forum and the admin frontends',
360
+ dependsOn: ['js'],
361
+ filesToReplace: [
362
+ { path: 'js/admin.js', moduleDeps: ['admin', { module: 'typescript', enabled: false }] },
363
+ { path: 'js/forum.js', moduleDeps: ['forum', { module: 'typescript', enabled: false }] },
364
+ { path: 'js/admin.ts', moduleDeps: ['admin', { module: 'typescript', enabled: true }] },
365
+ { path: 'js/forum.ts', moduleDeps: ['forum', { module: 'typescript', enabled: true }] },
366
+ ],
367
+ jsonToAugment: {},
368
+ needsTemplateParams: [],
369
+ inferEnabled: async (_fs, paths) => {
370
+ return (0, node_fs_1.existsSync)(paths.package('js/src/common'));
371
+ },
372
+ };
373
+ case 'css':
374
+ return {
375
+ name,
376
+ updatable: false,
377
+ togglable: true,
378
+ defaultEnabled: true,
379
+ shortDescription: 'CSS',
380
+ longDescription: "LESS starter files for Flarum's frontend styling.",
381
+ dependsOn: [],
382
+ filesToReplace: ['less/admin.less', 'less/forum.less'],
383
+ jsonToAugment: {},
384
+ needsTemplateParams: [],
385
+ inferEnabled: async (_fs, paths) => {
386
+ return (0, node_fs_1.existsSync)(paths.package('less'));
387
+ },
388
+ };
389
+ case 'locale':
390
+ return {
391
+ name,
392
+ updatable: false,
393
+ togglable: true,
394
+ defaultEnabled: true,
395
+ shortDescription: 'Locale',
396
+ longDescription: 'Translation starter files.',
397
+ dependsOn: [],
398
+ filesToReplace: ['locale/en.yml'],
399
+ jsonToAugment: {},
400
+ needsTemplateParams: [],
401
+ inferEnabled: async (_fs, paths) => {
402
+ return (0, node_fs_1.existsSync)(paths.package('locale'));
403
+ },
404
+ };
405
+ case 'gitConf':
406
+ return {
407
+ name,
408
+ updatable: true,
409
+ togglable: true,
410
+ defaultEnabled: true,
411
+ shortDescription: 'Git Configuration',
412
+ longDescription: 'Git config files (e.g. .gitignore, .gitattributes).',
413
+ dependsOn: [],
414
+ filesToReplace: [{ path: 'gitignore', destPath: '.gitignore' }, { path: 'js/gitignore', moduleDeps: ['js'], destPath: 'js/.gitignore' }, '.gitattributes'],
415
+ jsonToAugment: {},
416
+ needsTemplateParams: [],
417
+ };
418
+ case 'githubActions':
419
+ return {
420
+ name,
421
+ updatable: true,
422
+ togglable: true,
423
+ defaultEnabled: true,
424
+ shortDescription: 'GitHub Actions CI',
425
+ longDescription: 'Automatically run checks via GitHub Actions CI. Free for open source projects.',
426
+ dependsOn: [],
427
+ filesToReplace: [
428
+ { path: '.github/workflows/frontend.yml', monorepoPath: '.github/workflows/${params.extensionId}-frontend.yml' },
429
+ { path: '.github/workflows/backend.yml', monorepoPath: '.github/workflows/${params.extensionId}-backend.yml' },
430
+ ],
431
+ jsonToAugment: {},
432
+ needsTemplateParams: ['frontendDirectory', 'backendDirectory', 'mainGitBranch', 'extensionId', 'extensionName'],
433
+ };
434
+ case 'prettier':
435
+ return {
436
+ name,
437
+ updatable: true,
438
+ togglable: true,
439
+ defaultEnabled: true,
440
+ shortDescription: 'Auto-format frontend code with Prettier.',
441
+ dependsOn: ['js'],
442
+ filesToReplace: [],
443
+ jsonToAugment: {
444
+ 'js/package.json': ['prettier', 'devDependencies.prettier', 'devDependencies.@flarum/prettier-config', 'scripts.format', 'scripts.format-check'],
445
+ },
446
+ needsTemplateParams: [],
447
+ inferEnabled: async (_fs, paths) => {
448
+ if (!(0, node_fs_1.existsSync)(paths.package('js/package.json'))) {
449
+ return false;
450
+ }
451
+ return (0, node_fs_1.readFileSync)('js/package.json').includes('prettier');
452
+ },
453
+ };
454
+ case 'typescript':
455
+ return {
456
+ name,
457
+ updatable: true,
458
+ togglable: true,
459
+ defaultEnabled: true,
460
+ shortDescription: 'Support TypeScript in frontend code.',
461
+ dependsOn: ['js'],
462
+ filesToReplace: ['js/tsconfig.json'],
463
+ jsonToAugment: {
464
+ 'js/package.json': [
465
+ 'prettier',
466
+ 'devDependencies.flarum-tsconfig',
467
+ 'devDependencies.typescript',
468
+ 'devDependencies.typescript-coverage-report',
469
+ 'scripts.check-typings',
470
+ 'scripts.check-typings-coverage',
471
+ ],
472
+ },
473
+ needsTemplateParams: [],
474
+ inferEnabled: async (_fs, paths) => {
475
+ return (0, node_fs_1.existsSync)(paths.package('js/tsconfig.json'));
476
+ },
477
+ };
478
+ case 'bundlewatch':
479
+ return {
480
+ name,
481
+ updatable: true,
482
+ togglable: true,
483
+ defaultEnabled: false,
484
+ shortDescription: 'Enable Bundlewatch Checks',
485
+ dependsOn: ['js'],
486
+ filesToReplace: ['js/.bundlewatch.config.json'],
487
+ jsonToAugment: {},
488
+ needsTemplateParams: [],
489
+ inferEnabled: async (_fs, paths) => {
490
+ return (0, node_fs_1.existsSync)(paths.package('js/.bundlewatch.config.json'));
491
+ },
492
+ };
493
+ case 'backendTesting':
494
+ return {
495
+ name,
496
+ updatable: true,
497
+ togglable: true,
498
+ defaultEnabled: true,
499
+ shortDescription: 'Backend PHP unit and integration testing via PHPUnit.',
500
+ dependsOn: [],
501
+ filesToReplace: [
502
+ 'tests/phpunit.integration.xml',
503
+ 'tests/phpunit.unit.xml',
504
+ 'tests/fixtures/.gitkeep',
505
+ 'tests/integration/setup.php',
506
+ 'tests/unit/.gitkeep',
507
+ ],
508
+ jsonToAugment: {
509
+ 'composer.json': [
510
+ 'autoload-dev.psr-4.${params.packageNamespaceEscapedSlash}\\Tests\\',
511
+ 'scripts.test',
512
+ 'scripts.test:unit',
513
+ 'scripts.test:integration',
514
+ 'scripts.test:setup',
515
+ 'scripts-descriptions.test',
516
+ 'scripts-descriptions.test:unit',
517
+ 'scripts-descriptions.test:integration',
518
+ 'scripts-descriptions.test:setup',
519
+ 'require-dev.flarum/testing',
520
+ ],
521
+ },
522
+ needsTemplateParams: ['packageNamespaceEscapedSlash'],
523
+ inferEnabled: async (_fs, paths) => {
524
+ return (0, node_fs_1.existsSync)(paths.package('tests'));
525
+ },
526
+ };
527
+ case 'editorConfig':
528
+ return {
529
+ name,
530
+ updatable: true,
531
+ togglable: true,
532
+ defaultEnabled: true,
533
+ shortDescription: 'EditorConfig setup',
534
+ dependsOn: [],
535
+ filesToReplace: ['.editorconfig'],
536
+ jsonToAugment: {},
537
+ needsTemplateParams: [],
538
+ };
539
+ case 'styleci':
540
+ return {
541
+ name,
542
+ updatable: true,
543
+ togglable: true,
544
+ defaultEnabled: true,
545
+ shortDescription: 'StyleCI config file',
546
+ dependsOn: [],
547
+ filesToReplace: [
548
+ { path: '.styleci.yml', monorepoPath: '.styleci.yml' },
549
+ ],
550
+ jsonToAugment: {},
551
+ needsTemplateParams: [],
552
+ };
553
+ }
554
+ return assertUnreachable(name);
555
+ }
556
+ let cached;
557
+ function genExtScaffolder() {
558
+ if (cached)
559
+ return cached;
560
+ const moduleStatusCache = {
561
+ get: async (module, fs, paths) => {
562
+ var _a, _b, _c;
563
+ const json = (0, composer_1.getComposerJson)(fs, paths);
564
+ return !module.togglable || ((_c = (_b = (_a = json === null || json === void 0 ? void 0 : json.extra) === null || _a === void 0 ? void 0 : _a['flarum-cli']) === null || _b === void 0 ? void 0 : _b.modules) === null || _c === void 0 ? void 0 : _c[module.name]);
565
+ },
566
+ set: async (module, enabled, fs, paths) => {
567
+ const json = {
568
+ extra: {
569
+ 'flarum-cli': {
570
+ modules: {
571
+ [module.name]: enabled,
572
+ },
573
+ },
574
+ },
575
+ };
576
+ (0, mem_fs_editor_1.create)(fs).extendJSON(paths.package('composer.json'), json, undefined, 4);
577
+ },
578
+ };
579
+ const excludeScaffoldingFunc = (fs, paths) => {
580
+ var _a, _b, _c;
581
+ const json = (0, composer_1.getComposerJson)(fs, paths);
582
+ return (_c = (_b = (_a = json === null || json === void 0 ? void 0 : json.extra) === null || _a === void 0 ? void 0 : _a['flarum-cli']) === null || _b === void 0 ? void 0 : _b.excludeScaffolding) !== null && _c !== void 0 ? _c : [];
583
+ };
584
+ const scaffolder = new scaffolder_1.Scaffolder((0, node_path_1.resolve)(__dirname, '../../boilerplate/skeleton/extension'), moduleStatusCache, excludeScaffoldingFunc);
585
+ for (const name of exports.EXTENSION_MODULES) {
586
+ scaffolder.registerModule(moduleNameToDef(name));
587
+ }
588
+ for (const name of exports.EXTENSION_PARAMS) {
589
+ scaffolder.registerTemplateParam(paramNamesToDef(name));
590
+ }
591
+ cached = scaffolder;
592
+ return scaffolder;
593
+ }
594
+ exports.genExtScaffolder = genExtScaffolder;
@@ -1,15 +1,15 @@
1
1
  import { Store } from 'mem-fs';
2
- import { ParamProvider } from '../../provider/param-provider';
3
- import { PathProvider } from '../../provider/path-provider';
4
- import { PhpProvider } from '../../provider/php-provider';
5
- import { Step } from '../step-manager';
6
- export declare abstract class BaseJsStep implements Step {
2
+ import { IO } from 'boilersmith/io';
3
+ import { Paths } from 'boilersmith/paths';
4
+ import { Step } from 'boilersmith/step-manager';
5
+ import { FlarumProviders } from '../../providers';
6
+ export declare abstract class BaseJsStep implements Step<FlarumProviders> {
7
7
  abstract type: string;
8
8
  composable: boolean;
9
- run(fs: Store, pathProvider: PathProvider, paramProvider: ParamProvider, _phpProvider: PhpProvider): Promise<Store>;
10
- protected abstract getDefinition(paramProvider: ParamProvider): Promise<string>;
11
- protected abstract getImports(frontend: string, pathProvider: PathProvider, paramProvider: ParamProvider): Promise<string>;
9
+ run(fs: Store, paths: Paths, io: IO, _providers: FlarumProviders): Promise<Store>;
10
+ protected abstract getDefinition(io: IO): Promise<string>;
11
+ protected abstract getImports(frontend: string, paths: Paths, io: IO): Promise<string>;
12
12
  protected importPath(frontend: string, classNamespace: string): string;
13
13
  exposes: never[];
14
- getExposed(_pathProvider: PathProvider, _paramProvider: ParamProvider): Record<string, unknown>;
14
+ getExposed(_paths: Paths, _paramProvider: IO): Record<string, unknown>;
15
15
  }
@@ -1,37 +1,38 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.BaseJsStep = void 0;
4
- const glob_1 = require("glob");
4
+ const tslib_1 = require("tslib");
5
+ const globby_1 = (0, tslib_1.__importDefault)(require("globby"));
5
6
  const mem_fs_editor_1 = require("mem-fs-editor");
6
- const IMPORTS_REGEX = /((^import\s+(?:([\w,{}\s*]+)\s+from)?\s*(?:(?:["'])?([@\w\s\\/.-]+)\3?(?:["'])?)\s*;?\s*)*)(.*)/m;
7
- const INIT_REGEX = /^(app\.initializers\.add\('[^']+',\s*\(\)\s*=>\s*\{)$/m;
7
+ const IMPORTS_REGEX = /((^import\s+(?:([\s\w*,{}]+)\s+from)?\s*["']?([\s\w./@\\-]+)\3?["']?\s*;?\s*)*)(.*)/m;
8
+ const INIT_REGEX = /^(app\.initializers\.add\('[^']+',\s*\(\)\s*=>\s*{)$/m;
8
9
  class BaseJsStep {
9
10
  constructor() {
10
11
  this.composable = true;
11
12
  this.exposes = [];
12
13
  }
13
- async run(fs, pathProvider, paramProvider, _phpProvider) {
14
- const fsEditor = mem_fs_editor_1.create(fs);
15
- const frontend = await paramProvider.get({ name: 'frontend', type: 'text' });
14
+ async run(fs, paths, io, _providers) {
15
+ const fsEditor = (0, mem_fs_editor_1.create)(fs);
16
+ const frontend = await io.getParam({ name: 'frontend', type: 'text' });
16
17
  let frontends = [frontend];
17
18
  if (frontend === 'common') {
18
19
  frontends = ['admin', 'forum'];
19
20
  }
20
- frontends.forEach(frontend => {
21
- const fsSrcFilePaths = glob_1.glob.sync(pathProvider.ext(`js/src/${frontend}/*.{js,jsx,ts,tsx}`));
21
+ for (const frontend of frontends) {
22
+ const fsSrcFilePaths = globby_1.default.sync(paths.package(`js/src/${frontend}/*.{js,jsx,ts,tsx}`));
22
23
  fsSrcFilePaths.forEach(async (match) => {
23
24
  /**
24
25
  * @TODO look into using https://esprima.org/ instead
25
26
  */
26
27
  const currContents = fsEditor.read(match);
27
- const imports = await this.getImports(frontend, pathProvider, paramProvider);
28
- const definition = await this.getDefinition(paramProvider);
28
+ const imports = await this.getImports(frontend, paths, io);
29
+ const definition = await this.getDefinition(io);
29
30
  const newContents = currContents
30
31
  .replace(INIT_REGEX, `$1\n ${definition}\n`)
31
32
  .replace(IMPORTS_REGEX, `$1${imports}\n\n$5`);
32
33
  fsEditor.write(match, newContents);
33
34
  });
34
- });
35
+ }
35
36
  return fs;
36
37
  }
37
38
  importPath(frontend, classNamespace) {
@@ -39,7 +40,7 @@ class BaseJsStep {
39
40
  path = path.replace(`../${frontend}/`, './');
40
41
  return path;
41
42
  }
42
- getExposed(_pathProvider, _paramProvider) {
43
+ getExposed(_paths, _paramProvider) {
43
44
  return {};
44
45
  }
45
46
  }