@xubylele/schema-forge 1.8.1 → 1.9.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 CHANGED
@@ -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;
@@ -70,8 +74,9 @@ interface RunResult {
70
74
  }
71
75
  /**
72
76
  * Initialize a new schema project in the current directory.
77
+ * @param options.provider - Database provider: 'postgres' (default) or 'supabase'. Supabase uses supabase/migrations for output.
73
78
  */
74
- declare function init(): Promise<RunResult>;
79
+ declare function init(options?: InitOptions): Promise<RunResult>;
75
80
  /**
76
81
  * Generate SQL migration from schema files.
77
82
  */
@@ -98,4 +103,4 @@ declare function introspect(options?: IntrospectOptions): Promise<RunResult>;
98
103
  */
99
104
  declare function importSchema(inputPath: string, options?: ImportOptions): Promise<RunResult>;
100
105
 
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 };
106
+ 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
@@ -3389,7 +3389,21 @@ async function runImport(inputPath, options = {}) {
3389
3389
 
3390
3390
  // src/commands/init.ts
3391
3391
  var import_commander5 = require("commander");
3392
- async function runInit() {
3392
+ var import_path11 = __toESM(require("path"));
3393
+ var ALLOWED_PROVIDERS = ["postgres", "supabase"];
3394
+ function resolveInitProvider(provider) {
3395
+ if (!provider) {
3396
+ return "postgres";
3397
+ }
3398
+ const normalized = provider.trim().toLowerCase();
3399
+ if (ALLOWED_PROVIDERS.includes(normalized)) {
3400
+ return normalized;
3401
+ }
3402
+ throw new Error(
3403
+ `Invalid provider "${provider}". Allowed values: ${ALLOWED_PROVIDERS.join(", ")}.`
3404
+ );
3405
+ }
3406
+ async function runInit(options) {
3393
3407
  const root = getProjectRoot();
3394
3408
  const schemaForgeDir = getSchemaForgeDir(root);
3395
3409
  if (await fileExists(schemaForgeDir)) {
@@ -3407,6 +3421,7 @@ async function runInit() {
3407
3421
  if (await fileExists(statePath)) {
3408
3422
  throw new Error(`${statePath} already exists`);
3409
3423
  }
3424
+ const provider = resolveInitProvider(options?.provider);
3410
3425
  info("Initializing schema project...");
3411
3426
  await ensureDir(schemaForgeDir);
3412
3427
  const schemaContent = `# SchemaForge schema definition
@@ -3419,9 +3434,26 @@ table users {
3419
3434
  `;
3420
3435
  await writeTextFile(schemaFilePath, schemaContent);
3421
3436
  success(`Created ${schemaFilePath}`);
3437
+ let outputDir;
3438
+ if (provider === "supabase") {
3439
+ const supabaseDir = import_path11.default.join(root, "supabase");
3440
+ const migrationsDir = import_path11.default.join(root, "supabase", "migrations");
3441
+ if (!await fileExists(supabaseDir)) {
3442
+ await ensureDir(migrationsDir);
3443
+ success(`Created supabase/migrations`);
3444
+ } else {
3445
+ await ensureDir(migrationsDir);
3446
+ success(`Using existing supabase/; migrations at supabase/migrations`);
3447
+ }
3448
+ outputDir = "supabase/migrations";
3449
+ } else {
3450
+ outputDir = "migrations";
3451
+ await ensureDir(import_path11.default.join(root, outputDir));
3452
+ success(`Created ${outputDir}`);
3453
+ }
3422
3454
  const config = {
3423
- provider: "postgres",
3424
- outputDir: "migrations",
3455
+ provider,
3456
+ outputDir,
3425
3457
  schemaFile: "schemaforge/schema.sf",
3426
3458
  stateFile: "schemaforge/state.json",
3427
3459
  sql: {
@@ -3437,9 +3469,6 @@ table users {
3437
3469
  };
3438
3470
  await writeJsonFile(statePath, state);
3439
3471
  success(`Created ${statePath}`);
3440
- const outputDir = "migrations";
3441
- await ensureDir(outputDir);
3442
- success(`Created ${outputDir}`);
3443
3472
  success("Project initialized successfully");
3444
3473
  info("Next steps:");
3445
3474
  info(" 1. Edit schemaforge/schema.sf to define your schema");
@@ -3449,9 +3478,9 @@ table users {
3449
3478
 
3450
3479
  // src/commands/introspect.ts
3451
3480
  var import_commander6 = require("commander");
3452
- var import_path11 = __toESM(require("path"));
3481
+ var import_path12 = __toESM(require("path"));
3453
3482
  function resolveOutputPath(root, outputPath) {
3454
- return import_path11.default.isAbsolute(outputPath) ? outputPath : import_path11.default.join(root, outputPath);
3483
+ return import_path12.default.isAbsolute(outputPath) ? outputPath : import_path12.default.join(root, outputPath);
3455
3484
  }
3456
3485
  async function runIntrospect(options = {}) {
3457
3486
  const connectionString = resolvePostgresConnectionString({ url: options.url });
@@ -3478,9 +3507,9 @@ async function runIntrospect(options = {}) {
3478
3507
 
3479
3508
  // src/commands/validate.ts
3480
3509
  var import_commander7 = require("commander");
3481
- var import_path12 = __toESM(require("path"));
3510
+ var import_path13 = __toESM(require("path"));
3482
3511
  function resolveConfigPath5(root, targetPath) {
3483
- return import_path12.default.isAbsolute(targetPath) ? targetPath : import_path12.default.join(root, targetPath);
3512
+ return import_path13.default.isAbsolute(targetPath) ? targetPath : import_path13.default.join(root, targetPath);
3484
3513
  }
3485
3514
  async function runValidate(options = {}) {
3486
3515
  const root = getProjectRoot();
@@ -3598,8 +3627,8 @@ async function runWithResult(fn) {
3598
3627
  return { exitCode: EXIT_CODES.VALIDATION_ERROR };
3599
3628
  }
3600
3629
  }
3601
- async function init() {
3602
- return runWithResult(() => runInit());
3630
+ async function init(options = {}) {
3631
+ return runWithResult(() => runInit(options));
3603
3632
  }
3604
3633
  async function generate(options = {}) {
3605
3634
  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.8.1",
2736
+ version: "1.9.0",
2737
2737
  description: "Universal migration generator from schema DSL",
2738
2738
  main: "dist/cli.js",
2739
2739
  type: "commonjs",
@@ -3454,7 +3454,21 @@ async function runImport(inputPath, options = {}) {
3454
3454
 
3455
3455
  // src/commands/init.ts
3456
3456
  var import_commander5 = require("commander");
3457
- async function runInit() {
3457
+ var import_path11 = __toESM(require("path"));
3458
+ var ALLOWED_PROVIDERS = ["postgres", "supabase"];
3459
+ function resolveInitProvider(provider) {
3460
+ if (!provider) {
3461
+ return "postgres";
3462
+ }
3463
+ const normalized = provider.trim().toLowerCase();
3464
+ if (ALLOWED_PROVIDERS.includes(normalized)) {
3465
+ return normalized;
3466
+ }
3467
+ throw new Error(
3468
+ `Invalid provider "${provider}". Allowed values: ${ALLOWED_PROVIDERS.join(", ")}.`
3469
+ );
3470
+ }
3471
+ async function runInit(options) {
3458
3472
  const root = getProjectRoot();
3459
3473
  const schemaForgeDir = getSchemaForgeDir(root);
3460
3474
  if (await fileExists(schemaForgeDir)) {
@@ -3472,6 +3486,7 @@ async function runInit() {
3472
3486
  if (await fileExists(statePath)) {
3473
3487
  throw new Error(`${statePath} already exists`);
3474
3488
  }
3489
+ const provider = resolveInitProvider(options?.provider);
3475
3490
  info("Initializing schema project...");
3476
3491
  await ensureDir(schemaForgeDir);
3477
3492
  const schemaContent = `# SchemaForge schema definition
@@ -3484,9 +3499,26 @@ table users {
3484
3499
  `;
3485
3500
  await writeTextFile(schemaFilePath, schemaContent);
3486
3501
  success(`Created ${schemaFilePath}`);
3502
+ let outputDir;
3503
+ if (provider === "supabase") {
3504
+ const supabaseDir = import_path11.default.join(root, "supabase");
3505
+ const migrationsDir = import_path11.default.join(root, "supabase", "migrations");
3506
+ if (!await fileExists(supabaseDir)) {
3507
+ await ensureDir(migrationsDir);
3508
+ success(`Created supabase/migrations`);
3509
+ } else {
3510
+ await ensureDir(migrationsDir);
3511
+ success(`Using existing supabase/; migrations at supabase/migrations`);
3512
+ }
3513
+ outputDir = "supabase/migrations";
3514
+ } else {
3515
+ outputDir = "migrations";
3516
+ await ensureDir(import_path11.default.join(root, outputDir));
3517
+ success(`Created ${outputDir}`);
3518
+ }
3487
3519
  const config = {
3488
- provider: "postgres",
3489
- outputDir: "migrations",
3520
+ provider,
3521
+ outputDir,
3490
3522
  schemaFile: "schemaforge/schema.sf",
3491
3523
  stateFile: "schemaforge/state.json",
3492
3524
  sql: {
@@ -3502,9 +3534,6 @@ table users {
3502
3534
  };
3503
3535
  await writeJsonFile(statePath, state);
3504
3536
  success(`Created ${statePath}`);
3505
- const outputDir = "migrations";
3506
- await ensureDir(outputDir);
3507
- success(`Created ${outputDir}`);
3508
3537
  success("Project initialized successfully");
3509
3538
  info("Next steps:");
3510
3539
  info(" 1. Edit schemaforge/schema.sf to define your schema");
@@ -3514,9 +3543,9 @@ table users {
3514
3543
 
3515
3544
  // src/commands/introspect.ts
3516
3545
  var import_commander6 = require("commander");
3517
- var import_path11 = __toESM(require("path"));
3546
+ var import_path12 = __toESM(require("path"));
3518
3547
  function resolveOutputPath(root, outputPath) {
3519
- return import_path11.default.isAbsolute(outputPath) ? outputPath : import_path11.default.join(root, outputPath);
3548
+ return import_path12.default.isAbsolute(outputPath) ? outputPath : import_path12.default.join(root, outputPath);
3520
3549
  }
3521
3550
  async function runIntrospect(options = {}) {
3522
3551
  const connectionString = resolvePostgresConnectionString({ url: options.url });
@@ -3543,9 +3572,9 @@ async function runIntrospect(options = {}) {
3543
3572
 
3544
3573
  // src/commands/validate.ts
3545
3574
  var import_commander7 = require("commander");
3546
- var import_path12 = __toESM(require("path"));
3575
+ var import_path13 = __toESM(require("path"));
3547
3576
  function resolveConfigPath5(root, targetPath) {
3548
- return import_path12.default.isAbsolute(targetPath) ? targetPath : import_path12.default.join(root, targetPath);
3577
+ return import_path13.default.isAbsolute(targetPath) ? targetPath : import_path13.default.join(root, targetPath);
3549
3578
  }
3550
3579
  async function runValidate(options = {}) {
3551
3580
  const root = getProjectRoot();
@@ -3710,9 +3739,12 @@ async function handleError(error2) {
3710
3739
  }
3711
3740
  process.exitCode = EXIT_CODES.VALIDATION_ERROR;
3712
3741
  }
3713
- program.command("init").description("Initialize a new schema project").action(async () => {
3742
+ program.command("init").description(
3743
+ "Initialize a new schema project. Optional provider: postgres (default) or supabase. Supabase uses supabase/migrations for output."
3744
+ ).argument("[provider]", "Database provider: postgres or supabase").option("--provider <provider>", "Database provider: postgres or supabase (overrides argument)").action(async (providerArg, options) => {
3714
3745
  try {
3715
- await runInit();
3746
+ const provider = options.provider ?? providerArg;
3747
+ await runInit({ provider });
3716
3748
  } catch (error2) {
3717
3749
  await handleError(error2);
3718
3750
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xubylele/schema-forge",
3
- "version": "1.8.1",
3
+ "version": "1.9.0",
4
4
  "description": "Universal migration generator from schema DSL",
5
5
  "main": "dist/cli.js",
6
6
  "type": "commonjs",