@flarum/cli 2.0.0-beta.13 → 2.0.0-beta.14

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 (112) hide show
  1. package/README.md +136 -39
  2. package/boilerplate/skeleton/extension/.gitattributes +1 -0
  3. package/boilerplate/skeleton/extension/.github/workflows/backend.yml +1 -1
  4. package/boilerplate/skeleton/extension/.github/workflows/frontend.yml +3 -1
  5. package/boilerplate/skeleton/extension/LICENSE.md +1 -1
  6. package/boilerplate/skeleton/extension/composer.json +4 -2
  7. package/boilerplate/skeleton/extension/js/package.json +4 -1
  8. package/boilerplate/skeleton/extension/tests/phpunit.integration.xml +1 -0
  9. package/lib/base-command.d.ts +3 -1
  10. package/lib/base-command.js +27 -14
  11. package/lib/boilersmith/io.d.ts +28 -8
  12. package/lib/boilersmith/io.js +4 -2
  13. package/lib/boilersmith/paths.d.ts +2 -2
  14. package/lib/boilersmith/paths.js +2 -2
  15. package/lib/boilersmith/scaffolding/audit-step-factory.js +10 -10
  16. package/lib/boilersmith/scaffolding/infra-step-factory.js +2 -2
  17. package/lib/boilersmith/scaffolding/init-step-factory.js +5 -5
  18. package/lib/boilersmith/scaffolding/module.d.ts +19 -8
  19. package/lib/boilersmith/scaffolding/module.js +30 -17
  20. package/lib/boilersmith/scaffolding/scaffolder.d.ts +4 -1
  21. package/lib/boilersmith/scaffolding/scaffolder.js +29 -29
  22. package/lib/boilersmith/scaffolding/template-param.d.ts +1 -1
  23. package/lib/boilersmith/scaffolding/template-param.js +2 -2
  24. package/lib/boilersmith/step-manager.d.ts +0 -1
  25. package/lib/boilersmith/step-manager.js +10 -20
  26. package/lib/boilersmith/steps/stub-base.js +1 -1
  27. package/lib/boilersmith/utils/clone-and-fill.js +1 -1
  28. package/lib/boilersmith/utils/commit-async.d.ts +2 -0
  29. package/lib/boilersmith/utils/commit-async.js +15 -0
  30. package/lib/commands/audit/infra.d.ts +1 -1
  31. package/lib/commands/audit/infra.js +30 -8
  32. package/lib/commands/infra.d.ts +2 -2
  33. package/lib/commands/infra.js +18 -12
  34. package/lib/commands/init.d.ts +1 -1
  35. package/lib/commands/init.js +4 -2
  36. package/lib/commands/make/backend/api-controller.js +1 -2
  37. package/lib/commands/make/backend/api-serializer-attributes.js +1 -2
  38. package/lib/commands/make/backend/command.js +1 -2
  39. package/lib/commands/make/backend/event-listener.js +1 -2
  40. package/lib/commands/make/backend/handler.js +2 -5
  41. package/lib/commands/make/backend/integration-test.js +2 -4
  42. package/lib/commands/make/backend/migration.js +1 -2
  43. package/lib/commands/make/backend/model.js +1 -2
  44. package/lib/commands/make/backend/policy.js +1 -2
  45. package/lib/commands/make/backend/route.js +1 -2
  46. package/lib/commands/make/backend/service-provider.js +1 -2
  47. package/lib/commands/make/frontend/model.js +2 -5
  48. package/lib/commands/monorepo/create.d.ts +15 -0
  49. package/lib/commands/monorepo/create.js +20 -0
  50. package/lib/commands/update/js-imports.js +1 -2
  51. package/lib/help.js +1 -1
  52. package/lib/steps/gen-ext-scaffolder.d.ts +1 -1
  53. package/lib/steps/gen-ext-scaffolder.js +94 -38
  54. package/lib/steps/js/base.js +2 -4
  55. package/lib/steps/js/model.js +4 -4
  56. package/lib/steps/misc/git.d.ts +1 -1
  57. package/lib/steps/misc/git.js +2 -2
  58. package/lib/steps/misc/npm.d.ts +11 -0
  59. package/lib/steps/misc/npm.js +19 -0
  60. package/lib/steps/monorepo/create.d.ts +17 -0
  61. package/lib/steps/monorepo/create.js +181 -0
  62. package/lib/steps/stubs/backend/api-controller.d.ts +1 -1
  63. package/lib/steps/stubs/backend/api-controller.js +3 -0
  64. package/lib/steps/stubs/backend/api-serializer.d.ts +1 -1
  65. package/lib/steps/stubs/backend/api-serializer.js +3 -0
  66. package/lib/steps/stubs/backend/command.d.ts +0 -5
  67. package/lib/steps/stubs/backend/command.js +1 -0
  68. package/lib/steps/stubs/backend/event-listener.d.ts +1 -1
  69. package/lib/steps/stubs/backend/event-listener.js +2 -0
  70. package/lib/steps/stubs/backend/handler-command.d.ts +1 -1
  71. package/lib/steps/stubs/backend/handler-command.js +1 -0
  72. package/lib/steps/stubs/backend/handler.d.ts +1 -1
  73. package/lib/steps/stubs/backend/handler.js +4 -0
  74. package/lib/steps/stubs/backend/integration-test.d.ts +1 -1
  75. package/lib/steps/stubs/backend/integration-test.js +2 -0
  76. package/lib/steps/stubs/backend/job.d.ts +1 -1
  77. package/lib/steps/stubs/backend/job.js +1 -0
  78. package/lib/steps/stubs/backend/migration.js +4 -1
  79. package/lib/steps/stubs/backend/model.d.ts +1 -1
  80. package/lib/steps/stubs/backend/model.js +1 -0
  81. package/lib/steps/stubs/backend/policy.d.ts +1 -1
  82. package/lib/steps/stubs/backend/policy.js +2 -0
  83. package/lib/steps/stubs/backend/repository.d.ts +1 -1
  84. package/lib/steps/stubs/backend/repository.js +2 -0
  85. package/lib/steps/stubs/backend/service-provider.d.ts +1 -1
  86. package/lib/steps/stubs/backend/service-provider.js +1 -0
  87. package/lib/steps/stubs/backend/validator.d.ts +1 -1
  88. package/lib/steps/stubs/backend/validator.js +1 -0
  89. package/lib/steps/stubs/flarum-base.js +1 -1
  90. package/lib/steps/stubs/frontend/component.d.ts +0 -5
  91. package/lib/steps/stubs/frontend/component.js +1 -0
  92. package/lib/steps/stubs/frontend/modal.d.ts +0 -5
  93. package/lib/steps/stubs/frontend/modal.js +1 -0
  94. package/lib/steps/stubs/frontend/model.d.ts +0 -5
  95. package/lib/steps/stubs/frontend/model.js +1 -0
  96. package/lib/steps/stubs/js-base.js +8 -5
  97. package/lib/steps/stubs/php-base.js +10 -8
  98. package/lib/steps/update/js-imports.js +8 -2
  99. package/lib/utils/composer.d.ts +1 -0
  100. package/lib/utils/migration.js +3 -1
  101. package/lib/utils/monorepo.d.ts +24 -0
  102. package/lib/utils/monorepo.js +24 -0
  103. package/lib/utils/validation.d.ts +2 -0
  104. package/lib/utils/validation.js +6 -0
  105. package/oclif.manifest.json +1 -1
  106. package/package.json +7 -3
  107. package/php-subsystem/composer.json +9 -9
  108. package/php-subsystem/composer.lock +64 -71
  109. package/php-subsystem/vendor/composer/installed.json +54 -61
  110. package/php-subsystem/vendor/nikic/php-parser/README.md +55 -59
  111. package/php-subsystem/vendor/nikic/php-parser/composer.json +39 -39
  112. package/php-subsystem/vendor/nikic/php-parser/grammar/README.md +17 -20
@@ -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 }, [
@@ -7,8 +7,7 @@ const policy_2 = require("../../../steps/extenders/policy");
7
7
  const gen_ext_scaffolder_1 = require("../../../steps/gen-ext-scaffolder");
8
8
  class Policy 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('policy', new policy_1.GeneratePolicyStub(this.STUB_PATH, (0, gen_ext_scaffolder_1.genExtScaffolder)()))
14
13
  .step(new policy_2.GeneratePolicyExtender(), { 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 route_1 = require("../../../steps/extenders/route");
6
6
  class Route extends base_command_1.default {
7
7
  steps(stepManager) {
8
- return stepManager
9
- .step(new route_1.GenerateRoutesExtender());
8
+ return stepManager.step(new route_1.GenerateRoutesExtender());
10
9
  }
11
10
  }
12
11
  exports.default = Route;
@@ -7,8 +7,7 @@ const service_provider_2 = require("../../../steps/extenders/service-provider");
7
7
  const gen_ext_scaffolder_1 = require("../../../steps/gen-ext-scaffolder");
8
8
  class ServiceProvider 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('provider', new service_provider_1.GenerateServiceProviderStub(this.STUB_PATH, (0, gen_ext_scaffolder_1.genExtScaffolder)()))
14
13
  .step(new service_provider_2.GenerateServiceProviderExtender(), { optional: true, confirmationMessage: 'Generate corresponding extender?', default: true }, [
@@ -7,11 +7,8 @@ const model_2 = require("../../../steps/js/model");
7
7
  const gen_ext_scaffolder_1 = require("../../../steps/gen-ext-scaffolder");
8
8
  class Model extends base_command_1.default {
9
9
  steps(stepManager) {
10
- return stepManager
11
- .atomicGroup(stepManager => {
12
- stepManager
13
- .namedStep('model', new model_1.GenerateModelStub(this.STUB_PATH, (0, gen_ext_scaffolder_1.genExtScaffolder)()))
14
- .step(new model_2.GenerateModelDefinition(), {}, [
10
+ return stepManager.atomicGroup((stepManager) => {
11
+ stepManager.namedStep('model', new model_1.GenerateModelStub(this.STUB_PATH, (0, gen_ext_scaffolder_1.genExtScaffolder)())).step(new model_2.GenerateModelDefinition(), {}, [
15
12
  {
16
13
  sourceStep: 'model',
17
14
  exposedName: 'frontend',
@@ -0,0 +1,15 @@
1
+ import { StepManager } from 'boilersmith/step-manager';
2
+ import BaseCommand from '../../base-command';
3
+ import { FlarumProviders } from '../../providers';
4
+ export default class Create extends BaseCommand {
5
+ static description: string;
6
+ static flags: {
7
+ config: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined>;
8
+ };
9
+ static args: {
10
+ name: string;
11
+ description: string;
12
+ }[];
13
+ protected requireExistingExtension: boolean;
14
+ protected steps(stepManager: StepManager<FlarumProviders>): StepManager<FlarumProviders>;
15
+ }
@@ -0,0 +1,20 @@
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 core_1 = require("@oclif/core");
6
+ const create_1 = require("../../steps/monorepo/create");
7
+ const gen_ext_scaffolder_1 = require("../../steps/gen-ext-scaffolder");
8
+ class Create extends base_command_1.default {
9
+ constructor() {
10
+ super(...arguments);
11
+ this.requireExistingExtension = false;
12
+ }
13
+ steps(stepManager) {
14
+ return stepManager.step(new create_1.MonorepoCreate((0, gen_ext_scaffolder_1.genExtScaffolder)(), this.flags.config));
15
+ }
16
+ }
17
+ exports.default = Create;
18
+ Create.description = 'Create a monorepo of Flarum extensions.';
19
+ Create.flags = Object.assign({ config: core_1.Flags.string({ char: 'c', required: false }) }, base_command_1.default.flags);
20
+ Create.args = [...base_command_1.default.args];
@@ -5,8 +5,7 @@ const js_imports_1 = require("../../steps/update/js-imports");
5
5
  const base_command_1 = (0, tslib_1.__importDefault)(require("../../base-command"));
6
6
  class UpdateJsImports extends base_command_1.default {
7
7
  steps(stepManager) {
8
- return stepManager
9
- .step(new js_imports_1.UpdateJSImports());
8
+ return stepManager.step(new js_imports_1.UpdateJSImports());
10
9
  }
11
10
  async additionalPreRunChecks(extRoot) {
12
11
  await this.ensureComposerInstallRan(extRoot);
package/lib/help.js CHANGED
@@ -12,7 +12,7 @@ function prepTopic(topic) {
12
12
  return Object.assign({}, topic, { name: chalk_1.default.green(topic.name.replace(COLON_REGEX, ' ')) });
13
13
  }
14
14
  function colorHeaders(text) {
15
- return text.replace(/(TOPICS|TOPIC|DESCRIPTION|USAGE|COMMANDS|VERSION|ARGUMENTS|OPTIONS)/g, match => {
15
+ return text.replace(/(TOPICS|TOPIC|DESCRIPTION|USAGE|COMMANDS|VERSION|ARGUMENTS|OPTIONS)/g, (match) => {
16
16
  return chalk_1.default.yellow(match);
17
17
  });
18
18
  }
@@ -1,5 +1,5 @@
1
1
  import { Scaffolder } from 'boilersmith/scaffolding/scaffolder';
2
- export declare const EXTENSION_PARAMS: readonly ["packageName", "packageDescription", "packageNamespace", "authorName", "authorEmail", "extensionName", "licenseType", "mainGitBranch", "licenseText", "packageNamespaceEscapedSlash", "extensionId", "year", "backendDirectory", "frontendDirectory"];
2
+ export declare const EXTENSION_PARAMS: readonly ["packageName", "packageDescription", "packageNamespace", "authorName", "authorEmail", "extensionName", "licenseType", "mainGitBranch", "jsPackageManager", "licenseText", "packageNamespaceEscapedSlash", "extensionId", "year", "backendDirectory", "frontendDirectory"];
3
3
  export declare type ExtensionParams = typeof EXTENSION_PARAMS[number];
4
4
  export declare const EXTENSION_MODULES: readonly ["core", "icon", "admin", "forum", "js", "jsCommon", "css", "locale", "gitConf", "githubActions", "prettier", "typescript", "bundlewatch", "backendTesting", "editorConfig", "styleci"];
5
5
  export declare type ExtensionModules = typeof EXTENSION_MODULES[number];
@@ -5,6 +5,7 @@ const tslib_1 = require("tslib");
5
5
  const scaffolder_1 = require("boilersmith/scaffolding/scaffolder");
6
6
  const chalk_1 = (0, tslib_1.__importDefault)(require("chalk"));
7
7
  const mem_fs_editor_1 = require("mem-fs-editor");
8
+ const node_child_process_1 = require("node:child_process");
8
9
  const node_fs_1 = require("node:fs");
9
10
  const node_path_1 = require("node:path");
10
11
  const simple_git_1 = (0, tslib_1.__importDefault)(require("simple-git"));
@@ -22,6 +23,7 @@ exports.EXTENSION_PARAMS = [
22
23
  'extensionName',
23
24
  'licenseType',
24
25
  'mainGitBranch',
26
+ 'jsPackageManager',
25
27
  'licenseText',
26
28
  'packageNamespaceEscapedSlash',
27
29
  'extensionId',
@@ -37,8 +39,8 @@ function paramNamesToDef(name) {
37
39
  name,
38
40
  type: 'text',
39
41
  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
+ validate: (s) => /^([\dA-Za-z-]{2,})\/([\dA-Za-z-]{2,})$/.test(s.trim()) || 'Invalid package name format',
43
+ format: (s) => s.toLowerCase(),
42
44
  },
43
45
  getCurrVal: async (fs, paths) => {
44
46
  const json = (0, composer_1.getComposerJson)(fs, paths);
@@ -64,11 +66,11 @@ function paramNamesToDef(name) {
64
66
  name,
65
67
  type: 'text',
66
68
  message: `Package namespace ${chalk_1.default.dim('(Vendor\\ExtensionName)')}`,
67
- validate: s => /^([\dA-Za-z]+)\\([\dA-Za-z]+)$/.test(s.trim()) || 'Invalid namespace format',
69
+ validate: (s) => /^([\dA-Za-z]+)\\([\dA-Za-z]+)$/.test(s.trim()) || 'Invalid namespace format',
68
70
  format: (str) => str &&
69
71
  str
70
72
  .split('\\')
71
- .map(s => s[0].toUpperCase() + s.slice(1))
73
+ .map((s) => s[0].toUpperCase() + s.slice(1))
72
74
  .join('\\'),
73
75
  },
74
76
  getCurrVal: async (fs, paths) => {
@@ -97,7 +99,7 @@ function paramNamesToDef(name) {
97
99
  name,
98
100
  type: 'text',
99
101
  message: 'Author email',
100
- validate: s => !s || /^[\w!#$%&*+./=?^`{|}~’-]+@[\dA-Za-z-]+(?:\.[\dA-Za-z-]+)*$/.test(s) || 'Invalid email format',
102
+ validate: (s) => !s || /^[\w!#$%&*+./=?^`{|}~’-]+@[\dA-Za-z-]+(?:\.[\dA-Za-z-]+)*$/.test(s) || 'Invalid email format',
101
103
  },
102
104
  getCurrVal: async (fs, paths) => {
103
105
  var _a, _b, _c;
@@ -111,8 +113,8 @@ function paramNamesToDef(name) {
111
113
  name,
112
114
  type: 'text',
113
115
  message: 'Extension name',
114
- validate: str => Boolean(str.trim()) || 'The extension name is required',
115
- format: str => str
116
+ validate: (str) => Boolean(str.trim()) || 'The extension name is required',
117
+ format: (str) => str
116
118
  .split(' ')
117
119
  .map((s) => (s.length > 3 ? s[0].toUpperCase() + s.slice(1) : s))
118
120
  .join(' '),
@@ -131,7 +133,7 @@ function paramNamesToDef(name) {
131
133
  name,
132
134
  type: 'autocomplete',
133
135
  message: 'License',
134
- choices: [...simple_1.default].map(e => ({ title: e, value: e })),
136
+ choices: [...simple_1.default].map((e) => ({ title: e, value: e })),
135
137
  },
136
138
  getCurrVal: async (fs, paths) => {
137
139
  var _a;
@@ -170,12 +172,37 @@ function paramNamesToDef(name) {
170
172
  type: 'text',
171
173
  message: `Main git branch ${chalk_1.default.dim('(JS will automatically build when changes are pushed to GitHub on this branch)')}`,
172
174
  // See https://stackoverflow.com/a/12093994/11091039
173
- validate: s => /^(?!.*\/\.)(?!.*\.\.)(?!\/)(?!.*\/\/)(?!.*@{)(?!.*\\)[^\000-\037 *:?[^~\177]+(?<!\.lock)(?<!\/)(?<!\.)$/.test(s.trim()) || 'Invalid git branch',
175
+ validate: (s) => /^(?!.*\/\.)(?!.*\.\.)(?!\/)(?!.*\/\/)(?!.*@{)(?!.*\\)[^\000-\037 *:?[^~\177]+(?<!\.lock)(?<!\/)(?<!\.)$/.test(s.trim()) ||
176
+ 'Invalid git branch',
174
177
  initial: 'main',
175
178
  },
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
+ getCurrVal: async (_fs, paths) => {
180
+ var _a, _b;
181
+ const cwd = (_a = paths.monorepo()) !== null && _a !== void 0 ? _a : paths.package();
182
+ try {
183
+ const remotes = (0, node_child_process_1.execSync)('git remote', { cwd, timeout: 2000 }).toString().split('\n');
184
+ if (remotes.includes('origin')) {
185
+ return (0, node_child_process_1.execSync)("git remote show origin | grep 'HEAD branch' | cut -d' ' -f5", { cwd }).toString();
186
+ }
187
+ }
188
+ catch (_c) { }
189
+ return (_b = (await (0, simple_git_1.default)(cwd).getConfig('init.defaultBranch')).value) !== null && _b !== void 0 ? _b : 'main';
190
+ },
191
+ };
192
+ case 'jsPackageManager':
193
+ return {
194
+ prompt: {
195
+ name,
196
+ type: 'select',
197
+ message: 'JS Package Manager',
198
+ initial: 'yarn',
199
+ choices: [
200
+ { title: 'Yarn', value: 'yarn' },
201
+ { title: 'NPM', value: 'npm' },
202
+ ],
203
+ },
204
+ getCurrVal: async (fs, paths) => {
205
+ return (0, mem_fs_editor_1.create)(fs).exists(paths.package('js/yarn.lock')) ? 'yarn' : 'npm';
179
206
  },
180
207
  };
181
208
  case 'backendDirectory':
@@ -225,17 +252,7 @@ function moduleNameToDef(name) {
225
252
  updatable: false,
226
253
  togglable: false,
227
254
  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
- ],
255
+ filesToReplace: ['extend.php', 'README.md', 'LICENSE.md'],
239
256
  jsonToAugment: {
240
257
  'composer.json': [
241
258
  'name',
@@ -248,6 +265,8 @@ function moduleNameToDef(name) {
248
265
  'autoload.psr-4.${params.packageNamespaceEscapedSlash}\\',
249
266
  'extra.flarum-extension.title',
250
267
  'extra.flarum-extension.category',
268
+ 'minimum-stability',
269
+ 'prefer-stable',
251
270
  ],
252
271
  },
253
272
  needsTemplateParams: [
@@ -287,6 +306,8 @@ function moduleNameToDef(name) {
287
306
  filesToReplace: [
288
307
  { path: 'js/admin.js', moduleDeps: ['js', { module: 'typescript', enabled: false }] },
289
308
  { path: 'js/admin.ts', moduleDeps: ['js', { module: 'typescript', enabled: true }] },
309
+ { path: 'js/src/admin/index.js', doNotUpdate: true, moduleDeps: ['js', { module: 'typescript', enabled: false }] },
310
+ { path: 'js/src/admin/index.ts', doNotUpdate: true, moduleDeps: ['js', { module: 'typescript', enabled: true }] },
290
311
  ],
291
312
  jsonToAugment: {},
292
313
  needsTemplateParams: [],
@@ -307,6 +328,8 @@ function moduleNameToDef(name) {
307
328
  filesToReplace: [
308
329
  { path: 'js/forum.js', moduleDeps: ['js', { module: 'typescript', enabled: false }] },
309
330
  { path: 'js/forum.ts', moduleDeps: ['js', { module: 'typescript', enabled: true }] },
331
+ { path: 'js/src/forum/index.js', doNotUpdate: true, moduleDeps: ['js', { module: 'typescript', enabled: false }] },
332
+ { path: 'js/src/forum/index.ts', doNotUpdate: true, moduleDeps: ['js', { module: 'typescript', enabled: true }] },
310
333
  ],
311
334
  jsonToAugment: {},
312
335
  needsTemplateParams: [],
@@ -331,6 +354,12 @@ function moduleNameToDef(name) {
331
354
  { path: 'js/forum.js', moduleDeps: ['forum', { module: 'typescript', enabled: false }] },
332
355
  { path: 'js/admin.ts', moduleDeps: ['admin', { module: 'typescript', enabled: true }] },
333
356
  { path: 'js/forum.ts', moduleDeps: ['forum', { module: 'typescript', enabled: true }] },
357
+ { path: 'js/src/admin/index.js', doNotUpdate: true, moduleDeps: ['admin', { module: 'typescript', enabled: false }] },
358
+ { path: 'js/src/forum/index.js', doNotUpdate: true, moduleDeps: ['forum', { module: 'typescript', enabled: false }] },
359
+ { path: 'js/src/common/index.js', doNotUpdate: true, moduleDeps: ['jsCommon', { module: 'typescript', enabled: false }] },
360
+ { path: 'js/src/admin/index.ts', doNotUpdate: true, moduleDeps: ['admin', { module: 'typescript', enabled: true }] },
361
+ { path: 'js/src/forum/index.ts', doNotUpdate: true, moduleDeps: ['forum', { module: 'typescript', enabled: true }] },
362
+ { path: 'js/src/common/index.ts', doNotUpdate: true, moduleDeps: ['jsCommon', { module: 'typescript', enabled: true }] },
334
363
  ],
335
364
  jsonToAugment: {
336
365
  'js/package.json': [
@@ -344,7 +373,7 @@ function moduleNameToDef(name) {
344
373
  'scripts.analyze',
345
374
  ],
346
375
  },
347
- needsTemplateParams: ['packageName'],
376
+ needsTemplateParams: ['packageName', 'jsPackageManager'],
348
377
  inferEnabled: async (_fs, paths) => {
349
378
  return (0, node_fs_1.existsSync)(paths.package('js'));
350
379
  },
@@ -363,6 +392,8 @@ function moduleNameToDef(name) {
363
392
  { path: 'js/forum.js', moduleDeps: ['forum', { module: 'typescript', enabled: false }] },
364
393
  { path: 'js/admin.ts', moduleDeps: ['admin', { module: 'typescript', enabled: true }] },
365
394
  { path: 'js/forum.ts', moduleDeps: ['forum', { module: 'typescript', enabled: true }] },
395
+ { path: 'js/src/common/index.js', doNotUpdate: true, moduleDeps: [{ module: 'typescript', enabled: false }] },
396
+ { path: 'js/src/common/index.ts', doNotUpdate: true, moduleDeps: [{ module: 'typescript', enabled: true }] },
366
397
  ],
367
398
  jsonToAugment: {},
368
399
  needsTemplateParams: [],
@@ -373,13 +404,16 @@ function moduleNameToDef(name) {
373
404
  case 'css':
374
405
  return {
375
406
  name,
376
- updatable: false,
407
+ updatable: true,
377
408
  togglable: true,
378
409
  defaultEnabled: true,
379
410
  shortDescription: 'CSS',
380
411
  longDescription: "LESS starter files for Flarum's frontend styling.",
381
412
  dependsOn: [],
382
- filesToReplace: ['less/admin.less', 'less/forum.less'],
413
+ filesToReplace: [
414
+ { path: 'less/admin.less', doNotUpdate: true, moduleDeps: ['admin'] },
415
+ { path: 'less/forum.less', doNotUpdate: true, moduleDeps: ['forum'] },
416
+ ],
383
417
  jsonToAugment: {},
384
418
  needsTemplateParams: [],
385
419
  inferEnabled: async (_fs, paths) => {
@@ -395,7 +429,7 @@ function moduleNameToDef(name) {
395
429
  shortDescription: 'Locale',
396
430
  longDescription: 'Translation starter files.',
397
431
  dependsOn: [],
398
- filesToReplace: ['locale/en.yml'],
432
+ filesToReplace: [{ path: 'locale/en.yml', doNotUpdate: true }],
399
433
  jsonToAugment: {},
400
434
  needsTemplateParams: [],
401
435
  inferEnabled: async (_fs, paths) => {
@@ -411,7 +445,11 @@ function moduleNameToDef(name) {
411
445
  shortDescription: 'Git Configuration',
412
446
  longDescription: 'Git config files (e.g. .gitignore, .gitattributes).',
413
447
  dependsOn: [],
414
- filesToReplace: [{ path: 'gitignore', destPath: '.gitignore' }, { path: 'js/gitignore', moduleDeps: ['js'], destPath: 'js/.gitignore' }, '.gitattributes'],
448
+ filesToReplace: [
449
+ { path: 'gitignore', destPath: '.gitignore' },
450
+ { path: 'js/gitignore', moduleDeps: ['js'], destPath: 'js/.gitignore' },
451
+ '.gitattributes',
452
+ ],
415
453
  jsonToAugment: {},
416
454
  needsTemplateParams: [],
417
455
  };
@@ -425,8 +463,17 @@ function moduleNameToDef(name) {
425
463
  longDescription: 'Automatically run checks via GitHub Actions CI. Free for open source projects.',
426
464
  dependsOn: [],
427
465
  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' },
466
+ {
467
+ path: '.github/workflows/frontend.yml',
468
+ monorepoPath: '.github/workflows/${params.extensionId}-frontend.yml',
469
+ requireMonorepo: false,
470
+ moduleDeps: ['js'],
471
+ },
472
+ {
473
+ path: '.github/workflows/backend.yml',
474
+ monorepoPath: '.github/workflows/${params.extensionId}-backend.yml',
475
+ requireMonorepo: false,
476
+ },
430
477
  ],
431
478
  jsonToAugment: {},
432
479
  needsTemplateParams: ['frontendDirectory', 'backendDirectory', 'mainGitBranch', 'extensionId', 'extensionName'],
@@ -441,14 +488,20 @@ function moduleNameToDef(name) {
441
488
  dependsOn: ['js'],
442
489
  filesToReplace: [],
443
490
  jsonToAugment: {
444
- 'js/package.json': ['prettier', 'devDependencies.prettier', 'devDependencies.@flarum/prettier-config', 'scripts.format', 'scripts.format-check'],
491
+ 'js/package.json': [
492
+ 'prettier',
493
+ 'devDependencies.prettier',
494
+ 'devDependencies.@flarum/prettier-config',
495
+ 'scripts.format',
496
+ 'scripts.format-check',
497
+ ],
445
498
  },
446
499
  needsTemplateParams: [],
447
500
  inferEnabled: async (_fs, paths) => {
448
501
  if (!(0, node_fs_1.existsSync)(paths.package('js/package.json'))) {
449
502
  return false;
450
503
  }
451
- return (0, node_fs_1.readFileSync)('js/package.json').includes('prettier');
504
+ return (0, node_fs_1.readFileSync)(paths.package('js/package.json')).includes('prettier');
452
505
  },
453
506
  };
454
507
  case 'typescript':
@@ -462,10 +515,12 @@ function moduleNameToDef(name) {
462
515
  filesToReplace: ['js/tsconfig.json'],
463
516
  jsonToAugment: {
464
517
  'js/package.json': [
465
- 'prettier',
466
518
  'devDependencies.flarum-tsconfig',
467
519
  'devDependencies.typescript',
468
520
  'devDependencies.typescript-coverage-report',
521
+ 'scripts.clean-typings',
522
+ 'scripts.build-typings',
523
+ 'scripts.post-build-typings',
469
524
  'scripts.check-typings',
470
525
  'scripts.check-typings-coverage',
471
526
  ],
@@ -544,9 +599,7 @@ function moduleNameToDef(name) {
544
599
  defaultEnabled: true,
545
600
  shortDescription: 'StyleCI config file',
546
601
  dependsOn: [],
547
- filesToReplace: [
548
- { path: '.styleci.yml', monorepoPath: '.styleci.yml' },
549
- ],
602
+ filesToReplace: [{ path: '.styleci.yml', monorepoPath: '.styleci.yml', requireMonorepo: false }],
550
603
  jsonToAugment: {},
551
604
  needsTemplateParams: [],
552
605
  };
@@ -577,9 +630,12 @@ function genExtScaffolder() {
577
630
  },
578
631
  };
579
632
  const excludeScaffoldingFunc = (fs, paths) => {
580
- var _a, _b, _c;
633
+ var _a, _b, _c, _d, _e, _f;
581
634
  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 : [];
635
+ return {
636
+ files: (_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 : [],
637
+ configKeys: (_f = (_e = (_d = json === null || json === void 0 ? void 0 : json.extra) === null || _d === void 0 ? void 0 : _d['flarum-cli']) === null || _e === void 0 ? void 0 : _e.excludeScaffoldingConfigKeys) !== null && _f !== void 0 ? _f : {},
638
+ };
583
639
  };
584
640
  const scaffolder = new scaffolder_1.Scaffolder((0, node_path_1.resolve)(__dirname, '../../boilerplate/skeleton/extension'), moduleStatusCache, excludeScaffoldingFunc);
585
641
  for (const name of exports.EXTENSION_MODULES) {
@@ -13,7 +13,7 @@ class BaseJsStep {
13
13
  }
14
14
  async run(fs, paths, io, _providers) {
15
15
  const fsEditor = (0, mem_fs_editor_1.create)(fs);
16
- const frontend = await io.getParam({ name: 'frontend', type: 'text' });
16
+ const frontend = await io.getParam({ name: 'frontend', message: 'Frontend', type: 'text' });
17
17
  let frontends = [frontend];
18
18
  if (frontend === 'common') {
19
19
  frontends = ['admin', 'forum'];
@@ -27,9 +27,7 @@ class BaseJsStep {
27
27
  const currContents = fsEditor.read(match);
28
28
  const imports = await this.getImports(frontend, paths, io);
29
29
  const definition = await this.getDefinition(io);
30
- const newContents = currContents
31
- .replace(INIT_REGEX, `$1\n ${definition}\n`)
32
- .replace(IMPORTS_REGEX, `$1${imports}\n\n$5`);
30
+ const newContents = currContents.replace(INIT_REGEX, `$1\n ${definition}\n`).replace(IMPORTS_REGEX, `$1${imports}\n\n$5`);
33
31
  fsEditor.write(match, newContents);
34
32
  });
35
33
  }
@@ -9,14 +9,14 @@ class GenerateModelDefinition extends base_1.BaseJsStep {
9
9
  this.exposes = [];
10
10
  }
11
11
  async getDefinition(io) {
12
- const className = await io.getParam({ name: 'className', type: 'text' });
13
- let modelType = await io.getParam({ name: 'modelType', type: 'text' });
12
+ const className = await io.getParam({ name: 'className', message: 'Class name', type: 'text' });
13
+ let modelType = await io.getParam({ name: 'modelType', message: 'Model type', type: 'text' });
14
14
  modelType = modelType.includes('-') ? `['${modelType}']` : `.${modelType}`;
15
15
  return `app.store.models${modelType} = ${className};`;
16
16
  }
17
17
  async getImports(frontend, paths, io) {
18
- const className = await io.getParam({ name: 'className', type: 'text' });
19
- const classNamespace = await io.getParam({ name: 'classNamespace', type: 'text' });
18
+ const className = await io.getParam({ name: 'className', message: 'Class name', type: 'text' });
19
+ const classNamespace = await io.getParam({ name: 'classNamespace', message: 'Class namespace', type: 'text' });
20
20
  const importPath = this.importPath(frontend, classNamespace);
21
21
  return `import ${className} from '${importPath}';`;
22
22
  }
@@ -5,7 +5,7 @@ import { DefaultProviders, Step } from 'boilersmith/step-manager';
5
5
  export declare class GitInit implements Step {
6
6
  type: string;
7
7
  composable: boolean;
8
- run(fs: Store, _paths: Paths, _paramProvider: IO, _providers: DefaultProviders): Promise<Store>;
8
+ run(fs: Store, paths: Paths, _paramProvider: IO, _providers: DefaultProviders): Promise<Store>;
9
9
  exposes: never[];
10
10
  getExposed(): Record<string, unknown>;
11
11
  }
@@ -9,8 +9,8 @@ class GitInit {
9
9
  this.composable = false;
10
10
  this.exposes = [];
11
11
  }
12
- async run(fs, _paths, _paramProvider, _providers) {
13
- (0, simple_git_1.default)().init();
12
+ async run(fs, paths, _paramProvider, _providers) {
13
+ (0, simple_git_1.default)(paths.package()).init();
14
14
  return fs;
15
15
  }
16
16
  getExposed() {
@@ -0,0 +1,11 @@
1
+ import { Store } from 'mem-fs';
2
+ import { IO } from 'boilersmith/io';
3
+ import { Paths } from 'boilersmith/paths';
4
+ import { DefaultProviders, Step } from 'boilersmith/step-manager';
5
+ export declare class NpmInstall implements Step {
6
+ type: string;
7
+ composable: boolean;
8
+ run(fs: Store, paths: Paths, _paramProvider: IO, _providers: DefaultProviders): Promise<Store>;
9
+ exposes: never[];
10
+ getExposed(): Record<string, unknown>;
11
+ }