Skip to content

Commit b05c174

Browse files
authored
feat: add --namespace CLI option (#22)
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 ```
1 parent 683de80 commit b05c174

File tree

6 files changed

+149
-41
lines changed

6 files changed

+149
-41
lines changed

src/contentful-typescript-codegen.ts

+8-1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ const cli = meow(
1414
--output, -o Where to write to
1515
--poll, -p Continuously refresh types
1616
--interval N, -i The interval in seconds at which to poll (defaults to 15)
17+
--namespace N, -n Wrap types in namespace N (disabled by default)
1718
--fields-only Output a tree that _only_ ensures fields are valid
1819
and present, and does not provide types for Sys,
1920
Assets, or Rich Text. This is useful for ensuring raw
@@ -44,6 +45,11 @@ const cli = meow(
4445
alias: "i",
4546
required: false,
4647
},
48+
namespace: {
49+
type: "string",
50+
alias: "n",
51+
required: false,
52+
},
4753
localization: {
4854
type: "boolean",
4955
alias: "l",
@@ -63,10 +69,11 @@ async function runCodegen(outputFile: string) {
6369

6470
let output
6571
if (cli.flags.fieldsOnly) {
66-
output = await renderFieldsOnly(contentTypes.items)
72+
output = await renderFieldsOnly(contentTypes.items, { namespace: cli.flags.namespace })
6773
} else {
6874
output = await render(contentTypes.items, locales.items, {
6975
localization: cli.flags.localization,
76+
namespace: cli.flags.namespace,
7077
})
7178
}
7279

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
export default function renderNamespace(source: string, namespace: string | undefined) {
2+
if (!namespace) return source
3+
4+
return `
5+
declare namespace ${namespace} {
6+
${source}
7+
}
8+
9+
export as namespace ${namespace}
10+
export=${namespace}
11+
`
12+
}

src/renderers/render.ts

+6-2
Original file line numberDiff line numberDiff line change
@@ -7,21 +7,23 @@ import renderContentType from "./contentful/renderContentType"
77
import renderUnion from "./typescript/renderUnion"
88
import renderAllLocales from "./contentful/renderAllLocales"
99
import renderDefaultLocale from "./contentful/renderDefaultLocale"
10+
import renderNamespace from "./contentful/renderNamespace"
1011
import renderLocalizedTypes from "./contentful/renderLocalizedTypes"
1112

1213
interface Options {
1314
localization?: boolean
15+
namespace?: string
1416
}
1517

1618
export default async function render(
1719
contentTypes: ContentType[],
1820
locales: Locale[],
19-
{ localization = false }: Options = {},
21+
{ namespace, localization = false }: Options = {},
2022
) {
2123
const sortedContentTypes = contentTypes.sort((a, b) => a.sys.id.localeCompare(b.sys.id))
2224
const sortedLocales = locales.sort((a, b) => a.code.localeCompare(b.code))
2325

24-
const source = [
26+
const typingsSource = [
2527
renderContentfulImports(localization),
2628
renderAllContentTypes(sortedContentTypes, localization),
2729
renderAllContentTypeIds(sortedContentTypes),
@@ -30,6 +32,8 @@ export default async function render(
3032
renderLocalizedTypes(localization),
3133
].join("\n\n")
3234

35+
const source = [renderContentfulImports(), renderNamespace(typingsSource, namespace)].join("\n\n")
36+
3337
const prettierConfig = await resolveConfig(process.cwd())
3438
return format(source, { ...prettierConfig, parser: "typescript" })
3539
}

src/renderers/renderFieldsOnly.ts

+11-2
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,20 @@ import { ContentType } from "contentful"
33
import { format, resolveConfig } from "prettier"
44

55
import renderContentType from "./contentful-fields-only/renderContentType"
6+
import renderNamespace from "./contentful/renderNamespace"
67

7-
export default async function renderFieldsOnly(contentTypes: ContentType[]) {
8+
interface Options {
9+
namespace?: string
10+
}
11+
12+
export default async function renderFieldsOnly(
13+
contentTypes: ContentType[],
14+
{ namespace }: Options = {},
15+
) {
816
const sortedContentTypes = contentTypes.sort((a, b) => a.sys.id.localeCompare(b.sys.id))
917

10-
const source = renderAllContentTypes(sortedContentTypes)
18+
const typingsSource = renderAllContentTypes(sortedContentTypes)
19+
const source = [renderNamespace(typingsSource, namespace)].join("\n\n")
1120

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

test/renderers/render.test.ts

+58
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,11 @@ describe("render()", () => {
5858
import { Asset, Entry } from \\"contentful\\"
5959
import { Document } from \\"@contentful/rich-text-types\\"
6060
61+
// THIS FILE IS AUTOMATICALLY GENERATED. DO NOT MODIFY IT.
62+
63+
import { Asset, Entry } from \\"contentful\\"
64+
import { Document } from \\"@contentful/rich-text-types\\"
65+
6166
export interface IMyContentTypeFields {
6267
/** Array field */
6368
arrayField: (\\"one\\" | \\"of\\" | \\"the\\" | \\"above\\")[]
@@ -125,6 +130,11 @@ describe("render()", () => {
125130
expect(await render(contentTypes, locales, { localization: true })).toMatchInlineSnapshot(`
126131
"// THIS FILE IS AUTOMATICALLY GENERATED. DO NOT MODIFY IT.
127132
133+
import { Asset, Entry } from \\"contentful\\"
134+
import { Document } from \\"@contentful/rich-text-types\\"
135+
136+
// THIS FILE IS AUTOMATICALLY GENERATED. DO NOT MODIFY IT.
137+
128138
import { Entry } from \\"contentful\\"
129139
import { Document } from \\"@contentful/rich-text-types\\"
130140
@@ -182,4 +192,52 @@ describe("render()", () => {
182192
"
183193
`)
184194
})
195+
196+
it("renders given a content type inside a namespace", async () => {
197+
expect(await render(contentTypes, locales, { namespace: "Codegen" })).toMatchInlineSnapshot(`
198+
"// THIS FILE IS AUTOMATICALLY GENERATED. DO NOT MODIFY IT.
199+
200+
import { Asset, Entry } from \\"contentful\\"
201+
import { Document } from \\"@contentful/rich-text-types\\"
202+
203+
declare namespace Codegen {
204+
// THIS FILE IS AUTOMATICALLY GENERATED. DO NOT MODIFY IT.
205+
206+
import { Asset, Entry } from \\"contentful\\"
207+
import { Document } from \\"@contentful/rich-text-types\\"
208+
209+
export interface IMyContentTypeFields {
210+
/** Array field */
211+
arrayField: (\\"one\\" | \\"of\\" | \\"the\\" | \\"above\\")[]
212+
}
213+
214+
export interface IMyContentType extends Entry<IMyContentTypeFields> {
215+
sys: {
216+
id: string
217+
type: string
218+
createdAt: string
219+
updatedAt: string
220+
locale: string
221+
contentType: {
222+
sys: {
223+
id: \\"myContentType\\"
224+
linkType: \\"ContentType\\"
225+
type: \\"Link\\"
226+
}
227+
}
228+
}
229+
}
230+
231+
export type CONTENT_TYPE = \\"myContentType\\"
232+
233+
export type LOCALE_CODE = \\"en-US\\" | \\"pt-BR\\"
234+
235+
export type CONTENTFUL_DEFAULT_LOCALE_CODE = \\"en-US\\"
236+
}
237+
238+
export as namespace Codegen
239+
export = Codegen
240+
"
241+
`)
242+
})
185243
})

test/renderers/renderFieldsOnly.test.ts

+54-36
Original file line numberDiff line numberDiff line change
@@ -2,47 +2,65 @@ import renderFieldsOnly from "../../src/renderers/renderFieldsOnly"
22
import { ContentType, Sys } from "contentful"
33

44
describe("renderFieldsOnly()", () => {
5-
it("renders given a content type", async () => {
6-
const contentTypes: ContentType[] = [
7-
{
8-
sys: {
9-
id: "myContentType",
10-
} as Sys,
11-
fields: [
12-
{
13-
id: "arrayField",
14-
name: "Array field",
15-
required: true,
16-
validations: [{}],
17-
items: {
18-
type: "Symbol",
19-
validations: [
20-
{
21-
in: ["one", "of", "the", "above"],
22-
},
23-
],
24-
},
25-
disabled: false,
26-
omitted: false,
27-
localized: false,
28-
type: "Array",
5+
const contentTypes: ContentType[] = [
6+
{
7+
sys: {
8+
id: "myContentType",
9+
} as Sys,
10+
fields: [
11+
{
12+
id: "arrayField",
13+
name: "Array field",
14+
required: true,
15+
validations: [{}],
16+
items: {
17+
type: "Symbol",
18+
validations: [
19+
{
20+
in: ["one", "of", "the", "above"],
21+
},
22+
],
2923
},
30-
],
31-
description: "",
32-
displayField: "",
33-
name: "",
34-
toPlainObject: () => ({} as ContentType),
35-
},
36-
]
24+
disabled: false,
25+
omitted: false,
26+
localized: false,
27+
type: "Array",
28+
},
29+
],
30+
description: "",
31+
displayField: "",
32+
name: "",
33+
toPlainObject: () => ({} as ContentType),
34+
},
35+
]
3736

37+
it("renders a given content type", async () => {
3838
expect(await renderFieldsOnly(contentTypes)).toMatchInlineSnapshot(`
39-
"export interface IMyContentType {
40-
fields: {
41-
/** Array field */
42-
arrayField: (\\"one\\" | \\"of\\" | \\"the\\" | \\"above\\")[]
39+
"export interface IMyContentType {
40+
fields: {
41+
/** Array field */
42+
arrayField: (\\"one\\" | \\"of\\" | \\"the\\" | \\"above\\")[]
43+
}
44+
[otherKeys: string]: any
45+
}
46+
"
47+
`)
48+
})
49+
50+
it("renders a given content type inside a namespace", async () => {
51+
expect(await renderFieldsOnly(contentTypes, { namespace: "Codegen" })).toMatchInlineSnapshot(`
52+
"declare namespace Codegen {
53+
export interface IMyContentType {
54+
fields: {
55+
/** Array field */
56+
arrayField: (\\"one\\" | \\"of\\" | \\"the\\" | \\"above\\")[]
57+
}
58+
[otherKeys: string]: any
4359
}
44-
[otherKeys: string]: any
4560
}
61+
62+
export as namespace Codegen
63+
export = Codegen
4664
"
4765
`)
4866
})

0 commit comments

Comments
 (0)