@xylex-group/athena 3.0.2 → 3.1.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 +1 -1
- package/dist/billing.cjs +1 -1
- package/dist/billing.cjs.map +1 -1
- package/dist/billing.js +1 -1
- package/dist/billing.js.map +1 -1
- package/dist/browser.cjs +322 -1
- package/dist/browser.cjs.map +1 -1
- package/dist/browser.d.cts +5 -5
- package/dist/browser.d.ts +5 -5
- package/dist/browser.js +301 -2
- package/dist/browser.js.map +1 -1
- package/dist/cli/index.cjs +5381 -3772
- package/dist/cli/index.cjs.map +1 -1
- package/dist/cli/index.d.cts +17 -10
- package/dist/cli/index.d.ts +17 -10
- package/dist/cli/index.js +5385 -3776
- package/dist/cli/index.js.map +1 -1
- package/dist/index.cjs +1723 -26
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +28 -6
- package/dist/index.d.ts +28 -6
- package/dist/index.js +1695 -28
- package/dist/index.js.map +1 -1
- package/dist/model-form-BbdzJ9Uh.d.ts +259 -0
- package/dist/model-form-BhWWsA-7.d.cts +259 -0
- package/dist/{module-CkUM6v58.d.ts → module-DKkJKOuJ.d.ts} +2 -2
- package/dist/{module-CB25egcO.d.cts → module-xFd7_Igv.d.cts} +2 -2
- package/dist/next/client.cjs +1 -1
- package/dist/next/client.cjs.map +1 -1
- package/dist/next/client.js +1 -1
- package/dist/next/client.js.map +1 -1
- package/dist/next/server.cjs +1 -1
- package/dist/next/server.cjs.map +1 -1
- package/dist/next/server.js +1 -1
- package/dist/next/server.js.map +1 -1
- package/dist/pipeline-DuKzYGia.d.cts +93 -0
- package/dist/pipeline-wer2G9xW.d.ts +93 -0
- package/dist/react.cjs +400 -3
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +67 -2
- package/dist/react.d.ts +67 -2
- package/dist/react.js +400 -4
- package/dist/react.js.map +1 -1
- package/dist/{types-BBm-kEBL.d.cts → types-1ztXDgPa.d.cts} +62 -2
- package/dist/{types-BaAMXCqK.d.ts → types-CccOiXPo.d.ts} +62 -2
- package/package.json +1 -1
- package/dist/model-form-Dh0sisdL.d.ts +0 -97
- package/dist/model-form-oOAJUVd4.d.cts +0 -97
- package/dist/pipeline-B8aN2EHe.d.ts +0 -8
- package/dist/pipeline-D4W-Cc-A.d.cts +0 -8
package/dist/index.cjs
CHANGED
|
@@ -573,8 +573,8 @@ function computeDelayMs(attempt, error, config) {
|
|
|
573
573
|
}
|
|
574
574
|
function sleep(ms) {
|
|
575
575
|
if (ms <= 0) return Promise.resolve();
|
|
576
|
-
return new Promise((
|
|
577
|
-
setTimeout(
|
|
576
|
+
return new Promise((resolve4) => {
|
|
577
|
+
setTimeout(resolve4, ms);
|
|
578
578
|
});
|
|
579
579
|
}
|
|
580
580
|
async function withRetry(config, fn) {
|
|
@@ -2009,7 +2009,7 @@ function buildAthenaGatewayUrl(baseUrl, path) {
|
|
|
2009
2009
|
|
|
2010
2010
|
// package.json
|
|
2011
2011
|
var package_default = {
|
|
2012
|
-
version: "3.0
|
|
2012
|
+
version: "3.1.0"
|
|
2013
2013
|
};
|
|
2014
2014
|
|
|
2015
2015
|
// src/sdk-version.ts
|
|
@@ -5228,7 +5228,7 @@ async function putWithXhr(url, signed, body, signal, onProgress) {
|
|
|
5228
5228
|
if (Xhr === void 0) {
|
|
5229
5229
|
return Promise.reject(new Error("athena.storage.file.upload direct mode requires XMLHttpRequest in this runtime"));
|
|
5230
5230
|
}
|
|
5231
|
-
return new Promise((
|
|
5231
|
+
return new Promise((resolve4, reject) => {
|
|
5232
5232
|
const xhr = new Xhr();
|
|
5233
5233
|
const abort = () => xhr.abort();
|
|
5234
5234
|
xhr.open("PUT", url);
|
|
@@ -5241,7 +5241,7 @@ async function putWithXhr(url, signed, body, signal, onProgress) {
|
|
|
5241
5241
|
return;
|
|
5242
5242
|
}
|
|
5243
5243
|
onProgress({ loaded: bodySize(body) });
|
|
5244
|
-
|
|
5244
|
+
resolve4(new Response(xhr.response, {
|
|
5245
5245
|
status: xhr.status,
|
|
5246
5246
|
statusText: xhr.statusText,
|
|
5247
5247
|
headers: parseXhrHeaders(xhr.getAllResponseHeaders())
|
|
@@ -5694,7 +5694,7 @@ function putUploadBodyWithXhr(url, source, headers, options, onProgress) {
|
|
|
5694
5694
|
if (Xhr === void 0) {
|
|
5695
5695
|
return Promise.reject(new Error("athena.storage.file.upload requires XMLHttpRequest in this runtime"));
|
|
5696
5696
|
}
|
|
5697
|
-
return new Promise((
|
|
5697
|
+
return new Promise((resolve4, reject) => {
|
|
5698
5698
|
const xhr = new Xhr();
|
|
5699
5699
|
const abort = () => xhr.abort();
|
|
5700
5700
|
xhr.open("PUT", url);
|
|
@@ -5711,7 +5711,7 @@ function putUploadBodyWithXhr(url, source, headers, options, onProgress) {
|
|
|
5711
5711
|
return;
|
|
5712
5712
|
}
|
|
5713
5713
|
onProgress({ loaded: source.sizeBytes });
|
|
5714
|
-
|
|
5714
|
+
resolve4(new Response(xhr.response, {
|
|
5715
5715
|
status: xhr.status,
|
|
5716
5716
|
statusText: xhr.statusText,
|
|
5717
5717
|
headers: parseXhrHeaders2(xhr.getAllResponseHeaders())
|
|
@@ -10770,6 +10770,305 @@ var Backend = {
|
|
|
10770
10770
|
ScyllaDB: { type: "scylladb" }
|
|
10771
10771
|
};
|
|
10772
10772
|
|
|
10773
|
+
// src/query/read-query.ts
|
|
10774
|
+
function normalizeAthenaReadQueryOrderBy(orderBy) {
|
|
10775
|
+
if (!orderBy) {
|
|
10776
|
+
return [];
|
|
10777
|
+
}
|
|
10778
|
+
const list = Array.isArray(orderBy) ? orderBy : [orderBy];
|
|
10779
|
+
return list.filter(
|
|
10780
|
+
(entry) => entry && typeof entry.column === "string" && entry.column.trim().length > 0
|
|
10781
|
+
);
|
|
10782
|
+
}
|
|
10783
|
+
function isRecord12(value) {
|
|
10784
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
10785
|
+
}
|
|
10786
|
+
function flattenAthenaRowValue(row, column) {
|
|
10787
|
+
if (!column.relation) {
|
|
10788
|
+
return row[column.column];
|
|
10789
|
+
}
|
|
10790
|
+
const relationValue = row[column.relation.name];
|
|
10791
|
+
if (Array.isArray(relationValue)) {
|
|
10792
|
+
return relationValue.map((entry) => isRecord12(entry) ? entry[column.column] : void 0).filter((entry) => entry !== void 0);
|
|
10793
|
+
}
|
|
10794
|
+
if (isRecord12(relationValue)) {
|
|
10795
|
+
return relationValue[column.column];
|
|
10796
|
+
}
|
|
10797
|
+
return void 0;
|
|
10798
|
+
}
|
|
10799
|
+
function resolveFlatRowKey(row, index, preferredKey) {
|
|
10800
|
+
const preferredValue = preferredKey && preferredKey in row ? row[preferredKey] : void 0;
|
|
10801
|
+
if (preferredValue !== void 0 && preferredValue !== null && `${preferredValue}`.trim().length > 0) {
|
|
10802
|
+
return String(preferredValue);
|
|
10803
|
+
}
|
|
10804
|
+
for (const [key, value] of Object.entries(row)) {
|
|
10805
|
+
if (key === "__rowKey") {
|
|
10806
|
+
continue;
|
|
10807
|
+
}
|
|
10808
|
+
if (value === void 0 || value === null) {
|
|
10809
|
+
continue;
|
|
10810
|
+
}
|
|
10811
|
+
if (Array.isArray(value)) {
|
|
10812
|
+
if (value.length > 0) {
|
|
10813
|
+
return `${key}-${value.join("-")}`;
|
|
10814
|
+
}
|
|
10815
|
+
continue;
|
|
10816
|
+
}
|
|
10817
|
+
const nextValue = String(value).trim();
|
|
10818
|
+
if (nextValue.length > 0) {
|
|
10819
|
+
return nextValue;
|
|
10820
|
+
}
|
|
10821
|
+
}
|
|
10822
|
+
return `row-${index + 1}`;
|
|
10823
|
+
}
|
|
10824
|
+
function flattenAthenaReadQueryRows(rows, columns, preferredKey) {
|
|
10825
|
+
return rows.map((entry, index) => {
|
|
10826
|
+
const sourceRow = isRecord12(entry) ? entry : {};
|
|
10827
|
+
const flatRow = columns.reduce(
|
|
10828
|
+
(currentRow, column) => {
|
|
10829
|
+
currentRow[column.key] = flattenAthenaRowValue(sourceRow, column);
|
|
10830
|
+
return currentRow;
|
|
10831
|
+
},
|
|
10832
|
+
{ __rowKey: "" }
|
|
10833
|
+
);
|
|
10834
|
+
flatRow.__rowKey = resolveFlatRowKey(flatRow, index, preferredKey);
|
|
10835
|
+
return flatRow;
|
|
10836
|
+
});
|
|
10837
|
+
}
|
|
10838
|
+
var flattenAthenaRows = flattenAthenaReadQueryRows;
|
|
10839
|
+
function buildAthenaReadQuerySelectString(columns) {
|
|
10840
|
+
const baseColumns = columns.filter((column) => !column.relation).map((column) => column.column);
|
|
10841
|
+
const relationGroups = /* @__PURE__ */ new Map();
|
|
10842
|
+
for (const column of columns) {
|
|
10843
|
+
if (!column.relation) {
|
|
10844
|
+
continue;
|
|
10845
|
+
}
|
|
10846
|
+
const groupKey = [
|
|
10847
|
+
column.relation.name,
|
|
10848
|
+
column.relation.schema ?? "",
|
|
10849
|
+
column.relation.table
|
|
10850
|
+
].join(":");
|
|
10851
|
+
const existingGroup = relationGroups.get(groupKey);
|
|
10852
|
+
if (existingGroup) {
|
|
10853
|
+
if (!existingGroup.columns.includes(column.column)) {
|
|
10854
|
+
existingGroup.columns.push(column.column);
|
|
10855
|
+
}
|
|
10856
|
+
continue;
|
|
10857
|
+
}
|
|
10858
|
+
relationGroups.set(groupKey, {
|
|
10859
|
+
columns: [column.column],
|
|
10860
|
+
relation: column.relation
|
|
10861
|
+
});
|
|
10862
|
+
}
|
|
10863
|
+
const relationColumns = [...relationGroups.values()].map(
|
|
10864
|
+
({ columns: relationColumns2, relation }) => {
|
|
10865
|
+
const relationTarget = relation.schema ? `${relation.schema}.${relation.table}` : relation.table;
|
|
10866
|
+
return `${relation.name}:${relationTarget}(${relationColumns2.join(",")})`;
|
|
10867
|
+
}
|
|
10868
|
+
);
|
|
10869
|
+
return [...baseColumns, ...relationColumns].join(",");
|
|
10870
|
+
}
|
|
10871
|
+
var buildAthenaTableSelectString = buildAthenaReadQuerySelectString;
|
|
10872
|
+
function buildAthenaReadQueryFindManySelect(columns) {
|
|
10873
|
+
const select = {};
|
|
10874
|
+
for (const column of columns) {
|
|
10875
|
+
if (!column.relation) {
|
|
10876
|
+
select[column.column] = true;
|
|
10877
|
+
continue;
|
|
10878
|
+
}
|
|
10879
|
+
const existingRelation = select[column.relation.name];
|
|
10880
|
+
if (existingRelation && existingRelation !== true && isRecord12(existingRelation.select)) {
|
|
10881
|
+
existingRelation.select[column.column] = true;
|
|
10882
|
+
continue;
|
|
10883
|
+
}
|
|
10884
|
+
select[column.relation.name] = {
|
|
10885
|
+
...column.relation.schema ? { schema: column.relation.schema } : {},
|
|
10886
|
+
select: {
|
|
10887
|
+
[column.column]: true
|
|
10888
|
+
}
|
|
10889
|
+
};
|
|
10890
|
+
}
|
|
10891
|
+
return select;
|
|
10892
|
+
}
|
|
10893
|
+
var buildAthenaTableFindManySelect = buildAthenaReadQueryFindManySelect;
|
|
10894
|
+
function buildAthenaReadQueryFindManyWhere(filters) {
|
|
10895
|
+
if (!filters?.length) {
|
|
10896
|
+
return;
|
|
10897
|
+
}
|
|
10898
|
+
return filters.reduce(
|
|
10899
|
+
(where, filter) => {
|
|
10900
|
+
const operator = filter.operator ?? "eq";
|
|
10901
|
+
where[filter.column] = operator === "eq" ? filter.value : { [operator]: filter.value };
|
|
10902
|
+
return where;
|
|
10903
|
+
},
|
|
10904
|
+
{}
|
|
10905
|
+
);
|
|
10906
|
+
}
|
|
10907
|
+
var buildAthenaTableFindManyWhere = buildAthenaReadQueryFindManyWhere;
|
|
10908
|
+
function buildAthenaReadQueryFindManyOrderBy(orderBy) {
|
|
10909
|
+
const normalized = normalizeAthenaReadQueryOrderBy(orderBy);
|
|
10910
|
+
if (normalized.length === 0) {
|
|
10911
|
+
return;
|
|
10912
|
+
}
|
|
10913
|
+
if (normalized.length === 1) {
|
|
10914
|
+
const primary = normalized[0];
|
|
10915
|
+
if (!primary) {
|
|
10916
|
+
return;
|
|
10917
|
+
}
|
|
10918
|
+
return {
|
|
10919
|
+
ascending: primary.direction !== "desc",
|
|
10920
|
+
column: primary.column
|
|
10921
|
+
};
|
|
10922
|
+
}
|
|
10923
|
+
return Object.fromEntries(
|
|
10924
|
+
normalized.map((entry) => [
|
|
10925
|
+
entry.column,
|
|
10926
|
+
entry.direction === "desc" ? "desc" : "asc"
|
|
10927
|
+
])
|
|
10928
|
+
);
|
|
10929
|
+
}
|
|
10930
|
+
var buildAthenaTableFindManyOrderBy = buildAthenaReadQueryFindManyOrderBy;
|
|
10931
|
+
var normalizeAthenaTableOrderBy = normalizeAthenaReadQueryOrderBy;
|
|
10932
|
+
function applyAthenaReadQueryFilters(queryBuilder, filters) {
|
|
10933
|
+
if (!filters?.length) {
|
|
10934
|
+
return queryBuilder;
|
|
10935
|
+
}
|
|
10936
|
+
return filters.reduce((currentBuilder, filter) => {
|
|
10937
|
+
const operator = filter.operator ?? "eq";
|
|
10938
|
+
const builderMethod = currentBuilder[operator];
|
|
10939
|
+
if (typeof builderMethod !== "function") {
|
|
10940
|
+
return currentBuilder;
|
|
10941
|
+
}
|
|
10942
|
+
return builderMethod.call(currentBuilder, filter.column, filter.value);
|
|
10943
|
+
}, queryBuilder);
|
|
10944
|
+
}
|
|
10945
|
+
var applyAthenaTableFilters = applyAthenaReadQueryFilters;
|
|
10946
|
+
function applyAthenaReadQuerySelectOrder(queryBuilder, orderBy) {
|
|
10947
|
+
const normalized = normalizeAthenaReadQueryOrderBy(orderBy);
|
|
10948
|
+
if (normalized.length === 0) {
|
|
10949
|
+
return queryBuilder;
|
|
10950
|
+
}
|
|
10951
|
+
return normalized.reduce(
|
|
10952
|
+
(builder, entry) => builder.order(entry.column, {
|
|
10953
|
+
ascending: entry.direction !== "desc"
|
|
10954
|
+
}),
|
|
10955
|
+
queryBuilder
|
|
10956
|
+
);
|
|
10957
|
+
}
|
|
10958
|
+
var applyAthenaTableSelectOrder = applyAthenaReadQuerySelectOrder;
|
|
10959
|
+
function applyAthenaReadQuerySelectLimit(queryBuilder, limit) {
|
|
10960
|
+
if (!limit || limit < 1) {
|
|
10961
|
+
return queryBuilder;
|
|
10962
|
+
}
|
|
10963
|
+
return queryBuilder.limit(limit);
|
|
10964
|
+
}
|
|
10965
|
+
var applyAthenaTableSelectLimit = applyAthenaReadQuerySelectLimit;
|
|
10966
|
+
function clampAthenaReadQueryTotalItems(totalItems, limit) {
|
|
10967
|
+
if (!limit || limit < 1) {
|
|
10968
|
+
return totalItems;
|
|
10969
|
+
}
|
|
10970
|
+
return Math.min(totalItems, limit);
|
|
10971
|
+
}
|
|
10972
|
+
var clampAthenaTableTotalItems = clampAthenaReadQueryTotalItems;
|
|
10973
|
+
function resolveCountValue(...candidates) {
|
|
10974
|
+
for (const candidate of candidates) {
|
|
10975
|
+
if (typeof candidate === "number" && Number.isFinite(candidate)) {
|
|
10976
|
+
return Math.max(0, Math.trunc(candidate));
|
|
10977
|
+
}
|
|
10978
|
+
}
|
|
10979
|
+
return 0;
|
|
10980
|
+
}
|
|
10981
|
+
function resolveTotalItemsFromPage({
|
|
10982
|
+
countCandidates,
|
|
10983
|
+
limit,
|
|
10984
|
+
page,
|
|
10985
|
+
pageSize,
|
|
10986
|
+
rowCount
|
|
10987
|
+
}) {
|
|
10988
|
+
const exactCount = resolveCountValue(...countCandidates);
|
|
10989
|
+
if (exactCount > 0) {
|
|
10990
|
+
return clampAthenaReadQueryTotalItems(exactCount, limit);
|
|
10991
|
+
}
|
|
10992
|
+
if (rowCount > 0) {
|
|
10993
|
+
const base = (page - 1) * pageSize + rowCount;
|
|
10994
|
+
const synthetic = rowCount >= pageSize ? base + 1 : base;
|
|
10995
|
+
return clampAthenaReadQueryTotalItems(synthetic, limit);
|
|
10996
|
+
}
|
|
10997
|
+
return clampAthenaReadQueryTotalItems(exactCount, limit);
|
|
10998
|
+
}
|
|
10999
|
+
async function executeAthenaReadQuery({
|
|
11000
|
+
client,
|
|
11001
|
+
page,
|
|
11002
|
+
pageSize,
|
|
11003
|
+
query
|
|
11004
|
+
}) {
|
|
11005
|
+
const db = client.db;
|
|
11006
|
+
const baseBuilder = db.from(query.table, {
|
|
11007
|
+
schema: query.schema
|
|
11008
|
+
});
|
|
11009
|
+
const countBuilder = applyAthenaReadQueryFilters(
|
|
11010
|
+
db.from(query.table, { schema: query.schema }),
|
|
11011
|
+
query.filters
|
|
11012
|
+
);
|
|
11013
|
+
const countResult = await countBuilder.select(query.countColumn, {
|
|
11014
|
+
count: "exact",
|
|
11015
|
+
head: true
|
|
11016
|
+
});
|
|
11017
|
+
if ((query.mode ?? "findMany") === "select") {
|
|
11018
|
+
const selectBuilder = applyAthenaReadQuerySelectLimit(
|
|
11019
|
+
applyAthenaReadQuerySelectOrder(
|
|
11020
|
+
applyAthenaReadQueryFilters(baseBuilder, query.filters),
|
|
11021
|
+
query.orderBy
|
|
11022
|
+
),
|
|
11023
|
+
query.limit
|
|
11024
|
+
);
|
|
11025
|
+
const result2 = await selectBuilder.currentPage(page).pageSize(pageSize).select(buildAthenaReadQuerySelectString(query.columns), {
|
|
11026
|
+
count: "exact"
|
|
11027
|
+
});
|
|
11028
|
+
const rows2 = flattenAthenaReadQueryRows(
|
|
11029
|
+
Array.isArray(result2.data) ? result2.data : [],
|
|
11030
|
+
query.columns,
|
|
11031
|
+
query.rowKey
|
|
11032
|
+
);
|
|
11033
|
+
return {
|
|
11034
|
+
debugAst: getAthenaDebugAst(result2) ?? void 0,
|
|
11035
|
+
rows: rows2,
|
|
11036
|
+
totalItems: resolveTotalItemsFromPage({
|
|
11037
|
+
countCandidates: [countResult.count, result2.count],
|
|
11038
|
+
limit: query.limit,
|
|
11039
|
+
page,
|
|
11040
|
+
pageSize,
|
|
11041
|
+
rowCount: rows2.length
|
|
11042
|
+
})
|
|
11043
|
+
};
|
|
11044
|
+
}
|
|
11045
|
+
const findManyOrderBy = buildAthenaReadQueryFindManyOrderBy(query.orderBy);
|
|
11046
|
+
const findManyOptions = {
|
|
11047
|
+
...query.limit ? { limit: query.limit } : {},
|
|
11048
|
+
...findManyOrderBy ? { orderBy: findManyOrderBy } : {},
|
|
11049
|
+
select: buildAthenaReadQueryFindManySelect(query.columns),
|
|
11050
|
+
...query.filters?.length ? { where: buildAthenaReadQueryFindManyWhere(query.filters) } : {}
|
|
11051
|
+
};
|
|
11052
|
+
const result = await baseBuilder.currentPage(page).pageSize(pageSize).findMany(findManyOptions);
|
|
11053
|
+
const rows = flattenAthenaReadQueryRows(
|
|
11054
|
+
Array.isArray(result.data) ? result.data : [],
|
|
11055
|
+
query.columns,
|
|
11056
|
+
query.rowKey
|
|
11057
|
+
);
|
|
11058
|
+
return {
|
|
11059
|
+
debugAst: getAthenaDebugAst(result) ?? void 0,
|
|
11060
|
+
rows,
|
|
11061
|
+
totalItems: resolveTotalItemsFromPage({
|
|
11062
|
+
countCandidates: [countResult.count, result.count],
|
|
11063
|
+
limit: query.limit,
|
|
11064
|
+
page,
|
|
11065
|
+
pageSize,
|
|
11066
|
+
rowCount: rows.length
|
|
11067
|
+
})
|
|
11068
|
+
};
|
|
11069
|
+
}
|
|
11070
|
+
var executeAthenaTableQuery = executeAthenaReadQuery;
|
|
11071
|
+
|
|
10773
11072
|
// src/schema/definitions.ts
|
|
10774
11073
|
function defineModel(input) {
|
|
10775
11074
|
return input;
|
|
@@ -10790,7 +11089,7 @@ function resolveNullishValue(mode) {
|
|
|
10790
11089
|
if (mode === "null") return null;
|
|
10791
11090
|
return "";
|
|
10792
11091
|
}
|
|
10793
|
-
function
|
|
11092
|
+
function isRecord13(value) {
|
|
10794
11093
|
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
10795
11094
|
}
|
|
10796
11095
|
function isNullableColumn(model, key) {
|
|
@@ -10799,7 +11098,7 @@ function isNullableColumn(model, key) {
|
|
|
10799
11098
|
}
|
|
10800
11099
|
function toModelFormDefaults(model, values, options) {
|
|
10801
11100
|
const source = values;
|
|
10802
|
-
if (!
|
|
11101
|
+
if (!isRecord13(source)) {
|
|
10803
11102
|
return {};
|
|
10804
11103
|
}
|
|
10805
11104
|
const mode = options?.nullishMode ?? "empty-string";
|
|
@@ -11719,6 +12018,12 @@ var ATHENA_DIRECT_TARGETS = {
|
|
|
11719
12018
|
};
|
|
11720
12019
|
var DEFAULT_OUTPUT_FORMAT = "table-builder";
|
|
11721
12020
|
var DEFAULT_OUTPUT_PRESET = "athena-direct";
|
|
12021
|
+
var DEFAULT_ARTIFACT_WRITE_POLICY = "merge";
|
|
12022
|
+
var ARTIFACT_WRITE_POLICIES = /* @__PURE__ */ new Set([
|
|
12023
|
+
"merge",
|
|
12024
|
+
"skip",
|
|
12025
|
+
"overwrite"
|
|
12026
|
+
]);
|
|
11722
12027
|
var DEFAULT_NAMING = {
|
|
11723
12028
|
modelType: "pascal",
|
|
11724
12029
|
modelConst: "camel",
|
|
@@ -11998,6 +12303,23 @@ function normalizeFilterConfig(input) {
|
|
|
11998
12303
|
excludeTables: normalizeTableSelection(input?.excludeTables)
|
|
11999
12304
|
};
|
|
12000
12305
|
}
|
|
12306
|
+
function normalizeArtifactWritePolicy(value, fieldName) {
|
|
12307
|
+
if (value === void 0 || value === null || value === "") {
|
|
12308
|
+
return DEFAULT_ARTIFACT_WRITE_POLICY;
|
|
12309
|
+
}
|
|
12310
|
+
if (typeof value === "string" && ARTIFACT_WRITE_POLICIES.has(value)) {
|
|
12311
|
+
return value;
|
|
12312
|
+
}
|
|
12313
|
+
throw new Error(
|
|
12314
|
+
`Invalid output.artifactWrite.${fieldName}: expected one of merge | skip | overwrite, received ${JSON.stringify(value)}.`
|
|
12315
|
+
);
|
|
12316
|
+
}
|
|
12317
|
+
function normalizeArtifactWriteConfig(input) {
|
|
12318
|
+
return {
|
|
12319
|
+
database: normalizeArtifactWritePolicy(input?.database, "database"),
|
|
12320
|
+
registry: normalizeArtifactWritePolicy(input?.registry, "registry")
|
|
12321
|
+
};
|
|
12322
|
+
}
|
|
12001
12323
|
function normalizeOutputConfig(output) {
|
|
12002
12324
|
const preset = output?.preset ?? DEFAULT_OUTPUT_PRESET;
|
|
12003
12325
|
return {
|
|
@@ -12009,7 +12331,8 @@ function normalizeOutputConfig(output) {
|
|
|
12009
12331
|
},
|
|
12010
12332
|
placeholderMap: {
|
|
12011
12333
|
...output?.placeholderMap ?? {}
|
|
12012
|
-
}
|
|
12334
|
+
},
|
|
12335
|
+
artifactWrite: normalizeArtifactWriteConfig(output?.artifactWrite)
|
|
12013
12336
|
};
|
|
12014
12337
|
}
|
|
12015
12338
|
function normalizeProviderConfig(provider) {
|
|
@@ -12292,6 +12615,486 @@ async function loadGeneratorConfig(options = {}) {
|
|
|
12292
12615
|
}
|
|
12293
12616
|
}
|
|
12294
12617
|
|
|
12618
|
+
// src/generator/schema-discovery.ts
|
|
12619
|
+
var DISCOVER_POSTGRES_SCHEMAS_SQL = `
|
|
12620
|
+
SELECT DISTINCT n.nspname AS schema_name
|
|
12621
|
+
FROM pg_namespace n
|
|
12622
|
+
JOIN pg_class c ON c.relnamespace = n.oid
|
|
12623
|
+
WHERE c.relkind IN ('r', 'p')
|
|
12624
|
+
AND n.nspname NOT IN ('pg_catalog', 'information_schema')
|
|
12625
|
+
AND n.nspname NOT LIKE 'pg_toast%'
|
|
12626
|
+
AND n.nspname NOT LIKE 'pg_temp_%'
|
|
12627
|
+
AND n.nspname NOT LIKE 'pg_toast_temp_%'
|
|
12628
|
+
ORDER BY n.nspname;
|
|
12629
|
+
`.trim();
|
|
12630
|
+
var SYSTEM_SCHEMA_PREFIXES = ["pg_"];
|
|
12631
|
+
var SYSTEM_SCHEMAS = /* @__PURE__ */ new Set(["pg_catalog", "information_schema"]);
|
|
12632
|
+
function normalizeDiscoveredSchemas(input) {
|
|
12633
|
+
const schemas = [];
|
|
12634
|
+
const seen = /* @__PURE__ */ new Set();
|
|
12635
|
+
for (const value of input) {
|
|
12636
|
+
const schema = value.trim();
|
|
12637
|
+
if (!schema || seen.has(schema)) {
|
|
12638
|
+
continue;
|
|
12639
|
+
}
|
|
12640
|
+
if (SYSTEM_SCHEMAS.has(schema)) {
|
|
12641
|
+
continue;
|
|
12642
|
+
}
|
|
12643
|
+
if (SYSTEM_SCHEMA_PREFIXES.some((prefix) => schema.startsWith(prefix))) {
|
|
12644
|
+
continue;
|
|
12645
|
+
}
|
|
12646
|
+
seen.add(schema);
|
|
12647
|
+
schemas.push(schema);
|
|
12648
|
+
}
|
|
12649
|
+
return schemas;
|
|
12650
|
+
}
|
|
12651
|
+
function mergeSchemaSelections(configured, discovered) {
|
|
12652
|
+
const result = [];
|
|
12653
|
+
const seen = /* @__PURE__ */ new Set();
|
|
12654
|
+
for (const value of configured ?? []) {
|
|
12655
|
+
const schema = value.trim();
|
|
12656
|
+
if (!schema || seen.has(schema)) {
|
|
12657
|
+
continue;
|
|
12658
|
+
}
|
|
12659
|
+
seen.add(schema);
|
|
12660
|
+
result.push(schema);
|
|
12661
|
+
}
|
|
12662
|
+
for (const value of discovered) {
|
|
12663
|
+
const schema = value.trim();
|
|
12664
|
+
if (!schema || seen.has(schema)) {
|
|
12665
|
+
continue;
|
|
12666
|
+
}
|
|
12667
|
+
seen.add(schema);
|
|
12668
|
+
result.push(schema);
|
|
12669
|
+
}
|
|
12670
|
+
return result.length > 0 ? result : ["public"];
|
|
12671
|
+
}
|
|
12672
|
+
function schemasEqual(left, right) {
|
|
12673
|
+
const a = normalizeDiscoveredSchemas(left ?? []);
|
|
12674
|
+
const b = normalizeDiscoveredSchemas(right ?? []);
|
|
12675
|
+
if (a.length !== b.length) {
|
|
12676
|
+
return false;
|
|
12677
|
+
}
|
|
12678
|
+
const set = new Set(a);
|
|
12679
|
+
return b.every((schema) => set.has(schema));
|
|
12680
|
+
}
|
|
12681
|
+
function coerceSchemaName(row) {
|
|
12682
|
+
const raw = row.schema_name ?? row.schemaName ?? row.nspname;
|
|
12683
|
+
if (typeof raw !== "string") {
|
|
12684
|
+
return void 0;
|
|
12685
|
+
}
|
|
12686
|
+
const trimmed = raw.trim();
|
|
12687
|
+
return trimmed.length > 0 ? trimmed : void 0;
|
|
12688
|
+
}
|
|
12689
|
+
async function loadPgPoolConstructor2() {
|
|
12690
|
+
const module = await import('pg');
|
|
12691
|
+
const poolConstructor = module.Pool ?? module.default?.Pool;
|
|
12692
|
+
if (!poolConstructor) {
|
|
12693
|
+
throw new Error(
|
|
12694
|
+
'@xylex-group/athena: Unable to load the PostgreSQL driver for schema discovery. Ensure "pg" is installed and this API runs in a Node.js server runtime.'
|
|
12695
|
+
);
|
|
12696
|
+
}
|
|
12697
|
+
return poolConstructor;
|
|
12698
|
+
}
|
|
12699
|
+
async function discoverDirectSchemas(config) {
|
|
12700
|
+
const PoolConstructor = await loadPgPoolConstructor2();
|
|
12701
|
+
const pool = new PoolConstructor({ connectionString: config.connectionString });
|
|
12702
|
+
try {
|
|
12703
|
+
const result = await pool.query(DISCOVER_POSTGRES_SCHEMAS_SQL);
|
|
12704
|
+
const names = result.rows.map(coerceSchemaName).filter((value) => Boolean(value));
|
|
12705
|
+
return normalizeDiscoveredSchemas(names);
|
|
12706
|
+
} finally {
|
|
12707
|
+
await pool.end();
|
|
12708
|
+
}
|
|
12709
|
+
}
|
|
12710
|
+
async function discoverGatewaySchemas(config) {
|
|
12711
|
+
const client = createClient({
|
|
12712
|
+
db: { url: config.gatewayUrl },
|
|
12713
|
+
key: config.apiKey,
|
|
12714
|
+
backend: {
|
|
12715
|
+
type: config.backend ?? "postgresql"
|
|
12716
|
+
}
|
|
12717
|
+
});
|
|
12718
|
+
const result = await client.query(DISCOVER_POSTGRES_SCHEMAS_SQL);
|
|
12719
|
+
if (result.error || result.status < 200 || result.status >= 300) {
|
|
12720
|
+
throw new Error(
|
|
12721
|
+
result.error?.message ?? `Gateway schema discovery failed with status ${result.status}`
|
|
12722
|
+
);
|
|
12723
|
+
}
|
|
12724
|
+
const names = (result.data ?? []).map(coerceSchemaName).filter((value) => Boolean(value));
|
|
12725
|
+
return normalizeDiscoveredSchemas(names);
|
|
12726
|
+
}
|
|
12727
|
+
async function discoverPostgresSchemas(provider) {
|
|
12728
|
+
if (provider.kind === "postgres" && provider.mode === "direct") {
|
|
12729
|
+
return discoverDirectSchemas(provider);
|
|
12730
|
+
}
|
|
12731
|
+
if (provider.kind === "postgres" && provider.mode === "gateway") {
|
|
12732
|
+
return discoverGatewaySchemas(provider);
|
|
12733
|
+
}
|
|
12734
|
+
throw new Error(
|
|
12735
|
+
`Schema discovery is only implemented for postgres direct/gateway providers (received ${provider.kind}/${"mode" in provider ? provider.mode : "unknown"}).`
|
|
12736
|
+
);
|
|
12737
|
+
}
|
|
12738
|
+
|
|
12739
|
+
// src/generator/config-file.ts
|
|
12740
|
+
function hasEnv(keys) {
|
|
12741
|
+
for (const key of keys) {
|
|
12742
|
+
const value = process.env[key];
|
|
12743
|
+
if (typeof value === "string" && value.trim().length > 0) {
|
|
12744
|
+
return true;
|
|
12745
|
+
}
|
|
12746
|
+
}
|
|
12747
|
+
return false;
|
|
12748
|
+
}
|
|
12749
|
+
var DIRECT_CONNECTION_KEYS = [
|
|
12750
|
+
"ATHENA_GENERATOR_PG_URL",
|
|
12751
|
+
"DATABASE_URL",
|
|
12752
|
+
"PG_URL",
|
|
12753
|
+
"POSTGRES_URL",
|
|
12754
|
+
"POSTGRESQL_URL"
|
|
12755
|
+
];
|
|
12756
|
+
var GATEWAY_URL_KEYS = ["ATHENA_URL", "ATHENA_GATEWAY_URL", "ATHENA_GENERATOR_URL"];
|
|
12757
|
+
var GATEWAY_KEY_KEYS = [
|
|
12758
|
+
"ATHENA_API_KEY",
|
|
12759
|
+
"ATHENA_GATEWAY_API_KEY",
|
|
12760
|
+
"ATHENA_GENERATOR_API_KEY"
|
|
12761
|
+
];
|
|
12762
|
+
function detectGeneratorProviderMode(preferred = "auto") {
|
|
12763
|
+
if (preferred === "direct" || preferred === "gateway") {
|
|
12764
|
+
return preferred;
|
|
12765
|
+
}
|
|
12766
|
+
const hasDirect = hasEnv(DIRECT_CONNECTION_KEYS);
|
|
12767
|
+
const hasGateway = hasEnv(GATEWAY_URL_KEYS) && hasEnv(GATEWAY_KEY_KEYS);
|
|
12768
|
+
if (hasDirect) {
|
|
12769
|
+
return "direct";
|
|
12770
|
+
}
|
|
12771
|
+
if (hasGateway) {
|
|
12772
|
+
return "gateway";
|
|
12773
|
+
}
|
|
12774
|
+
return "direct";
|
|
12775
|
+
}
|
|
12776
|
+
function formatStringArray(values, indent) {
|
|
12777
|
+
if (values.length === 0) {
|
|
12778
|
+
return "[]";
|
|
12779
|
+
}
|
|
12780
|
+
const inner = values.map((value) => `${indent} ${JSON.stringify(value)}`).join(",\n");
|
|
12781
|
+
return `[
|
|
12782
|
+
${inner},
|
|
12783
|
+
${indent}]`;
|
|
12784
|
+
}
|
|
12785
|
+
function buildDirectProviderBlock(schemas) {
|
|
12786
|
+
return ` provider: {
|
|
12787
|
+
kind: "postgres",
|
|
12788
|
+
mode: "direct",
|
|
12789
|
+
connectionString: generatorEnv("DATABASE_URL"),
|
|
12790
|
+
database: generatorEnv("ATHENA_GENERATOR_DB", { optional: true }),
|
|
12791
|
+
schemas: ${formatStringArray(schemas, " ")},
|
|
12792
|
+
}`;
|
|
12793
|
+
}
|
|
12794
|
+
function buildGatewayProviderBlock(schemas) {
|
|
12795
|
+
return ` provider: {
|
|
12796
|
+
kind: "postgres",
|
|
12797
|
+
mode: "gateway",
|
|
12798
|
+
gatewayUrl: generatorEnv("ATHENA_URL"),
|
|
12799
|
+
apiKey: generatorEnv("ATHENA_API_KEY"),
|
|
12800
|
+
database: generatorEnv("ATHENA_GENERATOR_DB", { default: "postgres" }),
|
|
12801
|
+
schemas: ${formatStringArray(schemas, " ")},
|
|
12802
|
+
}`;
|
|
12803
|
+
}
|
|
12804
|
+
function renderGeneratorConfigFile(options) {
|
|
12805
|
+
const schemas = options.schemas && options.schemas.length > 0 ? [...options.schemas] : [...DEFAULT_POSTGRES_SCHEMAS];
|
|
12806
|
+
const providerBlock = options.mode === "gateway" ? buildGatewayProviderBlock(schemas) : buildDirectProviderBlock(schemas);
|
|
12807
|
+
return `import { defineGeneratorConfig, generatorEnv } from "@xylex-group/athena";
|
|
12808
|
+
|
|
12809
|
+
export default defineGeneratorConfig({
|
|
12810
|
+
${providerBlock},
|
|
12811
|
+
output: {
|
|
12812
|
+
format: "table-builder",
|
|
12813
|
+
preset: "athena-direct",
|
|
12814
|
+
targets: {
|
|
12815
|
+
model: "athena/models/{schema_kebab}/{model_kebab}.ts",
|
|
12816
|
+
schema: "athena/schemas/{schema_kebab}.ts",
|
|
12817
|
+
database: "athena/relations.ts",
|
|
12818
|
+
registry: "athena/registry.generated.ts",
|
|
12819
|
+
},
|
|
12820
|
+
placeholderMap: {
|
|
12821
|
+
namespace: "athena",
|
|
12822
|
+
},
|
|
12823
|
+
},
|
|
12824
|
+
naming: {
|
|
12825
|
+
modelType: "pascal",
|
|
12826
|
+
modelConst: "camel",
|
|
12827
|
+
schemaConst: "camel",
|
|
12828
|
+
databaseConst: "camel",
|
|
12829
|
+
registryConst: "camel",
|
|
12830
|
+
},
|
|
12831
|
+
features: {
|
|
12832
|
+
emitRelations: true,
|
|
12833
|
+
emitRegistry: true,
|
|
12834
|
+
},
|
|
12835
|
+
experimental: {
|
|
12836
|
+
postgresGatewayIntrospection: false,
|
|
12837
|
+
scyllaProviderContracts: true,
|
|
12838
|
+
},
|
|
12839
|
+
});
|
|
12840
|
+
`;
|
|
12841
|
+
}
|
|
12842
|
+
function resolveConfigPath(cwd, configPath) {
|
|
12843
|
+
if (configPath) {
|
|
12844
|
+
const absolutePath2 = path.resolve(cwd, configPath);
|
|
12845
|
+
return {
|
|
12846
|
+
absolutePath: absolutePath2,
|
|
12847
|
+
relativePath: configPath.replace(/\\/g, "/"),
|
|
12848
|
+
exists: fs.existsSync(absolutePath2)
|
|
12849
|
+
};
|
|
12850
|
+
}
|
|
12851
|
+
const discovered = findGeneratorConfigPath(cwd);
|
|
12852
|
+
if (discovered) {
|
|
12853
|
+
const relativePath = discovered.startsWith(cwd) ? discovered.slice(cwd.length).replace(/^[/\\]/, "").replace(/\\/g, "/") : "athena.config.ts";
|
|
12854
|
+
return {
|
|
12855
|
+
absolutePath: discovered,
|
|
12856
|
+
relativePath,
|
|
12857
|
+
exists: true
|
|
12858
|
+
};
|
|
12859
|
+
}
|
|
12860
|
+
const absolutePath = path.resolve(cwd, "athena.config.ts");
|
|
12861
|
+
return {
|
|
12862
|
+
absolutePath,
|
|
12863
|
+
relativePath: "athena.config.ts",
|
|
12864
|
+
exists: false
|
|
12865
|
+
};
|
|
12866
|
+
}
|
|
12867
|
+
function providerModeFromConfig(provider, preferred) {
|
|
12868
|
+
if (provider && provider.kind === "postgres") {
|
|
12869
|
+
if (provider.mode === "gateway") {
|
|
12870
|
+
return "gateway";
|
|
12871
|
+
}
|
|
12872
|
+
if (provider.mode === "direct") {
|
|
12873
|
+
return "direct";
|
|
12874
|
+
}
|
|
12875
|
+
}
|
|
12876
|
+
return detectGeneratorProviderMode(preferred);
|
|
12877
|
+
}
|
|
12878
|
+
function schemasFromNormalized(config) {
|
|
12879
|
+
if (config.provider.kind !== "postgres") {
|
|
12880
|
+
return [...DEFAULT_POSTGRES_SCHEMAS];
|
|
12881
|
+
}
|
|
12882
|
+
return normalizeSchemaSelection(config.provider.schemas);
|
|
12883
|
+
}
|
|
12884
|
+
function patchSchemasInConfigSource(source, schemas) {
|
|
12885
|
+
const formattedInline = `[${schemas.map((value) => JSON.stringify(value)).join(", ")}]`;
|
|
12886
|
+
const formattedMultiline = formatStringArray(schemas, " ");
|
|
12887
|
+
const listDefaultPattern = /(schemas\s*:\s*generatorEnv\.list\s*\(\s*['"][^'"]+['"]\s*,\s*\{[\s\S]*?default\s*:\s*)(\[[^\]]*\])/m;
|
|
12888
|
+
if (listDefaultPattern.test(source)) {
|
|
12889
|
+
return source.replace(listDefaultPattern, `$1${formattedInline}`);
|
|
12890
|
+
}
|
|
12891
|
+
const literalPattern = /(schemas\s*:\s*)(\[[^\]]*\])/m;
|
|
12892
|
+
if (literalPattern.test(source)) {
|
|
12893
|
+
const usesMultiline = /schemas\s*:\s*\[\s*\n/.test(source);
|
|
12894
|
+
return source.replace(
|
|
12895
|
+
literalPattern,
|
|
12896
|
+
`$1${usesMultiline ? formattedMultiline : formattedInline}`
|
|
12897
|
+
);
|
|
12898
|
+
}
|
|
12899
|
+
const modeLine = /(mode\s*:\s*["'](?:direct|gateway)["']\s*,)/m;
|
|
12900
|
+
if (modeLine.test(source)) {
|
|
12901
|
+
return source.replace(
|
|
12902
|
+
modeLine,
|
|
12903
|
+
`$1
|
|
12904
|
+
schemas: ${formattedInline},`
|
|
12905
|
+
);
|
|
12906
|
+
}
|
|
12907
|
+
return void 0;
|
|
12908
|
+
}
|
|
12909
|
+
function extractLiteralSchemas(source) {
|
|
12910
|
+
const listDefaultMatch = source.match(
|
|
12911
|
+
/schemas\s*:\s*generatorEnv\.list\s*\(\s*['"][^'"]+['"]\s*,\s*\{[\s\S]*?default\s*:\s*(\[[^\]]*\])/m
|
|
12912
|
+
);
|
|
12913
|
+
const literalMatch = listDefaultMatch ?? source.match(/schemas\s*:\s*(\[[^\]]*\])/m);
|
|
12914
|
+
if (!literalMatch) {
|
|
12915
|
+
return void 0;
|
|
12916
|
+
}
|
|
12917
|
+
try {
|
|
12918
|
+
const parsed = JSON.parse(literalMatch[1].replace(/'/g, '"'));
|
|
12919
|
+
if (!Array.isArray(parsed)) {
|
|
12920
|
+
return void 0;
|
|
12921
|
+
}
|
|
12922
|
+
return parsed.map((value) => typeof value === "string" ? value.trim() : "").filter((value) => value.length > 0);
|
|
12923
|
+
} catch {
|
|
12924
|
+
return void 0;
|
|
12925
|
+
}
|
|
12926
|
+
}
|
|
12927
|
+
async function resolveDiscoveredSchemas(options) {
|
|
12928
|
+
if (options.explicit && options.explicit.length > 0) {
|
|
12929
|
+
return {
|
|
12930
|
+
schemas: normalizeSchemaSelection(options.explicit),
|
|
12931
|
+
discovered: false
|
|
12932
|
+
};
|
|
12933
|
+
}
|
|
12934
|
+
if (!options.discoverSchemas) {
|
|
12935
|
+
if (options.loaded) {
|
|
12936
|
+
return {
|
|
12937
|
+
schemas: schemasFromNormalized(options.loaded.config),
|
|
12938
|
+
discovered: false
|
|
12939
|
+
};
|
|
12940
|
+
}
|
|
12941
|
+
return {
|
|
12942
|
+
schemas: [...DEFAULT_POSTGRES_SCHEMAS],
|
|
12943
|
+
discovered: false
|
|
12944
|
+
};
|
|
12945
|
+
}
|
|
12946
|
+
try {
|
|
12947
|
+
let provider = options.provider;
|
|
12948
|
+
if (!provider && options.loaded) {
|
|
12949
|
+
provider = options.loaded.config.provider;
|
|
12950
|
+
}
|
|
12951
|
+
if (!provider) {
|
|
12952
|
+
const probeConfig = {
|
|
12953
|
+
provider: options.mode === "gateway" ? { kind: "postgres", mode: "gateway" } : { kind: "postgres", mode: "direct" }
|
|
12954
|
+
};
|
|
12955
|
+
const normalized = normalizeGeneratorConfig(probeConfig);
|
|
12956
|
+
provider = normalized.provider;
|
|
12957
|
+
}
|
|
12958
|
+
const discovered = await discoverPostgresSchemas(provider);
|
|
12959
|
+
if (discovered.length === 0) {
|
|
12960
|
+
const fallback = options.loaded ? schemasFromNormalized(options.loaded.config) : [...DEFAULT_POSTGRES_SCHEMAS];
|
|
12961
|
+
return { schemas: fallback, discovered: true };
|
|
12962
|
+
}
|
|
12963
|
+
if (options.loaded) {
|
|
12964
|
+
return {
|
|
12965
|
+
schemas: mergeSchemaSelections(schemasFromNormalized(options.loaded.config), discovered),
|
|
12966
|
+
discovered: true
|
|
12967
|
+
};
|
|
12968
|
+
}
|
|
12969
|
+
return { schemas: discovered, discovered: true };
|
|
12970
|
+
} catch (error) {
|
|
12971
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
12972
|
+
const fallback = options.loaded ? schemasFromNormalized(options.loaded.config) : [...DEFAULT_POSTGRES_SCHEMAS];
|
|
12973
|
+
return {
|
|
12974
|
+
schemas: fallback,
|
|
12975
|
+
discovered: false,
|
|
12976
|
+
discoveryError: message
|
|
12977
|
+
};
|
|
12978
|
+
}
|
|
12979
|
+
}
|
|
12980
|
+
async function ensureGeneratorConfigFile(options = {}) {
|
|
12981
|
+
const cwd = options.cwd ?? process.cwd();
|
|
12982
|
+
const dryRun = options.dryRun === true;
|
|
12983
|
+
const discoverSchemas = options.discoverSchemas !== false;
|
|
12984
|
+
const force = options.force === true;
|
|
12985
|
+
const preferredMode = options.mode ?? "auto";
|
|
12986
|
+
const pathInfo = resolveConfigPath(cwd, options.configPath);
|
|
12987
|
+
const changes = [];
|
|
12988
|
+
let loaded = options.loaded;
|
|
12989
|
+
if (!loaded && pathInfo.exists && !force) {
|
|
12990
|
+
try {
|
|
12991
|
+
loaded = await loadGeneratorConfig({
|
|
12992
|
+
cwd,
|
|
12993
|
+
configPath: pathInfo.absolutePath
|
|
12994
|
+
});
|
|
12995
|
+
} catch {
|
|
12996
|
+
}
|
|
12997
|
+
}
|
|
12998
|
+
const mode = providerModeFromConfig(loaded?.config.provider ?? options.provider, preferredMode);
|
|
12999
|
+
const schemaResolution = await resolveDiscoveredSchemas({
|
|
13000
|
+
discoverSchemas,
|
|
13001
|
+
provider: options.provider ?? loaded?.config.provider,
|
|
13002
|
+
loaded,
|
|
13003
|
+
explicit: options.schemas,
|
|
13004
|
+
mode
|
|
13005
|
+
});
|
|
13006
|
+
if (schemaResolution.discoveryError) {
|
|
13007
|
+
changes.push(`schema-discovery-failed: ${schemaResolution.discoveryError}`);
|
|
13008
|
+
} else if (schemaResolution.discovered) {
|
|
13009
|
+
changes.push(`schemas-discovered: ${schemaResolution.schemas.join(",")}`);
|
|
13010
|
+
}
|
|
13011
|
+
if (!pathInfo.exists || force) {
|
|
13012
|
+
const content = renderGeneratorConfigFile({
|
|
13013
|
+
mode,
|
|
13014
|
+
schemas: schemaResolution.schemas
|
|
13015
|
+
});
|
|
13016
|
+
if (!pathInfo.exists) {
|
|
13017
|
+
changes.push("created-modern-config");
|
|
13018
|
+
} else {
|
|
13019
|
+
changes.push("force-rewrote-config");
|
|
13020
|
+
}
|
|
13021
|
+
if (!dryRun) {
|
|
13022
|
+
await promises.mkdir(path.dirname(pathInfo.absolutePath), { recursive: true });
|
|
13023
|
+
await promises.writeFile(pathInfo.absolutePath, content, "utf8");
|
|
13024
|
+
}
|
|
13025
|
+
return {
|
|
13026
|
+
action: pathInfo.exists ? "updated" : "created",
|
|
13027
|
+
path: pathInfo.relativePath,
|
|
13028
|
+
absolutePath: pathInfo.absolutePath,
|
|
13029
|
+
content,
|
|
13030
|
+
schemas: schemaResolution.schemas,
|
|
13031
|
+
changes,
|
|
13032
|
+
mode,
|
|
13033
|
+
reason: pathInfo.exists ? "force rewrite" : "config file missing"
|
|
13034
|
+
};
|
|
13035
|
+
}
|
|
13036
|
+
const existingSource = await promises.readFile(pathInfo.absolutePath, "utf8");
|
|
13037
|
+
const existingLiteralSchemas = extractLiteralSchemas(existingSource);
|
|
13038
|
+
const existingSchemas = existingLiteralSchemas ?? (loaded ? schemasFromNormalized(loaded.config) : [...DEFAULT_POSTGRES_SCHEMAS]);
|
|
13039
|
+
if (schemasEqual(existingSchemas, schemaResolution.schemas)) {
|
|
13040
|
+
return {
|
|
13041
|
+
action: "unchanged",
|
|
13042
|
+
path: pathInfo.relativePath,
|
|
13043
|
+
absolutePath: pathInfo.absolutePath,
|
|
13044
|
+
content: existingSource,
|
|
13045
|
+
schemas: existingSchemas,
|
|
13046
|
+
changes: changes.length > 0 ? changes : ["schemas-already-current"],
|
|
13047
|
+
mode,
|
|
13048
|
+
reason: "schemas already match discovered/configured set"
|
|
13049
|
+
};
|
|
13050
|
+
}
|
|
13051
|
+
const patched = patchSchemasInConfigSource(existingSource, schemaResolution.schemas);
|
|
13052
|
+
if (!patched) {
|
|
13053
|
+
return {
|
|
13054
|
+
action: "skipped",
|
|
13055
|
+
path: pathInfo.relativePath,
|
|
13056
|
+
absolutePath: pathInfo.absolutePath,
|
|
13057
|
+
content: existingSource,
|
|
13058
|
+
schemas: existingSchemas,
|
|
13059
|
+
changes: [
|
|
13060
|
+
...changes,
|
|
13061
|
+
"could-not-patch-schemas-surgically",
|
|
13062
|
+
"re-run with force=true to rewrite full template"
|
|
13063
|
+
],
|
|
13064
|
+
mode,
|
|
13065
|
+
reason: "existing config schemas could not be updated surgically without risking a destructive rewrite"
|
|
13066
|
+
};
|
|
13067
|
+
}
|
|
13068
|
+
if (patched === existingSource) {
|
|
13069
|
+
return {
|
|
13070
|
+
action: "unchanged",
|
|
13071
|
+
path: pathInfo.relativePath,
|
|
13072
|
+
absolutePath: pathInfo.absolutePath,
|
|
13073
|
+
content: existingSource,
|
|
13074
|
+
schemas: existingSchemas,
|
|
13075
|
+
changes: [...changes, "patch-noop"],
|
|
13076
|
+
mode,
|
|
13077
|
+
reason: "patch produced identical content"
|
|
13078
|
+
};
|
|
13079
|
+
}
|
|
13080
|
+
changes.push(
|
|
13081
|
+
`schemas-updated: ${existingSchemas.join(",")} -> ${schemaResolution.schemas.join(",")}`
|
|
13082
|
+
);
|
|
13083
|
+
if (!dryRun) {
|
|
13084
|
+
await promises.writeFile(pathInfo.absolutePath, patched, "utf8");
|
|
13085
|
+
}
|
|
13086
|
+
return {
|
|
13087
|
+
action: "updated",
|
|
13088
|
+
path: pathInfo.relativePath,
|
|
13089
|
+
absolutePath: pathInfo.absolutePath,
|
|
13090
|
+
content: patched,
|
|
13091
|
+
schemas: schemaResolution.schemas,
|
|
13092
|
+
changes,
|
|
13093
|
+
mode,
|
|
13094
|
+
reason: "auto-filled provider.schemas"
|
|
13095
|
+
};
|
|
13096
|
+
}
|
|
13097
|
+
|
|
12295
13098
|
// src/generator/env.ts
|
|
12296
13099
|
function readEnvStringValue2(key) {
|
|
12297
13100
|
if (typeof process === "undefined" || !process.env) {
|
|
@@ -13270,9 +14073,764 @@ function resolveGeneratorProvider(providerConfig, experimentalFlags) {
|
|
|
13270
14073
|
}
|
|
13271
14074
|
throw new Error(`Unsupported generator provider kind: ${providerConfig.kind ?? "unknown"}`);
|
|
13272
14075
|
}
|
|
13273
|
-
|
|
13274
|
-
|
|
14076
|
+
|
|
14077
|
+
// src/generator/artifact-merge.ts
|
|
14078
|
+
var IMPORT_RE = /^import\s+(?:type\s+)?(?:\{([^}]*)\}|([A-Za-z_$][\w$]*))\s+from\s+(['"])([^'"]+)\3\s*;?\s*$/gm;
|
|
14079
|
+
var DEFINE_EXPORT_RE = /export\s+const\s+([A-Za-z_$][\w$]*)\s*=\s*(define(?:Database|Registry))\s*\(\s*\{/g;
|
|
14080
|
+
var META_EXPORT_RE = /export\s+const\s+__athena_schema_meta\s*=\s*\{/g;
|
|
14081
|
+
var KNOWN_META_KEYS = /* @__PURE__ */ new Set([
|
|
14082
|
+
"schemaVersion",
|
|
14083
|
+
"generatedAt",
|
|
14084
|
+
"database",
|
|
14085
|
+
"outputPreset",
|
|
14086
|
+
"outputFormat"
|
|
14087
|
+
]);
|
|
14088
|
+
function detectNewline(source) {
|
|
14089
|
+
return source.includes("\r\n") ? "\r\n" : "\n";
|
|
14090
|
+
}
|
|
14091
|
+
function detectStyle(source) {
|
|
14092
|
+
const newline = detectNewline(source);
|
|
14093
|
+
const single = (source.match(/'/g) ?? []).length;
|
|
14094
|
+
const double = (source.match(/"/g) ?? []).length;
|
|
14095
|
+
const quote = double > single ? '"' : "'";
|
|
14096
|
+
const importLines = source.split(/\r?\n/).filter((line) => line.trimStart().startsWith("import "));
|
|
14097
|
+
const semicolons = importLines.length > 0 ? importLines.filter((line) => line.trimEnd().endsWith(";")).length >= importLines.length / 2 : false;
|
|
14098
|
+
const objectLines = source.split(/\r?\n/).map((line) => line.trim()).filter((line) => /^[A-Za-z0-9_'"]+\s*:\s*.+/.test(line));
|
|
14099
|
+
const trailingComma = objectLines.length > 0 ? objectLines.filter((line) => line.endsWith(",")).length >= Math.ceil(objectLines.length / 2) : true;
|
|
14100
|
+
const indentMatch = source.match(/\n([ \t]+)\S/);
|
|
14101
|
+
const indent = indentMatch?.[1] ?? " ";
|
|
14102
|
+
return { quote, semicolons, trailingComma, indent, newline };
|
|
14103
|
+
}
|
|
14104
|
+
function quoteString(value, quote) {
|
|
14105
|
+
const escaped = value.replace(/\\/g, "\\\\").replace(new RegExp(quote, "g"), `\\${quote}`);
|
|
14106
|
+
return `${quote}${escaped}${quote}`;
|
|
14107
|
+
}
|
|
14108
|
+
function parseNamedImports(source) {
|
|
14109
|
+
const imports = [];
|
|
14110
|
+
IMPORT_RE.lastIndex = 0;
|
|
14111
|
+
let match;
|
|
14112
|
+
while ((match = IMPORT_RE.exec(source)) !== null) {
|
|
14113
|
+
const named = match[1];
|
|
14114
|
+
const defaultName = match[2];
|
|
14115
|
+
const module = match[4];
|
|
14116
|
+
const names = named ? named.split(",").map((part) => part.trim()).filter(Boolean).map((part) => {
|
|
14117
|
+
const alias = part.split(/\s+as\s+/);
|
|
14118
|
+
return (alias[1] ?? alias[0]).trim();
|
|
14119
|
+
}) : defaultName ? [defaultName] : [];
|
|
14120
|
+
imports.push({
|
|
14121
|
+
names,
|
|
14122
|
+
module,
|
|
14123
|
+
raw: match[0],
|
|
14124
|
+
start: match.index,
|
|
14125
|
+
end: match.index + match[0].length
|
|
14126
|
+
});
|
|
14127
|
+
}
|
|
14128
|
+
return imports;
|
|
14129
|
+
}
|
|
14130
|
+
function findMatchingBrace(source, openIndex) {
|
|
14131
|
+
let depth = 0;
|
|
14132
|
+
let inSingle = false;
|
|
14133
|
+
let inDouble = false;
|
|
14134
|
+
let inTemplate = false;
|
|
14135
|
+
let escaped = false;
|
|
14136
|
+
for (let i = openIndex; i < source.length; i += 1) {
|
|
14137
|
+
const ch = source[i];
|
|
14138
|
+
if (escaped) {
|
|
14139
|
+
escaped = false;
|
|
14140
|
+
continue;
|
|
14141
|
+
}
|
|
14142
|
+
if (ch === "\\" && (inSingle || inDouble || inTemplate)) {
|
|
14143
|
+
escaped = true;
|
|
14144
|
+
continue;
|
|
14145
|
+
}
|
|
14146
|
+
if (!inDouble && !inTemplate && ch === "'") {
|
|
14147
|
+
inSingle = !inSingle;
|
|
14148
|
+
continue;
|
|
14149
|
+
}
|
|
14150
|
+
if (!inSingle && !inTemplate && ch === '"') {
|
|
14151
|
+
inDouble = !inDouble;
|
|
14152
|
+
continue;
|
|
14153
|
+
}
|
|
14154
|
+
if (!inSingle && !inDouble && ch === "`") {
|
|
14155
|
+
inTemplate = !inTemplate;
|
|
14156
|
+
continue;
|
|
14157
|
+
}
|
|
14158
|
+
if (inSingle || inDouble || inTemplate) {
|
|
14159
|
+
continue;
|
|
14160
|
+
}
|
|
14161
|
+
if (ch === "{") {
|
|
14162
|
+
depth += 1;
|
|
14163
|
+
} else if (ch === "}") {
|
|
14164
|
+
depth -= 1;
|
|
14165
|
+
if (depth === 0) {
|
|
14166
|
+
return i;
|
|
14167
|
+
}
|
|
14168
|
+
}
|
|
14169
|
+
}
|
|
14170
|
+
return -1;
|
|
14171
|
+
}
|
|
14172
|
+
function parseObjectEntries(body) {
|
|
14173
|
+
const entries = [];
|
|
14174
|
+
const lines = body.split(/\r?\n/);
|
|
14175
|
+
for (const line of lines) {
|
|
14176
|
+
const trimmed = line.trim();
|
|
14177
|
+
if (!trimmed || trimmed.startsWith("//") || trimmed.startsWith("/*")) {
|
|
14178
|
+
continue;
|
|
14179
|
+
}
|
|
14180
|
+
const withoutComma = trimmed.endsWith(",") ? trimmed.slice(0, -1).trimEnd() : trimmed;
|
|
14181
|
+
const match = withoutComma.match(/^([A-Za-z_$][\w$]*|['"][^'"]+['"])\s*:\s*(.+)$/);
|
|
14182
|
+
if (!match) {
|
|
14183
|
+
continue;
|
|
14184
|
+
}
|
|
14185
|
+
const keyRaw = match[1];
|
|
14186
|
+
const key = keyRaw.startsWith("'") || keyRaw.startsWith('"') ? keyRaw.slice(1, -1) : keyRaw;
|
|
14187
|
+
entries.push({
|
|
14188
|
+
key,
|
|
14189
|
+
value: match[2].trim(),
|
|
14190
|
+
raw: trimmed
|
|
14191
|
+
});
|
|
14192
|
+
}
|
|
14193
|
+
return entries;
|
|
13275
14194
|
}
|
|
14195
|
+
function parseDefineBlocks(source) {
|
|
14196
|
+
const blocks = [];
|
|
14197
|
+
DEFINE_EXPORT_RE.lastIndex = 0;
|
|
14198
|
+
let match;
|
|
14199
|
+
while ((match = DEFINE_EXPORT_RE.exec(source)) !== null) {
|
|
14200
|
+
const exportName = match[1];
|
|
14201
|
+
const callName = match[2];
|
|
14202
|
+
const openBrace = match.index + match[0].lastIndexOf("{");
|
|
14203
|
+
const closeBrace = findMatchingBrace(source, openBrace);
|
|
14204
|
+
if (closeBrace < 0) {
|
|
14205
|
+
continue;
|
|
14206
|
+
}
|
|
14207
|
+
const body = source.slice(openBrace + 1, closeBrace);
|
|
14208
|
+
const fullEnd = (() => {
|
|
14209
|
+
let i = closeBrace + 1;
|
|
14210
|
+
while (i < source.length && /\s/.test(source[i])) i += 1;
|
|
14211
|
+
if (source[i] === ")") i += 1;
|
|
14212
|
+
while (i < source.length && /\s/.test(source[i])) i += 1;
|
|
14213
|
+
if (source[i] === ";") i += 1;
|
|
14214
|
+
return i;
|
|
14215
|
+
})();
|
|
14216
|
+
blocks.push({
|
|
14217
|
+
kind: callName === "defineDatabase" ? "database" : "registry",
|
|
14218
|
+
exportName,
|
|
14219
|
+
callName,
|
|
14220
|
+
entries: parseObjectEntries(body),
|
|
14221
|
+
bodyStart: openBrace + 1,
|
|
14222
|
+
bodyEnd: closeBrace,
|
|
14223
|
+
fullStart: match.index,
|
|
14224
|
+
fullEnd,
|
|
14225
|
+
raw: source.slice(match.index, fullEnd)
|
|
14226
|
+
});
|
|
14227
|
+
}
|
|
14228
|
+
return blocks;
|
|
14229
|
+
}
|
|
14230
|
+
function parseMetaBlock(source) {
|
|
14231
|
+
META_EXPORT_RE.lastIndex = 0;
|
|
14232
|
+
const match = META_EXPORT_RE.exec(source);
|
|
14233
|
+
if (!match) {
|
|
14234
|
+
return void 0;
|
|
14235
|
+
}
|
|
14236
|
+
const openBrace = match.index + match[0].lastIndexOf("{");
|
|
14237
|
+
const closeBrace = findMatchingBrace(source, openBrace);
|
|
14238
|
+
if (closeBrace < 0) {
|
|
14239
|
+
return void 0;
|
|
14240
|
+
}
|
|
14241
|
+
let fullEnd = closeBrace + 1;
|
|
14242
|
+
const after = source.slice(fullEnd);
|
|
14243
|
+
const asConst = after.match(/^\s*as\s+const\s*;?/);
|
|
14244
|
+
if (asConst) {
|
|
14245
|
+
fullEnd += asConst[0].length;
|
|
14246
|
+
} else if (source[fullEnd] === ";") {
|
|
14247
|
+
fullEnd += 1;
|
|
14248
|
+
}
|
|
14249
|
+
return {
|
|
14250
|
+
entries: parseObjectEntries(source.slice(openBrace + 1, closeBrace)),
|
|
14251
|
+
bodyStart: openBrace + 1,
|
|
14252
|
+
bodyEnd: closeBrace,
|
|
14253
|
+
fullStart: match.index,
|
|
14254
|
+
fullEnd,
|
|
14255
|
+
raw: source.slice(match.index, fullEnd)
|
|
14256
|
+
};
|
|
14257
|
+
}
|
|
14258
|
+
function hasImportBinding(imports, name, module) {
|
|
14259
|
+
return imports.some(
|
|
14260
|
+
(item) => item.names.includes(name) && (module === void 0)
|
|
14261
|
+
);
|
|
14262
|
+
}
|
|
14263
|
+
function findImportForName(imports, name) {
|
|
14264
|
+
return imports.find((item) => item.names.includes(name));
|
|
14265
|
+
}
|
|
14266
|
+
function normalizeModulePath(modulePath) {
|
|
14267
|
+
return modulePath.replace(/\\/g, "/").replace(/^\.\//, "").replace(/\.ts$/, "");
|
|
14268
|
+
}
|
|
14269
|
+
function formatImport(names, modulePath, style) {
|
|
14270
|
+
const body = `import { ${names.join(", ")} } from ${quoteString(modulePath, style.quote)}`;
|
|
14271
|
+
return style.semicolons ? `${body};` : body;
|
|
14272
|
+
}
|
|
14273
|
+
function formatObjectEntry(key, value, style, isLast) {
|
|
14274
|
+
const needsQuote = !/^[A-Za-z_$][\w$]*$/.test(key);
|
|
14275
|
+
const renderedKey = needsQuote ? quoteString(key, style.quote) : key;
|
|
14276
|
+
const comma = !isLast || style.trailingComma ? "," : "";
|
|
14277
|
+
return `${style.indent}${renderedKey}: ${value}${comma}`;
|
|
14278
|
+
}
|
|
14279
|
+
function replaceRange(source, start, end, insertion) {
|
|
14280
|
+
return source.slice(0, start) + insertion + source.slice(end);
|
|
14281
|
+
}
|
|
14282
|
+
function collectDuplicateKeys(entries) {
|
|
14283
|
+
const seen = /* @__PURE__ */ new Set();
|
|
14284
|
+
const dupes = [];
|
|
14285
|
+
for (const entry of entries) {
|
|
14286
|
+
if (seen.has(entry.key)) {
|
|
14287
|
+
dupes.push(entry.key);
|
|
14288
|
+
}
|
|
14289
|
+
seen.add(entry.key);
|
|
14290
|
+
}
|
|
14291
|
+
return dupes;
|
|
14292
|
+
}
|
|
14293
|
+
function collectDuplicateImportBindings(imports) {
|
|
14294
|
+
const seen = /* @__PURE__ */ new Set();
|
|
14295
|
+
const dupes = [];
|
|
14296
|
+
for (const item of imports) {
|
|
14297
|
+
for (const name of item.names) {
|
|
14298
|
+
if (seen.has(name)) {
|
|
14299
|
+
dupes.push(name);
|
|
14300
|
+
}
|
|
14301
|
+
seen.add(name);
|
|
14302
|
+
}
|
|
14303
|
+
}
|
|
14304
|
+
return dupes;
|
|
14305
|
+
}
|
|
14306
|
+
function lintArtifactSource(source, kind) {
|
|
14307
|
+
const errors = [];
|
|
14308
|
+
const imports = parseNamedImports(source);
|
|
14309
|
+
const dupImports = collectDuplicateImportBindings(imports);
|
|
14310
|
+
if (dupImports.length > 0) {
|
|
14311
|
+
errors.push(`duplicate import bindings: ${dupImports.join(", ")}`);
|
|
14312
|
+
}
|
|
14313
|
+
const blocks = parseDefineBlocks(source).filter((block2) => block2.kind === kind);
|
|
14314
|
+
if (blocks.length === 0) {
|
|
14315
|
+
errors.push(`missing export const \u2026 = define${kind === "database" ? "Database" : "Registry"}({\u2026})`);
|
|
14316
|
+
return errors;
|
|
14317
|
+
}
|
|
14318
|
+
if (blocks.length > 1) {
|
|
14319
|
+
errors.push(`multiple define${kind === "database" ? "Database" : "Registry"} exports found`);
|
|
14320
|
+
}
|
|
14321
|
+
const block = blocks[0];
|
|
14322
|
+
const dupKeys = collectDuplicateKeys(block.entries);
|
|
14323
|
+
if (dupKeys.length > 0) {
|
|
14324
|
+
errors.push(`duplicate object keys: ${dupKeys.join(", ")}`);
|
|
14325
|
+
}
|
|
14326
|
+
for (const entry of block.entries) {
|
|
14327
|
+
const valueId = entry.value.match(/^[A-Za-z_$][\w$]*$/)?.[0];
|
|
14328
|
+
if (valueId && !hasImportBinding(imports, valueId) && valueId !== block.exportName) {
|
|
14329
|
+
if (!source.includes(`const ${valueId}`) && !source.includes(`function ${valueId}`)) {
|
|
14330
|
+
errors.push(`value "${valueId}" for key "${entry.key}" is not imported`);
|
|
14331
|
+
}
|
|
14332
|
+
}
|
|
14333
|
+
}
|
|
14334
|
+
if (kind === "database" && !hasImportBinding(imports, "defineDatabase")) {
|
|
14335
|
+
errors.push("missing defineDatabase import");
|
|
14336
|
+
}
|
|
14337
|
+
if (kind === "registry" && !hasImportBinding(imports, "defineRegistry")) {
|
|
14338
|
+
errors.push("missing defineRegistry import");
|
|
14339
|
+
}
|
|
14340
|
+
return errors;
|
|
14341
|
+
}
|
|
14342
|
+
function preservedCustomUnits(existing, generated, kind) {
|
|
14343
|
+
const custom = [];
|
|
14344
|
+
const existingImports = parseNamedImports(existing);
|
|
14345
|
+
const generatedImports = parseNamedImports(generated);
|
|
14346
|
+
const generatedModules = new Set(generatedImports.map((item) => normalizeModulePath(item.module)));
|
|
14347
|
+
const generatedNames = new Set(generatedImports.flatMap((item) => item.names));
|
|
14348
|
+
for (const item of existingImports) {
|
|
14349
|
+
const moduleNorm = normalizeModulePath(item.module);
|
|
14350
|
+
if (moduleNorm.includes("@xylex-group/athena")) {
|
|
14351
|
+
continue;
|
|
14352
|
+
}
|
|
14353
|
+
const unexpectedNames = item.names.filter((name) => !generatedNames.has(name));
|
|
14354
|
+
if (unexpectedNames.length > 0 && !generatedModules.has(moduleNorm)) {
|
|
14355
|
+
custom.push(`import { ${unexpectedNames.join(", ")} } from '${item.module}'`);
|
|
14356
|
+
} else if (unexpectedNames.length > 0) {
|
|
14357
|
+
custom.push(`import binding(s): ${unexpectedNames.join(", ")}`);
|
|
14358
|
+
}
|
|
14359
|
+
}
|
|
14360
|
+
const existingBlocks = parseDefineBlocks(existing).filter((block) => block.kind === kind);
|
|
14361
|
+
const generatedBlocks = parseDefineBlocks(generated).filter((block) => block.kind === kind);
|
|
14362
|
+
const generatedKeys = new Set(generatedBlocks[0]?.entries.map((entry) => entry.key) ?? []);
|
|
14363
|
+
for (const entry of existingBlocks[0]?.entries ?? []) {
|
|
14364
|
+
if (!generatedKeys.has(entry.key)) {
|
|
14365
|
+
custom.push(`${kind} entry: ${entry.key}: ${entry.value}`);
|
|
14366
|
+
}
|
|
14367
|
+
}
|
|
14368
|
+
if (kind === "registry") {
|
|
14369
|
+
const existingMeta = parseMetaBlock(existing);
|
|
14370
|
+
const generatedMeta = parseMetaBlock(generated);
|
|
14371
|
+
const generatedMetaKeys = new Set(generatedMeta?.entries.map((entry) => entry.key) ?? []);
|
|
14372
|
+
for (const entry of existingMeta?.entries ?? []) {
|
|
14373
|
+
if (!generatedMetaKeys.has(entry.key) && !KNOWN_META_KEYS.has(entry.key)) {
|
|
14374
|
+
custom.push(`meta entry: ${entry.key}: ${entry.value}`);
|
|
14375
|
+
}
|
|
14376
|
+
}
|
|
14377
|
+
}
|
|
14378
|
+
const exportConstRe = /^export\s+const\s+([A-Za-z_$][\w$]*)\b/gm;
|
|
14379
|
+
const generatedExports = /* @__PURE__ */ new Set();
|
|
14380
|
+
let match;
|
|
14381
|
+
exportConstRe.lastIndex = 0;
|
|
14382
|
+
while ((match = exportConstRe.exec(generated)) !== null) {
|
|
14383
|
+
generatedExports.add(match[1]);
|
|
14384
|
+
}
|
|
14385
|
+
exportConstRe.lastIndex = 0;
|
|
14386
|
+
while ((match = exportConstRe.exec(existing)) !== null) {
|
|
14387
|
+
if (!generatedExports.has(match[1]) && match[1] !== "__athena_schema_meta") {
|
|
14388
|
+
custom.push(`export const ${match[1]}`);
|
|
14389
|
+
}
|
|
14390
|
+
}
|
|
14391
|
+
return custom;
|
|
14392
|
+
}
|
|
14393
|
+
function insertImportAfterPackageImports(source, importLine, style) {
|
|
14394
|
+
const imports = parseNamedImports(source);
|
|
14395
|
+
if (imports.length === 0) {
|
|
14396
|
+
return `${importLine}${style.newline}${source}`;
|
|
14397
|
+
}
|
|
14398
|
+
let anchor = imports[imports.length - 1];
|
|
14399
|
+
for (let i = imports.length - 1; i >= 0; i -= 1) {
|
|
14400
|
+
if (imports[i].module.startsWith(".")) {
|
|
14401
|
+
anchor = imports[i];
|
|
14402
|
+
break;
|
|
14403
|
+
}
|
|
14404
|
+
}
|
|
14405
|
+
const insertAt = anchor.end;
|
|
14406
|
+
const before = source.slice(0, insertAt);
|
|
14407
|
+
const after = source.slice(insertAt);
|
|
14408
|
+
const needsLeadingNl = !before.endsWith("\n");
|
|
14409
|
+
const prefix = needsLeadingNl ? style.newline : "";
|
|
14410
|
+
return `${before}${prefix}${importLine}${after.startsWith("\n") || after.startsWith("\r\n") ? "" : style.newline}${after}`;
|
|
14411
|
+
}
|
|
14412
|
+
function rewriteObjectBody(entries, style) {
|
|
14413
|
+
if (entries.length === 0) {
|
|
14414
|
+
return style.newline;
|
|
14415
|
+
}
|
|
14416
|
+
const lines = entries.map(
|
|
14417
|
+
(entry, index) => formatObjectEntry(entry.key, entry.value, style, index === entries.length - 1)
|
|
14418
|
+
);
|
|
14419
|
+
return `${style.newline}${lines.join(style.newline)}${style.newline}`;
|
|
14420
|
+
}
|
|
14421
|
+
function mergeDatabaseArtifact(existing, generated) {
|
|
14422
|
+
const style = detectStyle(existing);
|
|
14423
|
+
const generatedStyle = detectStyle(generated);
|
|
14424
|
+
const effectiveStyle = {
|
|
14425
|
+
...style,
|
|
14426
|
+
// Prefer existing fingerprint; fall back to generated if existing is empty-ish
|
|
14427
|
+
quote: existing.includes('"') || existing.includes("'") ? style.quote : generatedStyle.quote
|
|
14428
|
+
};
|
|
14429
|
+
const generatedImports = parseNamedImports(generated);
|
|
14430
|
+
const existingBlocks = parseDefineBlocks(existing).filter((block) => block.kind === "database");
|
|
14431
|
+
const generatedBlocks = parseDefineBlocks(generated).filter((block) => block.kind === "database");
|
|
14432
|
+
if (existingBlocks.length === 0 || generatedBlocks.length === 0) {
|
|
14433
|
+
return {
|
|
14434
|
+
action: "skip",
|
|
14435
|
+
skipReason: "merge-unparseable",
|
|
14436
|
+
added: [],
|
|
14437
|
+
preservedCustom: [],
|
|
14438
|
+
conflicts: [],
|
|
14439
|
+
lintErrors: [],
|
|
14440
|
+
detail: "could not locate defineDatabase({\u2026}) export for merge"
|
|
14441
|
+
};
|
|
14442
|
+
}
|
|
14443
|
+
const generatedBlock = generatedBlocks[0];
|
|
14444
|
+
const conflicts = [];
|
|
14445
|
+
const added = [];
|
|
14446
|
+
let next = existing;
|
|
14447
|
+
if (!hasImportBinding(parseNamedImports(next), "defineDatabase")) {
|
|
14448
|
+
const pkgImport = generatedImports.find((item) => item.names.includes("defineDatabase"));
|
|
14449
|
+
if (pkgImport) {
|
|
14450
|
+
const line = formatImport(["defineDatabase"], pkgImport.module, effectiveStyle);
|
|
14451
|
+
next = insertImportAfterPackageImports(next, line, effectiveStyle);
|
|
14452
|
+
added.push("import defineDatabase");
|
|
14453
|
+
}
|
|
14454
|
+
}
|
|
14455
|
+
let workingImports = parseNamedImports(next);
|
|
14456
|
+
let workingBlocks = parseDefineBlocks(next).filter((block) => block.kind === "database");
|
|
14457
|
+
let workingBlock = workingBlocks[0];
|
|
14458
|
+
const entryMap = new Map(workingBlock.entries.map((entry) => [entry.key, entry]));
|
|
14459
|
+
for (const desired of generatedBlock.entries) {
|
|
14460
|
+
const existingEntry = entryMap.get(desired.key);
|
|
14461
|
+
if (existingEntry) {
|
|
14462
|
+
if (existingEntry.value !== desired.value) {
|
|
14463
|
+
conflicts.push(
|
|
14464
|
+
`key "${desired.key}" maps to ${existingEntry.value} (existing) vs ${desired.value} (generated)`
|
|
14465
|
+
);
|
|
14466
|
+
}
|
|
14467
|
+
continue;
|
|
14468
|
+
}
|
|
14469
|
+
const desiredImport = generatedImports.find((item) => item.names.includes(desired.value));
|
|
14470
|
+
if (desiredImport) {
|
|
14471
|
+
const existingForName = findImportForName(workingImports, desired.value);
|
|
14472
|
+
if (existingForName) {
|
|
14473
|
+
if (normalizeModulePath(existingForName.module) !== normalizeModulePath(desiredImport.module)) {
|
|
14474
|
+
conflicts.push(
|
|
14475
|
+
`binding "${desired.value}" imported from '${existingForName.module}' vs '${desiredImport.module}'`
|
|
14476
|
+
);
|
|
14477
|
+
continue;
|
|
14478
|
+
}
|
|
14479
|
+
} else {
|
|
14480
|
+
const line = formatImport([desired.value], desiredImport.module, effectiveStyle);
|
|
14481
|
+
next = insertImportAfterPackageImports(next, line, effectiveStyle);
|
|
14482
|
+
added.push(`import ${desired.value}`);
|
|
14483
|
+
workingImports = parseNamedImports(next);
|
|
14484
|
+
}
|
|
14485
|
+
}
|
|
14486
|
+
workingBlocks = parseDefineBlocks(next).filter((block) => block.kind === "database");
|
|
14487
|
+
workingBlock = workingBlocks[0];
|
|
14488
|
+
const nextEntries = [...workingBlock.entries, { key: desired.key, value: desired.value, raw: "" }];
|
|
14489
|
+
const body = rewriteObjectBody(nextEntries, effectiveStyle);
|
|
14490
|
+
next = replaceRange(next, workingBlock.bodyStart, workingBlock.bodyEnd, body);
|
|
14491
|
+
entryMap.set(desired.key, { key: desired.key, value: desired.value, raw: "" });
|
|
14492
|
+
added.push(`database entry: ${desired.key}`);
|
|
14493
|
+
}
|
|
14494
|
+
if (conflicts.length > 0 && added.length === 0) {
|
|
14495
|
+
return {
|
|
14496
|
+
action: "skip",
|
|
14497
|
+
skipReason: "merge-conflict",
|
|
14498
|
+
added: [],
|
|
14499
|
+
preservedCustom: preservedCustomUnits(existing, generated, "database"),
|
|
14500
|
+
conflicts,
|
|
14501
|
+
lintErrors: [],
|
|
14502
|
+
detail: conflicts.join("; ")
|
|
14503
|
+
};
|
|
14504
|
+
}
|
|
14505
|
+
const lintErrors = lintArtifactSource(next, "database");
|
|
14506
|
+
if (lintErrors.length > 0) {
|
|
14507
|
+
return {
|
|
14508
|
+
action: "skip",
|
|
14509
|
+
skipReason: "merge-lint-failed",
|
|
14510
|
+
added,
|
|
14511
|
+
preservedCustom: preservedCustomUnits(existing, generated, "database"),
|
|
14512
|
+
conflicts,
|
|
14513
|
+
lintErrors,
|
|
14514
|
+
detail: lintErrors.join("; ")
|
|
14515
|
+
};
|
|
14516
|
+
}
|
|
14517
|
+
const preservedCustom = preservedCustomUnits(next, generated, "database");
|
|
14518
|
+
if (next === existing || next.replace(/\r\n/g, "\n") === existing.replace(/\r\n/g, "\n")) {
|
|
14519
|
+
return {
|
|
14520
|
+
action: "unchanged",
|
|
14521
|
+
content: existing,
|
|
14522
|
+
skipReason: "already-current",
|
|
14523
|
+
added: [],
|
|
14524
|
+
preservedCustom,
|
|
14525
|
+
conflicts,
|
|
14526
|
+
lintErrors: [],
|
|
14527
|
+
detail: conflicts.length > 0 ? conflicts.join("; ") : void 0
|
|
14528
|
+
};
|
|
14529
|
+
}
|
|
14530
|
+
return {
|
|
14531
|
+
action: "write",
|
|
14532
|
+
content: next.endsWith("\n") ? next : `${next}${effectiveStyle.newline}`,
|
|
14533
|
+
writeReason: "merged",
|
|
14534
|
+
added,
|
|
14535
|
+
preservedCustom,
|
|
14536
|
+
conflicts,
|
|
14537
|
+
lintErrors: []
|
|
14538
|
+
};
|
|
14539
|
+
}
|
|
14540
|
+
function mergeMetaFields(existingMeta, generatedMeta) {
|
|
14541
|
+
const added = [];
|
|
14542
|
+
if (!generatedMeta) {
|
|
14543
|
+
return { entries: existingMeta?.entries ?? [], changed: false, added };
|
|
14544
|
+
}
|
|
14545
|
+
if (!existingMeta) {
|
|
14546
|
+
return {
|
|
14547
|
+
entries: generatedMeta.entries,
|
|
14548
|
+
changed: true,
|
|
14549
|
+
added: generatedMeta.entries.map((entry) => `meta entry: ${entry.key}`)
|
|
14550
|
+
};
|
|
14551
|
+
}
|
|
14552
|
+
const map = new Map(existingMeta.entries.map((entry) => [entry.key, entry]));
|
|
14553
|
+
let changed = false;
|
|
14554
|
+
for (const desired of generatedMeta.entries) {
|
|
14555
|
+
const current = map.get(desired.key);
|
|
14556
|
+
if (!current) {
|
|
14557
|
+
map.set(desired.key, desired);
|
|
14558
|
+
added.push(`meta entry: ${desired.key}`);
|
|
14559
|
+
changed = true;
|
|
14560
|
+
continue;
|
|
14561
|
+
}
|
|
14562
|
+
if (KNOWN_META_KEYS.has(desired.key) && current.value !== desired.value) {
|
|
14563
|
+
map.set(desired.key, desired);
|
|
14564
|
+
added.push(`meta refresh: ${desired.key}`);
|
|
14565
|
+
changed = true;
|
|
14566
|
+
}
|
|
14567
|
+
}
|
|
14568
|
+
const ordered = [];
|
|
14569
|
+
const seen = /* @__PURE__ */ new Set();
|
|
14570
|
+
for (const entry of existingMeta.entries) {
|
|
14571
|
+
const next = map.get(entry.key);
|
|
14572
|
+
if (next) {
|
|
14573
|
+
ordered.push(next);
|
|
14574
|
+
seen.add(entry.key);
|
|
14575
|
+
}
|
|
14576
|
+
}
|
|
14577
|
+
for (const entry of generatedMeta.entries) {
|
|
14578
|
+
if (!seen.has(entry.key)) {
|
|
14579
|
+
const next = map.get(entry.key);
|
|
14580
|
+
if (next) {
|
|
14581
|
+
ordered.push(next);
|
|
14582
|
+
seen.add(entry.key);
|
|
14583
|
+
}
|
|
14584
|
+
}
|
|
14585
|
+
}
|
|
14586
|
+
for (const [key, entry] of map) {
|
|
14587
|
+
if (!seen.has(key)) {
|
|
14588
|
+
ordered.push(entry);
|
|
14589
|
+
}
|
|
14590
|
+
}
|
|
14591
|
+
return { entries: ordered, changed, added };
|
|
14592
|
+
}
|
|
14593
|
+
function mergeRegistryArtifact(existing, generated) {
|
|
14594
|
+
const style = detectStyle(existing);
|
|
14595
|
+
const effectiveStyle = style;
|
|
14596
|
+
const generatedImports = parseNamedImports(generated);
|
|
14597
|
+
const existingBlocks = parseDefineBlocks(existing).filter((block) => block.kind === "registry");
|
|
14598
|
+
const generatedBlocks = parseDefineBlocks(generated).filter((block) => block.kind === "registry");
|
|
14599
|
+
if (existingBlocks.length === 0 || generatedBlocks.length === 0) {
|
|
14600
|
+
return {
|
|
14601
|
+
action: "skip",
|
|
14602
|
+
skipReason: "merge-unparseable",
|
|
14603
|
+
added: [],
|
|
14604
|
+
preservedCustom: [],
|
|
14605
|
+
conflicts: [],
|
|
14606
|
+
lintErrors: [],
|
|
14607
|
+
detail: "could not locate defineRegistry({\u2026}) export for merge"
|
|
14608
|
+
};
|
|
14609
|
+
}
|
|
14610
|
+
const existingBlock = existingBlocks[0];
|
|
14611
|
+
const generatedBlock = generatedBlocks[0];
|
|
14612
|
+
const conflicts = [];
|
|
14613
|
+
const added = [];
|
|
14614
|
+
let next = existing;
|
|
14615
|
+
if (!hasImportBinding(parseNamedImports(next), "defineRegistry")) {
|
|
14616
|
+
const pkgImport = generatedImports.find((item) => item.names.includes("defineRegistry"));
|
|
14617
|
+
if (pkgImport) {
|
|
14618
|
+
next = insertImportAfterPackageImports(
|
|
14619
|
+
next,
|
|
14620
|
+
formatImport(["defineRegistry"], pkgImport.module, effectiveStyle),
|
|
14621
|
+
effectiveStyle
|
|
14622
|
+
);
|
|
14623
|
+
added.push("import defineRegistry");
|
|
14624
|
+
}
|
|
14625
|
+
}
|
|
14626
|
+
const preferredDbValue = existingBlock.entries[0]?.value ?? generatedBlock.entries[0]?.value;
|
|
14627
|
+
const generatedDbImport = generatedImports.find((item) => item.names.includes(generatedBlock.entries[0]?.value ?? "")) ?? generatedImports.find((item) => item.module.startsWith("."));
|
|
14628
|
+
if (preferredDbValue && generatedDbImport) {
|
|
14629
|
+
const existingForName = findImportForName(parseNamedImports(next), preferredDbValue);
|
|
14630
|
+
if (!existingForName) {
|
|
14631
|
+
const modulePath = generatedDbImport.module;
|
|
14632
|
+
const importName = findImportForName(generatedImports, preferredDbValue)?.names[0] ?? generatedBlock.entries[0]?.value ?? preferredDbValue;
|
|
14633
|
+
if (!hasImportBinding(parseNamedImports(next), importName)) {
|
|
14634
|
+
next = insertImportAfterPackageImports(
|
|
14635
|
+
next,
|
|
14636
|
+
formatImport([importName], modulePath, effectiveStyle),
|
|
14637
|
+
effectiveStyle
|
|
14638
|
+
);
|
|
14639
|
+
added.push(`import ${importName}`);
|
|
14640
|
+
}
|
|
14641
|
+
} else if (normalizeModulePath(existingForName.module) !== normalizeModulePath(generatedDbImport.module)) {
|
|
14642
|
+
conflicts.push(
|
|
14643
|
+
`binding "${preferredDbValue}" imported from '${existingForName.module}' vs '${generatedDbImport.module}'`
|
|
14644
|
+
);
|
|
14645
|
+
}
|
|
14646
|
+
}
|
|
14647
|
+
let workingBlocks = parseDefineBlocks(next).filter((block) => block.kind === "registry");
|
|
14648
|
+
let workingBlock = workingBlocks[0];
|
|
14649
|
+
const entryMap = new Map(workingBlock.entries.map((entry) => [entry.key, entry]));
|
|
14650
|
+
for (const desired of generatedBlock.entries) {
|
|
14651
|
+
const existingEntry = entryMap.get(desired.key);
|
|
14652
|
+
if (existingEntry) {
|
|
14653
|
+
continue;
|
|
14654
|
+
}
|
|
14655
|
+
const dbImport = parseNamedImports(next).find(
|
|
14656
|
+
(item) => item.module.startsWith(".") && item.names.some((name) => name !== "defineRegistry")
|
|
14657
|
+
);
|
|
14658
|
+
const value = dbImport?.names[0] ?? desired.value;
|
|
14659
|
+
const nextEntries = [...workingBlock.entries, { key: desired.key, value, raw: "" }];
|
|
14660
|
+
const body = rewriteObjectBody(nextEntries, effectiveStyle);
|
|
14661
|
+
next = replaceRange(next, workingBlock.bodyStart, workingBlock.bodyEnd, body);
|
|
14662
|
+
entryMap.set(desired.key, { key: desired.key, value, raw: "" });
|
|
14663
|
+
added.push(`registry entry: ${desired.key}`);
|
|
14664
|
+
workingBlocks = parseDefineBlocks(next).filter((block) => block.kind === "registry");
|
|
14665
|
+
workingBlock = workingBlocks[0];
|
|
14666
|
+
}
|
|
14667
|
+
const existingMeta = parseMetaBlock(next);
|
|
14668
|
+
const generatedMeta = parseMetaBlock(generated);
|
|
14669
|
+
const structuralAdded = added.length > 0;
|
|
14670
|
+
if (generatedMeta) {
|
|
14671
|
+
if (!existingMeta) {
|
|
14672
|
+
const blocks = parseDefineBlocks(next).filter((block) => block.kind === "registry");
|
|
14673
|
+
const insertAt = blocks[0]?.fullStart ?? next.length;
|
|
14674
|
+
const metaBody = rewriteObjectBody(generatedMeta.entries, effectiveStyle);
|
|
14675
|
+
const metaBlock = `export const __athena_schema_meta = {${metaBody}} as const${effectiveStyle.semicolons ? ";" : ""}${effectiveStyle.newline}${effectiveStyle.newline}`;
|
|
14676
|
+
next = replaceRange(next, insertAt, insertAt, metaBlock);
|
|
14677
|
+
added.push("__athena_schema_meta");
|
|
14678
|
+
} else {
|
|
14679
|
+
const desiredEntries = structuralAdded ? generatedMeta.entries : generatedMeta.entries.filter((entry) => {
|
|
14680
|
+
return !existingMeta.entries.some((current) => current.key === entry.key);
|
|
14681
|
+
});
|
|
14682
|
+
if (structuralAdded) {
|
|
14683
|
+
const merged = mergeMetaFields(existingMeta, generatedMeta);
|
|
14684
|
+
if (merged.changed) {
|
|
14685
|
+
const metaNow = parseMetaBlock(next);
|
|
14686
|
+
if (metaNow) {
|
|
14687
|
+
const body = rewriteObjectBody(merged.entries, effectiveStyle);
|
|
14688
|
+
next = replaceRange(next, metaNow.bodyStart, metaNow.bodyEnd, body);
|
|
14689
|
+
added.push(...merged.added);
|
|
14690
|
+
}
|
|
14691
|
+
}
|
|
14692
|
+
} else if (desiredEntries.length > 0) {
|
|
14693
|
+
const map = new Map(existingMeta.entries.map((entry) => [entry.key, entry]));
|
|
14694
|
+
for (const entry of desiredEntries) {
|
|
14695
|
+
map.set(entry.key, entry);
|
|
14696
|
+
added.push(`meta entry: ${entry.key}`);
|
|
14697
|
+
}
|
|
14698
|
+
const ordered = [
|
|
14699
|
+
...existingMeta.entries.map((entry) => map.get(entry.key)),
|
|
14700
|
+
...desiredEntries.filter((entry) => !existingMeta.entries.some((e) => e.key === entry.key))
|
|
14701
|
+
];
|
|
14702
|
+
const metaNow = parseMetaBlock(next);
|
|
14703
|
+
if (metaNow) {
|
|
14704
|
+
const body = rewriteObjectBody(ordered, effectiveStyle);
|
|
14705
|
+
next = replaceRange(next, metaNow.bodyStart, metaNow.bodyEnd, body);
|
|
14706
|
+
}
|
|
14707
|
+
}
|
|
14708
|
+
}
|
|
14709
|
+
}
|
|
14710
|
+
if (conflicts.length > 0 && added.length === 0) {
|
|
14711
|
+
return {
|
|
14712
|
+
action: "skip",
|
|
14713
|
+
skipReason: "merge-conflict",
|
|
14714
|
+
added: [],
|
|
14715
|
+
preservedCustom: preservedCustomUnits(existing, generated, "registry"),
|
|
14716
|
+
conflicts,
|
|
14717
|
+
lintErrors: [],
|
|
14718
|
+
detail: conflicts.join("; ")
|
|
14719
|
+
};
|
|
14720
|
+
}
|
|
14721
|
+
const lintErrors = lintArtifactSource(next, "registry");
|
|
14722
|
+
if (lintErrors.length > 0) {
|
|
14723
|
+
return {
|
|
14724
|
+
action: "skip",
|
|
14725
|
+
skipReason: "merge-lint-failed",
|
|
14726
|
+
added,
|
|
14727
|
+
preservedCustom: preservedCustomUnits(existing, generated, "registry"),
|
|
14728
|
+
conflicts,
|
|
14729
|
+
lintErrors,
|
|
14730
|
+
detail: lintErrors.join("; ")
|
|
14731
|
+
};
|
|
14732
|
+
}
|
|
14733
|
+
const preservedCustom = preservedCustomUnits(next, generated, "registry");
|
|
14734
|
+
if (next.replace(/\r\n/g, "\n") === existing.replace(/\r\n/g, "\n")) {
|
|
14735
|
+
return {
|
|
14736
|
+
action: "unchanged",
|
|
14737
|
+
content: existing,
|
|
14738
|
+
skipReason: "already-current",
|
|
14739
|
+
added: [],
|
|
14740
|
+
preservedCustom,
|
|
14741
|
+
conflicts,
|
|
14742
|
+
lintErrors: []
|
|
14743
|
+
};
|
|
14744
|
+
}
|
|
14745
|
+
return {
|
|
14746
|
+
action: "write",
|
|
14747
|
+
content: next.endsWith("\n") ? next : `${next}${effectiveStyle.newline}`,
|
|
14748
|
+
writeReason: "merged",
|
|
14749
|
+
added,
|
|
14750
|
+
preservedCustom,
|
|
14751
|
+
conflicts,
|
|
14752
|
+
lintErrors: []
|
|
14753
|
+
};
|
|
14754
|
+
}
|
|
14755
|
+
function mergeProtectedArtifact(kind, existing, generated, policy) {
|
|
14756
|
+
if (policy === "overwrite") {
|
|
14757
|
+
if (existing.replace(/\r\n/g, "\n") === generated.replace(/\r\n/g, "\n")) {
|
|
14758
|
+
return {
|
|
14759
|
+
action: "unchanged",
|
|
14760
|
+
content: existing,
|
|
14761
|
+
skipReason: "already-current",
|
|
14762
|
+
added: [],
|
|
14763
|
+
preservedCustom: [],
|
|
14764
|
+
conflicts: [],
|
|
14765
|
+
lintErrors: []
|
|
14766
|
+
};
|
|
14767
|
+
}
|
|
14768
|
+
return {
|
|
14769
|
+
action: "write",
|
|
14770
|
+
content: generated,
|
|
14771
|
+
writeReason: "overwritten",
|
|
14772
|
+
added: ["full overwrite"],
|
|
14773
|
+
preservedCustom: [],
|
|
14774
|
+
conflicts: [],
|
|
14775
|
+
lintErrors: []
|
|
14776
|
+
};
|
|
14777
|
+
}
|
|
14778
|
+
if (policy === "skip") {
|
|
14779
|
+
return {
|
|
14780
|
+
action: "skip",
|
|
14781
|
+
skipReason: "protected-existing-file",
|
|
14782
|
+
added: [],
|
|
14783
|
+
preservedCustom: preservedCustomUnits(existing, generated, kind),
|
|
14784
|
+
conflicts: [],
|
|
14785
|
+
lintErrors: [],
|
|
14786
|
+
detail: "artifactWrite policy is skip"
|
|
14787
|
+
};
|
|
14788
|
+
}
|
|
14789
|
+
return kind === "database" ? mergeDatabaseArtifact(existing, generated) : mergeRegistryArtifact(existing, generated);
|
|
14790
|
+
}
|
|
14791
|
+
function resolveArtifactWritePlan(file, existingContent, policy) {
|
|
14792
|
+
if (existingContent === null) {
|
|
14793
|
+
return {
|
|
14794
|
+
action: "write",
|
|
14795
|
+
content: file.content,
|
|
14796
|
+
writeReason: "created",
|
|
14797
|
+
added: ["created"],
|
|
14798
|
+
preservedCustom: [],
|
|
14799
|
+
conflicts: [],
|
|
14800
|
+
lintErrors: []
|
|
14801
|
+
};
|
|
14802
|
+
}
|
|
14803
|
+
if (file.kind === "model" || file.kind === "schema" || policy === "always") {
|
|
14804
|
+
if (existingContent.replace(/\r\n/g, "\n") === file.content.replace(/\r\n/g, "\n")) {
|
|
14805
|
+
return {
|
|
14806
|
+
action: "unchanged",
|
|
14807
|
+
content: existingContent,
|
|
14808
|
+
skipReason: "already-current",
|
|
14809
|
+
added: [],
|
|
14810
|
+
preservedCustom: [],
|
|
14811
|
+
conflicts: [],
|
|
14812
|
+
lintErrors: []
|
|
14813
|
+
};
|
|
14814
|
+
}
|
|
14815
|
+
return {
|
|
14816
|
+
action: "write",
|
|
14817
|
+
content: file.content,
|
|
14818
|
+
writeReason: existingContent ? "overwritten" : "created",
|
|
14819
|
+
added: ["overwritten"],
|
|
14820
|
+
preservedCustom: [],
|
|
14821
|
+
conflicts: [],
|
|
14822
|
+
lintErrors: []
|
|
14823
|
+
};
|
|
14824
|
+
}
|
|
14825
|
+
return mergeProtectedArtifact(
|
|
14826
|
+
file.kind,
|
|
14827
|
+
existingContent,
|
|
14828
|
+
file.content,
|
|
14829
|
+
policy
|
|
14830
|
+
);
|
|
14831
|
+
}
|
|
14832
|
+
|
|
14833
|
+
// src/generator/pipeline.ts
|
|
13276
14834
|
async function fileExists(path) {
|
|
13277
14835
|
try {
|
|
13278
14836
|
await promises.stat(path);
|
|
@@ -13281,47 +14839,156 @@ async function fileExists(path) {
|
|
|
13281
14839
|
return false;
|
|
13282
14840
|
}
|
|
13283
14841
|
}
|
|
13284
|
-
async function
|
|
14842
|
+
async function readExisting(path) {
|
|
14843
|
+
try {
|
|
14844
|
+
return await promises.readFile(path, "utf8");
|
|
14845
|
+
} catch {
|
|
14846
|
+
return null;
|
|
14847
|
+
}
|
|
14848
|
+
}
|
|
14849
|
+
function policyForArtifact(file, config) {
|
|
14850
|
+
if (file.kind === "model" || file.kind === "schema") {
|
|
14851
|
+
return "always";
|
|
14852
|
+
}
|
|
14853
|
+
if (file.kind === "database") {
|
|
14854
|
+
return config.output.artifactWrite.database;
|
|
14855
|
+
}
|
|
14856
|
+
return config.output.artifactWrite.registry;
|
|
14857
|
+
}
|
|
14858
|
+
async function writeArtifacts(files, cwd, config, dryRun) {
|
|
13285
14859
|
const writtenFiles = [];
|
|
14860
|
+
const writtenDetails = [];
|
|
13286
14861
|
const skippedFiles = [];
|
|
13287
14862
|
for (const file of files) {
|
|
13288
14863
|
const absolutePath = path.resolve(cwd, file.path);
|
|
13289
|
-
|
|
14864
|
+
const exists = await fileExists(absolutePath);
|
|
14865
|
+
const existingContent = exists ? await readExisting(absolutePath) : null;
|
|
14866
|
+
const policy = policyForArtifact(file, config);
|
|
14867
|
+
const plan = resolveArtifactWritePlan(file, existingContent, policy);
|
|
14868
|
+
if (plan.action === "skip" || plan.action === "unchanged") {
|
|
14869
|
+
skippedFiles.push({
|
|
14870
|
+
kind: file.kind,
|
|
14871
|
+
path: file.path,
|
|
14872
|
+
reason: plan.skipReason ?? "already-current",
|
|
14873
|
+
detail: plan.detail,
|
|
14874
|
+
preservedCustom: plan.preservedCustom.length > 0 ? plan.preservedCustom : void 0,
|
|
14875
|
+
conflicts: plan.conflicts.length > 0 ? plan.conflicts : void 0,
|
|
14876
|
+
lintErrors: plan.lintErrors.length > 0 ? plan.lintErrors : void 0
|
|
14877
|
+
});
|
|
14878
|
+
continue;
|
|
14879
|
+
}
|
|
14880
|
+
if (!plan.content || !plan.writeReason) {
|
|
13290
14881
|
skippedFiles.push({
|
|
13291
14882
|
kind: file.kind,
|
|
13292
14883
|
path: file.path,
|
|
13293
|
-
reason: "
|
|
14884
|
+
reason: "merge-lint-failed",
|
|
14885
|
+
detail: "merge produced no content",
|
|
14886
|
+
lintErrors: plan.lintErrors
|
|
13294
14887
|
});
|
|
13295
14888
|
continue;
|
|
13296
14889
|
}
|
|
13297
|
-
|
|
13298
|
-
|
|
14890
|
+
if (!dryRun) {
|
|
14891
|
+
await promises.mkdir(path.dirname(absolutePath), { recursive: true });
|
|
14892
|
+
await promises.writeFile(absolutePath, plan.content, "utf8");
|
|
14893
|
+
}
|
|
13299
14894
|
writtenFiles.push(file.path);
|
|
14895
|
+
writtenDetails.push({
|
|
14896
|
+
kind: file.kind,
|
|
14897
|
+
path: file.path,
|
|
14898
|
+
reason: plan.writeReason,
|
|
14899
|
+
added: plan.added.length > 0 ? plan.added : void 0,
|
|
14900
|
+
preservedCustom: plan.preservedCustom.length > 0 ? plan.preservedCustom : void 0
|
|
14901
|
+
});
|
|
13300
14902
|
}
|
|
13301
14903
|
return {
|
|
13302
14904
|
writtenFiles,
|
|
14905
|
+
writtenDetails,
|
|
13303
14906
|
skippedFiles
|
|
13304
14907
|
};
|
|
13305
14908
|
}
|
|
14909
|
+
function withPostgresSchemas(config, schemas) {
|
|
14910
|
+
if (config.provider.kind !== "postgres") {
|
|
14911
|
+
return config;
|
|
14912
|
+
}
|
|
14913
|
+
return {
|
|
14914
|
+
...config,
|
|
14915
|
+
provider: {
|
|
14916
|
+
...config.provider,
|
|
14917
|
+
schemas
|
|
14918
|
+
}
|
|
14919
|
+
};
|
|
14920
|
+
}
|
|
13306
14921
|
async function runSchemaGenerator(options = {}) {
|
|
13307
14922
|
const cwd = options.cwd ?? process.cwd();
|
|
14923
|
+
const dryRun = options.dryRun === true;
|
|
14924
|
+
const writeConfig = options.writeConfig !== false;
|
|
14925
|
+
const discoverSchemas = options.discoverSchemas !== false;
|
|
13308
14926
|
const configOptions = {
|
|
13309
14927
|
cwd,
|
|
13310
14928
|
configPath: options.configPath
|
|
13311
14929
|
};
|
|
13312
|
-
const
|
|
14930
|
+
const loaded = await loadGeneratorConfig(configOptions);
|
|
14931
|
+
let { configPath, config } = loaded;
|
|
14932
|
+
let configEnsure;
|
|
14933
|
+
let effectiveSchemas = resolveProviderSchemas(config.provider);
|
|
14934
|
+
const canDiscoverLive = discoverSchemas && config.provider.kind === "postgres" && !options.provider;
|
|
14935
|
+
if (canDiscoverLive) {
|
|
14936
|
+
try {
|
|
14937
|
+
const discovered = await discoverPostgresSchemas(config.provider);
|
|
14938
|
+
if (discovered.length > 0) {
|
|
14939
|
+
effectiveSchemas = mergeSchemaSelections(effectiveSchemas, discovered);
|
|
14940
|
+
}
|
|
14941
|
+
} catch {
|
|
14942
|
+
}
|
|
14943
|
+
}
|
|
14944
|
+
config = withPostgresSchemas(config, effectiveSchemas);
|
|
14945
|
+
const shouldEnsureConfig = writeConfig && config.provider.kind === "postgres" && !options.provider;
|
|
14946
|
+
if (shouldEnsureConfig) {
|
|
14947
|
+
const ensureResult = await ensureGeneratorConfigFile({
|
|
14948
|
+
cwd,
|
|
14949
|
+
configPath: options.configPath,
|
|
14950
|
+
dryRun,
|
|
14951
|
+
// Schemas already resolved above — avoid a second discovery round-trip.
|
|
14952
|
+
discoverSchemas: false,
|
|
14953
|
+
provider: config.provider,
|
|
14954
|
+
loaded: { configPath, config },
|
|
14955
|
+
schemas: effectiveSchemas,
|
|
14956
|
+
mode: config.provider.mode
|
|
14957
|
+
});
|
|
14958
|
+
configEnsure = {
|
|
14959
|
+
action: ensureResult.action,
|
|
14960
|
+
path: ensureResult.path,
|
|
14961
|
+
schemas: ensureResult.schemas,
|
|
14962
|
+
changes: ensureResult.changes,
|
|
14963
|
+
reason: ensureResult.reason
|
|
14964
|
+
};
|
|
14965
|
+
if (ensureResult.action === "created" || ensureResult.action === "updated" || ensureResult.action === "unchanged" && configPath === "[environment defaults]") {
|
|
14966
|
+
configPath = ensureResult.absolutePath;
|
|
14967
|
+
if (ensureResult.schemas.length > 0) {
|
|
14968
|
+
effectiveSchemas = ensureResult.schemas;
|
|
14969
|
+
config = withPostgresSchemas(config, effectiveSchemas);
|
|
14970
|
+
}
|
|
14971
|
+
}
|
|
14972
|
+
}
|
|
13313
14973
|
const provider = options.provider ?? resolveGeneratorProvider(config.provider, config.experimental);
|
|
13314
14974
|
const snapshot = await provider.inspect({
|
|
13315
|
-
schemas:
|
|
14975
|
+
schemas: effectiveSchemas
|
|
13316
14976
|
});
|
|
13317
14977
|
const generated = generateArtifactsFromSnapshot(snapshot, config);
|
|
13318
|
-
const writeResult =
|
|
14978
|
+
const writeResult = await writeArtifacts(
|
|
14979
|
+
generated.files,
|
|
14980
|
+
cwd,
|
|
14981
|
+
config,
|
|
14982
|
+
dryRun
|
|
14983
|
+
);
|
|
13319
14984
|
return {
|
|
13320
14985
|
...generated,
|
|
13321
14986
|
configPath,
|
|
13322
14987
|
config,
|
|
13323
14988
|
writtenFiles: writeResult.writtenFiles,
|
|
13324
|
-
|
|
14989
|
+
writtenDetails: writeResult.writtenDetails,
|
|
14990
|
+
skippedFiles: writeResult.skippedFiles,
|
|
14991
|
+
configEnsure
|
|
13325
14992
|
};
|
|
13326
14993
|
}
|
|
13327
14994
|
|
|
@@ -13390,15 +15057,15 @@ function readCookieFromHeaders(headers, name) {
|
|
|
13390
15057
|
}
|
|
13391
15058
|
return parseCookies(cookieHeader).get(name);
|
|
13392
15059
|
}
|
|
13393
|
-
function
|
|
15060
|
+
function isRecord14(value) {
|
|
13394
15061
|
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
13395
15062
|
}
|
|
13396
15063
|
function resolveSessionCandidate(value) {
|
|
13397
|
-
if (!
|
|
15064
|
+
if (!isRecord14(value)) {
|
|
13398
15065
|
return null;
|
|
13399
15066
|
}
|
|
13400
|
-
const session =
|
|
13401
|
-
const user =
|
|
15067
|
+
const session = isRecord14(value.session) ? value.session : void 0;
|
|
15068
|
+
const user = isRecord14(value.user) ? value.user : void 0;
|
|
13402
15069
|
if (session && typeof session.token === "string" && session.token.length > 0 && user) {
|
|
13403
15070
|
return {
|
|
13404
15071
|
session,
|
|
@@ -13408,7 +15075,7 @@ function resolveSessionCandidate(value) {
|
|
|
13408
15075
|
return null;
|
|
13409
15076
|
}
|
|
13410
15077
|
function inferSessionPair(returned) {
|
|
13411
|
-
return resolveSessionCandidate(returned) ?? (
|
|
15078
|
+
return resolveSessionCandidate(returned) ?? (isRecord14(returned) ? resolveSessionCandidate(returned.data) : null) ?? (isRecord14(returned) ? resolveSessionCandidate(returned.session) : null);
|
|
13412
15079
|
}
|
|
13413
15080
|
function resolveResponseHeaders(ctx) {
|
|
13414
15081
|
if (ctx.context.responseHeaders instanceof Headers) {
|
|
@@ -13839,11 +15506,27 @@ exports.Backend = Backend;
|
|
|
13839
15506
|
exports.DEFAULT_MULTIPART_PART_SIZE_BYTES = DEFAULT_MULTIPART_PART_SIZE_BYTES;
|
|
13840
15507
|
exports.DEFAULT_MULTIPART_THRESHOLD_BYTES = DEFAULT_MULTIPART_THRESHOLD_BYTES;
|
|
13841
15508
|
exports.DEFAULT_POSTGRES_SCHEMAS = DEFAULT_POSTGRES_SCHEMAS;
|
|
15509
|
+
exports.applyAthenaReadQueryFilters = applyAthenaReadQueryFilters;
|
|
15510
|
+
exports.applyAthenaReadQuerySelectLimit = applyAthenaReadQuerySelectLimit;
|
|
15511
|
+
exports.applyAthenaReadQuerySelectOrder = applyAthenaReadQuerySelectOrder;
|
|
15512
|
+
exports.applyAthenaTableFilters = applyAthenaTableFilters;
|
|
15513
|
+
exports.applyAthenaTableSelectLimit = applyAthenaTableSelectLimit;
|
|
15514
|
+
exports.applyAthenaTableSelectOrder = applyAthenaTableSelectOrder;
|
|
13842
15515
|
exports.assertInt = assertInt;
|
|
13843
15516
|
exports.athenaAuth = athenaAuth;
|
|
13844
15517
|
exports.billingSdkManifest = billingSdkManifest;
|
|
13845
15518
|
exports.boolean = boolean;
|
|
15519
|
+
exports.buildAthenaReadQueryFindManyOrderBy = buildAthenaReadQueryFindManyOrderBy;
|
|
15520
|
+
exports.buildAthenaReadQueryFindManySelect = buildAthenaReadQueryFindManySelect;
|
|
15521
|
+
exports.buildAthenaReadQueryFindManyWhere = buildAthenaReadQueryFindManyWhere;
|
|
15522
|
+
exports.buildAthenaReadQuerySelectString = buildAthenaReadQuerySelectString;
|
|
15523
|
+
exports.buildAthenaTableFindManyOrderBy = buildAthenaTableFindManyOrderBy;
|
|
15524
|
+
exports.buildAthenaTableFindManySelect = buildAthenaTableFindManySelect;
|
|
15525
|
+
exports.buildAthenaTableFindManyWhere = buildAthenaTableFindManyWhere;
|
|
15526
|
+
exports.buildAthenaTableSelectString = buildAthenaTableSelectString;
|
|
13846
15527
|
exports.chatSdkManifest = chatSdkManifest;
|
|
15528
|
+
exports.clampAthenaReadQueryTotalItems = clampAthenaReadQueryTotalItems;
|
|
15529
|
+
exports.clampAthenaTableTotalItems = clampAthenaTableTotalItems;
|
|
13847
15530
|
exports.coerceInt = coerceInt;
|
|
13848
15531
|
exports.createAthenaStorageError = createAthenaStorageError;
|
|
13849
15532
|
exports.createAuthReactEmailInput = createAuthReactEmailInput;
|
|
@@ -13859,10 +15542,17 @@ exports.defineGeneratorConfig = defineGeneratorConfig;
|
|
|
13859
15542
|
exports.defineModel = defineModel;
|
|
13860
15543
|
exports.defineRegistry = defineRegistry;
|
|
13861
15544
|
exports.defineSchema = defineSchema;
|
|
15545
|
+
exports.detectGeneratorProviderMode = detectGeneratorProviderMode;
|
|
15546
|
+
exports.discoverPostgresSchemas = discoverPostgresSchemas;
|
|
13862
15547
|
exports.ensureActiveOrganization = ensureActiveOrganization;
|
|
15548
|
+
exports.ensureGeneratorConfigFile = ensureGeneratorConfigFile;
|
|
13863
15549
|
exports.enumeration = enumeration;
|
|
15550
|
+
exports.executeAthenaReadQuery = executeAthenaReadQuery;
|
|
15551
|
+
exports.executeAthenaTableQuery = executeAthenaTableQuery;
|
|
13864
15552
|
exports.filterIntrospectionSnapshot = filterIntrospectionSnapshot;
|
|
13865
15553
|
exports.findGeneratorConfigPath = findGeneratorConfigPath;
|
|
15554
|
+
exports.flattenAthenaReadQueryRows = flattenAthenaReadQueryRows;
|
|
15555
|
+
exports.flattenAthenaRows = flattenAthenaRows;
|
|
13866
15556
|
exports.generateArtifactsFromSnapshot = generateArtifactsFromSnapshot;
|
|
13867
15557
|
exports.generatorEnv = generatorEnv;
|
|
13868
15558
|
exports.getAthenaDebugAst = getAthenaDebugAst;
|
|
@@ -13871,14 +15561,20 @@ exports.isAthenaGatewayError = isAthenaGatewayError;
|
|
|
13871
15561
|
exports.isOk = isOk;
|
|
13872
15562
|
exports.json = json;
|
|
13873
15563
|
exports.loadGeneratorConfig = loadGeneratorConfig;
|
|
15564
|
+
exports.mergeSchemaSelections = mergeSchemaSelections;
|
|
13874
15565
|
exports.normalizeAthenaError = normalizeAthenaError;
|
|
13875
15566
|
exports.normalizeAthenaGatewayBaseUrl = normalizeAthenaGatewayBaseUrl;
|
|
15567
|
+
exports.normalizeAthenaReadQueryOrderBy = normalizeAthenaReadQueryOrderBy;
|
|
15568
|
+
exports.normalizeAthenaTableOrderBy = normalizeAthenaTableOrderBy;
|
|
15569
|
+
exports.normalizeDiscoveredSchemas = normalizeDiscoveredSchemas;
|
|
13876
15570
|
exports.normalizeGeneratorConfig = normalizeGeneratorConfig;
|
|
13877
15571
|
exports.normalizeSchemaSelection = normalizeSchemaSelection;
|
|
13878
15572
|
exports.normalizeTableSelection = normalizeTableSelection;
|
|
13879
15573
|
exports.number = number;
|
|
13880
15574
|
exports.parseBooleanFlag = parseBooleanFlag2;
|
|
15575
|
+
exports.patchSchemasInConfigSource = patchSchemasInConfigSource;
|
|
13881
15576
|
exports.renderAthenaReactEmail = renderAthenaReactEmail;
|
|
15577
|
+
exports.renderGeneratorConfigFile = renderGeneratorConfigFile;
|
|
13882
15578
|
exports.requireAffected = requireAffected;
|
|
13883
15579
|
exports.requireSuccess = requireSuccess;
|
|
13884
15580
|
exports.resolveGeneratorProvider = resolveGeneratorProvider;
|
|
@@ -13886,6 +15582,7 @@ exports.resolvePostgresColumnType = resolvePostgresColumnType;
|
|
|
13886
15582
|
exports.resolveProviderSchemas = resolveProviderSchemas;
|
|
13887
15583
|
exports.resolveStoragePath = resolveStoragePath;
|
|
13888
15584
|
exports.runSchemaGenerator = runSchemaGenerator;
|
|
15585
|
+
exports.schemasEqual = schemasEqual;
|
|
13889
15586
|
exports.storageSdkManifest = storageSdkManifest;
|
|
13890
15587
|
exports.string = string;
|
|
13891
15588
|
exports.table = table;
|