Skip to content

Added prefix and suffix support #47

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 31 additions & 1 deletion src/contentful-typescript-codegen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ const cli = meow(
Options
--output, -o Where to write to
--poll, -p Continuously refresh types
--prefix STR, -P Define prefix STR for types, defaults to 'I'
--suffix STR, -S Define suffix STR for types, defaults to empty string
--no-prefix, -nP Disable prefix completely
--no-suffix, -nS Disable suffix completely
--interval N, -i The interval in seconds at which to poll (defaults to 15)
--namespace N, -n Wrap types in namespace N (disabled by default)
--fields-only Output a tree that _only_ ensures fields are valid
Expand Down Expand Up @@ -40,6 +44,26 @@ const cli = meow(
alias: "p",
required: false,
},
prefix: {
type: "string",
alias: "P",
required: false,
},
suffix: {
type: "string",
alias: "S",
required: false,
},
noPrefix: {
type: "boolean",
alias: "nP",
required: false,
},
noSuffix: {
type: "boolean",
alias: "nS",
required: false,
},
interval: {
type: "string",
alias: "i",
Expand Down Expand Up @@ -69,11 +93,17 @@ async function runCodegen(outputFile: string) {

let output
if (cli.flags.fieldsOnly) {
output = await renderFieldsOnly(contentTypes.items, { namespace: cli.flags.namespace })
output = await renderFieldsOnly(contentTypes.items, {
namespace: cli.flags.namespace,
prefix: cli.flags.noPrefix ? "" : cli.flags.prefix,
suffix: cli.flags.noSuffix ? "" : cli.flags.suffix,
})
} else {
output = await render(contentTypes.items, locales.items, {
localization: cli.flags.localization,
namespace: cli.flags.namespace,
prefix: cli.flags.noPrefix ? "" : cli.flags.prefix,
suffix: cli.flags.noSuffix ? "" : cli.flags.suffix,
})
}

Expand Down
7 changes: 3 additions & 4 deletions src/renderers/contentful-fields-only/fields/renderArray.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@ import { Field } from "contentful"
import renderSymbol from "../../contentful/fields/renderSymbol"
import renderLink from "../../contentful-fields-only/fields/renderLink"
import renderArrayOf from "../../typescript/renderArrayOf"
import { Options } from "../../renderFieldsOnly"

export default function renderArray(field: Field): string {
export default function renderArray(field: Field, options: Options): string {
if (!field.items) {
throw new Error(`Cannot render non-array field ${field.id} as an array`)
}
Expand All @@ -20,9 +21,7 @@ export default function renderArray(field: Field): string {
}

case "Link": {
return renderArrayOf(renderLink(fieldWithValidations))
return renderArrayOf(renderLink(fieldWithValidations, options))
}
}

return renderArrayOf("unknown")
}
7 changes: 5 additions & 2 deletions src/renderers/contentful-fields-only/fields/renderLink.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { Field } from "contentful"
import renderContentTypeId from "../../contentful/renderContentTypeId"
import { renderUnionValues } from "../../typescript/renderUnion"
import { Options } from "../../renderFieldsOnly"

export default function renderLink(field: Field): string {
export default function renderLink(field: Field, options: Options): string {
if (field.linkType === "Asset") {
return "any"
}
Expand All @@ -11,7 +12,9 @@ export default function renderLink(field: Field): string {
const contentTypeValidation = field.validations.find(validation => !!validation.linkContentType)

if (contentTypeValidation) {
return renderUnionValues(contentTypeValidation.linkContentType!.map(renderContentTypeId))
return renderUnionValues(
contentTypeValidation.linkContentType!.map(link => renderContentTypeId(link, options)),
)
} else {
return "unknown"
}
Expand Down
14 changes: 8 additions & 6 deletions src/renderers/contentful-fields-only/renderContentType.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { ContentType, Field, FieldType } from "contentful"

import { Options } from "../renderFieldsOnly"

import renderInterface from "../typescript/renderInterface"
import renderField from "../contentful/renderField"
import renderContentTypeId from "../contentful/renderContentTypeId"
Expand All @@ -14,9 +16,9 @@ import renderNumber from "../contentful/fields/renderNumber"
import renderObject from "../contentful/fields/renderObject"
import renderSymbol from "../contentful/fields/renderSymbol"

export default function renderContentType(contentType: ContentType): string {
const name = renderContentTypeId(contentType.sys.id)
const fields = renderContentTypeFields(contentType.fields)
export default function renderContentType(contentType: ContentType, options: Options): string {
const name = renderContentTypeId(contentType.sys.id, options)
const fields = renderContentTypeFields(contentType.fields, options)

return renderInterface({
name,
Expand All @@ -27,11 +29,11 @@ export default function renderContentType(contentType: ContentType): string {
})
}

function renderContentTypeFields(fields: Field[]): string {
function renderContentTypeFields(fields: Field[], options: Options): string {
return fields
.filter(field => !field.omitted)
.map<string>(field => {
const functionMap: Record<FieldType, (field: Field) => string> = {
const functionMap: Record<FieldType, (field: Field, options: Options) => string> = {
Array: renderArray,
Boolean: renderBoolean,
Date: renderSymbol,
Expand All @@ -45,7 +47,7 @@ function renderContentTypeFields(fields: Field[]): string {
Text: renderSymbol,
}

return renderField(field, functionMap[field.type](field))
return renderField(field, functionMap[field.type](field, options), options)
})
.join("\n\n")
}
7 changes: 3 additions & 4 deletions src/renderers/contentful/fields/renderArray.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@ import { Field } from "contentful"
import renderSymbol from "./renderSymbol"
import renderLink from "./renderLink"
import renderArrayOf from "../../typescript/renderArrayOf"
import { Options } from "../../render"

export default function renderArray(field: Field): string {
export default function renderArray(field: Field, options: Options): string {
if (!field.items) {
throw new Error(`Cannot render non-array field ${field.id} as an array`)
}
Expand All @@ -20,9 +21,7 @@ export default function renderArray(field: Field): string {
}

case "Link": {
return renderArrayOf(renderLink(fieldWithValidations))
return renderArrayOf(renderLink(fieldWithValidations, options))
}
}

return renderArrayOf("unknown")
}
7 changes: 5 additions & 2 deletions src/renderers/contentful/fields/renderLink.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { Field } from "contentful"
import renderContentTypeId from "../renderContentTypeId"
import { renderUnionValues } from "../../typescript/renderUnion"
import { Options } from "../../render"

export default function renderLink(field: Field): string {
export default function renderLink(field: Field, options: Options): string {
if (field.linkType === "Asset") {
return "Asset"
}
Expand All @@ -11,7 +12,9 @@ export default function renderLink(field: Field): string {
const contentTypeValidation = field.validations.find(validation => !!validation.linkContentType)

if (contentTypeValidation) {
return renderUnionValues(contentTypeValidation.linkContentType!.map(renderContentTypeId))
return renderUnionValues(
contentTypeValidation.linkContentType!.map(link => renderContentTypeId(link, options)),
)
} else {
return "Entry<{ [fieldId: string]: unknown }>"
}
Expand Down
14 changes: 8 additions & 6 deletions src/renderers/contentful/renderContentType.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { ContentType, Field, FieldType, Sys } from "contentful"

import { Options } from "../render"

import renderInterface from "../typescript/renderInterface"
import renderField from "./renderField"
import renderContentTypeId from "./renderContentTypeId"
Expand All @@ -13,9 +15,9 @@ import renderObject from "./fields/renderObject"
import renderRichText from "./fields/renderRichText"
import renderSymbol from "./fields/renderSymbol"

export default function renderContentType(contentType: ContentType, localization: boolean): string {
const name = renderContentTypeId(contentType.sys.id)
const fields = renderContentTypeFields(contentType.fields, localization)
export default function renderContentType(contentType: ContentType, options: Options): string {
const name = renderContentTypeId(contentType.sys.id, options)
const fields = renderContentTypeFields(contentType.fields, options)
const sys = renderSys(contentType.sys)

return `
Expand All @@ -34,11 +36,11 @@ function descriptionComment(description: string | undefined) {
return ""
}

function renderContentTypeFields(fields: Field[], localization: boolean): string {
function renderContentTypeFields(fields: Field[], options: Options): string {
return fields
.filter(field => !field.omitted)
.map<string>(field => {
const functionMap: Record<FieldType, (field: Field) => string> = {
const functionMap: Record<FieldType, (field: Field, options: Options) => string> = {
Array: renderArray,
Boolean: renderBoolean,
Date: renderSymbol,
Expand All @@ -52,7 +54,7 @@ function renderContentTypeFields(fields: Field[], localization: boolean): string
Text: renderSymbol,
}

return renderField(field, functionMap[field.type](field), localization)
return renderField(field, functionMap[field.type](field, options), options)
})
.join("\n\n")
}
Expand Down
12 changes: 10 additions & 2 deletions src/renderers/contentful/renderContentTypeId.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
import { upperFirst, camelCase } from "lodash"
import { Options } from "../render"

export default function renderContentTypeId(contentTypeId: string): string {
return "I" + upperFirst(camelCase(contentTypeId))
export default function renderContentTypeId(contentTypeId: string, options: Options): string {
let str = upperFirst(camelCase(contentTypeId))

if (options.prefix === undefined) options.prefix = "I"

if (options.prefix) str = options.prefix + str
if (options.suffix) str = str + options.suffix

return str
}
9 changes: 3 additions & 6 deletions src/renderers/contentful/renderField.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
import { Field } from "contentful"
import renderInterfaceProperty from "../typescript/renderInterfaceProperty"
import { Options } from "../render"

export default function renderField(
field: Field,
type: string,
localization: boolean = false,
): string {
return renderInterfaceProperty(field.id, type, field.required, localization, field.name)
export default function renderField(field: Field, type: string, options: Options): string {
return renderInterfaceProperty(field.id, type, field.required, options.localization, field.name)
}
15 changes: 10 additions & 5 deletions src/renderers/render.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,21 +10,26 @@ import renderDefaultLocale from "./contentful/renderDefaultLocale"
import renderNamespace from "./contentful/renderNamespace"
import renderLocalizedTypes from "./contentful/renderLocalizedTypes"

interface Options {
export interface Options {
localization?: boolean
namespace?: string
prefix?: string
suffix?: string
}

export const defaultOptions: Options = {}

export default async function render(
contentTypes: ContentType[],
locales: Locale[],
{ namespace, localization = false }: Options = {},
options: Options,
) {
const { namespace, localization = false } = options
const sortedContentTypes = contentTypes.sort((a, b) => a.sys.id.localeCompare(b.sys.id))
const sortedLocales = locales.sort((a, b) => a.code.localeCompare(b.code))

const typingsSource = [
renderAllContentTypes(sortedContentTypes, localization),
renderAllContentTypes(sortedContentTypes, options),
renderAllContentTypeIds(sortedContentTypes),
renderAllLocales(sortedLocales),
renderDefaultLocale(sortedLocales),
Expand All @@ -40,8 +45,8 @@ export default async function render(
return format(source, { ...prettierConfig, parser: "typescript" })
}

function renderAllContentTypes(contentTypes: ContentType[], localization: boolean): string {
return contentTypes.map(contentType => renderContentType(contentType, localization)).join("\n\n")
function renderAllContentTypes(contentTypes: ContentType[], options: Options): string {
return contentTypes.map(contentType => renderContentType(contentType, options)).join("\n\n")
}

function renderAllContentTypeIds(contentTypes: ContentType[]): string {
Expand Down
17 changes: 8 additions & 9 deletions src/renderers/renderFieldsOnly.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,24 +5,23 @@ import { format, resolveConfig } from "prettier"
import renderContentType from "./contentful-fields-only/renderContentType"
import renderNamespace from "./contentful/renderNamespace"

interface Options {
export interface Options {
namespace?: string
prefix?: string
suffix?: string
}

export default async function renderFieldsOnly(
contentTypes: ContentType[],
{ namespace }: Options = {},
) {
export default async function renderFieldsOnly(contentTypes: ContentType[], options: Options) {
const sortedContentTypes = contentTypes.sort((a, b) => a.sys.id.localeCompare(b.sys.id))

const typingsSource = renderAllContentTypes(sortedContentTypes)
const source = [renderNamespace(typingsSource, namespace)].join("\n\n")
const typingsSource = renderAllContentTypes(sortedContentTypes, options)
const source = [renderNamespace(typingsSource, options.namespace)].join("\n\n")

const prettierConfig = await resolveConfig(process.cwd())

return format(source, { ...prettierConfig, parser: "typescript" })
}

function renderAllContentTypes(contentTypes: ContentType[]): string {
return contentTypes.map(contentType => renderContentType(contentType)).join("\n\n")
function renderAllContentTypes(contentTypes: ContentType[], options: Options): string {
return contentTypes.map(contentType => renderContentType(contentType, options)).join("\n\n")
}
2 changes: 1 addition & 1 deletion src/renderers/typescript/renderInterfaceProperty.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ export default function renderInterfaceProperty(
name: string,
type: string,
required: boolean,
localization: boolean,
localization?: boolean,
description?: string,
): string {
return [
Expand Down
Loading