config2ts 2.8.1 → 2.9.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 CHANGED
@@ -6,9 +6,72 @@ convert config to ts file.
6
6
 
7
7
  run command: `npm install -g config2ts`
8
8
 
9
- # how to use
9
+ # documentation
10
10
 
11
- config2ts -d config -o dist -n csv.ts -a public
11
+ Full documentation is published via GitHub Pages (this repo has Pages enabled):
12
+
13
+ - English: https://livingyang.github.io/config2ts/
14
+ - 中文: https://livingyang.github.io/config2ts/index-zh.html
15
+
16
+ # usage
17
+
18
+ `config2ts` supports two output modes selected by `-m, --mode`:
19
+
20
+ - `single` (default): merge every table into one file (`-n`, default `csv.ts`).
21
+ - `split`: write one `.ts` file per table plus an auto-generated `index.ts`.
22
+
23
+ This repo's `config/` folder ships example outputs generated from the same source
24
+ tables, so you can compare both layouts directly:
25
+
26
+ - single mode example: [`config/total.ts`](config/total.ts)
27
+ - split mode example: [`config/split/`](config/split/) (one file per table + `index.ts`)
28
+
29
+ ## single mode
30
+
31
+ Merge all config tables into a single TypeScript file.
32
+
33
+ ```bash
34
+ config2ts -d config -o dist -m single -n csv.ts -a public
35
+ ```
36
+
37
+ - `-n` is the merged output file name (default `csv.ts`).
38
+ - `-a` is optional; omit it to skip `assets.ts`.
39
+ - Example output: [`config/total.ts`](config/total.ts) — all tables as `export namespace XxxCsv { ... }` in one file.
40
+
41
+ ## split mode
42
+
43
+ Write one `.ts` file per config table (named after the source file, e.g.
44
+ `skill.csv` → `skill.ts`) plus an auto-generated `index.ts` that re-exports every
45
+ table and `assets.ts`. Cross-table `Ref`/`RefEnum`/`Template` references are
46
+ resolved with `import` statements injected at the top of the referencing file, so
47
+ every table is independently usable and tree-shakable.
48
+
49
+ ```bash
50
+ config2ts -d config -o dist -m split -a public
51
+ ```
52
+
53
+ - `-n` is reused as the index file name; the single-mode default `csv.ts` is
54
+ replaced by `index.ts` unless you pass `-n` explicitly.
55
+ - `-a` is optional; omit it to skip `assets.ts`.
56
+ - Example output: [`config/split/`](config/split/) — `z-base.ts`, `a-user.ts`,
57
+ `skill.ts`, … , `assets.ts`, and `index.ts`.
58
+
59
+ Output layout under `dist`:
60
+
61
+ ```
62
+ dist/
63
+ z-base.ts # export namespace ZBaseCsv { ... }
64
+ a-user.ts # import { ZBaseCsv } from "./z-base"; export namespace AUserCsv { ... }
65
+ skill.ts
66
+ ...
67
+ assets.ts # generated only when -a is given
68
+ index.ts # export * from "./z-base"; export * from "./a-user"; ...; export * from "./assets";
69
+ ```
70
+
71
+ Notes:
72
+ - Tables are emitted in topological order; a table only `import`s tables it
73
+ actually references, and missing/circular references print the same warnings as
74
+ single mode.
12
75
 
13
76
  # support type
14
77
 
@@ -36,7 +99,7 @@ config2ts -d config -o dist -n csv.ts -a public
36
99
  * `Enum[]` union contains every value actually present in the data (including `""` for empty slots)
37
100
  * `EnumIndex` will generate index type, and will use `Enum` type to generate interface
38
101
  * `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
39
- * `Template[file]` inherits a whole row from another table and overrides selected fields: a cell is `<baseId>|<key>:<value>,<key>:<value>` — a pipe separates the base row id from override pairs (e.g. `101|damage:150,range:8`), emitting `{ ...file.Map["101"], damage: 150, range: 8 }` typed `File.Record`; with no overrides the cell is just the id and emits a plain `file.Map["id"]` like `Ref`. Override values may be bare scalars or bracket-wrapped composites mirroring the generated TS syntax — arrays as `[v1,v2]` (e.g. `Params:[6,2.07]`, required for array-typed fields; a bare `Params:6,2.07` gets chopped by the pair comma and prints a warning) and flat objects as `{k:v,k:v}`. `Template[file][]` separates entries with `;` (the same element separator as `Object[]`), e.g. `101|damage:150;102|heal:500` emits `[{ ...file.Map["101"], damage: 150 },{ ...file.Map["102"], heal: 500 }]`. Override key typos and value-type mismatches fail at tsc compile time; overrides are flat top-level fields (no dot-path deep merge), and the target table must have an Index/EnumIndex Map
102
+ * `Template[file]` inherits a whole row from another table and overrides selected fields: a cell is `<baseId>|<key>:<value>,<key>:<value>` — a pipe separates the base row id from override pairs (e.g. `101|damage:150,range:8`), emitting `{ ...file.Map["101"], damage: 150, range: 8 }` typed `File.Record`; with no overrides the cell is just the id and emits a plain `file.Map["id"]` like `Ref`. Override values may be bare scalars or bracket-wrapped composites mirroring the generated TS syntax — arrays as `[v1,v2]` (e.g. `Params:[6,2.07]`, required for array-typed fields; a bare `Params:6,2.07` gets chopped by the pair comma and prints a warning) and flat objects as `{k:v,k:v}`. `Template[file][]` separates entries with `;` (the same element separator as `Object[]`), e.g. `101|damage:150;102|heal:500` emits `[{ ...file.Map["101"], damage: 150 },{ ...file.Map["102"], heal: 500 }]`. Override key typos and value-type mismatches fail at tsc compile time; overrides are flat top-level fields (no dot-path deep merge), and the target table must have an Index/EnumIndex Map
40
103
  * Merge order is resolved automatically: tables are topologically sorted so every referenced table (`Ref`/`RefEnum`/`Template`) is emitted before the tables referencing it — no filename tricks needed; tables without a dependency relation keep alphabetical order. Circular references (`a.csv -> b.csv -> a.csv`) and references to missing files print a warning
41
104
  * `Object` parse `key:value,key:value` format, auto-infer value types (number/boolean/string), generates a dedicated `type` that merges all keys
42
105
  * `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[]`
@@ -48,7 +111,7 @@ config2ts -d config -o dist -n csv.ts -a public
48
111
 
49
112
  Scan assets directory and generate an `assets.ts` index file with nested resource tree.
50
113
 
51
- - `-a, --assets <path>` set assets resource directory. default: `public`
114
+ - `-a, --assets <path>` set assets resource directory (optional, skip asset index if omitted)
52
115
  - Output file: `assets.ts` (alongside the merged config file)
53
116
  - File and directory names are used exactly as-is (e.g., `Direction.png` → `Direction`, `adjust-horizontal.png` → `'adjust-horizontal'`); keys with special characters are automatically quoted
54
117
  - `type` field uses file extension (lowercase), e.g. `'png'`, `'mp3'`, `'svg'`
@@ -103,9 +166,10 @@ const adjustMeta = ASSETS.public.image['adjust-horizontal'];
103
166
  -h, --help output usage information
104
167
  -V, --version output the version number
105
168
  -d, --dir <path> set convert path. default: ./
106
- -o, --outDir <path> set outDir path. default: ./
107
- -n, --name <name> output file name. default: csv.ts
108
- -a, --assets <path> set assets resource directory for asset index. default: public
169
+ -o, --outDir <path> set outDir path. default: same as -d
170
+ -n, --name <name> output file name (single mode) / index file name (split mode). default: csv.ts
171
+ -a, --assets <path> set assets resource directory for asset index (optional, skip asset index if omitted)
172
+ -m, --mode <mode> output mode: single (merge into one file) or split (one file per table + index.ts). default: single
109
173
  ```
110
174
 
111
175
  ## supported file formats
@@ -4,5 +4,5 @@ export declare function assets2ts(assetsDir: string): string;
4
4
  export declare function GetTsString(filePath: string): string;
5
5
  export declare function GetTsStringFromFileList(fileList: string[]): string;
6
6
  export declare function GetValidFileList(fileList: string[]): string[];
7
- export declare function startConvert(dir: string, outDir: string, merge: string, assetsDir?: string): void;
7
+ export declare function startConvert(dir: string, outDir: string, merge: string, assetsDir?: string, mode?: "single" | "split"): void;
8
8
  export {};
package/lib/config2ts.js CHANGED
@@ -871,11 +871,75 @@ function GetValidFileList(fileList) {
871
871
  return exports.Convert[GetFileExt(filePath)] != null;
872
872
  });
873
873
  }
874
- function startConvert(dir, outDir, merge, assetsDir) {
874
+ // Build the `import { XxxCsv } from "./xxx";` lines a split-mode file needs so
875
+ // its cross-table Ref/RefEnum/Template references resolve. `collectCsvReferences`
876
+ // returns the full base filenames (e.g. "z-base.csv") of referenced tables, which
877
+ // map 1:1 to the split output file "./z-base.ts" and to the namespace
878
+ // `pascalCase("z-base.csv")` === "ZBaseCsv".
879
+ function buildImportLines(filePath, validBases) {
880
+ const base = path.basename(filePath);
881
+ const refs = collectCsvReferences(filePath).filter((ref) => ref !== base);
882
+ const imported = new Set();
883
+ const lines = [];
884
+ for (const ref of refs) {
885
+ if (!validBases.has(ref)) {
886
+ continue; // missing referenced table; already warned by sortFilesByReferences
887
+ }
888
+ if (imported.has(ref)) {
889
+ continue;
890
+ }
891
+ imported.add(ref);
892
+ const ns = changeCase.pascalCase(ref);
893
+ const importPath = "./" + path.parse(ref).name;
894
+ lines.push(`import { ${ns} } from "${importPath}";`);
895
+ }
896
+ return lines.join("\n");
897
+ }
898
+ function startConvert(dir, outDir, merge, assetsDir, mode = "single") {
875
899
  const fileList = fs.readdirSync(dir);
876
900
  const fullFileList = GetValidFileList(fileList).map(function (filename) {
877
901
  return path.join(dir, filename);
878
902
  });
903
+ if (mode === "split") {
904
+ const validBases = new Set(fullFileList.map((f) => path.basename(f)));
905
+ const orderedFiles = sortFilesByReferences(fullFileList);
906
+ const exportedNames = [];
907
+ for (const filePath of orderedFiles) {
908
+ const base = path.basename(filePath);
909
+ const outName = path.parse(base).name + ".ts";
910
+ exportedNames.push(path.parse(base).name);
911
+ const imports = buildImportLines(filePath, validBases);
912
+ const body = GetTsString(filePath);
913
+ const content = AutoGenHeader + (imports ? imports + "\n\n" : "") + body + "\n";
914
+ const outPath = path.join(outDir, outName);
915
+ fs.writeFileSync(outPath, content, { encoding: "utf-8" });
916
+ console.log(`config2ts, ${base} -> ${outPath}`);
917
+ }
918
+ let assetsExport = null;
919
+ if (assetsDir) {
920
+ const assetsOutput = assets2ts(assetsDir);
921
+ if (assetsOutput) {
922
+ const assetsFile = path.join(outDir, "assets.ts");
923
+ fs.writeFileSync(assetsFile, AutoGenHeader + assetsOutput, { encoding: "utf-8" });
924
+ console.log(`assets2ts, resource dir: ${assetsDir}, output: ${assetsFile}`);
925
+ assetsExport = "assets";
926
+ }
927
+ }
928
+ // In split mode the `-n` value is reused as the index file name; fall back to
929
+ // "index.ts" when the caller leaves the single-mode default "csv.ts" intact.
930
+ const indexName = merge !== "csv.ts" ? merge : "index.ts";
931
+ let indexContent = AutoGenHeader;
932
+ for (const name of exportedNames) {
933
+ indexContent += `export * from "./${name}";\n`;
934
+ }
935
+ if (assetsExport) {
936
+ indexContent += `export * from "./${assetsExport}";\n`;
937
+ }
938
+ const indexPath = path.join(outDir, indexName);
939
+ fs.writeFileSync(indexPath, indexContent, { encoding: "utf-8" });
940
+ console.log(`config2ts, ${orderedFiles.length} config files, split mode, index: ${indexPath}`);
941
+ return;
942
+ }
879
943
  const mergeFile = path.join(outDir, merge);
880
944
  fs.writeFileSync(mergeFile, AutoGenHeader + GetTsStringFromFileList(fullFileList), { encoding: "utf-8" });
881
945
  console.log(`config2ts, ${fullFileList.length} config files, merge into: ${mergeFile}`);
package/lib/main.js CHANGED
@@ -42,10 +42,11 @@ const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf-8"));
42
42
  const program = new commander_1.Command();
43
43
  program
44
44
  .version(pkg.version)
45
- .option("-n, --name <name>", "output file name", "csv.ts")
45
+ .option("-n, --name <name>", "output file name (single mode) / index file name (split mode)", "csv.ts")
46
46
  .option("-d, --dir <path>", "set convert path", ".")
47
47
  .option("-o, --outDir <path>", "set outDir path")
48
- .option("-a, --assets <path>", "set assets resource directory for asset index", "public")
48
+ .option("-a, --assets <path>", "set assets resource directory for asset index (optional, skip asset index if omitted)")
49
+ .option("-m, --mode <mode>", "output mode: single (merge into one file) or split (one file per table + index.ts)", "single")
49
50
  .parse(process.argv);
50
51
  const options = program.opts();
51
52
  console.log(options);
@@ -60,4 +61,8 @@ const assetsDir = options.assets ? path.resolve(options.assets) : undefined;
60
61
  if (assetsDir) {
61
62
  console.log("assetsDir:", assetsDir);
62
63
  }
63
- (0, config2ts_1.startConvert)(dir, outDir, options.name, assetsDir);
64
+ const mode = options.mode === "split" ? "split" : "single";
65
+ if (mode === "single" && options.mode !== "single") {
66
+ console.warn(`[config2ts] warning: unknown mode "${options.mode}", falling back to "single"`);
67
+ }
68
+ (0, config2ts_1.startConvert)(dir, outDir, options.name, assetsDir, mode);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "config2ts",
3
- "version": "2.8.1",
3
+ "version": "2.9.0",
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",