typed-csv 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +190 -0
- package/dist/csv-loader/esbuild.d.mts +45 -0
- package/dist/csv-loader/esbuild.d.ts +45 -0
- package/dist/csv-loader/esbuild.js +2020 -0
- package/dist/csv-loader/esbuild.mjs +1985 -0
- package/dist/csv-loader/loader.d.mts +154 -0
- package/dist/csv-loader/loader.d.ts +154 -0
- package/dist/csv-loader/loader.js +1736 -0
- package/dist/csv-loader/loader.mjs +1701 -0
- package/dist/csv-loader/rollup.d.mts +60 -0
- package/dist/csv-loader/rollup.d.ts +60 -0
- package/dist/csv-loader/rollup.js +2006 -0
- package/dist/csv-loader/rollup.mjs +1971 -0
- package/dist/csv-loader/webpack.d.mts +42 -0
- package/dist/csv-loader/webpack.d.ts +42 -0
- package/dist/csv-loader/webpack.js +1979 -0
- package/dist/csv-loader/webpack.mjs +1948 -0
- package/dist/index.d.mts +65 -0
- package/dist/index.d.ts +65 -0
- package/dist/index.js +877 -0
- package/dist/index.mjs +845 -0
- package/package.json +76 -0
|
@@ -0,0 +1,2020 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/csv-loader/esbuild.ts
|
|
31
|
+
var esbuild_exports = {};
|
|
32
|
+
__export(esbuild_exports, {
|
|
33
|
+
csvLoader: () => csvLoader,
|
|
34
|
+
default: () => esbuild_default
|
|
35
|
+
});
|
|
36
|
+
module.exports = __toCommonJS(esbuild_exports);
|
|
37
|
+
var path4 = __toESM(require("path"));
|
|
38
|
+
var fs2 = __toESM(require("fs"));
|
|
39
|
+
|
|
40
|
+
// src/csv-loader/module-gen.ts
|
|
41
|
+
var path3 = __toESM(require("path"));
|
|
42
|
+
|
|
43
|
+
// src/csv-loader/loader.ts
|
|
44
|
+
var import_sync = require("csv-parse/sync");
|
|
45
|
+
|
|
46
|
+
// src/parser.ts
|
|
47
|
+
var ParseError = class extends Error {
|
|
48
|
+
constructor(message, position, schema, value) {
|
|
49
|
+
let fullMessage = message;
|
|
50
|
+
if (position !== void 0) {
|
|
51
|
+
fullMessage += ` at position ${position}`;
|
|
52
|
+
}
|
|
53
|
+
if (schema !== void 0) {
|
|
54
|
+
fullMessage += `. Schema: ${schema}`;
|
|
55
|
+
}
|
|
56
|
+
if (value !== void 0) {
|
|
57
|
+
fullMessage += `. Value: ${value}`;
|
|
58
|
+
}
|
|
59
|
+
super(fullMessage);
|
|
60
|
+
this.position = position;
|
|
61
|
+
this.schema = schema;
|
|
62
|
+
this.value = value;
|
|
63
|
+
this.name = "ParseError";
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
var Parser = class {
|
|
67
|
+
constructor(input) {
|
|
68
|
+
this.pos = 0;
|
|
69
|
+
this.input = input;
|
|
70
|
+
}
|
|
71
|
+
peek() {
|
|
72
|
+
return this.input[this.pos] || "";
|
|
73
|
+
}
|
|
74
|
+
consume() {
|
|
75
|
+
return this.input[this.pos++] || "";
|
|
76
|
+
}
|
|
77
|
+
skipWhitespace() {
|
|
78
|
+
while (this.pos < this.input.length && /\s/.test(this.input[this.pos])) {
|
|
79
|
+
this.pos++;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
match(str) {
|
|
83
|
+
return this.input.slice(this.pos, this.pos + str.length) === str;
|
|
84
|
+
}
|
|
85
|
+
consumeStr(str) {
|
|
86
|
+
if (this.match(str)) {
|
|
87
|
+
this.pos += str.length;
|
|
88
|
+
return true;
|
|
89
|
+
}
|
|
90
|
+
return false;
|
|
91
|
+
}
|
|
92
|
+
getPosition() {
|
|
93
|
+
return this.pos;
|
|
94
|
+
}
|
|
95
|
+
getInputLength() {
|
|
96
|
+
return this.input.length;
|
|
97
|
+
}
|
|
98
|
+
parseSchema() {
|
|
99
|
+
this.skipWhitespace();
|
|
100
|
+
let schema = this.parseSchemaInternal();
|
|
101
|
+
this.skipWhitespace();
|
|
102
|
+
if (this.consumeStr("[")) {
|
|
103
|
+
this.skipWhitespace();
|
|
104
|
+
if (!this.consumeStr("]")) {
|
|
105
|
+
throw new ParseError("Expected ]", this.pos);
|
|
106
|
+
}
|
|
107
|
+
schema = { type: "array", element: schema };
|
|
108
|
+
this.skipWhitespace();
|
|
109
|
+
}
|
|
110
|
+
if (this.consumeStr("|")) {
|
|
111
|
+
const members = [schema];
|
|
112
|
+
while (true) {
|
|
113
|
+
this.skipWhitespace();
|
|
114
|
+
const member = this.parseSchemaInternal();
|
|
115
|
+
members.push(member);
|
|
116
|
+
this.skipWhitespace();
|
|
117
|
+
if (!this.consumeStr("|")) {
|
|
118
|
+
break;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
return {
|
|
122
|
+
type: "union",
|
|
123
|
+
members
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
return schema;
|
|
127
|
+
}
|
|
128
|
+
parseSchemaInternal() {
|
|
129
|
+
this.skipWhitespace();
|
|
130
|
+
if (this.consumeStr("(")) {
|
|
131
|
+
this.skipWhitespace();
|
|
132
|
+
const schema = this.parseSchema();
|
|
133
|
+
this.skipWhitespace();
|
|
134
|
+
if (!this.consumeStr(")")) {
|
|
135
|
+
throw new ParseError("Expected )", this.pos);
|
|
136
|
+
}
|
|
137
|
+
this.skipWhitespace();
|
|
138
|
+
if (this.consumeStr("[")) {
|
|
139
|
+
this.skipWhitespace();
|
|
140
|
+
if (!this.consumeStr("]")) {
|
|
141
|
+
throw new ParseError("Expected ]", this.pos);
|
|
142
|
+
}
|
|
143
|
+
return { type: "array", element: schema };
|
|
144
|
+
}
|
|
145
|
+
return schema;
|
|
146
|
+
}
|
|
147
|
+
if (this.peek() === '"' || this.peek() === "'") {
|
|
148
|
+
return this.parseStringLiteralSchema();
|
|
149
|
+
}
|
|
150
|
+
if (this.consumeStr("~")) {
|
|
151
|
+
return this.parseReverseReferenceSchema();
|
|
152
|
+
}
|
|
153
|
+
if (this.consumeStr("@")) {
|
|
154
|
+
return this.parseReferenceSchema();
|
|
155
|
+
}
|
|
156
|
+
if (this.consumeStr("string")) {
|
|
157
|
+
if (this.consumeStr("[")) {
|
|
158
|
+
this.skipWhitespace();
|
|
159
|
+
if (!this.consumeStr("]")) {
|
|
160
|
+
throw new ParseError("Expected ]", this.pos);
|
|
161
|
+
}
|
|
162
|
+
return { type: "array", element: { type: "string" } };
|
|
163
|
+
}
|
|
164
|
+
return { type: "string" };
|
|
165
|
+
}
|
|
166
|
+
if (this.consumeStr("number")) {
|
|
167
|
+
if (this.consumeStr("[")) {
|
|
168
|
+
this.skipWhitespace();
|
|
169
|
+
if (!this.consumeStr("]")) {
|
|
170
|
+
throw new ParseError("Expected ]", this.pos);
|
|
171
|
+
}
|
|
172
|
+
return { type: "array", element: { type: "number" } };
|
|
173
|
+
}
|
|
174
|
+
return { type: "number" };
|
|
175
|
+
}
|
|
176
|
+
if (this.consumeStr("int")) {
|
|
177
|
+
if (this.consumeStr("[")) {
|
|
178
|
+
this.skipWhitespace();
|
|
179
|
+
if (!this.consumeStr("]")) {
|
|
180
|
+
throw new ParseError("Expected ]", this.pos);
|
|
181
|
+
}
|
|
182
|
+
return { type: "array", element: { type: "int" } };
|
|
183
|
+
}
|
|
184
|
+
return { type: "int" };
|
|
185
|
+
}
|
|
186
|
+
if (this.consumeStr("float")) {
|
|
187
|
+
if (this.consumeStr("[")) {
|
|
188
|
+
this.skipWhitespace();
|
|
189
|
+
if (!this.consumeStr("]")) {
|
|
190
|
+
throw new ParseError("Expected ]", this.pos);
|
|
191
|
+
}
|
|
192
|
+
return { type: "array", element: { type: "float" } };
|
|
193
|
+
}
|
|
194
|
+
return { type: "float" };
|
|
195
|
+
}
|
|
196
|
+
if (this.consumeStr("boolean")) {
|
|
197
|
+
if (this.consumeStr("[")) {
|
|
198
|
+
this.skipWhitespace();
|
|
199
|
+
if (!this.consumeStr("]")) {
|
|
200
|
+
throw new ParseError("Expected ]", this.pos);
|
|
201
|
+
}
|
|
202
|
+
return { type: "array", element: { type: "boolean" } };
|
|
203
|
+
}
|
|
204
|
+
return { type: "boolean" };
|
|
205
|
+
}
|
|
206
|
+
if (this.consumeStr("[")) {
|
|
207
|
+
const elements = [];
|
|
208
|
+
this.skipWhitespace();
|
|
209
|
+
if (this.peek() === "]") {
|
|
210
|
+
this.consume();
|
|
211
|
+
throw new ParseError("Empty array/tuple not allowed", this.pos);
|
|
212
|
+
}
|
|
213
|
+
elements.push(this.parseNamedSchema());
|
|
214
|
+
this.skipWhitespace();
|
|
215
|
+
if (this.consumeStr(";")) {
|
|
216
|
+
const remainingElements = [];
|
|
217
|
+
while (true) {
|
|
218
|
+
this.skipWhitespace();
|
|
219
|
+
remainingElements.push(this.parseNamedSchema());
|
|
220
|
+
this.skipWhitespace();
|
|
221
|
+
if (!this.consumeStr(";")) {
|
|
222
|
+
break;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
elements.push(...remainingElements);
|
|
226
|
+
}
|
|
227
|
+
this.skipWhitespace();
|
|
228
|
+
if (!this.consumeStr("]")) {
|
|
229
|
+
throw new ParseError("Expected ]", this.pos);
|
|
230
|
+
}
|
|
231
|
+
if (this.consumeStr("[")) {
|
|
232
|
+
this.skipWhitespace();
|
|
233
|
+
if (!this.consumeStr("]")) {
|
|
234
|
+
throw new ParseError("Expected ]", this.pos);
|
|
235
|
+
}
|
|
236
|
+
if (elements.length === 1 && !elements[0].name) {
|
|
237
|
+
return { type: "array", element: elements[0].schema };
|
|
238
|
+
}
|
|
239
|
+
return { type: "array", element: { type: "tuple", elements } };
|
|
240
|
+
}
|
|
241
|
+
if (elements.length === 1 && !elements[0].name) {
|
|
242
|
+
return { type: "array", element: elements[0].schema };
|
|
243
|
+
}
|
|
244
|
+
return { type: "tuple", elements };
|
|
245
|
+
}
|
|
246
|
+
throw new ParseError(
|
|
247
|
+
`Unknown type: ${this.peek() || "end of input"}`,
|
|
248
|
+
this.pos
|
|
249
|
+
);
|
|
250
|
+
}
|
|
251
|
+
parseStringLiteralSchema() {
|
|
252
|
+
const value = this.parseStringLiteral();
|
|
253
|
+
return {
|
|
254
|
+
type: "stringLiteral",
|
|
255
|
+
value
|
|
256
|
+
};
|
|
257
|
+
}
|
|
258
|
+
parseStringLiteral() {
|
|
259
|
+
const quote = this.peek();
|
|
260
|
+
if (quote !== '"' && quote !== "'") {
|
|
261
|
+
throw new ParseError("Expected string literal with quotes", this.pos);
|
|
262
|
+
}
|
|
263
|
+
this.consume();
|
|
264
|
+
let value = "";
|
|
265
|
+
while (this.pos < this.input.length) {
|
|
266
|
+
const char = this.peek();
|
|
267
|
+
if (char === "\\") {
|
|
268
|
+
this.consume();
|
|
269
|
+
const nextChar = this.consume();
|
|
270
|
+
if (nextChar === '"' || nextChar === "'" || nextChar === "\\" || nextChar === "|" || nextChar === ";" || nextChar === "(" || nextChar === ")") {
|
|
271
|
+
value += nextChar;
|
|
272
|
+
} else {
|
|
273
|
+
value += "\\" + nextChar;
|
|
274
|
+
}
|
|
275
|
+
} else if (char === quote) {
|
|
276
|
+
this.consume();
|
|
277
|
+
return value;
|
|
278
|
+
} else {
|
|
279
|
+
value += this.consume();
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
throw new ParseError("Unterminated string literal", this.pos);
|
|
283
|
+
}
|
|
284
|
+
parseNamedSchema() {
|
|
285
|
+
this.skipWhitespace();
|
|
286
|
+
const startpos = this.pos;
|
|
287
|
+
let identifier = "";
|
|
288
|
+
while (this.pos < this.input.length && /[a-zA-Z0-9\-_]/.test(this.peek())) {
|
|
289
|
+
identifier += this.consume();
|
|
290
|
+
}
|
|
291
|
+
if (identifier.length === 0) {
|
|
292
|
+
const schema = this.parseSchema();
|
|
293
|
+
return { schema };
|
|
294
|
+
}
|
|
295
|
+
this.skipWhitespace();
|
|
296
|
+
if (this.consumeStr(":")) {
|
|
297
|
+
this.skipWhitespace();
|
|
298
|
+
const name = identifier;
|
|
299
|
+
const schema = this.parseSchema();
|
|
300
|
+
return { name, schema };
|
|
301
|
+
} else {
|
|
302
|
+
this.pos = startpos;
|
|
303
|
+
const schema = this.parseSchema();
|
|
304
|
+
return { schema };
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
parseReferenceSchema() {
|
|
308
|
+
let tableName = "";
|
|
309
|
+
while (this.pos < this.input.length && /[a-zA-Z0-9\-_]/.test(this.peek())) {
|
|
310
|
+
tableName += this.consume();
|
|
311
|
+
}
|
|
312
|
+
if (tableName.length === 0) {
|
|
313
|
+
throw new ParseError("Expected table name after @", this.pos);
|
|
314
|
+
}
|
|
315
|
+
this.skipWhitespace();
|
|
316
|
+
if (this.consumeStr("[]")) {
|
|
317
|
+
this.skipWhitespace();
|
|
318
|
+
const isOptional2 = this.consumeStr("?");
|
|
319
|
+
return {
|
|
320
|
+
type: "reference",
|
|
321
|
+
tableName,
|
|
322
|
+
isArray: true,
|
|
323
|
+
isOptional: isOptional2
|
|
324
|
+
};
|
|
325
|
+
}
|
|
326
|
+
const isOptional = this.consumeStr("?");
|
|
327
|
+
return {
|
|
328
|
+
type: "reference",
|
|
329
|
+
tableName,
|
|
330
|
+
isArray: false,
|
|
331
|
+
isOptional
|
|
332
|
+
};
|
|
333
|
+
}
|
|
334
|
+
parseReverseReferenceSchema() {
|
|
335
|
+
let tableName = "";
|
|
336
|
+
while (this.pos < this.input.length && /[a-zA-Z0-9\-_]/.test(this.peek())) {
|
|
337
|
+
tableName += this.consume();
|
|
338
|
+
}
|
|
339
|
+
if (tableName.length === 0) {
|
|
340
|
+
throw new ParseError("Expected table name after ~", this.pos);
|
|
341
|
+
}
|
|
342
|
+
this.skipWhitespace();
|
|
343
|
+
if (!this.consumeStr("(")) {
|
|
344
|
+
throw new ParseError(
|
|
345
|
+
"Expected ( after reverse reference table name",
|
|
346
|
+
this.pos
|
|
347
|
+
);
|
|
348
|
+
}
|
|
349
|
+
this.skipWhitespace();
|
|
350
|
+
let foreignKey = "";
|
|
351
|
+
while (this.pos < this.input.length && /[a-zA-Z0-9\-_]/.test(this.peek())) {
|
|
352
|
+
foreignKey += this.consume();
|
|
353
|
+
}
|
|
354
|
+
if (foreignKey.length === 0) {
|
|
355
|
+
throw new ParseError("Expected foreign key name inside ()", this.pos);
|
|
356
|
+
}
|
|
357
|
+
this.skipWhitespace();
|
|
358
|
+
if (!this.consumeStr(")")) {
|
|
359
|
+
throw new ParseError("Expected ) after foreign key name", this.pos);
|
|
360
|
+
}
|
|
361
|
+
this.skipWhitespace();
|
|
362
|
+
const isOptional = this.consumeStr("?");
|
|
363
|
+
return {
|
|
364
|
+
type: "reverseReference",
|
|
365
|
+
tableName,
|
|
366
|
+
foreignKey,
|
|
367
|
+
isOptional
|
|
368
|
+
};
|
|
369
|
+
}
|
|
370
|
+
};
|
|
371
|
+
function parseSchema(schemaString) {
|
|
372
|
+
const parser = new Parser(schemaString.trim());
|
|
373
|
+
const schema = parser.parseSchema();
|
|
374
|
+
if (parser.getPosition() < parser.getInputLength()) {
|
|
375
|
+
throw new ParseError("Unexpected input after schema", parser.getPosition());
|
|
376
|
+
}
|
|
377
|
+
return schema;
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
// src/type-utils.ts
|
|
381
|
+
function schemaToTypeString(schema, resourceNames) {
|
|
382
|
+
switch (schema.type) {
|
|
383
|
+
case "string":
|
|
384
|
+
return "string";
|
|
385
|
+
case "number":
|
|
386
|
+
case "int":
|
|
387
|
+
case "float":
|
|
388
|
+
return "number";
|
|
389
|
+
case "boolean":
|
|
390
|
+
return "boolean";
|
|
391
|
+
case "stringLiteral":
|
|
392
|
+
return `"${schema.value}"`;
|
|
393
|
+
case "union":
|
|
394
|
+
return schema.members.map((m) => schemaToTypeString(m, resourceNames)).join(" | ");
|
|
395
|
+
case "reference": {
|
|
396
|
+
const typeName = resourceNames?.get(schema.tableName) || schema.tableName.charAt(0).toUpperCase() + schema.tableName.slice(1);
|
|
397
|
+
const baseType = schema.isArray ? `${typeName}[]` : typeName;
|
|
398
|
+
return schema.isOptional ? `${baseType} | null` : baseType;
|
|
399
|
+
}
|
|
400
|
+
case "reverseReference": {
|
|
401
|
+
const typeName = resourceNames?.get(schema.tableName) || schema.tableName.charAt(0).toUpperCase() + schema.tableName.slice(1);
|
|
402
|
+
const baseType = `${typeName}[]`;
|
|
403
|
+
return schema.isOptional ? `${baseType} | null` : baseType;
|
|
404
|
+
}
|
|
405
|
+
case "array":
|
|
406
|
+
if (schema.element.type === "tuple") {
|
|
407
|
+
const tupleElements2 = schema.element.elements.map((el) => {
|
|
408
|
+
const typeStr = schemaToTypeString(el.schema, resourceNames);
|
|
409
|
+
return el.name ? `${el.name}: ${typeStr}` : typeStr;
|
|
410
|
+
});
|
|
411
|
+
return `[${tupleElements2.join(", ")}][]`;
|
|
412
|
+
}
|
|
413
|
+
const elementType = schemaToTypeString(schema.element, resourceNames);
|
|
414
|
+
if (schema.element.type === "union") {
|
|
415
|
+
return `(${elementType})[]`;
|
|
416
|
+
}
|
|
417
|
+
return `${elementType}[]`;
|
|
418
|
+
case "tuple":
|
|
419
|
+
const tupleElements = schema.elements.map((el) => {
|
|
420
|
+
const typeStr = schemaToTypeString(el.schema, resourceNames);
|
|
421
|
+
return el.name ? `${el.name}: ${typeStr}` : typeStr;
|
|
422
|
+
});
|
|
423
|
+
return `[${tupleElements.join(", ")}]`;
|
|
424
|
+
default:
|
|
425
|
+
return "unknown";
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
function createValidator(schema) {
|
|
429
|
+
return function validate(value) {
|
|
430
|
+
switch (schema.type) {
|
|
431
|
+
case "string":
|
|
432
|
+
return typeof value === "string";
|
|
433
|
+
case "number":
|
|
434
|
+
return typeof value === "number" && !isNaN(value);
|
|
435
|
+
case "int":
|
|
436
|
+
return typeof value === "number" && !isNaN(value) && Number.isInteger(value);
|
|
437
|
+
case "float":
|
|
438
|
+
return typeof value === "number" && !isNaN(value);
|
|
439
|
+
case "boolean":
|
|
440
|
+
return typeof value === "boolean";
|
|
441
|
+
case "stringLiteral":
|
|
442
|
+
return typeof value === "string" && value === schema.value;
|
|
443
|
+
case "union":
|
|
444
|
+
return schema.members.some((member) => createValidator(member)(value));
|
|
445
|
+
case "tuple":
|
|
446
|
+
if (!Array.isArray(value)) return false;
|
|
447
|
+
if (value.length !== schema.elements.length) return false;
|
|
448
|
+
return schema.elements.every(
|
|
449
|
+
(elementSchema, index) => createValidator(elementSchema.schema)(value[index])
|
|
450
|
+
);
|
|
451
|
+
case "array":
|
|
452
|
+
if (!Array.isArray(value)) return false;
|
|
453
|
+
return value.every((item) => createValidator(schema.element)(item));
|
|
454
|
+
case "reference":
|
|
455
|
+
if (schema.isOptional && value === null) return true;
|
|
456
|
+
if (schema.isArray) {
|
|
457
|
+
return Array.isArray(value) && value.every((id) => typeof id === "string");
|
|
458
|
+
}
|
|
459
|
+
return typeof value === "string" || Array.isArray(value) && value.every((id) => typeof id === "string");
|
|
460
|
+
case "reverseReference":
|
|
461
|
+
if (schema.isOptional && value === null) return true;
|
|
462
|
+
return Array.isArray(value);
|
|
463
|
+
default:
|
|
464
|
+
return false;
|
|
465
|
+
}
|
|
466
|
+
};
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
// src/value-parser.ts
|
|
470
|
+
var ValueParser = class {
|
|
471
|
+
constructor(input, schemaString) {
|
|
472
|
+
this.pos = 0;
|
|
473
|
+
this.input = input;
|
|
474
|
+
this.schemaString = schemaString;
|
|
475
|
+
}
|
|
476
|
+
peek() {
|
|
477
|
+
return this.input[this.pos] || "";
|
|
478
|
+
}
|
|
479
|
+
consume() {
|
|
480
|
+
return this.input[this.pos++] || "";
|
|
481
|
+
}
|
|
482
|
+
skipWhitespace() {
|
|
483
|
+
while (this.pos < this.input.length && /\s/.test(this.input[this.pos])) {
|
|
484
|
+
this.pos++;
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
consumeStr(str) {
|
|
488
|
+
if (this.input.slice(this.pos, this.pos + str.length) === str) {
|
|
489
|
+
this.pos += str.length;
|
|
490
|
+
return true;
|
|
491
|
+
}
|
|
492
|
+
return false;
|
|
493
|
+
}
|
|
494
|
+
parseValue(schema, allowOmitBrackets = false) {
|
|
495
|
+
this.skipWhitespace();
|
|
496
|
+
switch (schema.type) {
|
|
497
|
+
case "string":
|
|
498
|
+
return this.parseStringValue();
|
|
499
|
+
case "number":
|
|
500
|
+
return this.parseNumberValue();
|
|
501
|
+
case "int":
|
|
502
|
+
return this.parseIntValue();
|
|
503
|
+
case "float":
|
|
504
|
+
return this.parseFloatValue();
|
|
505
|
+
case "boolean":
|
|
506
|
+
return this.parseBooleanValue();
|
|
507
|
+
case "stringLiteral":
|
|
508
|
+
return this.parseStringLiteralValue(schema);
|
|
509
|
+
case "union":
|
|
510
|
+
return this.parseUnionValue(schema);
|
|
511
|
+
case "tuple":
|
|
512
|
+
return this.parseTupleValue(schema, allowOmitBrackets);
|
|
513
|
+
case "array":
|
|
514
|
+
return this.parseArrayValue(schema, allowOmitBrackets);
|
|
515
|
+
case "reference":
|
|
516
|
+
return this.parseReferenceValue(schema);
|
|
517
|
+
case "reverseReference":
|
|
518
|
+
return null;
|
|
519
|
+
default:
|
|
520
|
+
throw new ParseError(
|
|
521
|
+
`Unknown schema type: ${schema.type}`,
|
|
522
|
+
this.pos,
|
|
523
|
+
this.schemaString,
|
|
524
|
+
this.input
|
|
525
|
+
);
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
parseStringValue() {
|
|
529
|
+
let result = "";
|
|
530
|
+
while (this.pos < this.input.length) {
|
|
531
|
+
const char = this.peek();
|
|
532
|
+
if (char === "\\") {
|
|
533
|
+
this.consume();
|
|
534
|
+
const nextChar = this.consume();
|
|
535
|
+
if (nextChar === ";" || nextChar === "[" || nextChar === "]" || nextChar === "\\") {
|
|
536
|
+
result += nextChar;
|
|
537
|
+
} else {
|
|
538
|
+
result += "\\" + nextChar;
|
|
539
|
+
}
|
|
540
|
+
} else if (char === ";" || char === "]") {
|
|
541
|
+
break;
|
|
542
|
+
} else {
|
|
543
|
+
result += this.consume();
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
return result.trim();
|
|
547
|
+
}
|
|
548
|
+
parseNumberValue() {
|
|
549
|
+
let numStr = "";
|
|
550
|
+
while (this.pos < this.input.length && /[\d.\-+eE]/.test(this.peek())) {
|
|
551
|
+
numStr += this.consume();
|
|
552
|
+
}
|
|
553
|
+
const num = parseFloat(numStr);
|
|
554
|
+
if (isNaN(num)) {
|
|
555
|
+
throw new ParseError(
|
|
556
|
+
"Invalid number",
|
|
557
|
+
this.pos - numStr.length,
|
|
558
|
+
this.schemaString,
|
|
559
|
+
this.input
|
|
560
|
+
);
|
|
561
|
+
}
|
|
562
|
+
return num;
|
|
563
|
+
}
|
|
564
|
+
parseIntValue() {
|
|
565
|
+
let numStr = "";
|
|
566
|
+
while (this.pos < this.input.length && /[\d.\-+eE]/.test(this.peek())) {
|
|
567
|
+
numStr += this.consume();
|
|
568
|
+
}
|
|
569
|
+
const num = parseFloat(numStr);
|
|
570
|
+
if (isNaN(num)) {
|
|
571
|
+
throw new ParseError(
|
|
572
|
+
"Invalid number",
|
|
573
|
+
this.pos - numStr.length,
|
|
574
|
+
this.schemaString,
|
|
575
|
+
this.input
|
|
576
|
+
);
|
|
577
|
+
}
|
|
578
|
+
if (!Number.isInteger(num)) {
|
|
579
|
+
throw new ParseError(
|
|
580
|
+
"Expected integer value",
|
|
581
|
+
this.pos - numStr.length,
|
|
582
|
+
this.schemaString,
|
|
583
|
+
this.input
|
|
584
|
+
);
|
|
585
|
+
}
|
|
586
|
+
return num;
|
|
587
|
+
}
|
|
588
|
+
parseFloatValue() {
|
|
589
|
+
return this.parseNumberValue();
|
|
590
|
+
}
|
|
591
|
+
parseBooleanValue() {
|
|
592
|
+
if (this.consumeStr("true")) {
|
|
593
|
+
return true;
|
|
594
|
+
}
|
|
595
|
+
if (this.consumeStr("false")) {
|
|
596
|
+
return false;
|
|
597
|
+
}
|
|
598
|
+
throw new ParseError(
|
|
599
|
+
"Expected true or false",
|
|
600
|
+
this.pos,
|
|
601
|
+
this.schemaString,
|
|
602
|
+
this.input
|
|
603
|
+
);
|
|
604
|
+
}
|
|
605
|
+
parseStringLiteralValue(schema) {
|
|
606
|
+
const quote = this.peek();
|
|
607
|
+
if (quote === '"' || quote === "'") {
|
|
608
|
+
this.consume();
|
|
609
|
+
let value = "";
|
|
610
|
+
while (this.pos < this.input.length) {
|
|
611
|
+
const char = this.peek();
|
|
612
|
+
if (char === "\\") {
|
|
613
|
+
this.consume();
|
|
614
|
+
const nextChar = this.consume();
|
|
615
|
+
if (nextChar === '"' || nextChar === "'" || nextChar === "\\" || nextChar === ";") {
|
|
616
|
+
value += nextChar;
|
|
617
|
+
} else {
|
|
618
|
+
value += "\\" + nextChar;
|
|
619
|
+
}
|
|
620
|
+
} else if (char === quote) {
|
|
621
|
+
this.consume();
|
|
622
|
+
if (value !== schema.value) {
|
|
623
|
+
throw new ParseError(
|
|
624
|
+
`Invalid value '"${value}"'. Expected '"${schema.value}"'`,
|
|
625
|
+
this.pos,
|
|
626
|
+
this.schemaString,
|
|
627
|
+
this.input
|
|
628
|
+
);
|
|
629
|
+
}
|
|
630
|
+
return value;
|
|
631
|
+
} else {
|
|
632
|
+
value += this.consume();
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
throw new ParseError(
|
|
636
|
+
"Unterminated string literal",
|
|
637
|
+
this.pos,
|
|
638
|
+
this.schemaString,
|
|
639
|
+
this.input
|
|
640
|
+
);
|
|
641
|
+
} else {
|
|
642
|
+
let value = "";
|
|
643
|
+
while (this.pos < this.input.length) {
|
|
644
|
+
const char = this.peek();
|
|
645
|
+
if (char === ";" || char === "]" || char === ")") {
|
|
646
|
+
break;
|
|
647
|
+
}
|
|
648
|
+
value += this.consume();
|
|
649
|
+
}
|
|
650
|
+
value = value.trim();
|
|
651
|
+
if (value !== schema.value) {
|
|
652
|
+
throw new ParseError(
|
|
653
|
+
`Invalid value '${value}'. Expected '${schema.value}'`,
|
|
654
|
+
this.pos - value.length,
|
|
655
|
+
this.schemaString,
|
|
656
|
+
this.input
|
|
657
|
+
);
|
|
658
|
+
}
|
|
659
|
+
return value;
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
parseUnionValue(schema) {
|
|
663
|
+
const savedPos = this.pos;
|
|
664
|
+
const errors = [];
|
|
665
|
+
for (let i = 0; i < schema.members.length; i++) {
|
|
666
|
+
this.pos = savedPos;
|
|
667
|
+
try {
|
|
668
|
+
return this.parseValue(schema.members[i], false);
|
|
669
|
+
} catch (e) {
|
|
670
|
+
errors.push(e);
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
throw new ParseError(
|
|
674
|
+
`Value does not match any union member. Tried ${schema.members.length} alternatives.`,
|
|
675
|
+
this.pos,
|
|
676
|
+
this.schemaString,
|
|
677
|
+
this.input
|
|
678
|
+
);
|
|
679
|
+
}
|
|
680
|
+
parseTupleValue(schema, allowOmitBrackets) {
|
|
681
|
+
let hasOpenBracket = false;
|
|
682
|
+
if (this.peek() === "[") {
|
|
683
|
+
this.consume();
|
|
684
|
+
hasOpenBracket = true;
|
|
685
|
+
} else if (!allowOmitBrackets) {
|
|
686
|
+
throw new ParseError(
|
|
687
|
+
"Expected [",
|
|
688
|
+
this.pos,
|
|
689
|
+
this.schemaString,
|
|
690
|
+
this.input
|
|
691
|
+
);
|
|
692
|
+
}
|
|
693
|
+
this.skipWhitespace();
|
|
694
|
+
if (this.peek() === "]" && hasOpenBracket) {
|
|
695
|
+
this.consume();
|
|
696
|
+
return [];
|
|
697
|
+
}
|
|
698
|
+
const result = [];
|
|
699
|
+
for (let i = 0; i < schema.elements.length; i++) {
|
|
700
|
+
this.skipWhitespace();
|
|
701
|
+
const elementSchema = schema.elements[i];
|
|
702
|
+
if (elementSchema.name) {
|
|
703
|
+
this.skipWhitespace();
|
|
704
|
+
const savedPos = this.pos;
|
|
705
|
+
if (this.consumeStr(`${elementSchema.name}:`)) {
|
|
706
|
+
this.skipWhitespace();
|
|
707
|
+
} else {
|
|
708
|
+
this.pos = savedPos;
|
|
709
|
+
}
|
|
710
|
+
}
|
|
711
|
+
result.push(this.parseValue(elementSchema.schema, false));
|
|
712
|
+
this.skipWhitespace();
|
|
713
|
+
if (i < schema.elements.length - 1) {
|
|
714
|
+
if (!this.consumeStr(";")) {
|
|
715
|
+
throw new ParseError(
|
|
716
|
+
"Expected ;",
|
|
717
|
+
this.pos,
|
|
718
|
+
this.schemaString,
|
|
719
|
+
this.input
|
|
720
|
+
);
|
|
721
|
+
}
|
|
722
|
+
}
|
|
723
|
+
}
|
|
724
|
+
this.skipWhitespace();
|
|
725
|
+
if (hasOpenBracket) {
|
|
726
|
+
if (!this.consumeStr("]")) {
|
|
727
|
+
throw new ParseError(
|
|
728
|
+
"Expected ]",
|
|
729
|
+
this.pos,
|
|
730
|
+
this.schemaString,
|
|
731
|
+
this.input
|
|
732
|
+
);
|
|
733
|
+
}
|
|
734
|
+
}
|
|
735
|
+
return result;
|
|
736
|
+
}
|
|
737
|
+
parseArrayValue(schema, allowOmitBrackets) {
|
|
738
|
+
let hasOpenBracket = false;
|
|
739
|
+
const elementIsTupleOrArray = schema.element.type === "tuple" || schema.element.type === "array";
|
|
740
|
+
if (this.pos >= this.input.length || !this.input.trim()) {
|
|
741
|
+
return [];
|
|
742
|
+
}
|
|
743
|
+
if (this.peek() === "[") {
|
|
744
|
+
if (!elementIsTupleOrArray) {
|
|
745
|
+
this.consume();
|
|
746
|
+
hasOpenBracket = true;
|
|
747
|
+
} else {
|
|
748
|
+
const savedPos = this.pos;
|
|
749
|
+
this.consume();
|
|
750
|
+
this.skipWhitespace();
|
|
751
|
+
if (this.peek() === "]") {
|
|
752
|
+
this.consume();
|
|
753
|
+
return [];
|
|
754
|
+
} else if (this.peek() === "[") {
|
|
755
|
+
hasOpenBracket = true;
|
|
756
|
+
} else {
|
|
757
|
+
this.pos = savedPos;
|
|
758
|
+
}
|
|
759
|
+
}
|
|
760
|
+
}
|
|
761
|
+
if (!hasOpenBracket && !allowOmitBrackets && !elementIsTupleOrArray) {
|
|
762
|
+
throw new ParseError(
|
|
763
|
+
"Expected [",
|
|
764
|
+
this.pos,
|
|
765
|
+
this.schemaString,
|
|
766
|
+
this.input
|
|
767
|
+
);
|
|
768
|
+
}
|
|
769
|
+
this.skipWhitespace();
|
|
770
|
+
if (this.peek() === "]" && hasOpenBracket) {
|
|
771
|
+
this.consume();
|
|
772
|
+
return [];
|
|
773
|
+
}
|
|
774
|
+
const result = [];
|
|
775
|
+
while (true) {
|
|
776
|
+
this.skipWhitespace();
|
|
777
|
+
result.push(this.parseValue(schema.element, elementIsTupleOrArray));
|
|
778
|
+
this.skipWhitespace();
|
|
779
|
+
if (!this.consumeStr(";")) {
|
|
780
|
+
break;
|
|
781
|
+
}
|
|
782
|
+
}
|
|
783
|
+
this.skipWhitespace();
|
|
784
|
+
if (hasOpenBracket) {
|
|
785
|
+
if (!this.consumeStr("]")) {
|
|
786
|
+
throw new ParseError(
|
|
787
|
+
"Expected ]",
|
|
788
|
+
this.pos,
|
|
789
|
+
this.schemaString,
|
|
790
|
+
this.input
|
|
791
|
+
);
|
|
792
|
+
}
|
|
793
|
+
}
|
|
794
|
+
return result;
|
|
795
|
+
}
|
|
796
|
+
parseReferenceValue(schema) {
|
|
797
|
+
if (schema.isOptional) {
|
|
798
|
+
this.skipWhitespace();
|
|
799
|
+
if (this.pos >= this.input.length) {
|
|
800
|
+
return null;
|
|
801
|
+
}
|
|
802
|
+
}
|
|
803
|
+
if (schema.isArray) {
|
|
804
|
+
let hasOpenBracket = false;
|
|
805
|
+
if (this.peek() === "[") {
|
|
806
|
+
this.consume();
|
|
807
|
+
hasOpenBracket = true;
|
|
808
|
+
}
|
|
809
|
+
this.skipWhitespace();
|
|
810
|
+
if (this.peek() === "]" && hasOpenBracket) {
|
|
811
|
+
this.consume();
|
|
812
|
+
return [];
|
|
813
|
+
}
|
|
814
|
+
const ids = [];
|
|
815
|
+
while (true) {
|
|
816
|
+
this.skipWhitespace();
|
|
817
|
+
let id = "";
|
|
818
|
+
while (this.pos < this.input.length && this.peek() !== ";" && this.peek() !== "]") {
|
|
819
|
+
id += this.consume();
|
|
820
|
+
}
|
|
821
|
+
ids.push(id.trim());
|
|
822
|
+
this.skipWhitespace();
|
|
823
|
+
if (!this.consumeStr(";")) {
|
|
824
|
+
break;
|
|
825
|
+
}
|
|
826
|
+
}
|
|
827
|
+
if (hasOpenBracket) {
|
|
828
|
+
if (!this.consumeStr("]")) {
|
|
829
|
+
throw new ParseError(
|
|
830
|
+
"Expected ]",
|
|
831
|
+
this.pos,
|
|
832
|
+
this.schemaString,
|
|
833
|
+
this.input
|
|
834
|
+
);
|
|
835
|
+
}
|
|
836
|
+
}
|
|
837
|
+
return ids;
|
|
838
|
+
} else {
|
|
839
|
+
let id = "";
|
|
840
|
+
while (this.pos < this.input.length) {
|
|
841
|
+
const char = this.peek();
|
|
842
|
+
if (char === ";" || char === "]" || char === ",") {
|
|
843
|
+
break;
|
|
844
|
+
}
|
|
845
|
+
id += this.consume();
|
|
846
|
+
}
|
|
847
|
+
return id.trim();
|
|
848
|
+
}
|
|
849
|
+
}
|
|
850
|
+
getPosition() {
|
|
851
|
+
return this.pos;
|
|
852
|
+
}
|
|
853
|
+
getInputLength() {
|
|
854
|
+
return this.input.length;
|
|
855
|
+
}
|
|
856
|
+
};
|
|
857
|
+
function parseValue(schema, valueString, schemaString) {
|
|
858
|
+
const sStr = schemaString || schemaToTypeString(schema);
|
|
859
|
+
const parser = new ValueParser(valueString.trim(), sStr);
|
|
860
|
+
const allowOmitBrackets = schema.type === "tuple" || schema.type === "array";
|
|
861
|
+
const value = parser.parseValue(schema, allowOmitBrackets);
|
|
862
|
+
if (parser.getPosition() < parser.getInputLength()) {
|
|
863
|
+
throw new ParseError(
|
|
864
|
+
"Unexpected input after value",
|
|
865
|
+
parser.getPosition(),
|
|
866
|
+
sStr,
|
|
867
|
+
valueString.trim()
|
|
868
|
+
);
|
|
869
|
+
}
|
|
870
|
+
return value;
|
|
871
|
+
}
|
|
872
|
+
|
|
873
|
+
// src/csv-loader/reference-resolver.ts
|
|
874
|
+
var fs = __toESM(require("fs"));
|
|
875
|
+
var path = __toESM(require("path"));
|
|
876
|
+
var referenceTableCache = /* @__PURE__ */ new Map();
|
|
877
|
+
var loadingFiles = /* @__PURE__ */ new Set();
|
|
878
|
+
function hasNestedReferences(schema) {
|
|
879
|
+
switch (schema.type) {
|
|
880
|
+
case "reference":
|
|
881
|
+
case "reverseReference":
|
|
882
|
+
return true;
|
|
883
|
+
case "tuple":
|
|
884
|
+
return schema.elements.some((el) => hasNestedReferences(el.schema));
|
|
885
|
+
case "array":
|
|
886
|
+
return hasNestedReferences(schema.element);
|
|
887
|
+
case "union":
|
|
888
|
+
return schema.members.some((m) => hasNestedReferences(m));
|
|
889
|
+
default:
|
|
890
|
+
return false;
|
|
891
|
+
}
|
|
892
|
+
}
|
|
893
|
+
function loadReferenceTable(schema, refBaseDir, defaultPrimaryKey, currentFilePath) {
|
|
894
|
+
const baseDir = refBaseDir || (currentFilePath ? path.dirname(currentFilePath) : process.cwd());
|
|
895
|
+
const fileName = `${schema.tableName}.csv`;
|
|
896
|
+
const refFilePath = path.isAbsolute(fileName) ? fileName : path.join(baseDir, fileName);
|
|
897
|
+
let refTable;
|
|
898
|
+
if (referenceTableCache.has(refFilePath)) {
|
|
899
|
+
refTable = referenceTableCache.get(refFilePath);
|
|
900
|
+
} else {
|
|
901
|
+
if (loadingFiles.has(refFilePath)) {
|
|
902
|
+
throw new Error(
|
|
903
|
+
`Circular reference detected: table "${schema.tableName}" (${refFilePath}) is already being loaded`
|
|
904
|
+
);
|
|
905
|
+
}
|
|
906
|
+
loadingFiles.add(refFilePath);
|
|
907
|
+
try {
|
|
908
|
+
const refContent = fs.readFileSync(refFilePath, "utf-8");
|
|
909
|
+
const refResult = parseCsv(refContent, {
|
|
910
|
+
currentFilePath: refFilePath,
|
|
911
|
+
emitTypes: false
|
|
912
|
+
});
|
|
913
|
+
refTable = refResult.data;
|
|
914
|
+
referenceTableCache.set(refFilePath, refTable);
|
|
915
|
+
} catch (error) {
|
|
916
|
+
throw new Error(
|
|
917
|
+
`Failed to load referenced table "${schema.tableName}" from ${refFilePath}: ${error instanceof Error ? error.message : String(error)}`
|
|
918
|
+
);
|
|
919
|
+
} finally {
|
|
920
|
+
loadingFiles.delete(refFilePath);
|
|
921
|
+
}
|
|
922
|
+
}
|
|
923
|
+
const lookup = /* @__PURE__ */ new Map();
|
|
924
|
+
refTable.forEach((row) => {
|
|
925
|
+
const pkValue = row[defaultPrimaryKey];
|
|
926
|
+
if (pkValue !== void 0) {
|
|
927
|
+
lookup.set(String(pkValue), row);
|
|
928
|
+
}
|
|
929
|
+
});
|
|
930
|
+
return { lookup, refTable };
|
|
931
|
+
}
|
|
932
|
+
function resolveReferenceId(id, lookup, tableName) {
|
|
933
|
+
const obj = lookup.get(id);
|
|
934
|
+
if (!obj) {
|
|
935
|
+
throw new Error(`Reference to "${tableName}" with id="${id}" not found`);
|
|
936
|
+
}
|
|
937
|
+
return obj;
|
|
938
|
+
}
|
|
939
|
+
function parseReferenceIds(schema, valueString) {
|
|
940
|
+
const trimmed = valueString.trim();
|
|
941
|
+
if (schema.isOptional && trimmed === "") {
|
|
942
|
+
return null;
|
|
943
|
+
}
|
|
944
|
+
return parseValue(schema, trimmed);
|
|
945
|
+
}
|
|
946
|
+
function parseValueWithReferenceIds(valueString, schema) {
|
|
947
|
+
if (!hasNestedReferences(schema)) {
|
|
948
|
+
return parseValue(schema, valueString);
|
|
949
|
+
}
|
|
950
|
+
switch (schema.type) {
|
|
951
|
+
case "reference":
|
|
952
|
+
return parseReferenceIds(schema, valueString);
|
|
953
|
+
case "reverseReference":
|
|
954
|
+
return null;
|
|
955
|
+
case "tuple": {
|
|
956
|
+
const parsed = parseValue(schema, valueString);
|
|
957
|
+
return schema.elements.map(
|
|
958
|
+
(el, i) => hasNestedReferences(el.schema) ? extractNestedReferenceIds(parsed[i], el.schema) : parsed[i]
|
|
959
|
+
);
|
|
960
|
+
}
|
|
961
|
+
case "array": {
|
|
962
|
+
const parsed = parseValue(schema, valueString);
|
|
963
|
+
return parsed.map(
|
|
964
|
+
(item) => hasNestedReferences(schema.element) ? extractNestedReferenceIds(item, schema.element) : item
|
|
965
|
+
);
|
|
966
|
+
}
|
|
967
|
+
case "union": {
|
|
968
|
+
for (const member of schema.members) {
|
|
969
|
+
if (hasNestedReferences(member)) {
|
|
970
|
+
try {
|
|
971
|
+
const parsed = parseValue(member, valueString);
|
|
972
|
+
return extractNestedReferenceIds(parsed, member);
|
|
973
|
+
} catch {
|
|
974
|
+
}
|
|
975
|
+
}
|
|
976
|
+
}
|
|
977
|
+
return parseValue(schema, valueString);
|
|
978
|
+
}
|
|
979
|
+
default:
|
|
980
|
+
return parseValue(schema, valueString);
|
|
981
|
+
}
|
|
982
|
+
}
|
|
983
|
+
function extractNestedReferenceIds(value, schema) {
|
|
984
|
+
switch (schema.type) {
|
|
985
|
+
case "reference":
|
|
986
|
+
if (value === null || value === void 0) return value;
|
|
987
|
+
if (schema.isArray) {
|
|
988
|
+
const ids = Array.isArray(value) ? value : [value];
|
|
989
|
+
return ids.map((id) => String(id));
|
|
990
|
+
}
|
|
991
|
+
return String(value);
|
|
992
|
+
case "reverseReference":
|
|
993
|
+
return null;
|
|
994
|
+
case "tuple": {
|
|
995
|
+
if (!Array.isArray(value)) return value;
|
|
996
|
+
return schema.elements.map(
|
|
997
|
+
(el, i) => hasNestedReferences(el.schema) ? extractNestedReferenceIds(value[i], el.schema) : value[i]
|
|
998
|
+
);
|
|
999
|
+
}
|
|
1000
|
+
case "array": {
|
|
1001
|
+
if (!Array.isArray(value)) return value;
|
|
1002
|
+
return value.map(
|
|
1003
|
+
(item) => hasNestedReferences(schema.element) ? extractNestedReferenceIds(item, schema.element) : item
|
|
1004
|
+
);
|
|
1005
|
+
}
|
|
1006
|
+
case "union": {
|
|
1007
|
+
for (const member of schema.members) {
|
|
1008
|
+
if (hasNestedReferences(member)) {
|
|
1009
|
+
try {
|
|
1010
|
+
return extractNestedReferenceIds(value, member);
|
|
1011
|
+
} catch {
|
|
1012
|
+
}
|
|
1013
|
+
}
|
|
1014
|
+
}
|
|
1015
|
+
return value;
|
|
1016
|
+
}
|
|
1017
|
+
default:
|
|
1018
|
+
return value;
|
|
1019
|
+
}
|
|
1020
|
+
}
|
|
1021
|
+
function collectReferenceFields(schema, name) {
|
|
1022
|
+
const fields = [];
|
|
1023
|
+
switch (schema.type) {
|
|
1024
|
+
case "reference":
|
|
1025
|
+
fields.push({
|
|
1026
|
+
name,
|
|
1027
|
+
tableName: schema.tableName,
|
|
1028
|
+
isArray: schema.isArray,
|
|
1029
|
+
schema
|
|
1030
|
+
});
|
|
1031
|
+
break;
|
|
1032
|
+
case "reverseReference":
|
|
1033
|
+
fields.push({
|
|
1034
|
+
name,
|
|
1035
|
+
tableName: schema.tableName,
|
|
1036
|
+
isArray: true,
|
|
1037
|
+
foreignKey: schema.foreignKey,
|
|
1038
|
+
schema
|
|
1039
|
+
});
|
|
1040
|
+
break;
|
|
1041
|
+
case "tuple":
|
|
1042
|
+
for (const el of schema.elements) {
|
|
1043
|
+
fields.push(...collectReferenceFields(el.schema, name));
|
|
1044
|
+
}
|
|
1045
|
+
break;
|
|
1046
|
+
case "array":
|
|
1047
|
+
fields.push(...collectReferenceFields(schema.element, name));
|
|
1048
|
+
break;
|
|
1049
|
+
case "union":
|
|
1050
|
+
for (const member of schema.members) {
|
|
1051
|
+
fields.push(...collectReferenceFields(member, name));
|
|
1052
|
+
}
|
|
1053
|
+
break;
|
|
1054
|
+
}
|
|
1055
|
+
return fields;
|
|
1056
|
+
}
|
|
1057
|
+
function parseValueWithReferences(valueString, schema, refBaseDir, defaultPrimaryKey, currentFilePath, currentRowPk) {
|
|
1058
|
+
if (!hasNestedReferences(schema)) {
|
|
1059
|
+
return parseValue(schema, valueString);
|
|
1060
|
+
}
|
|
1061
|
+
switch (schema.type) {
|
|
1062
|
+
case "reference":
|
|
1063
|
+
return parseReferenceValue(
|
|
1064
|
+
schema,
|
|
1065
|
+
valueString,
|
|
1066
|
+
refBaseDir,
|
|
1067
|
+
defaultPrimaryKey,
|
|
1068
|
+
currentFilePath
|
|
1069
|
+
);
|
|
1070
|
+
case "reverseReference": {
|
|
1071
|
+
if (currentRowPk === void 0) return [];
|
|
1072
|
+
return resolveReverseReference(
|
|
1073
|
+
schema,
|
|
1074
|
+
currentRowPk,
|
|
1075
|
+
refBaseDir,
|
|
1076
|
+
defaultPrimaryKey,
|
|
1077
|
+
currentFilePath
|
|
1078
|
+
);
|
|
1079
|
+
}
|
|
1080
|
+
case "tuple": {
|
|
1081
|
+
const parsed = parseValue(schema, valueString);
|
|
1082
|
+
return schema.elements.map(
|
|
1083
|
+
(el, i) => resolveNestedReferences(
|
|
1084
|
+
parsed[i],
|
|
1085
|
+
el.schema,
|
|
1086
|
+
refBaseDir,
|
|
1087
|
+
defaultPrimaryKey,
|
|
1088
|
+
currentFilePath,
|
|
1089
|
+
currentRowPk
|
|
1090
|
+
)
|
|
1091
|
+
);
|
|
1092
|
+
}
|
|
1093
|
+
case "array": {
|
|
1094
|
+
const parsed = parseValue(schema, valueString);
|
|
1095
|
+
return parsed.map(
|
|
1096
|
+
(item) => resolveNestedReferences(
|
|
1097
|
+
item,
|
|
1098
|
+
schema.element,
|
|
1099
|
+
refBaseDir,
|
|
1100
|
+
defaultPrimaryKey,
|
|
1101
|
+
currentFilePath,
|
|
1102
|
+
currentRowPk
|
|
1103
|
+
)
|
|
1104
|
+
);
|
|
1105
|
+
}
|
|
1106
|
+
case "union": {
|
|
1107
|
+
const errors = [];
|
|
1108
|
+
for (const member of schema.members) {
|
|
1109
|
+
if (hasNestedReferences(member)) {
|
|
1110
|
+
try {
|
|
1111
|
+
const parsed = parseValue(member, valueString);
|
|
1112
|
+
return resolveNestedReferences(
|
|
1113
|
+
parsed,
|
|
1114
|
+
member,
|
|
1115
|
+
refBaseDir,
|
|
1116
|
+
defaultPrimaryKey,
|
|
1117
|
+
currentFilePath,
|
|
1118
|
+
currentRowPk
|
|
1119
|
+
);
|
|
1120
|
+
} catch (e) {
|
|
1121
|
+
errors.push(e instanceof Error ? e : new Error(String(e)));
|
|
1122
|
+
}
|
|
1123
|
+
}
|
|
1124
|
+
}
|
|
1125
|
+
if (errors.length > 0 && errors.every(
|
|
1126
|
+
(e) => /not found|Circular reference|Failed to load/.test(e.message)
|
|
1127
|
+
)) {
|
|
1128
|
+
for (const member of schema.members) {
|
|
1129
|
+
if (!hasNestedReferences(member)) {
|
|
1130
|
+
try {
|
|
1131
|
+
return parseValue(member, valueString);
|
|
1132
|
+
} catch {
|
|
1133
|
+
}
|
|
1134
|
+
}
|
|
1135
|
+
}
|
|
1136
|
+
}
|
|
1137
|
+
return parseValue(schema, valueString);
|
|
1138
|
+
}
|
|
1139
|
+
default:
|
|
1140
|
+
return parseValue(schema, valueString);
|
|
1141
|
+
}
|
|
1142
|
+
}
|
|
1143
|
+
function resolveReverseReference(schema, pkValue, refBaseDir, defaultPrimaryKey, currentFilePath) {
|
|
1144
|
+
const { refTable } = loadReferenceTable(
|
|
1145
|
+
schema,
|
|
1146
|
+
refBaseDir,
|
|
1147
|
+
defaultPrimaryKey,
|
|
1148
|
+
currentFilePath
|
|
1149
|
+
);
|
|
1150
|
+
const pkStr = String(pkValue);
|
|
1151
|
+
return refTable.filter((row) => {
|
|
1152
|
+
const fkValue = row[schema.foreignKey];
|
|
1153
|
+
const fkStr = fkValue !== null && fkValue !== void 0 && typeof fkValue === "object" ? String(fkValue[defaultPrimaryKey]) : String(fkValue);
|
|
1154
|
+
return fkStr === pkStr;
|
|
1155
|
+
});
|
|
1156
|
+
}
|
|
1157
|
+
function resolveNestedReferences(value, schema, refBaseDir, defaultPrimaryKey, currentFilePath, currentRowPk) {
|
|
1158
|
+
switch (schema.type) {
|
|
1159
|
+
case "reference": {
|
|
1160
|
+
if (value === null || value === void 0) return value;
|
|
1161
|
+
const { lookup } = loadReferenceTable(
|
|
1162
|
+
schema,
|
|
1163
|
+
refBaseDir,
|
|
1164
|
+
defaultPrimaryKey,
|
|
1165
|
+
currentFilePath
|
|
1166
|
+
);
|
|
1167
|
+
if (schema.isArray) {
|
|
1168
|
+
const ids = Array.isArray(value) ? value : [value];
|
|
1169
|
+
return ids.map(
|
|
1170
|
+
(id) => resolveReferenceId(String(id), lookup, schema.tableName)
|
|
1171
|
+
);
|
|
1172
|
+
}
|
|
1173
|
+
return resolveReferenceId(String(value), lookup, schema.tableName);
|
|
1174
|
+
}
|
|
1175
|
+
case "reverseReference": {
|
|
1176
|
+
if (currentRowPk === void 0) return [];
|
|
1177
|
+
const results = resolveReverseReference(
|
|
1178
|
+
schema,
|
|
1179
|
+
currentRowPk,
|
|
1180
|
+
refBaseDir,
|
|
1181
|
+
defaultPrimaryKey,
|
|
1182
|
+
currentFilePath
|
|
1183
|
+
);
|
|
1184
|
+
return results;
|
|
1185
|
+
}
|
|
1186
|
+
case "tuple": {
|
|
1187
|
+
if (!Array.isArray(value)) return value;
|
|
1188
|
+
return schema.elements.map(
|
|
1189
|
+
(el, i) => resolveNestedReferences(
|
|
1190
|
+
value[i],
|
|
1191
|
+
el.schema,
|
|
1192
|
+
refBaseDir,
|
|
1193
|
+
defaultPrimaryKey,
|
|
1194
|
+
currentFilePath,
|
|
1195
|
+
currentRowPk
|
|
1196
|
+
)
|
|
1197
|
+
);
|
|
1198
|
+
}
|
|
1199
|
+
case "array": {
|
|
1200
|
+
if (!Array.isArray(value)) return value;
|
|
1201
|
+
return value.map(
|
|
1202
|
+
(item) => resolveNestedReferences(
|
|
1203
|
+
item,
|
|
1204
|
+
schema.element,
|
|
1205
|
+
refBaseDir,
|
|
1206
|
+
defaultPrimaryKey,
|
|
1207
|
+
currentFilePath,
|
|
1208
|
+
currentRowPk
|
|
1209
|
+
)
|
|
1210
|
+
);
|
|
1211
|
+
}
|
|
1212
|
+
case "union": {
|
|
1213
|
+
const errors = [];
|
|
1214
|
+
for (const member of schema.members) {
|
|
1215
|
+
if (hasNestedReferences(member)) {
|
|
1216
|
+
try {
|
|
1217
|
+
return resolveNestedReferences(
|
|
1218
|
+
value,
|
|
1219
|
+
member,
|
|
1220
|
+
refBaseDir,
|
|
1221
|
+
defaultPrimaryKey,
|
|
1222
|
+
currentFilePath,
|
|
1223
|
+
currentRowPk
|
|
1224
|
+
);
|
|
1225
|
+
} catch (e) {
|
|
1226
|
+
errors.push(e instanceof Error ? e : new Error(String(e)));
|
|
1227
|
+
}
|
|
1228
|
+
}
|
|
1229
|
+
}
|
|
1230
|
+
if (errors.length > 0) {
|
|
1231
|
+
throw errors[0];
|
|
1232
|
+
}
|
|
1233
|
+
return value;
|
|
1234
|
+
}
|
|
1235
|
+
default:
|
|
1236
|
+
return value;
|
|
1237
|
+
}
|
|
1238
|
+
}
|
|
1239
|
+
function parseReferenceValue(schema, valueString, refBaseDir, defaultPrimaryKey, currentFilePath) {
|
|
1240
|
+
const trimmed = valueString.trim();
|
|
1241
|
+
if (schema.isOptional && trimmed === "") {
|
|
1242
|
+
return null;
|
|
1243
|
+
}
|
|
1244
|
+
const { lookup } = loadReferenceTable(
|
|
1245
|
+
schema,
|
|
1246
|
+
refBaseDir,
|
|
1247
|
+
defaultPrimaryKey,
|
|
1248
|
+
currentFilePath
|
|
1249
|
+
);
|
|
1250
|
+
const ids = parseValue(schema, trimmed);
|
|
1251
|
+
if (ids === null) return null;
|
|
1252
|
+
if (schema.isArray && Array.isArray(ids)) {
|
|
1253
|
+
return ids.map((id) => resolveReferenceId(id, lookup, schema.tableName));
|
|
1254
|
+
}
|
|
1255
|
+
return resolveReferenceId(ids, lookup, schema.tableName);
|
|
1256
|
+
}
|
|
1257
|
+
|
|
1258
|
+
// src/csv-loader/type-gen.ts
|
|
1259
|
+
var path2 = __toESM(require("path"));
|
|
1260
|
+
function resolveReferencesInSchemaString(schemaString, resourceNames) {
|
|
1261
|
+
return schemaString.replace(/@([a-zA-Z0-9\-_]+)(\[\])?/g, (_match, tableName, arraySuffix) => {
|
|
1262
|
+
const typeName = resourceNames.get(tableName) || tableName.charAt(0).toUpperCase() + tableName.slice(1);
|
|
1263
|
+
return arraySuffix ? `${typeName}[]` : typeName;
|
|
1264
|
+
}).replace(/; ?/g, ", ");
|
|
1265
|
+
}
|
|
1266
|
+
function generateTypeDefinition(resourceName, propertyConfigs, references, currentFilePath, typeDeclarations = []) {
|
|
1267
|
+
const typeName = resourceName ? `${resourceName}Table` : "Table";
|
|
1268
|
+
const currentTableName = currentFilePath ? path2.basename(currentFilePath, path2.extname(currentFilePath)) : void 0;
|
|
1269
|
+
const singularType = resourceName ? resourceName.charAt(0).toUpperCase() + resourceName.slice(1) : `${typeName}[number]`;
|
|
1270
|
+
const imports = [];
|
|
1271
|
+
const resourceNames = /* @__PURE__ */ new Map();
|
|
1272
|
+
references.forEach((tableName) => {
|
|
1273
|
+
if (tableName === currentTableName) {
|
|
1274
|
+
resourceNames.set(tableName, singularType);
|
|
1275
|
+
return;
|
|
1276
|
+
}
|
|
1277
|
+
const typeBase = tableName.charAt(0).toUpperCase() + tableName.slice(1);
|
|
1278
|
+
resourceNames.set(tableName, typeBase);
|
|
1279
|
+
let importPath;
|
|
1280
|
+
if (currentFilePath) {
|
|
1281
|
+
importPath = `./${tableName}.csv`;
|
|
1282
|
+
} else {
|
|
1283
|
+
importPath = `../${tableName}.csv`;
|
|
1284
|
+
}
|
|
1285
|
+
imports.push(`import type { ${typeBase} } from '${importPath}';`);
|
|
1286
|
+
});
|
|
1287
|
+
const importSection = imports.length > 0 ? imports.join("\n") + "\n\n" : "";
|
|
1288
|
+
const typeDeclarationSection = typeDeclarations.length > 0 ? typeDeclarations.map(
|
|
1289
|
+
(decl) => `export type ${decl.name} = ${decl.schemaString ? resolveReferencesInSchemaString(decl.schemaString, resourceNames) : schemaToTypeString(decl.schema, resourceNames)};`
|
|
1290
|
+
).join("\n") + "\n\n" : "";
|
|
1291
|
+
const properties = propertyConfigs.map((config) => {
|
|
1292
|
+
const typeStr = config.declaredTypeName ? config.declaredTypeName : config.schemaString ? resolveReferencesInSchemaString(config.schemaString, resourceNames) : schemaToTypeString(config.schema, resourceNames);
|
|
1293
|
+
return ` readonly ${config.name}: ${typeStr};`;
|
|
1294
|
+
}).join("\n");
|
|
1295
|
+
let exportAlias = "";
|
|
1296
|
+
if (resourceName) {
|
|
1297
|
+
const singularType2 = resourceName.charAt(0).toUpperCase() + resourceName.slice(1);
|
|
1298
|
+
exportAlias = `
|
|
1299
|
+
export type ${singularType2} = ${typeName}[number];`;
|
|
1300
|
+
}
|
|
1301
|
+
return `${importSection}${typeDeclarationSection}type ${typeName} = readonly {
|
|
1302
|
+
${properties}
|
|
1303
|
+
}[];
|
|
1304
|
+
${exportAlias}
|
|
1305
|
+
|
|
1306
|
+
declare function getData(): ${typeName};
|
|
1307
|
+
export default getData;
|
|
1308
|
+
`;
|
|
1309
|
+
}
|
|
1310
|
+
|
|
1311
|
+
// src/csv-loader/type-declarations.ts
|
|
1312
|
+
function parseTypeDeclaration(line, commentChar = "#") {
|
|
1313
|
+
const trimmed = line.trim();
|
|
1314
|
+
if (!trimmed.startsWith(commentChar)) return null;
|
|
1315
|
+
const content = trimmed.slice(commentChar.length).trim();
|
|
1316
|
+
const match = content.match(/^type\s+([A-Z][a-zA-Z0-9]*)\s*=\s*(.+)$/);
|
|
1317
|
+
if (!match) return null;
|
|
1318
|
+
const [, typeName, schemaString] = match;
|
|
1319
|
+
return { typeName, schemaString };
|
|
1320
|
+
}
|
|
1321
|
+
function expandTypeName(schemaString, declaredTypes) {
|
|
1322
|
+
const trimmed = schemaString.trim();
|
|
1323
|
+
if (declaredTypes.has(trimmed)) {
|
|
1324
|
+
return declaredTypes.get(trimmed);
|
|
1325
|
+
}
|
|
1326
|
+
return null;
|
|
1327
|
+
}
|
|
1328
|
+
function expandSchemaString(schemaString, declaredTypes) {
|
|
1329
|
+
let result = schemaString;
|
|
1330
|
+
let prev = "";
|
|
1331
|
+
while (prev !== result) {
|
|
1332
|
+
prev = result;
|
|
1333
|
+
result = expandSchemaInString(result, declaredTypes);
|
|
1334
|
+
}
|
|
1335
|
+
return result;
|
|
1336
|
+
}
|
|
1337
|
+
function expandSchemaInString(schemaString, declaredTypes) {
|
|
1338
|
+
const expanded = expandTypeName(schemaString.trim(), declaredTypes);
|
|
1339
|
+
if (expanded !== null) {
|
|
1340
|
+
return expanded;
|
|
1341
|
+
}
|
|
1342
|
+
const trimmed = schemaString.trim();
|
|
1343
|
+
if (trimmed.endsWith("[]")) {
|
|
1344
|
+
const inner = trimmed.slice(0, -2);
|
|
1345
|
+
const expandedInner = expandSchemaInString(inner, declaredTypes);
|
|
1346
|
+
return `${expandedInner}[]`;
|
|
1347
|
+
}
|
|
1348
|
+
if (schemaString.includes("|")) {
|
|
1349
|
+
const parts = splitByToken(schemaString, "|");
|
|
1350
|
+
if (parts.length > 1) {
|
|
1351
|
+
const expandedParts = parts.map(
|
|
1352
|
+
(part) => expandSchemaInString(part.trim(), declaredTypes)
|
|
1353
|
+
);
|
|
1354
|
+
return expandedParts.join(" | ");
|
|
1355
|
+
}
|
|
1356
|
+
}
|
|
1357
|
+
if (schemaString.startsWith("[") && schemaString.endsWith("]")) {
|
|
1358
|
+
const inner = schemaString.slice(1, -1);
|
|
1359
|
+
if (inner.includes(";")) {
|
|
1360
|
+
const elements = splitByToken(inner, ";");
|
|
1361
|
+
const expandedElements = elements.map(
|
|
1362
|
+
(el) => expandSchemaInString(el.trim(), declaredTypes)
|
|
1363
|
+
);
|
|
1364
|
+
return `[${expandedElements.join("; ")}]`;
|
|
1365
|
+
}
|
|
1366
|
+
return `[${expandSchemaInString(inner, declaredTypes)}]`;
|
|
1367
|
+
}
|
|
1368
|
+
const typeNameMatch = schemaString.trim().match(/^[A-Z][a-zA-Z0-9]*$/);
|
|
1369
|
+
if (typeNameMatch) {
|
|
1370
|
+
const expanded2 = expandTypeName(schemaString.trim(), declaredTypes);
|
|
1371
|
+
if (expanded2 !== null) {
|
|
1372
|
+
return expanded2;
|
|
1373
|
+
}
|
|
1374
|
+
}
|
|
1375
|
+
return schemaString;
|
|
1376
|
+
}
|
|
1377
|
+
function splitByToken(str, token) {
|
|
1378
|
+
const result = [];
|
|
1379
|
+
let current = "";
|
|
1380
|
+
let inQuote = null;
|
|
1381
|
+
for (let i = 0; i < str.length; i++) {
|
|
1382
|
+
const char = str[i];
|
|
1383
|
+
if (inQuote) {
|
|
1384
|
+
if (char === inQuote && str[i - 1] !== "\\") {
|
|
1385
|
+
inQuote = null;
|
|
1386
|
+
}
|
|
1387
|
+
current += char;
|
|
1388
|
+
} else if (char === '"' || char === "'") {
|
|
1389
|
+
inQuote = char;
|
|
1390
|
+
current += char;
|
|
1391
|
+
} else if (char === token && inQuote === null) {
|
|
1392
|
+
result.push(current);
|
|
1393
|
+
current = "";
|
|
1394
|
+
} else {
|
|
1395
|
+
current += char;
|
|
1396
|
+
}
|
|
1397
|
+
}
|
|
1398
|
+
if (current.length > 0 || str.endsWith(token)) {
|
|
1399
|
+
result.push(current);
|
|
1400
|
+
}
|
|
1401
|
+
return result;
|
|
1402
|
+
}
|
|
1403
|
+
function resolveTypeReferences(schema, declaredTypes) {
|
|
1404
|
+
switch (schema.type) {
|
|
1405
|
+
case "union":
|
|
1406
|
+
return {
|
|
1407
|
+
type: "union",
|
|
1408
|
+
members: schema.members.map(
|
|
1409
|
+
(m) => resolveTypeReferences(m, declaredTypes)
|
|
1410
|
+
)
|
|
1411
|
+
};
|
|
1412
|
+
case "tuple":
|
|
1413
|
+
return {
|
|
1414
|
+
type: "tuple",
|
|
1415
|
+
elements: schema.elements.map((el) => ({
|
|
1416
|
+
name: el.name,
|
|
1417
|
+
schema: resolveTypeReferences(el.schema, declaredTypes)
|
|
1418
|
+
}))
|
|
1419
|
+
};
|
|
1420
|
+
case "array":
|
|
1421
|
+
return {
|
|
1422
|
+
type: "array",
|
|
1423
|
+
element: resolveTypeReferences(schema.element, declaredTypes)
|
|
1424
|
+
};
|
|
1425
|
+
case "reference":
|
|
1426
|
+
return schema;
|
|
1427
|
+
default:
|
|
1428
|
+
return schema;
|
|
1429
|
+
}
|
|
1430
|
+
}
|
|
1431
|
+
function parseReverseReferenceDeclaration(line, commentChar = "#") {
|
|
1432
|
+
const trimmed = line.trim();
|
|
1433
|
+
if (!trimmed.startsWith(commentChar)) return null;
|
|
1434
|
+
const content = trimmed.slice(commentChar.length).trim();
|
|
1435
|
+
const match = content.match(/^inject\s+(\w+)\s*=\s*~(\w+)\((\w+)\)(\?)?$/);
|
|
1436
|
+
if (!match) return null;
|
|
1437
|
+
const [, fieldName, tableName, foreignKey, optionalMark] = match;
|
|
1438
|
+
const isOptional = optionalMark === "?";
|
|
1439
|
+
const schema = {
|
|
1440
|
+
type: "reverseReference",
|
|
1441
|
+
tableName,
|
|
1442
|
+
foreignKey,
|
|
1443
|
+
isOptional
|
|
1444
|
+
};
|
|
1445
|
+
return {
|
|
1446
|
+
fieldName,
|
|
1447
|
+
tableName,
|
|
1448
|
+
foreignKey,
|
|
1449
|
+
isOptional,
|
|
1450
|
+
schema
|
|
1451
|
+
};
|
|
1452
|
+
}
|
|
1453
|
+
|
|
1454
|
+
// src/csv-loader/loader.ts
|
|
1455
|
+
function parseCsv(content, options = {}) {
|
|
1456
|
+
const delimiter = options.delimiter ?? ",";
|
|
1457
|
+
const quote = options.quote ?? '"';
|
|
1458
|
+
const escape = options.escape ?? "\\";
|
|
1459
|
+
const bom = options.bom ?? true;
|
|
1460
|
+
const comment = options.comment === false ? void 0 : options.comment ?? "#";
|
|
1461
|
+
const trim = options.trim ?? true;
|
|
1462
|
+
const emitTypes = options.emitTypes ?? true;
|
|
1463
|
+
const refBaseDir = options.refBaseDir;
|
|
1464
|
+
const defaultPrimaryKey = options.defaultPrimaryKey ?? "id";
|
|
1465
|
+
const reverseReferences = [];
|
|
1466
|
+
const typeDeclarationsRaw = [];
|
|
1467
|
+
let filteredContent = content;
|
|
1468
|
+
if (comment) {
|
|
1469
|
+
const lines = content.split(/\r?\n/);
|
|
1470
|
+
const nonCommentLines = [];
|
|
1471
|
+
for (const line of lines) {
|
|
1472
|
+
const trimmed = line.trim();
|
|
1473
|
+
if (trimmed.startsWith(comment)) {
|
|
1474
|
+
const typeDecl = parseTypeDeclaration(trimmed, comment);
|
|
1475
|
+
if (typeDecl) {
|
|
1476
|
+
typeDeclarationsRaw.push(typeDecl);
|
|
1477
|
+
continue;
|
|
1478
|
+
}
|
|
1479
|
+
const decl = parseReverseReferenceDeclaration(trimmed, comment);
|
|
1480
|
+
if (decl) {
|
|
1481
|
+
reverseReferences.push(decl);
|
|
1482
|
+
continue;
|
|
1483
|
+
}
|
|
1484
|
+
continue;
|
|
1485
|
+
}
|
|
1486
|
+
nonCommentLines.push(line);
|
|
1487
|
+
}
|
|
1488
|
+
filteredContent = nonCommentLines.join("\n");
|
|
1489
|
+
}
|
|
1490
|
+
const records = (0, import_sync.parse)(filteredContent, {
|
|
1491
|
+
delimiter,
|
|
1492
|
+
quote,
|
|
1493
|
+
escape,
|
|
1494
|
+
bom,
|
|
1495
|
+
comment: void 0,
|
|
1496
|
+
trim,
|
|
1497
|
+
skip_empty_lines: true,
|
|
1498
|
+
relax_column_count: true
|
|
1499
|
+
});
|
|
1500
|
+
const filteredRecords = records;
|
|
1501
|
+
if (filteredRecords.length < 2) {
|
|
1502
|
+
throw new Error("CSV must have at least 2 rows: headers and schemas");
|
|
1503
|
+
}
|
|
1504
|
+
const headers = filteredRecords[0];
|
|
1505
|
+
const schemas = filteredRecords[1];
|
|
1506
|
+
if (headers.length !== schemas.length) {
|
|
1507
|
+
throw new Error(
|
|
1508
|
+
`Header count (${headers.length}) does not match schema count (${schemas.length})`
|
|
1509
|
+
);
|
|
1510
|
+
}
|
|
1511
|
+
const dataRows = filteredRecords.slice(2);
|
|
1512
|
+
for (let col = 0; col < schemas.length; col++) {
|
|
1513
|
+
const cell = (schemas[col] ?? "").trim();
|
|
1514
|
+
if (comment && cell.startsWith(comment)) {
|
|
1515
|
+
const typeDecl = parseTypeDeclaration(cell, comment);
|
|
1516
|
+
if (typeDecl) {
|
|
1517
|
+
typeDeclarationsRaw.push(typeDecl);
|
|
1518
|
+
continue;
|
|
1519
|
+
}
|
|
1520
|
+
const decl = parseReverseReferenceDeclaration(cell, comment);
|
|
1521
|
+
if (decl) {
|
|
1522
|
+
reverseReferences.push(decl);
|
|
1523
|
+
}
|
|
1524
|
+
}
|
|
1525
|
+
}
|
|
1526
|
+
const declaredTypeNames = /* @__PURE__ */ new Set();
|
|
1527
|
+
for (const decl of typeDeclarationsRaw) {
|
|
1528
|
+
declaredTypeNames.add(decl.typeName);
|
|
1529
|
+
}
|
|
1530
|
+
const declaredSchemaStrings = /* @__PURE__ */ new Map();
|
|
1531
|
+
for (const decl of typeDeclarationsRaw) {
|
|
1532
|
+
declaredSchemaStrings.set(decl.typeName, decl.schemaString);
|
|
1533
|
+
}
|
|
1534
|
+
const typeDeclarationsParsed = [];
|
|
1535
|
+
for (const decl of typeDeclarationsRaw) {
|
|
1536
|
+
const expandedSchema = expandSchemaString(
|
|
1537
|
+
decl.schemaString,
|
|
1538
|
+
declaredSchemaStrings
|
|
1539
|
+
);
|
|
1540
|
+
const schema = parseSchema(expandedSchema.trim());
|
|
1541
|
+
typeDeclarationsParsed.push({
|
|
1542
|
+
name: decl.typeName,
|
|
1543
|
+
schema,
|
|
1544
|
+
schemaString: decl.schemaString
|
|
1545
|
+
});
|
|
1546
|
+
}
|
|
1547
|
+
const declaredTypes = /* @__PURE__ */ new Map();
|
|
1548
|
+
for (const decl of typeDeclarationsParsed) {
|
|
1549
|
+
declaredTypes.set(decl.name, decl.schema);
|
|
1550
|
+
}
|
|
1551
|
+
const typeDeclarations = [];
|
|
1552
|
+
for (const decl of typeDeclarationsParsed) {
|
|
1553
|
+
const resolvedSchema = resolveTypeReferences(decl.schema, declaredTypes);
|
|
1554
|
+
typeDeclarations.push({
|
|
1555
|
+
name: decl.name,
|
|
1556
|
+
schema: resolvedSchema,
|
|
1557
|
+
schemaString: decl.schemaString
|
|
1558
|
+
});
|
|
1559
|
+
}
|
|
1560
|
+
for (const decl of typeDeclarations) {
|
|
1561
|
+
declaredTypes.set(decl.name, decl.schema);
|
|
1562
|
+
}
|
|
1563
|
+
const resolveReferences = options.resolveReferences ?? true;
|
|
1564
|
+
const propertyConfigs = headers.map(
|
|
1565
|
+
(header, index) => {
|
|
1566
|
+
const schemaString = schemas[index];
|
|
1567
|
+
let schema;
|
|
1568
|
+
let declaredTypeName;
|
|
1569
|
+
let columnSchemaString;
|
|
1570
|
+
if (declaredTypes.has(schemaString)) {
|
|
1571
|
+
schema = declaredTypes.get(schemaString);
|
|
1572
|
+
declaredTypeName = schemaString;
|
|
1573
|
+
} else {
|
|
1574
|
+
const expandedSchema = expandSchemaString(
|
|
1575
|
+
schemaString,
|
|
1576
|
+
declaredSchemaStrings
|
|
1577
|
+
);
|
|
1578
|
+
schema = parseSchema(expandedSchema.trim());
|
|
1579
|
+
if (expandedSchema !== schemaString) {
|
|
1580
|
+
columnSchemaString = schemaString;
|
|
1581
|
+
}
|
|
1582
|
+
}
|
|
1583
|
+
const config = {
|
|
1584
|
+
name: header,
|
|
1585
|
+
schema,
|
|
1586
|
+
validator: createValidator(schema),
|
|
1587
|
+
parser: (valueString) => parseValue(schema, valueString),
|
|
1588
|
+
declaredTypeName,
|
|
1589
|
+
schemaString: columnSchemaString
|
|
1590
|
+
};
|
|
1591
|
+
if (schema.type === "reference") {
|
|
1592
|
+
config.isReference = true;
|
|
1593
|
+
config.referenceTableName = schema.tableName;
|
|
1594
|
+
config.referenceIsArray = schema.isArray;
|
|
1595
|
+
if (resolveReferences) {
|
|
1596
|
+
config.parser = (valueString) => {
|
|
1597
|
+
return parseReferenceValue(
|
|
1598
|
+
schema,
|
|
1599
|
+
valueString,
|
|
1600
|
+
refBaseDir,
|
|
1601
|
+
defaultPrimaryKey,
|
|
1602
|
+
options.currentFilePath
|
|
1603
|
+
);
|
|
1604
|
+
};
|
|
1605
|
+
} else {
|
|
1606
|
+
config.parser = (valueString) => {
|
|
1607
|
+
return parseReferenceIds(schema, valueString);
|
|
1608
|
+
};
|
|
1609
|
+
}
|
|
1610
|
+
} else if (hasNestedReferences(schema)) {
|
|
1611
|
+
config.isReference = true;
|
|
1612
|
+
if (resolveReferences) {
|
|
1613
|
+
config.parser = (valueString) => {
|
|
1614
|
+
return parseValueWithReferences(
|
|
1615
|
+
valueString,
|
|
1616
|
+
schema,
|
|
1617
|
+
refBaseDir,
|
|
1618
|
+
defaultPrimaryKey,
|
|
1619
|
+
options.currentFilePath
|
|
1620
|
+
);
|
|
1621
|
+
};
|
|
1622
|
+
} else {
|
|
1623
|
+
config.parser = (valueString) => {
|
|
1624
|
+
return parseValueWithReferenceIds(valueString, schema);
|
|
1625
|
+
};
|
|
1626
|
+
}
|
|
1627
|
+
}
|
|
1628
|
+
return config;
|
|
1629
|
+
}
|
|
1630
|
+
);
|
|
1631
|
+
for (const decl of reverseReferences) {
|
|
1632
|
+
const config = {
|
|
1633
|
+
name: decl.fieldName,
|
|
1634
|
+
schema: decl.schema,
|
|
1635
|
+
validator: createValidator(decl.schema),
|
|
1636
|
+
parser: (_valueString) => {
|
|
1637
|
+
return null;
|
|
1638
|
+
},
|
|
1639
|
+
isReference: true,
|
|
1640
|
+
isReverseReference: true,
|
|
1641
|
+
referenceTableName: decl.tableName,
|
|
1642
|
+
referenceIsArray: true,
|
|
1643
|
+
reverseReferenceForeignKey: decl.foreignKey
|
|
1644
|
+
};
|
|
1645
|
+
propertyConfigs.push(config);
|
|
1646
|
+
}
|
|
1647
|
+
const references = /* @__PURE__ */ new Set();
|
|
1648
|
+
function collectReferences(schema) {
|
|
1649
|
+
if (schema.type === "reference") {
|
|
1650
|
+
references.add(schema.tableName);
|
|
1651
|
+
} else if (schema.type === "reverseReference") {
|
|
1652
|
+
references.add(schema.tableName);
|
|
1653
|
+
} else if (schema.type === "tuple") {
|
|
1654
|
+
schema.elements.forEach((el) => collectReferences(el.schema));
|
|
1655
|
+
} else if (schema.type === "array") {
|
|
1656
|
+
collectReferences(schema.element);
|
|
1657
|
+
} else if (schema.type === "union") {
|
|
1658
|
+
schema.members.forEach((m) => collectReferences(m));
|
|
1659
|
+
}
|
|
1660
|
+
}
|
|
1661
|
+
propertyConfigs.forEach((config) => {
|
|
1662
|
+
if (config.isReference && config.referenceTableName) {
|
|
1663
|
+
references.add(config.referenceTableName);
|
|
1664
|
+
}
|
|
1665
|
+
collectReferences(config.schema);
|
|
1666
|
+
});
|
|
1667
|
+
const objects = dataRows.map((row, rowIndex) => {
|
|
1668
|
+
const obj = {};
|
|
1669
|
+
propertyConfigs.forEach((config, colIndex) => {
|
|
1670
|
+
if (config.isReverseReference) {
|
|
1671
|
+
return;
|
|
1672
|
+
}
|
|
1673
|
+
const rawValue = row[colIndex] ?? "";
|
|
1674
|
+
try {
|
|
1675
|
+
const parsed = config.parser(rawValue);
|
|
1676
|
+
if (!config.isReference && !config.validator(parsed)) {
|
|
1677
|
+
throw new Error(
|
|
1678
|
+
`Validation failed for property "${config.name}" at row ${rowIndex + 3}: ${rawValue}`
|
|
1679
|
+
);
|
|
1680
|
+
}
|
|
1681
|
+
obj[config.name] = parsed;
|
|
1682
|
+
} catch (error) {
|
|
1683
|
+
if (error instanceof Error) {
|
|
1684
|
+
throw new Error(
|
|
1685
|
+
`Failed to parse property "${config.name}" at row ${rowIndex + 3}, column ${colIndex + 1}: ${error.message}`
|
|
1686
|
+
);
|
|
1687
|
+
}
|
|
1688
|
+
throw error;
|
|
1689
|
+
}
|
|
1690
|
+
});
|
|
1691
|
+
return obj;
|
|
1692
|
+
});
|
|
1693
|
+
if (resolveReferences) {
|
|
1694
|
+
for (const decl of reverseReferences) {
|
|
1695
|
+
for (const obj of objects) {
|
|
1696
|
+
const pkValue = obj[defaultPrimaryKey];
|
|
1697
|
+
if (pkValue !== void 0) {
|
|
1698
|
+
const resolved = resolveReverseReference(
|
|
1699
|
+
decl.schema,
|
|
1700
|
+
pkValue,
|
|
1701
|
+
refBaseDir,
|
|
1702
|
+
defaultPrimaryKey,
|
|
1703
|
+
options.currentFilePath
|
|
1704
|
+
);
|
|
1705
|
+
obj[decl.fieldName] = decl.isOptional && resolved.length === 0 ? null : resolved;
|
|
1706
|
+
} else {
|
|
1707
|
+
obj[decl.fieldName] = decl.isOptional ? null : [];
|
|
1708
|
+
}
|
|
1709
|
+
}
|
|
1710
|
+
}
|
|
1711
|
+
}
|
|
1712
|
+
const referenceFields = [];
|
|
1713
|
+
if (!resolveReferences) {
|
|
1714
|
+
for (const config of propertyConfigs) {
|
|
1715
|
+
if (hasNestedReferences(config.schema)) {
|
|
1716
|
+
referenceFields.push(
|
|
1717
|
+
...collectReferenceFields(config.schema, config.name)
|
|
1718
|
+
);
|
|
1719
|
+
}
|
|
1720
|
+
}
|
|
1721
|
+
}
|
|
1722
|
+
const result = {
|
|
1723
|
+
data: objects,
|
|
1724
|
+
propertyConfigs,
|
|
1725
|
+
references,
|
|
1726
|
+
referenceFields,
|
|
1727
|
+
reverseReferences,
|
|
1728
|
+
typeDeclarations
|
|
1729
|
+
};
|
|
1730
|
+
if (emitTypes) {
|
|
1731
|
+
result.typeDefinition = generateTypeDefinition(
|
|
1732
|
+
options.resourceName || "",
|
|
1733
|
+
propertyConfigs,
|
|
1734
|
+
references,
|
|
1735
|
+
options.currentFilePath,
|
|
1736
|
+
typeDeclarations
|
|
1737
|
+
);
|
|
1738
|
+
}
|
|
1739
|
+
return result;
|
|
1740
|
+
}
|
|
1741
|
+
|
|
1742
|
+
// src/csv-loader/module-gen.ts
|
|
1743
|
+
function generateSchemaResolutionCode(schema, valueExpr, lookupVar, pkField, reverseLookupVar) {
|
|
1744
|
+
switch (schema.type) {
|
|
1745
|
+
case "reference": {
|
|
1746
|
+
const lookup = lookupVar(schema.tableName);
|
|
1747
|
+
if (schema.isOptional) {
|
|
1748
|
+
if (schema.isArray) {
|
|
1749
|
+
return `(${valueExpr} === null || ${valueExpr} === undefined ? ${valueExpr} : (Array.isArray(${valueExpr}) ? ${valueExpr}.map(id => ${lookup}.get(String(id))) : ${lookup}.get(String(${valueExpr}))))`;
|
|
1750
|
+
}
|
|
1751
|
+
return `(${valueExpr} === null || ${valueExpr} === undefined ? ${valueExpr} : ${lookup}.get(String(${valueExpr})))`;
|
|
1752
|
+
}
|
|
1753
|
+
if (schema.isArray) {
|
|
1754
|
+
return `(Array.isArray(${valueExpr}) ? ${valueExpr}.map(id => ${lookup}.get(String(id))) : ${valueExpr})`;
|
|
1755
|
+
}
|
|
1756
|
+
return `${lookup}.get(String(${valueExpr}))`;
|
|
1757
|
+
}
|
|
1758
|
+
case "reverseReference": {
|
|
1759
|
+
if (!reverseLookupVar) return valueExpr;
|
|
1760
|
+
const reverseLookup = reverseLookupVar(
|
|
1761
|
+
schema.tableName,
|
|
1762
|
+
schema.foreignKey
|
|
1763
|
+
);
|
|
1764
|
+
if (schema.isOptional) {
|
|
1765
|
+
return `(${reverseLookup}.get(String(row.${pkField})) || null)`;
|
|
1766
|
+
}
|
|
1767
|
+
return `(${reverseLookup}.get(String(row.${pkField})) || [])`;
|
|
1768
|
+
}
|
|
1769
|
+
case "tuple": {
|
|
1770
|
+
const elementResolvers = schema.elements.map((el, i) => {
|
|
1771
|
+
if (hasNestedReferences(el.schema)) {
|
|
1772
|
+
return generateSchemaResolutionCode(
|
|
1773
|
+
el.schema,
|
|
1774
|
+
`${valueExpr}[${i}]`,
|
|
1775
|
+
lookupVar,
|
|
1776
|
+
pkField,
|
|
1777
|
+
reverseLookupVar
|
|
1778
|
+
);
|
|
1779
|
+
}
|
|
1780
|
+
return `${valueExpr}[${i}]`;
|
|
1781
|
+
});
|
|
1782
|
+
return `[${elementResolvers.join(", ")}]`;
|
|
1783
|
+
}
|
|
1784
|
+
case "array": {
|
|
1785
|
+
if (hasNestedReferences(schema.element)) {
|
|
1786
|
+
const itemResolve = generateSchemaResolutionCode(
|
|
1787
|
+
schema.element,
|
|
1788
|
+
"item",
|
|
1789
|
+
lookupVar,
|
|
1790
|
+
pkField,
|
|
1791
|
+
reverseLookupVar
|
|
1792
|
+
);
|
|
1793
|
+
return `(${valueExpr}).map(item => ${itemResolve})`;
|
|
1794
|
+
}
|
|
1795
|
+
return valueExpr;
|
|
1796
|
+
}
|
|
1797
|
+
case "union": {
|
|
1798
|
+
const refMembers = schema.members.filter((m) => hasNestedReferences(m));
|
|
1799
|
+
const nonRefMembers = schema.members.filter(
|
|
1800
|
+
(m) => !hasNestedReferences(m)
|
|
1801
|
+
);
|
|
1802
|
+
const resolveParts = [];
|
|
1803
|
+
for (const member of refMembers) {
|
|
1804
|
+
const resolveCode = generateSchemaResolutionCode(
|
|
1805
|
+
member,
|
|
1806
|
+
valueExpr,
|
|
1807
|
+
lookupVar,
|
|
1808
|
+
pkField,
|
|
1809
|
+
reverseLookupVar
|
|
1810
|
+
);
|
|
1811
|
+
resolveParts.push(resolveCode);
|
|
1812
|
+
}
|
|
1813
|
+
if (nonRefMembers.length > 0) {
|
|
1814
|
+
resolveParts.push(valueExpr);
|
|
1815
|
+
}
|
|
1816
|
+
if (resolveParts.length === 0) return valueExpr;
|
|
1817
|
+
if (resolveParts.length === 1) return resolveParts[0];
|
|
1818
|
+
return `(${resolveParts.join(" ?? ")})`;
|
|
1819
|
+
}
|
|
1820
|
+
default:
|
|
1821
|
+
return valueExpr;
|
|
1822
|
+
}
|
|
1823
|
+
}
|
|
1824
|
+
function csvToModule(content, options = {}) {
|
|
1825
|
+
const result = parseCsv(content, { ...options, resolveReferences: false });
|
|
1826
|
+
const hasRefs = result.referenceFields.length > 0 || result.reverseReferences.length > 0;
|
|
1827
|
+
const defaultPrimaryKey = options.defaultPrimaryKey ?? "id";
|
|
1828
|
+
const imports = [];
|
|
1829
|
+
const lookupInits = [];
|
|
1830
|
+
const lookupVarMap = /* @__PURE__ */ new Map();
|
|
1831
|
+
const reverseLookupInits = [];
|
|
1832
|
+
const reverseLookupVarMap = /* @__PURE__ */ new Map();
|
|
1833
|
+
const currentTableName = options.currentFilePath ? path3.basename(
|
|
1834
|
+
options.currentFilePath,
|
|
1835
|
+
path3.extname(options.currentFilePath)
|
|
1836
|
+
) : void 0;
|
|
1837
|
+
const uniqueTables = new Set(result.referenceFields.map((f) => f.tableName));
|
|
1838
|
+
for (const decl of result.reverseReferences) {
|
|
1839
|
+
uniqueTables.add(decl.tableName);
|
|
1840
|
+
}
|
|
1841
|
+
uniqueTables.forEach((tableName) => {
|
|
1842
|
+
const lookupVar2 = `_${tableName}Lookup`;
|
|
1843
|
+
lookupVarMap.set(tableName, lookupVar2);
|
|
1844
|
+
if (tableName === currentTableName) {
|
|
1845
|
+
lookupInits.push(
|
|
1846
|
+
`const ${lookupVar2} = new Map(_raw.map(p => [String(p.${defaultPrimaryKey}), p]));`
|
|
1847
|
+
);
|
|
1848
|
+
} else {
|
|
1849
|
+
const varName = `_${tableName}`;
|
|
1850
|
+
imports.push(`import ${varName} from './${tableName}.csv';`);
|
|
1851
|
+
lookupInits.push(
|
|
1852
|
+
`const ${lookupVar2} = new Map(${varName}().map(p => [String(p.${defaultPrimaryKey}), p]));`
|
|
1853
|
+
);
|
|
1854
|
+
}
|
|
1855
|
+
});
|
|
1856
|
+
for (const decl of result.reverseReferences) {
|
|
1857
|
+
const key = `${decl.tableName}:${decl.foreignKey}`;
|
|
1858
|
+
if (reverseLookupVarMap.has(key)) continue;
|
|
1859
|
+
const revLookupVar = `_${decl.tableName}By_${decl.foreignKey}`;
|
|
1860
|
+
reverseLookupVarMap.set(key, revLookupVar);
|
|
1861
|
+
if (decl.tableName === currentTableName) {
|
|
1862
|
+
reverseLookupInits.push(
|
|
1863
|
+
`const ${revLookupVar} = new Map();`,
|
|
1864
|
+
`for (const r of _raw) {`,
|
|
1865
|
+
` const kv = r.${decl.foreignKey};`,
|
|
1866
|
+
` const k = String(typeof kv === "object" && "${defaultPrimaryKey}" in kv ? kv.${defaultPrimaryKey} : kv);`,
|
|
1867
|
+
` if (!${revLookupVar}.has(k)) ${revLookupVar}.set(k, []);`,
|
|
1868
|
+
` ${revLookupVar}.get(k).push(r);`,
|
|
1869
|
+
`}`
|
|
1870
|
+
);
|
|
1871
|
+
} else {
|
|
1872
|
+
const varName = `_${decl.tableName}`;
|
|
1873
|
+
reverseLookupInits.push(
|
|
1874
|
+
`const ${revLookupVar} = new Map();`,
|
|
1875
|
+
`for (const r of ${varName}()) {`,
|
|
1876
|
+
` const kv = r.${decl.foreignKey};`,
|
|
1877
|
+
` const k = String(typeof kv === "object" && "${defaultPrimaryKey}" in kv ? kv.${defaultPrimaryKey} : kv);`,
|
|
1878
|
+
` if (!${revLookupVar}.has(k)) ${revLookupVar}.set(k, []);`,
|
|
1879
|
+
` ${revLookupVar}.get(k).push(r);`,
|
|
1880
|
+
`}`
|
|
1881
|
+
);
|
|
1882
|
+
}
|
|
1883
|
+
}
|
|
1884
|
+
const lookupVar = (tableName) => lookupVarMap.get(tableName);
|
|
1885
|
+
const reverseLookupVar = (tableName, foreignKey) => reverseLookupVarMap.get(`${tableName}:${foreignKey}`);
|
|
1886
|
+
const rowResolvers = [];
|
|
1887
|
+
for (const config of result.propertyConfigs) {
|
|
1888
|
+
if (config.isReverseReference) {
|
|
1889
|
+
const decl = result.reverseReferences.find(
|
|
1890
|
+
(d) => d.fieldName === config.name
|
|
1891
|
+
);
|
|
1892
|
+
if (decl) {
|
|
1893
|
+
const revLookup = reverseLookupVar(decl.tableName, decl.foreignKey);
|
|
1894
|
+
if (decl.isOptional) {
|
|
1895
|
+
rowResolvers.push({
|
|
1896
|
+
name: config.name,
|
|
1897
|
+
code: `(${revLookup}.get(String(row.${defaultPrimaryKey})) || null)`
|
|
1898
|
+
});
|
|
1899
|
+
} else {
|
|
1900
|
+
rowResolvers.push({
|
|
1901
|
+
name: config.name,
|
|
1902
|
+
code: `(${revLookup}.get(String(row.${defaultPrimaryKey})) || [])`
|
|
1903
|
+
});
|
|
1904
|
+
}
|
|
1905
|
+
}
|
|
1906
|
+
} else if (hasNestedReferences(config.schema)) {
|
|
1907
|
+
const resolveCode = generateSchemaResolutionCode(
|
|
1908
|
+
config.schema,
|
|
1909
|
+
`row.${config.name}`,
|
|
1910
|
+
lookupVar,
|
|
1911
|
+
defaultPrimaryKey,
|
|
1912
|
+
reverseLookupVar
|
|
1913
|
+
);
|
|
1914
|
+
rowResolvers.push({ name: config.name, code: resolveCode });
|
|
1915
|
+
}
|
|
1916
|
+
}
|
|
1917
|
+
const rawJson = JSON.stringify(result.data, null, 2);
|
|
1918
|
+
const js = [
|
|
1919
|
+
...imports,
|
|
1920
|
+
"",
|
|
1921
|
+
`const _raw = ${rawJson};`,
|
|
1922
|
+
"",
|
|
1923
|
+
"let _resolved = null;",
|
|
1924
|
+
"",
|
|
1925
|
+
"export default function getData() {",
|
|
1926
|
+
" if (_resolved) return _resolved;",
|
|
1927
|
+
" _resolved = _raw;",
|
|
1928
|
+
...lookupInits.map((l) => ` ${l}`),
|
|
1929
|
+
...reverseLookupInits.map((l) => ` ${l}`),
|
|
1930
|
+
...rowResolvers.length > 0 ? [
|
|
1931
|
+
" _resolved = _raw.map(row => {",
|
|
1932
|
+
...rowResolvers.map((r) => ` row.${r.name} = ${r.code};`),
|
|
1933
|
+
" return row;",
|
|
1934
|
+
" });"
|
|
1935
|
+
] : [],
|
|
1936
|
+
" return _resolved;",
|
|
1937
|
+
"}"
|
|
1938
|
+
].join("\n");
|
|
1939
|
+
return {
|
|
1940
|
+
js,
|
|
1941
|
+
dts: result.typeDefinition
|
|
1942
|
+
};
|
|
1943
|
+
}
|
|
1944
|
+
|
|
1945
|
+
// src/csv-loader/esbuild.ts
|
|
1946
|
+
function createFilter(pattern) {
|
|
1947
|
+
if (pattern instanceof RegExp) return pattern;
|
|
1948
|
+
if (Array.isArray(pattern)) {
|
|
1949
|
+
const first = pattern[0];
|
|
1950
|
+
return first instanceof RegExp ? first : new RegExp(first);
|
|
1951
|
+
}
|
|
1952
|
+
return new RegExp(pattern);
|
|
1953
|
+
}
|
|
1954
|
+
function matchesPattern(id, pattern) {
|
|
1955
|
+
if (!pattern) return true;
|
|
1956
|
+
const patterns = Array.isArray(pattern) ? pattern : [pattern];
|
|
1957
|
+
return patterns.some((p) => {
|
|
1958
|
+
if (p instanceof RegExp) return p.test(id);
|
|
1959
|
+
return id.includes(p);
|
|
1960
|
+
});
|
|
1961
|
+
}
|
|
1962
|
+
function csvLoader(options = {}) {
|
|
1963
|
+
const {
|
|
1964
|
+
include = /\.csv$/,
|
|
1965
|
+
exclude,
|
|
1966
|
+
emitTypes = true,
|
|
1967
|
+
typesOutputDir = "",
|
|
1968
|
+
writeToDisk = false,
|
|
1969
|
+
...parseOptions
|
|
1970
|
+
} = options;
|
|
1971
|
+
const includeFilter = createFilter(include);
|
|
1972
|
+
return {
|
|
1973
|
+
name: "typed-csv",
|
|
1974
|
+
setup(build) {
|
|
1975
|
+
build.onLoad({ filter: includeFilter }, async (args) => {
|
|
1976
|
+
if (exclude && !matchesPattern(args.path, exclude)) {
|
|
1977
|
+
return null;
|
|
1978
|
+
}
|
|
1979
|
+
let content;
|
|
1980
|
+
try {
|
|
1981
|
+
content = await fs2.promises.readFile(args.path, "utf-8");
|
|
1982
|
+
} catch (error) {
|
|
1983
|
+
return {
|
|
1984
|
+
errors: [{ text: `Failed to read file: ${args.path}` }]
|
|
1985
|
+
};
|
|
1986
|
+
}
|
|
1987
|
+
const fileName = path4.basename(args.path, ".csv").split(".")[0];
|
|
1988
|
+
const resourceName = fileName.replace(
|
|
1989
|
+
/[-_\s]+(.)?/g,
|
|
1990
|
+
(_, char) => char ? char.toUpperCase() : ""
|
|
1991
|
+
).replace(/^(.)/, (_, char) => char.toUpperCase());
|
|
1992
|
+
const result = csvToModule(content, {
|
|
1993
|
+
...parseOptions,
|
|
1994
|
+
emitTypes,
|
|
1995
|
+
resourceName,
|
|
1996
|
+
currentFilePath: args.path,
|
|
1997
|
+
refBaseDir: options.refBaseDir,
|
|
1998
|
+
defaultPrimaryKey: options.defaultPrimaryKey
|
|
1999
|
+
});
|
|
2000
|
+
if (emitTypes && result.dts) {
|
|
2001
|
+
const dtsPath = typesOutputDir ? path4.join(typesOutputDir, path4.basename(args.path) + ".d.ts") : args.path + ".d.ts";
|
|
2002
|
+
if (writeToDisk) {
|
|
2003
|
+
const absolutePath = path4.isAbsolute(dtsPath) ? dtsPath : path4.join(process.cwd(), dtsPath);
|
|
2004
|
+
fs2.mkdirSync(path4.dirname(absolutePath), { recursive: true });
|
|
2005
|
+
fs2.writeFileSync(absolutePath, result.dts);
|
|
2006
|
+
}
|
|
2007
|
+
}
|
|
2008
|
+
return {
|
|
2009
|
+
contents: result.js,
|
|
2010
|
+
loader: "js"
|
|
2011
|
+
};
|
|
2012
|
+
});
|
|
2013
|
+
}
|
|
2014
|
+
};
|
|
2015
|
+
}
|
|
2016
|
+
var esbuild_default = csvLoader;
|
|
2017
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
2018
|
+
0 && (module.exports = {
|
|
2019
|
+
csvLoader
|
|
2020
|
+
});
|