@game-infra/valibot-to-csharp 0.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/dist/naming.js ADDED
@@ -0,0 +1,91 @@
1
+ /**
2
+ * Small naming helpers shared by the parser and the emitter.
3
+ */
4
+ const DTO_REPLACEMENTS = [
5
+ // Preserve casing but normalise DTO → Dto everywhere it appears.
6
+ [/DTO/g, "Dto"],
7
+ ];
8
+ /**
9
+ * Convert arbitrary identifiers / string enum values into PascalCase.
10
+ *
11
+ * @example
12
+ * ```ts
13
+ * import { toPascalCase } from "@game-infra/valibot-to-csharp";
14
+ *
15
+ * toPascalCase("fooBar"); // "FooBar"
16
+ * toPascalCase("foo_bar-baz"); // "FooBarBaz"
17
+ * toPascalCase("EventDTO"); // "EventDto"
18
+ * ```
19
+ */
20
+ export function toPascalCase(input) {
21
+ if (!input)
22
+ return "";
23
+ // Split on non-alphanumeric or camelCase boundaries.
24
+ const parts = input
25
+ .replace(/[^A-Za-z0-9]+/g, " ")
26
+ .replace(/([a-z0-9])([A-Z])/g, "$1 $2")
27
+ .replace(/([A-Z]+)([A-Z][a-z])/g, "$1 $2")
28
+ .trim()
29
+ .split(/\s+/);
30
+ return parts
31
+ .map((p) => (p.length === 0 ? "" : p[0].toUpperCase() + p.slice(1).toLowerCase()))
32
+ .join("");
33
+ }
34
+ /**
35
+ * Strip the trailing "Schema" suffix from a valibot const name and normalise
36
+ * common acronyms (DTO → Dto). Returns a PascalCase C# type name.
37
+ *
38
+ * @example
39
+ * ```ts
40
+ * import { stripSchemaSuffix } from "@game-infra/valibot-to-csharp";
41
+ *
42
+ * stripSchemaSuffix("FooSchema"); // "Foo"
43
+ * stripSchemaSuffix("EventDefinitionDTOSchema"); // "EventDefinitionDto"
44
+ * stripSchemaSuffix("fooBarSchema"); // "FooBar"
45
+ * ```
46
+ */
47
+ export function stripSchemaSuffix(name) {
48
+ let out = name;
49
+ if (out.endsWith("Schema")) {
50
+ out = out.slice(0, -"Schema".length);
51
+ }
52
+ for (const [re, rep] of DTO_REPLACEMENTS) {
53
+ out = out.replace(re, rep);
54
+ }
55
+ // Ensure leading uppercase.
56
+ if (out.length > 0) {
57
+ out = out[0].toUpperCase() + out.slice(1);
58
+ }
59
+ return out;
60
+ }
61
+ /**
62
+ * Escape a C# string literal (for JsonPropertyName values etc.).
63
+ *
64
+ * @example
65
+ * ```ts
66
+ * import { csStringLiteral } from "@game-infra/valibot-to-csharp";
67
+ *
68
+ * csStringLiteral('a"b\\c'); // '"a\\"b\\\\c"'
69
+ * ```
70
+ */
71
+ export function csStringLiteral(value) {
72
+ return '"' + value.replace(/\\/g, "\\\\").replace(/"/g, '\\"') + '"';
73
+ }
74
+ /**
75
+ * Indent every non-empty line of `text` by `spaces` spaces.
76
+ *
77
+ * @example
78
+ * ```ts
79
+ * import { indent } from "@game-infra/valibot-to-csharp";
80
+ *
81
+ * indent("a\nb", 4); // " a\n b"
82
+ * ```
83
+ */
84
+ export function indent(text, spaces) {
85
+ const pad = " ".repeat(spaces);
86
+ return text
87
+ .split("\n")
88
+ .map((l) => (l.length === 0 ? l : pad + l))
89
+ .join("\n");
90
+ }
91
+ //# sourceMappingURL=naming.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"naming.js","sourceRoot":"","sources":["../src/naming.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,gBAAgB,GAA4B;IAChD,iEAAiE;IACjE,CAAC,MAAM,EAAE,KAAK,CAAC;CAChB,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,YAAY,CAAC,KAAa;IACxC,IAAI,CAAC,KAAK;QAAE,OAAO,EAAE,CAAC;IACtB,qDAAqD;IACrD,MAAM,KAAK,GAAG,KAAK;SAChB,OAAO,CAAC,gBAAgB,EAAE,GAAG,CAAC;SAC9B,OAAO,CAAC,oBAAoB,EAAE,OAAO,CAAC;SACtC,OAAO,CAAC,uBAAuB,EAAE,OAAO,CAAC;SACzC,IAAI,EAAE;SACN,KAAK,CAAC,KAAK,CAAC,CAAC;IAChB,OAAO,KAAK;SACT,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAE,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC;SAClF,IAAI,CAAC,EAAE,CAAC,CAAC;AACd,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,iBAAiB,CAAC,IAAY;IAC5C,IAAI,GAAG,GAAG,IAAI,CAAC;IACf,IAAI,GAAG,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC3B,GAAG,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IACvC,CAAC;IACD,KAAK,MAAM,CAAC,EAAE,EAAE,GAAG,CAAC,IAAI,gBAAgB,EAAE,CAAC;QACzC,GAAG,GAAG,GAAG,CAAC,OAAO,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC;IAC7B,CAAC;IACD,4BAA4B;IAC5B,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACnB,GAAG,GAAG,GAAG,CAAC,CAAC,CAAE,CAAC,WAAW,EAAE,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAC7C,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,eAAe,CAAC,KAAa;IAC3C,OAAO,GAAG,GAAG,KAAK,CAAC,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,GAAG,GAAG,CAAC;AACvE,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,MAAM,CAAC,IAAY,EAAE,MAAc;IACjD,MAAM,GAAG,GAAG,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IAC/B,OAAO,IAAI;SACR,KAAK,CAAC,IAAI,CAAC;SACX,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC;SAC1C,IAAI,CAAC,IAAI,CAAC,CAAC;AAChB,CAAC"}
@@ -0,0 +1,22 @@
1
+ import type { SchemaModule } from "./ir.js";
2
+ /**
3
+ * Parse a set of TypeScript files containing valibot schemas into a
4
+ * {@link SchemaModule}.
5
+ *
6
+ * The parser is deliberately syntactic: it never runs any code, it just walks
7
+ * the AST of each file, tracks imports across local relative paths, and
8
+ * produces an IR that the emitter can turn into C#. Anything coming from
9
+ * node_modules is ignored.
10
+ *
11
+ * @example
12
+ * ```ts
13
+ * import { parseFiles } from "@game-infra/valibot-to-csharp";
14
+ *
15
+ * const module = parseFiles(["./schemas/events.ts"]);
16
+ * for (const [name, schema] of module.schemas) {
17
+ * console.log(name, schema.schema.kind);
18
+ * }
19
+ * ```
20
+ */
21
+ export declare function parseFiles(entryFiles: string[]): SchemaModule;
22
+ //# sourceMappingURL=parser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../src/parser.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAA4B,YAAY,EAAc,MAAM,SAAS,CAAC;AAElF;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,UAAU,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,YAAY,CA8F7D"}
package/dist/parser.js ADDED
@@ -0,0 +1,321 @@
1
+ import * as fs from "node:fs";
2
+ import * as path from "node:path";
3
+ // This parser relies on the classic, in-process TypeScript compiler API
4
+ // (`ts.createSourceFile`, the `ts.isX` node guards, `ts.SyntaxKind`) to walk a
5
+ // source file synchronously. TypeScript 7.0 no longer exposes that JavaScript
6
+ // API from the `typescript` package root (it only offers a process-based
7
+ // `typescript/unstable/sync` API), so per the official TS 7 migration guidance
8
+ // we import the compiler API from the `@typescript/typescript6` compatibility
9
+ // package while the rest of the monorepo compiles with TypeScript 7.
10
+ import ts from "@typescript/typescript6";
11
+ /**
12
+ * Parse a set of TypeScript files containing valibot schemas into a
13
+ * {@link SchemaModule}.
14
+ *
15
+ * The parser is deliberately syntactic: it never runs any code, it just walks
16
+ * the AST of each file, tracks imports across local relative paths, and
17
+ * produces an IR that the emitter can turn into C#. Anything coming from
18
+ * node_modules is ignored.
19
+ *
20
+ * @example
21
+ * ```ts
22
+ * import { parseFiles } from "@game-infra/valibot-to-csharp";
23
+ *
24
+ * const module = parseFiles(["./schemas/events.ts"]);
25
+ * for (const [name, schema] of module.schemas) {
26
+ * console.log(name, schema.schema.kind);
27
+ * }
28
+ * ```
29
+ */
30
+ export function parseFiles(entryFiles) {
31
+ const seen = new Set();
32
+ const schemas = new Map();
33
+ const notes = [];
34
+ // Track which files we already reported the string('x') heuristic from.
35
+ const reportedStringLiteralPatternFiles = new Set();
36
+ const queue = [];
37
+ for (const f of entryFiles) {
38
+ const abs = path.resolve(f);
39
+ queue.push(abs);
40
+ }
41
+ while (queue.length > 0) {
42
+ const file = queue.shift();
43
+ if (seen.has(file))
44
+ continue;
45
+ seen.add(file);
46
+ if (!fs.existsSync(file))
47
+ continue;
48
+ const text = fs.readFileSync(file, "utf8");
49
+ const sourceFile = ts.createSourceFile(file, text, ts.ScriptTarget.ES2022,
50
+ /*setParentNodes*/ true, ts.ScriptKind.TS);
51
+ // Maps a local binding introduced by `import { X as Y } from '...'` or
52
+ // a plain `import { X }` to the original exported name. For our purposes
53
+ // we only need to know that a given identifier refers to a valibot helper
54
+ // (so we can recognise `string()`, `object()` etc.) or to a schema from
55
+ // another file (resolved below).
56
+ const valibotIdentifiers = new Set();
57
+ // identifier → resolved absolute TS file (for cross-file references)
58
+ const importedFromFile = new Map();
59
+ for (const stmt of sourceFile.statements) {
60
+ if (!ts.isImportDeclaration(stmt))
61
+ continue;
62
+ const mod = stmt.moduleSpecifier;
63
+ if (!ts.isStringLiteral(mod))
64
+ continue;
65
+ const moduleName = mod.text;
66
+ if (moduleName === "valibot") {
67
+ collectImportNames(stmt, valibotIdentifiers);
68
+ continue;
69
+ }
70
+ if (!moduleName.startsWith(".")) {
71
+ // Cross-package import (e.g. '@game-infra/some-schemas'). Skip it;
72
+ // per the spec we stop at node_modules.
73
+ continue;
74
+ }
75
+ const resolved = resolveRelativeImport(file, moduleName);
76
+ if (!resolved)
77
+ continue;
78
+ queue.push(resolved);
79
+ const names = new Set();
80
+ collectImportNames(stmt, names);
81
+ for (const n of names)
82
+ importedFromFile.set(n, resolved);
83
+ }
84
+ // Walk every top-level `export const X = <schema expression>` and build
85
+ // a NamedSchema from it. Anything that looks like it's not a valibot
86
+ // schema (e.g. a plain string constant, a function) is silently ignored.
87
+ for (const stmt of sourceFile.statements) {
88
+ if (!ts.isVariableStatement(stmt))
89
+ continue;
90
+ // Only track exports; if it's not exported we can't reference it anyway.
91
+ const isExported = stmt.modifiers?.some((m) => m.kind === ts.SyntaxKind.ExportKeyword);
92
+ if (!isExported)
93
+ continue;
94
+ for (const decl of stmt.declarationList.declarations) {
95
+ if (!ts.isIdentifier(decl.name))
96
+ continue;
97
+ const name = decl.name.text;
98
+ if (!decl.initializer)
99
+ continue;
100
+ try {
101
+ const schema = parseExpression(decl.initializer, {
102
+ valibotIdentifiers,
103
+ file,
104
+ noteStringLiteralPattern: () => {
105
+ if (!reportedStringLiteralPatternFiles.has(file)) {
106
+ reportedStringLiteralPatternFiles.add(file);
107
+ notes.push(`${path.basename(file)}: detected string("x") pattern treated as literal("x")`);
108
+ }
109
+ },
110
+ });
111
+ if (schema) {
112
+ schemas.set(name, { name, sourceFile: file, schema });
113
+ }
114
+ }
115
+ catch {
116
+ // Not a valibot schema expression. Fine, move on.
117
+ }
118
+ }
119
+ }
120
+ }
121
+ return { schemas, notes };
122
+ }
123
+ function collectImportNames(stmt, out) {
124
+ const clause = stmt.importClause;
125
+ if (!clause)
126
+ return;
127
+ const bindings = clause.namedBindings;
128
+ if (bindings && ts.isNamedImports(bindings)) {
129
+ for (const el of bindings.elements) {
130
+ if (el.isTypeOnly)
131
+ continue;
132
+ // `import { unknown as valibotUnknown }` imports track the local name.
133
+ out.add(el.name.text);
134
+ }
135
+ }
136
+ if (clause.name)
137
+ out.add(clause.name.text);
138
+ }
139
+ /**
140
+ * Resolve a relative import specifier (without an extension) against the
141
+ * importing file. Supports the typical editor/ts patterns: `./foo`, `./foo.ts`,
142
+ * `./foo.js` (treated as .ts), and `./foo/index.ts`.
143
+ */
144
+ function resolveRelativeImport(importingFile, spec) {
145
+ const base = path.dirname(importingFile);
146
+ const candidates = [];
147
+ const raw = path.resolve(base, spec);
148
+ // Strip a trailing .js extension if present. TS source normally writes .js
149
+ // to keep ESM happy post-compile, but the actual file is .ts.
150
+ const withoutJs = raw.endsWith(".js") ? raw.slice(0, -3) : raw;
151
+ candidates.push(`${withoutJs}.ts`, `${withoutJs}.tsx`, withoutJs, path.join(withoutJs, "index.ts"));
152
+ for (const c of candidates) {
153
+ if (fs.existsSync(c) && fs.statSync(c).isFile())
154
+ return c;
155
+ }
156
+ return null;
157
+ }
158
+ /**
159
+ * Recursive descent into a valibot schema expression. Returns `null` if the
160
+ * expression isn't recognised as a schema (in which case the caller treats
161
+ * the enclosing `export const` as "not a schema" and moves on).
162
+ */
163
+ function parseExpression(expr, ctx, opts = {}) {
164
+ // A bare identifier is a reference to another named schema (or an imported
165
+ // helper like `valibotUnknown`).
166
+ if (ts.isIdentifier(expr)) {
167
+ if (expr.text === "valibotUnknown")
168
+ return { kind: "unknown" };
169
+ return { kind: "ref", name: expr.text };
170
+ }
171
+ if (!ts.isCallExpression(expr))
172
+ return null;
173
+ const callee = expr.expression;
174
+ const fnName = ts.isIdentifier(callee) ? callee.text : null;
175
+ if (!fnName)
176
+ return null;
177
+ const args = expr.arguments;
178
+ switch (fnName) {
179
+ case "string": {
180
+ // Kludge: `string('foo')` inside a union means "literal foo".
181
+ if (args.length >= 1 && ts.isStringLiteral(args[0]) && opts.inUnion) {
182
+ ctx.noteStringLiteralPattern();
183
+ return { kind: "literal", value: args[0].text };
184
+ }
185
+ return { kind: "primitive", type: "string" };
186
+ }
187
+ case "number":
188
+ return { kind: "primitive", type: "number" };
189
+ case "boolean":
190
+ return { kind: "primitive", type: "boolean" };
191
+ case "unknown":
192
+ case "valibotUnknown":
193
+ return { kind: "unknown" };
194
+ case "array": {
195
+ const inner = args[0] ? parseExpression(args[0], ctx) : null;
196
+ return inner ? { kind: "array", inner } : null;
197
+ }
198
+ case "record": {
199
+ // record(key, value). We only support string keys; if it's anything
200
+ // else, fall back to JsonElement.
201
+ const valueArg = args[1];
202
+ const value = valueArg ? parseExpression(valueArg, ctx) : null;
203
+ return value ? { kind: "record", value } : null;
204
+ }
205
+ case "object": {
206
+ const shape = args[0];
207
+ if (!shape || !ts.isObjectLiteralExpression(shape))
208
+ return null;
209
+ const fields = [];
210
+ for (const prop of shape.properties) {
211
+ if (ts.isSpreadAssignment(prop)) {
212
+ // Best-effort: resolve spread of another object schema's .entries
213
+ // by ignoring for now. Cross-schema spreads are rare in the target
214
+ // surface; extend this if needed.
215
+ continue;
216
+ }
217
+ if (!ts.isPropertyAssignment(prop))
218
+ continue;
219
+ const nameNode = prop.name;
220
+ let fieldName = null;
221
+ if (ts.isIdentifier(nameNode))
222
+ fieldName = nameNode.text;
223
+ else if (ts.isStringLiteral(nameNode))
224
+ fieldName = nameNode.text;
225
+ if (!fieldName)
226
+ continue;
227
+ const inner = parseExpression(prop.initializer, ctx);
228
+ if (!inner)
229
+ continue;
230
+ const { optional, nullable, stripped } = unwrapOptionalNullable(inner);
231
+ fields.push({
232
+ name: fieldName,
233
+ schema: stripped,
234
+ optional,
235
+ nullable,
236
+ });
237
+ }
238
+ return { kind: "object", fields };
239
+ }
240
+ case "optional": {
241
+ const inner = args[0] ? parseExpression(args[0], ctx) : null;
242
+ return inner ? { kind: "optional", inner } : null;
243
+ }
244
+ case "nullable": {
245
+ const inner = args[0] ? parseExpression(args[0], ctx) : null;
246
+ return inner ? { kind: "nullable", inner } : null;
247
+ }
248
+ case "literal": {
249
+ const a = args[0];
250
+ if (!a)
251
+ return null;
252
+ if (ts.isStringLiteral(a))
253
+ return { kind: "literal", value: a.text };
254
+ // Only string literals are supported; ignore numbers/booleans.
255
+ return null;
256
+ }
257
+ case "picklist": {
258
+ const a = args[0];
259
+ if (!a || !ts.isArrayLiteralExpression(a))
260
+ return null;
261
+ const values = [];
262
+ for (const el of a.elements) {
263
+ if (ts.isStringLiteral(el))
264
+ values.push(el.text);
265
+ }
266
+ return { kind: "picklist", values };
267
+ }
268
+ case "union": {
269
+ const a = args[0];
270
+ if (!a || !ts.isArrayLiteralExpression(a))
271
+ return null;
272
+ const members = [];
273
+ for (const el of a.elements) {
274
+ const m = parseExpression(el, ctx, { inUnion: true });
275
+ if (m)
276
+ members.push(m);
277
+ }
278
+ return { kind: "union", members };
279
+ }
280
+ case "variant": {
281
+ const disc = args[0];
282
+ const membersArg = args[1];
283
+ if (!disc || !ts.isStringLiteral(disc))
284
+ return null;
285
+ if (!membersArg || !ts.isArrayLiteralExpression(membersArg))
286
+ return null;
287
+ const members = [];
288
+ for (const el of membersArg.elements) {
289
+ const m = parseExpression(el, ctx);
290
+ if (m)
291
+ members.push(m);
292
+ }
293
+ return { kind: "variant", discriminator: disc.text, members };
294
+ }
295
+ case "pipe": {
296
+ // pipe(schema, ...validators): we only care about the head schema.
297
+ const head = args[0];
298
+ return head ? parseExpression(head, ctx) : null;
299
+ }
300
+ default:
301
+ return null;
302
+ }
303
+ }
304
+ /**
305
+ * Peel outer `optional(...)`/`nullable(...)` wrappers off a schema and return
306
+ * the flags separately. Keeps the object-field IR flat.
307
+ */
308
+ function unwrapOptionalNullable(node) {
309
+ let optional = false;
310
+ let nullable = false;
311
+ let current = node;
312
+ while (current.kind === "optional" || current.kind === "nullable") {
313
+ if (current.kind === "optional")
314
+ optional = true;
315
+ else
316
+ nullable = true;
317
+ current = current.inner;
318
+ }
319
+ return { optional, nullable, stripped: current };
320
+ }
321
+ //# sourceMappingURL=parser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parser.js","sourceRoot":"","sources":["../src/parser.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,38 @@
1
+ {
2
+ "name": "@game-infra/valibot-to-csharp",
3
+ "version": "0.0.0",
4
+ "description": "Generate idiomatic C# record types from TypeScript valibot schemas",
5
+ "bin": {
6
+ "valibot-to-csharp": "./dist/cli.js"
7
+ },
8
+ "type": "module",
9
+ "sideEffects": false,
10
+ "exports": {
11
+ ".": {
12
+ "types": "./dist/index.d.ts",
13
+ "default": "./dist/index.js"
14
+ }
15
+ },
16
+ "files": [
17
+ "dist"
18
+ ],
19
+ "publishConfig": {
20
+ "access": "public"
21
+ },
22
+ "dependencies": {
23
+ "@typescript/typescript6": "^6.0.2"
24
+ },
25
+ "devDependencies": {
26
+ "@types/node": "^22.19.7",
27
+ "rimraf": "^6.1.3",
28
+ "typescript": "^7.0.2",
29
+ "valibot": "^1.4.0",
30
+ "vitest": "^4.0.0"
31
+ },
32
+ "scripts": {
33
+ "build": "rimraf dist && tsc --project tsconfig.build.json",
34
+ "typecheck": "tsc --noEmit",
35
+ "test": "vitest run",
36
+ "clean": "rimraf dist"
37
+ }
38
+ }