Compare commits

..

No commits in common. "e0317946d5262c434ea65b3662389aaebd2ac048" and "f101c1209715fcf399561d0dbf8d3751071e6bd7" have entirely different histories.

4 changed files with 12 additions and 125 deletions

View File

@ -160,11 +160,7 @@ export function parseCsv(
}
// Parse type declarations with expansion of type name references
const typeDeclarationsParsed: {
name: string;
schema: Schema;
schemaString: string;
}[] = [];
const typeDeclarationsParsed: { name: string; schema: Schema }[] = [];
for (const decl of typeDeclarationsRaw) {
// Expand any type name references before parsing
const expandedSchema = expandSchemaString(
@ -172,11 +168,7 @@ export function parseCsv(
declaredSchemaStrings,
);
const schema = parseSchema(expandedSchema.trim());
typeDeclarationsParsed.push({
name: decl.typeName,
schema,
schemaString: decl.schemaString,
});
typeDeclarationsParsed.push({ name: decl.typeName, schema });
}
// Build declared types map
@ -189,11 +181,7 @@ export function parseCsv(
const typeDeclarations: TypeDeclaration[] = [];
for (const decl of typeDeclarationsParsed) {
const resolvedSchema = resolveTypeReferences(decl.schema, declaredTypes);
typeDeclarations.push({
name: decl.name,
schema: resolvedSchema,
schemaString: decl.schemaString,
});
typeDeclarations.push({ name: decl.name, schema: resolvedSchema });
}
// Update declaredTypes with resolved schemas for column schema lookup
@ -209,21 +197,11 @@ export function parseCsv(
// Check if schema string matches a declared type name
let schema: Schema;
let declaredTypeName: string | undefined;
let columnSchemaString: string | undefined;
if (declaredTypes.has(schemaString)) {
schema = declaredTypes.get(schemaString)!;
declaredTypeName = schemaString;
} else {
// Expand any custom type name references before parsing
const expandedSchema = expandSchemaString(
schemaString,
declaredSchemaStrings,
);
schema = parseSchema(expandedSchema.trim());
// Only preserve the original schema string if expansion actually changed it
if (expandedSchema !== schemaString) {
columnSchemaString = schemaString;
}
schema = parseSchema(schemaString);
}
const config: PropertyConfig = {
@ -232,7 +210,6 @@ export function parseCsv(
validator: createValidator(schema),
parser: (valueString: string) => parseValue(schema, valueString),
declaredTypeName,
schemaString: columnSchemaString,
};
if (schema.type === "reference") {

View File

@ -56,9 +56,9 @@ describe("parseCsv - type declarations", () => {
currentFilePath: path.join(fixturesDir, "card.csv"),
});
expect(result.typeDefinition).toContain("export type Trigger =");
expect(result.typeDefinition).toContain("type Trigger =");
expect(result.typeDefinition).toContain(
"'onPlay' | 'onDraw' | 'onDiscard'",
'"onPlay" | "onDraw" | "onDiscard"',
);
});
@ -93,8 +93,8 @@ describe("parseCsv - type declarations", () => {
currentFilePath: path.join(fixturesDir, "card.csv"),
});
expect(result.typeDefinition).toContain("export type Trigger =");
expect(result.typeDefinition).toContain("export type Status =");
expect(result.typeDefinition).toContain("type Trigger =");
expect(result.typeDefinition).toContain("type Status =");
});
it("should ignore comment lines that are not type declarations", () => {
@ -196,96 +196,11 @@ describe("parseCsv - type declarations", () => {
});
// Both type declarations should appear
expect(result.typeDefinition).toContain("export type Trigger =");
expect(result.typeDefinition).toContain("export type Effect =");
expect(result.typeDefinition).toContain("type Trigger =");
expect(result.typeDefinition).toContain("type Effect =");
// Column should use the declared type name, not expanded union
expect(result.typeDefinition).toContain("readonly trigger: Trigger;");
});
it("should expand custom type names inside tuples and arrays", () => {
const csv = [
"# type IntentEffectTarget = 'user' | 'eachEnemy' | 'randomEnemy' | 'player'",
"# type IntentEffect = [IntentEffectTarget; string; int]",
"# type IntentEffects = IntentEffect[]",
"id,effects",
"string,IntentEffects",
"boost,[user;spike;1];[user;defend;4]",
].join("\n");
const result = parseCsv(csv, { emitTypes: false });
expect(result.typeDeclarations).toHaveLength(3);
const intentEffect = result.typeDeclarations.find(
(d) => d.name === "IntentEffect",
)!;
expect(intentEffect.schema.type).toBe("tuple");
// First element should be resolved to union, not a string "IntentEffectTarget"
const firstEl = (
intentEffect.schema as { elements: { schema: { type: string } }[] }
).elements[0].schema;
expect(firstEl.type).toBe("union");
});
it("should use declared type names in generated type definition for tuple arrays", () => {
const csv = [
"# type IntentEffectTarget = 'user' | 'eachEnemy' | 'randomEnemy' | 'player'",
"# type IntentEffect = [IntentEffectTarget; string; int]",
"# type IntentEffects = IntentEffect[]",
"id,effects",
"string,IntentEffects",
"boost,[user;spike;1];[user;defend;4]",
].join("\n");
const result = parseCsv(csv, {
emitTypes: true,
resourceName: "intent",
currentFilePath: path.join(fixturesDir, "intent.csv"),
});
expect(result.typeDefinition).toContain("export type IntentEffectTarget =");
expect(result.typeDefinition).toContain("export type IntentEffect =");
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
expect(result.typeDefinition).toContain("readonly effects: IntentEffects;");
});
it("should handle custom type inside a tuple used as an array element", () => {
const csv = [
'# type Type = "apple" | "orange"',
"id,items",
"string,[Type; int][]",
"001,[apple;2];[orange;3]",
].join("\n");
const result = parseCsv(csv, { emitTypes: false });
expect(result.data).toHaveLength(1);
expect(result.data[0]).toEqual({
id: "001",
items: [
["apple", 2],
["orange", 3],
],
});
const typeResult = parseCsv(csv, {
emitTypes: true,
resourceName: "item",
currentFilePath: path.join(fixturesDir, "item.csv"),
});
expect(typeResult.typeDefinition).toContain("export type Type =");
expect(typeResult.typeDefinition).toContain("[Type; int][]");
expect(typeResult.typeDefinition).toContain(
"readonly items: [Type; int][];",
);
});
});
describe("parseCsv - type declarations with resolveReferences: false", () => {

View File

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

View File

@ -78,8 +78,6 @@ export interface PropertyConfig {
reverseReferenceForeignKey?: string;
/** When a column uses a declared type name, this stores that name */
declaredTypeName?: string;
/** The original schema string for the column (preserves type name references for output) */
schemaString?: string;
}
/** Parsed reverse reference declaration from a comment line */
@ -100,8 +98,6 @@ export interface ReverseReferenceDeclaration {
export interface TypeDeclaration {
/** Name of the type being defined */
name: string;
/** The original schema string (preserves type name references for output) */
schemaString: string;
/** The parsed schema for this type */
schema: Schema;
}