@researchdatabox/redbox-dev-tools 0.0.1-beta.10173

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 (106) hide show
  1. package/README.md +255 -0
  2. package/bin/cli.js +3 -0
  3. package/bin/run-hook-mocha.js +3 -0
  4. package/bin/run-hook-tsc.js +3 -0
  5. package/bin/wrapper-webpack.js +168 -0
  6. package/config/tsconfig.base.json +16 -0
  7. package/dist/bin/run-hook-mocha.d.ts +1 -0
  8. package/dist/bin/run-hook-mocha.js +49 -0
  9. package/dist/bin/run-hook-tsc.d.ts +1 -0
  10. package/dist/bin/run-hook-tsc.js +19 -0
  11. package/dist/cli-parsers.d.ts +9 -0
  12. package/dist/cli-parsers.js +131 -0
  13. package/dist/cli.d.ts +1 -0
  14. package/dist/cli.js +491 -0
  15. package/dist/commands/form-config.d.ts +6 -0
  16. package/dist/commands/form-config.js +404 -0
  17. package/dist/completion/index.d.ts +1 -0
  18. package/dist/completion/index.js +218 -0
  19. package/dist/generators/add-method.d.ts +27 -0
  20. package/dist/generators/add-method.js +235 -0
  21. package/dist/generators/angular-app.d.ts +24 -0
  22. package/dist/generators/angular-app.js +342 -0
  23. package/dist/generators/angular-service.d.ts +21 -0
  24. package/dist/generators/angular-service.js +154 -0
  25. package/dist/generators/controller.d.ts +40 -0
  26. package/dist/generators/controller.js +195 -0
  27. package/dist/generators/form-component.d.ts +46 -0
  28. package/dist/generators/form-component.js +906 -0
  29. package/dist/generators/form-field.d.ts +15 -0
  30. package/dist/generators/form-field.js +160 -0
  31. package/dist/generators/migration.d.ts +15 -0
  32. package/dist/generators/migration.js +100 -0
  33. package/dist/generators/model.d.ts +42 -0
  34. package/dist/generators/model.js +206 -0
  35. package/dist/generators/service.d.ts +16 -0
  36. package/dist/generators/service.js +111 -0
  37. package/dist/runtime-resolver.d.ts +3 -0
  38. package/dist/runtime-resolver.js +27 -0
  39. package/dist/templates/hook-archetype.d.ts +12 -0
  40. package/dist/templates/hook-archetype.js +186 -0
  41. package/dist/testing.d.ts +7 -0
  42. package/dist/testing.js +53 -0
  43. package/dist/utils/config-helper.d.ts +71 -0
  44. package/dist/utils/config-helper.js +574 -0
  45. package/dist/utils/generator.d.ts +10 -0
  46. package/dist/utils/generator.js +68 -0
  47. package/dist/utils/hook-tsconfig.d.ts +9 -0
  48. package/dist/utils/hook-tsconfig.js +104 -0
  49. package/dist/utils/paths.d.ts +10 -0
  50. package/dist/utils/paths.js +60 -0
  51. package/index.js +4 -0
  52. package/package.json +85 -0
  53. package/runtime-resolver.d.ts +1 -0
  54. package/runtime-resolver.js +3 -0
  55. package/skills/redbox-angular-apps/SKILL.md +42 -0
  56. package/skills/redbox-angular-services/SKILL.md +29 -0
  57. package/skills/redbox-controllers/SKILL.md +65 -0
  58. package/skills/redbox-feature-design-planner/SKILL.md +169 -0
  59. package/skills/redbox-feature-implementation-review/SKILL.md +117 -0
  60. package/skills/redbox-form-components/SKILL.md +114 -0
  61. package/skills/redbox-form-config/SKILL.md +34 -0
  62. package/skills/redbox-hook-development/SKILL.md +66 -0
  63. package/skills/redbox-services/SKILL.md +54 -0
  64. package/skills/redbox-test-verification/SKILL.md +38 -0
  65. package/skills/redbox-testing/SKILL.md +64 -0
  66. package/skills/redbox-web-verification/SKILL.md +71 -0
  67. package/skills/redbox-web-verification/redbox-angular-apps/SKILL.md +48 -0
  68. package/skills/redbox-web-verification/redbox-angular-services/SKILL.md +30 -0
  69. package/skills/redbox-web-verification/redbox-controllers/SKILL.md +56 -0
  70. package/skills/redbox-web-verification/redbox-form-config/SKILL.md +29 -0
  71. package/skills/redbox-web-verification/redbox-hook-development/SKILL.md +61 -0
  72. package/skills/redbox-web-verification/redbox-services/SKILL.md +45 -0
  73. package/skills/redbox-web-verification/redbox-testing/SKILL.md +53 -0
  74. package/skills/redbox-web-verification/redbox-web-verification/SKILL.md +47 -0
  75. package/templates/hook-archetype/standard/.gitignore.hbs +4 -0
  76. package/templates/hook-archetype/standard/.npmignore.hbs +3 -0
  77. package/templates/hook-archetype/standard/.npmrc.hbs +6 -0
  78. package/templates/hook-archetype/standard/.nvmrc.hbs +1 -0
  79. package/templates/hook-archetype/standard/AGENTS.md.hbs +34 -0
  80. package/templates/hook-archetype/standard/Dockerfile.hbs +28 -0
  81. package/templates/hook-archetype/standard/README.md.hbs +39 -0
  82. package/templates/hook-archetype/standard/assets/fonts/.gitkeep +1 -0
  83. package/templates/hook-archetype/standard/language-defaults/.gitkeep +1 -0
  84. package/templates/hook-archetype/standard/package.json.hbs +40 -0
  85. package/templates/hook-archetype/standard/src/api/controllers/ExampleController.ts.hbs +21 -0
  86. package/templates/hook-archetype/standard/src/api/controllers/index.ts.hbs +23 -0
  87. package/templates/hook-archetype/standard/src/api/services/ExampleService.ts.hbs +22 -0
  88. package/templates/hook-archetype/standard/src/api/services/index.ts.hbs +23 -0
  89. package/templates/hook-archetype/standard/src/config/brandingConfigurationDefaults.ts.hbs +9 -0
  90. package/templates/hook-archetype/standard/src/config/reusableFormDefinitions.ts.hbs +6 -0
  91. package/templates/hook-archetype/standard/src/form-config/default-1.0-draft.ts.hbs +20 -0
  92. package/templates/hook-archetype/standard/src/form-config/index.ts.hbs +8 -0
  93. package/templates/hook-archetype/standard/src/index.ts.hbs +55 -0
  94. package/templates/hook-archetype/standard/support/bootstrap-data/.gitkeep +1 -0
  95. package/templates/hook-archetype/standard/support/development/docker-compose.yml.hbs +75 -0
  96. package/templates/hook-archetype/standard/support/integration-testing/docker-compose.mocha.yml.hbs +84 -0
  97. package/templates/hook-archetype/standard/support/integration-testing/run-mocha-hook.sh.hbs +9 -0
  98. package/templates/hook-archetype/standard/test/integration/hook-registration.test.ts.hbs +13 -0
  99. package/templates/hook-archetype/standard/test/support/globals.ts.hbs +40 -0
  100. package/templates/hook-archetype/standard/test/tsconfig.json.hbs +8 -0
  101. package/templates/hook-archetype/standard/test/unit/.mocharc.cjs.hbs +9 -0
  102. package/templates/hook-archetype/standard/test/unit/index.test.ts.hbs +40 -0
  103. package/templates/hook-archetype/standard/tsconfig.json.hbs +15 -0
  104. package/templates/hook-archetype/standard/views/.gitkeep +1 -0
  105. package/testing.d.ts +1 -0
  106. package/testing.js +3 -0
@@ -0,0 +1,404 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.registerMigrateFormConfigCommand = registerMigrateFormConfigCommand;
40
+ exports.registerMigrateDataClassificationCommand = registerMigrateDataClassificationCommand;
41
+ exports.registerClientFormConfigCommand = registerClientFormConfigCommand;
42
+ exports.registerQuestionTreeDiagramCommand = registerQuestionTreeDiagramCommand;
43
+ exports.registerMigrateFigshareConfigCommand = registerMigrateFigshareConfigCommand;
44
+ const fs_1 = __importDefault(require("fs"));
45
+ const path = __importStar(require("path"));
46
+ const redbox_core_1 = require("@researchdatabox/redbox-core");
47
+ const migrationLogger = {
48
+ silly: (...args) => console.debug(...args),
49
+ verbose: (...args) => console.debug(...args),
50
+ trace: (...args) => console.debug(...args),
51
+ debug: (...args) => console.debug(...args),
52
+ log: (...args) => console.log(...args),
53
+ info: (...args) => console.info(...args),
54
+ warn: (...args) => console.warn(...args),
55
+ error: (...args) => console.error(...args),
56
+ crit: (...args) => console.error(...args),
57
+ fatal: (...args) => console.error(...args),
58
+ silent: () => undefined,
59
+ blank: () => undefined,
60
+ };
61
+ function registerMigrateFormConfigCommand(program) {
62
+ program
63
+ .command('migrate-form-config')
64
+ .description('Migrate a legacy v4 JS form config file to the v5 TS form framework format')
65
+ .requiredOption('-i, --input <path>', 'Path to the legacy v4 form config JS file')
66
+ .requiredOption('-o, --output <path>', 'Path to write the migrated v5 TypeScript config file')
67
+ .option('--format <name>', "The output format, either 'esm' or 'cjs'")
68
+ .action(async (options) => {
69
+ try {
70
+ const globalOptions = program.opts();
71
+ const inputPath = path.resolve(options.input);
72
+ const outputPath = path.resolve(options.output);
73
+ const outputFormat = options.format || "esm";
74
+ console.log(`\n🛠️ Migrating form config to ${outputFormat} format: ${inputPath} -> ${outputPath}\n`);
75
+ const migrateVisitor = new redbox_core_1.MigrationV4ToV5FormConfigVisitor(migrationLogger);
76
+ const migrated = await (0, redbox_core_1.migrateFormConfigFile)(migrateVisitor, inputPath, outputFormat);
77
+ if (globalOptions.dryRun) {
78
+ console.log('[dry-run] Migration completed; no file written.');
79
+ }
80
+ else {
81
+ fs_1.default.mkdirSync(path.dirname(outputPath), { recursive: true });
82
+ fs_1.default.writeFileSync(outputPath, migrated.tsContent, 'utf8');
83
+ console.log(`✅ Wrote migrated form config: ${outputPath}`);
84
+ }
85
+ await (0, redbox_core_1.migrateFormConfigVerify)(migrated.migrated, migrationLogger);
86
+ console.log('\n✅ Done!\n');
87
+ }
88
+ catch (error) {
89
+ console.error(`\n❌ Error: `, error);
90
+ process.exit(1);
91
+ }
92
+ });
93
+ }
94
+ function registerMigrateDataClassificationCommand(program) {
95
+ program
96
+ .command('migrate-data-classification')
97
+ .description('Migrate a legacy v4 JS data classification definition file to the v5 TS form framework format')
98
+ .requiredOption('-i, --input <path>', 'Path to the legacy v4 JS data classification definition file')
99
+ .requiredOption('-o, --output <path>', 'Path to write the migrated v5 TypeScript question tree config file')
100
+ .option('--format <name>', "The output format, either 'esm' or 'cjs'")
101
+ .action(async (options) => {
102
+ try {
103
+ const globalOptions = program.opts();
104
+ const inputPath = path.resolve(options.input);
105
+ const outputPath = path.resolve(options.output);
106
+ const outputFormat = options.format || 'esm';
107
+ console.log(`\n🛠️ Migrating data classification to question tree to ${outputFormat} format: ${inputPath} -> ${outputPath}\n`);
108
+ const migrateVisitor = new redbox_core_1.MigrationV4ToV5FormConfigVisitor(migrationLogger);
109
+ const migrated = (0, redbox_core_1.migrateDataClassification)(migrateVisitor, inputPath, outputFormat);
110
+ if (globalOptions.dryRun) {
111
+ console.log('[dry-run] Migration completed; no file written.');
112
+ }
113
+ else {
114
+ fs_1.default.mkdirSync(path.dirname(outputPath), { recursive: true });
115
+ fs_1.default.writeFileSync(outputPath, migrated.tsContent, 'utf8');
116
+ console.log(`✅ Wrote migrated question tree config: ${outputPath}`);
117
+ }
118
+ await (0, redbox_core_1.migrateFormConfigVerify)(migrated.formConfig, migrationLogger);
119
+ console.log('\n✅ Done!\n');
120
+ }
121
+ catch (error) {
122
+ console.error(`\n❌ Error: `, error);
123
+ process.exit(1);
124
+ }
125
+ });
126
+ }
127
+ function registerClientFormConfigCommand(program) {
128
+ program
129
+ .command('client-form-config')
130
+ .description('Process a form config to produce the client form config')
131
+ .requiredOption('-i, --input <path>', 'Path to read the server-side form config TypeScript file')
132
+ .requiredOption('-o, --output <path>', 'Path to write the client-side form config TypeScript file')
133
+ .option('--formMode <name>', "The form mode, either 'edit' or 'view'")
134
+ .option('--userRoles <name...>', "The user roles, zero or more of 'Admin', 'Librarians', 'Researcher', 'Guest'")
135
+ .option('-r, --record <path>', "Path to read the data record file")
136
+ .action(async (options) => {
137
+ try {
138
+ const globalOptions = program.opts();
139
+ const inputPath = path.resolve(options.input);
140
+ const outputPath = path.resolve(options.output);
141
+ const formMode = options.formMode ?? null;
142
+ const userRoles = options.userRoles ?? null;
143
+ const record = options.record ? require(path.resolve(options.record)) : null;
144
+ console.log(`\n🛠️ Building client form config from server form config: ${inputPath} -> ${outputPath}\n`);
145
+ const serverFormConfig = require(inputPath).default;
146
+ const clientFormConfig = await (0, redbox_core_1.createClientFormConfig)(serverFormConfig, migrationLogger, formMode, userRoles, undefined, record);
147
+ const tsContent = `import { FormConfigFrame } from '@researchdatabox/sails-ng-common';
148
+ const clientFormConfig: FormConfigFrame = ${JSON.stringify(clientFormConfig, null, 2)};
149
+ export default clientFormConfig;`;
150
+ if (globalOptions.dryRun) {
151
+ console.log('[dry-run] Client form config built from server form config; no file written.');
152
+ }
153
+ else {
154
+ fs_1.default.mkdirSync(path.dirname(outputPath), { recursive: true });
155
+ fs_1.default.writeFileSync(outputPath, tsContent, 'utf8');
156
+ console.log(`✅ Wrote client form config: ${outputPath}`);
157
+ }
158
+ await (0, redbox_core_1.migrateFormConfigVerify)(clientFormConfig, migrationLogger);
159
+ console.log('\n✅ Done!\n');
160
+ }
161
+ catch (error) {
162
+ console.error(`\n❌ Error: `, error);
163
+ process.exit(1);
164
+ }
165
+ });
166
+ }
167
+ function registerQuestionTreeDiagramCommand(program) {
168
+ program
169
+ .command('question-tree-diagram')
170
+ .description('Convert a question tree config to a mermaid diagram text file')
171
+ .requiredOption('-i, --input <path>', 'Path to read the question tree form config TypeScript file')
172
+ .requiredOption('-o, --output <path>', 'Path to write the diagram text file')
173
+ .action(async (options) => {
174
+ try {
175
+ const globalOptions = program.opts();
176
+ const inputPath = path.resolve(options.input);
177
+ const outputPath = path.resolve(options.output);
178
+ console.log(`\n🛠️ Creating diagram from form config: ${inputPath} -> ${outputPath}\n`);
179
+ const componentConfig = require(inputPath);
180
+ const diagram = await (0, redbox_core_1.createQuestionTreeDiagram)(componentConfig, migrationLogger);
181
+ if (globalOptions.dryRun) {
182
+ console.log('[dry-run] Built diagram from form config; no file written.');
183
+ }
184
+ else {
185
+ fs_1.default.mkdirSync(path.dirname(outputPath), { recursive: true });
186
+ fs_1.default.writeFileSync(outputPath, diagram, 'utf8');
187
+ console.log(`✅ Wrote diagram text file: ${outputPath}`);
188
+ }
189
+ }
190
+ catch (error) {
191
+ console.error(`\n❌ Error: `, error);
192
+ process.exit(1);
193
+ }
194
+ });
195
+ }
196
+ function collectLegacyTemplates(value, pathPrefix = '') {
197
+ if (typeof value === 'string') {
198
+ return value.includes('<%') ? [pathPrefix] : [];
199
+ }
200
+ if (Array.isArray(value)) {
201
+ return value.flatMap((entry, index) => collectLegacyTemplates(entry, `${pathPrefix}[${index}]`));
202
+ }
203
+ if (value && typeof value === 'object') {
204
+ return Object.entries(value).flatMap(([key, entry]) => collectLegacyTemplates(entry, pathPrefix ? `${pathPrefix}.${key}` : key));
205
+ }
206
+ return [];
207
+ }
208
+ function loadLegacyModule(modulePath) {
209
+ const resolvedPath = path.resolve(modulePath);
210
+ const loaded = require(resolvedPath);
211
+ if (loaded == null || typeof loaded !== 'object') {
212
+ throw new Error(`Legacy config module '${resolvedPath}' did not export an object`);
213
+ }
214
+ return loaded;
215
+ }
216
+ function pickLegacyExport(moduleExports, exportName) {
217
+ const named = moduleExports[exportName];
218
+ if (named != null && typeof named === 'object') {
219
+ return named;
220
+ }
221
+ return moduleExports;
222
+ }
223
+ function toNumericStatusCodes(value) {
224
+ if (!Array.isArray(value)) {
225
+ return [408, 429, 500, 502, 503, 504];
226
+ }
227
+ return value
228
+ .map((entry) => Number(entry))
229
+ .filter((entry) => Number.isFinite(entry));
230
+ }
231
+ function createMigratedFigsharePublishingConfig(brand, figshareApi, figshareApiEnv = {}, figshareForMapping = {}) {
232
+ const overrideArtifacts = figshareApiEnv.overrideArtifacts ?? {};
233
+ const mapping = {
234
+ ...(figshareApi.mapping ?? {}),
235
+ ...(overrideArtifacts.mapping ?? {})
236
+ };
237
+ const resolvedBaseUrl = String(overrideArtifacts.baseURL ?? figshareApi.baseURL ?? '');
238
+ const resolvedFrontEndUrl = String(overrideArtifacts.frontEndURL ?? figshareApi.frontEndURL ?? '');
239
+ const resolvedToken = String(overrideArtifacts.APIToken ?? figshareApi.APIToken ?? '');
240
+ return {
241
+ enabled: Boolean(resolvedToken && resolvedBaseUrl && resolvedFrontEndUrl),
242
+ connection: {
243
+ baseUrl: resolvedBaseUrl,
244
+ frontEndUrl: resolvedFrontEndUrl,
245
+ token: resolvedToken,
246
+ timeoutMs: 30000,
247
+ operationTimeouts: {
248
+ metadataMs: 30000,
249
+ uploadInitMs: 30000,
250
+ uploadPartMs: 120000,
251
+ publishMs: 60000
252
+ },
253
+ retry: {
254
+ maxAttempts: Number(figshareApi.retry?.maxAttempts ?? 3),
255
+ baseDelayMs: Number(figshareApi.retry?.baseDelayMs ?? 500),
256
+ maxDelayMs: Number(figshareApi.retry?.maxDelayMs ?? 4000),
257
+ retryOnStatusCodes: toNumericStatusCodes(figshareApi.retry?.retryOnStatusCodes),
258
+ retryOnMethods: ['get', 'put', 'delete']
259
+ }
260
+ },
261
+ article: {
262
+ itemType: mapping.figshareItemType ?? 'dataset',
263
+ groupId: mapping.figshareItemGroupId,
264
+ publishMode: mapping.figshareNeedsPublishAfterFileUpload ? 'afterUploadsComplete' : 'immediate',
265
+ republishOnMetadataChange: true,
266
+ republishOnAssetChange: true
267
+ },
268
+ record: {
269
+ articleIdPath: mapping.recordFigArticleId ?? 'metadata.figshare_article_id',
270
+ articleUrlPaths: Array.isArray(mapping.recordFigArticleURL) ? mapping.recordFigArticleURL : [mapping.recordFigArticleURL ?? 'metadata.figshare_article_location'],
271
+ dataLocationsPath: mapping.recordDataLocations ?? 'metadata.dataLocations',
272
+ statusPath: 'metadata.figshareStatus',
273
+ errorPath: 'metadata.figshareError',
274
+ syncStatePath: 'metadata.figshareSyncState',
275
+ allFilesUploadedPath: typeof mapping.recordAllFilesUploaded === 'string' ? mapping.recordAllFilesUploaded : ''
276
+ },
277
+ selection: {
278
+ attachmentMode: mapping.figshareOnlyPublishSelectedAttachmentFiles ? 'selectedOnly' : 'all',
279
+ urlMode: mapping.figshareOnlyPublishSelectedLocationURLs ? 'selectedOnly' : 'all',
280
+ selectedFlagPath: 'selected'
281
+ },
282
+ authors: {
283
+ source: 'defaultRedboxContributors',
284
+ uniqueBy: mapping.recordAuthorUniqueBy ?? 'email',
285
+ externalNameField: mapping.recordAuthorExternalName ?? 'text_full_name',
286
+ maxInlineAuthors: 50,
287
+ contributorPaths: ['metadata.contributor_ci', 'metadata.contributors'],
288
+ lookup: []
289
+ },
290
+ metadata: {
291
+ title: { kind: 'path', path: 'metadata.title' },
292
+ description: { kind: 'path', path: 'metadata.description' },
293
+ keywords: { kind: 'path', path: 'metadata.finalKeywords', defaultValue: [] },
294
+ funding: { kind: 'path', path: 'metadata.funder' },
295
+ license: { source: { kind: 'path', path: mapping.recordLicensePath ?? 'metadata.license' }, matchBy: 'urlContains', required: true },
296
+ categories: { source: { kind: 'path', path: mapping.recordCategoryPath ?? 'metadata.forCodes', defaultValue: [] }, mappingStrategy: 'for2020Mapping' },
297
+ customFields: []
298
+ },
299
+ categories: {
300
+ strategy: 'for2020Mapping',
301
+ mappingTable: ((figshareForMapping.FORMapping ?? []).map((entry) => ({
302
+ sourceCode: String(entry.redboxCode ?? entry.sourceCode ?? ''),
303
+ figshareCategoryId: Number(entry.figshareCategoryId ?? entry.figCode ?? 0)
304
+ }))).filter((entry) => entry.sourceCode !== ''),
305
+ allowUnmapped: false
306
+ },
307
+ assets: {
308
+ enableHostedFiles: true,
309
+ enableLinkFiles: true,
310
+ dedupeStrategy: 'sourceId',
311
+ staging: {
312
+ tempDir: String(figshareApi.attachmentsFigshareTempDir ?? ''),
313
+ cleanupPolicy: 'deleteAfterSuccess',
314
+ diskSpaceThresholdBytes: 1073741824
315
+ }
316
+ },
317
+ embargo: {
318
+ mode: 'recordDriven',
319
+ forceSync: Boolean(mapping.figshareForceEmbargoUpdateAlways),
320
+ accessRights: {
321
+ accessRights: { kind: 'path', path: 'metadata.accessRights' },
322
+ fullEmbargoUntil: { kind: 'path', path: 'metadata.embargoUntil' },
323
+ fileEmbargoUntil: { kind: 'path', path: 'metadata.embargoUntil' },
324
+ reason: { kind: 'path', path: 'metadata.embargoReason' }
325
+ }
326
+ },
327
+ queue: {
328
+ publishAfterUploadDelay: typeof mapping.schedulePublishAfterUploadJob === 'string' ? mapping.schedulePublishAfterUploadJob : 'in 2 minutes',
329
+ uploadedFilesCleanupDelay: typeof mapping.scheduleUploadedFilesCleanupJob === 'string' ? mapping.scheduleUploadedFilesCleanupJob : 'in 5 minutes'
330
+ },
331
+ workflow: {
332
+ transitionRules: [],
333
+ transitionJob: {
334
+ enabled: String(mapping.figshareScheduledTransitionRecordWorkflowFromArticlePropertiesJob?.enabled ?? 'false') === 'true',
335
+ namedQuery: String(mapping.figshareScheduledTransitionRecordWorkflowFromArticlePropertiesJob?.namedQuery ?? ''),
336
+ targetStep: String(mapping.figshareScheduledTransitionRecordWorkflowFromArticlePropertiesJob?.targetStep ?? ''),
337
+ paramMap: mapping.figshareScheduledTransitionRecordWorkflowFromArticlePropertiesJob?.paramMap ?? {},
338
+ figshareTargetFieldKey: String(mapping.figshareScheduledTransitionRecordWorkflowFromArticlePropertiesJob?.figshareTargetFieldKey ?? ''),
339
+ figshareTargetFieldValue: String(mapping.figshareScheduledTransitionRecordWorkflowFromArticlePropertiesJob?.figshareTargetFieldValue ?? ''),
340
+ username: String(mapping.figshareScheduledTransitionRecordWorkflowFromArticlePropertiesJob?.username ?? ''),
341
+ userType: String(mapping.figshareScheduledTransitionRecordWorkflowFromArticlePropertiesJob?.userType ?? '')
342
+ }
343
+ },
344
+ testing: {
345
+ mode: figshareApi.testMode ? 'fixture' : 'live'
346
+ },
347
+ writeBack: {
348
+ articleId: 'metadata.figshare_article_id',
349
+ articleUrls: ['metadata.figshare_article_location'],
350
+ extraFields: []
351
+ },
352
+ migrationReport: {
353
+ brand,
354
+ unsupportedLegacyTemplates: collectLegacyTemplates(mapping)
355
+ }
356
+ };
357
+ }
358
+ function registerMigrateFigshareConfigCommand(program) {
359
+ program
360
+ .command('migrate-figshare-config')
361
+ .description('Migrate legacy Figshare config into figsharePublishing AppConfig JSON files')
362
+ .requiredOption('--figshare-api <path>', 'Path to the legacy figshareAPI config module')
363
+ .option('--figshare-api-env <path>', 'Path to the legacy figshareAPIEnv config module')
364
+ .option('--figshare-for-mapping <path>', 'Path to the legacy figshareReDBoxFORMapping config module')
365
+ .requiredOption('-o, --output <path>', 'Directory to write migrated figsharePublishing JSON files')
366
+ .option('-b, --brands <brands...>', 'Brands to generate config for', ['default'])
367
+ .action(async (options) => {
368
+ try {
369
+ const globalOptions = program.opts();
370
+ const outputDir = path.resolve(options.output);
371
+ const brands = options.brands;
372
+ const figshareApi = pickLegacyExport(loadLegacyModule(options.figshareApi), 'figshareAPI');
373
+ const figshareApiEnv = options.figshareApiEnv
374
+ ? pickLegacyExport(loadLegacyModule(options.figshareApiEnv), 'figshareAPIEnv')
375
+ : {};
376
+ const figshareForMapping = options.figshareForMapping
377
+ ? pickLegacyExport(loadLegacyModule(options.figshareForMapping), 'figshareReDBoxFORMapping')
378
+ : {};
379
+ if (!globalOptions.dryRun) {
380
+ fs_1.default.mkdirSync(outputDir, { recursive: true });
381
+ }
382
+ const report = brands.map((brand) => {
383
+ const migrated = createMigratedFigsharePublishingConfig(brand, figshareApi, figshareApiEnv, figshareForMapping);
384
+ const outputPath = path.join(outputDir, `${brand}.figsharePublishing.json`);
385
+ if (!globalOptions.dryRun) {
386
+ fs_1.default.writeFileSync(outputPath, JSON.stringify(migrated, null, 2) + '\n', 'utf8');
387
+ }
388
+ return {
389
+ brand,
390
+ outputPath,
391
+ unsupportedLegacyTemplates: migrated.migrationReport.unsupportedLegacyTemplates
392
+ };
393
+ });
394
+ if (globalOptions.dryRun) {
395
+ console.log('[dry-run] Migration report generated; no files written.');
396
+ }
397
+ console.log(JSON.stringify(report, null, 2));
398
+ }
399
+ catch (error) {
400
+ console.error(`\n❌ Error: `, error);
401
+ process.exit(1);
402
+ }
403
+ });
404
+ }
@@ -0,0 +1 @@
1
+ export declare function generateCompletionScript(shell: string): string;
@@ -0,0 +1,218 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.generateCompletionScript = generateCompletionScript;
4
+ function getCompletionSpec() {
5
+ const globalOptions = ['--root', '--core-types-root', '--angular-root', '--dry-run', '-h', '--help', '-V', '--version'];
6
+ const topLevelCommands = ['init', 'check', 'migrate-hook-dependencies', 'generate', 'g', 'install-skills', 'skills', 'migrate-form-config', 'completion', 'help'];
7
+ const generateCommands = ['controller', 'service', 'method', 'angular-app', 'angular-service', 'form-component', 'form-field', 'migration', 'model'];
8
+ const commandOptions = {
9
+ 'migrate-form-config': ['-i', '--input', '-o', '--output'],
10
+ 'check': [],
11
+ 'completion': [],
12
+ 'init': [],
13
+ 'install-skills': [],
14
+ 'migrate-hook-dependencies': [],
15
+ 'skills': [],
16
+ 'generate controller': ['--actions', '--webservice', '--class-name', '--route', '--routes', '--nav', '--lang', '--auth'],
17
+ 'generate service': ['--methods'],
18
+ 'generate method': ['--file', '--method', '--route', '--http', '--auth', '--nav', '--lang'],
19
+ 'generate angular-app': ['--ejs-view', '--auth'],
20
+ 'generate angular-service': ['--app', '--methods'],
21
+ 'generate form-component': ['--app', '--with-service'],
22
+ 'generate form-field': ['--type'],
23
+ 'generate migration': [],
24
+ 'generate model': ['--identity', '--attrs', '--belongs-to', '--has-many']
25
+ };
26
+ const fileValueOptions = ['--root', '--core-types-root', '--angular-root', '--input', '--output', '--file'];
27
+ return { globalOptions, topLevelCommands, generateCommands, commandOptions, fileValueOptions };
28
+ }
29
+ function generateBashCompletion() {
30
+ const spec = getCompletionSpec();
31
+ const top = spec.topLevelCommands.join(' ');
32
+ const generateSubs = spec.generateCommands.join(' ');
33
+ const globalOpts = spec.globalOptions.join(' ');
34
+ const fileOpts = spec.fileValueOptions.join(' ');
35
+ const commandOptionEntries = Object.entries(spec.commandOptions)
36
+ .map(([key, value]) => `"${key}") opts="${value.join(' ')}";;`)
37
+ .join('\n ');
38
+ return `# bash completion for redbox-dev-tools
39
+ _redbox_dev_tools_completion() {
40
+ local cur prev words cword
41
+ _init_completion || return
42
+
43
+ local top_commands="${top}"
44
+ local generate_subcommands="${generateSubs}"
45
+ local global_opts="${globalOpts}"
46
+ local file_value_opts="${fileOpts}"
47
+
48
+ case "$prev" in
49
+ $file_value_opts)
50
+ COMPREPLY=($(compgen -f -- "$cur"))
51
+ return
52
+ ;;
53
+ esac
54
+
55
+ if [[ $cword -le 1 ]]; then
56
+ COMPREPLY=($(compgen -W "$top_commands $global_opts" -- "$cur"))
57
+ return
58
+ fi
59
+
60
+ if [[ "\${words[1]}" == "generate" || "\${words[1]}" == "g" ]]; then
61
+ if [[ $cword -eq 2 ]]; then
62
+ COMPREPLY=($(compgen -W "$generate_subcommands" -- "$cur"))
63
+ return
64
+ fi
65
+ local key="generate \${words[2]}"
66
+ local opts=""
67
+ case "$key" in
68
+ ${commandOptionEntries}
69
+ *) opts="";;
70
+ esac
71
+ COMPREPLY=($(compgen -W "$opts $global_opts" -- "$cur"))
72
+ return
73
+ fi
74
+
75
+ local opts=""
76
+ case "\${words[1]}" in
77
+ "migrate-form-config") opts="-i --input -o --output" ;;
78
+ "check") opts="" ;;
79
+ "completion") opts="" ;;
80
+ "init") opts="" ;;
81
+ "install-skills") opts="" ;;
82
+ "migrate-hook-dependencies") opts="" ;;
83
+ "skills") opts="" ;;
84
+ *) opts="" ;;
85
+ esac
86
+
87
+ COMPREPLY=($(compgen -W "$opts $global_opts" -- "$cur"))
88
+ }
89
+
90
+ complete -F _redbox_dev_tools_completion redbox-dev-tools
91
+ `;
92
+ }
93
+ function generateZshCompletion() {
94
+ const bashScript = generateBashCompletion();
95
+ return `#compdef redbox-dev-tools
96
+ autoload -U +X bashcompinit && bashcompinit
97
+ ${bashScript}`;
98
+ }
99
+ function generateFishCompletion() {
100
+ const spec = getCompletionSpec();
101
+ const lines = [
102
+ '# fish completion for redbox-dev-tools',
103
+ 'set -l __rbhk_cmd redbox-dev-tools',
104
+ 'complete -c $__rbhk_cmd -f'
105
+ ];
106
+ for (const cmd of spec.topLevelCommands) {
107
+ lines.push(`complete -c $__rbhk_cmd -n "__fish_use_subcommand" -a "${cmd}"`);
108
+ }
109
+ for (const option of spec.globalOptions) {
110
+ if (option.startsWith('--')) {
111
+ const name = option.replace(/^--/, '');
112
+ const requiresValue = ['root', 'core-types-root', 'angular-root'].includes(name);
113
+ lines.push(`complete -c $__rbhk_cmd -l ${name}${requiresValue ? ' -r' : ''}`);
114
+ }
115
+ }
116
+ for (const sub of spec.generateCommands) {
117
+ lines.push(`complete -c $__rbhk_cmd -n "__fish_seen_subcommand_from generate g; and __fish_use_subcommand" -a "${sub}"`);
118
+ }
119
+ lines.push('complete -c $__rbhk_cmd -n "__fish_seen_subcommand_from migrate-form-config" -s i -l input -r');
120
+ lines.push('complete -c $__rbhk_cmd -n "__fish_seen_subcommand_from migrate-form-config" -s o -l output -r');
121
+ lines.push('complete -c $__rbhk_cmd -n "__fish_seen_subcommand_from completion" -a "bash zsh fish powershell pwsh"');
122
+ lines.push('complete -c $__rbhk_cmd -n "__fish_seen_subcommand_from generate; and __fish_seen_subcommand_from controller" -l actions -r');
123
+ lines.push('complete -c $__rbhk_cmd -n "__fish_seen_subcommand_from generate; and __fish_seen_subcommand_from controller" -l webservice');
124
+ lines.push('complete -c $__rbhk_cmd -n "__fish_seen_subcommand_from generate; and __fish_seen_subcommand_from controller" -l class-name -r');
125
+ lines.push('complete -c $__rbhk_cmd -n "__fish_seen_subcommand_from generate; and __fish_seen_subcommand_from controller" -l route -r');
126
+ lines.push('complete -c $__rbhk_cmd -n "__fish_seen_subcommand_from generate; and __fish_seen_subcommand_from controller" -l routes -r');
127
+ lines.push('complete -c $__rbhk_cmd -n "__fish_seen_subcommand_from generate; and __fish_seen_subcommand_from controller" -l nav -r');
128
+ lines.push('complete -c $__rbhk_cmd -n "__fish_seen_subcommand_from generate; and __fish_seen_subcommand_from controller" -l lang -r');
129
+ lines.push('complete -c $__rbhk_cmd -n "__fish_seen_subcommand_from generate; and __fish_seen_subcommand_from controller" -l auth -r');
130
+ lines.push('complete -c $__rbhk_cmd -n "__fish_seen_subcommand_from generate; and __fish_seen_subcommand_from service" -l methods -r');
131
+ lines.push('complete -c $__rbhk_cmd -n "__fish_seen_subcommand_from generate; and __fish_seen_subcommand_from method" -l file -r');
132
+ lines.push('complete -c $__rbhk_cmd -n "__fish_seen_subcommand_from generate; and __fish_seen_subcommand_from method" -l method -r');
133
+ lines.push('complete -c $__rbhk_cmd -n "__fish_seen_subcommand_from generate; and __fish_seen_subcommand_from method" -l route -r');
134
+ lines.push('complete -c $__rbhk_cmd -n "__fish_seen_subcommand_from generate; and __fish_seen_subcommand_from method" -l http -r');
135
+ lines.push('complete -c $__rbhk_cmd -n "__fish_seen_subcommand_from generate; and __fish_seen_subcommand_from method" -l auth -r');
136
+ lines.push('complete -c $__rbhk_cmd -n "__fish_seen_subcommand_from generate; and __fish_seen_subcommand_from method" -l nav -r');
137
+ lines.push('complete -c $__rbhk_cmd -n "__fish_seen_subcommand_from generate; and __fish_seen_subcommand_from method" -l lang -r');
138
+ lines.push('complete -c $__rbhk_cmd -n "__fish_seen_subcommand_from generate; and __fish_seen_subcommand_from angular-app" -l ejs-view -r');
139
+ lines.push('complete -c $__rbhk_cmd -n "__fish_seen_subcommand_from generate; and __fish_seen_subcommand_from angular-app" -l auth -r');
140
+ lines.push('complete -c $__rbhk_cmd -n "__fish_seen_subcommand_from generate; and __fish_seen_subcommand_from angular-service" -l app -r');
141
+ lines.push('complete -c $__rbhk_cmd -n "__fish_seen_subcommand_from generate; and __fish_seen_subcommand_from angular-service" -l methods -r');
142
+ lines.push('complete -c $__rbhk_cmd -n "__fish_seen_subcommand_from generate; and __fish_seen_subcommand_from form-component" -l app -r');
143
+ lines.push('complete -c $__rbhk_cmd -n "__fish_seen_subcommand_from generate; and __fish_seen_subcommand_from form-component" -l with-service');
144
+ lines.push('complete -c $__rbhk_cmd -n "__fish_seen_subcommand_from generate; and __fish_seen_subcommand_from form-field" -l type -r');
145
+ lines.push('complete -c $__rbhk_cmd -n "__fish_seen_subcommand_from generate; and __fish_seen_subcommand_from model" -l identity -r');
146
+ lines.push('complete -c $__rbhk_cmd -n "__fish_seen_subcommand_from generate; and __fish_seen_subcommand_from model" -l attrs -r');
147
+ lines.push('complete -c $__rbhk_cmd -n "__fish_seen_subcommand_from generate; and __fish_seen_subcommand_from model" -l belongs-to -r');
148
+ lines.push('complete -c $__rbhk_cmd -n "__fish_seen_subcommand_from generate; and __fish_seen_subcommand_from model" -l has-many -r');
149
+ return `${lines.join('\n')}\n`;
150
+ }
151
+ function generatePowerShellCompletion() {
152
+ return `# PowerShell completion for redbox-dev-tools
153
+ Register-ArgumentCompleter -Native -CommandName redbox-dev-tools -ScriptBlock {
154
+ param($wordToComplete, $commandAst, $cursorPosition)
155
+ $tokens = $commandAst.CommandElements | ForEach-Object { $_.Extent.Text }
156
+ $global = @('--root','--core-types-root','--angular-root','--dry-run','-h','--help','-V','--version')
157
+ $top = @('init','check','migrate-hook-dependencies','generate','g','install-skills','skills','migrate-form-config','completion','help')
158
+ $generateSub = @('controller','service','method','angular-app','angular-service','form-component','form-field','migration','model')
159
+
160
+ if ($tokens.Count -le 2) {
161
+ @($top + $global) | Where-Object { $_ -like "$wordToComplete*" } | ForEach-Object {
162
+ [System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_)
163
+ }
164
+ return
165
+ }
166
+
167
+ if ($tokens[1] -eq 'generate' -or $tokens[1] -eq 'g') {
168
+ if ($tokens.Count -le 3) {
169
+ $generateSub | Where-Object { $_ -like "$wordToComplete*" } | ForEach-Object {
170
+ [System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_)
171
+ }
172
+ return
173
+ }
174
+ $sub = $tokens[2]
175
+ $opts = switch ($sub) {
176
+ 'controller' { @('--actions','--webservice','--class-name','--route','--routes','--nav','--lang','--auth') }
177
+ 'service' { @('--methods') }
178
+ 'method' { @('--file','--method','--route','--http','--auth','--nav','--lang') }
179
+ 'angular-app' { @('--ejs-view','--auth') }
180
+ 'angular-service' { @('--app','--methods') }
181
+ 'form-component' { @('--app','--with-service') }
182
+ 'form-field' { @('--type') }
183
+ 'model' { @('--identity','--attrs','--belongs-to','--has-many') }
184
+ default { @() }
185
+ }
186
+ @($opts + $global) | Where-Object { $_ -like "$wordToComplete*" } | ForEach-Object {
187
+ [System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterName', $_)
188
+ }
189
+ return
190
+ }
191
+
192
+ $opts = switch ($tokens[1]) {
193
+ 'migrate-form-config' { @('-i','--input','-o','--output') }
194
+ 'completion' { @('bash','zsh','fish','powershell','pwsh') }
195
+ default { @() }
196
+ }
197
+
198
+ @($opts + $global) | Where-Object { $_ -like "$wordToComplete*" } | ForEach-Object {
199
+ [System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterName', $_)
200
+ }
201
+ }
202
+ `;
203
+ }
204
+ function generateCompletionScript(shell) {
205
+ switch (shell) {
206
+ case 'bash':
207
+ return generateBashCompletion();
208
+ case 'zsh':
209
+ return generateZshCompletion();
210
+ case 'fish':
211
+ return generateFishCompletion();
212
+ case 'powershell':
213
+ case 'pwsh':
214
+ return generatePowerShellCompletion();
215
+ default:
216
+ throw new Error(`Unsupported shell '${shell}'. Expected one of: bash, zsh, fish, powershell`);
217
+ }
218
+ }
@@ -0,0 +1,27 @@
1
+ import { Generator, GeneratorOptions } from '../utils/generator';
2
+ import { RedboxPaths } from '../utils/paths';
3
+ import { NavigationMapping, LanguageDefaultEntry } from '../utils/config-helper';
4
+ export interface AddMethodGeneratorOptions extends GeneratorOptions {
5
+ file: string;
6
+ method: string;
7
+ route?: string;
8
+ http?: string;
9
+ auth?: string[];
10
+ navigation?: NavigationMapping[];
11
+ languageDefaults?: LanguageDefaultEntry[];
12
+ paths: RedboxPaths;
13
+ }
14
+ export declare class AddMethodGenerator extends Generator {
15
+ private filePath;
16
+ private method;
17
+ private route?;
18
+ private http?;
19
+ private auth?;
20
+ private navigation;
21
+ private languageDefaults;
22
+ private paths;
23
+ private project;
24
+ constructor(options: AddMethodGeneratorOptions);
25
+ generate(): Promise<void>;
26
+ private updateClass;
27
+ }