config2ts 2.5.7 → 2.5.9
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 +3 -3
- package/lib/config2ts.js +57 -16
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -33,10 +33,10 @@ config2ts -d config -o dist -n csv.ts -a public
|
|
|
33
33
|
* `Enum` support empty string type
|
|
34
34
|
* `Enum[]` union contains every value actually present in the data (including `""` for empty slots)
|
|
35
35
|
* `EnumIndex` will generate index type, and will use `Enum` type to generate interface
|
|
36
|
-
* `Ref` / `RefEnum` reference another csv's Record/
|
|
36
|
+
* `Ref` / `RefEnum` reference another csv's Record/enum by id: `Ref[file]` is one row (`file.Map["id"]`), `Ref[file][]` is an array of rows with comma-separated ids (`[file.Map["1"],file.Map["2"]]`, typed `File.Record[]`); use `Object[]` for inline private structures and `Ref[]` for shared, identity-bearing rows
|
|
37
37
|
* `Object` parse `key:value,key:value` format, auto-infer value types (number/boolean/string), generates a dedicated `type` that merges all keys
|
|
38
|
-
* `Object[]`
|
|
39
|
-
* Array convention (`String[]`/`Number[]`/`Enum[]`/`RefEnum[...] []
|
|
38
|
+
* `Object[]` separates objects with `;` while commas still separate `key:value` pairs inside each object (same syntax as the `Object` type), e.g. `num:1,,str:a;num:2` makes `[{num:1,str:'a'},{num:2}]`, a bare `;` makes `[{},{}]`; generates a dedicated element `type` merging all keys with the field typed as `type[]`
|
|
39
|
+
* Array convention: primitive arrays (`String[]`/`Number[]`/`Enum[]`/`RefEnum[...] []`) separate elements with `,` and `Object[]` separates objects with `;`; raw cell values are normalized (line breaks removed, whitespace trimmed); an empty cell generates `[]`; otherwise n separators make n+1 slots and every slot is kept (including interior or trailing ones) so parallel arrays stay index-aligned. Empty slots use the type's own zero value — `''` for string/enum/ref-enum, `0` for number, `{}` for empty object slots; `null` is never generated
|
|
40
40
|
* unrecognized field types fall back to `string` and print a warning (check for typos)
|
|
41
41
|
|
|
42
42
|
## assets2ts
|
package/lib/config2ts.js
CHANGED
|
@@ -77,7 +77,7 @@ function csv2ts(csvString, moduleName) {
|
|
|
77
77
|
if (i === 0) {
|
|
78
78
|
convert = d;
|
|
79
79
|
for (const k in convert) {
|
|
80
|
-
if (
|
|
80
|
+
if (parseRef(convert[k])) {
|
|
81
81
|
refFields.push(k);
|
|
82
82
|
}
|
|
83
83
|
if (parseRefEnum(convert[k])) {
|
|
@@ -107,8 +107,16 @@ function csv2ts(csvString, moduleName) {
|
|
|
107
107
|
else if (convert[k] === "Number[]") {
|
|
108
108
|
d[k] = splitStringArray(d[k]).map((val) => Number(val));
|
|
109
109
|
}
|
|
110
|
-
else if (
|
|
111
|
-
|
|
110
|
+
else if (parseRef(convert[k])) {
|
|
111
|
+
const ref = parseRef(convert[k]);
|
|
112
|
+
if (ref.isArray) {
|
|
113
|
+
const ids = splitStringArray(d[k]);
|
|
114
|
+
d[k] = ids;
|
|
115
|
+
if (ids.includes("")) {
|
|
116
|
+
console.warn(`[config2ts] warning: ${moduleName} row ${i} field "${k}" ref array contains an empty id`);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
else if (d[k] === "") {
|
|
112
120
|
console.warn(`[config2ts] warning: ${moduleName} row ${i} field "${k}" ref value is empty`);
|
|
113
121
|
}
|
|
114
122
|
}
|
|
@@ -208,10 +216,10 @@ function csv2ts(csvString, moduleName) {
|
|
|
208
216
|
else if (convert[field] == ObjectArrayString) {
|
|
209
217
|
fieldType = field + "[]";
|
|
210
218
|
}
|
|
211
|
-
else if (
|
|
212
|
-
const
|
|
213
|
-
const refModuleName = changeCase.pascalCase(refModule);
|
|
214
|
-
fieldType = `${refModuleName}.Record`;
|
|
219
|
+
else if (parseRef(convert[field])) {
|
|
220
|
+
const ref = parseRef(convert[field]);
|
|
221
|
+
const refModuleName = changeCase.pascalCase(ref.refModule);
|
|
222
|
+
fieldType = ref.isArray ? `${refModuleName}.Record[]` : `${refModuleName}.Record`;
|
|
215
223
|
}
|
|
216
224
|
else if (parseRefEnum(convert[field])) {
|
|
217
225
|
const refEnum = parseRefEnum(convert[field]);
|
|
@@ -241,10 +249,16 @@ function csv2ts(csvString, moduleName) {
|
|
|
241
249
|
template += " {\n";
|
|
242
250
|
for (const field in convert) {
|
|
243
251
|
let value = row[field];
|
|
244
|
-
if (
|
|
245
|
-
const
|
|
246
|
-
const refModuleName = changeCase.pascalCase(refModule);
|
|
247
|
-
|
|
252
|
+
if (parseRef(convert[field])) {
|
|
253
|
+
const ref = parseRef(convert[field]);
|
|
254
|
+
const refModuleName = changeCase.pascalCase(ref.refModule);
|
|
255
|
+
if (ref.isArray) {
|
|
256
|
+
const refs = value.map((id) => `${refModuleName}.Map[${JSON.stringify(id)}]`).join(",");
|
|
257
|
+
template += ` ${serializeField(field)}: [${refs}],\n`;
|
|
258
|
+
}
|
|
259
|
+
else {
|
|
260
|
+
template += ` ${serializeField(field)}: ${refModuleName}.Map[${JSON.stringify(value)}],\n`;
|
|
261
|
+
}
|
|
248
262
|
}
|
|
249
263
|
else {
|
|
250
264
|
template += ` ${serializeField(field)}: ${json5.stringify(value)},\n`;
|
|
@@ -292,22 +306,29 @@ function parseObject(str) {
|
|
|
292
306
|
function normalizeCell(str) {
|
|
293
307
|
return String(str).replace(/\r\n?|\n/g, "").trim();
|
|
294
308
|
}
|
|
295
|
-
// Split a comma-separated array cell: n commas make n+1 slots and every
|
|
296
|
-
// is kept (including an interior or trailing empty one), so parallel arrays
|
|
309
|
+
// Split a comma-separated primitive-array cell: n commas make n+1 slots and every
|
|
310
|
+
// slot is kept (including an interior or trailing empty one), so parallel arrays
|
|
297
311
|
// stay index-aligned. Empty slots follow the element's own parsing rule
|
|
298
|
-
// ('' for strings/enums, 0 for numbers
|
|
312
|
+
// ('' for strings/enums, 0 for numbers); null is never emitted.
|
|
299
313
|
// An empty cell resolves to an empty array.
|
|
314
|
+
// Note: Object[] uses semicolons as element separator (see parseObjectArray),
|
|
315
|
+
// because commas already separate key:value pairs inside an object.
|
|
300
316
|
function splitStringArray(str) {
|
|
301
317
|
if (str === "") {
|
|
302
318
|
return [];
|
|
303
319
|
}
|
|
304
320
|
return str.split(",").map((v) => v.trim());
|
|
305
321
|
}
|
|
322
|
+
// Object[] separates objects with semicolons (commas are reserved for the
|
|
323
|
+
// key:value pairs inside an object, same syntax as the Object type); each
|
|
324
|
+
// semicolon slot is parsed by the same object rule, so stray empty pairs within
|
|
325
|
+
// an object (e.g. "num:1,,str:a") are ignored while an empty object slot between
|
|
326
|
+
// semicolons (e.g. "a:1;;b:2") becomes an empty object placeholder.
|
|
306
327
|
function parseObjectArray(str) {
|
|
307
328
|
if (str === "") {
|
|
308
329
|
return [];
|
|
309
330
|
}
|
|
310
|
-
return str.split("
|
|
331
|
+
return str.split(";").map((part) => parseObject(part));
|
|
311
332
|
}
|
|
312
333
|
function parseObjectValue(value) {
|
|
313
334
|
if (value === "true")
|
|
@@ -337,7 +358,7 @@ function isKnownType(typeStr) {
|
|
|
337
358
|
if (knownTypes.includes(typeStr)) {
|
|
338
359
|
return true;
|
|
339
360
|
}
|
|
340
|
-
if (
|
|
361
|
+
if (parseRef(typeStr)) {
|
|
341
362
|
return true;
|
|
342
363
|
}
|
|
343
364
|
if (parseRefEnum(typeStr)) {
|
|
@@ -348,6 +369,26 @@ function isKnownType(typeStr) {
|
|
|
348
369
|
}
|
|
349
370
|
return false;
|
|
350
371
|
}
|
|
372
|
+
// Parse Ref[module] (single) and Ref[module][] (array of row references).
|
|
373
|
+
// Note: "RefEnum[...]" starts with "RefE", so it never collides with "Ref[".
|
|
374
|
+
function parseRef(typeStr) {
|
|
375
|
+
if (!typeStr.startsWith(RefPrefix)) {
|
|
376
|
+
return null;
|
|
377
|
+
}
|
|
378
|
+
let isArray = false;
|
|
379
|
+
let inner = typeStr;
|
|
380
|
+
if (typeStr.endsWith(RefEnumArraySuffix)) {
|
|
381
|
+
isArray = true;
|
|
382
|
+
inner = typeStr.slice(0, -RefEnumArraySuffix.length) + RefSuffix;
|
|
383
|
+
}
|
|
384
|
+
if (inner.startsWith(RefPrefix) && inner.endsWith(RefSuffix)) {
|
|
385
|
+
const refModule = inner.slice(RefPrefix.length, -RefSuffix.length);
|
|
386
|
+
if (refModule !== "") {
|
|
387
|
+
return { refModule, isArray };
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
return null;
|
|
391
|
+
}
|
|
351
392
|
function parseRefEnum(typeStr) {
|
|
352
393
|
if (typeStr.startsWith(RefEnumPrefix)) {
|
|
353
394
|
let isArray = false;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "config2ts",
|
|
3
|
-
"version": "2.5.
|
|
3
|
+
"version": "2.5.9",
|
|
4
4
|
"description": "Generate type-safe TypeScript from CSV/INI/TOML config tables — inferred types, enums, cross-table references, and a typed asset index, all from one CLI command.",
|
|
5
5
|
"main": "lib/config2ts.js",
|
|
6
6
|
"types": "lib/config2ts.d.ts",
|