Skip to content
Merged
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
5 changes: 5 additions & 0 deletions .changeset/eight-dodos-find.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@hey-api/codegen-core": patch
---

**node**: add `~dsl` property
5 changes: 5 additions & 0 deletions .changeset/eighty-cats-kneel.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@hey-api/shared": patch
---

**plugin**: add generics support to `querySymbol()` and `querySymbols()`
5 changes: 5 additions & 0 deletions .changeset/eleven-bees-invite.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@hey-api/openapi-ts": patch
---

**cli**: simplify generate command messages
5 changes: 5 additions & 0 deletions .changeset/huge-pets-remain.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@hey-api/openapi-ts": patch
---

**plugin(valibot)**: fix: revert referencing TypeScript enums
5 changes: 5 additions & 0 deletions .changeset/tired-suits-hunt.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@hey-api/openapi-ts": patch
---

**plugin(zod)**: fix: revert referencing TypeScript enums
17 changes: 17 additions & 0 deletions dev/inputs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,27 @@ export const inputs = {
clerk: path.resolve(specsPath, '3.0.x', 'clerk-2025-11-10.yaml'),
cloudflare: path.resolve(specsPath, '3.0.x', 'cloudflare-v4.json'),
full: path.resolve(specsPath, '3.1.x', 'full.yaml'),
'hey-api': 'hey-api/backend',
local: 'http://localhost:8000/openapi.json',
opencode: path.resolve(specsPath, '3.1.x', 'opencode.yaml'),
petstore:
'https://raw.githubusercontent.com/swagger-api/swagger-petstore/master/src/main/resources/openapi.yaml',
raw: {
components: {
schemas: {
Foo: {
type: 'string',
},
},
},
info: {
title: 'Raw Spec',
version: '1.0.0',
},
openapi: '3.1.0',
} as const,
readme: 'readme:@developers/v2.0#nysezql0wwo236',
'readme-uuid': 'readme:nysezql0wwo236',
redfish:
'https://raw.githubusercontent.com/DMTF/Redfish-Publications/refs/heads/main/openapi/openapi.yaml',
scalar: 'scalar:@scalar/access-service',
Expand Down
4 changes: 4 additions & 0 deletions packages/codegen-core/src/nodes/node.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import type { AnyString } from '@hey-api/types';

import type { File } from '../files/file';
import type { Language } from '../languages/types';
import type { IAnalysisContext } from '../planner/types';
Expand Down Expand Up @@ -46,4 +48,6 @@ export interface INode<T = unknown> {
toAst(): T;
/** Brand used for renderer dispatch. */
readonly '~brand': string;
/** Branding property to identify the DSL class at runtime. */
readonly '~dsl'?: AnyString;
}
10 changes: 5 additions & 5 deletions packages/openapi-python/src/createClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,8 @@ export async function createClient({
const inputPaths = config.input.map((input) => compileInputPath(input));

// on first run, print the message as soon as possible
if (config.logs.level !== 'silent' && !_watches) {
logInputPaths(inputPaths, jobIndex);
if (!_watches) {
logInputPaths(inputPaths, jobIndex, config.logs.level);
}

const getSpecData = async (input: Input, index: number) => {
Expand Down Expand Up @@ -116,9 +116,9 @@ export async function createClient({

// on subsequent runs in watch mode, print the message only if we know we're
// generating the output
if (config.logs.level !== 'silent' && _watches) {
if (_watches) {
console.clear();
logInputPaths(inputPaths, jobIndex);
logInputPaths(inputPaths, jobIndex, config.logs.level);
}

const eventInputPatch = logger.timeEvent('input.patch');
Expand Down Expand Up @@ -183,7 +183,7 @@ export async function createClient({
? `./${path.relative(process.env.INIT_CWD, config.output.path)}`
: config.output.path;
console.log(
`${jobPrefix}${colors.green('✅ Done!')} Your output is in ${colors.cyanBright(outputPath)} ${colors.gray(`(${fileCount} ${fileCount === 1 ? 'file' : 'files'} in ${ms(totalMs)})`)}`,
`${jobPrefix}${colors.green('')} ${colors.cyanBright(outputPath)} ${colors.gray(`· ${fileCount} ${fileCount === 1 ? 'file' : 'files'} · ${ms(totalMs)}`)}`,
);
}
}
Expand Down
26 changes: 13 additions & 13 deletions packages/openapi-ts-tests/main/test/3.1.x.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -378,14 +378,14 @@ describe(`OpenAPI ${version}`, () => {
},
{
config: createConfig({
input: 'enum-names-values.yaml',
input: 'enum-names-values.json',
output: 'enum-names-values',
}),
description: 'handles various enum names and values',
},
{
config: createConfig({
input: 'enum-names-values.yaml',
input: 'enum-names-values.json',
output: 'enum-names-values-javascript-SCREAMING_SNAKE_CASE',
plugins: [
{
Expand All @@ -401,7 +401,7 @@ describe(`OpenAPI ${version}`, () => {
},
{
config: createConfig({
input: 'enum-names-values.yaml',
input: 'enum-names-values.json',
output: 'enum-names-values-javascript-PascalCase',
plugins: [
{
Expand All @@ -417,7 +417,7 @@ describe(`OpenAPI ${version}`, () => {
},
{
config: createConfig({
input: 'enum-names-values.yaml',
input: 'enum-names-values.json',
output: 'enum-names-values-javascript-camelCase',
plugins: [
{
Expand All @@ -433,7 +433,7 @@ describe(`OpenAPI ${version}`, () => {
},
{
config: createConfig({
input: 'enum-names-values.yaml',
input: 'enum-names-values.json',
output: 'enum-names-values-javascript-snake_case',
plugins: [
{
Expand All @@ -449,7 +449,7 @@ describe(`OpenAPI ${version}`, () => {
},
{
config: createConfig({
input: 'enum-names-values.yaml',
input: 'enum-names-values.json',
output: 'enum-names-values-javascript-preserve',
plugins: [
{
Expand All @@ -465,7 +465,7 @@ describe(`OpenAPI ${version}`, () => {
},
{
config: createConfig({
input: 'enum-names-values.yaml',
input: 'enum-names-values.json',
output: 'enum-names-values-javascript-ignore-null',
plugins: [
{
Expand All @@ -482,7 +482,7 @@ describe(`OpenAPI ${version}`, () => {
},
{
config: createConfig({
input: 'enum-names-values.yaml',
input: 'enum-names-values.json',
output: 'enum-names-values-typescript-SCREAMING_SNAKE_CASE',
plugins: [
{
Expand All @@ -498,7 +498,7 @@ describe(`OpenAPI ${version}`, () => {
},
{
config: createConfig({
input: 'enum-names-values.yaml',
input: 'enum-names-values.json',
output: 'enum-names-values-typescript-PascalCase',
plugins: [
{
Expand All @@ -514,7 +514,7 @@ describe(`OpenAPI ${version}`, () => {
},
{
config: createConfig({
input: 'enum-names-values.yaml',
input: 'enum-names-values.json',
output: 'enum-names-values-typescript-camelCase',
plugins: [
{
Expand All @@ -530,7 +530,7 @@ describe(`OpenAPI ${version}`, () => {
},
{
config: createConfig({
input: 'enum-names-values.yaml',
input: 'enum-names-values.json',
output: 'enum-names-values-typescript-snake_case',
plugins: [
{
Expand All @@ -546,7 +546,7 @@ describe(`OpenAPI ${version}`, () => {
},
{
config: createConfig({
input: 'enum-names-values.yaml',
input: 'enum-names-values.json',
output: 'enum-names-values-typescript-preserve',
plugins: [
{
Expand All @@ -562,7 +562,7 @@ describe(`OpenAPI ${version}`, () => {
},
{
config: createConfig({
input: 'enum-names-values.yaml',
input: 'enum-names-values.json',
output: 'enum-names-values-typescript-const',
plugins: [
{
Expand Down
10 changes: 5 additions & 5 deletions packages/openapi-ts/src/createClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,8 @@ export async function createClient({
const inputPaths = config.input.map((input) => compileInputPath(input));

// on first run, print the message as soon as possible
if (config.logs.level !== 'silent' && !_watches) {
logInputPaths(inputPaths, jobIndex);
if (!_watches) {
logInputPaths(inputPaths, jobIndex, config.logs.level);
}

const getSpecData = async (input: Input, index: number) => {
Expand Down Expand Up @@ -116,9 +116,9 @@ export async function createClient({

// on subsequent runs in watch mode, print the message only if we know we're
// generating the output
if (config.logs.level !== 'silent' && _watches) {
if (_watches) {
console.clear();
logInputPaths(inputPaths, jobIndex);
logInputPaths(inputPaths, jobIndex, config.logs.level);
}

const eventInputPatch = logger.timeEvent('input.patch');
Expand Down Expand Up @@ -183,7 +183,7 @@ export async function createClient({
? `./${path.relative(process.env.INIT_CWD, config.output.path)}`
: config.output.path;
console.log(
`${jobPrefix}${colors.green('✅ Done!')} Your output is in ${colors.cyanBright(outputPath)} ${colors.gray(`(${fileCount} ${fileCount === 1 ? 'file' : 'files'} in ${ms(totalMs)})`)}`,
`${jobPrefix}${colors.green('')} ${colors.cyanBright(outputPath)} ${colors.gray(`· ${fileCount} ${fileCount === 1 ? 'file' : 'files'} · ${ms(totalMs)}`)}`,
);
}
}
Expand Down
34 changes: 16 additions & 18 deletions packages/openapi-ts/src/plugins/valibot/v1/toAst/enum.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { fromRef } from '@hey-api/codegen-core';
import { pathToJsonPointer, type SchemaVisitorContext, type SchemaWithType } from '@hey-api/shared';
import type { SchemaVisitorContext, SchemaWithType } from '@hey-api/shared';

import { $ } from '../../../../ts-dsl';
import type { EnumResolverContext } from '../../resolvers';
Expand Down Expand Up @@ -45,22 +44,21 @@ function baseNode(ctx: EnumResolverContext): PipeResult {

const { v } = ctx.plugin.symbols;

const def = ctx.plugin
.querySymbols({
resource: 'definition', // maybe we shouldn't hardcode definition
resourceId: pathToJsonPointer(fromRef(ctx.path)),
tool: 'typescript',
})
// find const or enum, but not const enums, because Valibot doesn't support them
.filter(
(symbol) =>
symbol.kind === 'var' ||
(symbol.kind === 'enum' &&
!(symbol.node as ReturnType<typeof $.enum>).hasModifier('const')),
)[0];
if (def) {
return $(v).attr(identifiers.schemas.enum).call(def);
}
// skip this feature for now, requires knowing whether the enum contains safe values only, which requires special handling that we don't currently support
// const def = ctx.plugin.querySymbol<ReturnType<typeof $.enum | typeof $.var>>(
// {
// resource: 'definition', // maybe we shouldn't hardcode definition
// resourceId: pathToJsonPointer(fromRef(ctx.path)),
// tool: 'typescript',
// },
// ['EnumTsDsl', 'VarTsDsl'],
// // skip const enums, not supported by Valibot
// // skip enums with default values, requires special handling that we don't currently support
// (symbol) => symbol.node?.['~dsl'] !== 'EnumTsDsl' || (!symbol.node.hasModifier('const') && ctx.schema.default === undefined),
// );
// if (def) {
// return $(v).attr(identifiers.schemas.enum).call(def);
// }

if (picklistMembers.length > 0 && picklistMembers.length === literalSchemas.length) {
return $(v)
Expand Down
34 changes: 16 additions & 18 deletions packages/openapi-ts/src/plugins/zod/mini/toAst/enum.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { fromRef } from '@hey-api/codegen-core';
import { pathToJsonPointer, type SchemaVisitorContext, type SchemaWithType } from '@hey-api/shared';
import type { SchemaVisitorContext, SchemaWithType } from '@hey-api/shared';

import { $ } from '../../../../ts-dsl';
import { identifiers } from '../../constants';
Expand Down Expand Up @@ -43,22 +42,21 @@ function baseNode(ctx: EnumResolverContext): Chain {

const { z } = ctx.plugin.symbols;

const def = ctx.plugin
.querySymbols({
resource: 'definition', // maybe we shouldn't hardcode definition
resourceId: pathToJsonPointer(fromRef(ctx.path)),
tool: 'typescript',
})
// find const or enum, but not const enums, because Zod doesn't support them
.filter(
(symbol) =>
symbol.kind === 'var' ||
(symbol.kind === 'enum' &&
!(symbol.node as ReturnType<typeof $.enum>).hasModifier('const')),
)[0];
if (def) {
return $(z).attr(identifiers.enum).call(def);
}
// skip this feature for now, requires knowing whether the enum contains safe values only, which requires special handling that we don't currently support
// const def = ctx.plugin.querySymbol<ReturnType<typeof $.enum | typeof $.var>>(
// {
// resource: 'definition', // maybe we shouldn't hardcode definition
// resourceId: pathToJsonPointer(fromRef(ctx.path)),
// tool: 'typescript',
// },
// ['EnumTsDsl', 'VarTsDsl'],
// // skip const enums, not supported by Zod
// // skip enums with default values, requires special handling that we don't currently support
// (symbol) => symbol.node?.['~dsl'] !== 'EnumTsDsl' || (!symbol.node.hasModifier('const') && ctx.schema.default === undefined),
// );
// if (def) {
// return $(z).attr(identifiers.enum).call(def);
// }

if (enumMembers.length > 0 && enumMembers.length === literalSchemas.length) {
return $(z)
Expand Down
34 changes: 16 additions & 18 deletions packages/openapi-ts/src/plugins/zod/v3/toAst/enum.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { fromRef } from '@hey-api/codegen-core';
import { pathToJsonPointer, type SchemaVisitorContext, type SchemaWithType } from '@hey-api/shared';
import type { SchemaVisitorContext, SchemaWithType } from '@hey-api/shared';

import { $ } from '../../../../ts-dsl';
import { identifiers } from '../../constants';
Expand Down Expand Up @@ -43,22 +42,21 @@ function baseNode(ctx: EnumResolverContext): Chain {

const { z } = ctx.plugin.symbols;

const def = ctx.plugin
.querySymbols({
resource: 'definition', // maybe we shouldn't hardcode definition
resourceId: pathToJsonPointer(fromRef(ctx.path)),
tool: 'typescript',
})
// find const or enum, but not const enums, because Zod doesn't support them
.filter(
(symbol) =>
symbol.kind === 'var' ||
(symbol.kind === 'enum' &&
!(symbol.node as ReturnType<typeof $.enum>).hasModifier('const')),
)[0];
if (def) {
return $(z).attr(identifiers.nativeEnum).call(def);
}
// skip this feature for now, requires knowing whether the enum contains safe values only, which requires special handling that we don't currently support
// const def = ctx.plugin.querySymbol<ReturnType<typeof $.enum | typeof $.var>>(
// {
// resource: 'definition', // maybe we shouldn't hardcode definition
// resourceId: pathToJsonPointer(fromRef(ctx.path)),
// tool: 'typescript',
// },
// ['EnumTsDsl', 'VarTsDsl'],
// // skip const enums, not supported by Zod
// // skip enums with default values, requires special handling that we don't currently support
// (symbol) => symbol.node?.['~dsl'] !== 'EnumTsDsl' || (!symbol.node.hasModifier('const') && ctx.schema.default === undefined),
// );
// if (def) {
// return $(z).attr(identifiers.nativeEnum).call(def);
// }

if (enumMembers.length > 0 && enumMembers.length === literalSchemas.length) {
return $(z)
Expand Down
Loading
Loading