Skip to content

Commit

Permalink
fix: references in generated output
Browse files Browse the repository at this point in the history
- fixed issues with missing references in the template input & generated output
- fixed typescript-with-decoders template for avoiding conflicting typenames for oneOf
- added strict checking for file name case for avoiding conflicting definitions written in diff files with diff file filename case
  • Loading branch information
sinha-sahil committed Jan 1, 2024
1 parent 1bb1982 commit 7e6b880
Show file tree
Hide file tree
Showing 6 changed files with 68 additions and 19 deletions.
8 changes: 8 additions & 0 deletions .changeset/spicy-candles-try.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
'type-crafter': patch
---

fix: conflicting type name & missing imports in generated output

- fixed issues with conflicting types in same file & missing type imports in generated output
- made filename case sensitive fro avoiding same types written in two different files with different naming case
31 changes: 21 additions & 10 deletions src/generators/generic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ async function generateObjectType(
properties: {}
};

let recursiveTypeGenOutput: GeneratedType<TemplateInput> | null = null;
const compositions: Array<GeneratedType<TemplateInput>> = [];
let dynamicGeneratedType: string = '';

const primitives: string[] = [];
Expand Down Expand Up @@ -205,12 +205,13 @@ async function generateObjectType(
languageDataType = arrayDataGenOutput.templateInput.type;
composerType = arrayDataGenOutput.templateInput.composerType ?? null;
} else if (propertyType === 'object') {
recursivePropertyName = toPascalCase(propertyName);
recursiveTypeGenOutput = await generateObjectType(
recursivePropertyName = typeName + toPascalCase(propertyName);
const recursiveTypeGenOutput = await generateObjectType(
recursivePropertyName,
typeInfo.properties[propertyName],
parentTypes
);
compositions.push(recursiveTypeGenOutput);
languageDataType = recursivePropertyName;
references.push(...recursiveTypeGenOutput.references);
primitives.push(...recursiveTypeGenOutput.primitives);
Expand Down Expand Up @@ -258,7 +259,9 @@ async function generateObjectType(
const result: GeneratedType<ObjectTemplateInput> = {
content:
Runtime.getObjectTemplate()(templateInput) +
(recursiveTypeGenOutput?.content ?? '') +
compositions.reduce((acc, curr) => {
return acc + curr.content;
}, '') +
dynamicGeneratedType,
primitives: new Set(primitives),
references: new Set(references),
Expand Down Expand Up @@ -425,13 +428,17 @@ async function generateOneOfTypes(
for (let index = 0; index < typeInfo.oneOf.length; index++) {
const oneOfItem = typeInfo.oneOf[index];
if (oneOfItem.$ref !== null) {
const referenceData = await resolveTypeReference(oneOfItem.$ref);
const referenceData = await generateReferencedType(
typeName + (index + 1),
oneOfItem,
parentTypes
);
const composition: OneOfTemplateInputComposition = {
source: 'referenced',
referencedType: referenceData.name
referencedType: referenceData.templateInput.typeName
};
templateInput.compositions.push(composition);
result.references.add(referenceData.name);
result.references.add(referenceData.templateInput.typeName);
} else {
const generatedType = await generateType(typeName + (index + 1), oneOfItem, parentTypes);

Expand Down Expand Up @@ -487,13 +494,17 @@ async function generateAllOfTypes(
for (let index = 0; index < typeInfo.allOf.length; index++) {
const allOfItem = typeInfo.allOf[index];
if (allOfItem.$ref !== null) {
const referenceData = await resolveTypeReference(allOfItem.$ref);
const referenceData = await generateReferencedType(
typeName + 'AllOf' + index,
allOfItem,
parentTypes
);
const composition: OneOfTemplateInputComposition = {
source: 'referenced',
referencedType: referenceData.name
referencedType: referenceData.templateInput.typeName
};
templateInput.compositions.push(composition);
result.references.add(referenceData.name);
result.references.add(referenceData.templateInput.typeName);
} else {
const generatedType = await generateType(typeName + (index + 1), allOfItem, parentTypes);

Expand Down
5 changes: 4 additions & 1 deletion src/templates/typescript-with-decoders/object-syntax.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
* @example {{{example}}}
{{/if}}
*/
export type {{typeName}} = {
export type {{typeName}} = {{#if (not (isEmptyObject properties))}} {
{{#each properties}}
/**
{{#if this.description}}
Expand All @@ -25,6 +25,9 @@ export type {{typeName}} = {
[keys: {{jsonKey additionalProperties.keyType}}]: {{additionalProperties.valueType}};
{{/if}}
};
{{else if (or (notEq length additionalProperties 0) (not (isEmptyObject additionalProperties)))}}
Record<{{jsonKey additionalProperties.keyType}}, {{additionalProperties.valueType}}>;
{{/if}}

export function decode{{typeName}}(rawInput: unknown): {{typeName}} | null {
if (isJSON(rawInput)) {
Expand Down
16 changes: 8 additions & 8 deletions src/templates/typescript-with-decoders/oneOf-syntax.hbs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
export type {{typeName}} =
{{#each compositions}}
| {{#if (eq this.source 'referenced')}}C{{referencedType}}
| {{#if (eq this.source 'referenced')}}C{{../typeName}}{{referencedType}}
{{else if (eq this.source 'inline')}}
{{#if this.templateInput.values}}
{{this.templateInput.typeName}}
{{else if (eq this.dataType 'object')}}
C{{this.templateInput.typeName}}
C{{typeName}}{{this.templateInput.typeName}}
{{else}}
{{this.templateInput.type}}
{{/if}}
Expand All @@ -16,7 +16,7 @@ export function decode{{typeName}}(rawInput: unknown): {{typeName}} | null {
const result: {{typeName}} | null =
{{#each compositions}}
{{#if (eq this.source 'referenced')}}
decodeC{{referencedType}}(rawInput)
decodeC{{../typeName}}{{referencedType}}(rawInput)
{{else if (eq this.dataType 'object')}}
decodeC{{this.templateInput.typeName}}(rawInput)
{{else if (eq this.dataType 'array')}}
Expand All @@ -36,26 +36,26 @@ export function decode{{typeName}}(rawInput: unknown): {{typeName}} | null {
{{#if this.templateInput.values}}
{{{this.content}}}
{{else if (eq this.source 'referenced')}}
export class C{{referencedType}} {
export class C{{../typeName}}{{referencedType}} {
data: {{referencedType}};
constructor(data: {{referencedType}}) {
this.data = data;
}
}

export function decodeC{{referencedType}}(rawInput: unknown): C{{referencedType}} | null {
export function decodeC{{../typeName}}{{referencedType}}(rawInput: unknown): C{{../typeName}}{{referencedType}} | null {
const result = decode{{referencedType}}(rawInput);
if (result === null) {
return null;
}
return new C{{referencedType}}(result);
return new C{{../typeName}}{{referencedType}}(result);
}

{{else if (eq this.dataType 'object')}}

{{{this.content}}}

export class C{{this.templateInput.typeName}} {
export class C{{../typeName}}{{this.templateInput.typeName}} {
data: {{this.templateInput.typeName}};
constructor(data: {{this.templateInput.typeName}}) {
this.data = data;
Expand All @@ -67,7 +67,7 @@ export function decodeC{{this.templateInput.typeName}}(rawInput: unknown) {
if (result === null) {
return null;
}
return new C{{this.templateInput.typeName}}(result);
return new C{{../typeName}}{{this.templateInput.typeName}}(result);
}

{{/if}}
Expand Down
11 changes: 11 additions & 0 deletions src/utils/file-system.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,21 @@ export function resolveFilePath(filePath: string, useCurrentDirectory: boolean =
return path.resolve(normalizedPath);
}

async function checkFileNameCase(filePath: string): Promise<boolean> {
const directory = path.dirname(filePath);
const fileName = path.basename(filePath);

const files = await fs.readdir(directory);
return files.includes(fileName);
}

export async function readFile(
filePath: string,
useCurrentWorkingDirectory: boolean = true
): Promise<string> {
if (!(await checkFileNameCase(filePath))) {
throw new Error(`File not found: ${filePath}`);
}
const data = await fs.readFile(resolveFilePath(filePath, useCurrentWorkingDirectory), 'utf-8');
return data;
}
Expand Down
16 changes: 16 additions & 0 deletions src/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -151,9 +151,25 @@ export function registerTemplateHelpers(): void {
(value: unknown) => Array.isArray(value) && value.length === 0
);
Handlebars.registerHelper('eq', (value1: unknown, value2: unknown) => value1 === value2);
Handlebars.registerHelper('notEq', (value1: unknown, value2: unknown) => value1 !== value2);
Handlebars.registerHelper(
'isEmptyObject',
(value: unknown) =>
typeof value === 'object' && value !== null && Object.keys(value).length === 0
);
Handlebars.registerHelper('jsonKey', refineJSONKey);
Handlebars.registerHelper('variableName', refineVariableName);
Handlebars.registerHelper('indexKey', refineIndexKey);
Handlebars.registerHelper('not', (value: unknown) => {
if (typeof value === 'boolean') {
return !value;
}
});
Handlebars.registerHelper('or', (value1: unknown, value2: unknown) => {
if (typeof value1 === 'boolean' && typeof value2 === 'boolean') {
return value1 || value2;
}
});
}

export function readNestedValue(json: unknown, keyPath: string[]): JSONObject {
Expand Down

0 comments on commit 7e6b880

Please sign in to comment.