config2ts 2.5.4 → 2.5.6

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
@@ -27,6 +27,7 @@ config2ts -d config -o dist -n csv.ts -a public
27
27
  | RefEnum | namespace.type |
28
28
  | RefEnum[] | namespace.type[] |
29
29
  | Object | type (Record) |
30
+ | Object[] | type[] (Record[]) |
30
31
 
31
32
  * `Number` support Infinity and NaN
32
33
  * `Enum` support empty string type
@@ -34,6 +35,9 @@ config2ts -d config -o dist -n csv.ts -a public
34
35
  * `EnumIndex` will generate index type, and will use `Enum` type to generate interface
35
36
  * `Ref` / `RefEnum` reference another csv's Record/type by id
36
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[]` parse `key:value,key:value;key:value,key:value` format (`;` separates objects, `,` separates key-value pairs), empty value generates `[]`, generates a dedicated element `type` with the field typed as `type[]`
39
+ * Array empty-data convention (`String[]`/`Number[]`/`Enum[]`/`RefEnum[...] []`/`Object[]`): an empty cell generates `[]`; empty segments from stray, leading or trailing separators (e.g. `"a,,b"`, `"1,,3"`, `"x:1;;y:2"`) are skipped — no phantom `""`, `0` or `{}` elements
40
+ * unrecognized field types fall back to `string` and print a warning (check for typos)
37
41
 
38
42
  ## assets2ts
39
43
 
package/lib/config2ts.js CHANGED
@@ -50,6 +50,7 @@ const EnumIndexStr = "EnumIndex";
50
50
  const EnumArrayString = "Enum[]";
51
51
  const IndexStr = "Index";
52
52
  const ObjectStr = "Object";
53
+ const ObjectArrayString = "Object[]";
53
54
  const RefPrefix = "Ref[";
54
55
  const RefSuffix = "]";
55
56
  const RefEnumPrefix = "RefEnum[";
@@ -82,6 +83,9 @@ function csv2ts(csvString, moduleName) {
82
83
  if (parseRefEnum(convert[k])) {
83
84
  refEnumFields.push(k);
84
85
  }
86
+ if (!isKnownType(convert[k])) {
87
+ console.warn(`[config2ts] warning: ${moduleName} field "${k}" has unrecognized type "${convert[k]}", values will be treated as string`);
88
+ }
85
89
  }
86
90
  return null;
87
91
  }
@@ -90,27 +94,17 @@ function csv2ts(csvString, moduleName) {
90
94
  if (convert[k] === ObjectStr) {
91
95
  d[k] = parseObject(d[k]);
92
96
  }
97
+ else if (convert[k] === ObjectArrayString) {
98
+ d[k] = parseObjectArray(d[k]);
99
+ }
93
100
  else if (typeof global[convert[k]] === "function") {
94
101
  d[k] = global[convert[k]](d[k]);
95
102
  }
96
- else if (convert[k] === "String[]") {
97
- if (d[k] === "") {
98
- d[k] = [];
99
- }
100
- else {
101
- d[k] = d[k].trim().split(",").map((v) => v.trim());
102
- }
103
+ else if (convert[k] === "String[]" || convert[k] === "Enum[]") {
104
+ d[k] = splitArrayValues(d[k]);
103
105
  }
104
106
  else if (convert[k] === "Number[]") {
105
- d[k] = d[k].trim().split(",").map((val) => Number(val));
106
- }
107
- else if (convert[k] === "Enum[]") {
108
- if (d[k] === "") {
109
- d[k] = [];
110
- }
111
- else {
112
- d[k] = d[k].trim().split(",").map((v) => v.trim());
113
- }
107
+ d[k] = splitArrayValues(d[k]).map((val) => Number(val));
114
108
  }
115
109
  else if (convert[k].startsWith(RefPrefix) && convert[k].endsWith(RefSuffix)) {
116
110
  if (d[k] === "") {
@@ -120,12 +114,7 @@ function csv2ts(csvString, moduleName) {
120
114
  else if (parseRefEnum(convert[k])) {
121
115
  const refEnum = parseRefEnum(convert[k]);
122
116
  if (refEnum.isArray) {
123
- if (d[k] === "") {
124
- d[k] = [];
125
- }
126
- else {
127
- d[k] = d[k].trim().split(",").map((v) => v.trim());
128
- }
117
+ d[k] = splitArrayValues(d[k]);
129
118
  }
130
119
  else {
131
120
  if (d[k] === "") {
@@ -172,15 +161,18 @@ function csv2ts(csvString, moduleName) {
172
161
  template += ` export type ${field} = ${enumValueStrings.join(" | ")};\n`;
173
162
  template += ` export const ${field}List: ${field}[] = [${enumValueStrings.join(", ")}];\n\n`;
174
163
  }
175
- else if (convert[field] == ObjectStr) {
164
+ else if (convert[field] == ObjectStr || convert[field] == ObjectArrayString) {
176
165
  const keyTypes = {};
166
+ const isArray = convert[field] == ObjectArrayString;
177
167
  for (const row of result) {
178
- const objValue = row[field];
179
- for (const key in objValue) {
180
- if (!keyTypes[key]) {
181
- keyTypes[key] = new Set();
168
+ const objValues = isArray ? row[field] : [row[field]];
169
+ for (const objValue of objValues) {
170
+ for (const key in objValue) {
171
+ if (!keyTypes[key]) {
172
+ keyTypes[key] = new Set();
173
+ }
174
+ keyTypes[key].add(getTypeName(objValue[key]));
182
175
  }
183
- keyTypes[key].add(getTypeName(objValue[key]));
184
176
  }
185
177
  }
186
178
  template += ` export type ${field} = {\n`;
@@ -212,6 +204,9 @@ function csv2ts(csvString, moduleName) {
212
204
  else if (convert[field] == ObjectStr) {
213
205
  fieldType = field;
214
206
  }
207
+ else if (convert[field] == ObjectArrayString) {
208
+ fieldType = field + "[]";
209
+ }
215
210
  else if (convert[field].startsWith(RefPrefix) && convert[field].endsWith(RefSuffix)) {
216
211
  const refModule = convert[field].slice(RefPrefix.length, -RefSuffix.length);
217
212
  const refModuleName = changeCase.pascalCase(refModule);
@@ -291,6 +286,22 @@ function parseObject(str) {
291
286
  }
292
287
  return result;
293
288
  }
289
+ function parseObjectArray(str) {
290
+ return str
291
+ .split(";")
292
+ .map((part) => part.trim())
293
+ .filter((part) => part !== "")
294
+ .map((part) => parseObject(part));
295
+ }
296
+ // Split a comma-separated array cell, trimming and dropping empty segments
297
+ // so stray/leading/trailing commas never produce phantom elements.
298
+ // An empty cell resolves to an empty array.
299
+ function splitArrayValues(str) {
300
+ return str
301
+ .split(",")
302
+ .map((v) => v.trim())
303
+ .filter((v) => v !== "");
304
+ }
294
305
  function parseObjectValue(value) {
295
306
  if (value === "true")
296
307
  return true;
@@ -311,6 +322,25 @@ function getTypeName(value) {
311
322
  return "boolean";
312
323
  return "string";
313
324
  }
325
+ function isKnownType(typeStr) {
326
+ if (typeStr === "") {
327
+ return true;
328
+ }
329
+ const knownTypes = [EnumStr, EnumIndexStr, EnumArrayString, IndexStr, ObjectStr, ObjectArrayString, "String[]", "Number[]"];
330
+ if (knownTypes.includes(typeStr)) {
331
+ return true;
332
+ }
333
+ if (typeStr.startsWith(RefPrefix) && typeStr.endsWith(RefSuffix)) {
334
+ return true;
335
+ }
336
+ if (parseRefEnum(typeStr)) {
337
+ return true;
338
+ }
339
+ if (typeof global[typeStr] === "function") {
340
+ return true;
341
+ }
342
+ return false;
343
+ }
314
344
  function parseRefEnum(typeStr) {
315
345
  if (typeStr.startsWith(RefEnumPrefix)) {
316
346
  let isArray = false;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "config2ts",
3
- "version": "2.5.4",
4
- "description": "convert config to ts file.",
3
+ "version": "2.5.6",
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",
7
7
  "bin": {