feat(csv-loader): preserve original schema strings in type generation

Store the original schema string during CSV parsing to prevent
unnecessary expansion of type name references in the generated
TypeScript definitions. This ensures that declared types reference
each other by name rather than inlining their full definitions.
This commit is contained in:
hypercross 2026-04-22 17:08:06 +08:00
parent ea362d4229
commit 46504a53dd
4 changed files with 33 additions and 14 deletions

View File

@ -160,7 +160,11 @@ export function parseCsv(
} }
// Parse type declarations with expansion of type name references // Parse type declarations with expansion of type name references
const typeDeclarationsParsed: { name: string; schema: Schema }[] = []; const typeDeclarationsParsed: {
name: string;
schema: Schema;
schemaString: string;
}[] = [];
for (const decl of typeDeclarationsRaw) { for (const decl of typeDeclarationsRaw) {
// Expand any type name references before parsing // Expand any type name references before parsing
const expandedSchema = expandSchemaString( const expandedSchema = expandSchemaString(
@ -168,7 +172,11 @@ export function parseCsv(
declaredSchemaStrings, declaredSchemaStrings,
); );
const schema = parseSchema(expandedSchema.trim()); const schema = parseSchema(expandedSchema.trim());
typeDeclarationsParsed.push({ name: decl.typeName, schema }); typeDeclarationsParsed.push({
name: decl.typeName,
schema,
schemaString: decl.schemaString,
});
} }
// Build declared types map // Build declared types map
@ -181,7 +189,11 @@ export function parseCsv(
const typeDeclarations: TypeDeclaration[] = []; const typeDeclarations: TypeDeclaration[] = [];
for (const decl of typeDeclarationsParsed) { for (const decl of typeDeclarationsParsed) {
const resolvedSchema = resolveTypeReferences(decl.schema, declaredTypes); const resolvedSchema = resolveTypeReferences(decl.schema, declaredTypes);
typeDeclarations.push({ name: decl.name, schema: resolvedSchema }); typeDeclarations.push({
name: decl.name,
schema: resolvedSchema,
schemaString: decl.schemaString,
});
} }
// Update declaredTypes with resolved schemas for column schema lookup // Update declaredTypes with resolved schemas for column schema lookup

View File

@ -56,9 +56,9 @@ describe("parseCsv - type declarations", () => {
currentFilePath: path.join(fixturesDir, "card.csv"), currentFilePath: path.join(fixturesDir, "card.csv"),
}); });
expect(result.typeDefinition).toContain("type Trigger ="); expect(result.typeDefinition).toContain("export type Trigger =");
expect(result.typeDefinition).toContain( expect(result.typeDefinition).toContain(
'"onPlay" | "onDraw" | "onDiscard"', "'onPlay' | 'onDraw' | 'onDiscard'",
); );
}); });
@ -93,8 +93,8 @@ describe("parseCsv - type declarations", () => {
currentFilePath: path.join(fixturesDir, "card.csv"), currentFilePath: path.join(fixturesDir, "card.csv"),
}); });
expect(result.typeDefinition).toContain("type Trigger ="); expect(result.typeDefinition).toContain("export type Trigger =");
expect(result.typeDefinition).toContain("type Status ="); expect(result.typeDefinition).toContain("export type Status =");
}); });
it("should ignore comment lines that are not type declarations", () => { it("should ignore comment lines that are not type declarations", () => {
@ -196,8 +196,8 @@ describe("parseCsv - type declarations", () => {
}); });
// Both type declarations should appear // Both type declarations should appear
expect(result.typeDefinition).toContain("type Trigger ="); expect(result.typeDefinition).toContain("export type Trigger =");
expect(result.typeDefinition).toContain("type Effect ="); expect(result.typeDefinition).toContain("export type Effect =");
// Column should use the declared type name, not expanded union // Column should use the declared type name, not expanded union
expect(result.typeDefinition).toContain("readonly trigger: Trigger;"); expect(result.typeDefinition).toContain("readonly trigger: Trigger;");
}); });
@ -242,10 +242,15 @@ describe("parseCsv - type declarations", () => {
currentFilePath: path.join(fixturesDir, "intent.csv"), currentFilePath: path.join(fixturesDir, "intent.csv"),
}); });
expect(result.typeDefinition).toContain("type IntentEffectTarget ="); expect(result.typeDefinition).toContain("export type IntentEffectTarget =");
expect(result.typeDefinition).toContain("type IntentEffect ="); expect(result.typeDefinition).toContain("export type IntentEffect =");
expect(result.typeDefinition).toContain("type IntentEffects ="); expect(result.typeDefinition).toContain("export type IntentEffects =");
// IntentEffect should reference IntentEffectTarget, not expand it
expect(result.typeDefinition).toContain(
"[IntentEffectTarget; string; int]",
);
// IntentEffects should reference IntentEffect, not expand it
expect(result.typeDefinition).toContain("IntentEffect[]");
// Column should reference IntentEffects, not inline expansion // Column should reference IntentEffects, not inline expansion
expect(result.typeDefinition).toContain("readonly effects: IntentEffects;"); expect(result.typeDefinition).toContain("readonly effects: IntentEffects;");
}); });

View File

@ -51,7 +51,7 @@ export function generateTypeDefinition(
? typeDeclarations ? typeDeclarations
.map( .map(
(decl) => (decl) =>
`export type ${decl.name} = ${schemaToTypeString(decl.schema, resourceNames)};`, `export type ${decl.name} = ${decl.schemaString ?? schemaToTypeString(decl.schema, resourceNames)};`,
) )
.join("\n") + "\n\n" .join("\n") + "\n\n"
: ""; : "";

View File

@ -98,6 +98,8 @@ export interface ReverseReferenceDeclaration {
export interface TypeDeclaration { export interface TypeDeclaration {
/** Name of the type being defined */ /** Name of the type being defined */
name: string; name: string;
/** The original schema string (preserves type name references for output) */
schemaString: string;
/** The parsed schema for this type */ /** The parsed schema for this type */
schema: Schema; schema: Schema;
} }