config2ts 2.5.8 → 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 CHANGED
@@ -33,7 +33,7 @@ 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/type by id
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
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
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
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 (convert[k].startsWith(RefPrefix) && convert[k].endsWith(RefSuffix)) {
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 (convert[k].startsWith(RefPrefix) && convert[k].endsWith(RefSuffix)) {
111
- if (d[k] === "") {
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 (convert[field].startsWith(RefPrefix) && convert[field].endsWith(RefSuffix)) {
212
- const refModule = convert[field].slice(RefPrefix.length, -RefSuffix.length);
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 (convert[field].startsWith(RefPrefix) && convert[field].endsWith(RefSuffix)) {
245
- const refModule = convert[field].slice(RefPrefix.length, -RefSuffix.length);
246
- const refModuleName = changeCase.pascalCase(refModule);
247
- template += ` ${serializeField(field)}: ${refModuleName}.Map[${JSON.stringify(value)}],\n`;
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`;
@@ -344,7 +358,7 @@ function isKnownType(typeStr) {
344
358
  if (knownTypes.includes(typeStr)) {
345
359
  return true;
346
360
  }
347
- if (typeStr.startsWith(RefPrefix) && typeStr.endsWith(RefSuffix)) {
361
+ if (parseRef(typeStr)) {
348
362
  return true;
349
363
  }
350
364
  if (parseRefEnum(typeStr)) {
@@ -355,6 +369,26 @@ function isKnownType(typeStr) {
355
369
  }
356
370
  return false;
357
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
+ }
358
392
  function parseRefEnum(typeStr) {
359
393
  if (typeStr.startsWith(RefEnumPrefix)) {
360
394
  let isArray = false;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "config2ts",
3
- "version": "2.5.8",
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",