@toiroakr/lines-db 0.6.1 → 0.8.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/CHANGELOG.md +27 -0
- package/bin/cli.js +163 -59
- package/dist/index.cjs +126 -31
- package/dist/index.d.cts +38 -2
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.ts +38 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +121 -31
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/cli.ts +121 -57
- package/src/database.test.ts +28 -0
- package/src/database.ts +89 -18
- package/src/index.ts +9 -0
- package/src/schema-extensions.test.ts +155 -0
- package/src/schema-extensions.ts +86 -0
- package/src/schema-loader.test.ts +90 -0
- package/src/schema-loader.ts +10 -18
- package/src/type-generator.ts +12 -10
- package/src/types.ts +9 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,32 @@
|
|
|
1
1
|
# @toiroakr/lines-db
|
|
2
2
|
|
|
3
|
+
## 0.8.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- c408b92: feat: display per-table validation results for directory validation
|
|
8
|
+
|
|
9
|
+
The `validate` command now shows individual results per table when validating a directory, including record counts for successful tables (e.g., `✓ users (3 records)`).
|
|
10
|
+
- Added `TableValidationResult` type and `tableResults` field to `ValidationResult`
|
|
11
|
+
- Each table result includes `tableName`, `valid`, `rowCount`, `errors`, and `warnings`
|
|
12
|
+
|
|
13
|
+
### Patch Changes
|
|
14
|
+
|
|
15
|
+
- e61a4ee: fix: gracefully handle foreign key validation when referenced table has errors
|
|
16
|
+
|
|
17
|
+
When validating a directory, if a table had validation errors, any table referencing it via foreign key would crash with a misleading `no such table` SQLite error. Now, foreign key constraints to failed tables are skipped with a clear warning (e.g., `⚠ Skipping foreign key validation for table 'child': referenced table 'parent' has validation errors`), and the child table's own schema validation still runs normally.
|
|
18
|
+
|
|
19
|
+
## 0.7.0
|
|
20
|
+
|
|
21
|
+
### Minor Changes
|
|
22
|
+
|
|
23
|
+
- 4597383: feat: support .mts and .cts schema file extensions
|
|
24
|
+
|
|
25
|
+
Schema files are now auto-detected with the following priority: `.schema.ts` > `.schema.mts` > `.schema.cts`. Mixed extensions within a single project are supported.
|
|
26
|
+
- Added `--output` option to `generate` command for specifying the output file path (e.g., `--output ./data/db.mts`)
|
|
27
|
+
- Import paths are correctly rewritten: `.ts`→`.js`, `.mts`→`.mjs`, `.cts`→`.cjs`
|
|
28
|
+
- New exported utilities: `findSchemaFile`, `isSchemaFile`, `extractTableNameFromSchemaFile`, `rewriteExtensionForImport`, `SCHEMA_EXTENSIONS`
|
|
29
|
+
|
|
3
30
|
## 0.6.1
|
|
4
31
|
|
|
5
32
|
### Patch Changes
|
package/bin/cli.js
CHANGED
|
@@ -10,6 +10,57 @@ import { runInNewContext } from "node:vm";
|
|
|
10
10
|
//#region rolldown:runtime
|
|
11
11
|
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
12
12
|
|
|
13
|
+
//#endregion
|
|
14
|
+
//#region src/schema-extensions.ts
|
|
15
|
+
/**
|
|
16
|
+
* Supported schema file extensions, in priority order.
|
|
17
|
+
* The first match wins when discovering schema files.
|
|
18
|
+
*/
|
|
19
|
+
const SCHEMA_EXTENSIONS = [
|
|
20
|
+
".schema.ts",
|
|
21
|
+
".schema.mts",
|
|
22
|
+
".schema.cts"
|
|
23
|
+
];
|
|
24
|
+
/**
|
|
25
|
+
* Map from schema extensions to their JavaScript import counterparts.
|
|
26
|
+
*/
|
|
27
|
+
const SCHEMA_TO_JS_IMPORT_MAP = {
|
|
28
|
+
".schema.ts": ".schema.js",
|
|
29
|
+
".schema.mts": ".schema.mjs",
|
|
30
|
+
".schema.cts": ".schema.cjs"
|
|
31
|
+
};
|
|
32
|
+
/**
|
|
33
|
+
* Try each supported schema extension and return the full path of the first
|
|
34
|
+
* one that exists on disk. Returns undefined if none is found.
|
|
35
|
+
*/
|
|
36
|
+
async function findSchemaFile(dir, tableName) {
|
|
37
|
+
for (const ext of SCHEMA_EXTENSIONS) {
|
|
38
|
+
const candidate = join(dir, `${tableName}${ext}`);
|
|
39
|
+
try {
|
|
40
|
+
await access(candidate);
|
|
41
|
+
return candidate;
|
|
42
|
+
} catch {}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Synchronously find a schema file among directory entries.
|
|
47
|
+
* Returns the full path of the first match, or undefined.
|
|
48
|
+
*/
|
|
49
|
+
function findSchemaFileInEntries(dataDirPath, tableName, entries) {
|
|
50
|
+
for (const ext of SCHEMA_EXTENSIONS) {
|
|
51
|
+
const candidateName = `${tableName}${ext}`;
|
|
52
|
+
if (entries.some((e) => e.isFile() && e.name === candidateName)) return join(dataDirPath, candidateName);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Rewrite a TypeScript path to its JavaScript counterpart for ESM imports.
|
|
57
|
+
* ".schema.ts" -> ".schema.js", ".schema.mts" -> ".schema.mjs", ".schema.cts" -> ".schema.cjs"
|
|
58
|
+
*/
|
|
59
|
+
function rewriteExtensionForImport(filePath) {
|
|
60
|
+
for (const [tsExt, jsExt] of Object.entries(SCHEMA_TO_JS_IMPORT_MAP)) if (filePath.endsWith(tsExt)) return filePath.slice(0, -tsExt.length) + jsExt;
|
|
61
|
+
return filePath;
|
|
62
|
+
}
|
|
63
|
+
|
|
13
64
|
//#endregion
|
|
14
65
|
//#region src/type-generator.ts
|
|
15
66
|
var TypeGenerator = class {
|
|
@@ -22,7 +73,7 @@ var TypeGenerator = class {
|
|
|
22
73
|
this.projectRoot = envProjectRoot !== void 0 ? envProjectRoot : options.projectRoot || process.cwd();
|
|
23
74
|
this.dataDir = options.dataDir;
|
|
24
75
|
this.dataDirPath = isAbsolute(this.dataDir) ? this.dataDir : join(this.projectRoot, this.dataDir);
|
|
25
|
-
this.outputFile = join(this.dataDirPath, "db.ts");
|
|
76
|
+
this.outputFile = options.output ? isAbsolute(options.output) ? options.output : join(this.projectRoot, options.output) : join(this.dataDirPath, "db.ts");
|
|
26
77
|
}
|
|
27
78
|
/**
|
|
28
79
|
* Generate types file from JSONL files and their optional schema files.
|
|
@@ -45,12 +96,10 @@ var TypeGenerator = class {
|
|
|
45
96
|
const tables = [];
|
|
46
97
|
for (const entry of entries) if (entry.isFile() && entry.name.endsWith(".jsonl")) {
|
|
47
98
|
const tableName = basename(entry.name, ".jsonl");
|
|
48
|
-
const
|
|
49
|
-
const schemaFilePath = join(this.dataDirPath, schemaFileName);
|
|
50
|
-
const hasSchema = entries.some((e) => e.isFile() && e.name === schemaFileName);
|
|
99
|
+
const schemaFilePath = findSchemaFileInEntries(this.dataDirPath, tableName, entries);
|
|
51
100
|
tables.push({
|
|
52
101
|
tableName,
|
|
53
|
-
schemaFile:
|
|
102
|
+
schemaFile: schemaFilePath
|
|
54
103
|
});
|
|
55
104
|
}
|
|
56
105
|
return tables;
|
|
@@ -71,7 +120,7 @@ var TypeGenerator = class {
|
|
|
71
120
|
if (table.schemaFile) {
|
|
72
121
|
const schemaIdentifier = this.createSchemaIdentifier(table.tableName, usedAliases);
|
|
73
122
|
usedAliases.add(schemaIdentifier);
|
|
74
|
-
let relativePath = relative(join(this.outputFile, ".."), table.schemaFile).replace(/\\/g, "/")
|
|
123
|
+
let relativePath = rewriteExtensionForImport(relative(join(this.outputFile, ".."), table.schemaFile).replace(/\\/g, "/"));
|
|
75
124
|
if (!relativePath.startsWith(".")) relativePath = "./" + relativePath;
|
|
76
125
|
imports.push(`import { schema as ${schemaIdentifier} } from '${relativePath}';`);
|
|
77
126
|
tableEntries.push(` ${tableKey}: InferOutput<typeof ${schemaIdentifier}>;`);
|
|
@@ -279,27 +328,17 @@ var SchemaLoader = class {
|
|
|
279
328
|
* Check if a schema file exists for a table
|
|
280
329
|
*/
|
|
281
330
|
static async hasSchema(jsonlPath) {
|
|
282
|
-
|
|
283
|
-
try {
|
|
284
|
-
await access(schemaPath);
|
|
285
|
-
return true;
|
|
286
|
-
} catch {
|
|
287
|
-
return false;
|
|
288
|
-
}
|
|
331
|
+
return await findSchemaFile(dirname(jsonlPath), basename(jsonlPath, ".jsonl")) !== void 0;
|
|
289
332
|
}
|
|
290
333
|
/**
|
|
291
334
|
* Load a validation schema file for a table
|
|
292
|
-
* Requires ${tableName}.schema.ts to exist alongside the JSONL file
|
|
335
|
+
* Requires ${tableName}.schema.{ts,mts,cts} to exist alongside the JSONL file
|
|
293
336
|
*/
|
|
294
337
|
static async loadSchema(jsonlPath) {
|
|
295
338
|
const dir = dirname(jsonlPath);
|
|
296
339
|
const tableName = basename(jsonlPath, ".jsonl");
|
|
297
|
-
const schemaPath =
|
|
298
|
-
|
|
299
|
-
await access(schemaPath);
|
|
300
|
-
} catch (error) {
|
|
301
|
-
throw new Error(`Schema file not found for table '${tableName}'. Expected: ${schemaPath}`, { cause: error instanceof Error ? error : void 0 });
|
|
302
|
-
}
|
|
340
|
+
const schemaPath = await findSchemaFile(dir, tableName);
|
|
341
|
+
if (!schemaPath) throw new Error(`Schema file not found for table '${tableName}'. Expected one of: ${SCHEMA_EXTENSIONS.map((ext) => `${tableName}${ext}`).join(", ")}`);
|
|
303
342
|
try {
|
|
304
343
|
const module = await import(`${pathToFileURL(schemaPath).href}?t=${Date.now()}`);
|
|
305
344
|
const schema = module.default || module.schema;
|
|
@@ -384,6 +423,7 @@ var LinesDB = class LinesDB {
|
|
|
384
423
|
async initialize(options) {
|
|
385
424
|
const allErrors = [];
|
|
386
425
|
const allWarnings = [];
|
|
426
|
+
const allRowCounts = /* @__PURE__ */ new Map();
|
|
387
427
|
const tableName = options?.tableName;
|
|
388
428
|
const detailedValidate = options?.detailedValidate ?? false;
|
|
389
429
|
const transform = options?.transform;
|
|
@@ -395,14 +435,27 @@ var LinesDB = class LinesDB {
|
|
|
395
435
|
const attemptedTables = /* @__PURE__ */ new Set();
|
|
396
436
|
for (const tableNameToLoad of tablesToLoad) if (!attemptedTables.has(tableNameToLoad)) {
|
|
397
437
|
const tableTransform = tableNameToLoad === tableName ? transform : void 0;
|
|
398
|
-
const { errors, warnings } = await this.loadTableWithDependencies(tableNameToLoad, loadedTables, loadingTables, attemptedTables, detailedValidate, tableTransform);
|
|
438
|
+
const { errors, warnings, rowCounts: tableRowCounts } = await this.loadTableWithDependencies(tableNameToLoad, loadedTables, loadingTables, attemptedTables, detailedValidate, tableTransform);
|
|
399
439
|
allErrors.push(...errors);
|
|
400
440
|
allWarnings.push(...warnings);
|
|
441
|
+
for (const [k, v] of tableRowCounts) allRowCounts.set(k, v);
|
|
401
442
|
}
|
|
443
|
+
const tableResults = tablesToLoad.map((name) => {
|
|
444
|
+
const tableErrors = allErrors.filter((e) => e.tableName === name);
|
|
445
|
+
const tableWarnings = allWarnings.filter((w) => w.includes(`'${name}'`));
|
|
446
|
+
return {
|
|
447
|
+
tableName: name,
|
|
448
|
+
valid: tableErrors.length === 0,
|
|
449
|
+
rowCount: allRowCounts.get(name) ?? 0,
|
|
450
|
+
errors: tableErrors,
|
|
451
|
+
warnings: tableWarnings
|
|
452
|
+
};
|
|
453
|
+
});
|
|
402
454
|
return {
|
|
403
455
|
valid: allErrors.length === 0,
|
|
404
456
|
errors: allErrors,
|
|
405
|
-
warnings: allWarnings
|
|
457
|
+
warnings: allWarnings,
|
|
458
|
+
tableResults
|
|
406
459
|
};
|
|
407
460
|
}
|
|
408
461
|
/**
|
|
@@ -411,9 +464,11 @@ var LinesDB = class LinesDB {
|
|
|
411
464
|
async loadTableWithDependencies(tableName, loadedTables, loadingTables, attemptedTables, detailedValidate, transform) {
|
|
412
465
|
const errors = [];
|
|
413
466
|
const warnings = [];
|
|
467
|
+
const rowCounts = /* @__PURE__ */ new Map();
|
|
414
468
|
if (attemptedTables.has(tableName)) return {
|
|
415
469
|
errors,
|
|
416
|
-
warnings
|
|
470
|
+
warnings,
|
|
471
|
+
rowCounts
|
|
417
472
|
};
|
|
418
473
|
attemptedTables.add(tableName);
|
|
419
474
|
if (loadingTables.has(tableName)) throw new Error(`Circular dependency detected for table '${tableName}'`);
|
|
@@ -424,8 +479,11 @@ var LinesDB = class LinesDB {
|
|
|
424
479
|
let foreignKeys;
|
|
425
480
|
try {
|
|
426
481
|
const { pathToFileURL: pathToFileURL$1 } = await import("node:url");
|
|
427
|
-
const
|
|
428
|
-
|
|
482
|
+
const schemaPath = await findSchemaFile(dirname(tableConfig.jsonlPath), basename(tableConfig.jsonlPath, ".jsonl"));
|
|
483
|
+
if (schemaPath) {
|
|
484
|
+
const schemaModule = await import(`${pathToFileURL$1(schemaPath).href}?t=${Date.now()}`);
|
|
485
|
+
foreignKeys = (schemaModule.schema || schemaModule.default)?.foreignKeys || schemaModule.foreignKeys;
|
|
486
|
+
}
|
|
429
487
|
} catch {}
|
|
430
488
|
if (foreignKeys && foreignKeys.length > 0) for (const fk of foreignKeys) {
|
|
431
489
|
const referencedTable = fk.references.table;
|
|
@@ -434,10 +492,21 @@ var LinesDB = class LinesDB {
|
|
|
434
492
|
const depResult = await this.loadTableWithDependencies(referencedTable, loadedTables, loadingTables, attemptedTables, detailedValidate, void 0);
|
|
435
493
|
errors.push(...depResult.errors);
|
|
436
494
|
warnings.push(...depResult.warnings);
|
|
495
|
+
for (const [k, v] of depResult.rowCounts) rowCounts.set(k, v);
|
|
437
496
|
} else throw new Error(`Foreign key reference to non-existent table '${referencedTable}' in table '${tableName}'`);
|
|
438
497
|
}
|
|
439
|
-
const
|
|
498
|
+
const failedDependencies = /* @__PURE__ */ new Set();
|
|
499
|
+
if (foreignKeys && foreignKeys.length > 0) {
|
|
500
|
+
for (const fk of foreignKeys) {
|
|
501
|
+
const referencedTable = fk.references.table;
|
|
502
|
+
if (referencedTable === tableName) continue;
|
|
503
|
+
if (attemptedTables.has(referencedTable) && !loadedTables.has(referencedTable)) failedDependencies.add(referencedTable);
|
|
504
|
+
}
|
|
505
|
+
if (failedDependencies.size > 0) for (const dep of failedDependencies) warnings.push(`Skipping foreign key validation for table '${tableName}': referenced table '${dep}' has validation errors`);
|
|
506
|
+
}
|
|
507
|
+
const { loaded, rowCount, errors: loadErrors } = await this.loadTable(tableName, tableConfig, detailedValidate, transform, failedDependencies);
|
|
440
508
|
errors.push(...loadErrors);
|
|
509
|
+
rowCounts.set(tableName, rowCount);
|
|
441
510
|
if (loaded) loadedTables.add(tableName);
|
|
442
511
|
else {
|
|
443
512
|
warnings.push(`Table '${tableName}' was not loaded (no data or skipped)`);
|
|
@@ -448,14 +517,15 @@ var LinesDB = class LinesDB {
|
|
|
448
517
|
}
|
|
449
518
|
return {
|
|
450
519
|
errors,
|
|
451
|
-
warnings
|
|
520
|
+
warnings,
|
|
521
|
+
rowCounts
|
|
452
522
|
};
|
|
453
523
|
}
|
|
454
524
|
/**
|
|
455
525
|
* Load a single table from JSONL file
|
|
456
526
|
* @returns Object with loaded status and validation errors
|
|
457
527
|
*/
|
|
458
|
-
async loadTable(tableName, config, detailedValidate, transform) {
|
|
528
|
+
async loadTable(tableName, config, detailedValidate, transform, failedDependencies) {
|
|
459
529
|
let data = await JsonlReader.read(config.jsonlPath);
|
|
460
530
|
if (transform) data = data.map((row) => transform(row));
|
|
461
531
|
let validationSchema = config.validationSchema;
|
|
@@ -465,7 +535,9 @@ var LinesDB = class LinesDB {
|
|
|
465
535
|
} catch (_error) {}
|
|
466
536
|
if (!config.validationSchema) try {
|
|
467
537
|
const { pathToFileURL: pathToFileURL$1 } = await import("node:url");
|
|
468
|
-
const
|
|
538
|
+
const schemaPath = await findSchemaFile(dirname(config.jsonlPath), basename(config.jsonlPath, ".jsonl"));
|
|
539
|
+
if (!schemaPath) throw new Error("Schema file not found");
|
|
540
|
+
const schemaModule = await import(`${pathToFileURL$1(schemaPath).href}?t=${Date.now()}`);
|
|
469
541
|
const schemaExport = schemaModule.schema || schemaModule.default;
|
|
470
542
|
if (schemaExport?.primaryKey) schemaMetadata.primaryKey = schemaExport.primaryKey;
|
|
471
543
|
else if (schemaModule.primaryKey) schemaMetadata.primaryKey = schemaModule.primaryKey;
|
|
@@ -508,6 +580,7 @@ var LinesDB = class LinesDB {
|
|
|
508
580
|
}));
|
|
509
581
|
if (validationErrors.length > 0) return {
|
|
510
582
|
loaded: false,
|
|
583
|
+
rowCount: data.length,
|
|
511
584
|
errors: validationErrorDetails
|
|
512
585
|
};
|
|
513
586
|
let schema;
|
|
@@ -522,6 +595,7 @@ var LinesDB = class LinesDB {
|
|
|
522
595
|
} else if (config.autoInferSchema !== false) {
|
|
523
596
|
if (validatedData.length === 0) return {
|
|
524
597
|
loaded: false,
|
|
598
|
+
rowCount: 0,
|
|
525
599
|
errors: []
|
|
526
600
|
};
|
|
527
601
|
schema = inferredSchema;
|
|
@@ -537,7 +611,7 @@ var LinesDB = class LinesDB {
|
|
|
537
611
|
const idColumn = schema.columns.find((c) => c.name === "id");
|
|
538
612
|
if (idColumn) idColumn.primaryKey = true;
|
|
539
613
|
}
|
|
540
|
-
if (foreignKeys) schema.foreignKeys = foreignKeys;
|
|
614
|
+
if (foreignKeys) schema.foreignKeys = failedDependencies && failedDependencies.size > 0 ? foreignKeys.filter((fk) => !failedDependencies.has(fk.references.table)) : foreignKeys;
|
|
541
615
|
if (indexes) {
|
|
542
616
|
schema.indexes = indexes;
|
|
543
617
|
for (const index of indexes) if (index.unique && index.columns.length === 1) {
|
|
@@ -551,11 +625,13 @@ var LinesDB = class LinesDB {
|
|
|
551
625
|
const insertErrors = this.insertDataWithDetailedValidation(tableName, schema, validatedData, config.jsonlPath);
|
|
552
626
|
if (insertErrors.length > 0) return {
|
|
553
627
|
loaded: false,
|
|
628
|
+
rowCount: data.length,
|
|
554
629
|
errors: insertErrors
|
|
555
630
|
};
|
|
556
631
|
} else this.insertData(tableName, schema, validatedData);
|
|
557
632
|
return {
|
|
558
633
|
loaded: true,
|
|
634
|
+
rowCount: data.length,
|
|
559
635
|
errors: []
|
|
560
636
|
};
|
|
561
637
|
}
|
|
@@ -1277,9 +1353,12 @@ function runInSandbox(expression, context = {}) {
|
|
|
1277
1353
|
}
|
|
1278
1354
|
const program = new Command();
|
|
1279
1355
|
program.name("@toiroakr/lines-db").description("Database utilities for JSONL files").version("1.0.0");
|
|
1280
|
-
program.command("generate").description("Generate TypeScript type definitions from schema files").argument("<dataDir>", "Directory containing JSONL and schema files").action(async (dataDir) => {
|
|
1356
|
+
program.command("generate").description("Generate TypeScript type definitions from schema files").argument("<dataDir>", "Directory containing JSONL and schema files").option("-o, --output <path>", "Output file path (default: db.ts in dataDir)").action(async (dataDir, options) => {
|
|
1281
1357
|
try {
|
|
1282
|
-
await new TypeGenerator({
|
|
1358
|
+
await new TypeGenerator({
|
|
1359
|
+
dataDir,
|
|
1360
|
+
output: options.output
|
|
1361
|
+
}).generate();
|
|
1283
1362
|
console.log("Type generation completed successfully!");
|
|
1284
1363
|
} catch (error) {
|
|
1285
1364
|
console.error("Error:", error instanceof Error ? error.message : String(error));
|
|
@@ -1306,48 +1385,73 @@ program.command("validate").description("Validate JSONL file(s) against schema")
|
|
|
1306
1385
|
} finally {
|
|
1307
1386
|
await db.close();
|
|
1308
1387
|
}
|
|
1309
|
-
if (
|
|
1310
|
-
for (const warning of result.warnings) console.warn(styleText("yellow", `⚠ ${warning}`));
|
|
1311
|
-
console.log("");
|
|
1312
|
-
}
|
|
1313
|
-
if (result.valid) {
|
|
1314
|
-
console.log("✓ All records are valid");
|
|
1315
|
-
process.exit(0);
|
|
1316
|
-
} else {
|
|
1388
|
+
if (!tableName) {
|
|
1317
1389
|
const formatter = new ErrorFormatter({ verbose: options.verbose });
|
|
1318
|
-
const
|
|
1319
|
-
for (const
|
|
1320
|
-
|
|
1321
|
-
fileErrors.
|
|
1322
|
-
|
|
1323
|
-
}
|
|
1324
|
-
for (const [file, fileErrors] of errorsByFile) {
|
|
1325
|
-
console.error(formatter.formatErrorHeader(fileErrors.length, file));
|
|
1390
|
+
for (const tableResult of result.tableResults) if (tableResult.valid && tableResult.warnings.length === 0) console.log(styleText("green", `✓ ${tableResult.tableName} (${tableResult.rowCount} records)`));
|
|
1391
|
+
else if (tableResult.valid && tableResult.warnings.length > 0) for (const warning of tableResult.warnings) console.warn(styleText("yellow", `⚠ ${warning}`));
|
|
1392
|
+
else {
|
|
1393
|
+
const fileErrors = tableResult.errors;
|
|
1394
|
+
console.error(formatter.formatErrorHeader(fileErrors.length, fileErrors[0]?.file));
|
|
1326
1395
|
console.error("");
|
|
1327
1396
|
const validationErrors = fileErrors.filter((e) => e.type !== "foreignKey" || !e.foreignKeyError);
|
|
1328
1397
|
const foreignKeyErrors = fileErrors.filter((e) => e.type === "foreignKey" && e.foreignKeyError);
|
|
1329
|
-
if (validationErrors.length > 0) {
|
|
1330
|
-
|
|
1398
|
+
if (validationErrors.length > 0) console.error(formatter.formatValidationErrors(validationErrors.map((e) => ({
|
|
1399
|
+
file: e.file,
|
|
1400
|
+
rowIndex: e.rowIndex,
|
|
1401
|
+
issues: e.issues
|
|
1402
|
+
}))));
|
|
1403
|
+
for (const error of foreignKeyErrors) if (error.foreignKeyError) console.error(formatter.formatForeignKeyError({
|
|
1404
|
+
file: error.file,
|
|
1405
|
+
rowIndex: error.rowIndex,
|
|
1406
|
+
column: error.foreignKeyError.column,
|
|
1407
|
+
value: error.foreignKeyError.value,
|
|
1408
|
+
referencedTable: error.foreignKeyError.referencedTable,
|
|
1409
|
+
referencedColumn: error.foreignKeyError.referencedColumn
|
|
1410
|
+
}));
|
|
1411
|
+
console.error("");
|
|
1412
|
+
}
|
|
1413
|
+
if (result.valid) {
|
|
1414
|
+
console.log("");
|
|
1415
|
+
console.log(styleText("green", "✓ All records are valid"));
|
|
1416
|
+
process.exit(0);
|
|
1417
|
+
} else process.exit(1);
|
|
1418
|
+
} else {
|
|
1419
|
+
if (result.warnings.length > 0) {
|
|
1420
|
+
for (const warning of result.warnings) console.warn(styleText("yellow", `⚠ ${warning}`));
|
|
1421
|
+
console.log("");
|
|
1422
|
+
}
|
|
1423
|
+
if (result.valid) {
|
|
1424
|
+
console.log(styleText("green", "✓ All records are valid"));
|
|
1425
|
+
process.exit(0);
|
|
1426
|
+
} else {
|
|
1427
|
+
const formatter = new ErrorFormatter({ verbose: options.verbose });
|
|
1428
|
+
for (const [, fileErrors] of result.errors.reduce((map, error) => {
|
|
1429
|
+
const errors = map.get(error.file) || [];
|
|
1430
|
+
errors.push(error);
|
|
1431
|
+
map.set(error.file, errors);
|
|
1432
|
+
return map;
|
|
1433
|
+
}, /* @__PURE__ */ new Map())) {
|
|
1434
|
+
console.error(formatter.formatErrorHeader(fileErrors.length, fileErrors[0]?.file));
|
|
1435
|
+
console.error("");
|
|
1436
|
+
const validationErrors = fileErrors.filter((e) => e.type !== "foreignKey" || !e.foreignKeyError);
|
|
1437
|
+
const foreignKeyErrors = fileErrors.filter((e) => e.type === "foreignKey" && e.foreignKeyError);
|
|
1438
|
+
if (validationErrors.length > 0) console.error(formatter.formatValidationErrors(validationErrors.map((e) => ({
|
|
1331
1439
|
file: e.file,
|
|
1332
1440
|
rowIndex: e.rowIndex,
|
|
1333
1441
|
issues: e.issues
|
|
1334
|
-
})));
|
|
1335
|
-
console.error(
|
|
1336
|
-
}
|
|
1337
|
-
for (const error of foreignKeyErrors) if (error.foreignKeyError) {
|
|
1338
|
-
const formattedFk = formatter.formatForeignKeyError({
|
|
1442
|
+
}))));
|
|
1443
|
+
for (const error of foreignKeyErrors) if (error.foreignKeyError) console.error(formatter.formatForeignKeyError({
|
|
1339
1444
|
file: error.file,
|
|
1340
1445
|
rowIndex: error.rowIndex,
|
|
1341
1446
|
column: error.foreignKeyError.column,
|
|
1342
1447
|
value: error.foreignKeyError.value,
|
|
1343
1448
|
referencedTable: error.foreignKeyError.referencedTable,
|
|
1344
1449
|
referencedColumn: error.foreignKeyError.referencedColumn
|
|
1345
|
-
});
|
|
1346
|
-
console.error(
|
|
1450
|
+
}));
|
|
1451
|
+
console.error("");
|
|
1347
1452
|
}
|
|
1348
|
-
|
|
1453
|
+
process.exit(1);
|
|
1349
1454
|
}
|
|
1350
|
-
process.exit(1);
|
|
1351
1455
|
}
|
|
1352
1456
|
} catch (error) {
|
|
1353
1457
|
console.error("Error:", error instanceof Error ? error.message : String(error));
|