这是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
5 changes: 5 additions & 0 deletions .changeset/twelve-mice-cheer.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@hey-api/openapi-ts': patch
---

feat(parser): input supports Scalar API Registry with `scalar:` prefix
11 changes: 11 additions & 0 deletions docs/openapi-ts/configuration/input.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,17 @@ export default {

We also provide shorthands for other registries:

::: details Scalar
Prefix your input with `scalar:` to use the Scalar API Registry.

```js [long]
export default {
input: 'scalar:@scalar/access-service', // [!code ++]
};
```

:::

::: details ReadMe
Prefix your input with `readme:` to use the ReadMe API Registry.

Expand Down
Original file line number Diff line number Diff line change
@@ -1,21 +1,29 @@
import type { AxiosError, RawAxiosRequestHeaders } from 'axios';
// This file is auto-generated by @hey-api/openapi-ts

import type { AxiosError, AxiosInstance, RawAxiosRequestHeaders } from 'axios';
import axios from 'axios';

import type { Client, Config } from './types';
import type { Client, Config } from './types.gen';
import {
buildUrl,
createConfig,
mergeConfigs,
mergeHeaders,
setAuthParams,
} from './utils';
} from './utils.gen';

export const createClient = (config: Config = {}): Client => {
let _config = mergeConfigs(createConfig(), config);

// eslint-disable-next-line @typescript-eslint/no-unused-vars
const { auth, ...configWithoutAuth } = _config;
const instance = axios.create(configWithoutAuth);
let instance: AxiosInstance;

if (_config.axios && !('Axios' in _config.axios)) {
instance = _config.axios;
} else {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const { auth, ...configWithoutAuth } = _config;
instance = axios.create(configWithoutAuth);
}

const getConfig = (): Config => ({ ..._config });

Expand Down Expand Up @@ -46,6 +54,10 @@ export const createClient = (config: Config = {}): Client => {
});
}

if (opts.requestValidator) {
await opts.requestValidator(opts);
}

if (opts.body && opts.bodySerializer) {
opts.body = opts.bodySerializer(opts.body);
}
Expand Down
16 changes: 9 additions & 7 deletions examples/openapi-ts-axios/src/client/client/index.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
export type { Auth } from '../core/auth';
export type { QuerySerializerOptions } from '../core/bodySerializer';
// This file is auto-generated by @hey-api/openapi-ts

export type { Auth } from '../core/auth.gen';
export type { QuerySerializerOptions } from '../core/bodySerializer.gen';
export {
formDataBodySerializer,
jsonBodySerializer,
urlSearchParamsBodySerializer,
} from '../core/bodySerializer';
export { buildClientParams } from '../core/params';
export { createClient } from './client';
} from '../core/bodySerializer.gen';
export { buildClientParams } from '../core/params.gen';
export { createClient } from './client.gen';
export type {
Client,
ClientOptions,
Expand All @@ -17,5 +19,5 @@ export type {
RequestOptions,
RequestResult,
TDataShape,
} from './types';
export { createConfig } from './utils';
} from './types.gen';
export { createConfig } from './utils.gen';
Original file line number Diff line number Diff line change
@@ -1,24 +1,30 @@
// This file is auto-generated by @hey-api/openapi-ts

import type {
AxiosError,
AxiosInstance,
AxiosRequestHeaders,
AxiosResponse,
AxiosStatic,
CreateAxiosDefaults,
} from 'axios';

import type { Auth } from '../core/auth';
import type { Client as CoreClient, Config as CoreConfig } from '../core/types';
import type { Auth } from '../core/auth.gen';
import type {
Client as CoreClient,
Config as CoreConfig,
} from '../core/types.gen';

export interface Config<T extends ClientOptions = ClientOptions>
extends Omit<CreateAxiosDefaults, 'auth' | 'baseURL' | 'headers' | 'method'>,
CoreConfig {
/**
* Axios implementation. You can use this option to provide a custom
* Axios instance.
* Axios implementation. You can use this option to provide either an
* `AxiosStatic` or an `AxiosInstance`.
*
* @default axios
*/
axios?: AxiosStatic;
axios?: AxiosStatic | AxiosInstance;
/**
* Base URL for all requests made by this client.
*/
Expand All @@ -30,7 +36,7 @@ export interface Config<T extends ClientOptions = ClientOptions>
* {@link https://developer.mozilla.org/docs/Web/API/Headers/Headers#init See more}
*/
headers?:
| CreateAxiosDefaults['headers']
| AxiosRequestHeaders
| Record<
string,
| string
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,22 @@
import { getAuthToken } from '../core/auth';
// This file is auto-generated by @hey-api/openapi-ts

import { getAuthToken } from '../core/auth.gen';
import type {
QuerySerializer,
QuerySerializerOptions,
} from '../core/bodySerializer';
import type { ArraySeparatorStyle } from '../core/pathSerializer';
} from '../core/bodySerializer.gen';
import type { ArraySeparatorStyle } from '../core/pathSerializer.gen';
import {
serializeArrayParam,
serializeObjectParam,
serializePrimitiveParam,
} from '../core/pathSerializer';
import type { Client, ClientOptions, Config, RequestOptions } from './types';
} from '../core/pathSerializer.gen';
import type {
Client,
ClientOptions,
Config,
RequestOptions,
} from './types.gen';

interface PathSerializer {
path: Record<string, unknown>;
Expand Down Expand Up @@ -138,6 +145,28 @@ export const createQuerySerializer = <T = unknown>({
return querySerializer;
};

const checkForExistence = (
options: Pick<RequestOptions, 'auth' | 'query'> & {
headers: Record<any, unknown>;
},
name?: string,
): boolean => {
if (!name) {
return false;
}
if (name in options.headers || options.query?.[name]) {
return true;
}
if (
'Cookie' in options.headers &&
options.headers['Cookie'] &&
typeof options.headers['Cookie'] === 'string'
) {
return options.headers['Cookie'].includes(`${name}=`);
}
return false;
};

export const setAuthParams = async ({
security,
...options
Expand All @@ -146,6 +175,9 @@ export const setAuthParams = async ({
headers: Record<any, unknown>;
}) => {
for (const auth of security) {
if (checkForExistence(options, auth.name)) {
continue;
}
const token = await getAuthToken(auth, options.auth);

if (!token) {
Expand Down Expand Up @@ -175,8 +207,6 @@ export const setAuthParams = async ({
options.headers[name] = token;
break;
}

return;
}
};

Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
// This file is auto-generated by @hey-api/openapi-ts

export type AuthToken = string | undefined;

export interface Auth {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
// This file is auto-generated by @hey-api/openapi-ts

import type {
ArrayStyle,
ObjectStyle,
SerializerOptions,
} from './pathSerializer';
} from './pathSerializer.gen';

export type QuerySerializer = (query: Record<string, unknown>) => string;

Expand All @@ -14,9 +16,15 @@ export interface QuerySerializerOptions {
object?: SerializerOptions<ObjectStyle>;
}

const serializeFormDataPair = (data: FormData, key: string, value: unknown) => {
const serializeFormDataPair = (
data: FormData,
key: string,
value: unknown,
): void => {
if (typeof value === 'string' || value instanceof Blob) {
data.append(key, value);
} else if (value instanceof Date) {
data.append(key, value.toISOString());
} else {
data.append(key, JSON.stringify(value));
}
Expand All @@ -26,7 +34,7 @@ const serializeUrlSearchParamsPair = (
data: URLSearchParams,
key: string,
value: unknown,
) => {
): void => {
if (typeof value === 'string') {
data.append(key, value);
} else {
Expand All @@ -37,7 +45,7 @@ const serializeUrlSearchParamsPair = (
export const formDataBodySerializer = {
bodySerializer: <T extends Record<string, any> | Array<Record<string, any>>>(
body: T,
) => {
): FormData => {
const data = new FormData();

Object.entries(body).forEach(([key, value]) => {
Expand All @@ -56,16 +64,16 @@ export const formDataBodySerializer = {
};

export const jsonBodySerializer = {
bodySerializer: <T>(body: T) =>
JSON.stringify(body, (key, value) =>
bodySerializer: <T>(body: T): string =>
JSON.stringify(body, (_key, value) =>
typeof value === 'bigint' ? value.toString() : value,
),
};

export const urlSearchParamsBodySerializer = {
bodySerializer: <T extends Record<string, any> | Array<Record<string, any>>>(
body: T,
) => {
): string => {
const data = new URLSearchParams();

Object.entries(body).forEach(([key, value]) => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,25 @@
// This file is auto-generated by @hey-api/openapi-ts

type Slot = 'body' | 'headers' | 'path' | 'query';

export type Field =
| {
in: Exclude<Slot, 'body'>;
/**
* Field name. This is the name we want the user to see and use.
*/
key: string;
/**
* Field mapped name. This is the name we want to use in the request.
* If omitted, we use the same value as `key`.
*/
map?: string;
}
| {
in: Extract<Slot, 'body'>;
/**
* Key isn't required for bodies.
*/
key?: string;
map?: string;
};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
// This file is auto-generated by @hey-api/openapi-ts

interface SerializeOptions<T>
extends SerializePrimitiveOptions,
SerializerOptions<T> {}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import type { Auth, AuthToken } from './auth';
// This file is auto-generated by @hey-api/openapi-ts

import type { Auth, AuthToken } from './auth.gen';
import type {
BodySerializer,
QuerySerializer,
QuerySerializerOptions,
} from './bodySerializer';
} from './bodySerializer.gen';

export interface Client<
RequestFn = never,
Expand Down Expand Up @@ -84,6 +86,12 @@ export interface Config {
* {@link https://swagger.io/docs/specification/serialization/#query View examples}
*/
querySerializer?: QuerySerializer | QuerySerializerOptions;
/**
* A function validating request data. This is useful if you want to ensure
* the request conforms to the desired shape, so it can be safely sent to
* the server.
*/
requestValidator?: (data: unknown) => Promise<unknown>;
/**
* A function transforming response data before it's returned. This is useful
* for post-processing data, e.g. converting ISO strings into Date objects.
Expand All @@ -96,3 +104,17 @@ export interface Config {
*/
responseValidator?: (data: unknown) => Promise<unknown>;
}

type IsExactlyNeverOrNeverUndefined<T> = [T] extends [never]
? true
: [T] extends [never | undefined]
? [undefined] extends [T]
? false
: true
: false;

export type OmitNever<T extends Record<string, unknown>> = {
[K in keyof T as IsExactlyNeverOrNeverUndefined<T[K]> extends true
? never
: K]: T[K];
};
Loading
Loading