@xylex-group/athena 1.6.0 → 1.6.2
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 +31 -6
- package/bin/athena-js.js +74 -6
- package/dist/cli/index.cjs +194 -30
- package/dist/cli/index.cjs.map +1 -1
- package/dist/cli/index.d.cts +21 -2
- package/dist/cli/index.d.ts +21 -2
- package/dist/cli/index.js +193 -31
- package/dist/cli/index.js.map +1 -1
- package/dist/errors-1b-LSTum.d.ts +31 -0
- package/dist/errors-BYRK5phv.d.cts +31 -0
- package/dist/index.cjs +104 -16
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +6 -338
- package/dist/index.d.ts +6 -338
- package/dist/index.js +104 -16
- package/dist/index.js.map +1 -1
- package/dist/pipeline-BQzpSLD3.d.ts +338 -0
- package/dist/pipeline-CA2aexDl.d.cts +338 -0
- package/dist/react.d.cts +3 -2
- package/dist/react.d.ts +3 -2
- package/dist/{errors-DQerAaXC.d.cts → types-v6UyGg-x.d.cts} +1 -29
- package/dist/{errors-DQerAaXC.d.ts → types-v6UyGg-x.d.ts} +1 -29
- package/package.json +2 -1
package/dist/cli/index.d.cts
CHANGED
|
@@ -1,6 +1,25 @@
|
|
|
1
|
+
import { r as runSchemaGenerator } from '../pipeline-CA2aexDl.cjs';
|
|
2
|
+
import '../types-v6UyGg-x.cjs';
|
|
3
|
+
|
|
4
|
+
interface GenerateCommand {
|
|
5
|
+
command: 'generate';
|
|
6
|
+
configPath?: string;
|
|
7
|
+
dryRun: boolean;
|
|
8
|
+
}
|
|
9
|
+
interface HelpCommand {
|
|
10
|
+
command: 'help';
|
|
11
|
+
topic: 'root' | 'generate';
|
|
12
|
+
}
|
|
13
|
+
type CliCommand = GenerateCommand | HelpCommand;
|
|
14
|
+
interface CliRuntime {
|
|
15
|
+
runGenerator?: typeof runSchemaGenerator;
|
|
16
|
+
log?: (message: string) => void;
|
|
17
|
+
}
|
|
18
|
+
declare function usage(topic?: HelpCommand['topic']): string;
|
|
19
|
+
declare function parseCommand(argv: string[]): CliCommand;
|
|
1
20
|
/**
|
|
2
21
|
* CLI entrypoint used by `bin/athena-js.js`.
|
|
3
22
|
*/
|
|
4
|
-
declare function runCLI(argv: string[]): Promise<void>;
|
|
23
|
+
declare function runCLI(argv: string[], runtime?: CliRuntime): Promise<void>;
|
|
5
24
|
|
|
6
|
-
export { runCLI };
|
|
25
|
+
export { type CliRuntime, parseCommand, runCLI, usage };
|
package/dist/cli/index.d.ts
CHANGED
|
@@ -1,6 +1,25 @@
|
|
|
1
|
+
import { r as runSchemaGenerator } from '../pipeline-BQzpSLD3.js';
|
|
2
|
+
import '../types-v6UyGg-x.js';
|
|
3
|
+
|
|
4
|
+
interface GenerateCommand {
|
|
5
|
+
command: 'generate';
|
|
6
|
+
configPath?: string;
|
|
7
|
+
dryRun: boolean;
|
|
8
|
+
}
|
|
9
|
+
interface HelpCommand {
|
|
10
|
+
command: 'help';
|
|
11
|
+
topic: 'root' | 'generate';
|
|
12
|
+
}
|
|
13
|
+
type CliCommand = GenerateCommand | HelpCommand;
|
|
14
|
+
interface CliRuntime {
|
|
15
|
+
runGenerator?: typeof runSchemaGenerator;
|
|
16
|
+
log?: (message: string) => void;
|
|
17
|
+
}
|
|
18
|
+
declare function usage(topic?: HelpCommand['topic']): string;
|
|
19
|
+
declare function parseCommand(argv: string[]): CliCommand;
|
|
1
20
|
/**
|
|
2
21
|
* CLI entrypoint used by `bin/athena-js.js`.
|
|
3
22
|
*/
|
|
4
|
-
declare function runCLI(argv: string[]): Promise<void>;
|
|
23
|
+
declare function runCLI(argv: string[], runtime?: CliRuntime): Promise<void>;
|
|
5
24
|
|
|
6
|
-
export { runCLI };
|
|
25
|
+
export { type CliRuntime, parseCommand, runCLI, usage };
|
package/dist/cli/index.js
CHANGED
|
@@ -298,10 +298,10 @@ var DEFAULT_CONFIG_CANDIDATES = [
|
|
|
298
298
|
".athena.config.js"
|
|
299
299
|
];
|
|
300
300
|
var DEFAULT_TARGETS = {
|
|
301
|
-
model: "
|
|
302
|
-
schema: "
|
|
303
|
-
database: "
|
|
304
|
-
registry: "
|
|
301
|
+
model: "athena/models/{model_kebab}.ts",
|
|
302
|
+
schema: "athena/schema.ts",
|
|
303
|
+
database: "athena/relations.ts",
|
|
304
|
+
registry: "athena/config.ts"
|
|
305
305
|
};
|
|
306
306
|
var DEFAULT_NAMING = {
|
|
307
307
|
modelType: "pascal",
|
|
@@ -329,6 +329,13 @@ function normalizeOutputConfig(output) {
|
|
|
329
329
|
}
|
|
330
330
|
};
|
|
331
331
|
}
|
|
332
|
+
function isAthenaGeneratorConfig(value) {
|
|
333
|
+
if (!value || typeof value !== "object") {
|
|
334
|
+
return false;
|
|
335
|
+
}
|
|
336
|
+
const record = value;
|
|
337
|
+
return Boolean(record.provider && typeof record.provider === "object") && Boolean(record.output && typeof record.output === "object");
|
|
338
|
+
}
|
|
332
339
|
function normalizeGeneratorConfig(input) {
|
|
333
340
|
return {
|
|
334
341
|
provider: input.provider,
|
|
@@ -357,18 +364,41 @@ function findGeneratorConfigPath(cwd = process.cwd()) {
|
|
|
357
364
|
return void 0;
|
|
358
365
|
}
|
|
359
366
|
function extractConfigExport(module) {
|
|
360
|
-
|
|
361
|
-
|
|
367
|
+
const visited = /* @__PURE__ */ new Set();
|
|
368
|
+
const queue = [module];
|
|
369
|
+
while (queue.length > 0) {
|
|
370
|
+
const current = queue.shift();
|
|
371
|
+
if (!current || typeof current !== "object" || visited.has(current)) {
|
|
372
|
+
continue;
|
|
373
|
+
}
|
|
374
|
+
visited.add(current);
|
|
375
|
+
const record = current;
|
|
376
|
+
if (isAthenaGeneratorConfig(record)) {
|
|
377
|
+
return record;
|
|
378
|
+
}
|
|
362
379
|
const defaultExport = record.default;
|
|
363
380
|
if (defaultExport && typeof defaultExport === "object") {
|
|
364
|
-
|
|
381
|
+
queue.push(defaultExport);
|
|
365
382
|
}
|
|
366
383
|
const namedConfigExport = record.config;
|
|
367
384
|
if (namedConfigExport && typeof namedConfigExport === "object") {
|
|
368
|
-
|
|
385
|
+
queue.push(namedConfigExport);
|
|
386
|
+
}
|
|
387
|
+
const moduleExports = record["module.exports"];
|
|
388
|
+
if (moduleExports && typeof moduleExports === "object") {
|
|
389
|
+
queue.push(moduleExports);
|
|
369
390
|
}
|
|
370
391
|
}
|
|
371
|
-
throw new Error(
|
|
392
|
+
throw new Error(
|
|
393
|
+
"Generator config file must export a config object as default export or `config`."
|
|
394
|
+
);
|
|
395
|
+
}
|
|
396
|
+
function importConfigModule(moduleSpecifier) {
|
|
397
|
+
const runtimeImport = new Function(
|
|
398
|
+
"moduleSpecifier",
|
|
399
|
+
"return import(moduleSpecifier)"
|
|
400
|
+
);
|
|
401
|
+
return runtimeImport(moduleSpecifier);
|
|
372
402
|
}
|
|
373
403
|
async function loadGeneratorConfig(options = {}) {
|
|
374
404
|
const cwd = options.cwd ?? process.cwd();
|
|
@@ -379,7 +409,7 @@ async function loadGeneratorConfig(options = {}) {
|
|
|
379
409
|
);
|
|
380
410
|
}
|
|
381
411
|
const moduleUrl = pathToFileURL(resolvedPath);
|
|
382
|
-
const module = await
|
|
412
|
+
const module = await importConfigModule(`${moduleUrl.href}?cacheBust=${Date.now()}`);
|
|
383
413
|
const rawConfig = extractConfigExport(module);
|
|
384
414
|
return {
|
|
385
415
|
configPath: resolvedPath,
|
|
@@ -2027,6 +2057,58 @@ function toTypeKind(code) {
|
|
|
2027
2057
|
function escapeSqlLiteral(value) {
|
|
2028
2058
|
return value.replace(/'/g, "''");
|
|
2029
2059
|
}
|
|
2060
|
+
function parsePostgresArrayLiteral(text) {
|
|
2061
|
+
const body = text.slice(1, -1).trim();
|
|
2062
|
+
if (!body) return [];
|
|
2063
|
+
const values = [];
|
|
2064
|
+
let current = "";
|
|
2065
|
+
let inQuotes = false;
|
|
2066
|
+
let escaped = false;
|
|
2067
|
+
for (const char of body) {
|
|
2068
|
+
if (escaped) {
|
|
2069
|
+
current += char;
|
|
2070
|
+
escaped = false;
|
|
2071
|
+
continue;
|
|
2072
|
+
}
|
|
2073
|
+
if (char === "\\") {
|
|
2074
|
+
escaped = true;
|
|
2075
|
+
continue;
|
|
2076
|
+
}
|
|
2077
|
+
if (char === '"') {
|
|
2078
|
+
inQuotes = !inQuotes;
|
|
2079
|
+
continue;
|
|
2080
|
+
}
|
|
2081
|
+
if (char === "," && !inQuotes) {
|
|
2082
|
+
values.push(current);
|
|
2083
|
+
current = "";
|
|
2084
|
+
continue;
|
|
2085
|
+
}
|
|
2086
|
+
current += char;
|
|
2087
|
+
}
|
|
2088
|
+
values.push(current);
|
|
2089
|
+
return values.map((value) => value.trim()).filter((value) => value.length > 0);
|
|
2090
|
+
}
|
|
2091
|
+
function coerceStringArray(value) {
|
|
2092
|
+
if (Array.isArray(value)) {
|
|
2093
|
+
return value.map((item) => typeof item === "string" ? item : String(item)).map((item) => item.trim()).filter((item) => item.length > 0);
|
|
2094
|
+
}
|
|
2095
|
+
if (typeof value === "string") {
|
|
2096
|
+
const trimmed = value.trim();
|
|
2097
|
+
if (!trimmed) return [];
|
|
2098
|
+
if (trimmed.startsWith("[") && trimmed.endsWith("]")) {
|
|
2099
|
+
try {
|
|
2100
|
+
const parsed = JSON.parse(trimmed);
|
|
2101
|
+
return coerceStringArray(parsed);
|
|
2102
|
+
} catch {
|
|
2103
|
+
}
|
|
2104
|
+
}
|
|
2105
|
+
if (trimmed.startsWith("{") && trimmed.endsWith("}")) {
|
|
2106
|
+
return parsePostgresArrayLiteral(trimmed);
|
|
2107
|
+
}
|
|
2108
|
+
return trimmed.split(",").map((item) => item.trim()).filter((item) => item.length > 0);
|
|
2109
|
+
}
|
|
2110
|
+
return [];
|
|
2111
|
+
}
|
|
2030
2112
|
function buildSchemaArrayLiteral(schemas) {
|
|
2031
2113
|
const normalized = schemas.length > 0 ? schemas : ["public"];
|
|
2032
2114
|
const literals = normalized.map((schema) => `'${escapeSqlLiteral(schema)}'`).join(", ");
|
|
@@ -2066,8 +2148,10 @@ var PostgresCatalogSnapshotAssembler = class {
|
|
|
2066
2148
|
addPrimaryKeyRows(primaryKeyRows) {
|
|
2067
2149
|
for (const row of primaryKeyRows) {
|
|
2068
2150
|
const table = this.ensureTable(row.schema_name, row.table_name);
|
|
2069
|
-
|
|
2070
|
-
|
|
2151
|
+
const primaryKeyColumns = coerceStringArray(row.columns);
|
|
2152
|
+
row.columns = primaryKeyColumns;
|
|
2153
|
+
table.primaryKey = primaryKeyColumns;
|
|
2154
|
+
for (const columnName of primaryKeyColumns) {
|
|
2071
2155
|
const column = table.columns[columnName];
|
|
2072
2156
|
if (column) {
|
|
2073
2157
|
column.isPrimaryKey = true;
|
|
@@ -2079,23 +2163,27 @@ var PostgresCatalogSnapshotAssembler = class {
|
|
|
2079
2163
|
for (const row of foreignKeyRows) {
|
|
2080
2164
|
const sourceTable = this.ensureTable(row.source_schema, row.source_table);
|
|
2081
2165
|
const targetTable = this.ensureTable(row.target_schema, row.target_table);
|
|
2166
|
+
const sourceColumns = coerceStringArray(row.source_columns);
|
|
2167
|
+
const targetColumns = coerceStringArray(row.target_columns);
|
|
2168
|
+
row.source_columns = sourceColumns;
|
|
2169
|
+
row.target_columns = targetColumns;
|
|
2082
2170
|
const sourceRelationKind = row.source_is_unique ? "one-to-one" : "many-to-one";
|
|
2083
2171
|
this.upsertRelation(sourceTable, relationKey(row.constraint_name, row.target_table), {
|
|
2084
2172
|
name: row.constraint_name,
|
|
2085
2173
|
kind: sourceRelationKind,
|
|
2086
|
-
sourceColumns
|
|
2174
|
+
sourceColumns,
|
|
2087
2175
|
targetSchema: row.target_schema,
|
|
2088
2176
|
targetModel: row.target_table,
|
|
2089
|
-
targetColumns
|
|
2177
|
+
targetColumns
|
|
2090
2178
|
});
|
|
2091
2179
|
const targetRelationKind = row.source_is_unique ? "one-to-one" : "one-to-many";
|
|
2092
2180
|
this.upsertRelation(targetTable, relationKey(row.source_table), {
|
|
2093
2181
|
name: relationKey(row.source_table, row.constraint_name),
|
|
2094
2182
|
kind: targetRelationKind,
|
|
2095
|
-
sourceColumns:
|
|
2183
|
+
sourceColumns: targetColumns,
|
|
2096
2184
|
targetSchema: row.source_schema,
|
|
2097
2185
|
targetModel: row.source_table,
|
|
2098
|
-
targetColumns:
|
|
2186
|
+
targetColumns: sourceColumns
|
|
2099
2187
|
});
|
|
2100
2188
|
}
|
|
2101
2189
|
}
|
|
@@ -2397,7 +2485,7 @@ async function runSchemaGenerator(options = {}) {
|
|
|
2397
2485
|
}
|
|
2398
2486
|
|
|
2399
2487
|
// src/cli/index.ts
|
|
2400
|
-
function
|
|
2488
|
+
function rootUsage() {
|
|
2401
2489
|
return [
|
|
2402
2490
|
"athena-js CLI",
|
|
2403
2491
|
"",
|
|
@@ -2406,12 +2494,42 @@ function usage() {
|
|
|
2406
2494
|
"",
|
|
2407
2495
|
"Examples:",
|
|
2408
2496
|
" athena-js generate",
|
|
2497
|
+
" athena-js generate --config ./athena.config.ts --dry-run",
|
|
2498
|
+
" athena-js generate --help"
|
|
2499
|
+
].join("\n");
|
|
2500
|
+
}
|
|
2501
|
+
function generateUsage() {
|
|
2502
|
+
return [
|
|
2503
|
+
"athena-js generate",
|
|
2504
|
+
"",
|
|
2505
|
+
"Usage:",
|
|
2506
|
+
" athena-js generate [--config <path>] [--dry-run]",
|
|
2507
|
+
"",
|
|
2508
|
+
"Options:",
|
|
2509
|
+
" --config <path> Explicit path to athena.config.ts or athena-js.config.ts",
|
|
2510
|
+
" --dry-run Build generated files in memory without writing them to disk",
|
|
2511
|
+
" -h, --help Show help for generate",
|
|
2512
|
+
"",
|
|
2513
|
+
"Examples:",
|
|
2514
|
+
" athena-js generate",
|
|
2409
2515
|
" athena-js generate --config ./athena.config.ts --dry-run"
|
|
2410
2516
|
].join("\n");
|
|
2411
2517
|
}
|
|
2518
|
+
function usage(topic = "root") {
|
|
2519
|
+
return topic === "generate" ? generateUsage() : rootUsage();
|
|
2520
|
+
}
|
|
2412
2521
|
function parseCommand(argv) {
|
|
2413
|
-
if (argv.length === 0 || argv[0] === "
|
|
2414
|
-
return { command: "help" };
|
|
2522
|
+
if (argv.length === 0 || argv[0] === "--help" || argv[0] === "-h") {
|
|
2523
|
+
return { command: "help", topic: "root" };
|
|
2524
|
+
}
|
|
2525
|
+
if (argv[0] === "help") {
|
|
2526
|
+
if (argv.length === 1) {
|
|
2527
|
+
return { command: "help", topic: "root" };
|
|
2528
|
+
}
|
|
2529
|
+
if (argv[1] === "generate") {
|
|
2530
|
+
return { command: "help", topic: "generate" };
|
|
2531
|
+
}
|
|
2532
|
+
throw new Error(`Unknown command "${argv[1]}".`);
|
|
2415
2533
|
}
|
|
2416
2534
|
const [command, ...rest] = argv;
|
|
2417
2535
|
if (command !== "generate") {
|
|
@@ -2421,13 +2539,16 @@ function parseCommand(argv) {
|
|
|
2421
2539
|
let dryRun = false;
|
|
2422
2540
|
for (let index = 0; index < rest.length; index += 1) {
|
|
2423
2541
|
const token = rest[index];
|
|
2542
|
+
if (token === "--help" || token === "-h") {
|
|
2543
|
+
return { command: "help", topic: "generate" };
|
|
2544
|
+
}
|
|
2424
2545
|
if (token === "--dry-run") {
|
|
2425
2546
|
dryRun = true;
|
|
2426
2547
|
continue;
|
|
2427
2548
|
}
|
|
2428
2549
|
if (token === "--config") {
|
|
2429
2550
|
const nextValue = rest[index + 1];
|
|
2430
|
-
if (!nextValue) {
|
|
2551
|
+
if (!nextValue || nextValue.startsWith("-")) {
|
|
2431
2552
|
throw new Error("Missing value for --config option.");
|
|
2432
2553
|
}
|
|
2433
2554
|
configPath = nextValue;
|
|
@@ -2442,29 +2563,70 @@ function parseCommand(argv) {
|
|
|
2442
2563
|
dryRun
|
|
2443
2564
|
};
|
|
2444
2565
|
}
|
|
2445
|
-
|
|
2566
|
+
function normalizeErrorMessage(error) {
|
|
2567
|
+
if (error instanceof Error) {
|
|
2568
|
+
return error.message;
|
|
2569
|
+
}
|
|
2570
|
+
if (typeof error === "string") {
|
|
2571
|
+
return error;
|
|
2572
|
+
}
|
|
2573
|
+
return "Unknown generator error.";
|
|
2574
|
+
}
|
|
2575
|
+
function extractMissingDatabaseName(message) {
|
|
2576
|
+
const match = message.match(/database "([^"]+)" does not exist/i);
|
|
2577
|
+
return match?.[1];
|
|
2578
|
+
}
|
|
2579
|
+
function isErrorWithCode(error) {
|
|
2580
|
+
return typeof error === "object" && error !== null && "code" in error;
|
|
2581
|
+
}
|
|
2582
|
+
function formatGeneratorError(error, configPath) {
|
|
2583
|
+
if (isErrorWithCode(error) && error.code === "3D000") {
|
|
2584
|
+
const message = normalizeErrorMessage(error);
|
|
2585
|
+
const databaseName = extractMissingDatabaseName(message);
|
|
2586
|
+
const databaseLabel = databaseName ? `PostgreSQL database "${databaseName}" does not exist` : "The target PostgreSQL database does not exist";
|
|
2587
|
+
const configLabel = configPath ? `config "${configPath}"` : "the resolved athena config";
|
|
2588
|
+
return new Error(
|
|
2589
|
+
[
|
|
2590
|
+
`${databaseLabel} (code 3D000).`,
|
|
2591
|
+
`Update provider.connectionString (and provider.database, if set) in ${configLabel}, or create that database before running generate.`
|
|
2592
|
+
].join("\n")
|
|
2593
|
+
);
|
|
2594
|
+
}
|
|
2595
|
+
if (error instanceof Error) {
|
|
2596
|
+
return error;
|
|
2597
|
+
}
|
|
2598
|
+
return new Error(normalizeErrorMessage(error));
|
|
2599
|
+
}
|
|
2600
|
+
async function runCLI(argv, runtime = {}) {
|
|
2601
|
+
const log = runtime.log ?? console.log;
|
|
2602
|
+
const runGenerator = runtime.runGenerator ?? runSchemaGenerator;
|
|
2446
2603
|
const parsed = parseCommand(argv);
|
|
2447
2604
|
if (parsed.command === "help") {
|
|
2448
|
-
|
|
2605
|
+
log(usage(parsed.topic));
|
|
2449
2606
|
return;
|
|
2450
2607
|
}
|
|
2451
|
-
|
|
2452
|
-
|
|
2453
|
-
|
|
2454
|
-
|
|
2608
|
+
let result;
|
|
2609
|
+
try {
|
|
2610
|
+
result = await runGenerator({
|
|
2611
|
+
configPath: parsed.configPath,
|
|
2612
|
+
dryRun: parsed.dryRun
|
|
2613
|
+
});
|
|
2614
|
+
} catch (error) {
|
|
2615
|
+
throw formatGeneratorError(error, parsed.configPath);
|
|
2616
|
+
}
|
|
2455
2617
|
if (parsed.dryRun) {
|
|
2456
|
-
|
|
2618
|
+
log(`[dry-run] Generated ${result.files.length} files from ${result.configPath}`);
|
|
2457
2619
|
for (const file of result.files) {
|
|
2458
|
-
|
|
2620
|
+
log(` - ${file.path}`);
|
|
2459
2621
|
}
|
|
2460
2622
|
return;
|
|
2461
2623
|
}
|
|
2462
|
-
|
|
2624
|
+
log(`Generated ${result.writtenFiles.length} files from ${result.configPath}`);
|
|
2463
2625
|
for (const filePath of result.writtenFiles) {
|
|
2464
|
-
|
|
2626
|
+
log(` - ${filePath}`);
|
|
2465
2627
|
}
|
|
2466
2628
|
}
|
|
2467
2629
|
|
|
2468
|
-
export { runCLI };
|
|
2630
|
+
export { parseCommand, runCLI, usage };
|
|
2469
2631
|
//# sourceMappingURL=index.js.map
|
|
2470
2632
|
//# sourceMappingURL=index.js.map
|