@actuate-media/cli 0.4.1 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (92) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/.turbo/turbo-test.log +69 -12
  3. package/CHANGELOG.md +58 -0
  4. package/dist/__tests__/db-init.test.d.ts +2 -0
  5. package/dist/__tests__/db-init.test.d.ts.map +1 -0
  6. package/dist/__tests__/db-init.test.js +127 -0
  7. package/dist/__tests__/db-init.test.js.map +1 -0
  8. package/dist/__tests__/db-sync.test.d.ts +2 -0
  9. package/dist/__tests__/db-sync.test.d.ts.map +1 -0
  10. package/dist/__tests__/db-sync.test.js +136 -0
  11. package/dist/__tests__/db-sync.test.js.map +1 -0
  12. package/dist/__tests__/deployment-diagnostics.test.js.map +1 -1
  13. package/dist/__tests__/init.test.js.map +1 -1
  14. package/dist/__tests__/schema-fragment.test.js +1 -1
  15. package/dist/__tests__/schema-fragment.test.js.map +1 -1
  16. package/dist/__tests__/seed.test.js.map +1 -1
  17. package/dist/commands/db-init.d.ts +19 -2
  18. package/dist/commands/db-init.d.ts.map +1 -1
  19. package/dist/commands/db-init.js +128 -306
  20. package/dist/commands/db-init.js.map +1 -1
  21. package/dist/commands/db-status.d.ts +1 -1
  22. package/dist/commands/db-status.d.ts.map +1 -1
  23. package/dist/commands/db-status.js +33 -33
  24. package/dist/commands/db-status.js.map +1 -1
  25. package/dist/commands/db-sync.d.ts +31 -0
  26. package/dist/commands/db-sync.d.ts.map +1 -0
  27. package/dist/commands/db-sync.js +195 -0
  28. package/dist/commands/db-sync.js.map +1 -0
  29. package/dist/commands/doctor.d.ts +1 -1
  30. package/dist/commands/doctor.d.ts.map +1 -1
  31. package/dist/commands/doctor.js +48 -41
  32. package/dist/commands/doctor.js.map +1 -1
  33. package/dist/commands/export.d.ts +1 -1
  34. package/dist/commands/export.d.ts.map +1 -1
  35. package/dist/commands/export.js +32 -32
  36. package/dist/commands/export.js.map +1 -1
  37. package/dist/commands/generate.d.ts +1 -1
  38. package/dist/commands/generate.d.ts.map +1 -1
  39. package/dist/commands/generate.js +8 -8
  40. package/dist/commands/generate.js.map +1 -1
  41. package/dist/commands/import.d.ts +1 -1
  42. package/dist/commands/import.d.ts.map +1 -1
  43. package/dist/commands/import.js +55 -58
  44. package/dist/commands/import.js.map +1 -1
  45. package/dist/commands/init.d.ts.map +1 -1
  46. package/dist/commands/init.js.map +1 -1
  47. package/dist/commands/migrate.d.ts +1 -1
  48. package/dist/commands/migrate.d.ts.map +1 -1
  49. package/dist/commands/migrate.js +18 -24
  50. package/dist/commands/migrate.js.map +1 -1
  51. package/dist/commands/seed.d.ts +1 -1
  52. package/dist/commands/seed.d.ts.map +1 -1
  53. package/dist/commands/seed.js +156 -157
  54. package/dist/commands/seed.js.map +1 -1
  55. package/dist/commands/update-check.d.ts +1 -1
  56. package/dist/commands/update-check.d.ts.map +1 -1
  57. package/dist/commands/update-check.js +34 -27
  58. package/dist/commands/update-check.js.map +1 -1
  59. package/dist/commands/upgrade.d.ts +1 -1
  60. package/dist/commands/upgrade.d.ts.map +1 -1
  61. package/dist/commands/upgrade.js +46 -34
  62. package/dist/commands/upgrade.js.map +1 -1
  63. package/dist/deployment/diagnostics.d.ts.map +1 -1
  64. package/dist/deployment/diagnostics.js +7 -2
  65. package/dist/deployment/diagnostics.js.map +1 -1
  66. package/dist/index.js +17 -15
  67. package/dist/index.js.map +1 -1
  68. package/dist/utils/logger.d.ts.map +1 -1
  69. package/dist/utils/logger.js +5 -5
  70. package/dist/utils/logger.js.map +1 -1
  71. package/package.json +3 -3
  72. package/src/__tests__/db-init.test.ts +155 -0
  73. package/src/__tests__/db-sync.test.ts +167 -0
  74. package/src/__tests__/deployment-diagnostics.test.ts +68 -60
  75. package/src/__tests__/init.test.ts +17 -17
  76. package/src/__tests__/schema-fragment.test.ts +29 -25
  77. package/src/__tests__/seed.test.ts +25 -25
  78. package/src/commands/db-init.ts +146 -319
  79. package/src/commands/db-status.ts +70 -68
  80. package/src/commands/db-sync.ts +227 -0
  81. package/src/commands/doctor.ts +102 -88
  82. package/src/commands/export.ts +65 -75
  83. package/src/commands/generate.ts +14 -16
  84. package/src/commands/import.ts +125 -140
  85. package/src/commands/init.ts +14 -14
  86. package/src/commands/migrate.ts +29 -35
  87. package/src/commands/seed.ts +294 -300
  88. package/src/commands/update-check.ts +77 -72
  89. package/src/commands/upgrade.ts +100 -85
  90. package/src/deployment/diagnostics.ts +86 -72
  91. package/src/index.ts +32 -30
  92. package/src/utils/logger.ts +10 -10
@@ -1,243 +1,228 @@
1
- import { Command } from "commander";
2
- import { readFile } from "node:fs/promises";
3
- import { existsSync } from "node:fs";
4
- import ora from "ora";
5
- import { logger } from "../utils/logger.js";
1
+ import { Command } from 'commander'
2
+ import { readFile } from 'node:fs/promises'
3
+ import { existsSync } from 'node:fs'
4
+ import ora from 'ora'
5
+ import { logger } from '../utils/logger.js'
6
6
 
7
7
  interface ImportOptions {
8
- source: string;
9
- format?: string;
10
- collection?: string;
11
- dryRun?: boolean;
8
+ source: string
9
+ format?: string
10
+ collection?: string
11
+ dryRun?: boolean
12
12
  }
13
13
 
14
14
  function detectFormat(filePath: string): string {
15
- const ext = filePath.split(".").pop()?.toLowerCase();
16
- if (ext === "json") return "json";
17
- if (ext === "csv") return "csv";
18
- if (ext === "xml" || ext === "wxr") return "wordpress";
19
- return "json";
15
+ const ext = filePath.split('.').pop()?.toLowerCase()
16
+ if (ext === 'json') return 'json'
17
+ if (ext === 'csv') return 'csv'
18
+ if (ext === 'xml' || ext === 'wxr') return 'wordpress'
19
+ return 'json'
20
20
  }
21
21
 
22
22
  function parseCsv(content: string): Record<string, string>[] {
23
- const lines = content.split("\n").filter((line) => line.trim());
24
- if (lines.length < 2) return [];
23
+ const lines = content.split('\n').filter((line) => line.trim())
24
+ if (lines.length < 2) return []
25
25
 
26
26
  const parseRow = (row: string): string[] => {
27
- const values: string[] = [];
28
- let current = "";
29
- let inQuotes = false;
27
+ const values: string[] = []
28
+ let current = ''
29
+ let inQuotes = false
30
30
 
31
31
  for (let i = 0; i < row.length; i++) {
32
- const char = row[i];
32
+ const char = row[i]
33
33
  if (char === '"') {
34
34
  if (inQuotes && row[i + 1] === '"') {
35
- current += '"';
36
- i++;
35
+ current += '"'
36
+ i++
37
37
  } else {
38
- inQuotes = !inQuotes;
38
+ inQuotes = !inQuotes
39
39
  }
40
- } else if (char === "," && !inQuotes) {
41
- values.push(current.trim());
42
- current = "";
40
+ } else if (char === ',' && !inQuotes) {
41
+ values.push(current.trim())
42
+ current = ''
43
43
  } else {
44
- current += char;
44
+ current += char
45
45
  }
46
46
  }
47
- values.push(current.trim());
48
- return values;
49
- };
47
+ values.push(current.trim())
48
+ return values
49
+ }
50
50
 
51
- const headers = parseRow(lines[0]!);
51
+ const headers = parseRow(lines[0]!)
52
52
  return lines.slice(1).map((line) => {
53
- const values = parseRow(line);
54
- const obj: Record<string, string> = {};
53
+ const values = parseRow(line)
54
+ const obj: Record<string, string> = {}
55
55
  headers.forEach((header, i) => {
56
- obj[header] = values[i] ?? "";
57
- });
58
- return obj;
59
- });
56
+ obj[header] = values[i] ?? ''
57
+ })
58
+ return obj
59
+ })
60
60
  }
61
61
 
62
62
  function parseWordPressXml(content: string): any[] {
63
- const items: any[] = [];
64
- const itemRegex = /<item>([\s\S]*?)<\/item>/g;
65
- let match: RegExpExecArray | null;
63
+ const items: any[] = []
64
+ const itemRegex = /<item>([\s\S]*?)<\/item>/g
65
+ let match: RegExpExecArray | null
66
66
 
67
67
  while ((match = itemRegex.exec(content)) !== null) {
68
- const itemXml = match[1];
68
+ const itemXml = match[1]
69
69
 
70
70
  const extract = (tag: string): string => {
71
- const tagRegex = new RegExp(`<${tag}><!\\[CDATA\\[([\\s\\S]*?)\\]\\]><\\/${tag}>|<${tag}>([\\s\\S]*?)<\\/${tag}>`);
72
- const m = tagRegex.exec(itemXml!);
73
- return m?.[1] ?? m?.[2] ?? "";
74
- };
71
+ const tagRegex = new RegExp(
72
+ `<${tag}><!\\[CDATA\\[([\\s\\S]*?)\\]\\]><\\/${tag}>|<${tag}>([\\s\\S]*?)<\\/${tag}>`,
73
+ )
74
+ const m = tagRegex.exec(itemXml!)
75
+ return m?.[1] ?? m?.[2] ?? ''
76
+ }
75
77
 
76
- const title = extract("title");
77
- const body = extract("content:encoded");
78
- const slug = extract("wp:post_name");
79
- const status = extract("wp:status");
80
- const postDate = extract("wp:post_date");
81
- const postType = extract("wp:post_type");
78
+ const title = extract('title')
79
+ const body = extract('content:encoded')
80
+ const slug = extract('wp:post_name')
81
+ const status = extract('wp:status')
82
+ const postDate = extract('wp:post_date')
83
+ const postType = extract('wp:post_type')
82
84
 
83
- if (postType && postType !== "post" && postType !== "page") continue;
85
+ if (postType && postType !== 'post' && postType !== 'page') continue
84
86
 
85
87
  items.push({
86
88
  title,
87
- slug: slug || title.toLowerCase().replace(/[^a-z0-9]+/g, "-"),
89
+ slug: slug || title.toLowerCase().replace(/[^a-z0-9]+/g, '-'),
88
90
  content: body,
89
91
  wpStatus: status,
90
92
  wpPostDate: postDate,
91
- collection: postType === "page" ? "pages" : "posts",
92
- });
93
+ collection: postType === 'page' ? 'pages' : 'posts',
94
+ })
93
95
  }
94
96
 
95
- return items;
97
+ return items
96
98
  }
97
99
 
98
100
  function printPreviewTable(records: any[], collection: string | undefined): void {
99
- console.log("\n Dry-run preview:\n");
100
- console.log(
101
- " " +
102
- "Collection".padEnd(16) +
103
- "Title / Slug".padEnd(40) +
104
- "Status",
105
- );
106
- console.log(" " + "-".repeat(66));
107
-
108
- const shown = records.slice(0, 20);
101
+ console.log('\n Dry-run preview:\n')
102
+ console.log(' ' + 'Collection'.padEnd(16) + 'Title / Slug'.padEnd(40) + 'Status')
103
+ console.log(' ' + '-'.repeat(66))
104
+
105
+ const shown = records.slice(0, 20)
109
106
  for (const rec of shown) {
110
- const col = (rec.collection ?? collection ?? "imported").padEnd(16);
111
- const label = (rec.title ?? rec.slug ?? "(untitled)").slice(0, 38).padEnd(40);
112
- const status = rec.status ?? rec.wpStatus ?? "DRAFT";
113
- console.log(` ${col}${label}${status}`);
107
+ const col = (rec.collection ?? collection ?? 'imported').padEnd(16)
108
+ const label = (rec.title ?? rec.slug ?? '(untitled)').slice(0, 38).padEnd(40)
109
+ const status = rec.status ?? rec.wpStatus ?? 'DRAFT'
110
+ console.log(` ${col}${label}${status}`)
114
111
  }
115
112
 
116
113
  if (records.length > 20) {
117
- console.log(` ... and ${records.length - 20} more`);
114
+ console.log(` ... and ${records.length - 20} more`)
118
115
  }
119
- console.log();
116
+ console.log()
120
117
  }
121
118
 
122
119
  async function runImport(options: ImportOptions): Promise<void> {
123
- const { source, collection, dryRun } = options;
120
+ const { source, collection, dryRun } = options
124
121
 
125
122
  if (!existsSync(source)) {
126
- logger.error(`File not found: ${source}`);
127
- process.exit(1);
123
+ logger.error(`File not found: ${source}`)
124
+ process.exit(1)
128
125
  }
129
126
 
130
- const format = options.format ?? detectFormat(source);
131
- const spinner = ora(`Parsing ${format} file: ${source}…`).start();
127
+ const format = options.format ?? detectFormat(source)
128
+ const spinner = ora(`Parsing ${format} file: ${source}…`).start()
132
129
 
133
130
  try {
134
- const raw = await readFile(source, "utf-8");
135
- let records: any[];
131
+ const raw = await readFile(source, 'utf-8')
132
+ let records: any[]
136
133
 
137
- if (format === "json") {
138
- const parsed = JSON.parse(raw);
134
+ if (format === 'json') {
135
+ const parsed = JSON.parse(raw)
139
136
  if (!Array.isArray(parsed)) {
140
- spinner.fail("JSON file must contain an array of documents.");
141
- process.exit(1);
137
+ spinner.fail('JSON file must contain an array of documents.')
138
+ process.exit(1)
142
139
  }
143
- records = parsed;
144
- } else if (format === "csv") {
140
+ records = parsed
141
+ } else if (format === 'csv') {
145
142
  if (!collection) {
146
- spinner.fail("The --collection option is required for CSV imports.");
147
- process.exit(1);
143
+ spinner.fail('The --collection option is required for CSV imports.')
144
+ process.exit(1)
148
145
  }
149
146
  records = parseCsv(raw).map((row) => ({
150
147
  collection,
151
148
  ...row,
152
- }));
153
- } else if (format === "wordpress") {
154
- records = parseWordPressXml(raw);
149
+ }))
150
+ } else if (format === 'wordpress') {
151
+ records = parseWordPressXml(raw)
155
152
  } else {
156
- spinner.fail(`Unsupported format: ${format}`);
157
- process.exit(1);
153
+ spinner.fail(`Unsupported format: ${format}`)
154
+ process.exit(1)
158
155
  }
159
156
 
160
- spinner.succeed(`Parsed ${records.length} records from ${source}.`);
157
+ spinner.succeed(`Parsed ${records.length} records from ${source}.`)
161
158
 
162
159
  if (records.length === 0) {
163
- logger.warn("No records found in file.");
164
- return;
160
+ logger.warn('No records found in file.')
161
+ return
165
162
  }
166
163
 
167
164
  if (dryRun) {
168
- printPreviewTable(records, collection);
169
- logger.info("Dry run — no data was written.");
170
- return;
165
+ printPreviewTable(records, collection)
166
+ logger.info('Dry run — no data was written.')
167
+ return
171
168
  }
172
169
 
173
- const writeSpinner = ora(`Importing ${records.length} records…`).start();
170
+ const writeSpinner = ora(`Importing ${records.length} records…`).start()
174
171
 
175
- const { getDB } = await import("@actuate-media/cms-core");
176
- const db = getDB<any>();
172
+ const { getDB } = await import('@actuate-media/cms-core')
173
+ const db = getDB<any>()
177
174
 
178
- let adminUser = await db.user.findFirst({ where: { role: "ADMIN" } });
175
+ let adminUser = await db.user.findFirst({ where: { role: 'ADMIN' } })
179
176
  if (!adminUser) {
180
177
  adminUser = await db.user.create({
181
178
  data: {
182
- email: "admin@actuatecms.dev",
183
- name: "Admin",
184
- role: "ADMIN",
179
+ email: 'admin@actuatecms.dev',
180
+ name: 'Admin',
181
+ role: 'ADMIN',
185
182
  isActive: true,
186
183
  isApproved: true,
187
184
  emailVerified: true,
188
185
  },
189
- });
186
+ })
190
187
  }
191
- const userId = adminUser.id;
188
+ const userId = adminUser.id
192
189
 
193
- let imported = 0;
190
+ let imported = 0
194
191
  for (const rec of records) {
195
- const docCollection = rec.collection ?? collection ?? "imported";
196
- const data: any = { ...rec };
197
- delete data.collection;
198
- delete data.wpStatus;
199
- delete data.wpPostDate;
192
+ const docCollection = rec.collection ?? collection ?? 'imported'
193
+ const data: any = { ...rec }
194
+ delete data.collection
195
+ delete data.wpStatus
196
+ delete data.wpPostDate
200
197
 
201
198
  await db.document.create({
202
199
  data: {
203
200
  collection: docCollection,
204
201
  data,
205
- status: "DRAFT",
202
+ status: 'DRAFT',
206
203
  createdById: userId,
207
204
  updatedById: userId,
208
205
  },
209
- });
210
- imported++;
206
+ })
207
+ imported++
211
208
  }
212
209
 
213
- writeSpinner.succeed(`Imported ${imported} documents as DRAFT.`);
210
+ writeSpinner.succeed(`Imported ${imported} documents as DRAFT.`)
214
211
  } catch (err) {
215
- spinner.fail("Import failed.");
216
- const message = err instanceof Error ? err.message : String(err);
217
- logger.error(message);
218
- process.exit(1);
212
+ spinner.fail('Import failed.')
213
+ const message = err instanceof Error ? err.message : String(err)
214
+ logger.error(message)
215
+ process.exit(1)
219
216
  }
220
217
  }
221
218
 
222
219
  export function registerImportCommand(program: Command): void {
223
220
  program
224
- .command("import")
225
- .description("Import content from JSON, CSV, or WordPress XML files")
226
- .requiredOption(
227
- "-s, --source <path>",
228
- "Path to the import file",
229
- )
230
- .option(
231
- "-f, --format <type>",
232
- "File format: json, csv, or wordpress (default: auto-detect)",
233
- )
234
- .option(
235
- "-c, --collection <slug>",
236
- "Target collection (required for csv/wordpress)",
237
- )
238
- .option(
239
- "--dry-run",
240
- "Preview import without writing to the database",
241
- )
242
- .action(runImport);
221
+ .command('import')
222
+ .description('Import content from JSON, CSV, or WordPress XML files')
223
+ .requiredOption('-s, --source <path>', 'Path to the import file')
224
+ .option('-f, --format <type>', 'File format: json, csv, or wordpress (default: auto-detect)')
225
+ .option('-c, --collection <slug>', 'Target collection (required for csv/wordpress)')
226
+ .option('--dry-run', 'Preview import without writing to the database')
227
+ .action(runImport)
243
228
  }
@@ -1,30 +1,30 @@
1
- import { spawn } from 'node:child_process';
2
- import type { Command } from 'commander';
3
- import { logger } from '../utils/logger.js';
1
+ import { spawn } from 'node:child_process'
2
+ import type { Command } from 'commander'
3
+ import { logger } from '../utils/logger.js'
4
4
 
5
5
  export function buildCreateActuateArgs(projectName?: string): string[] {
6
- const args = ['create', 'actuate-cms@latest'];
7
- if (projectName) args.push(projectName);
8
- return args;
6
+ const args = ['create', 'actuate-cms@latest']
7
+ if (projectName) args.push(projectName)
8
+ return args
9
9
  }
10
10
 
11
11
  function npmCommand(): string {
12
- return process.platform === 'win32' ? 'npm.cmd' : 'npm';
12
+ return process.platform === 'win32' ? 'npm.cmd' : 'npm'
13
13
  }
14
14
 
15
15
  async function runInit(projectName?: string): Promise<void> {
16
16
  const child = spawn(npmCommand(), buildCreateActuateArgs(projectName), {
17
17
  stdio: 'inherit',
18
- });
18
+ })
19
19
 
20
20
  const exitCode = await new Promise<number | null>((resolve, reject) => {
21
- child.once('error', reject);
22
- child.once('exit', resolve);
23
- });
21
+ child.once('error', reject)
22
+ child.once('exit', resolve)
23
+ })
24
24
 
25
25
  if (exitCode && exitCode !== 0) {
26
- logger.error(`Project initialization failed with exit code ${exitCode}.`);
27
- process.exit(exitCode);
26
+ logger.error(`Project initialization failed with exit code ${exitCode}.`)
27
+ process.exit(exitCode)
28
28
  }
29
29
  }
30
30
 
@@ -32,5 +32,5 @@ export function registerInitCommand(program: Command): void {
32
32
  program
33
33
  .command('init [project-name]')
34
34
  .description('Scaffold a new Actuate CMS project')
35
- .action(runInit);
35
+ .action(runInit)
36
36
  }
@@ -1,62 +1,56 @@
1
- import { Command } from "commander";
2
- import { execSync, type ExecSyncOptions } from "node:child_process";
3
- import ora from "ora";
4
- import { logger } from "../utils/logger.js";
1
+ import { Command } from 'commander'
2
+ import { execSync, type ExecSyncOptions } from 'node:child_process'
3
+ import ora from 'ora'
4
+ import { logger } from '../utils/logger.js'
5
5
 
6
- const execOpts: ExecSyncOptions = { stdio: "inherit", cwd: process.cwd() };
6
+ const execOpts: ExecSyncOptions = { stdio: 'inherit', cwd: process.cwd() }
7
7
 
8
8
  function runPendingMigrations(): void {
9
- const spinner = ora("Running pending migrations…").start();
9
+ const spinner = ora('Running pending migrations…').start()
10
10
  try {
11
- spinner.stop();
12
- execSync("npx prisma migrate deploy", execOpts);
13
- logger.success("All pending migrations applied.");
11
+ spinner.stop()
12
+ execSync('npx prisma migrate deploy', execOpts)
13
+ logger.success('All pending migrations applied.')
14
14
  } catch {
15
- spinner.fail("Migration run failed.");
16
- process.exitCode = 1;
15
+ spinner.fail('Migration run failed.')
16
+ process.exitCode = 1
17
17
  }
18
18
  }
19
19
 
20
20
  function createMigration(name: string): void {
21
- const spinner = ora(`Creating migration "${name}"…`).start();
21
+ const spinner = ora(`Creating migration "${name}"…`).start()
22
22
  try {
23
- spinner.stop();
24
- execSync(`npx prisma migrate dev --name ${name}`, execOpts);
25
- logger.success(`Migration "${name}" created.`);
23
+ spinner.stop()
24
+ execSync(`npx prisma migrate dev --name ${name}`, execOpts)
25
+ logger.success(`Migration "${name}" created.`)
26
26
  } catch {
27
- spinner.fail("Migration creation failed.");
28
- process.exitCode = 1;
27
+ spinner.fail('Migration creation failed.')
28
+ process.exitCode = 1
29
29
  }
30
30
  }
31
31
 
32
32
  function showMigrationStatus(): void {
33
- const spinner = ora("Checking migration status…").start();
33
+ const spinner = ora('Checking migration status…').start()
34
34
  try {
35
- spinner.stop();
36
- execSync("npx prisma migrate status", execOpts);
35
+ spinner.stop()
36
+ execSync('npx prisma migrate status', execOpts)
37
37
  } catch {
38
- spinner.fail("Could not retrieve migration status.");
39
- process.exitCode = 1;
38
+ spinner.fail('Could not retrieve migration status.')
39
+ process.exitCode = 1
40
40
  }
41
41
  }
42
42
 
43
43
  export function registerMigrateCommand(program: Command): void {
44
44
  const migrate = program
45
- .command("migrate")
46
- .description("Database migration utilities powered by Prisma");
45
+ .command('migrate')
46
+ .description('Database migration utilities powered by Prisma')
47
47
 
48
- migrate
49
- .command("run")
50
- .description("Apply all pending migrations")
51
- .action(runPendingMigrations);
48
+ migrate.command('run').description('Apply all pending migrations').action(runPendingMigrations)
52
49
 
53
50
  migrate
54
- .command("create <name>")
55
- .description("Create a new migration with the given name")
56
- .action(createMigration);
51
+ .command('create <name>')
52
+ .description('Create a new migration with the given name')
53
+ .action(createMigration)
57
54
 
58
- migrate
59
- .command("status")
60
- .description("Show current migration status")
61
- .action(showMigrationStatus);
55
+ migrate.command('status').description('Show current migration status').action(showMigrationStatus)
62
56
  }