这是indexloc提供的服务,不要输入任何密码
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
14 changes: 1 addition & 13 deletions docs/.vitepress/theme/components/Layout.vue
Original file line number Diff line number Diff line change
Expand Up @@ -8,26 +8,14 @@ const { Layout } = DefaultTheme;
<Layout>
<template #layout-top>
<div class="announcement">
<span> Build better APIs with Hey API Platform </span>
<span>Build better APIs with Hey API Platform</span>
<a
href="https://app.heyapi.dev/"
rel="noopener noreferrer"
target="_blank"
>Dashboard</a
>
</div>
<!-- <div class="announcement">
<span>
Request a feature<span class="hide-sm"> for your business</span>
</span>
<a
aria-label="Send an email to Lubos"
href="mailto:lubos@heyapi.dev?subject=Priority%20Feature%20Request"
target="_blank"
>
Let's Talk
</a>
</div> -->
</template>
<!-- <template #home-features-before>
<a
Expand Down
31 changes: 14 additions & 17 deletions packages/openapi-ts/src/plugins/@hey-api/sdk/shared/class.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,11 +132,12 @@ const createClientClass = ({
.param('args', (p) =>
p
.optional(optionalClient)
.type()
.object((o) =>
o.prop('client', (p) =>
p.optional(optionalClient).type(symbolClient.placeholder),
),
.type(
$.type
.object()
.prop('client', (p) =>
p.optional(optionalClient).type(symbolClient.placeholder),
),
),
)
.do(
Expand Down Expand Up @@ -445,18 +446,14 @@ export const generateClassSdk = ({
const ctor = $.init((i) =>
i
.param('args', (p) =>
p
.optional(!isClientRequired)
.type()
.object((o) =>
o
.prop('client', (p) =>
p
.optional(!isClientRequired)
.type(symbolClient.placeholder),
)
.prop('key', (p) => p.optional().type('string')),
),
p.optional(!isClientRequired).type(
$.type
.object()
.prop('client', (p) =>
p.optional(!isClientRequired).type(symbolClient.placeholder),
)
.prop('key', (p) => p.optional().type('string')),
),
)
.do(
$('super').call('args'),
Expand Down
30 changes: 14 additions & 16 deletions packages/openapi-ts/src/plugins/valibot/shared/export.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import type { Symbol } from '@hey-api/codegen-core';
import type ts from 'typescript';

import type { IR } from '~/ir/types';
import { createSchemaComment } from '~/plugins/shared/utils/schema';
import { tsc } from '~/tsc';
import { $ } from '~/ts-dsl';

import { identifiers } from '../v1/constants';
import { pipesToAst } from './pipesToAst';
Expand All @@ -25,19 +24,18 @@ export const exportAst = ({
resource: 'valibot.v',
});

const statement = tsc.constVariable({
comment: plugin.config.comments
? createSchemaComment({ schema })
: undefined,
exportConst: symbol.exported,
expression: pipesToAst({ pipes: ast.pipes, plugin }),
name: symbol.placeholder,
typeName: state.hasLazyExpression.value
? (tsc.propertyAccessExpression({
expression: v.placeholder,
name: ast.typeName || identifiers.types.GenericSchema.text,
}) as unknown as ts.TypeNode)
: undefined,
});
const statement = $.const(symbol.placeholder)
.export(symbol.exported)
.$if(plugin.config.comments && createSchemaComment({ schema }), (c, v) =>
c.describe(v as Array<string>),
)
.$if(state.hasLazyExpression.value, (c) =>
c.type(
$.type(v.placeholder).attr(
ast.typeName || identifiers.types.GenericSchema.text,
),
),
)
.assign(pipesToAst({ pipes: ast.pipes, plugin }));
plugin.setSymbolValue(symbol, statement);
};
14 changes: 5 additions & 9 deletions packages/openapi-ts/src/plugins/valibot/shared/pipesToAst.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type ts from 'typescript';

import { tsc } from '~/tsc';
import { $ } from '~/ts-dsl';

import type { ValibotPlugin } from '../types';
import { identifiers } from '../v1/constants';
Expand All @@ -20,12 +20,8 @@ export const pipesToAst = ({
category: 'external',
resource: 'valibot.v',
});
const expression = tsc.callExpression({
functionName: tsc.propertyAccessExpression({
expression: v.placeholder,
name: identifiers.methods.pipe,
}),
parameters: pipes,
});
return expression;
return $(v.placeholder)
.attr(identifiers.methods.pipe)
.call(...pipes)
.$render();
};
99 changes: 63 additions & 36 deletions packages/openapi-ts/src/ts-dsl/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,11 @@ export abstract class TsDsl<T extends ts.Node = ts.Node> implements ITsDsl<T> {
if (typeof input === 'string') {
return this.$expr(input) as NodeOfMaybe<I>;
}
if (typeof input === 'boolean') {
return (
input ? ts.factory.createTrue() : ts.factory.createFalse()
) as NodeOfMaybe<I>;
}
if (input instanceof Array) {
return input.map((item) => this._render(item)) as NodeOfMaybe<I>;
}
Expand All @@ -113,29 +118,33 @@ export abstract class TsDsl<T extends ts.Node = ts.Node> implements ITsDsl<T> {
const arr = input instanceof Array ? input : [input];
return arr.map((item) => {
const node =
typeof item === 'string'
? ts.factory.createIdentifier(item)
: this._render(item as any);
typeof item === 'string' ? this.$expr(item) : this._render(item as any);
return ts.isExpression(node)
? ts.factory.createExpressionStatement(node)
: (node as ts.Statement);
});
}

protected $type<I>(type: I): TypeOfMaybe<I> {
if (type === undefined) {
protected $type<I>(
input: I,
args?: ReadonlyArray<ts.TypeNode>,
): TypeOfMaybe<I> {
if (input === undefined) {
return undefined as TypeOfMaybe<I>;
}
if (typeof type === 'string') {
return ts.factory.createTypeReferenceNode(
type,
) as unknown as TypeOfMaybe<I>;
if (typeof input === 'string') {
return ts.factory.createTypeReferenceNode(input, args) as TypeOfMaybe<I>;
}
if (typeof type === 'boolean') {
const literal = type ? ts.factory.createTrue() : ts.factory.createFalse();
if (typeof input === 'boolean') {
const literal = input
? ts.factory.createTrue()
: ts.factory.createFalse();
return ts.factory.createLiteralTypeNode(literal) as TypeOfMaybe<I>;
}
return this._render(type as any) as TypeOfMaybe<I>;
if (input instanceof Array) {
return input.map((item) => this.$type(item, args)) as TypeOfMaybe<I>;
}
return this._render(input as any) as TypeOfMaybe<I>;
}

private _render<T extends ts.Node>(value: MaybeTsDsl<T>): T {
Expand All @@ -152,33 +161,51 @@ type NodeOf<I> =
? ReadonlyArray<U extends TsDsl<infer N> ? N : U>
: I extends string
? ts.Expression
: I extends TsDsl<infer N>
? N
: I extends ts.Node
? I
: never;

type TypeOfMaybe<I> = undefined extends I
? TypeOf<NonNullable<I>> | undefined
: TypeOf<I>;

type TypeOf<I> = I extends string
? ts.TypeNode
: I extends boolean
? ts.LiteralTypeNode
: I extends TsDsl<infer N>
? N
: I extends ts.TypeNode
? I
: never;
: I extends boolean
? ts.Expression
: I extends TsDsl<infer N>
? N
: I extends ts.Node
? I
: never;

export type MaybeTsDsl<T> =
// if T includes string in the union
// if T includes string
string extends T
? Exclude<T, string> extends ts.Node
? string | Exclude<T, string> | TsDsl<Exclude<T, string>>
: string
: // otherwise only node or DSL
T extends ts.Node
? T | TsDsl<T>
: never;
: // if it's a DSL itself
T extends TsDsl<any>
? T
: // otherwise if it’s a Node
T extends ts.Node
? T | TsDsl<T>
: never;

export type TypeOfTsDsl<T> = T extends TsDsl<infer U> ? U : never;

export abstract class TypeTsDsl<
T extends
| ts.TypeNode
| ts.TypeElement
| ts.LiteralTypeNode
| ts.TypeParameterDeclaration = ts.TypeNode,
> extends TsDsl<T> {}

type TypeOfMaybe<I> = undefined extends I
? TypeOf<NonNullable<I>> | undefined
: TypeOf<I>;

type TypeOf<I> =
I extends ReadonlyArray<infer U>
? ReadonlyArray<TypeOf<U>>
: I extends string
? ts.TypeNode
: I extends boolean
? ts.LiteralTypeNode
: I extends TsDsl<infer N>
? N
: I extends ts.TypeNode
? I
: never;
2 changes: 1 addition & 1 deletion packages/openapi-ts/src/ts-dsl/class.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ export class ClassTsDsl extends TsDsl<ts.ClassDeclaration> {
const body = this.$node(this.body) as ReadonlyArray<ts.ClassElement>;
return ts.factory.createClassDeclaration(
[...this.$decorators(), ...this.modifiers.list()],
ts.factory.createIdentifier(this.name),
this.$expr(this.name),
this.$generics(),
this.heritageClauses,
body,
Expand Down
19 changes: 11 additions & 8 deletions packages/openapi-ts/src/ts-dsl/field.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/* eslint-disable @typescript-eslint/no-unsafe-declaration-merging */
import ts from 'typescript';

import { TsDsl } from './base';
import { TsDsl, TypeTsDsl } from './base';
import { mixin } from './mixins/apply';
import { DecoratorMixin } from './mixins/decorator';
import { DescribeMixin } from './mixins/describe';
Expand All @@ -13,30 +13,33 @@ import {
ReadonlyMixin,
StaticMixin,
} from './mixins/modifiers';
import { createTypeAccessor, type TypeAccessor } from './mixins/type';
import { ValueMixin } from './mixins/value';
import { TypeExprTsDsl } from './type/expr';

export class FieldTsDsl extends TsDsl<ts.PropertyDeclaration> {
private modifiers = createModifierAccessor(this);
private name: string;
private _type: TypeAccessor<FieldTsDsl> = createTypeAccessor(this);

/** Sets the property's type. */
type: TypeAccessor<FieldTsDsl>['fn'] = this._type.fn;
private _type?: TypeTsDsl;

constructor(name: string, fn?: (f: FieldTsDsl) => void) {
super();
this.name = name;
fn?.(this);
}

/** Sets the field type. */
type(type: string | TypeTsDsl): this {
this._type = type instanceof TypeTsDsl ? type : new TypeExprTsDsl(type);
return this;
}

/** Builds the `PropertyDeclaration` node. */
$render(): ts.PropertyDeclaration {
return ts.factory.createPropertyDeclaration(
[...this.$decorators(), ...this.modifiers.list()],
ts.factory.createIdentifier(this.name),
this.$expr(this.name),
undefined,
this._type.$render(),
this.$type(this._type),
this.$value(),
);
}
Expand Down
Loading
Loading