@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/cli/index.cjs
CHANGED
|
@@ -7,6 +7,762 @@ var url = require('url');
|
|
|
7
7
|
|
|
8
8
|
// src/generator/pipeline.ts
|
|
9
9
|
|
|
10
|
+
// src/generator/artifact-merge.ts
|
|
11
|
+
var IMPORT_RE = /^import\s+(?:type\s+)?(?:\{([^}]*)\}|([A-Za-z_$][\w$]*))\s+from\s+(['"])([^'"]+)\3\s*;?\s*$/gm;
|
|
12
|
+
var DEFINE_EXPORT_RE = /export\s+const\s+([A-Za-z_$][\w$]*)\s*=\s*(define(?:Database|Registry))\s*\(\s*\{/g;
|
|
13
|
+
var META_EXPORT_RE = /export\s+const\s+__athena_schema_meta\s*=\s*\{/g;
|
|
14
|
+
var KNOWN_META_KEYS = /* @__PURE__ */ new Set([
|
|
15
|
+
"schemaVersion",
|
|
16
|
+
"generatedAt",
|
|
17
|
+
"database",
|
|
18
|
+
"outputPreset",
|
|
19
|
+
"outputFormat"
|
|
20
|
+
]);
|
|
21
|
+
function detectNewline(source) {
|
|
22
|
+
return source.includes("\r\n") ? "\r\n" : "\n";
|
|
23
|
+
}
|
|
24
|
+
function detectStyle(source) {
|
|
25
|
+
const newline = detectNewline(source);
|
|
26
|
+
const single = (source.match(/'/g) ?? []).length;
|
|
27
|
+
const double = (source.match(/"/g) ?? []).length;
|
|
28
|
+
const quote = double > single ? '"' : "'";
|
|
29
|
+
const importLines = source.split(/\r?\n/).filter((line) => line.trimStart().startsWith("import "));
|
|
30
|
+
const semicolons = importLines.length > 0 ? importLines.filter((line) => line.trimEnd().endsWith(";")).length >= importLines.length / 2 : false;
|
|
31
|
+
const objectLines = source.split(/\r?\n/).map((line) => line.trim()).filter((line) => /^[A-Za-z0-9_'"]+\s*:\s*.+/.test(line));
|
|
32
|
+
const trailingComma = objectLines.length > 0 ? objectLines.filter((line) => line.endsWith(",")).length >= Math.ceil(objectLines.length / 2) : true;
|
|
33
|
+
const indentMatch = source.match(/\n([ \t]+)\S/);
|
|
34
|
+
const indent = indentMatch?.[1] ?? " ";
|
|
35
|
+
return { quote, semicolons, trailingComma, indent, newline };
|
|
36
|
+
}
|
|
37
|
+
function quoteString(value, quote) {
|
|
38
|
+
const escaped = value.replace(/\\/g, "\\\\").replace(new RegExp(quote, "g"), `\\${quote}`);
|
|
39
|
+
return `${quote}${escaped}${quote}`;
|
|
40
|
+
}
|
|
41
|
+
function parseNamedImports(source) {
|
|
42
|
+
const imports = [];
|
|
43
|
+
IMPORT_RE.lastIndex = 0;
|
|
44
|
+
let match;
|
|
45
|
+
while ((match = IMPORT_RE.exec(source)) !== null) {
|
|
46
|
+
const named = match[1];
|
|
47
|
+
const defaultName = match[2];
|
|
48
|
+
const module = match[4];
|
|
49
|
+
const names = named ? named.split(",").map((part) => part.trim()).filter(Boolean).map((part) => {
|
|
50
|
+
const alias = part.split(/\s+as\s+/);
|
|
51
|
+
return (alias[1] ?? alias[0]).trim();
|
|
52
|
+
}) : defaultName ? [defaultName] : [];
|
|
53
|
+
imports.push({
|
|
54
|
+
names,
|
|
55
|
+
module,
|
|
56
|
+
raw: match[0],
|
|
57
|
+
start: match.index,
|
|
58
|
+
end: match.index + match[0].length
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
return imports;
|
|
62
|
+
}
|
|
63
|
+
function findMatchingBrace(source, openIndex) {
|
|
64
|
+
let depth = 0;
|
|
65
|
+
let inSingle = false;
|
|
66
|
+
let inDouble = false;
|
|
67
|
+
let inTemplate = false;
|
|
68
|
+
let escaped = false;
|
|
69
|
+
for (let i = openIndex; i < source.length; i += 1) {
|
|
70
|
+
const ch = source[i];
|
|
71
|
+
if (escaped) {
|
|
72
|
+
escaped = false;
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
if (ch === "\\" && (inSingle || inDouble || inTemplate)) {
|
|
76
|
+
escaped = true;
|
|
77
|
+
continue;
|
|
78
|
+
}
|
|
79
|
+
if (!inDouble && !inTemplate && ch === "'") {
|
|
80
|
+
inSingle = !inSingle;
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
if (!inSingle && !inTemplate && ch === '"') {
|
|
84
|
+
inDouble = !inDouble;
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
if (!inSingle && !inDouble && ch === "`") {
|
|
88
|
+
inTemplate = !inTemplate;
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
if (inSingle || inDouble || inTemplate) {
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
if (ch === "{") {
|
|
95
|
+
depth += 1;
|
|
96
|
+
} else if (ch === "}") {
|
|
97
|
+
depth -= 1;
|
|
98
|
+
if (depth === 0) {
|
|
99
|
+
return i;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
return -1;
|
|
104
|
+
}
|
|
105
|
+
function parseObjectEntries(body) {
|
|
106
|
+
const entries = [];
|
|
107
|
+
const lines = body.split(/\r?\n/);
|
|
108
|
+
for (const line of lines) {
|
|
109
|
+
const trimmed = line.trim();
|
|
110
|
+
if (!trimmed || trimmed.startsWith("//") || trimmed.startsWith("/*")) {
|
|
111
|
+
continue;
|
|
112
|
+
}
|
|
113
|
+
const withoutComma = trimmed.endsWith(",") ? trimmed.slice(0, -1).trimEnd() : trimmed;
|
|
114
|
+
const match = withoutComma.match(/^([A-Za-z_$][\w$]*|['"][^'"]+['"])\s*:\s*(.+)$/);
|
|
115
|
+
if (!match) {
|
|
116
|
+
continue;
|
|
117
|
+
}
|
|
118
|
+
const keyRaw = match[1];
|
|
119
|
+
const key = keyRaw.startsWith("'") || keyRaw.startsWith('"') ? keyRaw.slice(1, -1) : keyRaw;
|
|
120
|
+
entries.push({
|
|
121
|
+
key,
|
|
122
|
+
value: match[2].trim(),
|
|
123
|
+
raw: trimmed
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
return entries;
|
|
127
|
+
}
|
|
128
|
+
function parseDefineBlocks(source) {
|
|
129
|
+
const blocks = [];
|
|
130
|
+
DEFINE_EXPORT_RE.lastIndex = 0;
|
|
131
|
+
let match;
|
|
132
|
+
while ((match = DEFINE_EXPORT_RE.exec(source)) !== null) {
|
|
133
|
+
const exportName = match[1];
|
|
134
|
+
const callName = match[2];
|
|
135
|
+
const openBrace = match.index + match[0].lastIndexOf("{");
|
|
136
|
+
const closeBrace = findMatchingBrace(source, openBrace);
|
|
137
|
+
if (closeBrace < 0) {
|
|
138
|
+
continue;
|
|
139
|
+
}
|
|
140
|
+
const body = source.slice(openBrace + 1, closeBrace);
|
|
141
|
+
const fullEnd = (() => {
|
|
142
|
+
let i = closeBrace + 1;
|
|
143
|
+
while (i < source.length && /\s/.test(source[i])) i += 1;
|
|
144
|
+
if (source[i] === ")") i += 1;
|
|
145
|
+
while (i < source.length && /\s/.test(source[i])) i += 1;
|
|
146
|
+
if (source[i] === ";") i += 1;
|
|
147
|
+
return i;
|
|
148
|
+
})();
|
|
149
|
+
blocks.push({
|
|
150
|
+
kind: callName === "defineDatabase" ? "database" : "registry",
|
|
151
|
+
exportName,
|
|
152
|
+
callName,
|
|
153
|
+
entries: parseObjectEntries(body),
|
|
154
|
+
bodyStart: openBrace + 1,
|
|
155
|
+
bodyEnd: closeBrace,
|
|
156
|
+
fullStart: match.index,
|
|
157
|
+
fullEnd,
|
|
158
|
+
raw: source.slice(match.index, fullEnd)
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
return blocks;
|
|
162
|
+
}
|
|
163
|
+
function parseMetaBlock(source) {
|
|
164
|
+
META_EXPORT_RE.lastIndex = 0;
|
|
165
|
+
const match = META_EXPORT_RE.exec(source);
|
|
166
|
+
if (!match) {
|
|
167
|
+
return void 0;
|
|
168
|
+
}
|
|
169
|
+
const openBrace = match.index + match[0].lastIndexOf("{");
|
|
170
|
+
const closeBrace = findMatchingBrace(source, openBrace);
|
|
171
|
+
if (closeBrace < 0) {
|
|
172
|
+
return void 0;
|
|
173
|
+
}
|
|
174
|
+
let fullEnd = closeBrace + 1;
|
|
175
|
+
const after = source.slice(fullEnd);
|
|
176
|
+
const asConst = after.match(/^\s*as\s+const\s*;?/);
|
|
177
|
+
if (asConst) {
|
|
178
|
+
fullEnd += asConst[0].length;
|
|
179
|
+
} else if (source[fullEnd] === ";") {
|
|
180
|
+
fullEnd += 1;
|
|
181
|
+
}
|
|
182
|
+
return {
|
|
183
|
+
entries: parseObjectEntries(source.slice(openBrace + 1, closeBrace)),
|
|
184
|
+
bodyStart: openBrace + 1,
|
|
185
|
+
bodyEnd: closeBrace,
|
|
186
|
+
fullStart: match.index,
|
|
187
|
+
fullEnd,
|
|
188
|
+
raw: source.slice(match.index, fullEnd)
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
function hasImportBinding(imports, name, module) {
|
|
192
|
+
return imports.some(
|
|
193
|
+
(item) => item.names.includes(name) && (module === void 0)
|
|
194
|
+
);
|
|
195
|
+
}
|
|
196
|
+
function findImportForName(imports, name) {
|
|
197
|
+
return imports.find((item) => item.names.includes(name));
|
|
198
|
+
}
|
|
199
|
+
function normalizeModulePath(modulePath) {
|
|
200
|
+
return modulePath.replace(/\\/g, "/").replace(/^\.\//, "").replace(/\.ts$/, "");
|
|
201
|
+
}
|
|
202
|
+
function formatImport(names, modulePath, style) {
|
|
203
|
+
const body = `import { ${names.join(", ")} } from ${quoteString(modulePath, style.quote)}`;
|
|
204
|
+
return style.semicolons ? `${body};` : body;
|
|
205
|
+
}
|
|
206
|
+
function formatObjectEntry(key, value, style, isLast) {
|
|
207
|
+
const needsQuote = !/^[A-Za-z_$][\w$]*$/.test(key);
|
|
208
|
+
const renderedKey = needsQuote ? quoteString(key, style.quote) : key;
|
|
209
|
+
const comma = !isLast || style.trailingComma ? "," : "";
|
|
210
|
+
return `${style.indent}${renderedKey}: ${value}${comma}`;
|
|
211
|
+
}
|
|
212
|
+
function replaceRange(source, start, end, insertion) {
|
|
213
|
+
return source.slice(0, start) + insertion + source.slice(end);
|
|
214
|
+
}
|
|
215
|
+
function collectDuplicateKeys(entries) {
|
|
216
|
+
const seen = /* @__PURE__ */ new Set();
|
|
217
|
+
const dupes = [];
|
|
218
|
+
for (const entry of entries) {
|
|
219
|
+
if (seen.has(entry.key)) {
|
|
220
|
+
dupes.push(entry.key);
|
|
221
|
+
}
|
|
222
|
+
seen.add(entry.key);
|
|
223
|
+
}
|
|
224
|
+
return dupes;
|
|
225
|
+
}
|
|
226
|
+
function collectDuplicateImportBindings(imports) {
|
|
227
|
+
const seen = /* @__PURE__ */ new Set();
|
|
228
|
+
const dupes = [];
|
|
229
|
+
for (const item of imports) {
|
|
230
|
+
for (const name of item.names) {
|
|
231
|
+
if (seen.has(name)) {
|
|
232
|
+
dupes.push(name);
|
|
233
|
+
}
|
|
234
|
+
seen.add(name);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
return dupes;
|
|
238
|
+
}
|
|
239
|
+
function lintArtifactSource(source, kind) {
|
|
240
|
+
const errors = [];
|
|
241
|
+
const imports = parseNamedImports(source);
|
|
242
|
+
const dupImports = collectDuplicateImportBindings(imports);
|
|
243
|
+
if (dupImports.length > 0) {
|
|
244
|
+
errors.push(`duplicate import bindings: ${dupImports.join(", ")}`);
|
|
245
|
+
}
|
|
246
|
+
const blocks = parseDefineBlocks(source).filter((block2) => block2.kind === kind);
|
|
247
|
+
if (blocks.length === 0) {
|
|
248
|
+
errors.push(`missing export const \u2026 = define${kind === "database" ? "Database" : "Registry"}({\u2026})`);
|
|
249
|
+
return errors;
|
|
250
|
+
}
|
|
251
|
+
if (blocks.length > 1) {
|
|
252
|
+
errors.push(`multiple define${kind === "database" ? "Database" : "Registry"} exports found`);
|
|
253
|
+
}
|
|
254
|
+
const block = blocks[0];
|
|
255
|
+
const dupKeys = collectDuplicateKeys(block.entries);
|
|
256
|
+
if (dupKeys.length > 0) {
|
|
257
|
+
errors.push(`duplicate object keys: ${dupKeys.join(", ")}`);
|
|
258
|
+
}
|
|
259
|
+
for (const entry of block.entries) {
|
|
260
|
+
const valueId = entry.value.match(/^[A-Za-z_$][\w$]*$/)?.[0];
|
|
261
|
+
if (valueId && !hasImportBinding(imports, valueId) && valueId !== block.exportName) {
|
|
262
|
+
if (!source.includes(`const ${valueId}`) && !source.includes(`function ${valueId}`)) {
|
|
263
|
+
errors.push(`value "${valueId}" for key "${entry.key}" is not imported`);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
if (kind === "database" && !hasImportBinding(imports, "defineDatabase")) {
|
|
268
|
+
errors.push("missing defineDatabase import");
|
|
269
|
+
}
|
|
270
|
+
if (kind === "registry" && !hasImportBinding(imports, "defineRegistry")) {
|
|
271
|
+
errors.push("missing defineRegistry import");
|
|
272
|
+
}
|
|
273
|
+
return errors;
|
|
274
|
+
}
|
|
275
|
+
function preservedCustomUnits(existing, generated, kind) {
|
|
276
|
+
const custom = [];
|
|
277
|
+
const existingImports = parseNamedImports(existing);
|
|
278
|
+
const generatedImports = parseNamedImports(generated);
|
|
279
|
+
const generatedModules = new Set(generatedImports.map((item) => normalizeModulePath(item.module)));
|
|
280
|
+
const generatedNames = new Set(generatedImports.flatMap((item) => item.names));
|
|
281
|
+
for (const item of existingImports) {
|
|
282
|
+
const moduleNorm = normalizeModulePath(item.module);
|
|
283
|
+
if (moduleNorm.includes("@xylex-group/athena")) {
|
|
284
|
+
continue;
|
|
285
|
+
}
|
|
286
|
+
const unexpectedNames = item.names.filter((name) => !generatedNames.has(name));
|
|
287
|
+
if (unexpectedNames.length > 0 && !generatedModules.has(moduleNorm)) {
|
|
288
|
+
custom.push(`import { ${unexpectedNames.join(", ")} } from '${item.module}'`);
|
|
289
|
+
} else if (unexpectedNames.length > 0) {
|
|
290
|
+
custom.push(`import binding(s): ${unexpectedNames.join(", ")}`);
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
const existingBlocks = parseDefineBlocks(existing).filter((block) => block.kind === kind);
|
|
294
|
+
const generatedBlocks = parseDefineBlocks(generated).filter((block) => block.kind === kind);
|
|
295
|
+
const generatedKeys = new Set(generatedBlocks[0]?.entries.map((entry) => entry.key) ?? []);
|
|
296
|
+
for (const entry of existingBlocks[0]?.entries ?? []) {
|
|
297
|
+
if (!generatedKeys.has(entry.key)) {
|
|
298
|
+
custom.push(`${kind} entry: ${entry.key}: ${entry.value}`);
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
if (kind === "registry") {
|
|
302
|
+
const existingMeta = parseMetaBlock(existing);
|
|
303
|
+
const generatedMeta = parseMetaBlock(generated);
|
|
304
|
+
const generatedMetaKeys = new Set(generatedMeta?.entries.map((entry) => entry.key) ?? []);
|
|
305
|
+
for (const entry of existingMeta?.entries ?? []) {
|
|
306
|
+
if (!generatedMetaKeys.has(entry.key) && !KNOWN_META_KEYS.has(entry.key)) {
|
|
307
|
+
custom.push(`meta entry: ${entry.key}: ${entry.value}`);
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
const exportConstRe = /^export\s+const\s+([A-Za-z_$][\w$]*)\b/gm;
|
|
312
|
+
const generatedExports = /* @__PURE__ */ new Set();
|
|
313
|
+
let match;
|
|
314
|
+
exportConstRe.lastIndex = 0;
|
|
315
|
+
while ((match = exportConstRe.exec(generated)) !== null) {
|
|
316
|
+
generatedExports.add(match[1]);
|
|
317
|
+
}
|
|
318
|
+
exportConstRe.lastIndex = 0;
|
|
319
|
+
while ((match = exportConstRe.exec(existing)) !== null) {
|
|
320
|
+
if (!generatedExports.has(match[1]) && match[1] !== "__athena_schema_meta") {
|
|
321
|
+
custom.push(`export const ${match[1]}`);
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
return custom;
|
|
325
|
+
}
|
|
326
|
+
function insertImportAfterPackageImports(source, importLine, style) {
|
|
327
|
+
const imports = parseNamedImports(source);
|
|
328
|
+
if (imports.length === 0) {
|
|
329
|
+
return `${importLine}${style.newline}${source}`;
|
|
330
|
+
}
|
|
331
|
+
let anchor = imports[imports.length - 1];
|
|
332
|
+
for (let i = imports.length - 1; i >= 0; i -= 1) {
|
|
333
|
+
if (imports[i].module.startsWith(".")) {
|
|
334
|
+
anchor = imports[i];
|
|
335
|
+
break;
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
const insertAt = anchor.end;
|
|
339
|
+
const before = source.slice(0, insertAt);
|
|
340
|
+
const after = source.slice(insertAt);
|
|
341
|
+
const needsLeadingNl = !before.endsWith("\n");
|
|
342
|
+
const prefix = needsLeadingNl ? style.newline : "";
|
|
343
|
+
return `${before}${prefix}${importLine}${after.startsWith("\n") || after.startsWith("\r\n") ? "" : style.newline}${after}`;
|
|
344
|
+
}
|
|
345
|
+
function rewriteObjectBody(entries, style) {
|
|
346
|
+
if (entries.length === 0) {
|
|
347
|
+
return style.newline;
|
|
348
|
+
}
|
|
349
|
+
const lines = entries.map(
|
|
350
|
+
(entry, index) => formatObjectEntry(entry.key, entry.value, style, index === entries.length - 1)
|
|
351
|
+
);
|
|
352
|
+
return `${style.newline}${lines.join(style.newline)}${style.newline}`;
|
|
353
|
+
}
|
|
354
|
+
function mergeDatabaseArtifact(existing, generated) {
|
|
355
|
+
const style = detectStyle(existing);
|
|
356
|
+
const generatedStyle = detectStyle(generated);
|
|
357
|
+
const effectiveStyle = {
|
|
358
|
+
...style,
|
|
359
|
+
// Prefer existing fingerprint; fall back to generated if existing is empty-ish
|
|
360
|
+
quote: existing.includes('"') || existing.includes("'") ? style.quote : generatedStyle.quote
|
|
361
|
+
};
|
|
362
|
+
const generatedImports = parseNamedImports(generated);
|
|
363
|
+
const existingBlocks = parseDefineBlocks(existing).filter((block) => block.kind === "database");
|
|
364
|
+
const generatedBlocks = parseDefineBlocks(generated).filter((block) => block.kind === "database");
|
|
365
|
+
if (existingBlocks.length === 0 || generatedBlocks.length === 0) {
|
|
366
|
+
return {
|
|
367
|
+
action: "skip",
|
|
368
|
+
skipReason: "merge-unparseable",
|
|
369
|
+
added: [],
|
|
370
|
+
preservedCustom: [],
|
|
371
|
+
conflicts: [],
|
|
372
|
+
lintErrors: [],
|
|
373
|
+
detail: "could not locate defineDatabase({\u2026}) export for merge"
|
|
374
|
+
};
|
|
375
|
+
}
|
|
376
|
+
const generatedBlock = generatedBlocks[0];
|
|
377
|
+
const conflicts = [];
|
|
378
|
+
const added = [];
|
|
379
|
+
let next = existing;
|
|
380
|
+
if (!hasImportBinding(parseNamedImports(next), "defineDatabase")) {
|
|
381
|
+
const pkgImport = generatedImports.find((item) => item.names.includes("defineDatabase"));
|
|
382
|
+
if (pkgImport) {
|
|
383
|
+
const line = formatImport(["defineDatabase"], pkgImport.module, effectiveStyle);
|
|
384
|
+
next = insertImportAfterPackageImports(next, line, effectiveStyle);
|
|
385
|
+
added.push("import defineDatabase");
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
let workingImports = parseNamedImports(next);
|
|
389
|
+
let workingBlocks = parseDefineBlocks(next).filter((block) => block.kind === "database");
|
|
390
|
+
let workingBlock = workingBlocks[0];
|
|
391
|
+
const entryMap = new Map(workingBlock.entries.map((entry) => [entry.key, entry]));
|
|
392
|
+
for (const desired of generatedBlock.entries) {
|
|
393
|
+
const existingEntry = entryMap.get(desired.key);
|
|
394
|
+
if (existingEntry) {
|
|
395
|
+
if (existingEntry.value !== desired.value) {
|
|
396
|
+
conflicts.push(
|
|
397
|
+
`key "${desired.key}" maps to ${existingEntry.value} (existing) vs ${desired.value} (generated)`
|
|
398
|
+
);
|
|
399
|
+
}
|
|
400
|
+
continue;
|
|
401
|
+
}
|
|
402
|
+
const desiredImport = generatedImports.find((item) => item.names.includes(desired.value));
|
|
403
|
+
if (desiredImport) {
|
|
404
|
+
const existingForName = findImportForName(workingImports, desired.value);
|
|
405
|
+
if (existingForName) {
|
|
406
|
+
if (normalizeModulePath(existingForName.module) !== normalizeModulePath(desiredImport.module)) {
|
|
407
|
+
conflicts.push(
|
|
408
|
+
`binding "${desired.value}" imported from '${existingForName.module}' vs '${desiredImport.module}'`
|
|
409
|
+
);
|
|
410
|
+
continue;
|
|
411
|
+
}
|
|
412
|
+
} else {
|
|
413
|
+
const line = formatImport([desired.value], desiredImport.module, effectiveStyle);
|
|
414
|
+
next = insertImportAfterPackageImports(next, line, effectiveStyle);
|
|
415
|
+
added.push(`import ${desired.value}`);
|
|
416
|
+
workingImports = parseNamedImports(next);
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
workingBlocks = parseDefineBlocks(next).filter((block) => block.kind === "database");
|
|
420
|
+
workingBlock = workingBlocks[0];
|
|
421
|
+
const nextEntries = [...workingBlock.entries, { key: desired.key, value: desired.value, raw: "" }];
|
|
422
|
+
const body = rewriteObjectBody(nextEntries, effectiveStyle);
|
|
423
|
+
next = replaceRange(next, workingBlock.bodyStart, workingBlock.bodyEnd, body);
|
|
424
|
+
entryMap.set(desired.key, { key: desired.key, value: desired.value, raw: "" });
|
|
425
|
+
added.push(`database entry: ${desired.key}`);
|
|
426
|
+
}
|
|
427
|
+
if (conflicts.length > 0 && added.length === 0) {
|
|
428
|
+
return {
|
|
429
|
+
action: "skip",
|
|
430
|
+
skipReason: "merge-conflict",
|
|
431
|
+
added: [],
|
|
432
|
+
preservedCustom: preservedCustomUnits(existing, generated, "database"),
|
|
433
|
+
conflicts,
|
|
434
|
+
lintErrors: [],
|
|
435
|
+
detail: conflicts.join("; ")
|
|
436
|
+
};
|
|
437
|
+
}
|
|
438
|
+
const lintErrors = lintArtifactSource(next, "database");
|
|
439
|
+
if (lintErrors.length > 0) {
|
|
440
|
+
return {
|
|
441
|
+
action: "skip",
|
|
442
|
+
skipReason: "merge-lint-failed",
|
|
443
|
+
added,
|
|
444
|
+
preservedCustom: preservedCustomUnits(existing, generated, "database"),
|
|
445
|
+
conflicts,
|
|
446
|
+
lintErrors,
|
|
447
|
+
detail: lintErrors.join("; ")
|
|
448
|
+
};
|
|
449
|
+
}
|
|
450
|
+
const preservedCustom = preservedCustomUnits(next, generated, "database");
|
|
451
|
+
if (next === existing || next.replace(/\r\n/g, "\n") === existing.replace(/\r\n/g, "\n")) {
|
|
452
|
+
return {
|
|
453
|
+
action: "unchanged",
|
|
454
|
+
content: existing,
|
|
455
|
+
skipReason: "already-current",
|
|
456
|
+
added: [],
|
|
457
|
+
preservedCustom,
|
|
458
|
+
conflicts,
|
|
459
|
+
lintErrors: [],
|
|
460
|
+
detail: conflicts.length > 0 ? conflicts.join("; ") : void 0
|
|
461
|
+
};
|
|
462
|
+
}
|
|
463
|
+
return {
|
|
464
|
+
action: "write",
|
|
465
|
+
content: next.endsWith("\n") ? next : `${next}${effectiveStyle.newline}`,
|
|
466
|
+
writeReason: "merged",
|
|
467
|
+
added,
|
|
468
|
+
preservedCustom,
|
|
469
|
+
conflicts,
|
|
470
|
+
lintErrors: []
|
|
471
|
+
};
|
|
472
|
+
}
|
|
473
|
+
function mergeMetaFields(existingMeta, generatedMeta) {
|
|
474
|
+
const added = [];
|
|
475
|
+
if (!generatedMeta) {
|
|
476
|
+
return { entries: existingMeta?.entries ?? [], changed: false, added };
|
|
477
|
+
}
|
|
478
|
+
if (!existingMeta) {
|
|
479
|
+
return {
|
|
480
|
+
entries: generatedMeta.entries,
|
|
481
|
+
changed: true,
|
|
482
|
+
added: generatedMeta.entries.map((entry) => `meta entry: ${entry.key}`)
|
|
483
|
+
};
|
|
484
|
+
}
|
|
485
|
+
const map = new Map(existingMeta.entries.map((entry) => [entry.key, entry]));
|
|
486
|
+
let changed = false;
|
|
487
|
+
for (const desired of generatedMeta.entries) {
|
|
488
|
+
const current = map.get(desired.key);
|
|
489
|
+
if (!current) {
|
|
490
|
+
map.set(desired.key, desired);
|
|
491
|
+
added.push(`meta entry: ${desired.key}`);
|
|
492
|
+
changed = true;
|
|
493
|
+
continue;
|
|
494
|
+
}
|
|
495
|
+
if (KNOWN_META_KEYS.has(desired.key) && current.value !== desired.value) {
|
|
496
|
+
map.set(desired.key, desired);
|
|
497
|
+
added.push(`meta refresh: ${desired.key}`);
|
|
498
|
+
changed = true;
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
const ordered = [];
|
|
502
|
+
const seen = /* @__PURE__ */ new Set();
|
|
503
|
+
for (const entry of existingMeta.entries) {
|
|
504
|
+
const next = map.get(entry.key);
|
|
505
|
+
if (next) {
|
|
506
|
+
ordered.push(next);
|
|
507
|
+
seen.add(entry.key);
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
for (const entry of generatedMeta.entries) {
|
|
511
|
+
if (!seen.has(entry.key)) {
|
|
512
|
+
const next = map.get(entry.key);
|
|
513
|
+
if (next) {
|
|
514
|
+
ordered.push(next);
|
|
515
|
+
seen.add(entry.key);
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
for (const [key, entry] of map) {
|
|
520
|
+
if (!seen.has(key)) {
|
|
521
|
+
ordered.push(entry);
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
return { entries: ordered, changed, added };
|
|
525
|
+
}
|
|
526
|
+
function mergeRegistryArtifact(existing, generated) {
|
|
527
|
+
const style = detectStyle(existing);
|
|
528
|
+
const effectiveStyle = style;
|
|
529
|
+
const generatedImports = parseNamedImports(generated);
|
|
530
|
+
const existingBlocks = parseDefineBlocks(existing).filter((block) => block.kind === "registry");
|
|
531
|
+
const generatedBlocks = parseDefineBlocks(generated).filter((block) => block.kind === "registry");
|
|
532
|
+
if (existingBlocks.length === 0 || generatedBlocks.length === 0) {
|
|
533
|
+
return {
|
|
534
|
+
action: "skip",
|
|
535
|
+
skipReason: "merge-unparseable",
|
|
536
|
+
added: [],
|
|
537
|
+
preservedCustom: [],
|
|
538
|
+
conflicts: [],
|
|
539
|
+
lintErrors: [],
|
|
540
|
+
detail: "could not locate defineRegistry({\u2026}) export for merge"
|
|
541
|
+
};
|
|
542
|
+
}
|
|
543
|
+
const existingBlock = existingBlocks[0];
|
|
544
|
+
const generatedBlock = generatedBlocks[0];
|
|
545
|
+
const conflicts = [];
|
|
546
|
+
const added = [];
|
|
547
|
+
let next = existing;
|
|
548
|
+
if (!hasImportBinding(parseNamedImports(next), "defineRegistry")) {
|
|
549
|
+
const pkgImport = generatedImports.find((item) => item.names.includes("defineRegistry"));
|
|
550
|
+
if (pkgImport) {
|
|
551
|
+
next = insertImportAfterPackageImports(
|
|
552
|
+
next,
|
|
553
|
+
formatImport(["defineRegistry"], pkgImport.module, effectiveStyle),
|
|
554
|
+
effectiveStyle
|
|
555
|
+
);
|
|
556
|
+
added.push("import defineRegistry");
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
const preferredDbValue = existingBlock.entries[0]?.value ?? generatedBlock.entries[0]?.value;
|
|
560
|
+
const generatedDbImport = generatedImports.find((item) => item.names.includes(generatedBlock.entries[0]?.value ?? "")) ?? generatedImports.find((item) => item.module.startsWith("."));
|
|
561
|
+
if (preferredDbValue && generatedDbImport) {
|
|
562
|
+
const existingForName = findImportForName(parseNamedImports(next), preferredDbValue);
|
|
563
|
+
if (!existingForName) {
|
|
564
|
+
const modulePath = generatedDbImport.module;
|
|
565
|
+
const importName = findImportForName(generatedImports, preferredDbValue)?.names[0] ?? generatedBlock.entries[0]?.value ?? preferredDbValue;
|
|
566
|
+
if (!hasImportBinding(parseNamedImports(next), importName)) {
|
|
567
|
+
next = insertImportAfterPackageImports(
|
|
568
|
+
next,
|
|
569
|
+
formatImport([importName], modulePath, effectiveStyle),
|
|
570
|
+
effectiveStyle
|
|
571
|
+
);
|
|
572
|
+
added.push(`import ${importName}`);
|
|
573
|
+
}
|
|
574
|
+
} else if (normalizeModulePath(existingForName.module) !== normalizeModulePath(generatedDbImport.module)) {
|
|
575
|
+
conflicts.push(
|
|
576
|
+
`binding "${preferredDbValue}" imported from '${existingForName.module}' vs '${generatedDbImport.module}'`
|
|
577
|
+
);
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
let workingBlocks = parseDefineBlocks(next).filter((block) => block.kind === "registry");
|
|
581
|
+
let workingBlock = workingBlocks[0];
|
|
582
|
+
const entryMap = new Map(workingBlock.entries.map((entry) => [entry.key, entry]));
|
|
583
|
+
for (const desired of generatedBlock.entries) {
|
|
584
|
+
const existingEntry = entryMap.get(desired.key);
|
|
585
|
+
if (existingEntry) {
|
|
586
|
+
continue;
|
|
587
|
+
}
|
|
588
|
+
const dbImport = parseNamedImports(next).find(
|
|
589
|
+
(item) => item.module.startsWith(".") && item.names.some((name) => name !== "defineRegistry")
|
|
590
|
+
);
|
|
591
|
+
const value = dbImport?.names[0] ?? desired.value;
|
|
592
|
+
const nextEntries = [...workingBlock.entries, { key: desired.key, value, raw: "" }];
|
|
593
|
+
const body = rewriteObjectBody(nextEntries, effectiveStyle);
|
|
594
|
+
next = replaceRange(next, workingBlock.bodyStart, workingBlock.bodyEnd, body);
|
|
595
|
+
entryMap.set(desired.key, { key: desired.key, value, raw: "" });
|
|
596
|
+
added.push(`registry entry: ${desired.key}`);
|
|
597
|
+
workingBlocks = parseDefineBlocks(next).filter((block) => block.kind === "registry");
|
|
598
|
+
workingBlock = workingBlocks[0];
|
|
599
|
+
}
|
|
600
|
+
const existingMeta = parseMetaBlock(next);
|
|
601
|
+
const generatedMeta = parseMetaBlock(generated);
|
|
602
|
+
const structuralAdded = added.length > 0;
|
|
603
|
+
if (generatedMeta) {
|
|
604
|
+
if (!existingMeta) {
|
|
605
|
+
const blocks = parseDefineBlocks(next).filter((block) => block.kind === "registry");
|
|
606
|
+
const insertAt = blocks[0]?.fullStart ?? next.length;
|
|
607
|
+
const metaBody = rewriteObjectBody(generatedMeta.entries, effectiveStyle);
|
|
608
|
+
const metaBlock = `export const __athena_schema_meta = {${metaBody}} as const${effectiveStyle.semicolons ? ";" : ""}${effectiveStyle.newline}${effectiveStyle.newline}`;
|
|
609
|
+
next = replaceRange(next, insertAt, insertAt, metaBlock);
|
|
610
|
+
added.push("__athena_schema_meta");
|
|
611
|
+
} else {
|
|
612
|
+
const desiredEntries = structuralAdded ? generatedMeta.entries : generatedMeta.entries.filter((entry) => {
|
|
613
|
+
return !existingMeta.entries.some((current) => current.key === entry.key);
|
|
614
|
+
});
|
|
615
|
+
if (structuralAdded) {
|
|
616
|
+
const merged = mergeMetaFields(existingMeta, generatedMeta);
|
|
617
|
+
if (merged.changed) {
|
|
618
|
+
const metaNow = parseMetaBlock(next);
|
|
619
|
+
if (metaNow) {
|
|
620
|
+
const body = rewriteObjectBody(merged.entries, effectiveStyle);
|
|
621
|
+
next = replaceRange(next, metaNow.bodyStart, metaNow.bodyEnd, body);
|
|
622
|
+
added.push(...merged.added);
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
} else if (desiredEntries.length > 0) {
|
|
626
|
+
const map = new Map(existingMeta.entries.map((entry) => [entry.key, entry]));
|
|
627
|
+
for (const entry of desiredEntries) {
|
|
628
|
+
map.set(entry.key, entry);
|
|
629
|
+
added.push(`meta entry: ${entry.key}`);
|
|
630
|
+
}
|
|
631
|
+
const ordered = [
|
|
632
|
+
...existingMeta.entries.map((entry) => map.get(entry.key)),
|
|
633
|
+
...desiredEntries.filter((entry) => !existingMeta.entries.some((e) => e.key === entry.key))
|
|
634
|
+
];
|
|
635
|
+
const metaNow = parseMetaBlock(next);
|
|
636
|
+
if (metaNow) {
|
|
637
|
+
const body = rewriteObjectBody(ordered, effectiveStyle);
|
|
638
|
+
next = replaceRange(next, metaNow.bodyStart, metaNow.bodyEnd, body);
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
if (conflicts.length > 0 && added.length === 0) {
|
|
644
|
+
return {
|
|
645
|
+
action: "skip",
|
|
646
|
+
skipReason: "merge-conflict",
|
|
647
|
+
added: [],
|
|
648
|
+
preservedCustom: preservedCustomUnits(existing, generated, "registry"),
|
|
649
|
+
conflicts,
|
|
650
|
+
lintErrors: [],
|
|
651
|
+
detail: conflicts.join("; ")
|
|
652
|
+
};
|
|
653
|
+
}
|
|
654
|
+
const lintErrors = lintArtifactSource(next, "registry");
|
|
655
|
+
if (lintErrors.length > 0) {
|
|
656
|
+
return {
|
|
657
|
+
action: "skip",
|
|
658
|
+
skipReason: "merge-lint-failed",
|
|
659
|
+
added,
|
|
660
|
+
preservedCustom: preservedCustomUnits(existing, generated, "registry"),
|
|
661
|
+
conflicts,
|
|
662
|
+
lintErrors,
|
|
663
|
+
detail: lintErrors.join("; ")
|
|
664
|
+
};
|
|
665
|
+
}
|
|
666
|
+
const preservedCustom = preservedCustomUnits(next, generated, "registry");
|
|
667
|
+
if (next.replace(/\r\n/g, "\n") === existing.replace(/\r\n/g, "\n")) {
|
|
668
|
+
return {
|
|
669
|
+
action: "unchanged",
|
|
670
|
+
content: existing,
|
|
671
|
+
skipReason: "already-current",
|
|
672
|
+
added: [],
|
|
673
|
+
preservedCustom,
|
|
674
|
+
conflicts,
|
|
675
|
+
lintErrors: []
|
|
676
|
+
};
|
|
677
|
+
}
|
|
678
|
+
return {
|
|
679
|
+
action: "write",
|
|
680
|
+
content: next.endsWith("\n") ? next : `${next}${effectiveStyle.newline}`,
|
|
681
|
+
writeReason: "merged",
|
|
682
|
+
added,
|
|
683
|
+
preservedCustom,
|
|
684
|
+
conflicts,
|
|
685
|
+
lintErrors: []
|
|
686
|
+
};
|
|
687
|
+
}
|
|
688
|
+
function mergeProtectedArtifact(kind, existing, generated, policy) {
|
|
689
|
+
if (policy === "overwrite") {
|
|
690
|
+
if (existing.replace(/\r\n/g, "\n") === generated.replace(/\r\n/g, "\n")) {
|
|
691
|
+
return {
|
|
692
|
+
action: "unchanged",
|
|
693
|
+
content: existing,
|
|
694
|
+
skipReason: "already-current",
|
|
695
|
+
added: [],
|
|
696
|
+
preservedCustom: [],
|
|
697
|
+
conflicts: [],
|
|
698
|
+
lintErrors: []
|
|
699
|
+
};
|
|
700
|
+
}
|
|
701
|
+
return {
|
|
702
|
+
action: "write",
|
|
703
|
+
content: generated,
|
|
704
|
+
writeReason: "overwritten",
|
|
705
|
+
added: ["full overwrite"],
|
|
706
|
+
preservedCustom: [],
|
|
707
|
+
conflicts: [],
|
|
708
|
+
lintErrors: []
|
|
709
|
+
};
|
|
710
|
+
}
|
|
711
|
+
if (policy === "skip") {
|
|
712
|
+
return {
|
|
713
|
+
action: "skip",
|
|
714
|
+
skipReason: "protected-existing-file",
|
|
715
|
+
added: [],
|
|
716
|
+
preservedCustom: preservedCustomUnits(existing, generated, kind),
|
|
717
|
+
conflicts: [],
|
|
718
|
+
lintErrors: [],
|
|
719
|
+
detail: "artifactWrite policy is skip"
|
|
720
|
+
};
|
|
721
|
+
}
|
|
722
|
+
return kind === "database" ? mergeDatabaseArtifact(existing, generated) : mergeRegistryArtifact(existing, generated);
|
|
723
|
+
}
|
|
724
|
+
function resolveArtifactWritePlan(file, existingContent, policy) {
|
|
725
|
+
if (existingContent === null) {
|
|
726
|
+
return {
|
|
727
|
+
action: "write",
|
|
728
|
+
content: file.content,
|
|
729
|
+
writeReason: "created",
|
|
730
|
+
added: ["created"],
|
|
731
|
+
preservedCustom: [],
|
|
732
|
+
conflicts: [],
|
|
733
|
+
lintErrors: []
|
|
734
|
+
};
|
|
735
|
+
}
|
|
736
|
+
if (file.kind === "model" || file.kind === "schema" || policy === "always") {
|
|
737
|
+
if (existingContent.replace(/\r\n/g, "\n") === file.content.replace(/\r\n/g, "\n")) {
|
|
738
|
+
return {
|
|
739
|
+
action: "unchanged",
|
|
740
|
+
content: existingContent,
|
|
741
|
+
skipReason: "already-current",
|
|
742
|
+
added: [],
|
|
743
|
+
preservedCustom: [],
|
|
744
|
+
conflicts: [],
|
|
745
|
+
lintErrors: []
|
|
746
|
+
};
|
|
747
|
+
}
|
|
748
|
+
return {
|
|
749
|
+
action: "write",
|
|
750
|
+
content: file.content,
|
|
751
|
+
writeReason: existingContent ? "overwritten" : "created",
|
|
752
|
+
added: ["overwritten"],
|
|
753
|
+
preservedCustom: [],
|
|
754
|
+
conflicts: [],
|
|
755
|
+
lintErrors: []
|
|
756
|
+
};
|
|
757
|
+
}
|
|
758
|
+
return mergeProtectedArtifact(
|
|
759
|
+
file.kind,
|
|
760
|
+
existingContent,
|
|
761
|
+
file.content,
|
|
762
|
+
policy
|
|
763
|
+
);
|
|
764
|
+
}
|
|
765
|
+
|
|
10
766
|
// src/utils/slugify.ts
|
|
11
767
|
function slugify(input) {
|
|
12
768
|
return input.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 64);
|
|
@@ -783,6 +1539,12 @@ var ATHENA_DIRECT_TARGETS = {
|
|
|
783
1539
|
};
|
|
784
1540
|
var DEFAULT_OUTPUT_FORMAT = "table-builder";
|
|
785
1541
|
var DEFAULT_OUTPUT_PRESET = "athena-direct";
|
|
1542
|
+
var DEFAULT_ARTIFACT_WRITE_POLICY = "merge";
|
|
1543
|
+
var ARTIFACT_WRITE_POLICIES = /* @__PURE__ */ new Set([
|
|
1544
|
+
"merge",
|
|
1545
|
+
"skip",
|
|
1546
|
+
"overwrite"
|
|
1547
|
+
]);
|
|
786
1548
|
var DEFAULT_NAMING = {
|
|
787
1549
|
modelType: "pascal",
|
|
788
1550
|
modelConst: "camel",
|
|
@@ -1062,6 +1824,23 @@ function normalizeFilterConfig(input) {
|
|
|
1062
1824
|
excludeTables: normalizeTableSelection(input?.excludeTables)
|
|
1063
1825
|
};
|
|
1064
1826
|
}
|
|
1827
|
+
function normalizeArtifactWritePolicy(value, fieldName) {
|
|
1828
|
+
if (value === void 0 || value === null || value === "") {
|
|
1829
|
+
return DEFAULT_ARTIFACT_WRITE_POLICY;
|
|
1830
|
+
}
|
|
1831
|
+
if (typeof value === "string" && ARTIFACT_WRITE_POLICIES.has(value)) {
|
|
1832
|
+
return value;
|
|
1833
|
+
}
|
|
1834
|
+
throw new Error(
|
|
1835
|
+
`Invalid output.artifactWrite.${fieldName}: expected one of merge | skip | overwrite, received ${JSON.stringify(value)}.`
|
|
1836
|
+
);
|
|
1837
|
+
}
|
|
1838
|
+
function normalizeArtifactWriteConfig(input) {
|
|
1839
|
+
return {
|
|
1840
|
+
database: normalizeArtifactWritePolicy(input?.database, "database"),
|
|
1841
|
+
registry: normalizeArtifactWritePolicy(input?.registry, "registry")
|
|
1842
|
+
};
|
|
1843
|
+
}
|
|
1065
1844
|
function normalizeOutputConfig(output) {
|
|
1066
1845
|
const preset = output?.preset ?? DEFAULT_OUTPUT_PRESET;
|
|
1067
1846
|
return {
|
|
@@ -1073,7 +1852,8 @@ function normalizeOutputConfig(output) {
|
|
|
1073
1852
|
},
|
|
1074
1853
|
placeholderMap: {
|
|
1075
1854
|
...output?.placeholderMap ?? {}
|
|
1076
|
-
}
|
|
1855
|
+
},
|
|
1856
|
+
artifactWrite: normalizeArtifactWriteConfig(output?.artifactWrite)
|
|
1077
1857
|
};
|
|
1078
1858
|
}
|
|
1079
1859
|
function normalizeProviderConfig(provider) {
|
|
@@ -3222,7 +4002,7 @@ function buildRpcDebugSql(payload) {
|
|
|
3222
4002
|
}
|
|
3223
4003
|
|
|
3224
4004
|
// src/gateway/url.ts
|
|
3225
|
-
var ATHENA_DEFAULT_BASE_URL = "https://athena-
|
|
4005
|
+
var ATHENA_DEFAULT_BASE_URL = "https://mirror2.athena-cluster.com";
|
|
3226
4006
|
function describeReceivedValue(value) {
|
|
3227
4007
|
if (value === void 0) return "undefined";
|
|
3228
4008
|
if (value === null) return "null";
|
|
@@ -3245,14 +4025,14 @@ function normalizeAthenaGatewayBaseUrl(input, options = {}) {
|
|
|
3245
4025
|
if (candidate === void 0 || candidate === null) {
|
|
3246
4026
|
throw invalidBaseUrlError(
|
|
3247
4027
|
`${label} must be a non-empty absolute http(s) URL. Received ${describeReceivedValue(input)}.`,
|
|
3248
|
-
'Set ATHENA_URL in the explicit env object (or pass createClient({ url, key })) to a full URL such as "https://
|
|
4028
|
+
'Set ATHENA_URL in the explicit env object (or pass createClient({ url, key })) to a full URL such as "https://mirror2.athena-cluster.com".'
|
|
3249
4029
|
);
|
|
3250
4030
|
}
|
|
3251
4031
|
const trimmed = candidate.trim();
|
|
3252
4032
|
if (!trimmed) {
|
|
3253
4033
|
throw invalidBaseUrlError(
|
|
3254
4034
|
`${label} must be a non-empty absolute http(s) URL. Received ${describeReceivedValue(candidate)}.`,
|
|
3255
|
-
'Set ATHENA_URL in the explicit env object (or pass createClient({ url, key })) to a full URL such as "https://
|
|
4035
|
+
'Set ATHENA_URL in the explicit env object (or pass createClient({ url, key })) to a full URL such as "https://mirror2.athena-cluster.com".'
|
|
3256
4036
|
);
|
|
3257
4037
|
}
|
|
3258
4038
|
let parsed;
|
|
@@ -3261,13 +4041,13 @@ function normalizeAthenaGatewayBaseUrl(input, options = {}) {
|
|
|
3261
4041
|
} catch {
|
|
3262
4042
|
throw invalidBaseUrlError(
|
|
3263
4043
|
`${label} must be a valid absolute http(s) URL. Received ${describeReceivedValue(candidate)}.`,
|
|
3264
|
-
'Use a full URL including the protocol, for example "https://
|
|
4044
|
+
'Use a full URL including the protocol, for example "https://mirror2.athena-cluster.com".'
|
|
3265
4045
|
);
|
|
3266
4046
|
}
|
|
3267
4047
|
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
|
|
3268
4048
|
throw invalidBaseUrlError(
|
|
3269
4049
|
`${label} must use http or https. Received ${JSON.stringify(trimmed)}.`,
|
|
3270
|
-
'Use an Athena gateway URL such as "https://
|
|
4050
|
+
'Use an Athena gateway URL such as "https://mirror2.athena-cluster.com".'
|
|
3271
4051
|
);
|
|
3272
4052
|
}
|
|
3273
4053
|
if (parsed.search || parsed.hash) {
|
|
@@ -3290,7 +4070,7 @@ function buildAthenaGatewayUrl(baseUrl, path) {
|
|
|
3290
4070
|
|
|
3291
4071
|
// package.json
|
|
3292
4072
|
var package_default = {
|
|
3293
|
-
version: "3.0.
|
|
4073
|
+
version: "3.0.3"
|
|
3294
4074
|
};
|
|
3295
4075
|
|
|
3296
4076
|
// src/sdk-version.ts
|
|
@@ -3700,7 +4480,7 @@ function createAthenaRequest(config, resolveContext) {
|
|
|
3700
4480
|
}
|
|
3701
4481
|
|
|
3702
4482
|
// src/gateway/client.ts
|
|
3703
|
-
var DEFAULT_CLIENT = "
|
|
4483
|
+
var DEFAULT_CLIENT = "DEFAULT_CLIENT";
|
|
3704
4484
|
var SDK_NAME2 = "xylex-group/athena";
|
|
3705
4485
|
var SDK_HEADER_VALUE = buildSdkHeaderValue(SDK_NAME2);
|
|
3706
4486
|
function parseResponseBody(rawText, contentType) {
|
|
@@ -10528,6 +11308,25 @@ function createBillingModule(config) {
|
|
|
10528
11308
|
createCheckout(body, options) {
|
|
10529
11309
|
return call("POST", "/billing/v1/checkouts", body, options);
|
|
10530
11310
|
},
|
|
11311
|
+
listProducts(input, options) {
|
|
11312
|
+
return call(
|
|
11313
|
+
"GET",
|
|
11314
|
+
appendQuery3("/billing/v1/products", connectionQuery(input)),
|
|
11315
|
+
void 0,
|
|
11316
|
+
options
|
|
11317
|
+
);
|
|
11318
|
+
},
|
|
11319
|
+
listPrices(input, options) {
|
|
11320
|
+
return call(
|
|
11321
|
+
"GET",
|
|
11322
|
+
appendQuery3("/billing/v1/prices", {
|
|
11323
|
+
...connectionQuery(input),
|
|
11324
|
+
...input.productId ? { productId: input.productId } : {}
|
|
11325
|
+
}),
|
|
11326
|
+
void 0,
|
|
11327
|
+
options
|
|
11328
|
+
);
|
|
11329
|
+
},
|
|
10531
11330
|
listCustomers(input, options) {
|
|
10532
11331
|
return call(
|
|
10533
11332
|
"GET",
|
|
@@ -10674,10 +11473,7 @@ function createBillingModule(config) {
|
|
|
10674
11473
|
getRefund(id, input, options) {
|
|
10675
11474
|
return call(
|
|
10676
11475
|
"GET",
|
|
10677
|
-
appendQuery3(withPathParam2("/billing/v1/refunds/{id}", "id", id),
|
|
10678
|
-
...connectionQuery(input),
|
|
10679
|
-
...input.paymentId ? { paymentId: input.paymentId } : {}
|
|
10680
|
-
}),
|
|
11476
|
+
appendQuery3(withPathParam2("/billing/v1/refunds/{id}", "id", id), connectionQuery(input)),
|
|
10681
11477
|
void 0,
|
|
10682
11478
|
options
|
|
10683
11479
|
);
|
|
@@ -10685,10 +11481,7 @@ function createBillingModule(config) {
|
|
|
10685
11481
|
cancelRefund(id, input, options) {
|
|
10686
11482
|
return call(
|
|
10687
11483
|
"POST",
|
|
10688
|
-
appendQuery3(withPathParam2("/billing/v1/refunds/{id}/cancel", "id", id),
|
|
10689
|
-
...connectionQuery(input),
|
|
10690
|
-
...input.paymentId ? { paymentId: input.paymentId } : {}
|
|
10691
|
-
}),
|
|
11484
|
+
appendQuery3(withPathParam2("/billing/v1/refunds/{id}/cancel", "id", id), connectionQuery(input)),
|
|
10692
11485
|
{},
|
|
10693
11486
|
options
|
|
10694
11487
|
);
|
|
@@ -10707,10 +11500,10 @@ function createBillingModule(config) {
|
|
|
10707
11500
|
getSubscription(id, input, options) {
|
|
10708
11501
|
return call(
|
|
10709
11502
|
"GET",
|
|
10710
|
-
appendQuery3(
|
|
10711
|
-
|
|
10712
|
-
|
|
10713
|
-
|
|
11503
|
+
appendQuery3(
|
|
11504
|
+
withPathParam2("/billing/v1/subscriptions/{id}", "id", id),
|
|
11505
|
+
connectionQuery(input)
|
|
11506
|
+
),
|
|
10714
11507
|
void 0,
|
|
10715
11508
|
options
|
|
10716
11509
|
);
|
|
@@ -10726,10 +11519,10 @@ function createBillingModule(config) {
|
|
|
10726
11519
|
cancelSubscription(id, input, options) {
|
|
10727
11520
|
return call(
|
|
10728
11521
|
"POST",
|
|
10729
|
-
appendQuery3(
|
|
10730
|
-
|
|
10731
|
-
|
|
10732
|
-
|
|
11522
|
+
appendQuery3(
|
|
11523
|
+
withPathParam2("/billing/v1/subscriptions/{id}/cancel", "id", id),
|
|
11524
|
+
connectionQuery(input)
|
|
11525
|
+
),
|
|
10733
11526
|
{},
|
|
10734
11527
|
options
|
|
10735
11528
|
);
|
|
@@ -10753,6 +11546,57 @@ function createBillingModule(config) {
|
|
|
10753
11546
|
options
|
|
10754
11547
|
);
|
|
10755
11548
|
},
|
|
11549
|
+
listWebhooks(input, options) {
|
|
11550
|
+
return call(
|
|
11551
|
+
"GET",
|
|
11552
|
+
appendQuery3("/billing/v1/webhooks", connectionQuery(input)),
|
|
11553
|
+
void 0,
|
|
11554
|
+
options
|
|
11555
|
+
);
|
|
11556
|
+
},
|
|
11557
|
+
createWebhook(input, body, options) {
|
|
11558
|
+
return call(
|
|
11559
|
+
"POST",
|
|
11560
|
+
appendQuery3("/billing/v1/webhooks", connectionQuery(input)),
|
|
11561
|
+
body,
|
|
11562
|
+
options
|
|
11563
|
+
);
|
|
11564
|
+
},
|
|
11565
|
+
getWebhook(id, input, options) {
|
|
11566
|
+
return call(
|
|
11567
|
+
"GET",
|
|
11568
|
+
appendQuery3(withPathParam2("/billing/v1/webhooks/{id}", "id", id), connectionQuery(input)),
|
|
11569
|
+
void 0,
|
|
11570
|
+
options
|
|
11571
|
+
);
|
|
11572
|
+
},
|
|
11573
|
+
updateWebhook(id, input, body, options) {
|
|
11574
|
+
return call(
|
|
11575
|
+
"PATCH",
|
|
11576
|
+
appendQuery3(withPathParam2("/billing/v1/webhooks/{id}", "id", id), connectionQuery(input)),
|
|
11577
|
+
body,
|
|
11578
|
+
options
|
|
11579
|
+
);
|
|
11580
|
+
},
|
|
11581
|
+
deleteWebhook(id, input, options) {
|
|
11582
|
+
return call(
|
|
11583
|
+
"DELETE",
|
|
11584
|
+
appendQuery3(withPathParam2("/billing/v1/webhooks/{id}", "id", id), connectionQuery(input)),
|
|
11585
|
+
void 0,
|
|
11586
|
+
options
|
|
11587
|
+
);
|
|
11588
|
+
},
|
|
11589
|
+
testWebhook(id, input, options) {
|
|
11590
|
+
return call(
|
|
11591
|
+
"POST",
|
|
11592
|
+
appendQuery3(
|
|
11593
|
+
withPathParam2("/billing/v1/webhooks/{id}/test", "id", id),
|
|
11594
|
+
connectionQuery(input)
|
|
11595
|
+
),
|
|
11596
|
+
{},
|
|
11597
|
+
options
|
|
11598
|
+
);
|
|
11599
|
+
},
|
|
10756
11600
|
listConnections(clientName, options) {
|
|
10757
11601
|
return call(
|
|
10758
11602
|
"GET",
|
|
@@ -10930,6 +11774,31 @@ function createBillingModule(config) {
|
|
|
10930
11774
|
};
|
|
10931
11775
|
}
|
|
10932
11776
|
|
|
11777
|
+
// src/config/errors.ts
|
|
11778
|
+
var AthenaConfigurationError = class extends Error {
|
|
11779
|
+
code;
|
|
11780
|
+
service;
|
|
11781
|
+
constructor(code, message, service) {
|
|
11782
|
+
super(message);
|
|
11783
|
+
this.name = "AthenaConfigurationError";
|
|
11784
|
+
this.code = code;
|
|
11785
|
+
this.service = service;
|
|
11786
|
+
}
|
|
11787
|
+
};
|
|
11788
|
+
|
|
11789
|
+
// src/context/merge.ts
|
|
11790
|
+
function mergeAthenaRequestContexts(base, override) {
|
|
11791
|
+
if (!base && !override) return void 0;
|
|
11792
|
+
return {
|
|
11793
|
+
...base,
|
|
11794
|
+
...override,
|
|
11795
|
+
headers: base?.headers || override?.headers ? {
|
|
11796
|
+
...base?.headers ?? {},
|
|
11797
|
+
...override?.headers ?? {}
|
|
11798
|
+
} : void 0
|
|
11799
|
+
};
|
|
11800
|
+
}
|
|
11801
|
+
|
|
10933
11802
|
// src/v3-client.ts
|
|
10934
11803
|
var ENV_URL_KEYS = ["ATHENA_URL", "NEXT_PUBLIC_ATHENA_URL"];
|
|
10935
11804
|
var ENV_DB_URL_KEYS = ["ATHENA_DB_URL", "ATHENA_GATEWAY_URL", "NEXT_PUBLIC_ATHENA_DB_API_URL"];
|
|
@@ -10940,15 +11809,6 @@ var ENV_STORAGE_URL_KEYS = ["ATHENA_STORAGE_URL", "NEXT_PUBLIC_ATHENA_STORAGE_UR
|
|
|
10940
11809
|
var ENV_KEY_KEYS = ["ATHENA_API_KEY", "NEXT_PUBLIC_ATHENA_API_KEY", "ATHENA_GATEWAY_API_KEY", "X_API_KEY"];
|
|
10941
11810
|
var ENV_CLIENT_KEYS = ["ATHENA_CLIENT", "NEXT_PUBLIC_ATHENA_CLIENT"];
|
|
10942
11811
|
var MISSING_DB_SENTINEL = "https://athena.invalid/db";
|
|
10943
|
-
var AthenaConfigurationError = class extends Error {
|
|
10944
|
-
code = "ATHENA_SERVICE_NOT_CONFIGURED";
|
|
10945
|
-
service;
|
|
10946
|
-
constructor(service, message = `Athena ${service} is not configured.`) {
|
|
10947
|
-
super(message);
|
|
10948
|
-
this.name = "AthenaConfigurationError";
|
|
10949
|
-
this.service = service;
|
|
10950
|
-
}
|
|
10951
|
-
};
|
|
10952
11812
|
function readFirstEnv(env, keys) {
|
|
10953
11813
|
for (const key of keys) {
|
|
10954
11814
|
const value = env?.[key]?.trim();
|
|
@@ -10989,11 +11849,18 @@ function resolveCore(config) {
|
|
|
10989
11849
|
chatWs: normalizeOptional(config.chat?.wsUrl) ?? (explicitRootWinsOverEnvServices && root ? toWebSocketUrl(root) : void 0) ?? readFirstEnv(env, ENV_CHAT_WS_URL_KEYS) ?? (root ? toWebSocketUrl(root) : void 0)
|
|
10990
11850
|
};
|
|
10991
11851
|
if (!urls.db && !urls.auth && !urls.chat && !urls.storage && !urls.billing) {
|
|
10992
|
-
throw new AthenaConfigurationError(
|
|
11852
|
+
throw new AthenaConfigurationError(
|
|
11853
|
+
"ATHENA_NO_SERVICE_CONFIGURED",
|
|
11854
|
+
"Athena requires a unified URL or at least one configured service URL.",
|
|
11855
|
+
"db"
|
|
11856
|
+
);
|
|
10993
11857
|
}
|
|
10994
11858
|
const key = normalizeOptional(config.key) ?? readFirstEnv(env, ENV_KEY_KEYS);
|
|
10995
11859
|
if (!key) {
|
|
10996
|
-
throw new
|
|
11860
|
+
throw new AthenaConfigurationError(
|
|
11861
|
+
"ATHENA_API_KEY_REQUIRED",
|
|
11862
|
+
"Athena API key is required. Pass key or provide it through the explicit env object."
|
|
11863
|
+
);
|
|
10997
11864
|
}
|
|
10998
11865
|
const base = {
|
|
10999
11866
|
config,
|
|
@@ -11006,18 +11873,10 @@ function resolveCore(config) {
|
|
|
11006
11873
|
internalCore: createInternalClientCore(createInternalConfig(base))
|
|
11007
11874
|
};
|
|
11008
11875
|
}
|
|
11009
|
-
function mergeContexts(base, override) {
|
|
11010
|
-
if (!base && !override) return void 0;
|
|
11011
|
-
return {
|
|
11012
|
-
...base,
|
|
11013
|
-
...override,
|
|
11014
|
-
headers: base?.headers || override?.headers ? { ...base?.headers ?? {}, ...override?.headers ?? {} } : void 0
|
|
11015
|
-
};
|
|
11016
|
-
}
|
|
11017
11876
|
async function resolveConfiguredContext(core, viewContext) {
|
|
11018
11877
|
const configured = core.config.context;
|
|
11019
11878
|
const base = typeof configured === "function" ? await configured() : configured;
|
|
11020
|
-
return
|
|
11879
|
+
return mergeAthenaRequestContexts(base, viewContext);
|
|
11021
11880
|
}
|
|
11022
11881
|
function createInternalConfig(core) {
|
|
11023
11882
|
const { config, urls } = core;
|
|
@@ -11050,7 +11909,13 @@ function createInternalConfig(core) {
|
|
|
11050
11909
|
};
|
|
11051
11910
|
}
|
|
11052
11911
|
function serviceGuard(urls, service) {
|
|
11053
|
-
if (!urls[service])
|
|
11912
|
+
if (!urls[service]) {
|
|
11913
|
+
throw new AthenaConfigurationError(
|
|
11914
|
+
"ATHENA_SERVICE_NOT_CONFIGURED",
|
|
11915
|
+
`Athena ${service} is not configured.`,
|
|
11916
|
+
service
|
|
11917
|
+
);
|
|
11918
|
+
}
|
|
11054
11919
|
}
|
|
11055
11920
|
function createUnavailableNamespace(service, urls, path = []) {
|
|
11056
11921
|
return new Proxy(() => void 0, {
|
|
@@ -11109,7 +11974,7 @@ function createClientView(core, viewContext) {
|
|
|
11109
11974
|
return resolved.verifyConnection(options);
|
|
11110
11975
|
},
|
|
11111
11976
|
withContext(context) {
|
|
11112
|
-
return createClientView(core,
|
|
11977
|
+
return createClientView(core, mergeAthenaRequestContexts(viewContext, context));
|
|
11113
11978
|
}
|
|
11114
11979
|
};
|
|
11115
11980
|
return Object.freeze(client);
|
|
@@ -11660,9 +12525,6 @@ function resolveGeneratorProvider(providerConfig, experimentalFlags) {
|
|
|
11660
12525
|
}
|
|
11661
12526
|
|
|
11662
12527
|
// src/generator/pipeline.ts
|
|
11663
|
-
function canOverwriteArtifact(file) {
|
|
11664
|
-
return file.kind === "model" || file.kind === "schema";
|
|
11665
|
-
}
|
|
11666
12528
|
async function fileExists(path) {
|
|
11667
12529
|
try {
|
|
11668
12530
|
await promises.stat(path);
|
|
@@ -11671,25 +12533,70 @@ async function fileExists(path) {
|
|
|
11671
12533
|
return false;
|
|
11672
12534
|
}
|
|
11673
12535
|
}
|
|
11674
|
-
async function
|
|
12536
|
+
async function readExisting(path) {
|
|
12537
|
+
try {
|
|
12538
|
+
return await promises.readFile(path, "utf8");
|
|
12539
|
+
} catch {
|
|
12540
|
+
return null;
|
|
12541
|
+
}
|
|
12542
|
+
}
|
|
12543
|
+
function policyForArtifact(file, config) {
|
|
12544
|
+
if (file.kind === "model" || file.kind === "schema") {
|
|
12545
|
+
return "always";
|
|
12546
|
+
}
|
|
12547
|
+
if (file.kind === "database") {
|
|
12548
|
+
return config.output.artifactWrite.database;
|
|
12549
|
+
}
|
|
12550
|
+
return config.output.artifactWrite.registry;
|
|
12551
|
+
}
|
|
12552
|
+
async function writeArtifacts(files, cwd, config, dryRun) {
|
|
11675
12553
|
const writtenFiles = [];
|
|
12554
|
+
const writtenDetails = [];
|
|
11676
12555
|
const skippedFiles = [];
|
|
11677
12556
|
for (const file of files) {
|
|
11678
12557
|
const absolutePath = path.resolve(cwd, file.path);
|
|
11679
|
-
|
|
12558
|
+
const exists = await fileExists(absolutePath);
|
|
12559
|
+
const existingContent = exists ? await readExisting(absolutePath) : null;
|
|
12560
|
+
const policy = policyForArtifact(file, config);
|
|
12561
|
+
const plan = resolveArtifactWritePlan(file, existingContent, policy);
|
|
12562
|
+
if (plan.action === "skip" || plan.action === "unchanged") {
|
|
12563
|
+
skippedFiles.push({
|
|
12564
|
+
kind: file.kind,
|
|
12565
|
+
path: file.path,
|
|
12566
|
+
reason: plan.skipReason ?? "already-current",
|
|
12567
|
+
detail: plan.detail,
|
|
12568
|
+
preservedCustom: plan.preservedCustom.length > 0 ? plan.preservedCustom : void 0,
|
|
12569
|
+
conflicts: plan.conflicts.length > 0 ? plan.conflicts : void 0,
|
|
12570
|
+
lintErrors: plan.lintErrors.length > 0 ? plan.lintErrors : void 0
|
|
12571
|
+
});
|
|
12572
|
+
continue;
|
|
12573
|
+
}
|
|
12574
|
+
if (!plan.content || !plan.writeReason) {
|
|
11680
12575
|
skippedFiles.push({
|
|
11681
12576
|
kind: file.kind,
|
|
11682
12577
|
path: file.path,
|
|
11683
|
-
reason: "
|
|
12578
|
+
reason: "merge-lint-failed",
|
|
12579
|
+
detail: "merge produced no content",
|
|
12580
|
+
lintErrors: plan.lintErrors
|
|
11684
12581
|
});
|
|
11685
12582
|
continue;
|
|
11686
12583
|
}
|
|
11687
|
-
|
|
11688
|
-
|
|
12584
|
+
if (!dryRun) {
|
|
12585
|
+
await promises.mkdir(path.dirname(absolutePath), { recursive: true });
|
|
12586
|
+
await promises.writeFile(absolutePath, plan.content, "utf8");
|
|
12587
|
+
}
|
|
11689
12588
|
writtenFiles.push(file.path);
|
|
12589
|
+
writtenDetails.push({
|
|
12590
|
+
kind: file.kind,
|
|
12591
|
+
path: file.path,
|
|
12592
|
+
reason: plan.writeReason,
|
|
12593
|
+
added: plan.added.length > 0 ? plan.added : void 0,
|
|
12594
|
+
preservedCustom: plan.preservedCustom.length > 0 ? plan.preservedCustom : void 0
|
|
12595
|
+
});
|
|
11690
12596
|
}
|
|
11691
12597
|
return {
|
|
11692
12598
|
writtenFiles,
|
|
12599
|
+
writtenDetails,
|
|
11693
12600
|
skippedFiles
|
|
11694
12601
|
};
|
|
11695
12602
|
}
|
|
@@ -11705,12 +12612,18 @@ async function runSchemaGenerator(options = {}) {
|
|
|
11705
12612
|
schemas: resolveProviderSchemas(config.provider)
|
|
11706
12613
|
});
|
|
11707
12614
|
const generated = generateArtifactsFromSnapshot(snapshot, config);
|
|
11708
|
-
const writeResult =
|
|
12615
|
+
const writeResult = await writeArtifacts(
|
|
12616
|
+
generated.files,
|
|
12617
|
+
cwd,
|
|
12618
|
+
config,
|
|
12619
|
+
options.dryRun === true
|
|
12620
|
+
);
|
|
11709
12621
|
return {
|
|
11710
12622
|
...generated,
|
|
11711
12623
|
configPath,
|
|
11712
12624
|
config,
|
|
11713
12625
|
writtenFiles: writeResult.writtenFiles,
|
|
12626
|
+
writtenDetails: writeResult.writtenDetails,
|
|
11714
12627
|
skippedFiles: writeResult.skippedFiles
|
|
11715
12628
|
};
|
|
11716
12629
|
}
|
|
@@ -12000,10 +12913,52 @@ function logCliError(error, errorLog = console.error) {
|
|
|
12000
12913
|
}
|
|
12001
12914
|
function formatSkippedArtifactLine(artifact) {
|
|
12002
12915
|
if (artifact.reason === "protected-existing-file") {
|
|
12003
|
-
return ` [skip] ${artifact.path} (existing ${artifact.kind} artifacts are protected from overwrite;
|
|
12916
|
+
return ` [skip] ${artifact.path} (existing ${artifact.kind} artifacts are protected from overwrite; set output.artifactWrite.${artifact.kind}="merge"|"overwrite" or delete/retarget the file)`;
|
|
12917
|
+
}
|
|
12918
|
+
if (artifact.reason === "already-current") {
|
|
12919
|
+
const custom = artifact.preservedCustom && artifact.preservedCustom.length > 0 ? `; preserves ${artifact.preservedCustom.length} non-generated unit(s)` : "";
|
|
12920
|
+
return ` [ok] ${artifact.path} (already current${custom})`;
|
|
12921
|
+
}
|
|
12922
|
+
if (artifact.reason === "merge-conflict") {
|
|
12923
|
+
return ` [skip] ${artifact.path} (merge conflict: ${artifact.detail ?? "see conflicts"}; file left unchanged)`;
|
|
12924
|
+
}
|
|
12925
|
+
if (artifact.reason === "merge-lint-failed") {
|
|
12926
|
+
return ` [skip] ${artifact.path} (merge lint failed: ${artifact.detail ?? "invalid merged TypeScript"}; file left unchanged)`;
|
|
12927
|
+
}
|
|
12928
|
+
if (artifact.reason === "merge-unparseable") {
|
|
12929
|
+
return ` [skip] ${artifact.path} (existing ${artifact.kind} artifact is not mergeable; delete, retarget, or set output.artifactWrite.${artifact.kind}="overwrite")`;
|
|
12004
12930
|
}
|
|
12005
12931
|
return ` [skip] ${artifact.path}`;
|
|
12006
12932
|
}
|
|
12933
|
+
function formatWrittenArtifactLine(artifact) {
|
|
12934
|
+
if (artifact.reason === "merged") {
|
|
12935
|
+
const added = artifact.added && artifact.added.length > 0 ? ` +${artifact.added.length}: ${artifact.added.slice(0, 4).join(", ")}${artifact.added.length > 4 ? "\u2026" : ""}` : "";
|
|
12936
|
+
const custom = artifact.preservedCustom && artifact.preservedCustom.length > 0 ? `; preserves ${artifact.preservedCustom.length} non-generated unit(s)` : "";
|
|
12937
|
+
return ` [merge] ${artifact.path}${added}${custom}`;
|
|
12938
|
+
}
|
|
12939
|
+
if (artifact.reason === "overwritten") {
|
|
12940
|
+
return ` [write] ${artifact.path} (overwritten)`;
|
|
12941
|
+
}
|
|
12942
|
+
return ` - ${artifact.path}`;
|
|
12943
|
+
}
|
|
12944
|
+
function formatCustomPreserveWarnings(result) {
|
|
12945
|
+
const lines = [];
|
|
12946
|
+
for (const artifact of result.writtenDetails) {
|
|
12947
|
+
if (artifact.preservedCustom && artifact.preservedCustom.length > 0) {
|
|
12948
|
+
lines.push(
|
|
12949
|
+
` [warn] ${artifact.path} preserves non-generated unit(s): ${artifact.preservedCustom.slice(0, 3).join("; ")}${artifact.preservedCustom.length > 3 ? "\u2026" : ""}`
|
|
12950
|
+
);
|
|
12951
|
+
}
|
|
12952
|
+
}
|
|
12953
|
+
for (const artifact of result.skippedFiles) {
|
|
12954
|
+
if (artifact.reason === "already-current" && artifact.preservedCustom && artifact.preservedCustom.length > 0) {
|
|
12955
|
+
lines.push(
|
|
12956
|
+
` [warn] ${artifact.path} preserves non-generated unit(s): ${artifact.preservedCustom.slice(0, 3).join("; ")}${artifact.preservedCustom.length > 3 ? "\u2026" : ""}`
|
|
12957
|
+
);
|
|
12958
|
+
}
|
|
12959
|
+
}
|
|
12960
|
+
return lines;
|
|
12961
|
+
}
|
|
12007
12962
|
async function runCLI(argv, runtime = {}) {
|
|
12008
12963
|
const log = runtime.log ?? console.log;
|
|
12009
12964
|
const errorLog = runtime.errorLog ?? console.error;
|
|
@@ -12045,18 +13000,44 @@ async function runCLI(argv, runtime = {}) {
|
|
|
12045
13000
|
for (const file of result.files) {
|
|
12046
13001
|
log(` - ${file.path}`);
|
|
12047
13002
|
}
|
|
13003
|
+
if (result.writtenDetails?.length || result.skippedFiles?.length) {
|
|
13004
|
+
for (const artifact of result.writtenDetails ?? []) {
|
|
13005
|
+
if (artifact.kind === "database" || artifact.kind === "registry") {
|
|
13006
|
+
log(formatWrittenArtifactLine(artifact));
|
|
13007
|
+
}
|
|
13008
|
+
}
|
|
13009
|
+
for (const artifact of result.skippedFiles ?? []) {
|
|
13010
|
+
if (artifact.kind === "database" || artifact.kind === "registry") {
|
|
13011
|
+
log(formatSkippedArtifactLine(artifact));
|
|
13012
|
+
}
|
|
13013
|
+
}
|
|
13014
|
+
for (const line of formatCustomPreserveWarnings(result)) {
|
|
13015
|
+
log(line);
|
|
13016
|
+
}
|
|
13017
|
+
}
|
|
12048
13018
|
return;
|
|
12049
13019
|
}
|
|
12050
13020
|
log(`Generated ${result.writtenFiles.length} files from ${result.configPath}`);
|
|
12051
13021
|
for (const line of formatGeneratorModeLines(result)) {
|
|
12052
13022
|
log(line);
|
|
12053
13023
|
}
|
|
13024
|
+
const detailByPath = new Map(
|
|
13025
|
+
(result.writtenDetails ?? []).map((detail) => [detail.path, detail])
|
|
13026
|
+
);
|
|
12054
13027
|
for (const filePath of result.writtenFiles) {
|
|
12055
|
-
|
|
13028
|
+
const detail = detailByPath.get(filePath);
|
|
13029
|
+
if (detail && (detail.reason === "merged" || detail.reason === "overwritten")) {
|
|
13030
|
+
log(formatWrittenArtifactLine(detail));
|
|
13031
|
+
} else {
|
|
13032
|
+
log(` - ${filePath}`);
|
|
13033
|
+
}
|
|
12056
13034
|
}
|
|
12057
13035
|
for (const artifact of result.skippedFiles) {
|
|
12058
13036
|
log(formatSkippedArtifactLine(artifact));
|
|
12059
13037
|
}
|
|
13038
|
+
for (const line of formatCustomPreserveWarnings(result)) {
|
|
13039
|
+
log(line);
|
|
13040
|
+
}
|
|
12060
13041
|
}
|
|
12061
13042
|
|
|
12062
13043
|
exports.logCliError = logCliError;
|