-
Notifications
You must be signed in to change notification settings - Fork 26
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
4 changed files
with
306 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,168 @@ | ||
import { Project, SourceFile } from 'ts-morph'; | ||
import { CFContentType } from '../../types'; | ||
import { renderTypeGeneric } from '../generic'; | ||
import { BaseContentTypeRenderer } from './base-content-type-renderer'; | ||
|
||
/* | ||
* Renders the response types for the contentful content types | ||
* Based on https://github.com/contentful/contentful.js/issues/2138#issuecomment-1921923508 | ||
*/ | ||
|
||
const ChainModifiers = { | ||
WITH_UNRESOLVABLE_LINKS: 'WithUnresolvableLinksResponse', | ||
WITHOUT_UNRESOLVABLE_LINKS: 'WithoutUnresolvableLinksResponse', | ||
WITHOUT_LINK_RESOLUTION: 'WithoutLinkResolutionResponse', | ||
WITH_ALL_LOCALES: 'WithAllLocalesResponse', | ||
WITH_ALL_LOCALES_AND_WITHOUT_LINK_RESOLUTION: 'WithAllLocalesAndWithoutLinkResolutionResponse', | ||
WITH_ALL_LOCALES_AND_WITHOUT_UNRESOLVABLE_LINK: | ||
'WithAllLocalesAndWithoutUnresolvableLinksResponse', | ||
}; | ||
|
||
const LocaleWithDefaultTypeString = 'Locales extends LocaleCode = LocaleCode'; | ||
|
||
export class ResponseTypeRenderer extends BaseContentTypeRenderer { | ||
public static readonly FILE_BASE_NAME = 'ResponseType'; | ||
protected readonly files: SourceFile[]; | ||
|
||
constructor() { | ||
super(); | ||
this.files = []; | ||
} | ||
|
||
public override setup(project: Project): void { | ||
super.setup(project); | ||
const file = project.createSourceFile(`${ResponseTypeRenderer.FILE_BASE_NAME}.ts`, undefined, { | ||
overwrite: true, | ||
}); | ||
|
||
file.addImportDeclaration({ | ||
moduleSpecifier: 'contentful', | ||
namedImports: ['Entry', 'EntrySkeletonType', 'FieldsType', 'LocaleCode'], | ||
isTypeOnly: true, | ||
}); | ||
|
||
file.addStatements('/* Utility types for response types */'); | ||
|
||
file.addTypeAlias({ | ||
name: `${ChainModifiers.WITH_UNRESOLVABLE_LINKS}<T extends EntrySkeletonType<FieldsType, string>>`, | ||
type: `Entry<T>`, | ||
isExported: true, | ||
}); | ||
|
||
file.addTypeAlias({ | ||
name: `${ChainModifiers.WITH_ALL_LOCALES}<T extends EntrySkeletonType<FieldsType, string>, ${LocaleWithDefaultTypeString}>`, | ||
type: `Entry<T, 'WITH_ALL_LOCALES', Locales>`, | ||
isExported: true, | ||
}); | ||
|
||
file.addTypeAlias({ | ||
name: `${ChainModifiers.WITHOUT_LINK_RESOLUTION}<T extends EntrySkeletonType<FieldsType>>`, | ||
type: `Entry<T, 'WITHOUT_LINK_RESOLUTION'>`, | ||
isExported: true, | ||
}); | ||
|
||
file.addTypeAlias({ | ||
name: `${ChainModifiers.WITHOUT_UNRESOLVABLE_LINKS}<T extends EntrySkeletonType<FieldsType>>`, | ||
type: `Entry<T, 'WITHOUT_UNRESOLVABLE_LINKS'>`, | ||
isExported: true, | ||
}); | ||
|
||
file.addTypeAlias({ | ||
name: `${ChainModifiers.WITH_ALL_LOCALES_AND_WITHOUT_UNRESOLVABLE_LINK}<T extends EntrySkeletonType<FieldsType, string>, ${LocaleWithDefaultTypeString}>`, | ||
type: `Entry<T, 'WITH_ALL_LOCALES' | 'WITHOUT_UNRESOLVABLE_LINKS', Locales>`, | ||
isExported: true, | ||
}); | ||
|
||
file.addTypeAlias({ | ||
name: `${ChainModifiers.WITH_ALL_LOCALES_AND_WITHOUT_LINK_RESOLUTION}<T extends EntrySkeletonType<FieldsType>, ${LocaleWithDefaultTypeString}>`, | ||
type: `Entry<T, 'WITH_ALL_LOCALES' | 'WITHOUT_LINK_RESOLUTION', Locales>`, | ||
isExported: true, | ||
}); | ||
|
||
file.formatText(); | ||
this.files.push(file); | ||
} | ||
|
||
public render = (contentType: CFContentType, file: SourceFile): void => { | ||
const context = this.createContext(); | ||
|
||
const entitySkeletonName = context.moduleSkeletonName(contentType.sys.id); | ||
const entityName = context.moduleName(contentType.sys.id); | ||
|
||
// file.addImportDeclaration({ | ||
// moduleSpecifier: `./${ResponseTypeRenderer.FILE_BASE_NAME}`, | ||
// namedImports: Object.values(ChainModifiers), | ||
// isTypeOnly: true, | ||
// }); | ||
|
||
context.imports.add({ | ||
moduleSpecifier: `./${ResponseTypeRenderer.FILE_BASE_NAME}`, | ||
namedImports: Object.values(ChainModifiers), | ||
isTypeOnly: true, | ||
}); | ||
|
||
// file.addImportDeclaration({ | ||
// moduleSpecifier: `./${context.moduleName(contentType.sys.id)}`, | ||
// namedImports: [entitySkeletonName], | ||
// isTypeOnly: true, | ||
// }); | ||
|
||
file.addTypeAlias({ | ||
name: `${entityName}${ChainModifiers.WITH_UNRESOLVABLE_LINKS}`, | ||
isExported: true, | ||
type: renderTypeGeneric(ChainModifiers.WITH_UNRESOLVABLE_LINKS, entitySkeletonName), | ||
}); | ||
|
||
file.addTypeAlias({ | ||
name: `${entityName}${ChainModifiers.WITHOUT_LINK_RESOLUTION}`, | ||
isExported: true, | ||
type: renderTypeGeneric(ChainModifiers.WITHOUT_LINK_RESOLUTION, entitySkeletonName), | ||
}); | ||
|
||
file.addTypeAlias({ | ||
name: `${entityName}${ChainModifiers.WITHOUT_UNRESOLVABLE_LINKS}`, | ||
isExported: true, | ||
type: renderTypeGeneric(ChainModifiers.WITHOUT_UNRESOLVABLE_LINKS, entitySkeletonName), | ||
}); | ||
|
||
file.addTypeAlias({ | ||
name: `${entityName}${ChainModifiers.WITH_ALL_LOCALES}<${LocaleWithDefaultTypeString}>`, | ||
isExported: true, | ||
type: renderTypeGeneric(ChainModifiers.WITH_ALL_LOCALES, entitySkeletonName, 'Locales'), | ||
}); | ||
|
||
file.addTypeAlias({ | ||
name: `${entityName}${ChainModifiers.WITH_ALL_LOCALES_AND_WITHOUT_LINK_RESOLUTION}<${LocaleWithDefaultTypeString}>`, | ||
isExported: true, | ||
type: renderTypeGeneric( | ||
ChainModifiers.WITH_ALL_LOCALES_AND_WITHOUT_LINK_RESOLUTION, | ||
entitySkeletonName, | ||
'Locales', | ||
), | ||
}); | ||
|
||
file.addTypeAlias({ | ||
name: `${entityName}${ChainModifiers.WITH_ALL_LOCALES_AND_WITHOUT_UNRESOLVABLE_LINK}<${LocaleWithDefaultTypeString}>`, | ||
isExported: true, | ||
type: renderTypeGeneric( | ||
ChainModifiers.WITH_ALL_LOCALES_AND_WITHOUT_UNRESOLVABLE_LINK, | ||
entitySkeletonName, | ||
'Locales', | ||
), | ||
}); | ||
|
||
file.organizeImports({ | ||
ensureNewLineAtEndOfFile: true, | ||
}); | ||
|
||
for (const structure of context.imports) { | ||
file.addImportDeclaration(structure); | ||
} | ||
|
||
file.formatText(); | ||
}; | ||
|
||
public additionalFiles(): SourceFile[] { | ||
return this.files; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
import { Project, ScriptTarget, SourceFile } from 'ts-morph'; | ||
import { CFContentType } from '../../../src'; | ||
import { ResponseTypeRenderer } from '../../../src/renderer/type/response-type-renderer'; | ||
import stripIndent = require('strip-indent'); | ||
|
||
describe('A response type renderer class', () => { | ||
let project: Project; | ||
let testFile: SourceFile; | ||
|
||
beforeEach(() => { | ||
project = new Project({ | ||
useInMemoryFileSystem: true, | ||
compilerOptions: { | ||
target: ScriptTarget.ES5, | ||
declaration: true, | ||
}, | ||
}); | ||
testFile = project.createSourceFile('test.ts'); | ||
}); | ||
|
||
it('adds ResponseType.ts on setup', () => { | ||
const renderer = new ResponseTypeRenderer(); | ||
renderer.setup(project); | ||
|
||
const file = project.getSourceFile('ResponseType.ts'); | ||
|
||
// console.log(file?.getFullText()); | ||
|
||
expect(file?.getFullText()).toEqual( | ||
stripIndent( | ||
` | ||
import type { Entry, EntrySkeletonType, FieldsType, LocaleCode } from "contentful"; | ||
/* Utility types for response types */ | ||
export type WithUnresolvableLinksResponse<T extends EntrySkeletonType<FieldsType, string>> = Entry<T>; | ||
export type WithAllLocalesResponse<T extends EntrySkeletonType<FieldsType, string>, Locales extends LocaleCode = LocaleCode> = Entry<T, 'WITH_ALL_LOCALES', Locales>; | ||
export type WithoutLinkResolutionResponse<T extends EntrySkeletonType<FieldsType>> = Entry<T, 'WITHOUT_LINK_RESOLUTION'>; | ||
export type WithoutUnresolvableLinksResponse<T extends EntrySkeletonType<FieldsType>> = Entry<T, 'WITHOUT_UNRESOLVABLE_LINKS'>; | ||
export type WithAllLocalesAndWithoutUnresolvableLinksResponse<T extends EntrySkeletonType<FieldsType, string>, Locales extends LocaleCode = LocaleCode> = Entry<T, 'WITH_ALL_LOCALES' | 'WITHOUT_UNRESOLVABLE_LINKS', Locales>; | ||
export type WithAllLocalesAndWithoutLinkResolutionResponse<T extends EntrySkeletonType<FieldsType>, Locales extends LocaleCode = LocaleCode> = Entry<T, 'WITH_ALL_LOCALES' | 'WITHOUT_LINK_RESOLUTION', Locales>; | ||
` | ||
.replace(/.*/, '') | ||
.slice(1), | ||
), | ||
); | ||
}); | ||
|
||
it('adds localized-entry.ts on setup', () => { | ||
const renderer = new ResponseTypeRenderer(); | ||
renderer.setup(project); | ||
|
||
const contentType: CFContentType = { | ||
name: 'display name', | ||
sys: { | ||
id: 'test', | ||
type: 'Symbol', | ||
}, | ||
fields: [ | ||
{ | ||
id: 'field_id', | ||
name: 'field_name', | ||
disabled: false, | ||
localized: false, | ||
required: true, | ||
type: 'Symbol', | ||
omitted: false, | ||
validations: [], | ||
}, | ||
], | ||
}; | ||
|
||
renderer.render(contentType, testFile); | ||
|
||
expect(testFile.getFullText()).toEqual( | ||
stripIndent( | ||
` | ||
import type { WithAllLocalesAndWithoutLinkResolutionResponse, WithAllLocalesAndWithoutUnresolvableLinksResponse, WithAllLocalesResponse, WithUnresolvableLinksResponse, WithoutLinkResolutionResponse, WithoutUnresolvableLinksResponse } from "./ResponseType"; | ||
import type { TypeTestSkeleton } from "./TypeTest"; | ||
export type TypeTestWithUnresolvableLinksResponse = WithUnresolvableLinksResponse<TypeTestSkeleton>; | ||
export type TypeTestWithoutLinkResolutionResponse = WithoutLinkResolutionResponse<TypeTestSkeleton>; | ||
export type TypeTestWithoutUnresolvableLinksResponse = WithoutUnresolvableLinksResponse<TypeTestSkeleton>; | ||
export type TypeTestWithAllLocalesResponse<Locales extends LocaleCode = LocaleCode> = WithAllLocalesResponse<TypeTestSkeleton, Locales>; | ||
export type TypeTestWithAllLocalesAndWithoutLinkResolutionResponse<Locales extends LocaleCode = LocaleCode> = WithAllLocalesAndWithoutLinkResolutionResponse<TypeTestSkeleton, Locales>; | ||
export type TypeTestWithAllLocalesAndWithoutUnresolvableLinksResponse<Locales extends LocaleCode = LocaleCode> = WithAllLocalesAndWithoutUnresolvableLinksResponse<TypeTestSkeleton, Locales>; | ||
`, | ||
) | ||
.replace(/.*/, '') | ||
.slice(1), | ||
); | ||
}); | ||
}); |