@wasl-flow/codegen-contentful
v1.0.1
Published
Generate TypeScript interfaces and optional Zod schemas from Contentful content types via the Content Management API (CMA).
Maintainers
Readme
@wasl-flow/codegen-contentful
Generate TypeScript interfaces and optional Zod schemas from Contentful content types via the Content Management API (CMA).
Install
npm install @wasl-flow/codegen-contentful
# or
pnpm add @wasl-flow/codegen-contentfulQuick Start
# Using CLI arguments
npx codegen-contentful \
--token <CMA_TOKEN> \
--space <SPACE_ID> \
--out-dir ./src/generated/contentful
# Using environment variables (.env)
CONTENTFUL_MANAGEMENT_TOKEN=<token>
CONTENTFUL_SPACE_ID=<space_id>
CONTENTFUL_ENV_ID=master
npx codegen-contentful --out-dir ./src/generated/contentfulCLI Options
| Flag | Environment Variable | Default | Description |
| ---------------------- | ----------------------------- | ---------------------------- | ----------------------------------------- |
| --token | CONTENTFUL_MANAGEMENT_TOKEN | - | Contentful Management Token |
| --space | CONTENTFUL_SPACE_ID | - | Contentful Space ID |
| --env | CONTENTFUL_ENV_ID | master | Environment ID |
| --out-dir | - | ./src/generated/contentful | Output directory |
| --file-mode | - | single | single or per-type |
| --single-file-name | - | contentful-data-models.ts | Output file name for single mode |
| --name-suffix | - | DataModel | Type name suffix |
| --model-shape | - | enveloped | enveloped or flat |
| --type-field | - | type | Type discriminator field name |
| --collision-strategy | - | error | Flat collisions: error or overwrite |
| --zod | - | true | Generate Zod schemas (false to disable) |
| --format | - | none | none or prettier |
| --strict-validations | - | false | Throw on unsupported validations |
Note: --zod false disables schema generation. When --format prettier is selected, output is formatted with Prettier (fallbacks to unformatted output if Prettier cannot be loaded).
Output Modes
Single File
- Default:
contentful-data-models.ts - Configurable via
--single-file-name - Contains all interfaces and optional schemas.
Model Shape
enveloped(default):{ [typeField]: '<contentTypeId>', fields: { ...contentFields }, sys?: Record<string, unknown> }- Avoids key collisions with content fields.
flat:{ [typeField]: '<contentTypeId>', ...contentFields, sys?: Record<string, unknown> }- Can collide when content has fields named
typeFieldorsys. - Use
--collision-strategy overwriteto allow collisions in generated output.
Per-Type
- One file per content type (named from the type ID + suffix)
AssetDataModel.tsfor asset referencesindex.tsexporting all generated types- Stale generated
.tsfiles are removed if they start with the generator header. A legacy_shared.tsis also removed if present.
Type Mapping
| Contentful | TypeScript | Zod |
| ------------ | ----------------------------------------------------- | ------------------------------------------------ |
| Symbol/Text | string or string literal union from in validation | z.string() or z.enum([...]) |
| Integer | number | z.number().int() |
| Number | number | z.number() |
| Boolean | boolean | z.boolean() |
| Date | string | z.string() |
| RichText | unknown | z.unknown() |
| Object | Record<string, unknown> | z.record(z.unknown()) |
| Location | { lat: number; lon: number } | z.object({ lat: z.number(), lon: z.number() }) |
| Link (Asset) | AssetDataModel | AssetDataModelSchema |
| Link (Entry) | <Type>DataModel or union | <Type>DataModelSchema or z.union([...]) |
| Array | T[] | z.array(...) |
If a Link field does not declare entry content types, the generator falls back to unknown.
Validation Support
Supported validations are mapped when possible. Unsupported validations are emitted as TODO comments unless --strict-validations is enabled, in which case generation fails.
infor Symbol/Text becomes a literal union orz.enum([...]).regexpfor Symbol/Text becomesz.string().regex(...).rangefor Number/Integer becomes.min()/.max().sizefor Array becomes.min()/.max().
Circular References And Ordering
The generator builds a reference graph across content types and topologically sorts output so referenced types appear first. Circular references are detected and logged, and Zod schemas use z.lazy() to break cycles.
Programmatic API
import { generate, type CliOptions } from '@wasl-flow/codegen-contentful';
const options: CliOptions = {
token: process.env.CONTENTFUL_MANAGEMENT_TOKEN!,
space: process.env.CONTENTFUL_SPACE_ID!,
env: 'master',
outDir: './src/generated/contentful',
fileMode: 'single',
singleFileName: 'contentful-data-models.ts',
nameSuffix: 'DataModel',
modelShape: 'enveloped',
typeField: 'type',
collisionStrategy: 'error',
zod: true,
format: 'none',
strictValidations: false,
};
await generate(options);Limitations
- Rich text fields are typed as
unknown. - Link fields without explicit
linkContentTypevalidations are typed asunknown. - Only the validation rules described above are enforced at generation time.
