Skip to main content

client-generators

Write or change a Redocly client generator — the API model, the language-neutral helper toolkit, and the edit → regenerate → diff loop.

ソース情報

リポジトリ
Redocly/redocly-cli
ソースの最終更新活動
2026年10月8日 14:40
検出された SKILL.md の言語
英語
スター
1,523
フォーク
230

インストール方法

デフォルトでは、最初にソースを確認する Prompt が選択されています。直接コマンドに切り替えるか、ローカルコピーをダウンロードすることもできます。

ソースファイルを確認

インストールを決める前に、SKILL.md と SkillsMP に表示されている付属ファイルをお読みください。

SKILL.md を表示中

SKILL.md
ソースの指示 · 読み取り専用プレビュー
name
client-generators
description
Write or change a Redocly client generator — the API model, the language-neutral helper toolkit, and the edit → regenerate → diff loop.
# Writing custom client generators A generator is a plain module: `(input) => GeneratedFile[]`. It receives the language-agnostic API model and returns files — in ANY output language. It runs in the same pass as the built-ins; select it by path in `redocly.yaml`: ```yaml client: generators: [typescript, ./generators/my-generator.mjs] ``` ## The contract ```js /** @type {import('@redocly/client-generator').CustomGenerator} */ export default { name: 'my-generator', run({ model, output, outputMode, emit }) { return [{ path: output.path.replace(/\.ts$/, '.mine.txt'), content: '…' }]; }, // Optional: one idiomatic call snippet per operation for docs (x-codeSamples), // collected into an overlay file when `client.codeSamples: true` is set. sample(operation, { model, emit }) { return { lang: 'python', source: '…' }; }, // Optional: the reference page for what `run` emits, written when `client.docs` (or // --docs) is on. Same `{ path, content }` shape as `run`; `renderReferencePage` gives // the standard layout and takes `sample` for its snippets. A generator documents itself. docs({ model, output, emit }) { return [{ path: output.path.replace(/\.ts$/, '.mine.md'), content: '…' }]; }, }; ``` ## Declaring options A generator that needs configuration declares it as a schema; `run` then receives `options` already validated, with defaults applied: ```js export default { name: 'permissions-matrix', options: { type: 'object', properties: { groupBy: { enum: ['tag', 'path'], default: 'tag' } }, additionalProperties: false, }, run({ model, output, options }) { return [ { path: output.path.replace(/\.ts$/, '.permissions.md'), content: render(options.groupBy) }, ]; }, }; ``` Users set them per generator name: ```yaml client: generators: [typescript, ./generators/permissions-matrix.mjs] options: permissions-matrix: groupBy: path ``` The supported subset is a top-level `type: 'object'` with `properties`, `required`, and `additionalProperties`; each property is a scalar (`string`/`number`/`boolean`), an `enum`, or an array of scalars, and may carry a `default` and a `description`. Don't validate options inside `run` — an unknown key, a wrong type, a value outside an `enum`, or a missing `required` key already fails generation before `run` is called. Rules: output is deterministic (same description → same bytes); never add dependencies to the generated client; **never hand-edit generated output** — edit this generator and regenerate. Emitted file paths must stay inside the `--output` directory (subdirectories are fine) — escapes are rejected. Optionally declare `requiresGenerator` — the `@redocly/client-generator` version range you wrote this against (`'^1.2.0'`, `'~1.2.0'`, `'>=1.2.0'`, or an exact version). A CLI outside the range then fails with the fix path instead of feeding your generator an unexpected model shape. Ejected generators carry it automatically; hand-written ones without it are taken as current. ## The model (IR) `model.services[].operations[]` — each operation carries `name`, `specName`, `method`, `path`, `tags`, `pathParams`/`queryParams`/`headerParams`/`cookieParams`, `requestBody`, `successResponses`/`errorResponses` (each with a `schema`), and `security`. `model.schemas` holds the named schemas. Every schema is a discriminated union on `kind`: `scalar`, `array`, `object`, `record`, `ref`, `literal`, `enum`, `union` (optionally with a discriminator), `intersection` (allOf), `null`, `unknown`, `omit`. ## Helpers (import from '@redocly/client-generator') | Helper | Use | | ------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ | | `flattenAllOf(schema, model)` | The merged property view of allOf compositions — languages without intersection types render this. | | `deref(schema, model)` | Follow a `ref` chain to the schema it names (cycle-guarded). | | `jsonSuccessSchema(op)` / `sseResponse(op)` | The primary JSON success schema; the `text/event-stream` response when the operation streams. | | `isMultipartBody(op)` | Whether the request body is multipart. | | `isUntypedMultipartBody(op)` | Whether the request body is multipart with a schema that is neither an object nor a `$ref`, so the caller supplies the encoded body. | | `isBinaryContentType(contentType)` | Whether a body of this content type is bytes (archives, PDF, images, media) — decode it as a Blob, not JSON or text. | | `serverUrlParts(server)` | A server-URL template as literal/variable parts, ready for any concatenation syntax. | | `securityRequirements(op, model)` | The operation's security as OR-alternatives of AND-sets, denormalized against the declared schemes. | | `paginationItemSchema(pageSchema, itemsPointer, model)` | The raw element schema behind a pagination rule's `items` pointer — a `ref` element keeps its name. | | `discriminatorCases(schema, model)` | `{ property, cases }` dispatch table for discriminated unions. | | `isNullable(schema)` / `unwrapNullable(schema)` | Detect and strip `null` union members (`Optional[T]`, pointers, `Option<T>`). | | `enumValues(schema)` | Values plus SCREAMING_SNAKE member-name suggestions. | | `headerCoerceType(schema, model)` | Response-header coerce hint (`integer`/`number`/`boolean`/`string`) through refs, nullables, and allOf wrappers. | | `casing` / `identifierFor(name, { style, reserved })` | camel/pascal/snake/screaming; keyword-safe identifiers (`RESERVED_WORDS.python/go/typescript` shipped). | | `uniqueIdentifiers(names, { style, reserved, taken })` | The same, made unique among themselves and among names you already took — for a signature that takes one argument per parameter. | | `Printer` | Indentation-aware text builder — no manual whitespace bookkeeping. | | `docText(description)` | Description as trimmed lines for any comment syntax. | | `schemaAtPointer(schema, pointer, model)` | Resolve an RFC 6901 JSON pointer over a schema (through refs and allOf) — e.g. a pagination `items` pointer to its element type. | | `paginationRuleFor(op, config)` | The pagination rule that applies to an operation (per-op config > extension > fitting convention), normalized. | | `renderReferencePage(model, options)` | The Markdown reference page a generator's `docs` hook returns — your `sample` hook supplies its call snippets. | | `NotSupportedError` | Throw it to reject an option the generator can't honor — the CLI prints the message as a user error, not a crash. | | `AUTHORING_HELPER_NAMES` | The list of the above (introspection). | Worked example: the built-in `python` generator (`packages/client-generator/src/generators/python/index.ts` in the Redocly CLI repo) is authored with exactly this toolkit and nothing else — models via `flattenAllOf`/ `enumValues`/`discriminatorCases`, all code through `Printer`, every name through `identifierFor(..., RESERVED_WORDS.python)`. A generator that emits TypeScript may additionally use the source-text renderers from `@redocly/client-generator/generate` — `tsType` (schema → type), `tsJsdoc`, `codeLiteral`, `operationSignature`, `pascalCase`, `safeIdent`. There is no AST toolkit and no `typescript` dependency: every generator prints text through `Printer`. ## The loop 1. Edit the generator. 2. Run `redocly generate-client`. 3. Inspect `git diff` of the generated output. 4. Repeat. Generated files are never hand-edited. If you had to work around a **missing helper** or a wrong default, tell the user and suggest filing an issue at https://github.com/Redocly/redocly-cli/issues — include the generator snippet and the helper you expected to exist.
GitHubで見る