@xubylele/schema-forge 1.8.1 → 1.10.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.
- package/README.md +32 -11
- package/dist/api.d.ts +8 -2
- package/dist/api.js +45 -13
- package/dist/cli.js +53 -16
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
A modern CLI tool for database schema management with a clean DSL and automatic SQL migration generation.
|
|
4
4
|
|
|
5
|
-
**Website:** [schemaforge.xuby.cl](https://schemaforge.xuby.cl/) · **npm package:** [@xubylele/schema-forge](https://www.npmjs.com/package/@xubylele/schema-forge)
|
|
5
|
+
**Website:** [schemaforge.xuby.cl](https://schemaforge.xuby.cl/) · **npm package:** [@xubylele/schema-forge](https://www.npmjs.com/package/@xubylele/schema-forge) · **Roadmap:** [ROADMAP.md](ROADMAP.md)
|
|
6
6
|
|
|
7
7
|
## Features
|
|
8
8
|
|
|
@@ -40,7 +40,7 @@ const result = await generate({ name: 'MyMigration' });
|
|
|
40
40
|
if (result.exitCode !== EXIT_CODES.SUCCESS) process.exit(result.exitCode);
|
|
41
41
|
```
|
|
42
42
|
|
|
43
|
-
**Exports:** `init`, `generate`, `diff`, `doctor`, `validate`, `introspect`, `importSchema` (each returns `Promise<RunResult>`), `RunResult` (`{ exitCode: number }`), `EXIT_CODES`, and option types (`GenerateOptions`, `DiffOptions`, etc.). Entrypoint: `@xubylele/schema-forge/api`. Exit code semantics: [docs/exit-codes.json](docs/exit-codes.json).
|
|
43
|
+
**Exports:** `init`, `generate`, `diff`, `doctor`, `validate`, `introspect`, `importSchema` (each returns `Promise<RunResult>`), `RunResult` (`{ exitCode: number }`), `EXIT_CODES`, and option types (`InitOptions`, `GenerateOptions`, `DiffOptions`, etc.). Entrypoint: `@xubylele/schema-forge/api`. Exit code semantics: [docs/exit-codes.json](docs/exit-codes.json).
|
|
44
44
|
|
|
45
45
|
## Development
|
|
46
46
|
|
|
@@ -88,15 +88,20 @@ Here's a quick walkthrough to get started with SchemaForge:
|
|
|
88
88
|
### 1. Initialize a new project
|
|
89
89
|
|
|
90
90
|
```bash
|
|
91
|
-
schema-forge init
|
|
91
|
+
schema-forge init [provider]
|
|
92
92
|
```
|
|
93
93
|
|
|
94
|
+
Optional `provider`: `postgres` (default) or `supabase`. You can also use `--provider <provider>`.
|
|
95
|
+
|
|
96
|
+
- **postgres** – Creates `migrations/` at the project root and sets `outputDir` to `migrations`.
|
|
97
|
+
- **supabase** – Uses `supabase/migrations/` for migrations. If `supabase/` does not exist, it is created; if it already exists (e.g. from `supabase init`), SchemaForge config is set to use `supabase/migrations/`.
|
|
98
|
+
|
|
94
99
|
This creates:
|
|
95
100
|
|
|
96
101
|
- `schemaforge/schema.sf` - Your schema definition file
|
|
97
|
-
- `schemaforge/config.json` - Project configuration
|
|
102
|
+
- `schemaforge/config.json` - Project configuration (includes `provider` and `outputDir`)
|
|
98
103
|
- `schemaforge/state.json` - State tracking file
|
|
99
|
-
- `supabase/migrations/` - Directory for generated migrations
|
|
104
|
+
- `migrations/` or `supabase/migrations/` - Directory for generated migrations (depends on provider)
|
|
100
105
|
|
|
101
106
|
### 2. Define your schema
|
|
102
107
|
|
|
@@ -186,9 +191,18 @@ For common function-style defaults, comparisons are normalized to avoid obvious
|
|
|
186
191
|
Initialize a new SchemaForge project in the current directory.
|
|
187
192
|
|
|
188
193
|
```bash
|
|
189
|
-
schema-forge init
|
|
194
|
+
schema-forge init [provider]
|
|
195
|
+
schema-forge init --provider <provider>
|
|
190
196
|
```
|
|
191
197
|
|
|
198
|
+
- **`[provider]`** (optional) – `postgres` or `supabase`. Default is `postgres`.
|
|
199
|
+
- **`--provider <provider>`** – Same as above; overrides the positional argument if both are given.
|
|
200
|
+
|
|
201
|
+
**Behavior:**
|
|
202
|
+
|
|
203
|
+
- **postgres** (default): Creates `migrations/` at the project root. Config gets `provider: "postgres"` and `outputDir: "migrations"`.
|
|
204
|
+
- **supabase**: Uses `supabase/migrations/` for generated migrations. If the `supabase/` folder does not exist, it is created along with `supabase/migrations/`. If `supabase/` already exists (e.g. from an existing Supabase project), only `supabase/migrations/` is ensured and config is set to use it. Config gets `provider: "supabase"` and `outputDir: "supabase/migrations"`.
|
|
205
|
+
|
|
192
206
|
Creates the necessary directory structure and configuration files.
|
|
193
207
|
|
|
194
208
|
### `schema-forge generate`
|
|
@@ -578,6 +592,8 @@ table profiles {
|
|
|
578
592
|
|
|
579
593
|
## Project Structure
|
|
580
594
|
|
|
595
|
+
With **postgres** (default), migrations live in `migrations/` at the project root. With **supabase**, they live in `supabase/migrations/`. Example for a Supabase-backed project:
|
|
596
|
+
|
|
581
597
|
```bash
|
|
582
598
|
your-project/
|
|
583
599
|
+-- schemaforge/
|
|
@@ -585,14 +601,16 @@ your-project/
|
|
|
585
601
|
| +-- config.json # Project configuration
|
|
586
602
|
| \-- state.json # State tracking (auto-generated)
|
|
587
603
|
\-- supabase/
|
|
588
|
-
\-- migrations/ # Generated SQL migrations
|
|
604
|
+
\-- migrations/ # Generated SQL migrations (when provider is supabase)
|
|
589
605
|
+-- 20240101120000-initial.sql
|
|
590
606
|
\-- 20240101120100-add-user-avatar.sql
|
|
591
607
|
```
|
|
592
608
|
|
|
609
|
+
For postgres, replace `supabase/migrations/` with a top-level `migrations/` directory.
|
|
610
|
+
|
|
593
611
|
## Configuration
|
|
594
612
|
|
|
595
|
-
The `schemaforge/config.json` file contains project configuration:
|
|
613
|
+
The `schemaforge/config.json` file contains project configuration. The `provider` and `outputDir` values are set by `schema-forge init` based on the provider you choose:
|
|
596
614
|
|
|
597
615
|
```json
|
|
598
616
|
{
|
|
@@ -607,18 +625,21 @@ The `schemaforge/config.json` file contains project configuration:
|
|
|
607
625
|
}
|
|
608
626
|
```
|
|
609
627
|
|
|
628
|
+
- **postgres**: `provider: "postgres"`, `outputDir: "migrations"`.
|
|
629
|
+
- **supabase**: `provider: "supabase"`, `outputDir: "supabase/migrations"`.
|
|
630
|
+
|
|
610
631
|
## Supported Databases
|
|
611
632
|
|
|
612
633
|
Currently supports:
|
|
613
634
|
|
|
614
|
-
- PostgreSQL (`postgres`)
|
|
615
|
-
- Supabase (`supabase`)
|
|
635
|
+
- PostgreSQL (`postgres`) – default; migrations in `migrations/`
|
|
636
|
+
- Supabase (`supabase`) – migrations in `supabase/migrations/`; choose at init with `schema-forge init supabase`
|
|
616
637
|
|
|
617
638
|
## Development Workflow
|
|
618
639
|
|
|
619
640
|
A typical development workflow looks like this:
|
|
620
641
|
|
|
621
|
-
1. **Initialize** - `schema-forge init` (one time)
|
|
642
|
+
1. **Initialize** - `schema-forge init` or `schema-forge init supabase` (one time)
|
|
622
643
|
2. **Edit schema** - Modify `schemaforge/schema.sf`
|
|
623
644
|
3. **Preview changes** - `schema-forge diff` (optional)
|
|
624
645
|
4. **Generate migration** - `schema-forge generate --name "description"`
|
package/dist/api.d.ts
CHANGED
|
@@ -21,6 +21,10 @@ interface ImportOptions {
|
|
|
21
21
|
out?: string;
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
+
interface InitOptions {
|
|
25
|
+
provider?: string;
|
|
26
|
+
}
|
|
27
|
+
|
|
24
28
|
interface IntrospectOptions {
|
|
25
29
|
url?: string;
|
|
26
30
|
schema?: string;
|
|
@@ -32,6 +36,7 @@ interface ValidateOptions {
|
|
|
32
36
|
json?: boolean;
|
|
33
37
|
url?: string;
|
|
34
38
|
schema?: string;
|
|
39
|
+
force?: boolean;
|
|
35
40
|
}
|
|
36
41
|
|
|
37
42
|
/**
|
|
@@ -70,8 +75,9 @@ interface RunResult {
|
|
|
70
75
|
}
|
|
71
76
|
/**
|
|
72
77
|
* Initialize a new schema project in the current directory.
|
|
78
|
+
* @param options.provider - Database provider: 'postgres' (default) or 'supabase'. Supabase uses supabase/migrations for output.
|
|
73
79
|
*/
|
|
74
|
-
declare function init(): Promise<RunResult>;
|
|
80
|
+
declare function init(options?: InitOptions): Promise<RunResult>;
|
|
75
81
|
/**
|
|
76
82
|
* Generate SQL migration from schema files.
|
|
77
83
|
*/
|
|
@@ -98,4 +104,4 @@ declare function introspect(options?: IntrospectOptions): Promise<RunResult>;
|
|
|
98
104
|
*/
|
|
99
105
|
declare function importSchema(inputPath: string, options?: ImportOptions): Promise<RunResult>;
|
|
100
106
|
|
|
101
|
-
export { type DiffOptions, type DoctorOptions, EXIT_CODES, type GenerateOptions, type ImportOptions, type IntrospectOptions, type RunResult, type ValidateOptions, diff, doctor, generate, importSchema, init, introspect, validate };
|
|
107
|
+
export { type DiffOptions, type DoctorOptions, EXIT_CODES, type GenerateOptions, type ImportOptions, type InitOptions, type IntrospectOptions, type RunResult, type ValidateOptions, diff, doctor, generate, importSchema, init, introspect, validate };
|
package/dist/api.js
CHANGED
|
@@ -2950,6 +2950,9 @@ var EXIT_CODES = {
|
|
|
2950
2950
|
/** Destructive operation detected in CI environment without --force */
|
|
2951
2951
|
CI_DESTRUCTIVE: 3
|
|
2952
2952
|
};
|
|
2953
|
+
function shouldFailCIDestructive(isCIEnvironment, hasDestructiveFindings2, isForceEnabled) {
|
|
2954
|
+
return isCIEnvironment && hasDestructiveFindings2 && !isForceEnabled;
|
|
2955
|
+
}
|
|
2953
2956
|
|
|
2954
2957
|
// src/utils/output.ts
|
|
2955
2958
|
var import_boxen = __toESM(require("boxen"));
|
|
@@ -3389,7 +3392,21 @@ async function runImport(inputPath, options = {}) {
|
|
|
3389
3392
|
|
|
3390
3393
|
// src/commands/init.ts
|
|
3391
3394
|
var import_commander5 = require("commander");
|
|
3392
|
-
|
|
3395
|
+
var import_path11 = __toESM(require("path"));
|
|
3396
|
+
var ALLOWED_PROVIDERS = ["postgres", "supabase"];
|
|
3397
|
+
function resolveInitProvider(provider) {
|
|
3398
|
+
if (!provider) {
|
|
3399
|
+
return "postgres";
|
|
3400
|
+
}
|
|
3401
|
+
const normalized = provider.trim().toLowerCase();
|
|
3402
|
+
if (ALLOWED_PROVIDERS.includes(normalized)) {
|
|
3403
|
+
return normalized;
|
|
3404
|
+
}
|
|
3405
|
+
throw new Error(
|
|
3406
|
+
`Invalid provider "${provider}". Allowed values: ${ALLOWED_PROVIDERS.join(", ")}.`
|
|
3407
|
+
);
|
|
3408
|
+
}
|
|
3409
|
+
async function runInit(options) {
|
|
3393
3410
|
const root = getProjectRoot();
|
|
3394
3411
|
const schemaForgeDir = getSchemaForgeDir(root);
|
|
3395
3412
|
if (await fileExists(schemaForgeDir)) {
|
|
@@ -3407,6 +3424,7 @@ async function runInit() {
|
|
|
3407
3424
|
if (await fileExists(statePath)) {
|
|
3408
3425
|
throw new Error(`${statePath} already exists`);
|
|
3409
3426
|
}
|
|
3427
|
+
const provider = resolveInitProvider(options?.provider);
|
|
3410
3428
|
info("Initializing schema project...");
|
|
3411
3429
|
await ensureDir(schemaForgeDir);
|
|
3412
3430
|
const schemaContent = `# SchemaForge schema definition
|
|
@@ -3419,9 +3437,26 @@ table users {
|
|
|
3419
3437
|
`;
|
|
3420
3438
|
await writeTextFile(schemaFilePath, schemaContent);
|
|
3421
3439
|
success(`Created ${schemaFilePath}`);
|
|
3440
|
+
let outputDir;
|
|
3441
|
+
if (provider === "supabase") {
|
|
3442
|
+
const supabaseDir = import_path11.default.join(root, "supabase");
|
|
3443
|
+
const migrationsDir = import_path11.default.join(root, "supabase", "migrations");
|
|
3444
|
+
if (!await fileExists(supabaseDir)) {
|
|
3445
|
+
await ensureDir(migrationsDir);
|
|
3446
|
+
success(`Created supabase/migrations`);
|
|
3447
|
+
} else {
|
|
3448
|
+
await ensureDir(migrationsDir);
|
|
3449
|
+
success(`Using existing supabase/; migrations at supabase/migrations`);
|
|
3450
|
+
}
|
|
3451
|
+
outputDir = "supabase/migrations";
|
|
3452
|
+
} else {
|
|
3453
|
+
outputDir = "migrations";
|
|
3454
|
+
await ensureDir(import_path11.default.join(root, outputDir));
|
|
3455
|
+
success(`Created ${outputDir}`);
|
|
3456
|
+
}
|
|
3422
3457
|
const config = {
|
|
3423
|
-
provider
|
|
3424
|
-
outputDir
|
|
3458
|
+
provider,
|
|
3459
|
+
outputDir,
|
|
3425
3460
|
schemaFile: "schemaforge/schema.sf",
|
|
3426
3461
|
stateFile: "schemaforge/state.json",
|
|
3427
3462
|
sql: {
|
|
@@ -3437,9 +3472,6 @@ table users {
|
|
|
3437
3472
|
};
|
|
3438
3473
|
await writeJsonFile(statePath, state);
|
|
3439
3474
|
success(`Created ${statePath}`);
|
|
3440
|
-
const outputDir = "migrations";
|
|
3441
|
-
await ensureDir(outputDir);
|
|
3442
|
-
success(`Created ${outputDir}`);
|
|
3443
3475
|
success("Project initialized successfully");
|
|
3444
3476
|
info("Next steps:");
|
|
3445
3477
|
info(" 1. Edit schemaforge/schema.sf to define your schema");
|
|
@@ -3449,9 +3481,9 @@ table users {
|
|
|
3449
3481
|
|
|
3450
3482
|
// src/commands/introspect.ts
|
|
3451
3483
|
var import_commander6 = require("commander");
|
|
3452
|
-
var
|
|
3484
|
+
var import_path12 = __toESM(require("path"));
|
|
3453
3485
|
function resolveOutputPath(root, outputPath) {
|
|
3454
|
-
return
|
|
3486
|
+
return import_path12.default.isAbsolute(outputPath) ? outputPath : import_path12.default.join(root, outputPath);
|
|
3455
3487
|
}
|
|
3456
3488
|
async function runIntrospect(options = {}) {
|
|
3457
3489
|
const connectionString = resolvePostgresConnectionString({ url: options.url });
|
|
@@ -3478,9 +3510,9 @@ async function runIntrospect(options = {}) {
|
|
|
3478
3510
|
|
|
3479
3511
|
// src/commands/validate.ts
|
|
3480
3512
|
var import_commander7 = require("commander");
|
|
3481
|
-
var
|
|
3513
|
+
var import_path13 = __toESM(require("path"));
|
|
3482
3514
|
function resolveConfigPath5(root, targetPath) {
|
|
3483
|
-
return
|
|
3515
|
+
return import_path13.default.isAbsolute(targetPath) ? targetPath : import_path13.default.join(root, targetPath);
|
|
3484
3516
|
}
|
|
3485
3517
|
async function runValidate(options = {}) {
|
|
3486
3518
|
const root = getProjectRoot();
|
|
@@ -3554,7 +3586,7 @@ async function runValidate(options = {}) {
|
|
|
3554
3586
|
}
|
|
3555
3587
|
const findings = await validateSchemaChanges2(previousState, schema);
|
|
3556
3588
|
const report = await toValidationReport2(findings);
|
|
3557
|
-
if (isCI()
|
|
3589
|
+
if (shouldFailCIDestructive(isCI(), hasDestructiveFindings(findings), Boolean(options.force))) {
|
|
3558
3590
|
process.exitCode = EXIT_CODES.CI_DESTRUCTIVE;
|
|
3559
3591
|
} else {
|
|
3560
3592
|
process.exitCode = report.hasErrors ? EXIT_CODES.VALIDATION_ERROR : EXIT_CODES.SUCCESS;
|
|
@@ -3598,8 +3630,8 @@ async function runWithResult(fn) {
|
|
|
3598
3630
|
return { exitCode: EXIT_CODES.VALIDATION_ERROR };
|
|
3599
3631
|
}
|
|
3600
3632
|
}
|
|
3601
|
-
async function init() {
|
|
3602
|
-
return runWithResult(() => runInit());
|
|
3633
|
+
async function init(options = {}) {
|
|
3634
|
+
return runWithResult(() => runInit(options));
|
|
3603
3635
|
}
|
|
3604
3636
|
async function generate(options = {}) {
|
|
3605
3637
|
return runWithResult(() => runGenerate(options));
|
package/dist/cli.js
CHANGED
|
@@ -2733,7 +2733,7 @@ var import_commander8 = require("commander");
|
|
|
2733
2733
|
// package.json
|
|
2734
2734
|
var package_default = {
|
|
2735
2735
|
name: "@xubylele/schema-forge",
|
|
2736
|
-
version: "1.
|
|
2736
|
+
version: "1.10.0",
|
|
2737
2737
|
description: "Universal migration generator from schema DSL",
|
|
2738
2738
|
main: "dist/cli.js",
|
|
2739
2739
|
type: "commonjs",
|
|
@@ -3015,6 +3015,9 @@ var EXIT_CODES = {
|
|
|
3015
3015
|
/** Destructive operation detected in CI environment without --force */
|
|
3016
3016
|
CI_DESTRUCTIVE: 3
|
|
3017
3017
|
};
|
|
3018
|
+
function shouldFailCIDestructive(isCIEnvironment, hasDestructiveFindings2, isForceEnabled) {
|
|
3019
|
+
return isCIEnvironment && hasDestructiveFindings2 && !isForceEnabled;
|
|
3020
|
+
}
|
|
3018
3021
|
|
|
3019
3022
|
// src/utils/output.ts
|
|
3020
3023
|
var import_boxen = __toESM(require("boxen"));
|
|
@@ -3454,7 +3457,21 @@ async function runImport(inputPath, options = {}) {
|
|
|
3454
3457
|
|
|
3455
3458
|
// src/commands/init.ts
|
|
3456
3459
|
var import_commander5 = require("commander");
|
|
3457
|
-
|
|
3460
|
+
var import_path11 = __toESM(require("path"));
|
|
3461
|
+
var ALLOWED_PROVIDERS = ["postgres", "supabase"];
|
|
3462
|
+
function resolveInitProvider(provider) {
|
|
3463
|
+
if (!provider) {
|
|
3464
|
+
return "postgres";
|
|
3465
|
+
}
|
|
3466
|
+
const normalized = provider.trim().toLowerCase();
|
|
3467
|
+
if (ALLOWED_PROVIDERS.includes(normalized)) {
|
|
3468
|
+
return normalized;
|
|
3469
|
+
}
|
|
3470
|
+
throw new Error(
|
|
3471
|
+
`Invalid provider "${provider}". Allowed values: ${ALLOWED_PROVIDERS.join(", ")}.`
|
|
3472
|
+
);
|
|
3473
|
+
}
|
|
3474
|
+
async function runInit(options) {
|
|
3458
3475
|
const root = getProjectRoot();
|
|
3459
3476
|
const schemaForgeDir = getSchemaForgeDir(root);
|
|
3460
3477
|
if (await fileExists(schemaForgeDir)) {
|
|
@@ -3472,6 +3489,7 @@ async function runInit() {
|
|
|
3472
3489
|
if (await fileExists(statePath)) {
|
|
3473
3490
|
throw new Error(`${statePath} already exists`);
|
|
3474
3491
|
}
|
|
3492
|
+
const provider = resolveInitProvider(options?.provider);
|
|
3475
3493
|
info("Initializing schema project...");
|
|
3476
3494
|
await ensureDir(schemaForgeDir);
|
|
3477
3495
|
const schemaContent = `# SchemaForge schema definition
|
|
@@ -3484,9 +3502,26 @@ table users {
|
|
|
3484
3502
|
`;
|
|
3485
3503
|
await writeTextFile(schemaFilePath, schemaContent);
|
|
3486
3504
|
success(`Created ${schemaFilePath}`);
|
|
3505
|
+
let outputDir;
|
|
3506
|
+
if (provider === "supabase") {
|
|
3507
|
+
const supabaseDir = import_path11.default.join(root, "supabase");
|
|
3508
|
+
const migrationsDir = import_path11.default.join(root, "supabase", "migrations");
|
|
3509
|
+
if (!await fileExists(supabaseDir)) {
|
|
3510
|
+
await ensureDir(migrationsDir);
|
|
3511
|
+
success(`Created supabase/migrations`);
|
|
3512
|
+
} else {
|
|
3513
|
+
await ensureDir(migrationsDir);
|
|
3514
|
+
success(`Using existing supabase/; migrations at supabase/migrations`);
|
|
3515
|
+
}
|
|
3516
|
+
outputDir = "supabase/migrations";
|
|
3517
|
+
} else {
|
|
3518
|
+
outputDir = "migrations";
|
|
3519
|
+
await ensureDir(import_path11.default.join(root, outputDir));
|
|
3520
|
+
success(`Created ${outputDir}`);
|
|
3521
|
+
}
|
|
3487
3522
|
const config = {
|
|
3488
|
-
provider
|
|
3489
|
-
outputDir
|
|
3523
|
+
provider,
|
|
3524
|
+
outputDir,
|
|
3490
3525
|
schemaFile: "schemaforge/schema.sf",
|
|
3491
3526
|
stateFile: "schemaforge/state.json",
|
|
3492
3527
|
sql: {
|
|
@@ -3502,9 +3537,6 @@ table users {
|
|
|
3502
3537
|
};
|
|
3503
3538
|
await writeJsonFile(statePath, state);
|
|
3504
3539
|
success(`Created ${statePath}`);
|
|
3505
|
-
const outputDir = "migrations";
|
|
3506
|
-
await ensureDir(outputDir);
|
|
3507
|
-
success(`Created ${outputDir}`);
|
|
3508
3540
|
success("Project initialized successfully");
|
|
3509
3541
|
info("Next steps:");
|
|
3510
3542
|
info(" 1. Edit schemaforge/schema.sf to define your schema");
|
|
@@ -3514,9 +3546,9 @@ table users {
|
|
|
3514
3546
|
|
|
3515
3547
|
// src/commands/introspect.ts
|
|
3516
3548
|
var import_commander6 = require("commander");
|
|
3517
|
-
var
|
|
3549
|
+
var import_path12 = __toESM(require("path"));
|
|
3518
3550
|
function resolveOutputPath(root, outputPath) {
|
|
3519
|
-
return
|
|
3551
|
+
return import_path12.default.isAbsolute(outputPath) ? outputPath : import_path12.default.join(root, outputPath);
|
|
3520
3552
|
}
|
|
3521
3553
|
async function runIntrospect(options = {}) {
|
|
3522
3554
|
const connectionString = resolvePostgresConnectionString({ url: options.url });
|
|
@@ -3543,9 +3575,9 @@ async function runIntrospect(options = {}) {
|
|
|
3543
3575
|
|
|
3544
3576
|
// src/commands/validate.ts
|
|
3545
3577
|
var import_commander7 = require("commander");
|
|
3546
|
-
var
|
|
3578
|
+
var import_path13 = __toESM(require("path"));
|
|
3547
3579
|
function resolveConfigPath5(root, targetPath) {
|
|
3548
|
-
return
|
|
3580
|
+
return import_path13.default.isAbsolute(targetPath) ? targetPath : import_path13.default.join(root, targetPath);
|
|
3549
3581
|
}
|
|
3550
3582
|
async function runValidate(options = {}) {
|
|
3551
3583
|
const root = getProjectRoot();
|
|
@@ -3619,7 +3651,7 @@ async function runValidate(options = {}) {
|
|
|
3619
3651
|
}
|
|
3620
3652
|
const findings = await validateSchemaChanges2(previousState, schema);
|
|
3621
3653
|
const report = await toValidationReport2(findings);
|
|
3622
|
-
if (isCI()
|
|
3654
|
+
if (shouldFailCIDestructive(isCI(), hasDestructiveFindings(findings), Boolean(options.force))) {
|
|
3623
3655
|
process.exitCode = EXIT_CODES.CI_DESTRUCTIVE;
|
|
3624
3656
|
} else {
|
|
3625
3657
|
process.exitCode = report.hasErrors ? EXIT_CODES.VALIDATION_ERROR : EXIT_CODES.SUCCESS;
|
|
@@ -3710,9 +3742,12 @@ async function handleError(error2) {
|
|
|
3710
3742
|
}
|
|
3711
3743
|
process.exitCode = EXIT_CODES.VALIDATION_ERROR;
|
|
3712
3744
|
}
|
|
3713
|
-
program.command("init").description(
|
|
3745
|
+
program.command("init").description(
|
|
3746
|
+
"Initialize a new schema project. Optional provider: postgres (default) or supabase. Supabase uses supabase/migrations for output."
|
|
3747
|
+
).argument("[provider]", "Database provider: postgres or supabase").option("--provider <provider>", "Database provider: postgres or supabase (overrides argument)").action(async (providerArg, options) => {
|
|
3714
3748
|
try {
|
|
3715
|
-
|
|
3749
|
+
const provider = options.provider ?? providerArg;
|
|
3750
|
+
await runInit({ provider });
|
|
3716
3751
|
} catch (error2) {
|
|
3717
3752
|
await handleError(error2);
|
|
3718
3753
|
}
|
|
@@ -3756,9 +3791,11 @@ program.command("import").description("Import schema from SQL migrations").argum
|
|
|
3756
3791
|
await handleError(error2);
|
|
3757
3792
|
}
|
|
3758
3793
|
});
|
|
3759
|
-
program.command("validate").description("Detect destructive or risky schema changes. In CI environments (CI=true), exits with code 3 if destructive operations are detected.").option("--json", "Output structured JSON").option("--url <string>", "PostgreSQL connection URL for live drift validation (defaults to DATABASE_URL)").option("--schema <list>", "Comma-separated schema names to introspect (default: public)").action(async (options) => {
|
|
3794
|
+
program.command("validate").description("Detect destructive or risky schema changes. In CI environments (CI=true), exits with code 3 if destructive operations are detected unless --force is used.").option("--json", "Output structured JSON").option("--url <string>", "PostgreSQL connection URL for live drift validation (defaults to DATABASE_URL)").option("--schema <list>", "Comma-separated schema names to introspect (default: public)").action(async (options) => {
|
|
3760
3795
|
try {
|
|
3761
|
-
|
|
3796
|
+
const globalOptions = program.opts();
|
|
3797
|
+
validateFlagExclusivity(globalOptions);
|
|
3798
|
+
await runValidate({ ...options, ...globalOptions });
|
|
3762
3799
|
} catch (error2) {
|
|
3763
3800
|
await handleError(error2);
|
|
3764
3801
|
}
|