@flarum/cli 2.0.0-beta.8 → 2.0.0

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 (133) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +181 -49
  3. package/bin/run +2 -1
  4. package/bin/splitsh-lite-darwin +0 -0
  5. package/bin/splitsh-lite-linux +0 -0
  6. package/boilerplate/skeleton/extension/.gitattributes +16 -14
  7. package/boilerplate/skeleton/extension/.github/workflows/backend.yml +2 -6
  8. package/boilerplate/skeleton/extension/.github/workflows/frontend.yml +4 -6
  9. package/boilerplate/skeleton/extension/LICENSE.md +1 -1
  10. package/boilerplate/skeleton/extension/README.md +1 -1
  11. package/boilerplate/skeleton/extension/composer.json +6 -4
  12. package/boilerplate/skeleton/extension/extend.php +2 -2
  13. package/boilerplate/skeleton/extension/js/admin.ts +2 -0
  14. package/boilerplate/skeleton/extension/js/forum.ts +2 -0
  15. package/boilerplate/skeleton/extension/js/package.json +5 -1
  16. package/boilerplate/skeleton/extension/js/src/admin/index.ts +5 -0
  17. package/boilerplate/skeleton/extension/js/src/common/index.ts +5 -0
  18. package/boilerplate/skeleton/extension/js/src/forum/index.ts +5 -0
  19. package/boilerplate/skeleton/extension/js/tsconfig.json +10 -2
  20. package/boilerplate/skeleton/extension/locale/en.yml +1 -1
  21. package/boilerplate/skeleton/extension/tests/phpunit.integration.xml +1 -0
  22. package/lib/base-command.d.ts +3 -1
  23. package/lib/base-command.js +44 -31
  24. package/lib/boilersmith/io.d.ts +28 -8
  25. package/lib/boilersmith/io.js +4 -2
  26. package/lib/boilersmith/paths.d.ts +2 -2
  27. package/lib/boilersmith/paths.js +7 -7
  28. package/lib/boilersmith/scaffolding/audit-step-factory.js +11 -11
  29. package/lib/boilersmith/scaffolding/infra-step-factory.js +2 -2
  30. package/lib/boilersmith/scaffolding/init-step-factory.js +5 -5
  31. package/lib/boilersmith/scaffolding/module.d.ts +28 -8
  32. package/lib/boilersmith/scaffolding/module.js +59 -17
  33. package/lib/boilersmith/scaffolding/scaffolder.d.ts +4 -1
  34. package/lib/boilersmith/scaffolding/scaffolder.js +32 -32
  35. package/lib/boilersmith/scaffolding/template-param.d.ts +1 -1
  36. package/lib/boilersmith/scaffolding/template-param.js +2 -2
  37. package/lib/boilersmith/step-manager.d.ts +0 -1
  38. package/lib/boilersmith/step-manager.js +10 -20
  39. package/lib/boilersmith/steps/stub-base.js +3 -3
  40. package/lib/boilersmith/utils/clone-and-fill.js +1 -1
  41. package/lib/boilersmith/utils/commit-async.d.ts +2 -0
  42. package/lib/boilersmith/utils/commit-async.js +15 -0
  43. package/lib/boilersmith/utils/read-tpl.js +2 -2
  44. package/lib/commands/audit/infra.d.ts +1 -1
  45. package/lib/commands/audit/infra.js +30 -8
  46. package/lib/commands/infra.d.ts +2 -2
  47. package/lib/commands/infra.js +18 -12
  48. package/lib/commands/init.d.ts +1 -1
  49. package/lib/commands/init.js +4 -2
  50. package/lib/commands/make/backend/api-controller.js +1 -2
  51. package/lib/commands/make/backend/api-serializer-attributes.js +1 -2
  52. package/lib/commands/make/backend/command.js +1 -2
  53. package/lib/commands/make/backend/event-listener.js +1 -2
  54. package/lib/commands/make/backend/handler.js +2 -5
  55. package/lib/commands/make/backend/integration-test.js +2 -4
  56. package/lib/commands/make/backend/migration.js +1 -2
  57. package/lib/commands/make/backend/model.js +1 -2
  58. package/lib/commands/make/backend/policy.js +1 -2
  59. package/lib/commands/make/backend/route.js +1 -2
  60. package/lib/commands/make/backend/service-provider.js +1 -2
  61. package/lib/commands/make/frontend/model.js +2 -5
  62. package/lib/commands/monorepo/create.d.ts +15 -0
  63. package/lib/commands/monorepo/create.js +20 -0
  64. package/lib/commands/monorepo/split.d.ts +15 -0
  65. package/lib/commands/monorepo/split.js +19 -0
  66. package/lib/commands/update/js-imports.js +1 -2
  67. package/lib/help.js +1 -1
  68. package/lib/providers/php-provider.js +2 -2
  69. package/lib/steps/gen-ext-scaffolder.d.ts +2 -2
  70. package/lib/steps/gen-ext-scaffolder.js +187 -53
  71. package/lib/steps/js/base.js +2 -4
  72. package/lib/steps/js/model.js +4 -4
  73. package/lib/steps/misc/composer.js +2 -2
  74. package/lib/steps/misc/git.d.ts +1 -1
  75. package/lib/steps/misc/git.js +2 -2
  76. package/lib/steps/misc/npm.d.ts +11 -0
  77. package/lib/steps/misc/npm.js +19 -0
  78. package/lib/steps/misc/yarn.js +2 -2
  79. package/lib/steps/monorepo/create.d.ts +17 -0
  80. package/lib/steps/monorepo/create.js +186 -0
  81. package/lib/steps/monorepo/split.d.ts +14 -0
  82. package/lib/steps/monorepo/split.js +99 -0
  83. package/lib/steps/stubs/backend/api-controller.d.ts +1 -1
  84. package/lib/steps/stubs/backend/api-controller.js +3 -0
  85. package/lib/steps/stubs/backend/api-serializer.d.ts +1 -1
  86. package/lib/steps/stubs/backend/api-serializer.js +3 -0
  87. package/lib/steps/stubs/backend/command.d.ts +0 -5
  88. package/lib/steps/stubs/backend/command.js +1 -0
  89. package/lib/steps/stubs/backend/event-listener.d.ts +1 -1
  90. package/lib/steps/stubs/backend/event-listener.js +2 -0
  91. package/lib/steps/stubs/backend/handler-command.d.ts +1 -1
  92. package/lib/steps/stubs/backend/handler-command.js +1 -0
  93. package/lib/steps/stubs/backend/handler.d.ts +1 -1
  94. package/lib/steps/stubs/backend/handler.js +4 -0
  95. package/lib/steps/stubs/backend/integration-test.d.ts +1 -1
  96. package/lib/steps/stubs/backend/integration-test.js +2 -0
  97. package/lib/steps/stubs/backend/job.d.ts +1 -1
  98. package/lib/steps/stubs/backend/job.js +1 -0
  99. package/lib/steps/stubs/backend/migration.js +6 -3
  100. package/lib/steps/stubs/backend/model.d.ts +1 -1
  101. package/lib/steps/stubs/backend/model.js +1 -0
  102. package/lib/steps/stubs/backend/policy.d.ts +1 -1
  103. package/lib/steps/stubs/backend/policy.js +2 -0
  104. package/lib/steps/stubs/backend/repository.d.ts +1 -1
  105. package/lib/steps/stubs/backend/repository.js +2 -0
  106. package/lib/steps/stubs/backend/service-provider.d.ts +1 -1
  107. package/lib/steps/stubs/backend/service-provider.js +1 -0
  108. package/lib/steps/stubs/backend/validator.d.ts +1 -1
  109. package/lib/steps/stubs/backend/validator.js +1 -0
  110. package/lib/steps/stubs/flarum-base.js +1 -1
  111. package/lib/steps/stubs/frontend/component.d.ts +0 -5
  112. package/lib/steps/stubs/frontend/component.js +1 -0
  113. package/lib/steps/stubs/frontend/modal.d.ts +0 -5
  114. package/lib/steps/stubs/frontend/modal.js +1 -0
  115. package/lib/steps/stubs/frontend/model.d.ts +0 -5
  116. package/lib/steps/stubs/frontend/model.js +1 -0
  117. package/lib/steps/stubs/js-base.js +8 -5
  118. package/lib/steps/stubs/php-base.js +10 -8
  119. package/lib/steps/update/js-imports.js +8 -2
  120. package/lib/utils/composer.d.ts +1 -0
  121. package/lib/utils/migration.js +3 -1
  122. package/lib/utils/monorepo.d.ts +24 -0
  123. package/lib/utils/monorepo.js +24 -0
  124. package/lib/utils/validation.d.ts +2 -0
  125. package/lib/utils/validation.js +6 -0
  126. package/oclif.manifest.json +1 -1
  127. package/package.json +11 -5
  128. package/php-subsystem/composer.json +9 -9
  129. package/php-subsystem/composer.lock +64 -71
  130. package/php-subsystem/vendor/composer/installed.json +54 -61
  131. package/php-subsystem/vendor/nikic/php-parser/README.md +55 -59
  132. package/php-subsystem/vendor/nikic/php-parser/composer.json +39 -39
  133. package/php-subsystem/vendor/nikic/php-parser/grammar/README.md +17 -20
@@ -4,7 +4,10 @@ import { DefaultProviders, Step } from '../step-manager';
4
4
  import { Module, ModuleStatusCache } from './module';
5
5
  import { TemplateParam } from './template-param';
6
6
  import { IO } from 'boilersmith/io';
7
- export declare type ExcludeScaffoldingFunc = (fs: Store, paths: Paths) => string[];
7
+ export declare type ExcludeScaffoldingFunc = (fs: Store, paths: Paths) => {
8
+ files: string[];
9
+ configKeys: Record<string, string[]>;
10
+ };
8
11
  export declare class Scaffolder<TN extends string = string, MN extends string = string> {
9
12
  private templateParams;
10
13
  private modules;
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.Scaffolder = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  const globby_1 = (0, tslib_1.__importDefault)(require("globby"));
6
- const node_path_1 = require("node:path");
6
+ const path_1 = require("path");
7
7
  const json_leaf_paths_1 = require("boilersmith/utils/json-leaf-paths");
8
8
  const read_tpl_1 = require("boilersmith/utils/read-tpl");
9
9
  const init_step_factory_1 = require("./init-step-factory");
@@ -27,8 +27,8 @@ class Scaffolder {
27
27
  }
28
28
  registerTemplateParam(templateParam) {
29
29
  if ((0, template_param_1.isComputedParam)(templateParam)) {
30
- const currParams = new Set(this.templateParams.map(p => (0, template_param_1.getParamName)(p)));
31
- const missingDeps = templateParam.uses.filter(dep => !currParams.has(dep));
30
+ const currParams = new Set(this.templateParams.map((p) => (0, template_param_1.getParamName)(p)));
31
+ const missingDeps = templateParam.uses.filter((dep) => !currParams.has(dep));
32
32
  if (missingDeps.length > 0) {
33
33
  throw new Error(`Computed template param "${(0, template_param_1.getParamName)(templateParam)}" is missing dependency params: "${missingDeps.join(', ')}".`);
34
34
  }
@@ -56,7 +56,7 @@ class Scaffolder {
56
56
  }
57
57
  moduleFiles(moduleName) {
58
58
  var _a, _b;
59
- return (_b = (_a = this.modules.find(m => m.name === moduleName)) === null || _a === void 0 ? void 0 : _a.filesToReplace.map(f => typeof f === 'string' ? f : f.path)) !== null && _b !== void 0 ? _b : [];
59
+ return (_b = (_a = this.modules.find((m) => m.name === moduleName)) === null || _a === void 0 ? void 0 : _a.filesToReplace.map((f) => (typeof f === 'string' ? f : f.path))) !== null && _b !== void 0 ? _b : [];
60
60
  }
61
61
  /**
62
62
  * Confirm that all files and configuration keys in the scaffolding dir
@@ -66,13 +66,13 @@ class Scaffolder {
66
66
  async validate() {
67
67
  const errors = [];
68
68
  // Generate template data for future checks
69
- const paramVals = Object.fromEntries(this.templateParams.map(param => [(0, template_param_1.getParamName)(param), 'TEST']));
70
- const modulesEnabled = Object.fromEntries(this.modules.map(module => [module.name, true]));
69
+ const paramVals = Object.fromEntries(this.templateParams.map((param) => [(0, template_param_1.getParamName)(param), 'TEST']));
70
+ const modulesEnabled = Object.fromEntries(this.modules.map((module) => [module.name, true]));
71
71
  const tplData = { params: paramVals, modules: modulesEnabled };
72
- const tplDataFlat = Object.assign(Object.assign({}, (0, rename_keys_1.renameKeys)(tplData.modules, k => `modules.${k}`)), (0, rename_keys_1.renameKeys)(tplData.params, k => `params.${k}`));
73
- const moduleNames = new Set(this.modules.map(m => m.name));
72
+ const tplDataFlat = Object.assign(Object.assign({}, (0, rename_keys_1.renameKeys)(tplData.modules, (k) => `modules.${k}`)), (0, rename_keys_1.renameKeys)(tplData.params, (k) => `params.${k}`));
73
+ const moduleNames = new Set(this.modules.map((m) => m.name));
74
74
  for (const module of this.modules) {
75
- const missingDeps = module.togglable ? module.dependsOn.filter(dep => !moduleNames.has(dep)) : [];
75
+ const missingDeps = module.togglable ? module.dependsOn.filter((dep) => !moduleNames.has(dep)) : [];
76
76
  if (missingDeps.length > 0) {
77
77
  errors.push(`Module "${module.name}" depends on modules that are not registered: "${missingDeps.join(', ')}".`);
78
78
  }
@@ -81,23 +81,23 @@ class Scaffolder {
81
81
  const configKeysToOwnerModules = new Map();
82
82
  const templateParamsToUsingModules = new Map();
83
83
  for (const module of this.modules) {
84
- module.filesToReplace.forEach(file => {
84
+ module.filesToReplace.forEach((file) => {
85
85
  var _a;
86
86
  const path = typeof file === 'string' ? file : file.path;
87
87
  const currModules = (_a = filesToOwnerModules.get(path)) !== null && _a !== void 0 ? _a : [];
88
88
  filesToOwnerModules.set(path, [...currModules, module.name]);
89
89
  });
90
- module.needsTemplateParams.forEach(paramName => {
90
+ module.needsTemplateParams.forEach((paramName) => {
91
91
  var _a;
92
92
  const currModules = (_a = filesToOwnerModules.get(paramName)) !== null && _a !== void 0 ? _a : [];
93
93
  templateParamsToUsingModules.set(paramName, [...currModules, module.name]);
94
94
  });
95
- Object.keys(module.jsonToAugment).forEach(jsonPath => {
95
+ Object.keys(module.jsonToAugment).forEach((jsonPath) => {
96
96
  var _a;
97
97
  const ownedKeys = (0, clone_and_fill_1.cloneAndFill)(module.jsonToAugment, tplDataFlat)[jsonPath];
98
98
  const currJsonData = (_a = configKeysToOwnerModules.get(jsonPath)) !== null && _a !== void 0 ? _a : { fileOwners: [], keyOwners: new Map() };
99
99
  currJsonData.fileOwners.push(module.name);
100
- ownedKeys.forEach(key => {
100
+ ownedKeys.forEach((key) => {
101
101
  var _a;
102
102
  const currModules = (_a = currJsonData.keyOwners.get(key)) !== null && _a !== void 0 ? _a : [];
103
103
  currJsonData.keyOwners.set(key, [...currModules, module.name]);
@@ -109,46 +109,46 @@ class Scaffolder {
109
109
  const moduleOwnedFiles = [...filesToOwnerModules.keys()];
110
110
  const moduleOwnedJsonConfs = new Set(configKeysToOwnerModules.keys());
111
111
  moduleOwnedFiles
112
- .filter(path => moduleOwnedJsonConfs.has(path))
113
- .forEach(path => {
112
+ .filter((path) => moduleOwnedJsonConfs.has(path))
113
+ .forEach((path) => {
114
114
  var _a, _b;
115
115
  const fileModules = (_a = filesToOwnerModules.get(path)) === null || _a === void 0 ? void 0 : _a.join(', ');
116
116
  const keyModules = (_b = configKeysToOwnerModules.get(path)) === null || _b === void 0 ? void 0 : _b.fileOwners.join(', ');
117
117
  errors.push(`File "${path}" is owned by modules: "${fileModules}". However, it also has keys that are owned by modules: "${keyModules}".`);
118
118
  });
119
119
  // Ensure that all owned files exist in the filesystem.
120
- const scaffoldingFilePaths = new Set((await (0, globby_1.default)((0, node_path_1.resolve)(this.scaffoldDir, '**/*'), { dot: true })).map(p => p.replace(`${this.scaffoldDir}/`, '')).filter(p => p !== ''));
120
+ const scaffoldingFilePaths = new Set((await (0, globby_1.default)((0, path_1.resolve)(this.scaffoldDir, '**/*'), { dot: true })).map((p) => p.replace(`${this.scaffoldDir}/`, '')).filter((p) => p !== ''));
121
121
  moduleOwnedFiles
122
- .filter(path => !scaffoldingFilePaths.has(path))
123
- .forEach(path => {
122
+ .filter((path) => !scaffoldingFilePaths.has(path))
123
+ .forEach((path) => {
124
124
  var _a;
125
125
  const fileModules = (_a = filesToOwnerModules.get(path)) === null || _a === void 0 ? void 0 : _a.join(', ');
126
126
  errors.push(`File "${path}" is owned by modules: "${fileModules}", but it doesn't exist in the scaffolding directory.`);
127
127
  });
128
128
  [...moduleOwnedJsonConfs]
129
- .filter(path => !scaffoldingFilePaths.has(path))
130
- .forEach(path => {
129
+ .filter((path) => !scaffoldingFilePaths.has(path))
130
+ .forEach((path) => {
131
131
  var _a;
132
132
  const keyModules = (_a = configKeysToOwnerModules.get(path)) === null || _a === void 0 ? void 0 : _a.fileOwners.join(', ');
133
133
  errors.push(`File "${path}" has keys owned by modules: "${keyModules}", but it doesn't exist in the scaffolding directory.`);
134
134
  });
135
135
  // Ensure that all files in the filesystem are owned by at least one module.
136
136
  [...scaffoldingFilePaths]
137
- .filter(path => !filesToOwnerModules.has(path) && !configKeysToOwnerModules.has(path))
138
- .forEach(path => {
137
+ .filter((path) => !filesToOwnerModules.has(path) && !configKeysToOwnerModules.has(path))
138
+ .forEach((path) => {
139
139
  errors.push(`File "${path}" is not owned by any module.`);
140
140
  });
141
141
  // Ensure that every template param is used by at least one module.
142
142
  this.templateParams
143
- .filter(p => !templateParamsToUsingModules.has((0, template_param_1.getParamName)(p)))
144
- .forEach(p => {
143
+ .filter((p) => !templateParamsToUsingModules.has((0, template_param_1.getParamName)(p)))
144
+ .forEach((p) => {
145
145
  errors.push(`Template param "${(0, template_param_1.getParamName)(p)}" is defined, but not used by any modules.`);
146
146
  });
147
147
  // Ensure that every module's needed template params are provided.
148
- const providedParams = new Set(this.templateParams.map(p => (0, template_param_1.getParamName)(p)));
148
+ const providedParams = new Set(this.templateParams.map((p) => (0, template_param_1.getParamName)(p)));
149
149
  [...templateParamsToUsingModules.keys()]
150
- .filter(paramName => !providedParams.has(paramName))
151
- .forEach(paramName => {
150
+ .filter((paramName) => !providedParams.has(paramName))
151
+ .forEach((paramName) => {
152
152
  var _a;
153
153
  const paramModules = (_a = templateParamsToUsingModules.get(paramName)) === null || _a === void 0 ? void 0 : _a.join(', ');
154
154
  errors.push(`Template param "${paramName}" is used by modules: "${paramModules}", but is not provided.`);
@@ -164,14 +164,14 @@ class Scaffolder {
164
164
  if (errors.length > 0) {
165
165
  throw new Error(errors.join('\n'));
166
166
  }
167
- const contents = (0, read_tpl_1.readTpl)((0, node_path_1.resolve)(this.scaffoldDir, path), tplData);
167
+ const contents = (0, read_tpl_1.readTpl)((0, path_1.resolve)(this.scaffoldDir, path), tplData);
168
168
  let json;
169
169
  try {
170
170
  json = JSON.parse(contents);
171
171
  const keys = new Set((0, json_leaf_paths_1.jsonLeafPaths)(json));
172
172
  [...keys]
173
- .filter(k => !ownerData.keyOwners.has(k))
174
- .forEach(k => {
173
+ .filter((k) => !ownerData.keyOwners.has(k))
174
+ .forEach((k) => {
175
175
  errors.push(`Key "${k}" in file "${path}" is not owned by any module.`);
176
176
  });
177
177
  [...ownerData.keyOwners.entries()]
@@ -195,8 +195,8 @@ class Scaffolder {
195
195
  throw new Error(errors.join('\n'));
196
196
  }
197
197
  // Ensure that all files can be resolved with ejs using provided template variables.
198
- scaffoldingFilePaths.forEach(path => {
199
- (0, read_tpl_1.readTpl)((0, node_path_1.resolve)(this.scaffoldDir, path), tplData);
198
+ scaffoldingFilePaths.forEach((path) => {
199
+ (0, read_tpl_1.readTpl)((0, path_1.resolve)(this.scaffoldDir, path), tplData);
200
200
  });
201
201
  }
202
202
  }
@@ -11,7 +11,7 @@ interface PromptTemplateParam<T, N extends string = string> {
11
11
  }
12
12
  interface ComputedTemplateParam<T, N extends string = string> {
13
13
  name: N;
14
- uses: string[];
14
+ uses: N[];
15
15
  compute: (paths: Paths, ...args: any[]) => Promise<T>;
16
16
  }
17
17
  export declare type TemplateParam<T = unknown, N extends string = string> = PromptTemplateParam<T, N> | ComputedTemplateParam<T, N>;
@@ -17,7 +17,7 @@ async function withComputedParamValues(params, paths, paramVals) {
17
17
  const vals = Object.assign({}, paramVals);
18
18
  const computedParams = params.filter(isComputedParam);
19
19
  for (const p of computedParams) {
20
- const depValues = p.uses.map(key => vals[key]);
20
+ const depValues = p.uses.map((key) => vals[key]);
21
21
  // eslint-disable-next-line no-await-in-loop
22
22
  vals[p.name] = await p.compute(paths, ...depValues);
23
23
  }
@@ -39,7 +39,7 @@ async function currParamValues(params, fs, paths, io) {
39
39
  const paramVals = {};
40
40
  for (const p of promptParams) {
41
41
  // eslint-disable-next-line no-await-in-loop
42
- paramVals[p.prompt.name] = (_a = await p.getCurrVal(fs, paths)) !== null && _a !== void 0 ? _a : await io.getParam(p.prompt);
42
+ paramVals[p.prompt.name] = (_a = (await p.getCurrVal(fs, paths))) !== null && _a !== void 0 ? _a : (await io.getParam(p.prompt));
43
43
  }
44
44
  return withComputedParamValues(params, paths, paramVals);
45
45
  }
@@ -72,7 +72,6 @@ export declare class StepManager<Providers extends DefaultProviders> {
72
72
  run(paths: Paths, io: IO, providers: Providers, dry?: boolean): Promise<StepsResult>;
73
73
  protected stepShouldRun(storedStep: StoredStep<Providers>, io: IO, packagePath?: string): Promise<boolean>;
74
74
  protected runStep(storedStep: StoredStep<Providers>, paths: Paths, io: IO, providers: Providers, packagePath?: string, fs?: Store): Promise<Store>;
75
- protected commit(fs: Store): Promise<boolean>;
76
75
  }
77
76
  export declare class AtomicStepManager<Providers = DefaultProviders> extends StepManager<Providers> {
78
77
  protected steps: StoredStep<Providers>[];
@@ -3,9 +3,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.AtomicStepManager = exports.StepManager = void 0;
4
4
  /* eslint-disable no-await-in-loop */
5
5
  const mem_fs_1 = require("mem-fs");
6
- const mem_fs_editor_1 = require("mem-fs-editor");
7
6
  const exposed_param_manager_1 = require("./exposed-param-manager");
8
- const formatDependencies = (strings) => strings.map(s => `"${s}"`).join(', ');
7
+ const commit_async_1 = require("./utils/commit-async");
8
+ const formatDependencies = (strings) => strings.map((s) => `"${s}"`).join(', ');
9
9
  class StepManager {
10
10
  constructor() {
11
11
  this.steps = [];
@@ -37,7 +37,7 @@ class StepManager {
37
37
  return this;
38
38
  }
39
39
  validateDependencies(step, dependencies, mapPaths) {
40
- const missingDependencySteps = dependencies.map(dep => dep.sourceStep).filter(stepName => !this.namedSteps.has(stepName));
40
+ const missingDependencySteps = dependencies.map((dep) => dep.sourceStep).filter((stepName) => !this.namedSteps.has(stepName));
41
41
  if (missingDependencySteps.length > 0) {
42
42
  throw new Error(`Step of type "${step.type}" depends on nonexistent named steps ${formatDependencies(missingDependencySteps)}`);
43
43
  }
@@ -52,7 +52,7 @@ class StepManager {
52
52
  if (mapPaths.length === 0 && (sourceStep === null || sourceStep === void 0 ? void 0 : sourceStep.mapPaths.length)) {
53
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
54
  }
55
- const missingMapPathsDeps = mapPaths.filter(p => sourceStep && !sourceStep.mapPaths.includes(p));
55
+ const missingMapPathsDeps = mapPaths.filter((p) => sourceStep && !sourceStep.mapPaths.includes(p));
56
56
  if (sourceStep && (missingMapPathsDeps === null || missingMapPathsDeps === void 0 ? void 0 : missingMapPathsDeps.length) && sourceStep.mapPaths.length > 0) {
57
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
58
  }
@@ -62,7 +62,7 @@ class StepManager {
62
62
  }
63
63
  }
64
64
  async run(paths, io, providers, dry = false) {
65
- if (dry && this.steps.some(s => !(s instanceof AtomicStepManager) && !s.step.composable)) {
65
+ if (dry && this.steps.some((s) => !(s instanceof AtomicStepManager) && !s.step.composable)) {
66
66
  throw new Error('Cannot dry run, as this step manager has non-composable steps.');
67
67
  }
68
68
  const stepNames = [];
@@ -72,7 +72,7 @@ class StepManager {
72
72
  return;
73
73
  const fs = await this.runStep(step, paths, io, providers, packagePath);
74
74
  if (!dry) {
75
- await this.commit(fs);
75
+ await (0, commit_async_1.commitAsync)(fs);
76
76
  }
77
77
  stepNames.push(packagePath ? `${step.step.type} (${packagePath})` : step.step.type);
78
78
  };
@@ -139,9 +139,9 @@ class StepManager {
139
139
  const sourceStep = this.namedSteps.get(dep.sourceStep);
140
140
  let depValue;
141
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);
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
145
  if (dep.modifier) {
146
146
  depValue = dep.modifier(depValue);
147
147
  }
@@ -156,16 +156,6 @@ class StepManager {
156
156
  }
157
157
  return newFs;
158
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
159
  }
170
160
  exports.StepManager = StepManager;
171
161
  class AtomicStepManager extends StepManager {
@@ -222,7 +212,7 @@ class AtomicStepManager extends StepManager {
222
212
  };
223
213
  }
224
214
  if (!dry) {
225
- await this.commit(fs);
215
+ await (0, commit_async_1.commitAsync)(fs);
226
216
  }
227
217
  return {
228
218
  succeeded: true,
@@ -5,7 +5,7 @@ const tslib_1 = require("tslib");
5
5
  const pick_deep_1 = (0, tslib_1.__importDefault)(require("pick-deep"));
6
6
  const mem_fs_editor_1 = require("mem-fs-editor");
7
7
  const clone_and_fill_1 = require("../utils/clone-and-fill");
8
- const node_path_1 = require("node:path");
8
+ const path_1 = require("path");
9
9
  class BaseStubStep {
10
10
  constructor(stubDir, scaffolder) {
11
11
  this.composable = true;
@@ -27,7 +27,7 @@ class BaseStubStep {
27
27
  const newFileName = await this.getFileName(fs, paths, io);
28
28
  const newFilePath = paths.package(this.schema.root || this.defaultRoot, this.subdir, newFileName);
29
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);
30
+ fsEditor.copyTpl((0, path_1.resolve)(this.stubDir, stub), newFilePath, this.params);
31
31
  return fs;
32
32
  }
33
33
  getExposed(_paths, _paramProvider) {
@@ -38,7 +38,7 @@ class BaseStubStep {
38
38
  }
39
39
  async compileParams(fs, paths, io) {
40
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));
41
+ const paramDefs = this.schema.params.filter((param) => !this.implicitParams.includes(param.name) && !Object.keys(params).includes(param.name));
42
42
  for (const paramDef of paramDefs) {
43
43
  // eslint-disable-next-line no-await-in-loop
44
44
  params[paramDef.name] = await io.getParam(paramDef);
@@ -11,7 +11,7 @@ function cloneAndFill(obj, params) {
11
11
  if (typeof obj === 'string')
12
12
  return fill(obj, params);
13
13
  if (Array.isArray(obj))
14
- return obj.map(v => recursiveCopyAndFill(v, params));
14
+ return obj.map((v) => recursiveCopyAndFill(v, params));
15
15
  // eslint-disable-next-line no-new-object
16
16
  if (obj !== new Object(obj))
17
17
  return obj;
@@ -0,0 +1,2 @@
1
+ import { Store } from 'mem-fs';
2
+ export declare function commitAsync(fs: Store): Promise<boolean>;
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.commitAsync = void 0;
4
+ const mem_fs_editor_1 = require("mem-fs-editor");
5
+ async function commitAsync(fs) {
6
+ return new Promise((resolve, _reject) => {
7
+ (0, mem_fs_editor_1.create)(fs).commit((err) => {
8
+ if (err) {
9
+ throw new Error(err);
10
+ }
11
+ resolve(true);
12
+ });
13
+ });
14
+ }
15
+ exports.commitAsync = commitAsync;
@@ -2,9 +2,9 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.readTpl = void 0;
4
4
  const ejs_1 = require("ejs");
5
- const node_fs_1 = require("node:fs");
5
+ const fs_1 = require("fs");
6
6
  function readTpl(path, data, options) {
7
- const template = (0, node_fs_1.readFileSync)(path, 'utf8');
7
+ const template = (0, fs_1.readFileSync)(path, 'utf8');
8
8
  return (0, ejs_1.render)(template, data, Object.assign(Object.assign({ filename: path }, options), { async: false }));
9
9
  }
10
10
  exports.readTpl = readTpl;
@@ -11,6 +11,6 @@ export default class AuditInfra extends BaseCommand {
11
11
  name: string;
12
12
  description: string;
13
13
  }[];
14
- protected steps(stepManager: StepManager<FlarumProviders>): StepManager<FlarumProviders>;
14
+ protected steps(stepManager: StepManager<FlarumProviders>, extRoot: string): StepManager<FlarumProviders>;
15
15
  protected additionalPreRunChecks(extRoot: string): Promise<void>;
16
16
  }
@@ -4,16 +4,38 @@ const tslib_1 = require("tslib");
4
4
  const base_command_1 = (0, tslib_1.__importDefault)(require("../../base-command"));
5
5
  const gen_ext_scaffolder_1 = require("../../steps/gen-ext-scaffolder");
6
6
  const core_1 = require("@oclif/core");
7
+ const yarn_1 = require("../../steps/misc/yarn");
8
+ const composer_1 = require("../../steps/misc/composer");
9
+ const npm_1 = require("../../steps/misc/npm");
7
10
  class AuditInfra extends base_command_1.default {
8
- steps(stepManager) {
11
+ steps(stepManager, extRoot) {
9
12
  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);
13
+ const mapPaths = this.flags.monorepo
14
+ ? this.monorepoPaths({
15
+ includeCore: true,
16
+ includeExtensions: true,
17
+ includePhpPackages: false,
18
+ includeJSPackages: false,
19
+ })
20
+ : [];
21
+ stepManager.namedStep('audit', (0, gen_ext_scaffolder_1.genExtScaffolder)().genAuditStep(!this.flags.fix), {}, [], {}, mapPaths);
22
+ if (!this.flags.monorepo && !this.dry) {
23
+ const packageManager = this.jsPackageManager(extRoot);
24
+ stepManager.step(packageManager === 'npm' ? new npm_1.NpmInstall() : new yarn_1.YarnInstall(), { optional: true, confirmationMessage: `Run \`${packageManager !== null && packageManager !== void 0 ? packageManager : 'yarn'}\`? (recommended)`, default: true }, [
25
+ {
26
+ sourceStep: 'audit',
27
+ exposedName: '__succeeded',
28
+ dontRunIfFalsy: true,
29
+ },
30
+ ]);
31
+ stepManager.step(new composer_1.ComposerInstall(), { optional: true, confirmationMessage: 'Run `composer update`? (recommended)', default: true }, [
32
+ {
33
+ sourceStep: 'audit',
34
+ exposedName: '__succeeded',
35
+ dontRunIfFalsy: true,
36
+ },
37
+ ]);
38
+ }
17
39
  return stepManager;
18
40
  }
19
41
  async additionalPreRunChecks(extRoot) {
@@ -13,8 +13,8 @@ export default class Infra extends BaseCommand {
13
13
  name: string;
14
14
  description: string;
15
15
  required: boolean;
16
- options: ("core" | "icon" | "js" | "jsCommon" | "css" | "locale" | "gitConf" | "githubActions" | "prettier" | "typescript" | "bundlewatch" | "backendTesting" | "editorConfig" | "styleci")[];
16
+ options: ("core" | "js" | "icon" | "admin" | "forum" | "jsCommon" | "css" | "locale" | "gitConf" | "githubActions" | "prettier" | "typescript" | "bundlewatch" | "backendTesting" | "editorConfig" | "styleci")[];
17
17
  })[];
18
- protected steps(stepManager: StepManager<FlarumProviders>): StepManager<FlarumProviders>;
18
+ protected steps(stepManager: StepManager<FlarumProviders>, extRoot: string): StepManager<FlarumProviders>;
19
19
  protected additionalPreRunChecks(extRoot: string): Promise<void>;
20
20
  }
@@ -4,23 +4,26 @@ const tslib_1 = require("tslib");
4
4
  const composer_1 = require("../steps/misc/composer");
5
5
  const base_command_1 = (0, tslib_1.__importDefault)(require("../base-command"));
6
6
  const gen_ext_scaffolder_1 = require("../steps/gen-ext-scaffolder");
7
+ const npm_1 = require("../steps/misc/npm");
7
8
  const yarn_1 = require("../steps/misc/yarn");
8
9
  const core_1 = require("@oclif/core");
9
10
  class Infra extends base_command_1.default {
10
- steps(stepManager) {
11
+ steps(stepManager, extRoot) {
11
12
  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);
13
+ const mapPaths = this.flags.monorepo
14
+ ? this.monorepoPaths({
15
+ includeCore: true,
16
+ includeExtensions: true,
17
+ includePhpPackages: false,
18
+ includeJSPackages: false,
19
+ })
20
+ : [];
21
+ stepManager.namedStep('infra', (0, gen_ext_scaffolder_1.genExtScaffolder)().genInfraStep(this.args.module), {}, [], {}, mapPaths);
20
22
  const JS_MODULES = ['js', 'prettier', 'typescript'];
21
23
  const PHP_MODULES = ['backendTesting'];
24
+ const packageManager = this.jsPackageManager(extRoot);
22
25
  if (!this.flags.monorepo && JS_MODULES.includes(module)) {
23
- stepManager.step(new yarn_1.YarnInstall(), { optional: true, confirmationMessage: 'Run `yarn`? (recommended)', default: true }, [
26
+ stepManager.step(packageManager === 'npm' ? new npm_1.NpmInstall() : new yarn_1.YarnInstall(), { optional: true, confirmationMessage: `Run \`${packageManager !== null && packageManager !== void 0 ? packageManager : 'yarn'}\`? (recommended)`, default: true }, [
24
27
  {
25
28
  sourceStep: 'infra',
26
29
  exposedName: '__succeeded',
@@ -47,9 +50,12 @@ class Infra extends base_command_1.default {
47
50
  exports.default = Infra;
48
51
  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
52
  Infra.flags = Object.assign({ monorepo: core_1.Flags.boolean({ char: 'm', default: false }) }, base_command_1.default.flags);
50
- Infra.args = [{
53
+ Infra.args = [
54
+ {
51
55
  name: 'module',
52
56
  description: 'The name of the module to enable/update.',
53
57
  required: true,
54
58
  options: [...gen_ext_scaffolder_1.EXTENSION_MODULES],
55
- }, ...base_command_1.default.args];
59
+ },
60
+ ...base_command_1.default.args,
61
+ ];
@@ -11,7 +11,7 @@ export default class Init extends BaseCommand {
11
11
  description: string;
12
12
  }[];
13
13
  protected requireExistingExtension: boolean;
14
- protected steps(stepManager: StepManager<FlarumProviders>): StepManager<FlarumProviders>;
14
+ protected steps(stepManager: StepManager<FlarumProviders>, extRoot: string): StepManager<FlarumProviders>;
15
15
  protected welcomeMessage(): string;
16
16
  protected goodbyeMessage(): string;
17
17
  protected additionalPreRunChecks(extRoot: string): Promise<void>;
@@ -7,17 +7,19 @@ const base_command_1 = (0, tslib_1.__importDefault)(require("../base-command"));
7
7
  const yosay_1 = (0, tslib_1.__importDefault)(require("yosay"));
8
8
  const gen_ext_scaffolder_1 = require("../steps/gen-ext-scaffolder");
9
9
  const git_1 = require("../steps/misc/git");
10
+ const npm_1 = require("../steps/misc/npm");
10
11
  class Init extends base_command_1.default {
11
12
  constructor() {
12
13
  super(...arguments);
13
14
  this.requireExistingExtension = false;
14
15
  }
15
- steps(stepManager) {
16
+ steps(stepManager, extRoot) {
17
+ const packageManager = this.jsPackageManager(extRoot);
16
18
  return stepManager
17
19
  .namedStep('gitInit', new git_1.GitInit(), { optional: true, confirmationMessage: 'Run `git init`? (recommended)', default: true })
18
20
  .namedStep('skeleton', (0, gen_ext_scaffolder_1.genExtScaffolder)().genInitStep())
19
21
  .step(new composer_1.ComposerInstall(), { optional: true, confirmationMessage: 'Run `composer install`? (recommended)', default: true })
20
- .step(new yarn_1.YarnInstall(), { optional: true, confirmationMessage: 'Run `yarn install`? (recommended)', default: true }, [
22
+ .step(packageManager === 'npm' ? new npm_1.NpmInstall() : new yarn_1.YarnInstall(), { optional: true, confirmationMessage: `Run \`${packageManager !== null && packageManager !== void 0 ? packageManager : 'yarn'}\`? (recommended)`, default: true }, [
21
23
  {
22
24
  sourceStep: 'skeleton',
23
25
  exposedName: 'modules.js',
@@ -7,8 +7,7 @@ const route_1 = require("../../../steps/extenders/route");
7
7
  const gen_ext_scaffolder_1 = require("../../../steps/gen-ext-scaffolder");
8
8
  class ApiController extends base_command_1.default {
9
9
  steps(stepManager) {
10
- return stepManager
11
- .atomicGroup(stepManager => {
10
+ return stepManager.atomicGroup((stepManager) => {
12
11
  stepManager
13
12
  .namedStep('apiController', new api_controller_1.GenerateApiControllerStub(this.STUB_PATH, (0, gen_ext_scaffolder_1.genExtScaffolder)()))
14
13
  .step(new route_1.GenerateRoutesExtender(), { optional: true, confirmationMessage: 'Generate corresponding extender?', default: true }, [
@@ -5,8 +5,7 @@ const base_command_1 = (0, tslib_1.__importDefault)(require("../../../base-comma
5
5
  const api_serializer_1 = require("../../../steps/extenders/api-serializer");
6
6
  class ApiSerializerAttribute extends base_command_1.default {
7
7
  steps(stepManager) {
8
- return stepManager
9
- .step(new api_serializer_1.GenerateApiSerializerAttributesExtender());
8
+ return stepManager.step(new api_serializer_1.GenerateApiSerializerAttributesExtender());
10
9
  }
11
10
  }
12
11
  exports.default = ApiSerializerAttribute;
@@ -7,8 +7,7 @@ const console_command_1 = require("../../../steps/extenders/console-command");
7
7
  const gen_ext_scaffolder_1 = require("../../../steps/gen-ext-scaffolder");
8
8
  class Command extends base_command_1.default {
9
9
  steps(stepManager) {
10
- return stepManager
11
- .atomicGroup(stepManager => {
10
+ return stepManager.atomicGroup((stepManager) => {
12
11
  stepManager
13
12
  .namedStep('command', new command_1.GenerateCommandStub(this.STUB_PATH, (0, gen_ext_scaffolder_1.genExtScaffolder)()))
14
13
  .step(new console_command_1.GenerateConsoleCommandExtender(), { optional: true, confirmationMessage: 'Generate corresponding extender?', default: true }, [
@@ -7,8 +7,7 @@ const event_1 = require("../../../steps/extenders/event");
7
7
  const gen_ext_scaffolder_1 = require("../../../steps/gen-ext-scaffolder");
8
8
  class EventListener extends base_command_1.default {
9
9
  steps(stepManager) {
10
- return stepManager
11
- .atomicGroup(stepManager => {
10
+ return stepManager.atomicGroup((stepManager) => {
12
11
  stepManager
13
12
  .namedStep('listener', new event_listener_1.GenerateEventListenerStub(this.STUB_PATH, (0, gen_ext_scaffolder_1.genExtScaffolder)()))
14
13
  .step(new event_1.GenerateEventListenerExtender(), { optional: true, confirmationMessage: 'Generate corresponding extender?', default: true }, [
@@ -7,11 +7,8 @@ const handler_1 = require("../../../steps/stubs/backend/handler");
7
7
  const gen_ext_scaffolder_1 = require("../../../steps/gen-ext-scaffolder");
8
8
  class ApiController extends base_command_1.default {
9
9
  steps(stepManager) {
10
- return stepManager
11
- .atomicGroup(stepManager => {
12
- stepManager
13
- .namedStep('handlerCommand', new handler_command_1.GenerateHandlerCommandStub(this.STUB_PATH, (0, gen_ext_scaffolder_1.genExtScaffolder)()))
14
- .step(new handler_1.GenerateHandlerStub(this.STUB_PATH, (0, gen_ext_scaffolder_1.genExtScaffolder)()), {}, [
10
+ return stepManager.atomicGroup((stepManager) => {
11
+ stepManager.namedStep('handlerCommand', new handler_command_1.GenerateHandlerCommandStub(this.STUB_PATH, (0, gen_ext_scaffolder_1.genExtScaffolder)())).step(new handler_1.GenerateHandlerStub(this.STUB_PATH, (0, gen_ext_scaffolder_1.genExtScaffolder)()), {}, [
15
12
  {
16
13
  sourceStep: 'handlerCommand',
17
14
  exposedName: 'className',
@@ -6,10 +6,8 @@ const base_command_1 = (0, tslib_1.__importDefault)(require("../../../base-comma
6
6
  const integration_test_1 = require("../../../steps/stubs/backend/integration-test");
7
7
  class IntegrationTest extends base_command_1.default {
8
8
  steps(stepManager) {
9
- return stepManager
10
- .atomicGroup(stepManager => {
11
- stepManager
12
- .namedStep('test', new integration_test_1.GenerateIntegrationTestStub(this.STUB_PATH, (0, gen_ext_scaffolder_1.genExtScaffolder)()));
9
+ return stepManager.atomicGroup((stepManager) => {
10
+ stepManager.namedStep('test', new integration_test_1.GenerateIntegrationTestStub(this.STUB_PATH, (0, gen_ext_scaffolder_1.genExtScaffolder)()));
13
11
  });
14
12
  }
15
13
  }
@@ -6,8 +6,7 @@ const base_command_1 = (0, tslib_1.__importDefault)(require("../../../base-comma
6
6
  const migration_1 = require("../../../steps/stubs/backend/migration");
7
7
  class Migration extends base_command_1.default {
8
8
  steps(stepManager) {
9
- return stepManager
10
- .step(new migration_1.GenerateMigrationStub(this.STUB_PATH, (0, gen_ext_scaffolder_1.genExtScaffolder)()));
9
+ return stepManager.step(new migration_1.GenerateMigrationStub(this.STUB_PATH, (0, gen_ext_scaffolder_1.genExtScaffolder)()));
11
10
  }
12
11
  }
13
12
  exports.default = Migration;
@@ -18,8 +18,7 @@ const route_1 = require("../../../steps/extenders/route");
18
18
  const gen_ext_scaffolder_1 = require("../../../steps/gen-ext-scaffolder");
19
19
  class Model extends base_command_1.default {
20
20
  steps(stepManager) {
21
- return stepManager
22
- .atomicGroup(stepManager => {
21
+ return stepManager.atomicGroup((stepManager) => {
23
22
  stepManager
24
23
  .namedStep('model', new model_1.GenerateModelStub(this.STUB_PATH, (0, gen_ext_scaffolder_1.genExtScaffolder)()))
25
24
  .step(new migration_1.GenerateMigrationStub(this.STUB_PATH, (0, gen_ext_scaffolder_1.genExtScaffolder)()), { optional: true, confirmationMessage: 'Generate corresponding Migration?', default: true }, [