fix: update type generation
This commit is contained in:
parent
6eba70bb3b
commit
852a108c53
|
|
@ -846,15 +846,15 @@ describe('csvToModule - accessor-based output', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('csvToModule - circular reference support', () => {
|
describe('csvToModule - circular reference support', () => {
|
||||||
it('should emit accessor for self-referencing table', () => {
|
it('should emit accessor for self-referencing table without self-import', () => {
|
||||||
const csv = readFixture('self_ref.csv');
|
const csv = readFixture('self_ref.csv');
|
||||||
|
|
||||||
const result = csvToModule(csv, { emitTypes: false, currentFilePath: path.join(fixturesDir, 'self_ref.csv') });
|
const result = csvToModule(csv, { emitTypes: false, currentFilePath: path.join(fixturesDir, 'self_ref.csv') });
|
||||||
|
|
||||||
expect(result.js).toContain("import _self_ref from './self_ref.csv'");
|
expect(result.js).not.toContain("import _self_ref from './self_ref.csv'");
|
||||||
expect(result.js).toContain('export default function getData()');
|
expect(result.js).toContain('export default function getData()');
|
||||||
expect(result.js).toContain('_self_refLookup');
|
expect(result.js).toContain('_self_refLookup');
|
||||||
expect(result.js).toContain('_resolved = _raw;');
|
expect(result.js).toContain('_self_refLookup = new Map(_raw.map');
|
||||||
expect(result.js).toContain('parent: _self_refLookup.get(String(row.parent))');
|
expect(result.js).toContain('parent: _self_refLookup.get(String(row.parent))');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -878,14 +878,14 @@ describe('csvToModule - circular reference support', () => {
|
||||||
|
|
||||||
const result = csvToModule(csv, { emitTypes: false, currentFilePath: path.join(fixturesDir, 'self_ref.csv') });
|
const result = csvToModule(csv, { emitTypes: false, currentFilePath: path.join(fixturesDir, 'self_ref.csv') });
|
||||||
|
|
||||||
expect(result.js).toContain("import _self_ref from './self_ref.csv'");
|
expect(result.js).not.toContain("import _self_ref from './self_ref.csv'");
|
||||||
expect(result.js).toContain('_self_refLookup');
|
expect(result.js).toContain('_self_refLookup');
|
||||||
expect(result.js).toContain('export default function getData()');
|
expect(result.js).toContain('export default function getData()');
|
||||||
expect(result.js).toContain('parent_info:');
|
expect(result.js).toContain('parent_info:');
|
||||||
expect(result.js).toContain('_self_refLookup.get(String(row.parent_info[0]))');
|
expect(result.js).toContain('_self_refLookup.get(String(row.parent_info[0]))');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should emit accessor for self-referencing table with nested reference in union', () => {
|
it('should emit accessor for self-referencing table with nested reference in union with fallback', () => {
|
||||||
const csv = [
|
const csv = [
|
||||||
'id,name,ref_or_val',
|
'id,name,ref_or_val',
|
||||||
'string,string,@self_ref | string',
|
'string,string,@self_ref | string',
|
||||||
|
|
@ -895,10 +895,11 @@ describe('csvToModule - circular reference support', () => {
|
||||||
|
|
||||||
const result = csvToModule(csv, { emitTypes: false, currentFilePath: path.join(fixturesDir, 'self_ref.csv') });
|
const result = csvToModule(csv, { emitTypes: false, currentFilePath: path.join(fixturesDir, 'self_ref.csv') });
|
||||||
|
|
||||||
expect(result.js).toContain("import _self_ref from './self_ref.csv'");
|
expect(result.js).not.toContain("import _self_ref from './self_ref.csv'");
|
||||||
expect(result.js).toContain('_self_refLookup');
|
expect(result.js).toContain('_self_refLookup');
|
||||||
expect(result.js).toContain('export default function getData()');
|
expect(result.js).toContain('export default function getData()');
|
||||||
expect(result.js).toContain('ref_or_val:');
|
expect(result.js).toContain('ref_or_val:');
|
||||||
|
expect(result.js).toContain('_self_refLookup.get(String(row.ref_or_val)) ?? row.ref_or_val');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should emit accessor for self-referencing table with nested reference array in tuple', () => {
|
it('should emit accessor for self-referencing table with nested reference array in tuple', () => {
|
||||||
|
|
@ -910,20 +911,21 @@ describe('csvToModule - circular reference support', () => {
|
||||||
|
|
||||||
const result = csvToModule(csv, { emitTypes: false, currentFilePath: path.join(fixturesDir, 'self_ref.csv') });
|
const result = csvToModule(csv, { emitTypes: false, currentFilePath: path.join(fixturesDir, 'self_ref.csv') });
|
||||||
|
|
||||||
expect(result.js).toContain("import _self_ref from './self_ref.csv'");
|
expect(result.js).not.toContain("import _self_ref from './self_ref.csv'");
|
||||||
expect(result.js).toContain('_self_refLookup');
|
expect(result.js).toContain('_self_refLookup');
|
||||||
expect(result.js).toContain('export default function getData()');
|
expect(result.js).toContain('export default function getData()');
|
||||||
expect(result.js).toContain('children:');
|
expect(result.js).toContain('children:');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should generate correct type definition for self-referencing table', () => {
|
it('should generate correct type definition for self-referencing table using local singular type', () => {
|
||||||
const csv = readFixture('self_ref.csv');
|
const csv = readFixture('self_ref.csv');
|
||||||
|
|
||||||
const result = csvToModule(csv, { emitTypes: true, resourceName: 'nodes', currentFilePath: path.join(fixturesDir, 'self_ref.csv') });
|
const result = csvToModule(csv, { emitTypes: true, resourceName: 'nodes', currentFilePath: path.join(fixturesDir, 'self_ref.csv') });
|
||||||
|
|
||||||
expect(result.dts).toContain('declare function getData(): nodesTable');
|
expect(result.dts).toContain('declare function getData(): nodesTable');
|
||||||
expect(result.dts).toContain('Self_ref');
|
expect(result.dts).toContain('readonly parent: Nodes');
|
||||||
expect(result.dts).toContain("import type { Self_ref } from './self_ref.csv'");
|
expect(result.dts).not.toContain("import type { Self_ref } from './self_ref.csv'");
|
||||||
|
expect(result.dts).not.toContain('Self_ref');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should emit accessor for cross-referencing tables with array references', () => {
|
it('should emit accessor for cross-referencing tables with array references', () => {
|
||||||
|
|
@ -950,4 +952,17 @@ describe('csvToModule - circular reference support', () => {
|
||||||
expect(result.js).toContain('_circular_bLookup');
|
expect(result.js).toContain('_circular_bLookup');
|
||||||
expect(result.js).toContain('export default function getData()');
|
expect(result.js).toContain('export default function getData()');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should generate union fallback with ?? for non-reference union members', () => {
|
||||||
|
const csv = [
|
||||||
|
'id,value',
|
||||||
|
'string,@users | string',
|
||||||
|
'1,1',
|
||||||
|
'2,unknown',
|
||||||
|
].join('\n');
|
||||||
|
|
||||||
|
const result = csvToModule(csv, { emitTypes: false });
|
||||||
|
|
||||||
|
expect(result.js).toContain('?? row.value');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
@ -538,12 +538,22 @@ function generateTypeDefinition(
|
||||||
hasRefs?: boolean
|
hasRefs?: boolean
|
||||||
): string {
|
): string {
|
||||||
const typeName = resourceName ? `${resourceName}Table` : 'Table';
|
const typeName = resourceName ? `${resourceName}Table` : 'Table';
|
||||||
|
const currentTableName = currentFilePath
|
||||||
|
? path.basename(currentFilePath, path.extname(currentFilePath))
|
||||||
|
: undefined;
|
||||||
|
const singularType = resourceName
|
||||||
|
? resourceName.charAt(0).toUpperCase() + resourceName.slice(1)
|
||||||
|
: `${typeName}[number]`;
|
||||||
|
|
||||||
// Generate import statements for referenced tables
|
// Generate import statements for referenced tables
|
||||||
const imports: string[] = [];
|
const imports: string[] = [];
|
||||||
const resourceNames = new Map<string, string>();
|
const resourceNames = new Map<string, string>();
|
||||||
|
|
||||||
references.forEach(tableName => {
|
references.forEach(tableName => {
|
||||||
|
if (tableName === currentTableName) {
|
||||||
|
resourceNames.set(tableName, singularType);
|
||||||
|
return;
|
||||||
|
}
|
||||||
// Convert table name to type name by capitalizing
|
// Convert table name to type name by capitalizing
|
||||||
const typeBase = tableName.charAt(0).toUpperCase() + tableName.slice(1);
|
const typeBase = tableName.charAt(0).toUpperCase() + tableName.slice(1);
|
||||||
resourceNames.set(tableName, typeBase);
|
resourceNames.set(tableName, typeBase);
|
||||||
|
|
@ -551,10 +561,8 @@ function generateTypeDefinition(
|
||||||
// Generate import path based on current file path
|
// Generate import path based on current file path
|
||||||
let importPath: string;
|
let importPath: string;
|
||||||
if (currentFilePath) {
|
if (currentFilePath) {
|
||||||
// Both files are in the same directory, use relative path
|
|
||||||
importPath = `./${tableName}.csv`;
|
importPath = `./${tableName}.csv`;
|
||||||
} else {
|
} else {
|
||||||
// Fallback for unknown path
|
|
||||||
importPath = `../${tableName}.csv`;
|
importPath = `../${tableName}.csv`;
|
||||||
}
|
}
|
||||||
imports.push(`import type { ${typeBase} } from '${importPath}';`);
|
imports.push(`import type { ${typeBase} } from '${importPath}';`);
|
||||||
|
|
@ -793,15 +801,17 @@ function generateSchemaResolutionCode(
|
||||||
case 'union': {
|
case 'union': {
|
||||||
const refMembers = schema.members.filter(m => hasNestedReferences(m));
|
const refMembers = schema.members.filter(m => hasNestedReferences(m));
|
||||||
const nonRefMembers = schema.members.filter(m => !hasNestedReferences(m));
|
const nonRefMembers = schema.members.filter(m => !hasNestedReferences(m));
|
||||||
const parts: string[] = [];
|
const resolveParts: string[] = [];
|
||||||
for (const member of refMembers) {
|
for (const member of refMembers) {
|
||||||
const resolveCode = generateSchemaResolutionCode(member, valueExpr, lookupVar, pkField);
|
const resolveCode = generateSchemaResolutionCode(member, valueExpr, lookupVar, pkField);
|
||||||
parts.push(resolveCode);
|
resolveParts.push(resolveCode);
|
||||||
}
|
}
|
||||||
if (nonRefMembers.length > 0) {
|
if (nonRefMembers.length > 0) {
|
||||||
parts.push(valueExpr);
|
resolveParts.push(valueExpr);
|
||||||
}
|
}
|
||||||
return parts[0] || valueExpr;
|
if (resolveParts.length === 0) return valueExpr;
|
||||||
|
if (resolveParts.length === 1) return resolveParts[0];
|
||||||
|
return `(${resolveParts.join(' ?? ')})`;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
return valueExpr;
|
return valueExpr;
|
||||||
|
|
@ -834,14 +844,26 @@ export function csvToModule(
|
||||||
const lookupInits: string[] = [];
|
const lookupInits: string[] = [];
|
||||||
const lookupVarMap = new Map<string, string>();
|
const lookupVarMap = new Map<string, string>();
|
||||||
|
|
||||||
|
const currentTableName = options.currentFilePath
|
||||||
|
? path.basename(options.currentFilePath, path.extname(options.currentFilePath))
|
||||||
|
: undefined;
|
||||||
|
|
||||||
const uniqueTables = new Set(result.referenceFields.map(f => f.tableName));
|
const uniqueTables = new Set(result.referenceFields.map(f => f.tableName));
|
||||||
uniqueTables.forEach(tableName => {
|
uniqueTables.forEach(tableName => {
|
||||||
const varName = `_${tableName}`;
|
const lookupVar = `_${tableName}Lookup`;
|
||||||
lookupVarMap.set(tableName, `_${tableName}Lookup`);
|
lookupVarMap.set(tableName, lookupVar);
|
||||||
imports.push(`import ${varName} from './${tableName}.csv';`);
|
|
||||||
lookupInits.push(
|
if (tableName === currentTableName) {
|
||||||
`const _${tableName}Lookup = new Map(${varName}().map(p => [String(p.${defaultPrimaryKey}), p]));`
|
lookupInits.push(
|
||||||
);
|
`const ${lookupVar} = new Map(_raw.map(p => [String(p.${defaultPrimaryKey}), p]));`
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
const varName = `_${tableName}`;
|
||||||
|
imports.push(`import ${varName} from './${tableName}.csv';`);
|
||||||
|
lookupInits.push(
|
||||||
|
`const ${lookupVar} = new Map(${varName}().map(p => [String(p.${defaultPrimaryKey}), p]));`
|
||||||
|
);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const lookupVar = (tableName: string) => lookupVarMap.get(tableName)!;
|
const lookupVar = (tableName: string) => lookupVarMap.get(tableName)!;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue