@researchdatabox/redbox-dev-tools 0.0.1-beta.9700 → 0.0.1-beta.9909

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.
package/dist/cli.js CHANGED
@@ -383,6 +383,32 @@ generate
383
383
  process.exit(1);
384
384
  }
385
385
  });
386
+ generate
387
+ .command('migration <description>')
388
+ .description('Generate an app-local data migration in api/migrations/ (runs at lift, before coreBootstrap)')
389
+ .action(async (description) => {
390
+ try {
391
+ const globalOptions = program.opts();
392
+ const paths = (0, paths_1.resolvePaths)(globalOptions);
393
+ const { MigrationGenerator } = require('./generators/migration');
394
+ const generator = new MigrationGenerator({
395
+ description,
396
+ dryRun: globalOptions.dryRun,
397
+ root: paths.root,
398
+ });
399
+ console.log(`\nšŸ› ļø Generating data migration: ${description}...\n`);
400
+ await generator.generate();
401
+ console.log(`\nāœ… Done! Created migration '${generator.migrationName}'.\n`);
402
+ console.log('Next steps:');
403
+ console.log(` 1. Implement up() in ${path.relative(paths.root, generator.migrationPath)} (remove the placeholder throw)`);
404
+ console.log(' 2. Make sure up() is idempotent - it can run more than once');
405
+ console.log(' 3. Test by lifting the app, then verify the Migration table contains the new name\n');
406
+ }
407
+ catch (error) {
408
+ console.error(`\nāŒ Error: ${error.message}\n`);
409
+ process.exit(1);
410
+ }
411
+ });
386
412
  generate
387
413
  .command('form-field <name>')
388
414
  .description('Generate a new form field DSL configuration')
@@ -4,7 +4,7 @@ exports.generateCompletionScript = generateCompletionScript;
4
4
  function getCompletionSpec() {
5
5
  const globalOptions = ['--root', '--core-types-root', '--angular-root', '--dry-run', '-h', '--help', '-V', '--version'];
6
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', 'model'];
7
+ const generateCommands = ['controller', 'service', 'method', 'angular-app', 'angular-service', 'form-component', 'form-field', 'migration', 'model'];
8
8
  const commandOptions = {
9
9
  'migrate-form-config': ['-i', '--input', '-o', '--output'],
10
10
  'check': [],
@@ -20,6 +20,7 @@ function getCompletionSpec() {
20
20
  'generate angular-service': ['--app', '--methods'],
21
21
  'generate form-component': ['--app', '--with-service'],
22
22
  'generate form-field': ['--type'],
23
+ 'generate migration': [],
23
24
  'generate model': ['--identity', '--attrs', '--belongs-to', '--has-many']
24
25
  };
25
26
  const fileValueOptions = ['--root', '--core-types-root', '--angular-root', '--input', '--output', '--file'];
@@ -154,7 +155,7 @@ Register-ArgumentCompleter -Native -CommandName redbox-dev-tools -ScriptBlock {
154
155
  $tokens = $commandAst.CommandElements | ForEach-Object { $_.Extent.Text }
155
156
  $global = @('--root','--core-types-root','--angular-root','--dry-run','-h','--help','-V','--version')
156
157
  $top = @('init','check','migrate-hook-dependencies','generate','g','install-skills','skills','migrate-form-config','completion','help')
157
- $generateSub = @('controller','service','method','angular-app','angular-service','form-component','form-field','model')
158
+ $generateSub = @('controller','service','method','angular-app','angular-service','form-component','form-field','migration','model')
158
159
 
159
160
  if ($tokens.Count -le 2) {
160
161
  @($top + $global) | Where-Object { $_ -like "$wordToComplete*" } | ForEach-Object {
@@ -0,0 +1,15 @@
1
+ import { Generator, GeneratorOptions } from '../utils/generator';
2
+ export interface MigrationGeneratorOptions extends GeneratorOptions {
3
+ description: string;
4
+ /** Override the clock, used by tests for deterministic file names. */
5
+ now?: Date;
6
+ }
7
+ export declare class MigrationGenerator extends Generator {
8
+ private description;
9
+ private now;
10
+ migrationName: string;
11
+ migrationPath: string;
12
+ constructor(options: MigrationGeneratorOptions);
13
+ generate(): Promise<void>;
14
+ private generateMigrationContent;
15
+ }
@@ -0,0 +1,100 @@
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
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.MigrationGenerator = void 0;
37
+ const path = __importStar(require("path"));
38
+ const generator_1 = require("../utils/generator");
39
+ function slugify(description) {
40
+ return description
41
+ .trim()
42
+ .toLowerCase()
43
+ .replace(/[^a-z0-9]+/g, '-')
44
+ .replace(/^-+|-+$/g, '');
45
+ }
46
+ function formatTimestamp(now) {
47
+ const pad = (value) => String(value).padStart(2, '0');
48
+ return (`${now.getUTCFullYear()}${pad(now.getUTCMonth() + 1)}${pad(now.getUTCDate())}` +
49
+ `T${pad(now.getUTCHours())}${pad(now.getUTCMinutes())}${pad(now.getUTCSeconds())}`);
50
+ }
51
+ class MigrationGenerator extends generator_1.Generator {
52
+ description;
53
+ now;
54
+ migrationName = '';
55
+ migrationPath = '';
56
+ constructor(options) {
57
+ super(options);
58
+ this.description = options.description;
59
+ this.now = options.now ?? new Date();
60
+ }
61
+ async generate() {
62
+ const slug = slugify(this.description);
63
+ if (!slug) {
64
+ throw new Error(`Cannot derive a migration name from description "${this.description}". Use letters, numbers, and hyphens.`);
65
+ }
66
+ this.migrationName = `${formatTimestamp(this.now)}-${slug}`;
67
+ this.migrationPath = path.join(this.root, 'api', 'migrations', `${this.migrationName}.js`);
68
+ this.writeFile(this.migrationPath, this.generateMigrationContent(slug));
69
+ }
70
+ generateMigrationContent(slug) {
71
+ return `'use strict';
72
+
73
+ /**
74
+ * Data migration: ${slug}
75
+ *
76
+ * Runs once during application lift, before coreBootstrap().
77
+ * Migrations MUST be idempotent: if the process crashes after up() completes
78
+ * but before the run is logged, the migration runs again on the next lift.
79
+ * See the Data Migrations wiki page for the full contract.
80
+ */
81
+ module.exports = {
82
+ name: '${this.migrationName}',
83
+
84
+ up: async ({ context: sails } = {}) => {
85
+ // TODO: implement the forward data transformation.
86
+ // Example:
87
+ // await sails.models.appconfig.update({ key: 'oldKey' }, { key: 'newKey' });
88
+ throw new Error('Migration ${this.migrationName} is not implemented yet');
89
+ },
90
+
91
+ // Optional manual rollback - only ever invoked by operator-driven Umzug
92
+ // usage, never by a normal lift. Omit it entirely if a safe reverse is
93
+ // not possible.
94
+ // down: async ({ context: sails } = {}) => {
95
+ // },
96
+ };
97
+ `;
98
+ }
99
+ }
100
+ exports.MigrationGenerator = MigrationGenerator;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@researchdatabox/redbox-dev-tools",
3
- "version": "0.0.1-beta.9700",
3
+ "version": "0.0.1-beta.9909",
4
4
  "description": "ReDBox customisation dev tools - shared configuration, generators, and migration tooling",
5
5
  "type": "commonjs",
6
6
  "main": "index.js",
@@ -44,28 +44,28 @@
44
44
  },
45
45
  "homepage": "https://github.com/redbox-mint/redbox-portal/tree/v4.5.1#readme",
46
46
  "dependencies": {
47
- "@researchdatabox/redbox-core": "0.0.1-beta.9700",
48
- "@researchdatabox/sails-ng-common": "0.0.1-beta.9700",
49
- "@tsconfig/node24": "24.0.1",
47
+ "@researchdatabox/redbox-core": "0.0.1-beta.9909",
48
+ "@researchdatabox/sails-ng-common": "0.0.1-beta.9909",
49
+ "@tsconfig/node24": "24.0.4",
50
50
  "@types/chai": "5.2.3",
51
51
  "@types/lodash": "4.17.24",
52
52
  "@types/mocha": "10.0.10",
53
- "@types/node": "24.10.0",
54
- "axios": "1.15.2",
53
+ "@types/node": "24.12.4",
54
+ "axios": "1.16.1",
55
55
  "chai": "6.2.2",
56
- "commander": "14.0.3",
56
+ "commander": "15.0.0",
57
57
  "handlebars": "4.7.9",
58
- "lodash": "4.18.0",
59
- "mocha": "11.7.4",
60
- "rxjs": "7.8.1",
58
+ "lodash": "4.18.1",
59
+ "mocha": "11.7.6",
60
+ "rxjs": "7.8.2",
61
61
  "ts-node": "10.9.2",
62
62
  "ts-morph": "28.0.0",
63
- "typescript": "5.8.3",
64
- "zod": "3.25.28"
63
+ "typescript": "5.9.3",
64
+ "zod": "3.25.76"
65
65
  },
66
66
  "devDependencies": {
67
67
  "@types/sinon": "21.0.1",
68
- "sinon": "21.1.2"
68
+ "sinon": "22.0.0"
69
69
  },
70
70
  "peerDependenciesMeta": {
71
71
  "@researchdatabox/redbox-core": {
@@ -73,7 +73,7 @@
73
73
  }
74
74
  },
75
75
  "overrides": {
76
- "diff": "8.0.3",
76
+ "diff": "8.0.4",
77
77
  "mocha": {
78
78
  "serialize-javascript": "7.0.5"
79
79
  }