@objectstack/cli 3.0.5 → 3.0.7
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/.turbo/turbo-build.log +2 -26
- package/CHANGELOG.md +27 -0
- package/README.md +98 -54
- package/bin/run-dev.js +5 -0
- package/bin/run.js +5 -0
- package/dist/bin.d.ts +11 -0
- package/dist/bin.d.ts.map +1 -0
- package/dist/bin.js +12 -3759
- package/dist/bin.js.map +1 -0
- package/dist/commands/codemod/v2-to-v3.d.ts +10 -0
- package/dist/commands/codemod/v2-to-v3.d.ts.map +1 -0
- package/dist/commands/codemod/v2-to-v3.js +145 -0
- package/dist/commands/codemod/v2-to-v3.js.map +1 -0
- package/dist/commands/compile.d.ts +13 -0
- package/dist/commands/compile.d.ts.map +1 -0
- package/dist/commands/compile.js +91 -0
- package/dist/commands/compile.js.map +1 -0
- package/dist/commands/create.d.ts +91 -0
- package/dist/commands/create.d.ts.map +1 -0
- package/dist/commands/create.js +259 -0
- package/dist/commands/create.js.map +1 -0
- package/dist/commands/dev.d.ts +14 -0
- package/dist/commands/dev.d.ts.map +1 -0
- package/dist/commands/dev.js +67 -0
- package/dist/commands/dev.js.map +1 -0
- package/dist/commands/diff.d.ts +16 -0
- package/dist/commands/diff.d.ts.map +1 -0
- package/dist/commands/diff.js +239 -0
- package/dist/commands/diff.js.map +1 -0
- package/dist/commands/doctor.d.ts +10 -0
- package/dist/commands/doctor.d.ts.map +1 -0
- package/dist/commands/doctor.js +532 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/explain.d.ts +12 -0
- package/dist/commands/explain.d.ts.map +1 -0
- package/dist/commands/explain.js +368 -0
- package/dist/commands/explain.js.map +1 -0
- package/dist/commands/generate.d.ts +17 -0
- package/dist/commands/generate.d.ts.map +1 -0
- package/dist/commands/generate.js +833 -0
- package/dist/commands/generate.js.map +1 -0
- package/dist/commands/info.d.ts +12 -0
- package/dist/commands/info.d.ts.map +1 -0
- package/dist/commands/info.js +100 -0
- package/dist/commands/info.js.map +1 -0
- package/dist/commands/init.d.ts +22 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +295 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/lint.d.ts +13 -0
- package/dist/commands/lint.d.ts.map +1 -0
- package/dist/commands/lint.js +255 -0
- package/dist/commands/lint.js.map +1 -0
- package/dist/commands/plugin/add.d.ts +22 -0
- package/dist/commands/plugin/add.d.ts.map +1 -0
- package/dist/commands/plugin/add.js +93 -0
- package/dist/commands/plugin/add.js.map +1 -0
- package/dist/commands/plugin/info.d.ts +10 -0
- package/dist/commands/plugin/info.d.ts.map +1 -0
- package/dist/commands/plugin/info.js +65 -0
- package/dist/commands/plugin/info.js.map +1 -0
- package/dist/commands/plugin/list.d.ts +13 -0
- package/dist/commands/plugin/list.d.ts.map +1 -0
- package/dist/commands/plugin/list.js +78 -0
- package/dist/commands/plugin/list.js.map +1 -0
- package/dist/commands/plugin/remove.d.ts +20 -0
- package/dist/commands/plugin/remove.d.ts.map +1 -0
- package/dist/commands/plugin/remove.js +79 -0
- package/dist/commands/plugin/remove.js.map +1 -0
- package/dist/commands/serve.d.ts +15 -0
- package/dist/commands/serve.d.ts.map +1 -0
- package/dist/commands/serve.js +286 -0
- package/dist/commands/serve.js.map +1 -0
- package/dist/commands/studio.d.ts +19 -0
- package/dist/commands/studio.d.ts.map +1 -0
- package/dist/commands/studio.js +43 -0
- package/dist/commands/studio.js.map +1 -0
- package/dist/commands/test.d.ts +13 -0
- package/dist/commands/test.d.ts.map +1 -0
- package/dist/commands/test.js +120 -0
- package/dist/commands/test.js.map +1 -0
- package/dist/commands/validate.d.ts +13 -0
- package/dist/commands/validate.d.ts.map +1 -0
- package/dist/commands/validate.js +115 -0
- package/dist/commands/validate.js.map +1 -0
- package/dist/index.d.ts +15 -114
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +20 -2799
- package/dist/index.js.map +1 -0
- package/dist/utils/config.d.ts +21 -0
- package/dist/utils/config.d.ts.map +1 -0
- package/dist/utils/config.js +66 -0
- package/dist/utils/config.js.map +1 -0
- package/dist/utils/format.d.ts +52 -0
- package/dist/utils/format.d.ts.map +1 -0
- package/dist/utils/format.js +202 -0
- package/dist/utils/format.js.map +1 -0
- package/dist/utils/plugin-helpers.d.ts +14 -0
- package/dist/utils/plugin-helpers.d.ts.map +1 -0
- package/dist/utils/plugin-helpers.js +40 -0
- package/dist/utils/plugin-helpers.js.map +1 -0
- package/dist/utils/studio.d.ts +58 -0
- package/dist/utils/studio.d.ts.map +1 -0
- package/dist/utils/studio.js +288 -0
- package/dist/utils/studio.js.map +1 -0
- package/package.json +33 -15
- package/src/bin.ts +11 -104
- package/src/commands/{codemod.ts → codemod/v2-to-v3.ts} +21 -28
- package/src/commands/compile.ts +35 -25
- package/src/commands/create.ts +29 -19
- package/src/commands/dev.ts +21 -10
- package/src/commands/diff.ts +28 -19
- package/src/commands/doctor.ts +20 -11
- package/src/commands/explain.ts +20 -10
- package/src/commands/generate.ts +81 -90
- package/src/commands/info.ts +22 -11
- package/src/commands/init.ts +32 -20
- package/src/commands/lint.ts +27 -15
- package/src/commands/plugin/add.ts +112 -0
- package/src/commands/plugin/info.ts +79 -0
- package/src/commands/plugin/list.ts +93 -0
- package/src/commands/plugin/remove.ts +97 -0
- package/src/commands/serve.ts +30 -20
- package/src/commands/studio.ts +21 -11
- package/src/commands/test.ts +21 -10
- package/src/commands/validate.ts +36 -25
- package/src/index.ts +20 -12
- package/src/utils/format.ts +10 -6
- package/src/utils/plugin-helpers.ts +37 -0
- package/src/utils/studio.ts +0 -1
- package/test/commands.test.ts +76 -37
- package/test/plugin-commands.test.ts +42 -160
- package/test/plugin.test.ts +19 -23
- package/tsconfig.build.json +18 -0
- package/bin/objectstack.js +0 -2
- package/dist/chunk-CSHQEILI.js +0 -246
- package/dist/chunk-Q74JNWKD.js +0 -248
- package/dist/config-A7BN6UIT.js +0 -11
- package/dist/config-UN34WBHT.js +0 -10
- package/src/commands/plugin.ts +0 -372
- package/src/utils/plugin-commands.ts +0 -163
package/src/commands/generate.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.
|
|
2
2
|
|
|
3
|
-
import { Command } from '
|
|
3
|
+
import { Args, Command, Flags } from '@oclif/core';
|
|
4
4
|
import chalk from 'chalk';
|
|
5
5
|
import fs from 'fs';
|
|
6
6
|
import path from 'path';
|
|
@@ -305,14 +305,7 @@ function generateTypesFromConfig(config: Record<string, unknown>): string {
|
|
|
305
305
|
|
|
306
306
|
// ─── Command ────────────────────────────────────────────────────────
|
|
307
307
|
|
|
308
|
-
|
|
309
|
-
.alias('m')
|
|
310
|
-
.description('Generate metadata scaffold (object, view, action, flow, agent, dashboard, app)')
|
|
311
|
-
.argument('<type>', 'Metadata type to generate')
|
|
312
|
-
.argument('<name>', 'Name for the metadata (use kebab-case)')
|
|
313
|
-
.option('-d, --dir <directory>', 'Target directory (overrides default)')
|
|
314
|
-
.option('--dry-run', 'Show what would be created without writing files')
|
|
315
|
-
.action(async (type: string, name: string, options) => {
|
|
308
|
+
async function runMetadataGeneration(type: string, name: string, flags: { dir?: string; dryRun?: boolean }): Promise<void> {
|
|
316
309
|
printHeader('Generate');
|
|
317
310
|
|
|
318
311
|
const generator = GENERATORS[type];
|
|
@@ -330,7 +323,7 @@ const generateMetadataCommand = new Command('metadata')
|
|
|
330
323
|
process.exit(1);
|
|
331
324
|
}
|
|
332
325
|
|
|
333
|
-
const dir =
|
|
326
|
+
const dir = flags.dir || generator.defaultDir;
|
|
334
327
|
const fileName = `${toSnakeCase(name)}.ts`;
|
|
335
328
|
const filePath = path.join(process.cwd(), dir, fileName);
|
|
336
329
|
|
|
@@ -339,7 +332,7 @@ const generateMetadataCommand = new Command('metadata')
|
|
|
339
332
|
console.log(` ${chalk.dim('File:')} ${chalk.white(path.join(dir, fileName))}`);
|
|
340
333
|
console.log('');
|
|
341
334
|
|
|
342
|
-
if (
|
|
335
|
+
if (flags.dryRun) {
|
|
343
336
|
printInfo('Dry run — no files written');
|
|
344
337
|
console.log('');
|
|
345
338
|
console.log(chalk.dim(' Content:'));
|
|
@@ -395,14 +388,9 @@ const generateMetadataCommand = new Command('metadata')
|
|
|
395
388
|
printError(error.message || String(error));
|
|
396
389
|
process.exit(1);
|
|
397
390
|
}
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
.description('Generate TypeScript type definitions from ObjectStack configuration')
|
|
402
|
-
.argument('[config]', 'Configuration file path')
|
|
403
|
-
.option('-o, --output <file>', 'Output file path', 'src/types/objectstack.d.ts')
|
|
404
|
-
.option('--dry-run', 'Show what would be generated without writing files')
|
|
405
|
-
.action(async (configPath, options) => {
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
async function runTypesGeneration(configPath: string | undefined, flags: { output: string; dryRun?: boolean }): Promise<void> {
|
|
406
394
|
printHeader('Generate Types');
|
|
407
395
|
|
|
408
396
|
try {
|
|
@@ -411,12 +399,12 @@ const generateTypesCommand = new Command('types')
|
|
|
411
399
|
const { config, absolutePath } = await loadConfig(configPath);
|
|
412
400
|
|
|
413
401
|
console.log(` ${chalk.dim('Config:')} ${chalk.white(absolutePath)}`);
|
|
414
|
-
console.log(` ${chalk.dim('Output:')} ${chalk.white(
|
|
402
|
+
console.log(` ${chalk.dim('Output:')} ${chalk.white(flags.output)}`);
|
|
415
403
|
console.log('');
|
|
416
404
|
|
|
417
405
|
const content = generateTypesFromConfig(config as Record<string, unknown>);
|
|
418
406
|
|
|
419
|
-
if (
|
|
407
|
+
if (flags.dryRun) {
|
|
420
408
|
printInfo('Dry run — no files written');
|
|
421
409
|
console.log('');
|
|
422
410
|
for (const line of content.split('\n')) {
|
|
@@ -426,20 +414,20 @@ const generateTypesCommand = new Command('types')
|
|
|
426
414
|
return;
|
|
427
415
|
}
|
|
428
416
|
|
|
429
|
-
const outPath = path.resolve(process.cwd(),
|
|
417
|
+
const outPath = path.resolve(process.cwd(), flags.output);
|
|
430
418
|
const outDir = path.dirname(outPath);
|
|
431
419
|
if (!fs.existsSync(outDir)) {
|
|
432
420
|
fs.mkdirSync(outDir, { recursive: true });
|
|
433
421
|
}
|
|
434
422
|
fs.writeFileSync(outPath, content);
|
|
435
|
-
printSuccess(`Generated types at ${
|
|
423
|
+
printSuccess(`Generated types at ${flags.output}`);
|
|
436
424
|
console.log('');
|
|
437
425
|
|
|
438
426
|
} catch (error: any) {
|
|
439
427
|
printError(error.message || String(error));
|
|
440
428
|
process.exit(1);
|
|
441
429
|
}
|
|
442
|
-
|
|
430
|
+
}
|
|
443
431
|
|
|
444
432
|
// ─── Client SDK Generator ───────────────────────────────────────────
|
|
445
433
|
|
|
@@ -541,12 +529,7 @@ function generateClientFromConfig(config: Record<string, unknown>): string {
|
|
|
541
529
|
return lines.join('\n') + '\n';
|
|
542
530
|
}
|
|
543
531
|
|
|
544
|
-
|
|
545
|
-
.description('Generate a type-safe client SDK from ObjectStack configuration')
|
|
546
|
-
.argument('[config]', 'Configuration file path')
|
|
547
|
-
.option('-o, --output <file>', 'Output file path', 'src/client/objectstack-client.ts')
|
|
548
|
-
.option('--dry-run', 'Show output without writing')
|
|
549
|
-
.action(async (configPath, options) => {
|
|
532
|
+
async function runClientGeneration(configPath: string | undefined, flags: { output: string; dryRun?: boolean }): Promise<void> {
|
|
550
533
|
printHeader('Generate Client SDK');
|
|
551
534
|
|
|
552
535
|
try {
|
|
@@ -556,13 +539,13 @@ const generateClientCommand = new Command('client')
|
|
|
556
539
|
const { config, absolutePath } = await loadConfig(configPath);
|
|
557
540
|
|
|
558
541
|
console.log(` ${chalk.dim('Config:')} ${chalk.white(absolutePath)}`);
|
|
559
|
-
console.log(` ${chalk.dim('Output:')} ${chalk.white(
|
|
542
|
+
console.log(` ${chalk.dim('Output:')} ${chalk.white(flags.output)}`);
|
|
560
543
|
console.log('');
|
|
561
544
|
|
|
562
545
|
printStep('Generating client SDK...');
|
|
563
546
|
const content = generateClientFromConfig(config as Record<string, unknown>);
|
|
564
547
|
|
|
565
|
-
if (
|
|
548
|
+
if (flags.dryRun) {
|
|
566
549
|
printInfo('Dry run — no files written');
|
|
567
550
|
console.log('');
|
|
568
551
|
for (const line of content.split('\n')) {
|
|
@@ -572,20 +555,20 @@ const generateClientCommand = new Command('client')
|
|
|
572
555
|
return;
|
|
573
556
|
}
|
|
574
557
|
|
|
575
|
-
const outPath = path.resolve(process.cwd(),
|
|
558
|
+
const outPath = path.resolve(process.cwd(), flags.output);
|
|
576
559
|
const outDir = path.dirname(outPath);
|
|
577
560
|
if (!fs.existsSync(outDir)) {
|
|
578
561
|
fs.mkdirSync(outDir, { recursive: true });
|
|
579
562
|
}
|
|
580
563
|
fs.writeFileSync(outPath, content);
|
|
581
|
-
printSuccess(`Generated client SDK at ${
|
|
564
|
+
printSuccess(`Generated client SDK at ${flags.output} (${timer.display()})`);
|
|
582
565
|
console.log('');
|
|
583
566
|
|
|
584
567
|
} catch (error: any) {
|
|
585
568
|
printError(error.message || String(error));
|
|
586
569
|
process.exit(1);
|
|
587
570
|
}
|
|
588
|
-
|
|
571
|
+
}
|
|
589
572
|
|
|
590
573
|
// ─── Migration Generator ────────────────────────────────────────────
|
|
591
574
|
|
|
@@ -777,13 +760,7 @@ function generateMigrationTs(config: Record<string, unknown>): string {
|
|
|
777
760
|
return lines.join('\n') + '\n';
|
|
778
761
|
}
|
|
779
762
|
|
|
780
|
-
|
|
781
|
-
.description('Generate database migration from ObjectStack schema')
|
|
782
|
-
.argument('[config]', 'Configuration file path')
|
|
783
|
-
.option('-o, --output <file>', 'Output file path')
|
|
784
|
-
.option('--format <format>', 'Output format: sql or typescript', 'typescript')
|
|
785
|
-
.option('--dry-run', 'Show output without writing')
|
|
786
|
-
.action(async (configPath, options) => {
|
|
763
|
+
async function runMigrationGeneration(configPath: string | undefined, flags: { output?: string; format: string; dryRun?: boolean }): Promise<void> {
|
|
787
764
|
printHeader('Generate Migration');
|
|
788
765
|
|
|
789
766
|
try {
|
|
@@ -792,23 +769,23 @@ const generateMigrationCommand = new Command('migration')
|
|
|
792
769
|
printInfo('Loading configuration...');
|
|
793
770
|
const { config, absolutePath } = await loadConfig(configPath);
|
|
794
771
|
|
|
795
|
-
const ext =
|
|
772
|
+
const ext = flags.format === 'sql' ? 'sql' : 'ts';
|
|
796
773
|
// Format: YYYYMMDDHHmmss (e.g. 20250101120000)
|
|
797
774
|
const timestamp = new Date().toISOString().replace(/[-:T]/g, '').slice(0, 14);
|
|
798
775
|
const defaultOutput = `migrations/${timestamp}_migration.${ext}`;
|
|
799
|
-
const output =
|
|
776
|
+
const output = flags.output || defaultOutput;
|
|
800
777
|
|
|
801
778
|
console.log(` ${chalk.dim('Config:')} ${chalk.white(absolutePath)}`);
|
|
802
|
-
console.log(` ${chalk.dim('Format:')} ${chalk.white(
|
|
779
|
+
console.log(` ${chalk.dim('Format:')} ${chalk.white(flags.format)}`);
|
|
803
780
|
console.log(` ${chalk.dim('Output:')} ${chalk.white(output)}`);
|
|
804
781
|
console.log('');
|
|
805
782
|
|
|
806
783
|
printStep('Generating migration...');
|
|
807
|
-
const content =
|
|
784
|
+
const content = flags.format === 'sql'
|
|
808
785
|
? generateMigrationSql(config as Record<string, unknown>)
|
|
809
786
|
: generateMigrationTs(config as Record<string, unknown>);
|
|
810
787
|
|
|
811
|
-
if (
|
|
788
|
+
if (flags.dryRun) {
|
|
812
789
|
printInfo('Dry run — no files written');
|
|
813
790
|
console.log('');
|
|
814
791
|
for (const line of content.split('\n')) {
|
|
@@ -831,15 +808,11 @@ const generateMigrationCommand = new Command('migration')
|
|
|
831
808
|
printError(error.message || String(error));
|
|
832
809
|
process.exit(1);
|
|
833
810
|
}
|
|
834
|
-
|
|
811
|
+
}
|
|
835
812
|
|
|
836
813
|
// ─── JSON Schema Generator ──────────────────────────────────────────
|
|
837
814
|
|
|
838
|
-
|
|
839
|
-
.description('Generate JSON Schema for objectstack.config.ts (for IDE autocomplete)')
|
|
840
|
-
.option('-o, --output <file>', 'Output file path', 'objectstack.schema.json')
|
|
841
|
-
.option('--dry-run', 'Show output without writing')
|
|
842
|
-
.action(async (options) => {
|
|
815
|
+
async function runSchemaGeneration(flags: { output: string; dryRun?: boolean }): Promise<void> {
|
|
843
816
|
printHeader('Generate Schema');
|
|
844
817
|
|
|
845
818
|
try {
|
|
@@ -864,20 +837,20 @@ const generateSchemaCommand = new Command('schema')
|
|
|
864
837
|
|
|
865
838
|
const content = JSON.stringify(schema, null, 2) + '\n';
|
|
866
839
|
|
|
867
|
-
if (
|
|
840
|
+
if (flags.dryRun) {
|
|
868
841
|
printInfo('Dry run — no files written');
|
|
869
842
|
console.log('');
|
|
870
843
|
console.log(content);
|
|
871
844
|
return;
|
|
872
845
|
}
|
|
873
846
|
|
|
874
|
-
const outPath = path.resolve(process.cwd(),
|
|
847
|
+
const outPath = path.resolve(process.cwd(), flags.output);
|
|
875
848
|
const outDir = path.dirname(outPath);
|
|
876
849
|
if (!fs.existsSync(outDir)) {
|
|
877
850
|
fs.mkdirSync(outDir, { recursive: true });
|
|
878
851
|
}
|
|
879
852
|
fs.writeFileSync(outPath, content);
|
|
880
|
-
printSuccess(`Generated JSON Schema at ${
|
|
853
|
+
printSuccess(`Generated JSON Schema at ${flags.output} (${timer.display()})`);
|
|
881
854
|
console.log('');
|
|
882
855
|
console.log(chalk.dim(' Usage: Reference in your IDE or editor for autocomplete'));
|
|
883
856
|
console.log(chalk.dim(` Path: ${outPath}`));
|
|
@@ -887,47 +860,65 @@ const generateSchemaCommand = new Command('schema')
|
|
|
887
860
|
printError(error.message || String(error));
|
|
888
861
|
process.exit(1);
|
|
889
862
|
}
|
|
890
|
-
|
|
863
|
+
}
|
|
891
864
|
|
|
892
865
|
// ─── Main Generate Command ──────────────────────────────────────────
|
|
893
866
|
|
|
894
|
-
export
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
867
|
+
export default class Generate extends Command {
|
|
868
|
+
static override description = 'Generate metadata files or TypeScript types';
|
|
869
|
+
|
|
870
|
+
static override aliases = ['g'];
|
|
871
|
+
|
|
872
|
+
static override args = {
|
|
873
|
+
type: Args.string({ description: 'Metadata type to generate (object, view, action, flow, agent, dashboard, app)', required: true }),
|
|
874
|
+
name: Args.string({ description: 'Name for the metadata (use kebab-case)', required: false }),
|
|
875
|
+
};
|
|
876
|
+
|
|
877
|
+
static override flags = {
|
|
878
|
+
dir: Flags.string({ char: 'd', description: 'Target directory (overrides default)' }),
|
|
879
|
+
'dry-run': Flags.boolean({ description: 'Show what would be created without writing files' }),
|
|
880
|
+
output: Flags.string({ char: 'o', description: 'Output file path' }),
|
|
881
|
+
format: Flags.string({ description: 'Output format: sql or typescript', default: 'typescript' }),
|
|
882
|
+
};
|
|
883
|
+
|
|
884
|
+
async run(): Promise<void> {
|
|
885
|
+
const { args, flags } = await this.parse(Generate);
|
|
886
|
+
|
|
887
|
+
// Route to sub-commands by type name
|
|
888
|
+
switch (args.type) {
|
|
889
|
+
case 'types':
|
|
890
|
+
return runTypesGeneration(args.name, {
|
|
891
|
+
output: flags.output ?? 'src/types/objectstack.d.ts',
|
|
892
|
+
dryRun: flags['dry-run'],
|
|
893
|
+
});
|
|
894
|
+
case 'client':
|
|
895
|
+
return runClientGeneration(args.name, {
|
|
896
|
+
output: flags.output ?? 'src/client/objectstack-client.ts',
|
|
897
|
+
dryRun: flags['dry-run'],
|
|
898
|
+
});
|
|
899
|
+
case 'migration':
|
|
900
|
+
return runMigrationGeneration(args.name, {
|
|
901
|
+
output: flags.output,
|
|
902
|
+
format: flags.format ?? 'typescript',
|
|
903
|
+
dryRun: flags['dry-run'],
|
|
904
|
+
});
|
|
905
|
+
case 'schema':
|
|
906
|
+
return runSchemaGeneration({
|
|
907
|
+
output: flags.output ?? 'objectstack.schema.json',
|
|
908
|
+
dryRun: flags['dry-run'],
|
|
909
|
+
});
|
|
922
910
|
}
|
|
923
911
|
|
|
924
|
-
//
|
|
925
|
-
if (!name) {
|
|
912
|
+
// Metadata generation
|
|
913
|
+
if (!args.name) {
|
|
926
914
|
printError('Missing required argument: <name>');
|
|
927
915
|
console.log(chalk.dim(' Usage: objectstack generate <type> <name>'));
|
|
928
916
|
process.exit(1);
|
|
929
917
|
}
|
|
930
918
|
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
919
|
+
await runMetadataGeneration(args.type, args.name, {
|
|
920
|
+
dir: flags.dir,
|
|
921
|
+
dryRun: flags['dry-run'],
|
|
922
|
+
});
|
|
923
|
+
}
|
|
924
|
+
}
|
package/src/commands/info.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.
|
|
2
2
|
|
|
3
|
-
import { Command } from '
|
|
3
|
+
import { Args, Command, Flags } from '@oclif/core';
|
|
4
4
|
import chalk from 'chalk';
|
|
5
|
+
import { normalizeStackInput } from '@objectstack/spec';
|
|
5
6
|
import { loadConfig } from '../utils/config.js';
|
|
6
7
|
import {
|
|
7
8
|
printHeader,
|
|
@@ -14,22 +15,31 @@ import {
|
|
|
14
15
|
printMetadataStats,
|
|
15
16
|
} from '../utils/format.js';
|
|
16
17
|
|
|
17
|
-
export
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
18
|
+
export default class Info extends Command {
|
|
19
|
+
static override description = 'Display metadata summary of an ObjectStack configuration';
|
|
20
|
+
|
|
21
|
+
static override args = {
|
|
22
|
+
config: Args.string({ description: 'Configuration file path', required: false }),
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
static override flags = {
|
|
26
|
+
json: Flags.boolean({ description: 'Output as JSON' }),
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
async run(): Promise<void> {
|
|
30
|
+
const { args, flags } = await this.parse(Info);
|
|
22
31
|
const timer = createTimer();
|
|
23
32
|
|
|
24
|
-
if (!
|
|
33
|
+
if (!flags.json) {
|
|
25
34
|
printHeader('Info');
|
|
26
35
|
}
|
|
27
36
|
|
|
28
37
|
try {
|
|
29
|
-
const { config, absolutePath, duration } = await loadConfig(
|
|
38
|
+
const { config: rawConfig, absolutePath, duration } = await loadConfig(args.config);
|
|
39
|
+
const config: any = normalizeStackInput(rawConfig as Record<string, unknown>);
|
|
30
40
|
const stats = collectMetadataStats(config);
|
|
31
41
|
|
|
32
|
-
if (
|
|
42
|
+
if (flags.json) {
|
|
33
43
|
console.log(JSON.stringify({
|
|
34
44
|
config: absolutePath,
|
|
35
45
|
manifest: config.manifest || null,
|
|
@@ -102,7 +112,7 @@ export const infoCommand = new Command('info')
|
|
|
102
112
|
console.log('');
|
|
103
113
|
|
|
104
114
|
} catch (error: any) {
|
|
105
|
-
if (
|
|
115
|
+
if (flags.json) {
|
|
106
116
|
console.log(JSON.stringify({ error: error.message }));
|
|
107
117
|
process.exit(1);
|
|
108
118
|
}
|
|
@@ -110,4 +120,5 @@ export const infoCommand = new Command('info')
|
|
|
110
120
|
printError(error.message || String(error));
|
|
111
121
|
process.exit(1);
|
|
112
122
|
}
|
|
113
|
-
}
|
|
123
|
+
}
|
|
124
|
+
}
|
package/src/commands/init.ts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.
|
|
2
2
|
|
|
3
|
-
import { Command } from '
|
|
3
|
+
import { Args, Command, Flags } from '@oclif/core';
|
|
4
4
|
import chalk from 'chalk';
|
|
5
5
|
import fs from 'fs';
|
|
6
6
|
import path from 'path';
|
|
7
7
|
import { printHeader, printSuccess, printError, printStep, printKV, printInfo } from '../utils/format.js';
|
|
8
8
|
|
|
9
|
-
const TEMPLATES: Record<string, {
|
|
9
|
+
export const TEMPLATES: Record<string, {
|
|
10
10
|
description: string;
|
|
11
11
|
dependencies: Record<string, string>;
|
|
12
12
|
devDependencies: Record<string, string>;
|
|
@@ -179,33 +179,48 @@ function toTitleCase(str: string): string {
|
|
|
179
179
|
return str.replace(/[-_]/g, ' ').replace(/\b\w/g, c => c.toUpperCase());
|
|
180
180
|
}
|
|
181
181
|
|
|
182
|
-
|
|
183
|
-
.
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
182
|
+
function printWarning(msg: string) {
|
|
183
|
+
console.log(chalk.yellow(` ⚠ ${msg}`));
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
export default class Init extends Command {
|
|
187
|
+
static override id = 'init';
|
|
188
|
+
|
|
189
|
+
static override description = 'Initialize a new ObjectStack project in the current directory';
|
|
190
|
+
|
|
191
|
+
static override args = {
|
|
192
|
+
name: Args.string({ description: 'Project name (defaults to directory name)', required: false }),
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
static override flags = {
|
|
196
|
+
template: Flags.string({ char: 't', description: 'Template: app, plugin, empty', default: 'app' }),
|
|
197
|
+
install: Flags.boolean({ description: 'Install dependencies', default: true, allowNo: true }),
|
|
198
|
+
};
|
|
199
|
+
|
|
200
|
+
async run(): Promise<void> {
|
|
201
|
+
const { args, flags } = await this.parse(Init);
|
|
202
|
+
|
|
188
203
|
printHeader('Init');
|
|
189
204
|
|
|
190
205
|
const cwd = process.cwd();
|
|
191
|
-
const projectName = name || path.basename(cwd);
|
|
192
|
-
const template = TEMPLATES[
|
|
206
|
+
const projectName = args.name || path.basename(cwd);
|
|
207
|
+
const template = TEMPLATES[flags.template];
|
|
193
208
|
|
|
194
209
|
if (!template) {
|
|
195
|
-
printError(`Unknown template: ${
|
|
210
|
+
printError(`Unknown template: ${flags.template}`);
|
|
196
211
|
console.log(chalk.dim(` Available: ${Object.keys(TEMPLATES).join(', ')}`));
|
|
197
|
-
|
|
212
|
+
this.error(`Unknown template: ${flags.template}`);
|
|
198
213
|
}
|
|
199
214
|
|
|
200
215
|
// Check for existing config
|
|
201
216
|
if (fs.existsSync(path.join(cwd, 'objectstack.config.ts'))) {
|
|
202
217
|
printError('objectstack.config.ts already exists in this directory');
|
|
203
218
|
console.log(chalk.dim(' Use `objectstack generate` to add metadata to an existing project'));
|
|
204
|
-
|
|
219
|
+
this.error('objectstack.config.ts already exists in this directory');
|
|
205
220
|
}
|
|
206
221
|
|
|
207
222
|
printKV('Project', projectName);
|
|
208
|
-
printKV('Template', `${
|
|
223
|
+
printKV('Template', `${flags.template} — ${template.description}`);
|
|
209
224
|
printKV('Directory', cwd);
|
|
210
225
|
console.log('');
|
|
211
226
|
|
|
@@ -286,7 +301,7 @@ export const initCommand = new Command('init')
|
|
|
286
301
|
console.log('');
|
|
287
302
|
|
|
288
303
|
// Install dependencies
|
|
289
|
-
if (
|
|
304
|
+
if (flags.install) {
|
|
290
305
|
printStep('Installing dependencies...');
|
|
291
306
|
const { execSync } = await import('child_process');
|
|
292
307
|
try {
|
|
@@ -306,10 +321,7 @@ export const initCommand = new Command('init')
|
|
|
306
321
|
|
|
307
322
|
} catch (error: any) {
|
|
308
323
|
printError(error.message || String(error));
|
|
309
|
-
|
|
324
|
+
this.error(error.message || String(error));
|
|
310
325
|
}
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
function printWarning(msg: string) {
|
|
314
|
-
console.log(chalk.yellow(` ⚠ ${msg}`));
|
|
326
|
+
}
|
|
315
327
|
}
|
package/src/commands/lint.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.
|
|
2
2
|
|
|
3
|
-
import { Command } from '
|
|
3
|
+
import { Args, Command, Flags } from '@oclif/core';
|
|
4
4
|
import chalk from 'chalk';
|
|
5
|
+
import { normalizeStackInput } from '@objectstack/spec';
|
|
5
6
|
import { loadConfig } from '../utils/config.js';
|
|
6
7
|
import {
|
|
7
8
|
printHeader,
|
|
@@ -187,15 +188,24 @@ function lintConfig(config: any): LintIssue[] {
|
|
|
187
188
|
|
|
188
189
|
// ─── Command ────────────────────────────────────────────────────────
|
|
189
190
|
|
|
190
|
-
export
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
191
|
+
export default class Lint extends Command {
|
|
192
|
+
static override description = 'Check ObjectStack configuration for style and convention issues';
|
|
193
|
+
|
|
194
|
+
static override args = {
|
|
195
|
+
config: Args.string({ description: 'Configuration file path', required: false }),
|
|
196
|
+
};
|
|
197
|
+
|
|
198
|
+
static override flags = {
|
|
199
|
+
json: Flags.boolean({ description: 'Output as JSON' }),
|
|
200
|
+
fix: Flags.boolean({ description: 'Show what would be fixed (dry-run)' }),
|
|
201
|
+
};
|
|
202
|
+
|
|
203
|
+
async run(): Promise<void> {
|
|
204
|
+
const { args, flags } = await this.parse(Lint);
|
|
205
|
+
const configPath = args.config;
|
|
196
206
|
const timer = createTimer();
|
|
197
207
|
|
|
198
|
-
if (!
|
|
208
|
+
if (!flags.json) {
|
|
199
209
|
printHeader('Lint');
|
|
200
210
|
printStep('Loading configuration...');
|
|
201
211
|
}
|
|
@@ -203,14 +213,15 @@ export const lintCommand = new Command('lint')
|
|
|
203
213
|
try {
|
|
204
214
|
const { config, absolutePath } = await loadConfig(configPath);
|
|
205
215
|
|
|
206
|
-
if (!
|
|
216
|
+
if (!flags.json) {
|
|
207
217
|
printInfo(`Config: ${chalk.white(absolutePath)}`);
|
|
208
218
|
}
|
|
209
219
|
|
|
210
|
-
const
|
|
220
|
+
const normalized = normalizeStackInput(config as Record<string, unknown>);
|
|
221
|
+
const issues = lintConfig(normalized);
|
|
211
222
|
|
|
212
223
|
// ── JSON output ──
|
|
213
|
-
if (
|
|
224
|
+
if (flags.json) {
|
|
214
225
|
const errors = issues.filter((i) => i.severity === 'error');
|
|
215
226
|
const warnings = issues.filter((i) => i.severity === 'warning');
|
|
216
227
|
const suggestions = issues.filter((i) => i.severity === 'suggestion');
|
|
@@ -252,7 +263,7 @@ export const lintCommand = new Command('lint')
|
|
|
252
263
|
|
|
253
264
|
console.log(` ${color(icon)} ${color(issue.message)}`);
|
|
254
265
|
console.log(chalk.dim(` ${issue.rule} at ${issue.path}`));
|
|
255
|
-
if (
|
|
266
|
+
if (flags.fix && issue.fix) {
|
|
256
267
|
console.log(chalk.green(` → fix: ${issue.fix}`));
|
|
257
268
|
}
|
|
258
269
|
};
|
|
@@ -282,7 +293,7 @@ export const lintCommand = new Command('lint')
|
|
|
282
293
|
if (suggestions.length > 0) parts.push(chalk.blue(`${suggestions.length} suggestion(s)`));
|
|
283
294
|
console.log(` ${parts.join(', ')} ${chalk.dim(`(${timer.display()})`)}`);
|
|
284
295
|
|
|
285
|
-
if (
|
|
296
|
+
if (flags.fix) {
|
|
286
297
|
console.log('');
|
|
287
298
|
printInfo('Dry-run mode: no files were modified.');
|
|
288
299
|
}
|
|
@@ -292,7 +303,7 @@ export const lintCommand = new Command('lint')
|
|
|
292
303
|
if (errors.length > 0) process.exit(1);
|
|
293
304
|
|
|
294
305
|
} catch (error: any) {
|
|
295
|
-
if (
|
|
306
|
+
if (flags.json) {
|
|
296
307
|
console.log(JSON.stringify({ error: error.message }));
|
|
297
308
|
process.exit(1);
|
|
298
309
|
}
|
|
@@ -300,4 +311,5 @@ export const lintCommand = new Command('lint')
|
|
|
300
311
|
printError(error.message || String(error));
|
|
301
312
|
process.exit(1);
|
|
302
313
|
}
|
|
303
|
-
}
|
|
314
|
+
}
|
|
315
|
+
}
|