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