@flarum/cli 2.0.0-beta.9 → 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (137) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +161 -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/flarum/change.d.ts +16 -0
  47. package/lib/commands/flarum/change.js +103 -0
  48. package/lib/commands/flarum/info.d.ts +5 -0
  49. package/lib/commands/flarum/info.js +17 -0
  50. package/lib/commands/infra.d.ts +2 -2
  51. package/lib/commands/infra.js +18 -12
  52. package/lib/commands/init.d.ts +1 -1
  53. package/lib/commands/init.js +4 -2
  54. package/lib/commands/make/backend/api-controller.js +1 -2
  55. package/lib/commands/make/backend/api-serializer-attributes.js +1 -2
  56. package/lib/commands/make/backend/command.js +1 -2
  57. package/lib/commands/make/backend/event-listener.js +1 -2
  58. package/lib/commands/make/backend/handler.js +2 -5
  59. package/lib/commands/make/backend/integration-test.js +2 -4
  60. package/lib/commands/make/backend/migration.js +1 -2
  61. package/lib/commands/make/backend/model.js +1 -2
  62. package/lib/commands/make/backend/policy.js +1 -2
  63. package/lib/commands/make/backend/route.js +1 -2
  64. package/lib/commands/make/backend/service-provider.js +1 -2
  65. package/lib/commands/make/frontend/model.js +2 -5
  66. package/lib/commands/monorepo/create.d.ts +15 -0
  67. package/lib/commands/monorepo/create.js +20 -0
  68. package/lib/commands/monorepo/split.d.ts +15 -0
  69. package/lib/commands/monorepo/split.js +19 -0
  70. package/lib/commands/update/js-imports.js +1 -2
  71. package/lib/help.js +1 -1
  72. package/lib/providers/php-provider.js +2 -2
  73. package/lib/steps/gen-ext-scaffolder.d.ts +2 -2
  74. package/lib/steps/gen-ext-scaffolder.js +185 -51
  75. package/lib/steps/js/base.js +2 -4
  76. package/lib/steps/js/model.js +4 -4
  77. package/lib/steps/misc/composer.js +2 -2
  78. package/lib/steps/misc/git.d.ts +1 -1
  79. package/lib/steps/misc/git.js +2 -2
  80. package/lib/steps/misc/npm.d.ts +11 -0
  81. package/lib/steps/misc/npm.js +19 -0
  82. package/lib/steps/misc/yarn.js +2 -2
  83. package/lib/steps/monorepo/create.d.ts +17 -0
  84. package/lib/steps/monorepo/create.js +186 -0
  85. package/lib/steps/monorepo/split.d.ts +14 -0
  86. package/lib/steps/monorepo/split.js +99 -0
  87. package/lib/steps/stubs/backend/api-controller.d.ts +1 -1
  88. package/lib/steps/stubs/backend/api-controller.js +3 -0
  89. package/lib/steps/stubs/backend/api-serializer.d.ts +1 -1
  90. package/lib/steps/stubs/backend/api-serializer.js +3 -0
  91. package/lib/steps/stubs/backend/command.d.ts +0 -5
  92. package/lib/steps/stubs/backend/command.js +1 -0
  93. package/lib/steps/stubs/backend/event-listener.d.ts +1 -1
  94. package/lib/steps/stubs/backend/event-listener.js +2 -0
  95. package/lib/steps/stubs/backend/handler-command.d.ts +1 -1
  96. package/lib/steps/stubs/backend/handler-command.js +1 -0
  97. package/lib/steps/stubs/backend/handler.d.ts +1 -1
  98. package/lib/steps/stubs/backend/handler.js +4 -0
  99. package/lib/steps/stubs/backend/integration-test.d.ts +1 -1
  100. package/lib/steps/stubs/backend/integration-test.js +2 -0
  101. package/lib/steps/stubs/backend/job.d.ts +1 -1
  102. package/lib/steps/stubs/backend/job.js +1 -0
  103. package/lib/steps/stubs/backend/migration.js +6 -3
  104. package/lib/steps/stubs/backend/model.d.ts +1 -1
  105. package/lib/steps/stubs/backend/model.js +1 -0
  106. package/lib/steps/stubs/backend/policy.d.ts +1 -1
  107. package/lib/steps/stubs/backend/policy.js +2 -0
  108. package/lib/steps/stubs/backend/repository.d.ts +1 -1
  109. package/lib/steps/stubs/backend/repository.js +2 -0
  110. package/lib/steps/stubs/backend/service-provider.d.ts +1 -1
  111. package/lib/steps/stubs/backend/service-provider.js +1 -0
  112. package/lib/steps/stubs/backend/validator.d.ts +1 -1
  113. package/lib/steps/stubs/backend/validator.js +1 -0
  114. package/lib/steps/stubs/flarum-base.js +1 -1
  115. package/lib/steps/stubs/frontend/component.d.ts +0 -5
  116. package/lib/steps/stubs/frontend/component.js +1 -0
  117. package/lib/steps/stubs/frontend/modal.d.ts +0 -5
  118. package/lib/steps/stubs/frontend/modal.js +1 -0
  119. package/lib/steps/stubs/frontend/model.d.ts +0 -5
  120. package/lib/steps/stubs/frontend/model.js +1 -0
  121. package/lib/steps/stubs/js-base.js +8 -5
  122. package/lib/steps/stubs/php-base.js +10 -8
  123. package/lib/steps/update/js-imports.js +8 -2
  124. package/lib/utils/composer.d.ts +1 -0
  125. package/lib/utils/migration.js +3 -1
  126. package/lib/utils/monorepo.d.ts +24 -0
  127. package/lib/utils/monorepo.js +24 -0
  128. package/lib/utils/validation.d.ts +2 -0
  129. package/lib/utils/validation.js +6 -0
  130. package/oclif.manifest.json +1 -1
  131. package/package.json +12 -5
  132. package/php-subsystem/composer.json +9 -9
  133. package/php-subsystem/composer.lock +64 -71
  134. package/php-subsystem/vendor/composer/installed.json +54 -61
  135. package/php-subsystem/vendor/nikic/php-parser/README.md +55 -59
  136. package/php-subsystem/vendor/nikic/php-parser/composer.json +39 -39
  137. package/php-subsystem/vendor/nikic/php-parser/grammar/README.md +17 -20
@@ -4,16 +4,18 @@ exports.LocationType = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  const core_1 = require("@oclif/core");
6
6
  const cli_ux_1 = (0, tslib_1.__importDefault)(require("cli-ux"));
7
- const node_path_1 = require("node:path");
7
+ const path_1 = require("path");
8
8
  const globby_1 = (0, tslib_1.__importDefault)(require("globby"));
9
- const node_child_process_1 = require("node:child_process");
10
- const node_fs_1 = require("node:fs");
9
+ const child_process_1 = require("child_process");
10
+ const fs_1 = require("fs");
11
11
  const io_1 = require("boilersmith/io");
12
12
  const step_manager_1 = require("boilersmith/step-manager");
13
13
  const paths_1 = require("boilersmith/paths");
14
14
  const php_provider_1 = require("./providers/php-provider");
15
15
  const chalk_1 = (0, tslib_1.__importDefault)(require("chalk"));
16
16
  const errors_1 = require("@oclif/errors");
17
+ const monorepo_1 = require("./utils/monorepo");
18
+ const mem_fs_1 = require("mem-fs");
17
19
  var LocationType;
18
20
  (function (LocationType) {
19
21
  LocationType[LocationType["FLARUM_EXTENSION"] = 0] = "FLARUM_EXTENSION";
@@ -23,7 +25,7 @@ var LocationType;
23
25
  class BaseCommand extends core_1.Command {
24
26
  constructor() {
25
27
  super(...arguments);
26
- this.STUB_PATH = (0, node_path_1.resolve)(__dirname, '../boilerplate/stubs/');
28
+ this.STUB_PATH = (0, path_1.resolve)(__dirname, '../boilerplate/stubs/');
27
29
  this.dry = false;
28
30
  this.requireExistingExtension = true;
29
31
  }
@@ -51,10 +53,9 @@ class BaseCommand extends core_1.Command {
51
53
  requestedDir: path,
52
54
  package: extRoot,
53
55
  });
54
- const phpProvider = new php_provider_1.PhpSubsystemProvider((0, node_path_1.resolve)(__dirname, '../php-subsystem/index.php'));
55
- const out = await this.steps(new step_manager_1.StepManager())
56
- .run(paths, this.genIO(), { php: phpProvider }, this.dry);
57
- const errorMessages = out.messages.filter(m => m.type === 'error');
56
+ const phpProvider = new php_provider_1.PhpSubsystemProvider((0, path_1.resolve)(__dirname, '../php-subsystem/index.php'));
57
+ const out = await this.steps(new step_manager_1.StepManager(), extRoot).run(paths, this.genIO(), { php: phpProvider }, this.dry);
58
+ const errorMessages = out.messages.filter((m) => m.type === 'error');
58
59
  this.log('\n\n');
59
60
  if (out.succeeded && errorMessages.length === 0) {
60
61
  this.log(chalk_1.default.bold(chalk_1.default.underline(chalk_1.default.green('Success! The following steps were completed:'))));
@@ -66,7 +67,7 @@ class BaseCommand extends core_1.Command {
66
67
  }
67
68
  this.log(chalk_1.default.bold(chalk_1.default.yellow('The steps that completed were:')));
68
69
  }
69
- else if (out.error === 'EEXIT: 0') {
70
+ else if (out.error.startsWith('EEXIT:')) {
70
71
  this.log(chalk_1.default.bold(chalk_1.default.underline(chalk_1.default.red('Exiting.'))));
71
72
  if (out.stepsRan.length > 0) {
72
73
  this.log(chalk_1.default.bold(chalk_1.default.yellow('Before the exit, the following steps were completed:')));
@@ -86,7 +87,7 @@ class BaseCommand extends core_1.Command {
86
87
  for (const stepName of out.stepsRan)
87
88
  this.log(`- ${chalk_1.default.dim(stepName)}`);
88
89
  this.log('');
89
- const nonErrorMessages = out.messages.filter(m => m.type !== 'error');
90
+ const nonErrorMessages = out.messages.filter((m) => m.type !== 'error');
90
91
  if (nonErrorMessages.length > 0) {
91
92
  this.log('');
92
93
  this.log('The following messages were generated during execution:');
@@ -118,45 +119,53 @@ class BaseCommand extends core_1.Command {
118
119
  return new io_1.PromptsIO({}, [], this.flags['no-interaction'], errors_1.exit);
119
120
  }
120
121
  monorepoPaths(options) {
122
+ var _a, _b;
121
123
  try {
122
- const monorepoConfig = (0, node_fs_1.readFileSync)((0, node_path_1.resolve)(process.cwd(), 'flarum-monorepo.json'));
123
- const contents = JSON.parse(monorepoConfig.toString());
124
+ const monorepoConfig = (0, monorepo_1.getMonorepoConf)((0, mem_fs_1.create)(), new paths_1.NodePaths({ package: process.cwd() }));
124
125
  return [
125
- ...(options.includeCore ? [contents.packages.core] : []),
126
- ...(options.includeExtensions ? contents.packages.extensions : []),
127
- ...(options.includePhpPackages ? contents.packages.composerPackages : []),
128
- ...(options.includeJSPackages ? contents.packages.npmPackages : []),
126
+ ...(options.includeCore && monorepoConfig.packages.core ? [(0, monorepo_1.corePath)(monorepoConfig.packages.core.name)] : []),
127
+ ...(options.includeExtensions ? monorepoConfig.packages.extensions : []).map((ext) => (0, monorepo_1.extensionPath)(ext.name)),
128
+ ...(options.includePhpPackages ? (_a = monorepoConfig.packages.composer) !== null && _a !== void 0 ? _a : [] : []).map((lib) => (0, monorepo_1.composerPath)(lib.name)),
129
+ ...(options.includeJSPackages ? (_b = monorepoConfig.packages.npm) !== null && _b !== void 0 ? _b : [] : []).map((lib) => (0, monorepo_1.npmPath)(lib.name)),
129
130
  ];
130
131
  }
131
- catch (_a) {
132
+ catch (_c) {
132
133
  this.error('Could not run monorepo command: `flarum-monorepo.json` file is missing or invalid.');
133
134
  }
134
135
  }
136
+ isFlarumMonorepo(path) {
137
+ return (0, fs_1.existsSync)((0, path_1.resolve)(path, 'flarum-monorepo.json'));
138
+ }
135
139
  isFlarumCore(path) {
136
140
  try {
137
- const composerJsonPath = (0, node_path_1.resolve)(path, 'composer.json');
138
- const val = JSON.parse((0, node_fs_1.readFileSync)(composerJsonPath, 'utf8'));
141
+ const composerJsonPath = (0, path_1.resolve)(path, 'composer.json');
142
+ const val = JSON.parse((0, fs_1.readFileSync)(composerJsonPath, 'utf8'));
139
143
  return val.name === 'flarum/core';
140
144
  }
141
145
  catch (_a) {
142
146
  return false;
143
147
  }
144
148
  }
149
+ jsPackageManager(currDir) {
150
+ if (!(0, fs_1.existsSync)((0, path_1.resolve)(currDir, 'js')))
151
+ return null;
152
+ return (0, fs_1.existsSync)((0, path_1.resolve)(currDir, 'js/yarn.lock')) ? 'yarn' : 'npm';
153
+ }
145
154
  async getFlarumExtensionRoot(currDir) {
146
- let currPath = (0, node_path_1.resolve)(currDir);
155
+ let currPath = (0, path_1.resolve)(currDir);
147
156
  while (currPath !== '/') {
148
- if ((0, node_fs_1.existsSync)((0, node_path_1.resolve)(currPath, 'flarum-monorepo.json'))) {
157
+ if ((0, fs_1.existsSync)((0, path_1.resolve)(currPath, 'flarum-monorepo.json'))) {
149
158
  return { path: currPath, type: LocationType.FLARUM_MONOREPO };
150
159
  }
151
- if ((0, node_fs_1.existsSync)((0, node_path_1.resolve)(currPath, 'composer.json')) && (0, node_fs_1.existsSync)((0, node_path_1.resolve)(currPath, 'extend.php'))) {
160
+ if ((0, fs_1.existsSync)((0, path_1.resolve)(currPath, 'composer.json')) && (0, fs_1.existsSync)((0, path_1.resolve)(currPath, 'extend.php'))) {
152
161
  return { path: currPath, type: LocationType.FLARUM_EXTENSION };
153
162
  }
154
163
  if (this.isFlarumCore(currPath)) {
155
164
  return { path: currPath, type: LocationType.FLARUM_CORE };
156
165
  }
157
- currPath = (0, node_path_1.resolve)(currPath, '..');
166
+ currPath = (0, path_1.resolve)(currPath, '..');
158
167
  }
159
- this.error(`${(0, node_path_1.resolve)(currDir)} is not located in a valid Flarum package!
168
+ this.error(`${(0, path_1.resolve)(currDir)} is not located in a valid Flarum package!
160
169
  - Flarum extensions must contain (at a minimum) 'extend.php' and 'composer.json' files.
161
170
  - Flarum core must contain a 'composer.json' file with the name 'flarum/core'.
162
171
  - Flarum monorepos must have a valid 'flarum-monorepo.json' file`);
@@ -165,14 +174,14 @@ class BaseCommand extends core_1.Command {
165
174
  const verify = await this.genIO().getParam({
166
175
  name: 'verify',
167
176
  type: 'confirm',
168
- message: `Work in Flarum package located at ${(0, node_path_1.resolve)(extRoot)}?`,
177
+ message: `Work in Flarum package located at ${(0, path_1.resolve)(extRoot)}?`,
169
178
  initial: true,
170
179
  });
171
180
  if (!verify)
172
181
  this.exit();
173
182
  }
174
183
  async ensureComposerInstallRan(extRoot) {
175
- if ((0, node_fs_1.existsSync)((0, node_path_1.resolve)(extRoot, 'vendor/flarum/core/composer.json')))
184
+ if ((0, fs_1.existsSync)((0, path_1.resolve)(extRoot, 'vendor/flarum/core/composer.json')))
176
185
  return;
177
186
  this.log("This command requires `composer install` to have been ran in your extension's root directory.");
178
187
  const composer = await this.genIO().getParam({
@@ -183,7 +192,7 @@ class BaseCommand extends core_1.Command {
183
192
  });
184
193
  if (composer) {
185
194
  cli_ux_1.default.action.start('Installing composer packages');
186
- (0, node_child_process_1.execSync)('composer install', { cwd: extRoot });
195
+ (0, child_process_1.execSync)('composer install', { cwd: extRoot });
187
196
  cli_ux_1.default.action.stop();
188
197
  }
189
198
  else {
@@ -197,7 +206,7 @@ class BaseCommand extends core_1.Command {
197
206
  */
198
207
  async confirmOverrideFiles(dir, pattern, confirmationMessage) {
199
208
  const paths = Array.isArray(pattern) ? pattern : [pattern];
200
- const files = await (0, globby_1.default)(paths.map(p => (0, node_path_1.resolve)(dir, p)));
209
+ const files = await (0, globby_1.default)(paths.map((p) => (0, path_1.resolve)(dir, p)));
201
210
  const empty = files.length === 0 || (files.length === 1 && files[0] === '.git');
202
211
  if (empty)
203
212
  return false;
@@ -212,13 +221,17 @@ class BaseCommand extends core_1.Command {
212
221
  return true;
213
222
  }
214
223
  async deleteFiles(dir, pattern) {
215
- const pathsToDelete = await (0, globby_1.default)((0, node_path_1.resolve)(dir, pattern));
216
- pathsToDelete.forEach(node_fs_1.unlinkSync);
224
+ const pathsToDelete = await (0, globby_1.default)((0, path_1.resolve)(dir, pattern));
225
+ pathsToDelete.forEach(fs_1.unlinkSync);
217
226
  }
218
227
  }
219
228
  exports.default = BaseCommand;
220
229
  BaseCommand.flags = {
221
- 'no-interaction': core_1.Flags.boolean({ char: 'n', description: 'Do not ask any interactive questions, assume defaults. When impossible, error.', default: false }),
230
+ 'no-interaction': core_1.Flags.boolean({
231
+ char: 'n',
232
+ description: 'Do not ask any interactive questions, assume defaults. When impossible, error.',
233
+ default: false,
234
+ }),
222
235
  help: core_1.Flags.help({ char: 'h' }),
223
236
  };
224
237
  BaseCommand.args = [
@@ -1,6 +1,11 @@
1
- import { PromptObject } from 'prompts';
1
+ import { PromptObject, PromptType } from 'prompts';
2
+ declare type BooleanPromptType = PromptType & ('confirm' | 'toggle');
3
+ declare type StringPromptType = PromptType & ('text' | 'password' | 'invisible' | 'autocomplete');
4
+ declare type DatePromptType = PromptType & 'date';
5
+ declare type ListPromptType = PromptType & 'list';
2
6
  export declare type ParamDef<N extends string = string> = Omit<PromptObject<N>, 'name'> & {
3
7
  name: N;
8
+ message: string;
4
9
  };
5
10
  export declare type Message = {
6
11
  type: 'info' | 'warning' | 'error';
@@ -11,7 +16,19 @@ export interface IO {
11
16
  /**
12
17
  * Prompt the user for some input data.
13
18
  */
14
- getParam<T>(param: ParamDef): Promise<T>;
19
+ getParam(param: ParamDef & {
20
+ type: BooleanPromptType;
21
+ }, noCache?: boolean): Promise<boolean>;
22
+ getParam(param: ParamDef & {
23
+ type: StringPromptType;
24
+ }, noCache?: boolean): Promise<string>;
25
+ getParam(param: ParamDef & {
26
+ type: DatePromptType;
27
+ }, noCache?: boolean): Promise<Date>;
28
+ getParam(param: ParamDef & {
29
+ type: ListPromptType;
30
+ }, noCache?: boolean): Promise<string[]>;
31
+ getParam<T>(param: ParamDef, noCache?: boolean): Promise<T>;
15
32
  /**
16
33
  * Check if some data has already been prompted for.
17
34
  */
@@ -32,13 +49,16 @@ export interface IO {
32
49
  declare type OnCancel = () => void;
33
50
  export declare class PromptsIO implements IO {
34
51
  supportsAnsiColor: boolean;
35
- private cache;
36
- private messages;
37
- private noInteraction;
38
- private onCancel?;
39
- private prev?;
52
+ protected cache: Map<string, unknown>;
53
+ protected messages: Message[];
54
+ protected noInteraction: boolean;
55
+ protected onCancel?: OnCancel;
56
+ protected prev?: {
57
+ val: any;
58
+ prompt: ParamDef;
59
+ };
40
60
  constructor(initial?: Record<string, unknown>, messages?: Message[], noInteraction?: boolean, onCancel?: OnCancel);
41
- getParam<T>(paramDef: ParamDef): Promise<T>;
61
+ getParam<T>(paramDef: ParamDef, noCache?: boolean): Promise<T>;
42
62
  hasCached(name: string): boolean;
43
63
  /**
44
64
  * @internal
@@ -15,7 +15,7 @@ class PromptsIO {
15
15
  this.noInteraction = noInteraction;
16
16
  this.onCancel = onCancel;
17
17
  }
18
- async getParam(paramDef) {
18
+ async getParam(paramDef, noCache = false) {
19
19
  var _a, _b, _c;
20
20
  const paramName = paramDef.name;
21
21
  if (this.cache.has(paramName)) {
@@ -42,7 +42,9 @@ class PromptsIO {
42
42
  }));
43
43
  resValue = res[paramName];
44
44
  }
45
- this.cache.set(paramName, resValue);
45
+ if (!noCache) {
46
+ this.cache.set(paramName, resValue);
47
+ }
46
48
  this.prev = {
47
49
  val: resValue,
48
50
  prompt: paramDef,
@@ -3,7 +3,7 @@ export interface Paths {
3
3
  package(...path: string[]): string;
4
4
  requestedDir(...path: string[]): string | null;
5
5
  monorepo(...path: string[]): string | null;
6
- onMonorepoSub(packagePath: string): Paths;
6
+ onMonorepoSub(packagePath: string, monorepoPath?: string): Paths;
7
7
  }
8
8
  declare type InternalPaths = {
9
9
  package: string;
@@ -17,6 +17,6 @@ export declare class NodePaths implements Paths {
17
17
  package(...path: string[]): string;
18
18
  requestedDir(...path: string[]): string | null;
19
19
  monorepo(...path: string[]): string | null;
20
- onMonorepoSub(packagePath: string): NodePaths;
20
+ onMonorepoSub(packagePath: string, monorepoPath?: string): NodePaths;
21
21
  }
22
22
  export {};
@@ -1,29 +1,29 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.NodePaths = void 0;
4
- const node_path_1 = require("node:path");
4
+ const path_1 = require("path");
5
5
  class NodePaths {
6
6
  constructor(paths) {
7
7
  this.paths = paths;
8
8
  }
9
9
  cwd(...path) {
10
- return (0, node_path_1.resolve)(process.cwd(), ...path);
10
+ return (0, path_1.resolve)(process.cwd(), ...path);
11
11
  }
12
12
  package(...path) {
13
- return (0, node_path_1.resolve)(this.paths.package, ...path);
13
+ return (0, path_1.resolve)(this.paths.package, ...path);
14
14
  }
15
15
  requestedDir(...path) {
16
16
  if (!this.paths.requestedDir)
17
17
  return null;
18
- return (0, node_path_1.resolve)(this.paths.requestedDir, ...path);
18
+ return (0, path_1.resolve)(this.paths.requestedDir, ...path);
19
19
  }
20
20
  monorepo(...path) {
21
21
  if (!this.paths.monorepo)
22
22
  return null;
23
- return (0, node_path_1.resolve)(this.paths.monorepo, ...path);
23
+ return (0, path_1.resolve)(this.paths.monorepo, ...path);
24
24
  }
25
- onMonorepoSub(packagePath) {
26
- return new NodePaths(Object.assign(Object.assign({}, this.paths), { monorepo: this.paths.package, package: packagePath }));
25
+ onMonorepoSub(packagePath, monorepoPath) {
26
+ return new NodePaths(Object.assign(Object.assign({}, this.paths), { monorepo: monorepoPath !== null && monorepoPath !== void 0 ? monorepoPath : this.paths.package, package: packagePath }));
27
27
  }
28
28
  }
29
29
  exports.NodePaths = NodePaths;
@@ -8,7 +8,7 @@ const module_1 = require("./module");
8
8
  const template_param_1 = require("./template-param");
9
9
  const cond_format_1 = require("boilersmith/utils/cond-format");
10
10
  const chalk_1 = (0, tslib_1.__importDefault)(require("chalk"));
11
- const node_fs_1 = require("node:fs");
11
+ const fs_1 = require("fs");
12
12
  function auditStepFactory(dry, scaffoldDir, modules, templateParams, excludeScaffoldingFunc, moduleStatusCache) {
13
13
  let modulesEnabled;
14
14
  return {
@@ -17,28 +17,28 @@ function auditStepFactory(dry, scaffoldDir, modules, templateParams, excludeScaf
17
17
  async run(_fs, paths, io, _providers) {
18
18
  const paramVals = await (0, template_param_1.currParamValues)(templateParams, _fs, paths, io);
19
19
  modulesEnabled = await (0, module_1.currModulesEnabled)(modules, _fs, paths, moduleStatusCache);
20
- const actionableModules = modules.filter(m => m.updatable && modulesEnabled[m.name] && (!m.togglable || !m.dependsOn.some(dep => !modulesEnabled[dep])));
21
- io.info((0, cond_format_1.condFormat)(io.supportsAnsiColor, m => chalk_1.default.yellow(chalk_1.default.bold(chalk_1.default.underline(m))), `Auditing infrastructure for ${actionableModules.length} enabled modules:`), true);
20
+ const actionableModules = modules.filter((m) => m.updatable && modulesEnabled[m.name] && (!m.togglable || !m.dependsOn.some((dep) => !modulesEnabled[dep])));
21
+ io.info((0, cond_format_1.condFormat)(io.supportsAnsiColor, (m) => chalk_1.default.yellow(chalk_1.default.bold(chalk_1.default.underline(m))), `Auditing infrastructure for ${actionableModules.length} enabled modules:`), true);
22
22
  for (const m of modules) {
23
23
  if (actionableModules.includes(m)) {
24
- io.info((0, cond_format_1.condFormat)(io.supportsAnsiColor, m => chalk_1.default.dim(chalk_1.default.green(m)), `✓ ${m.name}: ${m.shortDescription}`), true);
24
+ io.info((0, cond_format_1.condFormat)(io.supportsAnsiColor, (m) => chalk_1.default.dim(chalk_1.default.green(m)), `✓ ${m.name}: ${m.shortDescription}`), true);
25
25
  }
26
26
  else if (m.updatable) {
27
- io.info((0, cond_format_1.condFormat)(io.supportsAnsiColor, m => chalk_1.default.dim(chalk_1.default.red(m)), `𐄂 ${m.name}: ${m.shortDescription} (disabled)`), true);
27
+ io.info((0, cond_format_1.condFormat)(io.supportsAnsiColor, (m) => chalk_1.default.dim(chalk_1.default.red(m)), `✕ ${m.name}: ${m.shortDescription} (disabled)`), true);
28
28
  }
29
29
  }
30
30
  for (const m of actionableModules) {
31
31
  const fs = dry ? (0, mem_fs_1.create)() : _fs;
32
- const excludeScaffolding = excludeScaffoldingFunc ? excludeScaffoldingFunc(fs, paths) : [];
32
+ const excludeScaffolding = excludeScaffoldingFunc ? excludeScaffoldingFunc(fs, paths) : { files: [], configKeys: {} };
33
33
  (0, module_1.applyModule)(m, modulesEnabled, paramVals, scaffoldDir, fs, paths, excludeScaffolding, true);
34
34
  if (dry) {
35
35
  const filesWithChanges = fs
36
36
  .all()
37
- .filter(f => f.state && f.state !== 'deleted')
38
- .filter(f => { var _a; return !(0, node_fs_1.existsSync)(f.path) || (0, node_fs_1.readFileSync)(f.path, 'utf8').toString() !== ((_a = f.contents) === null || _a === void 0 ? void 0 : _a.toString()); });
37
+ .filter((f) => f.state && f.state !== 'deleted')
38
+ .filter((f) => { var _a; return !(0, fs_1.existsSync)(f.path) || (0, fs_1.readFileSync)(f.path, 'utf8').toString() !== ((_a = f.contents) === null || _a === void 0 ? void 0 : _a.toString()); });
39
39
  if (filesWithChanges.length > 0) {
40
40
  io.error(`Module ${m.name} has ${filesWithChanges.length} changed files: ${filesWithChanges
41
- .map(f => f.path.replace(paths.package() + '/', ''))
41
+ .map((f) => f.path.replace(paths.package() + '/', ''))
42
42
  .join(', ')}`, false);
43
43
  }
44
44
  }
@@ -52,9 +52,9 @@ function auditStepFactory(dry, scaffoldDir, modules, templateParams, excludeScaf
52
52
  }
53
53
  return _fs;
54
54
  },
55
- exposes: modules.map(m => `modules.${m.name}`),
55
+ exposes: modules.map((m) => `modules.${m.name}`),
56
56
  getExposed(_paths, _paramProvider) {
57
- return (0, rename_keys_1.renameKeys)(modulesEnabled, k => `modules.${k}`);
57
+ return (0, rename_keys_1.renameKeys)(modulesEnabled, (k) => `modules.${k}`);
58
58
  },
59
59
  };
60
60
  }
@@ -4,7 +4,7 @@ exports.infraStepFactory = void 0;
4
4
  const module_1 = require("./module");
5
5
  const template_param_1 = require("./template-param");
6
6
  function infraStepFactory(scaffoldDir, moduleName, modules, templateParams, excludeScaffoldingFunc, moduleStatusCache) {
7
- const module = modules.find(m => m.name === moduleName);
7
+ const module = modules.find((m) => m.name === moduleName);
8
8
  if (!module) {
9
9
  throw new Error(`Module ${moduleName} not found`);
10
10
  }
@@ -17,7 +17,7 @@ function infraStepFactory(scaffoldDir, moduleName, modules, templateParams, excl
17
17
  if (!module.updatable) {
18
18
  io.error(`${module.name} is not updatable.`, true);
19
19
  }
20
- const excludeScaffolding = excludeScaffoldingFunc ? excludeScaffoldingFunc(fs, paths) : [];
20
+ const excludeScaffolding = excludeScaffoldingFunc ? excludeScaffoldingFunc(fs, paths) : { files: [], configKeys: {} };
21
21
  const initializing = !modulesEnabled[module.name];
22
22
  (0, module_1.applyModule)(module, Object.assign(Object.assign({}, modulesEnabled), { [module.name]: true }), paramVals, scaffoldDir, fs, paths, excludeScaffolding, initializing);
23
23
  if (moduleStatusCache) {
@@ -12,22 +12,22 @@ function initStepFactory(scaffoldDir, modules, templateParams, excludeScaffoldin
12
12
  async run(fs, paths, io, _providers) {
13
13
  const paramVals = await (0, template_param_1.promptParamValues)(templateParams, paths, io);
14
14
  modulesEnabled = await (0, module_1.promptModulesEnabled)(modules, io);
15
- const excludeScaffolding = excludeScaffoldingFunc ? excludeScaffoldingFunc(fs, paths) : [];
15
+ const excludeScaffolding = excludeScaffoldingFunc ? excludeScaffoldingFunc(fs, paths) : { files: [], configKeys: {} };
16
16
  for (const m of modules) {
17
- if (modulesEnabled[m.name] && (!m.togglable || !m.dependsOn.some(dep => !modulesEnabled[dep]))) {
17
+ if (modulesEnabled[m.name] && (!m.togglable || !m.dependsOn.some((dep) => !modulesEnabled[dep]))) {
18
18
  (0, module_1.applyModule)(m, modulesEnabled, paramVals, scaffoldDir, fs, paths, excludeScaffolding, true);
19
19
  }
20
20
  }
21
21
  if (moduleStatusCache) {
22
- modules.forEach(m => {
22
+ modules.forEach((m) => {
23
23
  (0, module_1.setModuleValue)(m, modulesEnabled[m.name], fs, paths, moduleStatusCache);
24
24
  });
25
25
  }
26
26
  return fs;
27
27
  },
28
- exposes: modules.map(m => `modules.${m.name}`),
28
+ exposes: modules.map((m) => `modules.${m.name}`),
29
29
  getExposed(_paths, _paramProvider) {
30
- return (0, rename_keys_1.renameKeys)(modulesEnabled, k => `modules.${k}`);
30
+ return (0, rename_keys_1.renameKeys)(modulesEnabled, (k) => `modules.${k}`);
31
31
  },
32
32
  };
33
33
  }
@@ -1,7 +1,8 @@
1
1
  import { Store } from 'mem-fs';
2
2
  import { IO } from 'boilersmith/io';
3
3
  import { Paths } from 'boilersmith/paths';
4
- interface FileOwnership {
4
+ import { ExcludeScaffoldingFunc } from './scaffolder';
5
+ declare type FileOwnershipCommon<N extends string> = {
5
6
  /**
6
7
  * The path to the file
7
8
  */
@@ -11,15 +12,28 @@ interface FileOwnership {
11
12
  */
12
13
  destPath?: string;
13
14
  /**
14
- * If any of the needed modules aren't enabled, the file won't be updated.
15
+ * Depends on other modules being enabled (or disabled).
15
16
  */
16
- needsOtherModules?: string[];
17
+ moduleDeps?: (N | {
18
+ module: N;
19
+ enabled: boolean;
20
+ })[];
21
+ /**
22
+ * Only create the file if it doesn't exist; do not update existing files.
23
+ */
24
+ doNotUpdate?: boolean;
25
+ };
26
+ declare type FileOwnership<N extends string> = (FileOwnershipCommon<N> & {
17
27
  /**
18
28
  * If in a monorepo, should the file be placed relative to the monorepo root, and if so, where?
19
29
  * If provided, takes priority over destPath.
20
30
  */
21
- monorepoPath?: string;
22
- }
31
+ monorepoPath: string;
32
+ /**
33
+ * Only place this file if in a monorepo?
34
+ */
35
+ requireMonorepo: boolean;
36
+ }) | FileOwnershipCommon<N>;
23
37
  interface CommonModule<N extends string> {
24
38
  name: N;
25
39
  shortDescription: string;
@@ -31,7 +45,7 @@ interface CommonModule<N extends string> {
31
45
  /**
32
46
  * A list of scaffolding files managed by this module.
33
47
  */
34
- filesToReplace: (string | FileOwnership)[];
48
+ filesToReplace: (string | FileOwnership<N>)[];
35
49
  /**
36
50
  * A map of names of JSON files to keys which should be deep-merged from the scaffolding.
37
51
  */
@@ -59,7 +73,13 @@ interface TogglableModule<N extends string> extends CommonModule<N> {
59
73
  /**
60
74
  * Can only be enabled if these other modules are enabled.
61
75
  */
62
- dependsOn: string[];
76
+ dependsOn: N[];
77
+ /**
78
+ * On an existing installation, if no information about whether this
79
+ * module is enabled or disabled is cached, infer whether it's enabled
80
+ * based on the current installation's state.
81
+ */
82
+ inferEnabled?: (fs: Store, paths: Paths) => Promise<boolean | undefined>;
63
83
  }
64
84
  export declare type Module<N extends string = string> = UntoggleableModule<N> | TogglableModule<N>;
65
85
  export declare type ModuleStatusCache<N extends string> = {
@@ -69,5 +89,5 @@ export declare type ModuleStatusCache<N extends string> = {
69
89
  export declare function promptModulesEnabled<N extends string>(modules: Module<N>[], io: IO): Promise<Record<N, boolean>>;
70
90
  export declare function currModulesEnabled<N extends string>(modules: Module<N>[], fs: Store, paths: Paths, cache?: ModuleStatusCache<N>): Promise<Record<N, boolean>>;
71
91
  export declare function setModuleValue<MN extends string>(module: Module<MN>, enabled: boolean, fs: Store, paths: Paths, cache: ModuleStatusCache<MN>): Promise<void>;
72
- export declare function applyModule<MN extends string, TN extends string>(module: Module<MN>, modulesEnabled: Record<string, boolean>, paramVals: Record<TN, unknown>, scaffoldDir: string, fs: Store, paths: Paths, excludeFiles?: string[], isInitial?: boolean): Promise<Store>;
92
+ export declare function applyModule<MN extends string, TN extends string>(module: Module<MN>, modulesEnabled: Record<string, boolean>, paramVals: Record<TN, unknown>, scaffoldDir: string, fs: Store, paths: Paths, excludeScaffolding?: ReturnType<ExcludeScaffoldingFunc>, isInitial?: boolean): Promise<Store>;
73
93
  export {};
@@ -4,7 +4,7 @@ exports.applyModule = exports.setModuleValue = exports.currModulesEnabled = expo
4
4
  const tslib_1 = require("tslib");
5
5
  const chalk_1 = (0, tslib_1.__importDefault)(require("chalk"));
6
6
  const mem_fs_editor_1 = require("mem-fs-editor");
7
- const node_path_1 = require("node:path");
7
+ const path_1 = require("path");
8
8
  const pick_deep_1 = (0, tslib_1.__importDefault)(require("pick-deep"));
9
9
  const read_tpl_1 = require("boilersmith/utils/read-tpl");
10
10
  const clone_and_fill_1 = require("boilersmith/utils/clone-and-fill");
@@ -19,7 +19,7 @@ async function promptModulesEnabled(modules, io) {
19
19
  message: `Advanced Initialization ${(0, cond_format_1.condFormat)(io.supportsAnsiColor, chalk_1.default.dim, '(fine-tune which features are enabled)')}`,
20
20
  });
21
21
  for (const m of modules) {
22
- const missingDeps = !m.togglable || m.dependsOn.some(dep => !modulesEnabled[dep]);
22
+ const missingDeps = !m.togglable || m.dependsOn.some((dep) => !modulesEnabled[dep]);
23
23
  if (!m.togglable) {
24
24
  modulesEnabled[m.name] = true;
25
25
  }
@@ -43,12 +43,13 @@ async function promptModulesEnabled(modules, io) {
43
43
  }
44
44
  exports.promptModulesEnabled = promptModulesEnabled;
45
45
  async function currModulesEnabled(modules, fs, paths, cache) {
46
+ var _a, _b;
46
47
  const modulesEnabled = {};
47
48
  for (const m of modules) {
48
49
  if (m.togglable) {
49
50
  // eslint-disable-next-line no-await-in-loop
50
- const cacheVal = await (cache === null || cache === void 0 ? void 0 : cache.get(m, fs, paths));
51
- modulesEnabled[m.name] = cacheVal !== null && cacheVal !== void 0 ? cacheVal : m.defaultEnabled;
51
+ const isEnabled = (_a = (await (cache === null || cache === void 0 ? void 0 : cache.get(m, fs, paths)))) !== null && _a !== void 0 ? _a : (await ((_b = m.inferEnabled) === null || _b === void 0 ? void 0 : _b.call(m, fs, paths)));
52
+ modulesEnabled[m.name] = isEnabled !== null && isEnabled !== void 0 ? isEnabled : m.defaultEnabled;
52
53
  }
53
54
  else {
54
55
  modulesEnabled[m.name] = true;
@@ -63,21 +64,23 @@ async function setModuleValue(module, enabled, fs, paths, cache) {
63
64
  }
64
65
  }
65
66
  exports.setModuleValue = setModuleValue;
66
- // eslint-disable-next-line max-params
67
- async function applyModule(module, modulesEnabled, paramVals, scaffoldDir, fs, paths, excludeFiles = [], isInitial = false) {
68
- var _a;
67
+ // eslint-disable-next-line max-params,complexity
68
+ async function applyModule(module, modulesEnabled, paramVals, scaffoldDir, fs, paths,
69
+ // eslint-disable-next-line unicorn/no-object-as-default-parameter
70
+ excludeScaffolding = { files: [], configKeys: {} }, isInitial = false) {
71
+ var _a, _b;
69
72
  const fsEditor = (0, mem_fs_editor_1.create)(fs);
70
73
  // Validate that module can be enabled
71
74
  if (!(modulesEnabled === null || modulesEnabled === void 0 ? void 0 : modulesEnabled[module.name])) {
72
75
  throw new Error(`Could not apply module "${module.name}", because it is not enabled in the provided module statuses.`);
73
76
  }
74
77
  // Validate that dependencies are enabled
75
- const missingDeps = module.togglable ? module.dependsOn.filter(dep => !modulesEnabled[dep]) : [];
78
+ const missingDeps = module.togglable ? module.dependsOn.filter((dep) => !modulesEnabled[dep]) : [];
76
79
  if (missingDeps.length > 0) {
77
80
  throw new Error(`Could not apply module "${module.name}", because the following dependency modules are missing: "${missingDeps.join(', ')}".`);
78
81
  }
79
82
  // Validate that all needed params are present
80
- const missingParams = module.needsTemplateParams.filter(p => !(p in paramVals));
83
+ const missingParams = module.needsTemplateParams.filter((p) => !(p in paramVals));
81
84
  if (missingParams.length > 0) {
82
85
  throw new Error(`Could not apply module "${module.name}", because the following params are missing: "${missingParams.join(', ')}".`);
83
86
  }
@@ -88,24 +91,63 @@ async function applyModule(module, modulesEnabled, paramVals, scaffoldDir, fs, p
88
91
  params: paramVals,
89
92
  modules: modulesEnabled,
90
93
  };
91
- 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}`));
94
+ 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}`));
95
+ // This is necessary because one layer of escaped backslashes is lost on template population.
96
+ tplData.params = Object.fromEntries(Object.entries(paramVals).map(([k, v]) => [k, typeof v === 'string' ? v.replace('\\', '\\\\') : v]));
92
97
  for (const file of module.filesToReplace) {
93
98
  const path = typeof file === 'string' ? file : file.path;
94
- const needsOtherModules = typeof file === 'string' ? [] : (_a = file.needsOtherModules) !== null && _a !== void 0 ? _a : [];
95
- if (!excludeFiles.includes(path) && !needsOtherModules.some(dep => !modulesEnabled[dep])) {
96
- const copyToIfMonorepo = typeof file !== 'string' && file.monorepoPath ? paths.monorepo((0, clone_and_fill_1.cloneAndFill)(file.monorepoPath, tplDataFlat)) : undefined;
97
- const copyTo = copyToIfMonorepo !== null && copyToIfMonorepo !== void 0 ? copyToIfMonorepo : paths.package(typeof file !== 'string' && file.destPath ? (0, clone_and_fill_1.cloneAndFill)(file.destPath, tplDataFlat) : path);
98
- fsEditor.copyTpl((0, node_path_1.resolve)(scaffoldDir, path), copyTo, tplData);
99
+ const moduleDeps = typeof file === 'string' ? [] : (_a = file.moduleDeps) !== null && _a !== void 0 ? _a : [];
100
+ const copyToIfMonorepo = typeof file !== 'string' && 'monorepoPath' in file && file.monorepoPath
101
+ ? paths.monorepo((0, clone_and_fill_1.cloneAndFill)(file.monorepoPath, tplDataFlat))
102
+ : undefined;
103
+ const copyTo = copyToIfMonorepo !== null && copyToIfMonorepo !== void 0 ? copyToIfMonorepo : paths.package(typeof file !== 'string' && file.destPath ? (0, clone_and_fill_1.cloneAndFill)(file.destPath, tplDataFlat) : path);
104
+ if (typeof file !== 'string' && file.doNotUpdate && fsEditor.exists(copyTo)) {
105
+ continue;
99
106
  }
107
+ if (typeof file !== 'string' && 'requireMonorepo' in file && file.requireMonorepo && paths.monorepo() === null) {
108
+ continue;
109
+ }
110
+ if (excludeScaffolding.files.includes(path) ||
111
+ moduleDeps.some((dep) => {
112
+ const depName = typeof dep === 'string' ? dep : dep.module;
113
+ const enabled = modulesEnabled[depName];
114
+ return typeof dep === 'string' || dep.enabled ? !enabled : enabled;
115
+ })) {
116
+ continue;
117
+ }
118
+ let source = (0, read_tpl_1.readTpl)((0, path_1.resolve)(scaffoldDir, path), tplData);
119
+ if (fsEditor.exists(copyTo)) {
120
+ source = applyCustomizations(source, fsEditor.read(copyTo));
121
+ }
122
+ fsEditor.write(copyTo, source);
100
123
  }
101
124
  const jsonPaths = (0, clone_and_fill_1.cloneAndFill)(module.jsonToAugment, tplDataFlat);
102
125
  for (const jsonPath of Object.keys(jsonPaths)) {
103
- const scaffoldContents = (0, read_tpl_1.readTpl)((0, node_path_1.resolve)(scaffoldDir, jsonPath), tplData);
126
+ const scaffoldContents = (0, read_tpl_1.readTpl)((0, path_1.resolve)(scaffoldDir, jsonPath), tplData);
104
127
  const scaffoldContentsJson = JSON.parse(scaffoldContents);
105
- const fieldsToAugment = jsonPaths[jsonPath];
128
+ const excludeKeys = (0, clone_and_fill_1.cloneAndFill)((_b = excludeScaffolding.configKeys[jsonPath]) !== null && _b !== void 0 ? _b : [], tplDataFlat);
129
+ const fieldsToAugment = jsonPaths[jsonPath].filter((key) => !excludeKeys.includes(key));
106
130
  const relevant = (0, pick_deep_1.default)(scaffoldContentsJson, fieldsToAugment);
107
131
  fsEditor.extendJSON(paths.package(jsonPath), relevant, undefined, 4);
108
132
  }
109
133
  return fs;
110
134
  }
111
135
  exports.applyModule = applyModule;
136
+ function applyCustomizations(source, curr) {
137
+ const commentStructures = [
138
+ ['//', '\n'],
139
+ ['/*', ' */'],
140
+ ['<!--', '-->'],
141
+ ['#', '\n'],
142
+ ];
143
+ commentStructures.forEach((x) => x);
144
+ return commentStructures.reduce((acc, [start, end]) => {
145
+ const CUSTOMIZATION_REGEX = new RegExp(`(${start}\\s*<CUSTOM-(?<id>.*)>\\s*${end})(?<contents>.*)(${start}\\s*</CUSTOM-\\k<id>>\\s*${end})`, 'gs');
146
+ const matches = curr.matchAll(CUSTOMIZATION_REGEX);
147
+ const customizations = Object.fromEntries([...matches]
148
+ .map((m) => m.groups)
149
+ .filter(Boolean)
150
+ .map((g) => [g === null || g === void 0 ? void 0 : g.id, g === null || g === void 0 ? void 0 : g.contents]));
151
+ return acc.replace(CUSTOMIZATION_REGEX, (_m, open, id, _c, close) => { var _a; return `${open}${(_a = customizations[id]) !== null && _a !== void 0 ? _a : ''}${close}`; });
152
+ }, source);
153
+ }