@lark-apaas/db-schema-sync 0.1.18 → 0.1.19-alpha.20260904074828
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin.js +47 -9
- package/dist/{chunk-7O4DEVTQ.js → chunk-UWBHRXTA.js} +290 -39
- package/dist/index.d.ts +17 -1
- package/dist/index.js +5 -3
- package/package.json +1 -1
package/dist/bin.js
CHANGED
|
@@ -5,8 +5,9 @@ import {
|
|
|
5
5
|
__require,
|
|
6
6
|
__toESM,
|
|
7
7
|
generateSchema,
|
|
8
|
-
resolveEnvOptions
|
|
9
|
-
|
|
8
|
+
resolveEnvOptions,
|
|
9
|
+
validateGeneratedSchema
|
|
10
|
+
} from "./chunk-UWBHRXTA.js";
|
|
10
11
|
|
|
11
12
|
// node_modules/dotenv/package.json
|
|
12
13
|
var require_package = __commonJS({
|
|
@@ -411,19 +412,50 @@ import { writeFileSync, mkdirSync, existsSync } from "fs";
|
|
|
411
412
|
// src/cli-args.ts
|
|
412
413
|
function parseArgs(argv) {
|
|
413
414
|
const args = argv.slice(2);
|
|
415
|
+
const command = args[0] === "validate" ? "validate" : "generate";
|
|
416
|
+
const optionArgs = command === "validate" ? args.slice(1) : args;
|
|
414
417
|
const getArg = (name) => {
|
|
415
|
-
const idx =
|
|
416
|
-
return idx !== -1 &&
|
|
418
|
+
const idx = optionArgs.indexOf(name);
|
|
419
|
+
return idx !== -1 && optionArgs[idx + 1] ? optionArgs[idx + 1] : void 0;
|
|
417
420
|
};
|
|
418
|
-
const hasFlag = (name) =>
|
|
421
|
+
const hasFlag = (name) => optionArgs.includes(name);
|
|
419
422
|
return {
|
|
423
|
+
command,
|
|
420
424
|
output: getArg("--output"),
|
|
425
|
+
input: getArg("--input"),
|
|
426
|
+
project: getArg("--project"),
|
|
421
427
|
exportCustomTypes: hasFlag("--export-custom-types")
|
|
422
428
|
};
|
|
423
429
|
}
|
|
424
430
|
|
|
425
431
|
// src/bin.ts
|
|
432
|
+
function getValidateExitCode(result) {
|
|
433
|
+
if (result.ok) return 0;
|
|
434
|
+
if (result.status === "invalid_artifact") return 2;
|
|
435
|
+
if (result.status === "inconclusive") return 3;
|
|
436
|
+
return 1;
|
|
437
|
+
}
|
|
426
438
|
async function main() {
|
|
439
|
+
const cliArgs = parseArgs(process.argv);
|
|
440
|
+
if (cliArgs.command === "validate") {
|
|
441
|
+
if (!cliArgs.input) {
|
|
442
|
+
const output3 = {
|
|
443
|
+
ok: false,
|
|
444
|
+
status: "inconclusive",
|
|
445
|
+
errorType: "validation_runner_failed",
|
|
446
|
+
durationMs: 0,
|
|
447
|
+
message: "--input is required for validate command"
|
|
448
|
+
};
|
|
449
|
+
console.log(JSON.stringify(output3));
|
|
450
|
+
process.exit(1);
|
|
451
|
+
}
|
|
452
|
+
const output2 = validateGeneratedSchema({
|
|
453
|
+
input: cliArgs.input,
|
|
454
|
+
project: cliArgs.project
|
|
455
|
+
});
|
|
456
|
+
console.log(JSON.stringify(output2));
|
|
457
|
+
process.exit(getValidateExitCode(output2));
|
|
458
|
+
}
|
|
427
459
|
for (const name of [".env.local", ".env"]) {
|
|
428
460
|
const envPath = resolve(process.cwd(), name);
|
|
429
461
|
if (existsSync(envPath)) {
|
|
@@ -431,25 +463,31 @@ async function main() {
|
|
|
431
463
|
console.log(`[db-schema-sync] \u2713 Loaded ${name}`);
|
|
432
464
|
}
|
|
433
465
|
}
|
|
434
|
-
const cliArgs = parseArgs(process.argv);
|
|
435
466
|
const output = cliArgs.output || process.env.DB_SCHEMA_OUTPUT || "server/database/schema.ts";
|
|
436
467
|
try {
|
|
437
468
|
const options = resolveEnvOptions();
|
|
438
469
|
console.log("[db-schema-sync] Starting...");
|
|
439
|
-
console.log(
|
|
470
|
+
console.log(
|
|
471
|
+
`[db-schema-sync] app_id=${options.appId}, dbBranch=${options.dbBranch}, exportCustomTypes=${cliArgs.exportCustomTypes}`
|
|
472
|
+
);
|
|
440
473
|
const schema = await generateSchema({
|
|
441
474
|
...options,
|
|
442
475
|
exportCustomTypes: cliArgs.exportCustomTypes
|
|
443
476
|
});
|
|
444
477
|
if (!schema.includes("pgTable") && !schema.includes("pgView")) {
|
|
445
|
-
console.warn(
|
|
478
|
+
console.warn(
|
|
479
|
+
"[db-schema-sync] \u26A0 Warning: No tables or views found in database. The generated schema will be empty."
|
|
480
|
+
);
|
|
446
481
|
}
|
|
447
482
|
const outputPath = resolve(process.cwd(), output);
|
|
448
483
|
mkdirSync(dirname(outputPath), { recursive: true });
|
|
449
484
|
writeFileSync(outputPath, schema, "utf8");
|
|
450
485
|
console.log(`[db-schema-sync] \u2713 Schema written to ${output}`);
|
|
451
486
|
} catch (err) {
|
|
452
|
-
console.error(
|
|
487
|
+
console.error(
|
|
488
|
+
`[db-schema-sync] \u2717 Failed:`,
|
|
489
|
+
err instanceof Error ? err.message : String(err)
|
|
490
|
+
);
|
|
453
491
|
process.exit(1);
|
|
454
492
|
}
|
|
455
493
|
}
|
|
@@ -268,11 +268,11 @@ var require_dist = __commonJS({
|
|
|
268
268
|
if (cached && cached.expiresAtMs - now > this.refreshBeforeMs) {
|
|
269
269
|
return { token: cached.token, accessKey: cached.accessKey };
|
|
270
270
|
}
|
|
271
|
-
const
|
|
272
|
-
if (
|
|
273
|
-
this.cache.set(filePath,
|
|
274
|
-
if (
|
|
275
|
-
return { token:
|
|
271
|
+
const result2 = this.readAndParse(filePath);
|
|
272
|
+
if (result2) {
|
|
273
|
+
this.cache.set(filePath, result2);
|
|
274
|
+
if (result2.expiresAtMs > now) {
|
|
275
|
+
return { token: result2.token, accessKey: result2.accessKey };
|
|
276
276
|
}
|
|
277
277
|
}
|
|
278
278
|
if (cached && cached.expiresAtMs > now) {
|
|
@@ -1157,15 +1157,15 @@ function toAsciiName(name) {
|
|
|
1157
1157
|
return name;
|
|
1158
1158
|
}
|
|
1159
1159
|
try {
|
|
1160
|
-
const
|
|
1160
|
+
const result2 = [];
|
|
1161
1161
|
for (const char of name) {
|
|
1162
1162
|
if (/[^\x00-\x7F]/.test(char) && import_tiny_pinyin.default.isSupported()) {
|
|
1163
|
-
|
|
1163
|
+
result2.push(import_tiny_pinyin.default.convertToPinyin(char, "", true));
|
|
1164
1164
|
} else {
|
|
1165
|
-
|
|
1165
|
+
result2.push(char);
|
|
1166
1166
|
}
|
|
1167
1167
|
}
|
|
1168
|
-
return
|
|
1168
|
+
return result2.join("_") || name;
|
|
1169
1169
|
} catch {
|
|
1170
1170
|
return name;
|
|
1171
1171
|
}
|
|
@@ -1847,13 +1847,13 @@ var defaultModifiers = [
|
|
|
1847
1847
|
}
|
|
1848
1848
|
];
|
|
1849
1849
|
function applyModifiers(field, modifiers) {
|
|
1850
|
-
let
|
|
1850
|
+
let result2 = "";
|
|
1851
1851
|
for (const mod of modifiers) {
|
|
1852
1852
|
if (mod.match(field)) {
|
|
1853
|
-
|
|
1853
|
+
result2 += mod.modify(field);
|
|
1854
1854
|
}
|
|
1855
1855
|
}
|
|
1856
|
-
return
|
|
1856
|
+
return result2;
|
|
1857
1857
|
}
|
|
1858
1858
|
|
|
1859
1859
|
// src/generator/structures/enum.ts
|
|
@@ -1863,19 +1863,17 @@ function generateEnumCode(schema) {
|
|
|
1863
1863
|
}
|
|
1864
1864
|
|
|
1865
1865
|
// src/generator/structures/index-gen.ts
|
|
1866
|
-
function generateIndexCode(idx, tableIdentifier
|
|
1866
|
+
function generateIndexCode(idx, tableIdentifier) {
|
|
1867
1867
|
const fn = idx.indexType === "unique" ? "uniqueIndex" : "index";
|
|
1868
|
-
const
|
|
1869
|
-
const columns = propertyRefs.map((prop) => `table.${prop}`).join(", ");
|
|
1868
|
+
const columns = idx.indexColumns.map((col) => `table.${sanitizePropertyName(col)}`).join(", ");
|
|
1870
1869
|
const escapedName = escapeDoubleQuote(idx.indexName);
|
|
1871
|
-
const allColumnsKnown = knownColumnProperties === void 0 ? true : propertyRefs.every((prop) => knownColumnProperties.has(prop));
|
|
1872
|
-
if (!columns || !allColumnsKnown) {
|
|
1873
|
-
return `// Complex index: ${idx.indexDef || idx.indexName}`;
|
|
1874
|
-
}
|
|
1875
1870
|
const creationType = idx.indexCreationType || "btree";
|
|
1876
|
-
if (creationType !== "btree") {
|
|
1871
|
+
if (creationType !== "btree" && columns) {
|
|
1877
1872
|
return `${fn}("${escapedName}").using("${creationType}", ${columns})`;
|
|
1878
1873
|
}
|
|
1874
|
+
if (!columns) {
|
|
1875
|
+
return `// Complex index: ${idx.indexDef || idx.indexName}`;
|
|
1876
|
+
}
|
|
1879
1877
|
return `${fn}("${escapedName}").on(${columns})`;
|
|
1880
1878
|
}
|
|
1881
1879
|
|
|
@@ -1901,18 +1899,16 @@ function generateForeignKeyCode(rel, tableIdentifier, tableIdentifierMap) {
|
|
|
1901
1899
|
|
|
1902
1900
|
// src/generator/structures/table.ts
|
|
1903
1901
|
function generateTableCode(table, schemaData, registry, modifiers, tableIdentifierMap) {
|
|
1904
|
-
const knownColumnProperties = /* @__PURE__ */ new Set();
|
|
1905
1902
|
const fieldLines = table.fields.map((field) => {
|
|
1906
1903
|
const mapper = registry.resolve(field);
|
|
1907
1904
|
const typeExpr = mapper.generate(field);
|
|
1908
1905
|
const mods = applyModifiers(field, modifiers);
|
|
1909
1906
|
const propName = sanitizePropertyName(field.fieldName);
|
|
1910
|
-
knownColumnProperties.add(propName);
|
|
1911
1907
|
return ` ${propName}: ${typeExpr}${mods},`;
|
|
1912
1908
|
});
|
|
1913
1909
|
const thirdArgParts = [];
|
|
1914
1910
|
for (const idx of table.indexes) {
|
|
1915
|
-
thirdArgParts.push(generateIndexCode(idx, table.identifier
|
|
1911
|
+
thirdArgParts.push(generateIndexCode(idx, table.identifier));
|
|
1916
1912
|
}
|
|
1917
1913
|
for (const rel of table.relationships) {
|
|
1918
1914
|
thirdArgParts.push(generateForeignKeyCode(rel, table.identifier, tableIdentifierMap));
|
|
@@ -2032,10 +2028,10 @@ function runEnhancers(source, enhancers, context) {
|
|
|
2032
2028
|
let current = source;
|
|
2033
2029
|
const allStats = {};
|
|
2034
2030
|
for (const enhancer of enhancers) {
|
|
2035
|
-
const
|
|
2036
|
-
current =
|
|
2037
|
-
if (
|
|
2038
|
-
allStats[enhancer.name] =
|
|
2031
|
+
const result2 = enhancer.enhance(current, context);
|
|
2032
|
+
current = result2.source;
|
|
2033
|
+
if (result2.stats) {
|
|
2034
|
+
allStats[enhancer.name] = result2.stats;
|
|
2039
2035
|
}
|
|
2040
2036
|
}
|
|
2041
2037
|
return { source: current, allStats };
|
|
@@ -2350,7 +2346,7 @@ var jsonbCommentsEnhancer = {
|
|
|
2350
2346
|
return { source, stats: { commentsAdded: 0 } };
|
|
2351
2347
|
}
|
|
2352
2348
|
const lines = source.split("\n");
|
|
2353
|
-
const
|
|
2349
|
+
const result2 = [];
|
|
2354
2350
|
let commentsAdded = 0;
|
|
2355
2351
|
let currentTableName = null;
|
|
2356
2352
|
for (let i = 0; i < lines.length; i++) {
|
|
@@ -2374,7 +2370,7 @@ var jsonbCommentsEnhancer = {
|
|
|
2374
2370
|
const parsed = parseColumnComment(comment);
|
|
2375
2371
|
const indentMatch = line.match(/^\s*/);
|
|
2376
2372
|
const indent = indentMatch ? indentMatch[0] : "";
|
|
2377
|
-
const prevLine =
|
|
2373
|
+
const prevLine = result2[result2.length - 1]?.trim() ?? "";
|
|
2378
2374
|
if (!prevLine.startsWith("/**") && !prevLine.startsWith("*") && !prevLine.startsWith("//")) {
|
|
2379
2375
|
const commentLines = [];
|
|
2380
2376
|
commentLines.push(`${indent}/**`);
|
|
@@ -2390,7 +2386,7 @@ var jsonbCommentsEnhancer = {
|
|
|
2390
2386
|
commentLines.push(`${indent} * @type ${safeType}`);
|
|
2391
2387
|
}
|
|
2392
2388
|
commentLines.push(`${indent} */`);
|
|
2393
|
-
|
|
2389
|
+
result2.push(...commentLines);
|
|
2394
2390
|
commentsAdded++;
|
|
2395
2391
|
}
|
|
2396
2392
|
}
|
|
@@ -2398,10 +2394,10 @@ var jsonbCommentsEnhancer = {
|
|
|
2398
2394
|
if (line.match(/^\}\);?\s*$/) || line.match(/^}\s*,\s*\{/)) {
|
|
2399
2395
|
currentTableName = null;
|
|
2400
2396
|
}
|
|
2401
|
-
|
|
2397
|
+
result2.push(line);
|
|
2402
2398
|
}
|
|
2403
2399
|
return {
|
|
2404
|
-
source:
|
|
2400
|
+
source: result2.join("\n"),
|
|
2405
2401
|
stats: { commentsAdded }
|
|
2406
2402
|
};
|
|
2407
2403
|
}
|
|
@@ -2464,7 +2460,7 @@ var syncedCommentsEnhancer = {
|
|
|
2464
2460
|
return { source };
|
|
2465
2461
|
}
|
|
2466
2462
|
const lines = source.split("\n");
|
|
2467
|
-
const
|
|
2463
|
+
const result2 = [];
|
|
2468
2464
|
let commentsAdded = 0;
|
|
2469
2465
|
let currentSyncedFields = null;
|
|
2470
2466
|
let insideTableBody = false;
|
|
@@ -2479,11 +2475,11 @@ var syncedCommentsEnhancer = {
|
|
|
2479
2475
|
currentSyncedFields = syncedFields;
|
|
2480
2476
|
insideTableBody = true;
|
|
2481
2477
|
braceDepth = 0;
|
|
2482
|
-
const prevLine =
|
|
2478
|
+
const prevLine = result2[result2.length - 1]?.trim() ?? "";
|
|
2483
2479
|
if (!prevLine.includes("Synced table")) {
|
|
2484
2480
|
const indentMatch = line.match(/^\s*/);
|
|
2485
2481
|
const indent = indentMatch ? indentMatch[0] : "";
|
|
2486
|
-
|
|
2482
|
+
result2.push(`${indent}// ${TABLE_COMMENT}`);
|
|
2487
2483
|
commentsAdded++;
|
|
2488
2484
|
}
|
|
2489
2485
|
}
|
|
@@ -2500,20 +2496,20 @@ var syncedCommentsEnhancer = {
|
|
|
2500
2496
|
if (currentSyncedFields && braceDepth >= 1 && !tableMatch) {
|
|
2501
2497
|
const columnName = extractColumnName(line);
|
|
2502
2498
|
if (columnName && currentSyncedFields.has(columnName)) {
|
|
2503
|
-
const prevLine =
|
|
2499
|
+
const prevLine = result2[result2.length - 1]?.trim() ?? "";
|
|
2504
2500
|
if (!prevLine.includes("Synced field")) {
|
|
2505
2501
|
const indentMatch = line.match(/^\s*/);
|
|
2506
2502
|
const indent = indentMatch ? indentMatch[0] : "";
|
|
2507
|
-
|
|
2503
|
+
result2.push(`${indent}// ${FIELD_COMMENT}`);
|
|
2508
2504
|
commentsAdded++;
|
|
2509
2505
|
}
|
|
2510
2506
|
}
|
|
2511
2507
|
}
|
|
2512
2508
|
}
|
|
2513
|
-
|
|
2509
|
+
result2.push(line);
|
|
2514
2510
|
}
|
|
2515
2511
|
return {
|
|
2516
|
-
source:
|
|
2512
|
+
source: result2.join("\n"),
|
|
2517
2513
|
stats: { commentsAdded }
|
|
2518
2514
|
};
|
|
2519
2515
|
}
|
|
@@ -2584,6 +2580,260 @@ var defaultEnhancers = [
|
|
|
2584
2580
|
formatEnhancer
|
|
2585
2581
|
];
|
|
2586
2582
|
|
|
2583
|
+
// src/validator.ts
|
|
2584
|
+
import { spawnSync } from "child_process";
|
|
2585
|
+
import {
|
|
2586
|
+
existsSync,
|
|
2587
|
+
mkdtempSync,
|
|
2588
|
+
readFileSync,
|
|
2589
|
+
rmSync,
|
|
2590
|
+
writeFileSync
|
|
2591
|
+
} from "fs";
|
|
2592
|
+
import { tmpdir } from "os";
|
|
2593
|
+
import { dirname, delimiter, join, resolve } from "path";
|
|
2594
|
+
function truncateMessage(message) {
|
|
2595
|
+
return message.length > 500 ? `${message.slice(0, 500)}...` : message;
|
|
2596
|
+
}
|
|
2597
|
+
function result(params, startTime) {
|
|
2598
|
+
return {
|
|
2599
|
+
...params,
|
|
2600
|
+
durationMs: Date.now() - startTime
|
|
2601
|
+
};
|
|
2602
|
+
}
|
|
2603
|
+
function findConfigFile(startDir, fileName) {
|
|
2604
|
+
let current = startDir;
|
|
2605
|
+
while (true) {
|
|
2606
|
+
const candidate = join(current, fileName);
|
|
2607
|
+
if (existsSync(candidate)) return candidate;
|
|
2608
|
+
const parent = dirname(current);
|
|
2609
|
+
if (parent === current) return void 0;
|
|
2610
|
+
current = parent;
|
|
2611
|
+
}
|
|
2612
|
+
}
|
|
2613
|
+
function findTsc(cwd) {
|
|
2614
|
+
const localTsc = join(
|
|
2615
|
+
cwd,
|
|
2616
|
+
"node_modules",
|
|
2617
|
+
".bin",
|
|
2618
|
+
process.platform === "win32" ? "tsc.cmd" : "tsc"
|
|
2619
|
+
);
|
|
2620
|
+
if (existsSync(localTsc)) return localTsc;
|
|
2621
|
+
const pathEnv = process.env.PATH ?? "";
|
|
2622
|
+
for (const dir of pathEnv.split(delimiter)) {
|
|
2623
|
+
if (!dir) continue;
|
|
2624
|
+
const candidate = join(
|
|
2625
|
+
dir,
|
|
2626
|
+
process.platform === "win32" ? "tsc.cmd" : "tsc"
|
|
2627
|
+
);
|
|
2628
|
+
if (existsSync(candidate)) return candidate;
|
|
2629
|
+
}
|
|
2630
|
+
return void 0;
|
|
2631
|
+
}
|
|
2632
|
+
function resolveProjectPath(params) {
|
|
2633
|
+
if (params.project) return resolve(params.cwd, params.project);
|
|
2634
|
+
return findConfigFile(dirname(params.inputPath), "tsconfig.node.json") ?? findConfigFile(dirname(params.inputPath), "tsconfig.json");
|
|
2635
|
+
}
|
|
2636
|
+
function createValidationTsconfig(params) {
|
|
2637
|
+
const dir = mkdtempSync(join(tmpdir(), "db-schema-sync-validate-"));
|
|
2638
|
+
const configPath = join(dir, "tsconfig.schema-validation.json");
|
|
2639
|
+
const compilerOptions = {
|
|
2640
|
+
noEmit: true,
|
|
2641
|
+
skipLibCheck: true,
|
|
2642
|
+
types: [],
|
|
2643
|
+
rootDir: dirname(params.inputPath)
|
|
2644
|
+
};
|
|
2645
|
+
const config = params.projectPath ? {
|
|
2646
|
+
extends: params.projectPath,
|
|
2647
|
+
compilerOptions,
|
|
2648
|
+
files: [params.inputPath],
|
|
2649
|
+
include: [],
|
|
2650
|
+
exclude: []
|
|
2651
|
+
} : {
|
|
2652
|
+
compilerOptions: {
|
|
2653
|
+
target: "ES2022",
|
|
2654
|
+
module: "NodeNext",
|
|
2655
|
+
moduleResolution: "NodeNext",
|
|
2656
|
+
esModuleInterop: true,
|
|
2657
|
+
strict: false,
|
|
2658
|
+
...compilerOptions
|
|
2659
|
+
},
|
|
2660
|
+
files: [params.inputPath],
|
|
2661
|
+
include: [],
|
|
2662
|
+
exclude: []
|
|
2663
|
+
};
|
|
2664
|
+
writeFileSync(configPath, JSON.stringify(config), "utf8");
|
|
2665
|
+
return { dir, path: configPath };
|
|
2666
|
+
}
|
|
2667
|
+
function runTsc(tscPath, cwd, args) {
|
|
2668
|
+
return spawnSync(tscPath, args, {
|
|
2669
|
+
cwd,
|
|
2670
|
+
encoding: "utf8",
|
|
2671
|
+
maxBuffer: 1024 * 1024
|
|
2672
|
+
});
|
|
2673
|
+
}
|
|
2674
|
+
function getTscOutput(output) {
|
|
2675
|
+
return truncateMessage(
|
|
2676
|
+
[output.stdout, output.stderr].filter(Boolean).join("\n").trim()
|
|
2677
|
+
);
|
|
2678
|
+
}
|
|
2679
|
+
function getFirstDiagnosticCode(output) {
|
|
2680
|
+
const match = output.match(/error TS(\d+):/);
|
|
2681
|
+
return match ? Number(match[1]) : void 0;
|
|
2682
|
+
}
|
|
2683
|
+
function isSyntaxDiagnostic(output) {
|
|
2684
|
+
const code = getFirstDiagnosticCode(output);
|
|
2685
|
+
return typeof code === "number" && code >= 1e3 && code < 2e3;
|
|
2686
|
+
}
|
|
2687
|
+
function isConfigDiagnostic(output) {
|
|
2688
|
+
const code = getFirstDiagnosticCode(output);
|
|
2689
|
+
return typeof code === "number" && code >= 5e3 && code < 6e3 || /tsconfig(?:\.[\w-]+)?\.json/i.test(output);
|
|
2690
|
+
}
|
|
2691
|
+
function isNoCheckUnsupported(output) {
|
|
2692
|
+
return /Unknown compiler option ['"]?--?noCheck['"]?/i.test(output);
|
|
2693
|
+
}
|
|
2694
|
+
function classifyFailedTscOutput(output) {
|
|
2695
|
+
if (isConfigDiagnostic(output)) {
|
|
2696
|
+
return {
|
|
2697
|
+
status: "inconclusive",
|
|
2698
|
+
errorType: "validation_runner_failed",
|
|
2699
|
+
message: output || "TypeScript validation runner failed"
|
|
2700
|
+
};
|
|
2701
|
+
}
|
|
2702
|
+
if (isSyntaxDiagnostic(output)) {
|
|
2703
|
+
return {
|
|
2704
|
+
status: "invalid_artifact",
|
|
2705
|
+
errorType: "generated_schema_syntax_error",
|
|
2706
|
+
message: output || "TypeScript syntax validation failed"
|
|
2707
|
+
};
|
|
2708
|
+
}
|
|
2709
|
+
if (getFirstDiagnosticCode(output) === void 0) {
|
|
2710
|
+
return {
|
|
2711
|
+
status: "inconclusive",
|
|
2712
|
+
errorType: "validation_runner_failed",
|
|
2713
|
+
message: output || "TypeScript validation runner failed"
|
|
2714
|
+
};
|
|
2715
|
+
}
|
|
2716
|
+
return {
|
|
2717
|
+
status: "invalid_artifact",
|
|
2718
|
+
errorType: "generated_schema_type_error",
|
|
2719
|
+
message: output || "TypeScript validation failed"
|
|
2720
|
+
};
|
|
2721
|
+
}
|
|
2722
|
+
function validateGeneratedSchema(options) {
|
|
2723
|
+
const startTime = Date.now();
|
|
2724
|
+
const cwd = options.cwd ?? process.cwd();
|
|
2725
|
+
const inputPath = resolve(cwd, options.input);
|
|
2726
|
+
try {
|
|
2727
|
+
if (!existsSync(inputPath)) {
|
|
2728
|
+
return result(
|
|
2729
|
+
{
|
|
2730
|
+
ok: false,
|
|
2731
|
+
status: "invalid_artifact",
|
|
2732
|
+
errorType: "generated_schema_missing",
|
|
2733
|
+
message: `Generated schema file not found: ${options.input}`
|
|
2734
|
+
},
|
|
2735
|
+
startTime
|
|
2736
|
+
);
|
|
2737
|
+
}
|
|
2738
|
+
if (!readFileSync(inputPath, "utf8").trim()) {
|
|
2739
|
+
return result(
|
|
2740
|
+
{
|
|
2741
|
+
ok: false,
|
|
2742
|
+
status: "invalid_artifact",
|
|
2743
|
+
errorType: "generated_schema_missing",
|
|
2744
|
+
message: `Generated schema file is empty: ${options.input}`
|
|
2745
|
+
},
|
|
2746
|
+
startTime
|
|
2747
|
+
);
|
|
2748
|
+
}
|
|
2749
|
+
const tscPath = findTsc(cwd);
|
|
2750
|
+
if (!tscPath) {
|
|
2751
|
+
return result(
|
|
2752
|
+
{
|
|
2753
|
+
ok: false,
|
|
2754
|
+
status: "inconclusive",
|
|
2755
|
+
errorType: "validation_runner_failed",
|
|
2756
|
+
message: "TypeScript compiler not found in sandbox. Please install project dependencies so node_modules/.bin/tsc is available."
|
|
2757
|
+
},
|
|
2758
|
+
startTime
|
|
2759
|
+
);
|
|
2760
|
+
}
|
|
2761
|
+
const projectPath = resolveProjectPath({
|
|
2762
|
+
cwd,
|
|
2763
|
+
inputPath,
|
|
2764
|
+
project: options.project
|
|
2765
|
+
});
|
|
2766
|
+
const tempConfig = createValidationTsconfig({ inputPath, projectPath });
|
|
2767
|
+
try {
|
|
2768
|
+
const syntaxOnly = runTsc(tscPath, cwd, [
|
|
2769
|
+
"--noEmit",
|
|
2770
|
+
"--pretty",
|
|
2771
|
+
"false",
|
|
2772
|
+
"--project",
|
|
2773
|
+
tempConfig.path,
|
|
2774
|
+
"--noCheck"
|
|
2775
|
+
]);
|
|
2776
|
+
const syntaxOutput = getTscOutput(syntaxOnly);
|
|
2777
|
+
if (syntaxOnly.error) {
|
|
2778
|
+
throw syntaxOnly.error;
|
|
2779
|
+
}
|
|
2780
|
+
if (syntaxOnly.status !== 0 && !isNoCheckUnsupported(syntaxOutput)) {
|
|
2781
|
+
const failure = classifyFailedTscOutput(syntaxOutput);
|
|
2782
|
+
return result(
|
|
2783
|
+
{
|
|
2784
|
+
ok: false,
|
|
2785
|
+
...failure
|
|
2786
|
+
},
|
|
2787
|
+
startTime
|
|
2788
|
+
);
|
|
2789
|
+
}
|
|
2790
|
+
const fullCheck = runTsc(tscPath, cwd, [
|
|
2791
|
+
"--noEmit",
|
|
2792
|
+
"--pretty",
|
|
2793
|
+
"false",
|
|
2794
|
+
"--project",
|
|
2795
|
+
tempConfig.path
|
|
2796
|
+
]);
|
|
2797
|
+
const fullOutput = getTscOutput(fullCheck);
|
|
2798
|
+
if (fullCheck.error) {
|
|
2799
|
+
throw fullCheck.error;
|
|
2800
|
+
}
|
|
2801
|
+
if (fullCheck.status !== 0) {
|
|
2802
|
+
const failure = classifyFailedTscOutput(fullOutput);
|
|
2803
|
+
return result(
|
|
2804
|
+
{
|
|
2805
|
+
ok: false,
|
|
2806
|
+
...failure
|
|
2807
|
+
},
|
|
2808
|
+
startTime
|
|
2809
|
+
);
|
|
2810
|
+
}
|
|
2811
|
+
} finally {
|
|
2812
|
+
rmSync(tempConfig.dir, { recursive: true, force: true });
|
|
2813
|
+
}
|
|
2814
|
+
return result(
|
|
2815
|
+
{
|
|
2816
|
+
ok: true,
|
|
2817
|
+
status: "success",
|
|
2818
|
+
errorType: "none"
|
|
2819
|
+
},
|
|
2820
|
+
startTime
|
|
2821
|
+
);
|
|
2822
|
+
} catch (error) {
|
|
2823
|
+
return result(
|
|
2824
|
+
{
|
|
2825
|
+
ok: false,
|
|
2826
|
+
status: "inconclusive",
|
|
2827
|
+
errorType: "validation_runner_failed",
|
|
2828
|
+
message: truncateMessage(
|
|
2829
|
+
error instanceof Error ? error.message : String(error)
|
|
2830
|
+
)
|
|
2831
|
+
},
|
|
2832
|
+
startTime
|
|
2833
|
+
);
|
|
2834
|
+
}
|
|
2835
|
+
}
|
|
2836
|
+
|
|
2587
2837
|
// src/index.ts
|
|
2588
2838
|
async function generateSchema(options) {
|
|
2589
2839
|
const schemaData = await fetchSchemaData(options);
|
|
@@ -2607,6 +2857,7 @@ export {
|
|
|
2607
2857
|
resolveEnvOptions,
|
|
2608
2858
|
normalizeApiResponse,
|
|
2609
2859
|
generateSchemaCode,
|
|
2860
|
+
validateGeneratedSchema,
|
|
2610
2861
|
generateSchema,
|
|
2611
2862
|
generateSchemaFromData
|
|
2612
2863
|
};
|
package/dist/index.d.ts
CHANGED
|
@@ -170,6 +170,22 @@ declare function normalizeApiResponse(response: ApiTableViewResponse | null | un
|
|
|
170
170
|
|
|
171
171
|
declare function generateSchemaCode(data: SchemaData): string;
|
|
172
172
|
|
|
173
|
+
type SchemaValidationStatus = 'success' | 'invalid_artifact' | 'inconclusive';
|
|
174
|
+
type SchemaValidationErrorType = 'none' | 'generated_schema_missing' | 'generated_schema_syntax_error' | 'generated_schema_type_error' | 'validation_runner_failed';
|
|
175
|
+
interface SchemaValidationOutput {
|
|
176
|
+
ok: boolean;
|
|
177
|
+
status: SchemaValidationStatus;
|
|
178
|
+
errorType: SchemaValidationErrorType;
|
|
179
|
+
durationMs: number;
|
|
180
|
+
message?: string;
|
|
181
|
+
}
|
|
182
|
+
interface ValidateGeneratedSchemaOptions {
|
|
183
|
+
input: string;
|
|
184
|
+
project?: string;
|
|
185
|
+
cwd?: string;
|
|
186
|
+
}
|
|
187
|
+
declare function validateGeneratedSchema(options: ValidateGeneratedSchemaOptions): SchemaValidationOutput;
|
|
188
|
+
|
|
173
189
|
interface GenerateSchemaOptions extends FetchOptions {
|
|
174
190
|
/** Skip specific enhancers by name */
|
|
175
191
|
skipEnhancers?: string[];
|
|
@@ -189,4 +205,4 @@ declare function generateSchemaFromData(schemaData: SchemaData, options?: {
|
|
|
189
205
|
exportCustomTypes?: boolean;
|
|
190
206
|
}): string;
|
|
191
207
|
|
|
192
|
-
export { type EnumSchema, type FetchOptions, type FieldSchema, type GenerateSchemaOptions, type SchemaData, type TableSchema, type ViewSchema, generateSchema, generateSchemaCode, generateSchemaFromData, normalizeApiResponse, resolveEnvOptions };
|
|
208
|
+
export { type EnumSchema, type FetchOptions, type FieldSchema, type GenerateSchemaOptions, type SchemaData, type SchemaValidationErrorType, type SchemaValidationOutput, type SchemaValidationStatus, type TableSchema, type ViewSchema, generateSchema, generateSchemaCode, generateSchemaFromData, normalizeApiResponse, resolveEnvOptions, validateGeneratedSchema };
|
package/dist/index.js
CHANGED
|
@@ -4,12 +4,14 @@ import {
|
|
|
4
4
|
generateSchemaCode,
|
|
5
5
|
generateSchemaFromData,
|
|
6
6
|
normalizeApiResponse,
|
|
7
|
-
resolveEnvOptions
|
|
8
|
-
|
|
7
|
+
resolveEnvOptions,
|
|
8
|
+
validateGeneratedSchema
|
|
9
|
+
} from "./chunk-UWBHRXTA.js";
|
|
9
10
|
export {
|
|
10
11
|
generateSchema,
|
|
11
12
|
generateSchemaCode,
|
|
12
13
|
generateSchemaFromData,
|
|
13
14
|
normalizeApiResponse,
|
|
14
|
-
resolveEnvOptions
|
|
15
|
+
resolveEnvOptions,
|
|
16
|
+
validateGeneratedSchema
|
|
15
17
|
};
|