Skip to content

Commit

Permalink
feat: add --namespace CLI option (#22)
Browse files Browse the repository at this point in the history
Add `--namespace N, -n Wrap types in namespace (disabled by default)` option that will wrap the generated types in a namespace 

---
Example: 

`$ npx contentful-typescript-codegen --output ./contentful.d.ts -n Codegen`

```ts
declare namespace Codegen {
...
}

export as namespace Codegen
export = Codegen
```
  • Loading branch information
zernie authored Apr 16, 2020
1 parent 683de80 commit b05c174
Show file tree
Hide file tree
Showing 6 changed files with 149 additions and 41 deletions.
9 changes: 8 additions & 1 deletion src/contentful-typescript-codegen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ const cli = meow(
--output, -o Where to write to
--poll, -p Continuously refresh types
--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
and present, and does not provide types for Sys,
Assets, or Rich Text. This is useful for ensuring raw
Expand Down Expand Up @@ -44,6 +45,11 @@ const cli = meow(
alias: "i",
required: false,
},
namespace: {
type: "string",
alias: "n",
required: false,
},
localization: {
type: "boolean",
alias: "l",
Expand All @@ -63,10 +69,11 @@ async function runCodegen(outputFile: string) {

let output
if (cli.flags.fieldsOnly) {
output = await renderFieldsOnly(contentTypes.items)
output = await renderFieldsOnly(contentTypes.items, { namespace: cli.flags.namespace })
} else {
output = await render(contentTypes.items, locales.items, {
localization: cli.flags.localization,
namespace: cli.flags.namespace,
})
}

Expand Down
12 changes: 12 additions & 0 deletions src/renderers/contentful/renderNamespace.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
export default function renderNamespace(source: string, namespace: string | undefined) {
if (!namespace) return source

return `
declare namespace ${namespace} {
${source}
}
export as namespace ${namespace}
export=${namespace}
`
}
8 changes: 6 additions & 2 deletions src/renderers/render.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,23 @@ import renderContentType from "./contentful/renderContentType"
import renderUnion from "./typescript/renderUnion"
import renderAllLocales from "./contentful/renderAllLocales"
import renderDefaultLocale from "./contentful/renderDefaultLocale"
import renderNamespace from "./contentful/renderNamespace"
import renderLocalizedTypes from "./contentful/renderLocalizedTypes"

interface Options {
localization?: boolean
namespace?: string
}

export default async function render(
contentTypes: ContentType[],
locales: Locale[],
{ localization = false }: Options = {},
{ 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 source = [
const typingsSource = [
renderContentfulImports(localization),
renderAllContentTypes(sortedContentTypes, localization),
renderAllContentTypeIds(sortedContentTypes),
Expand All @@ -30,6 +32,8 @@ export default async function render(
renderLocalizedTypes(localization),
].join("\n\n")

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

const prettierConfig = await resolveConfig(process.cwd())
return format(source, { ...prettierConfig, parser: "typescript" })
}
Expand Down
13 changes: 11 additions & 2 deletions src/renderers/renderFieldsOnly.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,20 @@ import { ContentType } from "contentful"
import { format, resolveConfig } from "prettier"

import renderContentType from "./contentful-fields-only/renderContentType"
import renderNamespace from "./contentful/renderNamespace"

export default async function renderFieldsOnly(contentTypes: ContentType[]) {
interface Options {
namespace?: string
}

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

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

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

Expand Down
58 changes: 58 additions & 0 deletions test/renderers/render.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,11 @@ describe("render()", () => {
import { Asset, Entry } from \\"contentful\\"
import { Document } from \\"@contentful/rich-text-types\\"
// THIS FILE IS AUTOMATICALLY GENERATED. DO NOT MODIFY IT.
import { Asset, Entry } from \\"contentful\\"
import { Document } from \\"@contentful/rich-text-types\\"
export interface IMyContentTypeFields {
/** Array field */
arrayField: (\\"one\\" | \\"of\\" | \\"the\\" | \\"above\\")[]
Expand Down Expand Up @@ -125,6 +130,11 @@ describe("render()", () => {
expect(await render(contentTypes, locales, { localization: true })).toMatchInlineSnapshot(`
"// THIS FILE IS AUTOMATICALLY GENERATED. DO NOT MODIFY IT.
import { Asset, Entry } from \\"contentful\\"
import { Document } from \\"@contentful/rich-text-types\\"
// THIS FILE IS AUTOMATICALLY GENERATED. DO NOT MODIFY IT.
import { Entry } from \\"contentful\\"
import { Document } from \\"@contentful/rich-text-types\\"
Expand Down Expand Up @@ -182,4 +192,52 @@ describe("render()", () => {
"
`)
})

it("renders given a content type inside a namespace", async () => {
expect(await render(contentTypes, locales, { namespace: "Codegen" })).toMatchInlineSnapshot(`
"// THIS FILE IS AUTOMATICALLY GENERATED. DO NOT MODIFY IT.
import { Asset, Entry } from \\"contentful\\"
import { Document } from \\"@contentful/rich-text-types\\"
declare namespace Codegen {
// THIS FILE IS AUTOMATICALLY GENERATED. DO NOT MODIFY IT.
import { Asset, Entry } from \\"contentful\\"
import { Document } from \\"@contentful/rich-text-types\\"
export interface IMyContentTypeFields {
/** Array field */
arrayField: (\\"one\\" | \\"of\\" | \\"the\\" | \\"above\\")[]
}
export interface IMyContentType extends Entry<IMyContentTypeFields> {
sys: {
id: string
type: string
createdAt: string
updatedAt: string
locale: string
contentType: {
sys: {
id: \\"myContentType\\"
linkType: \\"ContentType\\"
type: \\"Link\\"
}
}
}
}
export type CONTENT_TYPE = \\"myContentType\\"
export type LOCALE_CODE = \\"en-US\\" | \\"pt-BR\\"
export type CONTENTFUL_DEFAULT_LOCALE_CODE = \\"en-US\\"
}
export as namespace Codegen
export = Codegen
"
`)
})
})
90 changes: 54 additions & 36 deletions test/renderers/renderFieldsOnly.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,47 +2,65 @@ import renderFieldsOnly from "../../src/renderers/renderFieldsOnly"
import { ContentType, Sys } from "contentful"

describe("renderFieldsOnly()", () => {
it("renders given a content type", async () => {
const contentTypes: ContentType[] = [
{
sys: {
id: "myContentType",
} as Sys,
fields: [
{
id: "arrayField",
name: "Array field",
required: true,
validations: [{}],
items: {
type: "Symbol",
validations: [
{
in: ["one", "of", "the", "above"],
},
],
},
disabled: false,
omitted: false,
localized: false,
type: "Array",
const contentTypes: ContentType[] = [
{
sys: {
id: "myContentType",
} as Sys,
fields: [
{
id: "arrayField",
name: "Array field",
required: true,
validations: [{}],
items: {
type: "Symbol",
validations: [
{
in: ["one", "of", "the", "above"],
},
],
},
],
description: "",
displayField: "",
name: "",
toPlainObject: () => ({} as ContentType),
},
]
disabled: false,
omitted: false,
localized: false,
type: "Array",
},
],
description: "",
displayField: "",
name: "",
toPlainObject: () => ({} as ContentType),
},
]

it("renders a given content type", async () => {
expect(await renderFieldsOnly(contentTypes)).toMatchInlineSnapshot(`
"export interface IMyContentType {
fields: {
/** Array field */
arrayField: (\\"one\\" | \\"of\\" | \\"the\\" | \\"above\\")[]
"export interface IMyContentType {
fields: {
/** Array field */
arrayField: (\\"one\\" | \\"of\\" | \\"the\\" | \\"above\\")[]
}
[otherKeys: string]: any
}
"
`)
})

it("renders a given content type inside a namespace", async () => {
expect(await renderFieldsOnly(contentTypes, { namespace: "Codegen" })).toMatchInlineSnapshot(`
"declare namespace Codegen {
export interface IMyContentType {
fields: {
/** Array field */
arrayField: (\\"one\\" | \\"of\\" | \\"the\\" | \\"above\\")[]
}
[otherKeys: string]: any
}
[otherKeys: string]: any
}
export as namespace Codegen
export = Codegen
"
`)
})
Expand Down

0 comments on commit b05c174

Please sign in to comment.