@xylex-group/athena 3.0.0 → 3.0.3
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 +24 -10
- package/dist/{athena-auth-url-oLux_57a.d.cts → athena-request-headers-C7Jy-c_D.d.ts} +85 -1
- package/dist/{athena-auth-url-oLux_57a.d.ts → athena-request-headers-DujFFyMU.d.cts} +85 -1
- package/dist/billing.cjs +133 -21
- package/dist/billing.cjs.map +1 -1
- package/dist/billing.d.cts +41 -1
- package/dist/billing.d.ts +41 -1
- package/dist/billing.js +133 -21
- package/dist/billing.js.map +1 -1
- package/dist/browser.cjs +138 -45
- package/dist/browser.cjs.map +1 -1
- package/dist/browser.d.cts +9 -9
- package/dist/browser.d.ts +9 -9
- package/dist/browser.js +138 -45
- package/dist/browser.js.map +1 -1
- package/dist/cli/index.cjs +1038 -57
- package/dist/cli/index.cjs.map +1 -1
- package/dist/cli/index.d.cts +3 -3
- package/dist/cli/index.d.ts +3 -3
- package/dist/cli/index.js +1039 -58
- package/dist/cli/index.js.map +1 -1
- package/dist/index.cjs +977 -54
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +9 -9
- package/dist/index.d.ts +9 -9
- package/dist/index.js +978 -55
- package/dist/index.js.map +1 -1
- package/dist/{model-form-BKetpu6Q.d.ts → model-form-Dh0sisdL.d.ts} +1 -1
- package/dist/{model-form-BEfCGB5b.d.cts → model-form-oOAJUVd4.d.cts} +1 -1
- package/dist/{module-Bef_MAPO.d.ts → module-BruTcxe0.d.ts} +17 -5
- package/dist/{module-CrrSmpML.d.cts → module-CPG3ULxQ.d.cts} +17 -5
- package/dist/{module-8dSMcy0K.d.cts → module-C_ab-MM1.d.cts} +46 -12
- package/dist/{module-8dSMcy0K.d.ts → module-C_ab-MM1.d.ts} +46 -12
- package/dist/next/client.cjs +9817 -3
- package/dist/next/client.cjs.map +1 -1
- package/dist/next/client.d.cts +26 -1
- package/dist/next/client.d.ts +26 -1
- package/dist/next/client.js +9788 -4
- package/dist/next/client.js.map +1 -1
- package/dist/next/server.cjs +10398 -42
- package/dist/next/server.cjs.map +1 -1
- package/dist/next/server.d.cts +39 -4
- package/dist/next/server.d.ts +39 -4
- package/dist/next/server.js +10339 -43
- package/dist/next/server.js.map +1 -1
- package/dist/{pipeline-Dfsed4VD.d.cts → pipeline-CIzV9f7b.d.cts} +1 -1
- package/dist/{pipeline-BXFQbsUW.d.ts → pipeline-DNlc8Ayn.d.ts} +1 -1
- package/dist/proxy-request-headers-DGxdoyA0.d.cts +59 -0
- package/dist/proxy-request-headers-m4D2Tduy.d.ts +59 -0
- package/dist/react.cjs +7 -7
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +4 -4
- package/dist/react.d.ts +4 -4
- package/dist/react.js +7 -7
- package/dist/react.js.map +1 -1
- package/dist/social-providers.cjs +15 -11
- package/dist/social-providers.cjs.map +1 -1
- package/dist/social-providers.d.cts +17 -57
- package/dist/social-providers.d.ts +17 -57
- package/dist/social-providers.js +15 -11
- package/dist/social-providers.js.map +1 -1
- package/dist/{types-jClgDy1J.d.ts → types-B75PdABb.d.ts} +1 -1
- package/dist/{types-kO_Ut5wU.d.cts → types-CgCv5o6R.d.cts} +1 -1
- package/dist/{types-CK7cBQbC.d.ts → types-D6tZ9aoq.d.ts} +35 -2
- package/dist/{types-Z3-rsiM3.d.cts → types-DFr2cL1N.d.cts} +35 -2
- package/dist/utils.d.cts +4 -142
- package/dist/utils.d.ts +4 -142
- package/dist/{v3-client-G8JMOilK.d.cts → v3-client-CWfZHcKL.d.cts} +37 -21
- package/dist/{v3-client-CuCNy-JJ.d.ts → v3-client-DZp2NEhK.d.ts} +37 -21
- package/package.json +6 -3
package/dist/index.js
CHANGED
|
@@ -2,7 +2,7 @@ import { z } from 'zod';
|
|
|
2
2
|
import { existsSync, readFileSync } from 'fs';
|
|
3
3
|
import { resolve, dirname, posix } from 'path';
|
|
4
4
|
import { pathToFileURL } from 'url';
|
|
5
|
-
import { mkdir, writeFile, stat } from 'fs/promises';
|
|
5
|
+
import { mkdir, writeFile, stat, readFile } from 'fs/promises';
|
|
6
6
|
|
|
7
7
|
// src/gateway/errors.ts
|
|
8
8
|
var AthenaGatewayError = class _AthenaGatewayError extends Error {
|
|
@@ -1939,7 +1939,7 @@ function buildRpcDebugSql(payload) {
|
|
|
1939
1939
|
}
|
|
1940
1940
|
|
|
1941
1941
|
// src/gateway/url.ts
|
|
1942
|
-
var ATHENA_DEFAULT_BASE_URL = "https://athena-
|
|
1942
|
+
var ATHENA_DEFAULT_BASE_URL = "https://mirror2.athena-cluster.com";
|
|
1943
1943
|
function describeReceivedValue(value) {
|
|
1944
1944
|
if (value === void 0) return "undefined";
|
|
1945
1945
|
if (value === null) return "null";
|
|
@@ -1962,14 +1962,14 @@ function normalizeAthenaGatewayBaseUrl(input, options = {}) {
|
|
|
1962
1962
|
if (candidate === void 0 || candidate === null) {
|
|
1963
1963
|
throw invalidBaseUrlError(
|
|
1964
1964
|
`${label} must be a non-empty absolute http(s) URL. Received ${describeReceivedValue(input)}.`,
|
|
1965
|
-
'Set ATHENA_URL in the explicit env object (or pass createClient({ url, key })) to a full URL such as "https://
|
|
1965
|
+
'Set ATHENA_URL in the explicit env object (or pass createClient({ url, key })) to a full URL such as "https://mirror2.athena-cluster.com".'
|
|
1966
1966
|
);
|
|
1967
1967
|
}
|
|
1968
1968
|
const trimmed = candidate.trim();
|
|
1969
1969
|
if (!trimmed) {
|
|
1970
1970
|
throw invalidBaseUrlError(
|
|
1971
1971
|
`${label} must be a non-empty absolute http(s) URL. Received ${describeReceivedValue(candidate)}.`,
|
|
1972
|
-
'Set ATHENA_URL in the explicit env object (or pass createClient({ url, key })) to a full URL such as "https://
|
|
1972
|
+
'Set ATHENA_URL in the explicit env object (or pass createClient({ url, key })) to a full URL such as "https://mirror2.athena-cluster.com".'
|
|
1973
1973
|
);
|
|
1974
1974
|
}
|
|
1975
1975
|
let parsed;
|
|
@@ -1978,13 +1978,13 @@ function normalizeAthenaGatewayBaseUrl(input, options = {}) {
|
|
|
1978
1978
|
} catch {
|
|
1979
1979
|
throw invalidBaseUrlError(
|
|
1980
1980
|
`${label} must be a valid absolute http(s) URL. Received ${describeReceivedValue(candidate)}.`,
|
|
1981
|
-
'Use a full URL including the protocol, for example "https://
|
|
1981
|
+
'Use a full URL including the protocol, for example "https://mirror2.athena-cluster.com".'
|
|
1982
1982
|
);
|
|
1983
1983
|
}
|
|
1984
1984
|
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
|
|
1985
1985
|
throw invalidBaseUrlError(
|
|
1986
1986
|
`${label} must use http or https. Received ${JSON.stringify(trimmed)}.`,
|
|
1987
|
-
'Use an Athena gateway URL such as "https://
|
|
1987
|
+
'Use an Athena gateway URL such as "https://mirror2.athena-cluster.com".'
|
|
1988
1988
|
);
|
|
1989
1989
|
}
|
|
1990
1990
|
if (parsed.search || parsed.hash) {
|
|
@@ -2007,7 +2007,7 @@ function buildAthenaGatewayUrl(baseUrl, path) {
|
|
|
2007
2007
|
|
|
2008
2008
|
// package.json
|
|
2009
2009
|
var package_default = {
|
|
2010
|
-
version: "3.0.
|
|
2010
|
+
version: "3.0.3"
|
|
2011
2011
|
};
|
|
2012
2012
|
|
|
2013
2013
|
// src/sdk-version.ts
|
|
@@ -3055,7 +3055,7 @@ function createAthenaRequest(config, resolveContext) {
|
|
|
3055
3055
|
}
|
|
3056
3056
|
|
|
3057
3057
|
// src/gateway/client.ts
|
|
3058
|
-
var DEFAULT_CLIENT = "
|
|
3058
|
+
var DEFAULT_CLIENT = "DEFAULT_CLIENT";
|
|
3059
3059
|
var SDK_NAME2 = "xylex-group/athena";
|
|
3060
3060
|
var SDK_HEADER_VALUE = buildSdkHeaderValue(SDK_NAME2);
|
|
3061
3061
|
function parseResponseBody(rawText, contentType) {
|
|
@@ -9884,6 +9884,8 @@ var billingSdkManifest = {
|
|
|
9884
9884
|
methods: [
|
|
9885
9885
|
{ name: "getCapabilities", method: "GET", path: "/billing/v1/capabilities" },
|
|
9886
9886
|
{ name: "createCheckout", method: "POST", path: "/billing/v1/checkouts" },
|
|
9887
|
+
{ name: "listProducts", method: "GET", path: "/billing/v1/products" },
|
|
9888
|
+
{ name: "listPrices", method: "GET", path: "/billing/v1/prices" },
|
|
9887
9889
|
{ name: "listCustomers", method: "GET", path: "/billing/v1/customers" },
|
|
9888
9890
|
{ name: "createCustomer", method: "POST", path: "/billing/v1/customers" },
|
|
9889
9891
|
{ name: "getCustomer", method: "GET", path: "/billing/v1/customers/{id}" },
|
|
@@ -9909,6 +9911,12 @@ var billingSdkManifest = {
|
|
|
9909
9911
|
{ name: "cancelSubscription", method: "POST", path: "/billing/v1/subscriptions/{id}/cancel" },
|
|
9910
9912
|
{ name: "listInvoices", method: "GET", path: "/billing/v1/invoices" },
|
|
9911
9913
|
{ name: "getInvoice", method: "GET", path: "/billing/v1/invoices/{id}" },
|
|
9914
|
+
{ name: "listWebhooks", method: "GET", path: "/billing/v1/webhooks" },
|
|
9915
|
+
{ name: "createWebhook", method: "POST", path: "/billing/v1/webhooks" },
|
|
9916
|
+
{ name: "getWebhook", method: "GET", path: "/billing/v1/webhooks/{id}" },
|
|
9917
|
+
{ name: "updateWebhook", method: "PATCH", path: "/billing/v1/webhooks/{id}" },
|
|
9918
|
+
{ name: "deleteWebhook", method: "DELETE", path: "/billing/v1/webhooks/{id}" },
|
|
9919
|
+
{ name: "testWebhook", method: "POST", path: "/billing/v1/webhooks/{id}/test" },
|
|
9912
9920
|
{
|
|
9913
9921
|
name: "listConnections",
|
|
9914
9922
|
method: "GET",
|
|
@@ -10077,6 +10085,25 @@ function createBillingModule(config) {
|
|
|
10077
10085
|
createCheckout(body, options) {
|
|
10078
10086
|
return call("POST", "/billing/v1/checkouts", body, options);
|
|
10079
10087
|
},
|
|
10088
|
+
listProducts(input, options) {
|
|
10089
|
+
return call(
|
|
10090
|
+
"GET",
|
|
10091
|
+
appendQuery3("/billing/v1/products", connectionQuery(input)),
|
|
10092
|
+
void 0,
|
|
10093
|
+
options
|
|
10094
|
+
);
|
|
10095
|
+
},
|
|
10096
|
+
listPrices(input, options) {
|
|
10097
|
+
return call(
|
|
10098
|
+
"GET",
|
|
10099
|
+
appendQuery3("/billing/v1/prices", {
|
|
10100
|
+
...connectionQuery(input),
|
|
10101
|
+
...input.productId ? { productId: input.productId } : {}
|
|
10102
|
+
}),
|
|
10103
|
+
void 0,
|
|
10104
|
+
options
|
|
10105
|
+
);
|
|
10106
|
+
},
|
|
10080
10107
|
listCustomers(input, options) {
|
|
10081
10108
|
return call(
|
|
10082
10109
|
"GET",
|
|
@@ -10223,10 +10250,7 @@ function createBillingModule(config) {
|
|
|
10223
10250
|
getRefund(id, input, options) {
|
|
10224
10251
|
return call(
|
|
10225
10252
|
"GET",
|
|
10226
|
-
appendQuery3(withPathParam2("/billing/v1/refunds/{id}", "id", id),
|
|
10227
|
-
...connectionQuery(input),
|
|
10228
|
-
...input.paymentId ? { paymentId: input.paymentId } : {}
|
|
10229
|
-
}),
|
|
10253
|
+
appendQuery3(withPathParam2("/billing/v1/refunds/{id}", "id", id), connectionQuery(input)),
|
|
10230
10254
|
void 0,
|
|
10231
10255
|
options
|
|
10232
10256
|
);
|
|
@@ -10234,10 +10258,7 @@ function createBillingModule(config) {
|
|
|
10234
10258
|
cancelRefund(id, input, options) {
|
|
10235
10259
|
return call(
|
|
10236
10260
|
"POST",
|
|
10237
|
-
appendQuery3(withPathParam2("/billing/v1/refunds/{id}/cancel", "id", id),
|
|
10238
|
-
...connectionQuery(input),
|
|
10239
|
-
...input.paymentId ? { paymentId: input.paymentId } : {}
|
|
10240
|
-
}),
|
|
10261
|
+
appendQuery3(withPathParam2("/billing/v1/refunds/{id}/cancel", "id", id), connectionQuery(input)),
|
|
10241
10262
|
{},
|
|
10242
10263
|
options
|
|
10243
10264
|
);
|
|
@@ -10256,10 +10277,10 @@ function createBillingModule(config) {
|
|
|
10256
10277
|
getSubscription(id, input, options) {
|
|
10257
10278
|
return call(
|
|
10258
10279
|
"GET",
|
|
10259
|
-
appendQuery3(
|
|
10260
|
-
|
|
10261
|
-
|
|
10262
|
-
|
|
10280
|
+
appendQuery3(
|
|
10281
|
+
withPathParam2("/billing/v1/subscriptions/{id}", "id", id),
|
|
10282
|
+
connectionQuery(input)
|
|
10283
|
+
),
|
|
10263
10284
|
void 0,
|
|
10264
10285
|
options
|
|
10265
10286
|
);
|
|
@@ -10275,10 +10296,10 @@ function createBillingModule(config) {
|
|
|
10275
10296
|
cancelSubscription(id, input, options) {
|
|
10276
10297
|
return call(
|
|
10277
10298
|
"POST",
|
|
10278
|
-
appendQuery3(
|
|
10279
|
-
|
|
10280
|
-
|
|
10281
|
-
|
|
10299
|
+
appendQuery3(
|
|
10300
|
+
withPathParam2("/billing/v1/subscriptions/{id}/cancel", "id", id),
|
|
10301
|
+
connectionQuery(input)
|
|
10302
|
+
),
|
|
10282
10303
|
{},
|
|
10283
10304
|
options
|
|
10284
10305
|
);
|
|
@@ -10302,6 +10323,57 @@ function createBillingModule(config) {
|
|
|
10302
10323
|
options
|
|
10303
10324
|
);
|
|
10304
10325
|
},
|
|
10326
|
+
listWebhooks(input, options) {
|
|
10327
|
+
return call(
|
|
10328
|
+
"GET",
|
|
10329
|
+
appendQuery3("/billing/v1/webhooks", connectionQuery(input)),
|
|
10330
|
+
void 0,
|
|
10331
|
+
options
|
|
10332
|
+
);
|
|
10333
|
+
},
|
|
10334
|
+
createWebhook(input, body, options) {
|
|
10335
|
+
return call(
|
|
10336
|
+
"POST",
|
|
10337
|
+
appendQuery3("/billing/v1/webhooks", connectionQuery(input)),
|
|
10338
|
+
body,
|
|
10339
|
+
options
|
|
10340
|
+
);
|
|
10341
|
+
},
|
|
10342
|
+
getWebhook(id, input, options) {
|
|
10343
|
+
return call(
|
|
10344
|
+
"GET",
|
|
10345
|
+
appendQuery3(withPathParam2("/billing/v1/webhooks/{id}", "id", id), connectionQuery(input)),
|
|
10346
|
+
void 0,
|
|
10347
|
+
options
|
|
10348
|
+
);
|
|
10349
|
+
},
|
|
10350
|
+
updateWebhook(id, input, body, options) {
|
|
10351
|
+
return call(
|
|
10352
|
+
"PATCH",
|
|
10353
|
+
appendQuery3(withPathParam2("/billing/v1/webhooks/{id}", "id", id), connectionQuery(input)),
|
|
10354
|
+
body,
|
|
10355
|
+
options
|
|
10356
|
+
);
|
|
10357
|
+
},
|
|
10358
|
+
deleteWebhook(id, input, options) {
|
|
10359
|
+
return call(
|
|
10360
|
+
"DELETE",
|
|
10361
|
+
appendQuery3(withPathParam2("/billing/v1/webhooks/{id}", "id", id), connectionQuery(input)),
|
|
10362
|
+
void 0,
|
|
10363
|
+
options
|
|
10364
|
+
);
|
|
10365
|
+
},
|
|
10366
|
+
testWebhook(id, input, options) {
|
|
10367
|
+
return call(
|
|
10368
|
+
"POST",
|
|
10369
|
+
appendQuery3(
|
|
10370
|
+
withPathParam2("/billing/v1/webhooks/{id}/test", "id", id),
|
|
10371
|
+
connectionQuery(input)
|
|
10372
|
+
),
|
|
10373
|
+
{},
|
|
10374
|
+
options
|
|
10375
|
+
);
|
|
10376
|
+
},
|
|
10305
10377
|
listConnections(clientName, options) {
|
|
10306
10378
|
return call(
|
|
10307
10379
|
"GET",
|
|
@@ -10479,6 +10551,31 @@ function createBillingModule(config) {
|
|
|
10479
10551
|
};
|
|
10480
10552
|
}
|
|
10481
10553
|
|
|
10554
|
+
// src/config/errors.ts
|
|
10555
|
+
var AthenaConfigurationError = class extends Error {
|
|
10556
|
+
code;
|
|
10557
|
+
service;
|
|
10558
|
+
constructor(code, message, service) {
|
|
10559
|
+
super(message);
|
|
10560
|
+
this.name = "AthenaConfigurationError";
|
|
10561
|
+
this.code = code;
|
|
10562
|
+
this.service = service;
|
|
10563
|
+
}
|
|
10564
|
+
};
|
|
10565
|
+
|
|
10566
|
+
// src/context/merge.ts
|
|
10567
|
+
function mergeAthenaRequestContexts(base, override) {
|
|
10568
|
+
if (!base && !override) return void 0;
|
|
10569
|
+
return {
|
|
10570
|
+
...base,
|
|
10571
|
+
...override,
|
|
10572
|
+
headers: base?.headers || override?.headers ? {
|
|
10573
|
+
...base?.headers ?? {},
|
|
10574
|
+
...override?.headers ?? {}
|
|
10575
|
+
} : void 0
|
|
10576
|
+
};
|
|
10577
|
+
}
|
|
10578
|
+
|
|
10482
10579
|
// src/v3-client.ts
|
|
10483
10580
|
var ENV_URL_KEYS = ["ATHENA_URL", "NEXT_PUBLIC_ATHENA_URL"];
|
|
10484
10581
|
var ENV_DB_URL_KEYS = ["ATHENA_DB_URL", "ATHENA_GATEWAY_URL", "NEXT_PUBLIC_ATHENA_DB_API_URL"];
|
|
@@ -10489,15 +10586,6 @@ var ENV_STORAGE_URL_KEYS = ["ATHENA_STORAGE_URL", "NEXT_PUBLIC_ATHENA_STORAGE_UR
|
|
|
10489
10586
|
var ENV_KEY_KEYS = ["ATHENA_API_KEY", "NEXT_PUBLIC_ATHENA_API_KEY", "ATHENA_GATEWAY_API_KEY", "X_API_KEY"];
|
|
10490
10587
|
var ENV_CLIENT_KEYS = ["ATHENA_CLIENT", "NEXT_PUBLIC_ATHENA_CLIENT"];
|
|
10491
10588
|
var MISSING_DB_SENTINEL = "https://athena.invalid/db";
|
|
10492
|
-
var AthenaConfigurationError = class extends Error {
|
|
10493
|
-
code = "ATHENA_SERVICE_NOT_CONFIGURED";
|
|
10494
|
-
service;
|
|
10495
|
-
constructor(service, message = `Athena ${service} is not configured.`) {
|
|
10496
|
-
super(message);
|
|
10497
|
-
this.name = "AthenaConfigurationError";
|
|
10498
|
-
this.service = service;
|
|
10499
|
-
}
|
|
10500
|
-
};
|
|
10501
10589
|
function readFirstEnv(env, keys) {
|
|
10502
10590
|
for (const key of keys) {
|
|
10503
10591
|
const value = env?.[key]?.trim();
|
|
@@ -10538,11 +10626,18 @@ function resolveCore(config) {
|
|
|
10538
10626
|
chatWs: normalizeOptional(config.chat?.wsUrl) ?? (explicitRootWinsOverEnvServices && root ? toWebSocketUrl(root) : void 0) ?? readFirstEnv(env, ENV_CHAT_WS_URL_KEYS) ?? (root ? toWebSocketUrl(root) : void 0)
|
|
10539
10627
|
};
|
|
10540
10628
|
if (!urls.db && !urls.auth && !urls.chat && !urls.storage && !urls.billing) {
|
|
10541
|
-
throw new AthenaConfigurationError(
|
|
10629
|
+
throw new AthenaConfigurationError(
|
|
10630
|
+
"ATHENA_NO_SERVICE_CONFIGURED",
|
|
10631
|
+
"Athena requires a unified URL or at least one configured service URL.",
|
|
10632
|
+
"db"
|
|
10633
|
+
);
|
|
10542
10634
|
}
|
|
10543
10635
|
const key = normalizeOptional(config.key) ?? readFirstEnv(env, ENV_KEY_KEYS);
|
|
10544
10636
|
if (!key) {
|
|
10545
|
-
throw new
|
|
10637
|
+
throw new AthenaConfigurationError(
|
|
10638
|
+
"ATHENA_API_KEY_REQUIRED",
|
|
10639
|
+
"Athena API key is required. Pass key or provide it through the explicit env object."
|
|
10640
|
+
);
|
|
10546
10641
|
}
|
|
10547
10642
|
const base = {
|
|
10548
10643
|
config,
|
|
@@ -10555,18 +10650,10 @@ function resolveCore(config) {
|
|
|
10555
10650
|
internalCore: createInternalClientCore(createInternalConfig(base))
|
|
10556
10651
|
};
|
|
10557
10652
|
}
|
|
10558
|
-
function mergeContexts(base, override) {
|
|
10559
|
-
if (!base && !override) return void 0;
|
|
10560
|
-
return {
|
|
10561
|
-
...base,
|
|
10562
|
-
...override,
|
|
10563
|
-
headers: base?.headers || override?.headers ? { ...base?.headers ?? {}, ...override?.headers ?? {} } : void 0
|
|
10564
|
-
};
|
|
10565
|
-
}
|
|
10566
10653
|
async function resolveConfiguredContext(core, viewContext) {
|
|
10567
10654
|
const configured = core.config.context;
|
|
10568
10655
|
const base = typeof configured === "function" ? await configured() : configured;
|
|
10569
|
-
return
|
|
10656
|
+
return mergeAthenaRequestContexts(base, viewContext);
|
|
10570
10657
|
}
|
|
10571
10658
|
function createInternalConfig(core) {
|
|
10572
10659
|
const { config, urls } = core;
|
|
@@ -10599,7 +10686,13 @@ function createInternalConfig(core) {
|
|
|
10599
10686
|
};
|
|
10600
10687
|
}
|
|
10601
10688
|
function serviceGuard(urls, service) {
|
|
10602
|
-
if (!urls[service])
|
|
10689
|
+
if (!urls[service]) {
|
|
10690
|
+
throw new AthenaConfigurationError(
|
|
10691
|
+
"ATHENA_SERVICE_NOT_CONFIGURED",
|
|
10692
|
+
`Athena ${service} is not configured.`,
|
|
10693
|
+
service
|
|
10694
|
+
);
|
|
10695
|
+
}
|
|
10603
10696
|
}
|
|
10604
10697
|
function createUnavailableNamespace(service, urls, path = []) {
|
|
10605
10698
|
return new Proxy(() => void 0, {
|
|
@@ -10658,7 +10751,7 @@ function createClientView(core, viewContext) {
|
|
|
10658
10751
|
return resolved.verifyConnection(options);
|
|
10659
10752
|
},
|
|
10660
10753
|
withContext(context) {
|
|
10661
|
-
return createClientView(core,
|
|
10754
|
+
return createClientView(core, mergeAthenaRequestContexts(viewContext, context));
|
|
10662
10755
|
}
|
|
10663
10756
|
};
|
|
10664
10757
|
return Object.freeze(client);
|
|
@@ -11624,6 +11717,12 @@ var ATHENA_DIRECT_TARGETS = {
|
|
|
11624
11717
|
};
|
|
11625
11718
|
var DEFAULT_OUTPUT_FORMAT = "table-builder";
|
|
11626
11719
|
var DEFAULT_OUTPUT_PRESET = "athena-direct";
|
|
11720
|
+
var DEFAULT_ARTIFACT_WRITE_POLICY = "merge";
|
|
11721
|
+
var ARTIFACT_WRITE_POLICIES = /* @__PURE__ */ new Set([
|
|
11722
|
+
"merge",
|
|
11723
|
+
"skip",
|
|
11724
|
+
"overwrite"
|
|
11725
|
+
]);
|
|
11627
11726
|
var DEFAULT_NAMING = {
|
|
11628
11727
|
modelType: "pascal",
|
|
11629
11728
|
modelConst: "camel",
|
|
@@ -11903,6 +12002,23 @@ function normalizeFilterConfig(input) {
|
|
|
11903
12002
|
excludeTables: normalizeTableSelection(input?.excludeTables)
|
|
11904
12003
|
};
|
|
11905
12004
|
}
|
|
12005
|
+
function normalizeArtifactWritePolicy(value, fieldName) {
|
|
12006
|
+
if (value === void 0 || value === null || value === "") {
|
|
12007
|
+
return DEFAULT_ARTIFACT_WRITE_POLICY;
|
|
12008
|
+
}
|
|
12009
|
+
if (typeof value === "string" && ARTIFACT_WRITE_POLICIES.has(value)) {
|
|
12010
|
+
return value;
|
|
12011
|
+
}
|
|
12012
|
+
throw new Error(
|
|
12013
|
+
`Invalid output.artifactWrite.${fieldName}: expected one of merge | skip | overwrite, received ${JSON.stringify(value)}.`
|
|
12014
|
+
);
|
|
12015
|
+
}
|
|
12016
|
+
function normalizeArtifactWriteConfig(input) {
|
|
12017
|
+
return {
|
|
12018
|
+
database: normalizeArtifactWritePolicy(input?.database, "database"),
|
|
12019
|
+
registry: normalizeArtifactWritePolicy(input?.registry, "registry")
|
|
12020
|
+
};
|
|
12021
|
+
}
|
|
11906
12022
|
function normalizeOutputConfig(output) {
|
|
11907
12023
|
const preset = output?.preset ?? DEFAULT_OUTPUT_PRESET;
|
|
11908
12024
|
return {
|
|
@@ -11914,7 +12030,8 @@ function normalizeOutputConfig(output) {
|
|
|
11914
12030
|
},
|
|
11915
12031
|
placeholderMap: {
|
|
11916
12032
|
...output?.placeholderMap ?? {}
|
|
11917
|
-
}
|
|
12033
|
+
},
|
|
12034
|
+
artifactWrite: normalizeArtifactWriteConfig(output?.artifactWrite)
|
|
11918
12035
|
};
|
|
11919
12036
|
}
|
|
11920
12037
|
function normalizeProviderConfig(provider) {
|
|
@@ -13175,9 +13292,764 @@ function resolveGeneratorProvider(providerConfig, experimentalFlags) {
|
|
|
13175
13292
|
}
|
|
13176
13293
|
throw new Error(`Unsupported generator provider kind: ${providerConfig.kind ?? "unknown"}`);
|
|
13177
13294
|
}
|
|
13178
|
-
|
|
13179
|
-
|
|
13295
|
+
|
|
13296
|
+
// src/generator/artifact-merge.ts
|
|
13297
|
+
var IMPORT_RE = /^import\s+(?:type\s+)?(?:\{([^}]*)\}|([A-Za-z_$][\w$]*))\s+from\s+(['"])([^'"]+)\3\s*;?\s*$/gm;
|
|
13298
|
+
var DEFINE_EXPORT_RE = /export\s+const\s+([A-Za-z_$][\w$]*)\s*=\s*(define(?:Database|Registry))\s*\(\s*\{/g;
|
|
13299
|
+
var META_EXPORT_RE = /export\s+const\s+__athena_schema_meta\s*=\s*\{/g;
|
|
13300
|
+
var KNOWN_META_KEYS = /* @__PURE__ */ new Set([
|
|
13301
|
+
"schemaVersion",
|
|
13302
|
+
"generatedAt",
|
|
13303
|
+
"database",
|
|
13304
|
+
"outputPreset",
|
|
13305
|
+
"outputFormat"
|
|
13306
|
+
]);
|
|
13307
|
+
function detectNewline(source) {
|
|
13308
|
+
return source.includes("\r\n") ? "\r\n" : "\n";
|
|
13309
|
+
}
|
|
13310
|
+
function detectStyle(source) {
|
|
13311
|
+
const newline = detectNewline(source);
|
|
13312
|
+
const single = (source.match(/'/g) ?? []).length;
|
|
13313
|
+
const double = (source.match(/"/g) ?? []).length;
|
|
13314
|
+
const quote = double > single ? '"' : "'";
|
|
13315
|
+
const importLines = source.split(/\r?\n/).filter((line) => line.trimStart().startsWith("import "));
|
|
13316
|
+
const semicolons = importLines.length > 0 ? importLines.filter((line) => line.trimEnd().endsWith(";")).length >= importLines.length / 2 : false;
|
|
13317
|
+
const objectLines = source.split(/\r?\n/).map((line) => line.trim()).filter((line) => /^[A-Za-z0-9_'"]+\s*:\s*.+/.test(line));
|
|
13318
|
+
const trailingComma = objectLines.length > 0 ? objectLines.filter((line) => line.endsWith(",")).length >= Math.ceil(objectLines.length / 2) : true;
|
|
13319
|
+
const indentMatch = source.match(/\n([ \t]+)\S/);
|
|
13320
|
+
const indent = indentMatch?.[1] ?? " ";
|
|
13321
|
+
return { quote, semicolons, trailingComma, indent, newline };
|
|
13322
|
+
}
|
|
13323
|
+
function quoteString(value, quote) {
|
|
13324
|
+
const escaped = value.replace(/\\/g, "\\\\").replace(new RegExp(quote, "g"), `\\${quote}`);
|
|
13325
|
+
return `${quote}${escaped}${quote}`;
|
|
13326
|
+
}
|
|
13327
|
+
function parseNamedImports(source) {
|
|
13328
|
+
const imports = [];
|
|
13329
|
+
IMPORT_RE.lastIndex = 0;
|
|
13330
|
+
let match;
|
|
13331
|
+
while ((match = IMPORT_RE.exec(source)) !== null) {
|
|
13332
|
+
const named = match[1];
|
|
13333
|
+
const defaultName = match[2];
|
|
13334
|
+
const module = match[4];
|
|
13335
|
+
const names = named ? named.split(",").map((part) => part.trim()).filter(Boolean).map((part) => {
|
|
13336
|
+
const alias = part.split(/\s+as\s+/);
|
|
13337
|
+
return (alias[1] ?? alias[0]).trim();
|
|
13338
|
+
}) : defaultName ? [defaultName] : [];
|
|
13339
|
+
imports.push({
|
|
13340
|
+
names,
|
|
13341
|
+
module,
|
|
13342
|
+
raw: match[0],
|
|
13343
|
+
start: match.index,
|
|
13344
|
+
end: match.index + match[0].length
|
|
13345
|
+
});
|
|
13346
|
+
}
|
|
13347
|
+
return imports;
|
|
13348
|
+
}
|
|
13349
|
+
function findMatchingBrace(source, openIndex) {
|
|
13350
|
+
let depth = 0;
|
|
13351
|
+
let inSingle = false;
|
|
13352
|
+
let inDouble = false;
|
|
13353
|
+
let inTemplate = false;
|
|
13354
|
+
let escaped = false;
|
|
13355
|
+
for (let i = openIndex; i < source.length; i += 1) {
|
|
13356
|
+
const ch = source[i];
|
|
13357
|
+
if (escaped) {
|
|
13358
|
+
escaped = false;
|
|
13359
|
+
continue;
|
|
13360
|
+
}
|
|
13361
|
+
if (ch === "\\" && (inSingle || inDouble || inTemplate)) {
|
|
13362
|
+
escaped = true;
|
|
13363
|
+
continue;
|
|
13364
|
+
}
|
|
13365
|
+
if (!inDouble && !inTemplate && ch === "'") {
|
|
13366
|
+
inSingle = !inSingle;
|
|
13367
|
+
continue;
|
|
13368
|
+
}
|
|
13369
|
+
if (!inSingle && !inTemplate && ch === '"') {
|
|
13370
|
+
inDouble = !inDouble;
|
|
13371
|
+
continue;
|
|
13372
|
+
}
|
|
13373
|
+
if (!inSingle && !inDouble && ch === "`") {
|
|
13374
|
+
inTemplate = !inTemplate;
|
|
13375
|
+
continue;
|
|
13376
|
+
}
|
|
13377
|
+
if (inSingle || inDouble || inTemplate) {
|
|
13378
|
+
continue;
|
|
13379
|
+
}
|
|
13380
|
+
if (ch === "{") {
|
|
13381
|
+
depth += 1;
|
|
13382
|
+
} else if (ch === "}") {
|
|
13383
|
+
depth -= 1;
|
|
13384
|
+
if (depth === 0) {
|
|
13385
|
+
return i;
|
|
13386
|
+
}
|
|
13387
|
+
}
|
|
13388
|
+
}
|
|
13389
|
+
return -1;
|
|
13390
|
+
}
|
|
13391
|
+
function parseObjectEntries(body) {
|
|
13392
|
+
const entries = [];
|
|
13393
|
+
const lines = body.split(/\r?\n/);
|
|
13394
|
+
for (const line of lines) {
|
|
13395
|
+
const trimmed = line.trim();
|
|
13396
|
+
if (!trimmed || trimmed.startsWith("//") || trimmed.startsWith("/*")) {
|
|
13397
|
+
continue;
|
|
13398
|
+
}
|
|
13399
|
+
const withoutComma = trimmed.endsWith(",") ? trimmed.slice(0, -1).trimEnd() : trimmed;
|
|
13400
|
+
const match = withoutComma.match(/^([A-Za-z_$][\w$]*|['"][^'"]+['"])\s*:\s*(.+)$/);
|
|
13401
|
+
if (!match) {
|
|
13402
|
+
continue;
|
|
13403
|
+
}
|
|
13404
|
+
const keyRaw = match[1];
|
|
13405
|
+
const key = keyRaw.startsWith("'") || keyRaw.startsWith('"') ? keyRaw.slice(1, -1) : keyRaw;
|
|
13406
|
+
entries.push({
|
|
13407
|
+
key,
|
|
13408
|
+
value: match[2].trim(),
|
|
13409
|
+
raw: trimmed
|
|
13410
|
+
});
|
|
13411
|
+
}
|
|
13412
|
+
return entries;
|
|
13413
|
+
}
|
|
13414
|
+
function parseDefineBlocks(source) {
|
|
13415
|
+
const blocks = [];
|
|
13416
|
+
DEFINE_EXPORT_RE.lastIndex = 0;
|
|
13417
|
+
let match;
|
|
13418
|
+
while ((match = DEFINE_EXPORT_RE.exec(source)) !== null) {
|
|
13419
|
+
const exportName = match[1];
|
|
13420
|
+
const callName = match[2];
|
|
13421
|
+
const openBrace = match.index + match[0].lastIndexOf("{");
|
|
13422
|
+
const closeBrace = findMatchingBrace(source, openBrace);
|
|
13423
|
+
if (closeBrace < 0) {
|
|
13424
|
+
continue;
|
|
13425
|
+
}
|
|
13426
|
+
const body = source.slice(openBrace + 1, closeBrace);
|
|
13427
|
+
const fullEnd = (() => {
|
|
13428
|
+
let i = closeBrace + 1;
|
|
13429
|
+
while (i < source.length && /\s/.test(source[i])) i += 1;
|
|
13430
|
+
if (source[i] === ")") i += 1;
|
|
13431
|
+
while (i < source.length && /\s/.test(source[i])) i += 1;
|
|
13432
|
+
if (source[i] === ";") i += 1;
|
|
13433
|
+
return i;
|
|
13434
|
+
})();
|
|
13435
|
+
blocks.push({
|
|
13436
|
+
kind: callName === "defineDatabase" ? "database" : "registry",
|
|
13437
|
+
exportName,
|
|
13438
|
+
callName,
|
|
13439
|
+
entries: parseObjectEntries(body),
|
|
13440
|
+
bodyStart: openBrace + 1,
|
|
13441
|
+
bodyEnd: closeBrace,
|
|
13442
|
+
fullStart: match.index,
|
|
13443
|
+
fullEnd,
|
|
13444
|
+
raw: source.slice(match.index, fullEnd)
|
|
13445
|
+
});
|
|
13446
|
+
}
|
|
13447
|
+
return blocks;
|
|
13448
|
+
}
|
|
13449
|
+
function parseMetaBlock(source) {
|
|
13450
|
+
META_EXPORT_RE.lastIndex = 0;
|
|
13451
|
+
const match = META_EXPORT_RE.exec(source);
|
|
13452
|
+
if (!match) {
|
|
13453
|
+
return void 0;
|
|
13454
|
+
}
|
|
13455
|
+
const openBrace = match.index + match[0].lastIndexOf("{");
|
|
13456
|
+
const closeBrace = findMatchingBrace(source, openBrace);
|
|
13457
|
+
if (closeBrace < 0) {
|
|
13458
|
+
return void 0;
|
|
13459
|
+
}
|
|
13460
|
+
let fullEnd = closeBrace + 1;
|
|
13461
|
+
const after = source.slice(fullEnd);
|
|
13462
|
+
const asConst = after.match(/^\s*as\s+const\s*;?/);
|
|
13463
|
+
if (asConst) {
|
|
13464
|
+
fullEnd += asConst[0].length;
|
|
13465
|
+
} else if (source[fullEnd] === ";") {
|
|
13466
|
+
fullEnd += 1;
|
|
13467
|
+
}
|
|
13468
|
+
return {
|
|
13469
|
+
entries: parseObjectEntries(source.slice(openBrace + 1, closeBrace)),
|
|
13470
|
+
bodyStart: openBrace + 1,
|
|
13471
|
+
bodyEnd: closeBrace,
|
|
13472
|
+
fullStart: match.index,
|
|
13473
|
+
fullEnd,
|
|
13474
|
+
raw: source.slice(match.index, fullEnd)
|
|
13475
|
+
};
|
|
13476
|
+
}
|
|
13477
|
+
function hasImportBinding(imports, name, module) {
|
|
13478
|
+
return imports.some(
|
|
13479
|
+
(item) => item.names.includes(name) && (module === void 0)
|
|
13480
|
+
);
|
|
13481
|
+
}
|
|
13482
|
+
function findImportForName(imports, name) {
|
|
13483
|
+
return imports.find((item) => item.names.includes(name));
|
|
13484
|
+
}
|
|
13485
|
+
function normalizeModulePath(modulePath) {
|
|
13486
|
+
return modulePath.replace(/\\/g, "/").replace(/^\.\//, "").replace(/\.ts$/, "");
|
|
13487
|
+
}
|
|
13488
|
+
function formatImport(names, modulePath, style) {
|
|
13489
|
+
const body = `import { ${names.join(", ")} } from ${quoteString(modulePath, style.quote)}`;
|
|
13490
|
+
return style.semicolons ? `${body};` : body;
|
|
13491
|
+
}
|
|
13492
|
+
function formatObjectEntry(key, value, style, isLast) {
|
|
13493
|
+
const needsQuote = !/^[A-Za-z_$][\w$]*$/.test(key);
|
|
13494
|
+
const renderedKey = needsQuote ? quoteString(key, style.quote) : key;
|
|
13495
|
+
const comma = !isLast || style.trailingComma ? "," : "";
|
|
13496
|
+
return `${style.indent}${renderedKey}: ${value}${comma}`;
|
|
13497
|
+
}
|
|
13498
|
+
function replaceRange(source, start, end, insertion) {
|
|
13499
|
+
return source.slice(0, start) + insertion + source.slice(end);
|
|
13500
|
+
}
|
|
13501
|
+
function collectDuplicateKeys(entries) {
|
|
13502
|
+
const seen = /* @__PURE__ */ new Set();
|
|
13503
|
+
const dupes = [];
|
|
13504
|
+
for (const entry of entries) {
|
|
13505
|
+
if (seen.has(entry.key)) {
|
|
13506
|
+
dupes.push(entry.key);
|
|
13507
|
+
}
|
|
13508
|
+
seen.add(entry.key);
|
|
13509
|
+
}
|
|
13510
|
+
return dupes;
|
|
13511
|
+
}
|
|
13512
|
+
function collectDuplicateImportBindings(imports) {
|
|
13513
|
+
const seen = /* @__PURE__ */ new Set();
|
|
13514
|
+
const dupes = [];
|
|
13515
|
+
for (const item of imports) {
|
|
13516
|
+
for (const name of item.names) {
|
|
13517
|
+
if (seen.has(name)) {
|
|
13518
|
+
dupes.push(name);
|
|
13519
|
+
}
|
|
13520
|
+
seen.add(name);
|
|
13521
|
+
}
|
|
13522
|
+
}
|
|
13523
|
+
return dupes;
|
|
13524
|
+
}
|
|
13525
|
+
function lintArtifactSource(source, kind) {
|
|
13526
|
+
const errors = [];
|
|
13527
|
+
const imports = parseNamedImports(source);
|
|
13528
|
+
const dupImports = collectDuplicateImportBindings(imports);
|
|
13529
|
+
if (dupImports.length > 0) {
|
|
13530
|
+
errors.push(`duplicate import bindings: ${dupImports.join(", ")}`);
|
|
13531
|
+
}
|
|
13532
|
+
const blocks = parseDefineBlocks(source).filter((block2) => block2.kind === kind);
|
|
13533
|
+
if (blocks.length === 0) {
|
|
13534
|
+
errors.push(`missing export const \u2026 = define${kind === "database" ? "Database" : "Registry"}({\u2026})`);
|
|
13535
|
+
return errors;
|
|
13536
|
+
}
|
|
13537
|
+
if (blocks.length > 1) {
|
|
13538
|
+
errors.push(`multiple define${kind === "database" ? "Database" : "Registry"} exports found`);
|
|
13539
|
+
}
|
|
13540
|
+
const block = blocks[0];
|
|
13541
|
+
const dupKeys = collectDuplicateKeys(block.entries);
|
|
13542
|
+
if (dupKeys.length > 0) {
|
|
13543
|
+
errors.push(`duplicate object keys: ${dupKeys.join(", ")}`);
|
|
13544
|
+
}
|
|
13545
|
+
for (const entry of block.entries) {
|
|
13546
|
+
const valueId = entry.value.match(/^[A-Za-z_$][\w$]*$/)?.[0];
|
|
13547
|
+
if (valueId && !hasImportBinding(imports, valueId) && valueId !== block.exportName) {
|
|
13548
|
+
if (!source.includes(`const ${valueId}`) && !source.includes(`function ${valueId}`)) {
|
|
13549
|
+
errors.push(`value "${valueId}" for key "${entry.key}" is not imported`);
|
|
13550
|
+
}
|
|
13551
|
+
}
|
|
13552
|
+
}
|
|
13553
|
+
if (kind === "database" && !hasImportBinding(imports, "defineDatabase")) {
|
|
13554
|
+
errors.push("missing defineDatabase import");
|
|
13555
|
+
}
|
|
13556
|
+
if (kind === "registry" && !hasImportBinding(imports, "defineRegistry")) {
|
|
13557
|
+
errors.push("missing defineRegistry import");
|
|
13558
|
+
}
|
|
13559
|
+
return errors;
|
|
13560
|
+
}
|
|
13561
|
+
function preservedCustomUnits(existing, generated, kind) {
|
|
13562
|
+
const custom = [];
|
|
13563
|
+
const existingImports = parseNamedImports(existing);
|
|
13564
|
+
const generatedImports = parseNamedImports(generated);
|
|
13565
|
+
const generatedModules = new Set(generatedImports.map((item) => normalizeModulePath(item.module)));
|
|
13566
|
+
const generatedNames = new Set(generatedImports.flatMap((item) => item.names));
|
|
13567
|
+
for (const item of existingImports) {
|
|
13568
|
+
const moduleNorm = normalizeModulePath(item.module);
|
|
13569
|
+
if (moduleNorm.includes("@xylex-group/athena")) {
|
|
13570
|
+
continue;
|
|
13571
|
+
}
|
|
13572
|
+
const unexpectedNames = item.names.filter((name) => !generatedNames.has(name));
|
|
13573
|
+
if (unexpectedNames.length > 0 && !generatedModules.has(moduleNorm)) {
|
|
13574
|
+
custom.push(`import { ${unexpectedNames.join(", ")} } from '${item.module}'`);
|
|
13575
|
+
} else if (unexpectedNames.length > 0) {
|
|
13576
|
+
custom.push(`import binding(s): ${unexpectedNames.join(", ")}`);
|
|
13577
|
+
}
|
|
13578
|
+
}
|
|
13579
|
+
const existingBlocks = parseDefineBlocks(existing).filter((block) => block.kind === kind);
|
|
13580
|
+
const generatedBlocks = parseDefineBlocks(generated).filter((block) => block.kind === kind);
|
|
13581
|
+
const generatedKeys = new Set(generatedBlocks[0]?.entries.map((entry) => entry.key) ?? []);
|
|
13582
|
+
for (const entry of existingBlocks[0]?.entries ?? []) {
|
|
13583
|
+
if (!generatedKeys.has(entry.key)) {
|
|
13584
|
+
custom.push(`${kind} entry: ${entry.key}: ${entry.value}`);
|
|
13585
|
+
}
|
|
13586
|
+
}
|
|
13587
|
+
if (kind === "registry") {
|
|
13588
|
+
const existingMeta = parseMetaBlock(existing);
|
|
13589
|
+
const generatedMeta = parseMetaBlock(generated);
|
|
13590
|
+
const generatedMetaKeys = new Set(generatedMeta?.entries.map((entry) => entry.key) ?? []);
|
|
13591
|
+
for (const entry of existingMeta?.entries ?? []) {
|
|
13592
|
+
if (!generatedMetaKeys.has(entry.key) && !KNOWN_META_KEYS.has(entry.key)) {
|
|
13593
|
+
custom.push(`meta entry: ${entry.key}: ${entry.value}`);
|
|
13594
|
+
}
|
|
13595
|
+
}
|
|
13596
|
+
}
|
|
13597
|
+
const exportConstRe = /^export\s+const\s+([A-Za-z_$][\w$]*)\b/gm;
|
|
13598
|
+
const generatedExports = /* @__PURE__ */ new Set();
|
|
13599
|
+
let match;
|
|
13600
|
+
exportConstRe.lastIndex = 0;
|
|
13601
|
+
while ((match = exportConstRe.exec(generated)) !== null) {
|
|
13602
|
+
generatedExports.add(match[1]);
|
|
13603
|
+
}
|
|
13604
|
+
exportConstRe.lastIndex = 0;
|
|
13605
|
+
while ((match = exportConstRe.exec(existing)) !== null) {
|
|
13606
|
+
if (!generatedExports.has(match[1]) && match[1] !== "__athena_schema_meta") {
|
|
13607
|
+
custom.push(`export const ${match[1]}`);
|
|
13608
|
+
}
|
|
13609
|
+
}
|
|
13610
|
+
return custom;
|
|
13611
|
+
}
|
|
13612
|
+
function insertImportAfterPackageImports(source, importLine, style) {
|
|
13613
|
+
const imports = parseNamedImports(source);
|
|
13614
|
+
if (imports.length === 0) {
|
|
13615
|
+
return `${importLine}${style.newline}${source}`;
|
|
13616
|
+
}
|
|
13617
|
+
let anchor = imports[imports.length - 1];
|
|
13618
|
+
for (let i = imports.length - 1; i >= 0; i -= 1) {
|
|
13619
|
+
if (imports[i].module.startsWith(".")) {
|
|
13620
|
+
anchor = imports[i];
|
|
13621
|
+
break;
|
|
13622
|
+
}
|
|
13623
|
+
}
|
|
13624
|
+
const insertAt = anchor.end;
|
|
13625
|
+
const before = source.slice(0, insertAt);
|
|
13626
|
+
const after = source.slice(insertAt);
|
|
13627
|
+
const needsLeadingNl = !before.endsWith("\n");
|
|
13628
|
+
const prefix = needsLeadingNl ? style.newline : "";
|
|
13629
|
+
return `${before}${prefix}${importLine}${after.startsWith("\n") || after.startsWith("\r\n") ? "" : style.newline}${after}`;
|
|
13180
13630
|
}
|
|
13631
|
+
function rewriteObjectBody(entries, style) {
|
|
13632
|
+
if (entries.length === 0) {
|
|
13633
|
+
return style.newline;
|
|
13634
|
+
}
|
|
13635
|
+
const lines = entries.map(
|
|
13636
|
+
(entry, index) => formatObjectEntry(entry.key, entry.value, style, index === entries.length - 1)
|
|
13637
|
+
);
|
|
13638
|
+
return `${style.newline}${lines.join(style.newline)}${style.newline}`;
|
|
13639
|
+
}
|
|
13640
|
+
function mergeDatabaseArtifact(existing, generated) {
|
|
13641
|
+
const style = detectStyle(existing);
|
|
13642
|
+
const generatedStyle = detectStyle(generated);
|
|
13643
|
+
const effectiveStyle = {
|
|
13644
|
+
...style,
|
|
13645
|
+
// Prefer existing fingerprint; fall back to generated if existing is empty-ish
|
|
13646
|
+
quote: existing.includes('"') || existing.includes("'") ? style.quote : generatedStyle.quote
|
|
13647
|
+
};
|
|
13648
|
+
const generatedImports = parseNamedImports(generated);
|
|
13649
|
+
const existingBlocks = parseDefineBlocks(existing).filter((block) => block.kind === "database");
|
|
13650
|
+
const generatedBlocks = parseDefineBlocks(generated).filter((block) => block.kind === "database");
|
|
13651
|
+
if (existingBlocks.length === 0 || generatedBlocks.length === 0) {
|
|
13652
|
+
return {
|
|
13653
|
+
action: "skip",
|
|
13654
|
+
skipReason: "merge-unparseable",
|
|
13655
|
+
added: [],
|
|
13656
|
+
preservedCustom: [],
|
|
13657
|
+
conflicts: [],
|
|
13658
|
+
lintErrors: [],
|
|
13659
|
+
detail: "could not locate defineDatabase({\u2026}) export for merge"
|
|
13660
|
+
};
|
|
13661
|
+
}
|
|
13662
|
+
const generatedBlock = generatedBlocks[0];
|
|
13663
|
+
const conflicts = [];
|
|
13664
|
+
const added = [];
|
|
13665
|
+
let next = existing;
|
|
13666
|
+
if (!hasImportBinding(parseNamedImports(next), "defineDatabase")) {
|
|
13667
|
+
const pkgImport = generatedImports.find((item) => item.names.includes("defineDatabase"));
|
|
13668
|
+
if (pkgImport) {
|
|
13669
|
+
const line = formatImport(["defineDatabase"], pkgImport.module, effectiveStyle);
|
|
13670
|
+
next = insertImportAfterPackageImports(next, line, effectiveStyle);
|
|
13671
|
+
added.push("import defineDatabase");
|
|
13672
|
+
}
|
|
13673
|
+
}
|
|
13674
|
+
let workingImports = parseNamedImports(next);
|
|
13675
|
+
let workingBlocks = parseDefineBlocks(next).filter((block) => block.kind === "database");
|
|
13676
|
+
let workingBlock = workingBlocks[0];
|
|
13677
|
+
const entryMap = new Map(workingBlock.entries.map((entry) => [entry.key, entry]));
|
|
13678
|
+
for (const desired of generatedBlock.entries) {
|
|
13679
|
+
const existingEntry = entryMap.get(desired.key);
|
|
13680
|
+
if (existingEntry) {
|
|
13681
|
+
if (existingEntry.value !== desired.value) {
|
|
13682
|
+
conflicts.push(
|
|
13683
|
+
`key "${desired.key}" maps to ${existingEntry.value} (existing) vs ${desired.value} (generated)`
|
|
13684
|
+
);
|
|
13685
|
+
}
|
|
13686
|
+
continue;
|
|
13687
|
+
}
|
|
13688
|
+
const desiredImport = generatedImports.find((item) => item.names.includes(desired.value));
|
|
13689
|
+
if (desiredImport) {
|
|
13690
|
+
const existingForName = findImportForName(workingImports, desired.value);
|
|
13691
|
+
if (existingForName) {
|
|
13692
|
+
if (normalizeModulePath(existingForName.module) !== normalizeModulePath(desiredImport.module)) {
|
|
13693
|
+
conflicts.push(
|
|
13694
|
+
`binding "${desired.value}" imported from '${existingForName.module}' vs '${desiredImport.module}'`
|
|
13695
|
+
);
|
|
13696
|
+
continue;
|
|
13697
|
+
}
|
|
13698
|
+
} else {
|
|
13699
|
+
const line = formatImport([desired.value], desiredImport.module, effectiveStyle);
|
|
13700
|
+
next = insertImportAfterPackageImports(next, line, effectiveStyle);
|
|
13701
|
+
added.push(`import ${desired.value}`);
|
|
13702
|
+
workingImports = parseNamedImports(next);
|
|
13703
|
+
}
|
|
13704
|
+
}
|
|
13705
|
+
workingBlocks = parseDefineBlocks(next).filter((block) => block.kind === "database");
|
|
13706
|
+
workingBlock = workingBlocks[0];
|
|
13707
|
+
const nextEntries = [...workingBlock.entries, { key: desired.key, value: desired.value, raw: "" }];
|
|
13708
|
+
const body = rewriteObjectBody(nextEntries, effectiveStyle);
|
|
13709
|
+
next = replaceRange(next, workingBlock.bodyStart, workingBlock.bodyEnd, body);
|
|
13710
|
+
entryMap.set(desired.key, { key: desired.key, value: desired.value, raw: "" });
|
|
13711
|
+
added.push(`database entry: ${desired.key}`);
|
|
13712
|
+
}
|
|
13713
|
+
if (conflicts.length > 0 && added.length === 0) {
|
|
13714
|
+
return {
|
|
13715
|
+
action: "skip",
|
|
13716
|
+
skipReason: "merge-conflict",
|
|
13717
|
+
added: [],
|
|
13718
|
+
preservedCustom: preservedCustomUnits(existing, generated, "database"),
|
|
13719
|
+
conflicts,
|
|
13720
|
+
lintErrors: [],
|
|
13721
|
+
detail: conflicts.join("; ")
|
|
13722
|
+
};
|
|
13723
|
+
}
|
|
13724
|
+
const lintErrors = lintArtifactSource(next, "database");
|
|
13725
|
+
if (lintErrors.length > 0) {
|
|
13726
|
+
return {
|
|
13727
|
+
action: "skip",
|
|
13728
|
+
skipReason: "merge-lint-failed",
|
|
13729
|
+
added,
|
|
13730
|
+
preservedCustom: preservedCustomUnits(existing, generated, "database"),
|
|
13731
|
+
conflicts,
|
|
13732
|
+
lintErrors,
|
|
13733
|
+
detail: lintErrors.join("; ")
|
|
13734
|
+
};
|
|
13735
|
+
}
|
|
13736
|
+
const preservedCustom = preservedCustomUnits(next, generated, "database");
|
|
13737
|
+
if (next === existing || next.replace(/\r\n/g, "\n") === existing.replace(/\r\n/g, "\n")) {
|
|
13738
|
+
return {
|
|
13739
|
+
action: "unchanged",
|
|
13740
|
+
content: existing,
|
|
13741
|
+
skipReason: "already-current",
|
|
13742
|
+
added: [],
|
|
13743
|
+
preservedCustom,
|
|
13744
|
+
conflicts,
|
|
13745
|
+
lintErrors: [],
|
|
13746
|
+
detail: conflicts.length > 0 ? conflicts.join("; ") : void 0
|
|
13747
|
+
};
|
|
13748
|
+
}
|
|
13749
|
+
return {
|
|
13750
|
+
action: "write",
|
|
13751
|
+
content: next.endsWith("\n") ? next : `${next}${effectiveStyle.newline}`,
|
|
13752
|
+
writeReason: "merged",
|
|
13753
|
+
added,
|
|
13754
|
+
preservedCustom,
|
|
13755
|
+
conflicts,
|
|
13756
|
+
lintErrors: []
|
|
13757
|
+
};
|
|
13758
|
+
}
|
|
13759
|
+
function mergeMetaFields(existingMeta, generatedMeta) {
|
|
13760
|
+
const added = [];
|
|
13761
|
+
if (!generatedMeta) {
|
|
13762
|
+
return { entries: existingMeta?.entries ?? [], changed: false, added };
|
|
13763
|
+
}
|
|
13764
|
+
if (!existingMeta) {
|
|
13765
|
+
return {
|
|
13766
|
+
entries: generatedMeta.entries,
|
|
13767
|
+
changed: true,
|
|
13768
|
+
added: generatedMeta.entries.map((entry) => `meta entry: ${entry.key}`)
|
|
13769
|
+
};
|
|
13770
|
+
}
|
|
13771
|
+
const map = new Map(existingMeta.entries.map((entry) => [entry.key, entry]));
|
|
13772
|
+
let changed = false;
|
|
13773
|
+
for (const desired of generatedMeta.entries) {
|
|
13774
|
+
const current = map.get(desired.key);
|
|
13775
|
+
if (!current) {
|
|
13776
|
+
map.set(desired.key, desired);
|
|
13777
|
+
added.push(`meta entry: ${desired.key}`);
|
|
13778
|
+
changed = true;
|
|
13779
|
+
continue;
|
|
13780
|
+
}
|
|
13781
|
+
if (KNOWN_META_KEYS.has(desired.key) && current.value !== desired.value) {
|
|
13782
|
+
map.set(desired.key, desired);
|
|
13783
|
+
added.push(`meta refresh: ${desired.key}`);
|
|
13784
|
+
changed = true;
|
|
13785
|
+
}
|
|
13786
|
+
}
|
|
13787
|
+
const ordered = [];
|
|
13788
|
+
const seen = /* @__PURE__ */ new Set();
|
|
13789
|
+
for (const entry of existingMeta.entries) {
|
|
13790
|
+
const next = map.get(entry.key);
|
|
13791
|
+
if (next) {
|
|
13792
|
+
ordered.push(next);
|
|
13793
|
+
seen.add(entry.key);
|
|
13794
|
+
}
|
|
13795
|
+
}
|
|
13796
|
+
for (const entry of generatedMeta.entries) {
|
|
13797
|
+
if (!seen.has(entry.key)) {
|
|
13798
|
+
const next = map.get(entry.key);
|
|
13799
|
+
if (next) {
|
|
13800
|
+
ordered.push(next);
|
|
13801
|
+
seen.add(entry.key);
|
|
13802
|
+
}
|
|
13803
|
+
}
|
|
13804
|
+
}
|
|
13805
|
+
for (const [key, entry] of map) {
|
|
13806
|
+
if (!seen.has(key)) {
|
|
13807
|
+
ordered.push(entry);
|
|
13808
|
+
}
|
|
13809
|
+
}
|
|
13810
|
+
return { entries: ordered, changed, added };
|
|
13811
|
+
}
|
|
13812
|
+
function mergeRegistryArtifact(existing, generated) {
|
|
13813
|
+
const style = detectStyle(existing);
|
|
13814
|
+
const effectiveStyle = style;
|
|
13815
|
+
const generatedImports = parseNamedImports(generated);
|
|
13816
|
+
const existingBlocks = parseDefineBlocks(existing).filter((block) => block.kind === "registry");
|
|
13817
|
+
const generatedBlocks = parseDefineBlocks(generated).filter((block) => block.kind === "registry");
|
|
13818
|
+
if (existingBlocks.length === 0 || generatedBlocks.length === 0) {
|
|
13819
|
+
return {
|
|
13820
|
+
action: "skip",
|
|
13821
|
+
skipReason: "merge-unparseable",
|
|
13822
|
+
added: [],
|
|
13823
|
+
preservedCustom: [],
|
|
13824
|
+
conflicts: [],
|
|
13825
|
+
lintErrors: [],
|
|
13826
|
+
detail: "could not locate defineRegistry({\u2026}) export for merge"
|
|
13827
|
+
};
|
|
13828
|
+
}
|
|
13829
|
+
const existingBlock = existingBlocks[0];
|
|
13830
|
+
const generatedBlock = generatedBlocks[0];
|
|
13831
|
+
const conflicts = [];
|
|
13832
|
+
const added = [];
|
|
13833
|
+
let next = existing;
|
|
13834
|
+
if (!hasImportBinding(parseNamedImports(next), "defineRegistry")) {
|
|
13835
|
+
const pkgImport = generatedImports.find((item) => item.names.includes("defineRegistry"));
|
|
13836
|
+
if (pkgImport) {
|
|
13837
|
+
next = insertImportAfterPackageImports(
|
|
13838
|
+
next,
|
|
13839
|
+
formatImport(["defineRegistry"], pkgImport.module, effectiveStyle),
|
|
13840
|
+
effectiveStyle
|
|
13841
|
+
);
|
|
13842
|
+
added.push("import defineRegistry");
|
|
13843
|
+
}
|
|
13844
|
+
}
|
|
13845
|
+
const preferredDbValue = existingBlock.entries[0]?.value ?? generatedBlock.entries[0]?.value;
|
|
13846
|
+
const generatedDbImport = generatedImports.find((item) => item.names.includes(generatedBlock.entries[0]?.value ?? "")) ?? generatedImports.find((item) => item.module.startsWith("."));
|
|
13847
|
+
if (preferredDbValue && generatedDbImport) {
|
|
13848
|
+
const existingForName = findImportForName(parseNamedImports(next), preferredDbValue);
|
|
13849
|
+
if (!existingForName) {
|
|
13850
|
+
const modulePath = generatedDbImport.module;
|
|
13851
|
+
const importName = findImportForName(generatedImports, preferredDbValue)?.names[0] ?? generatedBlock.entries[0]?.value ?? preferredDbValue;
|
|
13852
|
+
if (!hasImportBinding(parseNamedImports(next), importName)) {
|
|
13853
|
+
next = insertImportAfterPackageImports(
|
|
13854
|
+
next,
|
|
13855
|
+
formatImport([importName], modulePath, effectiveStyle),
|
|
13856
|
+
effectiveStyle
|
|
13857
|
+
);
|
|
13858
|
+
added.push(`import ${importName}`);
|
|
13859
|
+
}
|
|
13860
|
+
} else if (normalizeModulePath(existingForName.module) !== normalizeModulePath(generatedDbImport.module)) {
|
|
13861
|
+
conflicts.push(
|
|
13862
|
+
`binding "${preferredDbValue}" imported from '${existingForName.module}' vs '${generatedDbImport.module}'`
|
|
13863
|
+
);
|
|
13864
|
+
}
|
|
13865
|
+
}
|
|
13866
|
+
let workingBlocks = parseDefineBlocks(next).filter((block) => block.kind === "registry");
|
|
13867
|
+
let workingBlock = workingBlocks[0];
|
|
13868
|
+
const entryMap = new Map(workingBlock.entries.map((entry) => [entry.key, entry]));
|
|
13869
|
+
for (const desired of generatedBlock.entries) {
|
|
13870
|
+
const existingEntry = entryMap.get(desired.key);
|
|
13871
|
+
if (existingEntry) {
|
|
13872
|
+
continue;
|
|
13873
|
+
}
|
|
13874
|
+
const dbImport = parseNamedImports(next).find(
|
|
13875
|
+
(item) => item.module.startsWith(".") && item.names.some((name) => name !== "defineRegistry")
|
|
13876
|
+
);
|
|
13877
|
+
const value = dbImport?.names[0] ?? desired.value;
|
|
13878
|
+
const nextEntries = [...workingBlock.entries, { key: desired.key, value, raw: "" }];
|
|
13879
|
+
const body = rewriteObjectBody(nextEntries, effectiveStyle);
|
|
13880
|
+
next = replaceRange(next, workingBlock.bodyStart, workingBlock.bodyEnd, body);
|
|
13881
|
+
entryMap.set(desired.key, { key: desired.key, value, raw: "" });
|
|
13882
|
+
added.push(`registry entry: ${desired.key}`);
|
|
13883
|
+
workingBlocks = parseDefineBlocks(next).filter((block) => block.kind === "registry");
|
|
13884
|
+
workingBlock = workingBlocks[0];
|
|
13885
|
+
}
|
|
13886
|
+
const existingMeta = parseMetaBlock(next);
|
|
13887
|
+
const generatedMeta = parseMetaBlock(generated);
|
|
13888
|
+
const structuralAdded = added.length > 0;
|
|
13889
|
+
if (generatedMeta) {
|
|
13890
|
+
if (!existingMeta) {
|
|
13891
|
+
const blocks = parseDefineBlocks(next).filter((block) => block.kind === "registry");
|
|
13892
|
+
const insertAt = blocks[0]?.fullStart ?? next.length;
|
|
13893
|
+
const metaBody = rewriteObjectBody(generatedMeta.entries, effectiveStyle);
|
|
13894
|
+
const metaBlock = `export const __athena_schema_meta = {${metaBody}} as const${effectiveStyle.semicolons ? ";" : ""}${effectiveStyle.newline}${effectiveStyle.newline}`;
|
|
13895
|
+
next = replaceRange(next, insertAt, insertAt, metaBlock);
|
|
13896
|
+
added.push("__athena_schema_meta");
|
|
13897
|
+
} else {
|
|
13898
|
+
const desiredEntries = structuralAdded ? generatedMeta.entries : generatedMeta.entries.filter((entry) => {
|
|
13899
|
+
return !existingMeta.entries.some((current) => current.key === entry.key);
|
|
13900
|
+
});
|
|
13901
|
+
if (structuralAdded) {
|
|
13902
|
+
const merged = mergeMetaFields(existingMeta, generatedMeta);
|
|
13903
|
+
if (merged.changed) {
|
|
13904
|
+
const metaNow = parseMetaBlock(next);
|
|
13905
|
+
if (metaNow) {
|
|
13906
|
+
const body = rewriteObjectBody(merged.entries, effectiveStyle);
|
|
13907
|
+
next = replaceRange(next, metaNow.bodyStart, metaNow.bodyEnd, body);
|
|
13908
|
+
added.push(...merged.added);
|
|
13909
|
+
}
|
|
13910
|
+
}
|
|
13911
|
+
} else if (desiredEntries.length > 0) {
|
|
13912
|
+
const map = new Map(existingMeta.entries.map((entry) => [entry.key, entry]));
|
|
13913
|
+
for (const entry of desiredEntries) {
|
|
13914
|
+
map.set(entry.key, entry);
|
|
13915
|
+
added.push(`meta entry: ${entry.key}`);
|
|
13916
|
+
}
|
|
13917
|
+
const ordered = [
|
|
13918
|
+
...existingMeta.entries.map((entry) => map.get(entry.key)),
|
|
13919
|
+
...desiredEntries.filter((entry) => !existingMeta.entries.some((e) => e.key === entry.key))
|
|
13920
|
+
];
|
|
13921
|
+
const metaNow = parseMetaBlock(next);
|
|
13922
|
+
if (metaNow) {
|
|
13923
|
+
const body = rewriteObjectBody(ordered, effectiveStyle);
|
|
13924
|
+
next = replaceRange(next, metaNow.bodyStart, metaNow.bodyEnd, body);
|
|
13925
|
+
}
|
|
13926
|
+
}
|
|
13927
|
+
}
|
|
13928
|
+
}
|
|
13929
|
+
if (conflicts.length > 0 && added.length === 0) {
|
|
13930
|
+
return {
|
|
13931
|
+
action: "skip",
|
|
13932
|
+
skipReason: "merge-conflict",
|
|
13933
|
+
added: [],
|
|
13934
|
+
preservedCustom: preservedCustomUnits(existing, generated, "registry"),
|
|
13935
|
+
conflicts,
|
|
13936
|
+
lintErrors: [],
|
|
13937
|
+
detail: conflicts.join("; ")
|
|
13938
|
+
};
|
|
13939
|
+
}
|
|
13940
|
+
const lintErrors = lintArtifactSource(next, "registry");
|
|
13941
|
+
if (lintErrors.length > 0) {
|
|
13942
|
+
return {
|
|
13943
|
+
action: "skip",
|
|
13944
|
+
skipReason: "merge-lint-failed",
|
|
13945
|
+
added,
|
|
13946
|
+
preservedCustom: preservedCustomUnits(existing, generated, "registry"),
|
|
13947
|
+
conflicts,
|
|
13948
|
+
lintErrors,
|
|
13949
|
+
detail: lintErrors.join("; ")
|
|
13950
|
+
};
|
|
13951
|
+
}
|
|
13952
|
+
const preservedCustom = preservedCustomUnits(next, generated, "registry");
|
|
13953
|
+
if (next.replace(/\r\n/g, "\n") === existing.replace(/\r\n/g, "\n")) {
|
|
13954
|
+
return {
|
|
13955
|
+
action: "unchanged",
|
|
13956
|
+
content: existing,
|
|
13957
|
+
skipReason: "already-current",
|
|
13958
|
+
added: [],
|
|
13959
|
+
preservedCustom,
|
|
13960
|
+
conflicts,
|
|
13961
|
+
lintErrors: []
|
|
13962
|
+
};
|
|
13963
|
+
}
|
|
13964
|
+
return {
|
|
13965
|
+
action: "write",
|
|
13966
|
+
content: next.endsWith("\n") ? next : `${next}${effectiveStyle.newline}`,
|
|
13967
|
+
writeReason: "merged",
|
|
13968
|
+
added,
|
|
13969
|
+
preservedCustom,
|
|
13970
|
+
conflicts,
|
|
13971
|
+
lintErrors: []
|
|
13972
|
+
};
|
|
13973
|
+
}
|
|
13974
|
+
function mergeProtectedArtifact(kind, existing, generated, policy) {
|
|
13975
|
+
if (policy === "overwrite") {
|
|
13976
|
+
if (existing.replace(/\r\n/g, "\n") === generated.replace(/\r\n/g, "\n")) {
|
|
13977
|
+
return {
|
|
13978
|
+
action: "unchanged",
|
|
13979
|
+
content: existing,
|
|
13980
|
+
skipReason: "already-current",
|
|
13981
|
+
added: [],
|
|
13982
|
+
preservedCustom: [],
|
|
13983
|
+
conflicts: [],
|
|
13984
|
+
lintErrors: []
|
|
13985
|
+
};
|
|
13986
|
+
}
|
|
13987
|
+
return {
|
|
13988
|
+
action: "write",
|
|
13989
|
+
content: generated,
|
|
13990
|
+
writeReason: "overwritten",
|
|
13991
|
+
added: ["full overwrite"],
|
|
13992
|
+
preservedCustom: [],
|
|
13993
|
+
conflicts: [],
|
|
13994
|
+
lintErrors: []
|
|
13995
|
+
};
|
|
13996
|
+
}
|
|
13997
|
+
if (policy === "skip") {
|
|
13998
|
+
return {
|
|
13999
|
+
action: "skip",
|
|
14000
|
+
skipReason: "protected-existing-file",
|
|
14001
|
+
added: [],
|
|
14002
|
+
preservedCustom: preservedCustomUnits(existing, generated, kind),
|
|
14003
|
+
conflicts: [],
|
|
14004
|
+
lintErrors: [],
|
|
14005
|
+
detail: "artifactWrite policy is skip"
|
|
14006
|
+
};
|
|
14007
|
+
}
|
|
14008
|
+
return kind === "database" ? mergeDatabaseArtifact(existing, generated) : mergeRegistryArtifact(existing, generated);
|
|
14009
|
+
}
|
|
14010
|
+
function resolveArtifactWritePlan(file, existingContent, policy) {
|
|
14011
|
+
if (existingContent === null) {
|
|
14012
|
+
return {
|
|
14013
|
+
action: "write",
|
|
14014
|
+
content: file.content,
|
|
14015
|
+
writeReason: "created",
|
|
14016
|
+
added: ["created"],
|
|
14017
|
+
preservedCustom: [],
|
|
14018
|
+
conflicts: [],
|
|
14019
|
+
lintErrors: []
|
|
14020
|
+
};
|
|
14021
|
+
}
|
|
14022
|
+
if (file.kind === "model" || file.kind === "schema" || policy === "always") {
|
|
14023
|
+
if (existingContent.replace(/\r\n/g, "\n") === file.content.replace(/\r\n/g, "\n")) {
|
|
14024
|
+
return {
|
|
14025
|
+
action: "unchanged",
|
|
14026
|
+
content: existingContent,
|
|
14027
|
+
skipReason: "already-current",
|
|
14028
|
+
added: [],
|
|
14029
|
+
preservedCustom: [],
|
|
14030
|
+
conflicts: [],
|
|
14031
|
+
lintErrors: []
|
|
14032
|
+
};
|
|
14033
|
+
}
|
|
14034
|
+
return {
|
|
14035
|
+
action: "write",
|
|
14036
|
+
content: file.content,
|
|
14037
|
+
writeReason: existingContent ? "overwritten" : "created",
|
|
14038
|
+
added: ["overwritten"],
|
|
14039
|
+
preservedCustom: [],
|
|
14040
|
+
conflicts: [],
|
|
14041
|
+
lintErrors: []
|
|
14042
|
+
};
|
|
14043
|
+
}
|
|
14044
|
+
return mergeProtectedArtifact(
|
|
14045
|
+
file.kind,
|
|
14046
|
+
existingContent,
|
|
14047
|
+
file.content,
|
|
14048
|
+
policy
|
|
14049
|
+
);
|
|
14050
|
+
}
|
|
14051
|
+
|
|
14052
|
+
// src/generator/pipeline.ts
|
|
13181
14053
|
async function fileExists(path) {
|
|
13182
14054
|
try {
|
|
13183
14055
|
await stat(path);
|
|
@@ -13186,25 +14058,70 @@ async function fileExists(path) {
|
|
|
13186
14058
|
return false;
|
|
13187
14059
|
}
|
|
13188
14060
|
}
|
|
13189
|
-
async function
|
|
14061
|
+
async function readExisting(path) {
|
|
14062
|
+
try {
|
|
14063
|
+
return await readFile(path, "utf8");
|
|
14064
|
+
} catch {
|
|
14065
|
+
return null;
|
|
14066
|
+
}
|
|
14067
|
+
}
|
|
14068
|
+
function policyForArtifact(file, config) {
|
|
14069
|
+
if (file.kind === "model" || file.kind === "schema") {
|
|
14070
|
+
return "always";
|
|
14071
|
+
}
|
|
14072
|
+
if (file.kind === "database") {
|
|
14073
|
+
return config.output.artifactWrite.database;
|
|
14074
|
+
}
|
|
14075
|
+
return config.output.artifactWrite.registry;
|
|
14076
|
+
}
|
|
14077
|
+
async function writeArtifacts(files, cwd, config, dryRun) {
|
|
13190
14078
|
const writtenFiles = [];
|
|
14079
|
+
const writtenDetails = [];
|
|
13191
14080
|
const skippedFiles = [];
|
|
13192
14081
|
for (const file of files) {
|
|
13193
14082
|
const absolutePath = resolve(cwd, file.path);
|
|
13194
|
-
|
|
14083
|
+
const exists = await fileExists(absolutePath);
|
|
14084
|
+
const existingContent = exists ? await readExisting(absolutePath) : null;
|
|
14085
|
+
const policy = policyForArtifact(file, config);
|
|
14086
|
+
const plan = resolveArtifactWritePlan(file, existingContent, policy);
|
|
14087
|
+
if (plan.action === "skip" || plan.action === "unchanged") {
|
|
14088
|
+
skippedFiles.push({
|
|
14089
|
+
kind: file.kind,
|
|
14090
|
+
path: file.path,
|
|
14091
|
+
reason: plan.skipReason ?? "already-current",
|
|
14092
|
+
detail: plan.detail,
|
|
14093
|
+
preservedCustom: plan.preservedCustom.length > 0 ? plan.preservedCustom : void 0,
|
|
14094
|
+
conflicts: plan.conflicts.length > 0 ? plan.conflicts : void 0,
|
|
14095
|
+
lintErrors: plan.lintErrors.length > 0 ? plan.lintErrors : void 0
|
|
14096
|
+
});
|
|
14097
|
+
continue;
|
|
14098
|
+
}
|
|
14099
|
+
if (!plan.content || !plan.writeReason) {
|
|
13195
14100
|
skippedFiles.push({
|
|
13196
14101
|
kind: file.kind,
|
|
13197
14102
|
path: file.path,
|
|
13198
|
-
reason: "
|
|
14103
|
+
reason: "merge-lint-failed",
|
|
14104
|
+
detail: "merge produced no content",
|
|
14105
|
+
lintErrors: plan.lintErrors
|
|
13199
14106
|
});
|
|
13200
14107
|
continue;
|
|
13201
14108
|
}
|
|
13202
|
-
|
|
13203
|
-
|
|
14109
|
+
if (!dryRun) {
|
|
14110
|
+
await mkdir(dirname(absolutePath), { recursive: true });
|
|
14111
|
+
await writeFile(absolutePath, plan.content, "utf8");
|
|
14112
|
+
}
|
|
13204
14113
|
writtenFiles.push(file.path);
|
|
14114
|
+
writtenDetails.push({
|
|
14115
|
+
kind: file.kind,
|
|
14116
|
+
path: file.path,
|
|
14117
|
+
reason: plan.writeReason,
|
|
14118
|
+
added: plan.added.length > 0 ? plan.added : void 0,
|
|
14119
|
+
preservedCustom: plan.preservedCustom.length > 0 ? plan.preservedCustom : void 0
|
|
14120
|
+
});
|
|
13205
14121
|
}
|
|
13206
14122
|
return {
|
|
13207
14123
|
writtenFiles,
|
|
14124
|
+
writtenDetails,
|
|
13208
14125
|
skippedFiles
|
|
13209
14126
|
};
|
|
13210
14127
|
}
|
|
@@ -13220,12 +14137,18 @@ async function runSchemaGenerator(options = {}) {
|
|
|
13220
14137
|
schemas: resolveProviderSchemas(config.provider)
|
|
13221
14138
|
});
|
|
13222
14139
|
const generated = generateArtifactsFromSnapshot(snapshot, config);
|
|
13223
|
-
const writeResult =
|
|
14140
|
+
const writeResult = await writeArtifacts(
|
|
14141
|
+
generated.files,
|
|
14142
|
+
cwd,
|
|
14143
|
+
config,
|
|
14144
|
+
options.dryRun === true
|
|
14145
|
+
);
|
|
13224
14146
|
return {
|
|
13225
14147
|
...generated,
|
|
13226
14148
|
configPath,
|
|
13227
14149
|
config,
|
|
13228
14150
|
writtenFiles: writeResult.writtenFiles,
|
|
14151
|
+
writtenDetails: writeResult.writtenDetails,
|
|
13229
14152
|
skippedFiles: writeResult.skippedFiles
|
|
13230
14153
|
};
|
|
13231
14154
|
}
|