这是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: 4 additions & 1 deletion .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,10 @@
"cwd": "${workspaceFolder}/dev",
"runtimeExecutable": "node",
"runtimeArgs": ["-r", "ts-node/register/transpile-only"],
"program": "${workspaceFolder}/packages/openapi-ts/src/run.ts"
"program": "${workspaceFolder}/packages/openapi-ts/src/run.ts",
"env": {
"DEBUG": "false"
}
}
]
}
8 changes: 4 additions & 4 deletions dev/openapi-ts.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,9 @@ export default defineConfig(() => {
// 'dutchie.json',
// 'invalid',
// 'openai.yaml',
'full.yaml',
// 'full.yaml',
// 'opencode.yaml',
// 'sdk-instance.yaml',
'sdk-instance.yaml',
// 'string-with-format.yaml',
// 'transformers.json',
// 'type-format.yaml',
Expand Down Expand Up @@ -214,7 +214,7 @@ export default defineConfig(() => {
{
// baseUrl: false,
// exportFromIndex: true,
name: '@hey-api/client-fetch',
// name: '@hey-api/client-fetch',
// name: 'legacy/angular',
// runtimeConfigPath: path.resolve(__dirname, 'hey-api.ts'),
// runtimeConfigPath: './src/hey-api.ts',
Expand Down Expand Up @@ -259,7 +259,7 @@ export default defineConfig(() => {
// fields.unwrap('path')
// },
// include...
// instance: true,
instance: true,
name: '@hey-api/sdk',
// operationId: false,
// params_EXPERIMENTAL: 'experiment',
Expand Down
39 changes: 39 additions & 0 deletions packages/codegen-core/src/__tests__/symbols.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -230,4 +230,43 @@ describe('SymbolRegistry', () => {
expect(cacheKeys3.length).toBe(3);
expect(registry['queryCache'].get(cacheKeys3[2]!)).toEqual([]);
});

it('returns the same stub reference for identical unresolved meta', () => {
const registry = new SymbolRegistry();

const stubA1 = registry.reference({ a: 1 });
const stubA2 = registry.reference({ a: 1 });

// Same reference, not new instance
expect(stubA1).toBe(stubA2);

// Cache entry created by the internal query call
const cacheKey = registry['buildCacheKey']({ a: 1 });
expect(registry['queryCache'].has(cacheKey)).toBe(true);
expect(registry['queryCache'].get(cacheKey)).toEqual([]);
});

it('demonstrates stub addition does not invalidate unrelated cache', () => {
const registry = new SymbolRegistry();

// Create one indexed symbol and one query to seed cache
const symA = registry.register({ meta: { foo: 'bar' }, name: 'A' });
const resultFoo = registry.query({ foo: 'bar' });
expect(resultFoo).toEqual([symA]);
const cacheKeysBefore = Array.from(registry['queryCache'].keys());
expect(cacheKeysBefore.length).toBe(1);

// Add unrelated stub (its meta triggers its own query)
const stub = registry.reference({ something: 'else' });
expect(stub.meta).toEqual({ something: 'else' });

// Existing cache entry still present, plus one new entry for stub
const cacheKeysAfter = Array.from(registry['queryCache'].keys());
expect(cacheKeysAfter.length).toBe(cacheKeysBefore.length + 1);
expect(cacheKeysAfter).toEqual(expect.arrayContaining(cacheKeysBefore));

// The new stub isn't indexed, so query returns nothing yet
const newQuery = registry.query({ something: 'else' });
expect(newQuery).toEqual([]);
});
});
7 changes: 7 additions & 0 deletions packages/codegen-core/src/symbols/registry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export class SymbolRegistry implements ISymbolRegistry {
private registerOrder: Set<SymbolId> = new Set();
// TODO: remove after removing selectors
private selectorToId: Map<string, SymbolId> = new Map();
private stubCache: Map<QueryCacheKey, SymbolId> = new Map();
private stubs: Set<SymbolId> = new Set();
private values: Map<SymbolId, ISymbolOut> = new Map();

Expand Down Expand Up @@ -118,6 +119,9 @@ export class SymbolRegistry implements ISymbolRegistry {
}
const [registered] = this.query(symbol.meta);
if (registered) return registered;
const cacheKey = this.buildCacheKey(symbol.meta);
const cachedId = this.stubCache.get(cacheKey);
if (cachedId !== undefined) return this.values.get(cachedId)!;
const id = this.id;
const stub: ISymbolOut = {
exportFrom: [],
Expand All @@ -127,6 +131,7 @@ export class SymbolRegistry implements ISymbolRegistry {
};
this.values.set(stub.id, stub);
this.stubs.add(stub.id);
this.stubCache.set(cacheKey, stub.id);
return stub;
}

Expand Down Expand Up @@ -294,6 +299,8 @@ export class SymbolRegistry implements ISymbolRegistry {
stub?.meta &&
this.isSubset(this.buildIndexKeySpace(stub.meta), indexKeySpace)
) {
const cacheKey = this.buildCacheKey(stub.meta);
this.stubCache.delete(cacheKey);
this.values.set(stubId, Object.assign(stub, symbol));
this.stubs.delete(stubId);
}
Expand Down
1 change: 1 addition & 0 deletions packages/openapi-ts/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ declare module '@hey-api/codegen-core' {
| 'arktype'
| 'fastify'
| 'json-schema'
| 'sdk'
| 'typescript'
| 'valibot'
| 'zod'
Expand Down
18 changes: 10 additions & 8 deletions packages/openapi-ts/src/plugins/@angular/common/httpRequests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -289,10 +289,11 @@ const generateAngularRequestMethod = ({
resource: '@angular/common/http.HttpRequest',
});

const sdkPlugin = plugin.getPluginOrThrow('@hey-api/sdk');
const symbolOptions = plugin.referenceSymbol(
sdkPlugin.api.selector('Options'),
);
const symbolOptions = plugin.referenceSymbol({
category: 'type',
resource: 'client-options',
tool: 'sdk',
});

const symbolDataType = plugin.querySymbol({
category: 'type',
Expand Down Expand Up @@ -349,10 +350,11 @@ const generateAngularRequestFunction = ({
resource: '@angular/common/http.HttpRequest',
});

const sdkPlugin = plugin.getPluginOrThrow('@hey-api/sdk');
const symbolOptions = plugin.referenceSymbol(
sdkPlugin.api.selector('Options'),
);
const symbolOptions = plugin.referenceSymbol({
category: 'type',
resource: 'client-options',
tool: 'sdk',
});

const symbolDataType = plugin.querySymbol({
category: 'type',
Expand Down
18 changes: 10 additions & 8 deletions packages/openapi-ts/src/plugins/@angular/common/httpResources.ts
Original file line number Diff line number Diff line change
Expand Up @@ -375,10 +375,11 @@ const generateAngularResourceMethod = ({
operation: IR.OperationObject;
plugin: AngularCommonPlugin['Instance'];
}) => {
const sdkPlugin = plugin.getPluginOrThrow('@hey-api/sdk');
const symbolOptions = plugin.referenceSymbol(
sdkPlugin.api.selector('Options'),
);
const symbolOptions = plugin.referenceSymbol({
category: 'type',
resource: 'client-options',
tool: 'sdk',
});

const symbolDataType = plugin.querySymbol({
category: 'type',
Expand Down Expand Up @@ -430,10 +431,11 @@ const generateAngularResourceFunction = ({
plugin: AngularCommonPlugin['Instance'];
symbol: Symbol;
}) => {
const sdkPlugin = plugin.getPluginOrThrow('@hey-api/sdk');
const symbolOptions = plugin.referenceSymbol(
sdkPlugin.api.selector('Options'),
);
const symbolOptions = plugin.referenceSymbol({
category: 'type',
resource: 'client-options',
tool: 'sdk',
});

const symbolDataType = plugin.querySymbol({
category: 'type',
Expand Down
40 changes: 2 additions & 38 deletions packages/openapi-ts/src/plugins/@hey-api/sdk/api.ts
Original file line number Diff line number Diff line change
@@ -1,39 +1,3 @@
import type { Selector } from '@hey-api/codegen-core';
export type IApi = any;

import type { Plugin } from '~/plugins';

type SelectorType =
| 'buildClientParams'
| 'class'
| 'Client'
| 'Composable'
| 'formDataBodySerializer'
| 'function'
| 'Options'
| 'urlSearchParamsBodySerializer';

export type IApi = {
/**
* @param type Selector type.
* @param value Depends on `type`:
* - `buildClientParams`: never
* - `class`: current class name
* - `Client`: never
* - `Composable`: never
* - `formDataBodySerializer`: never
* - `function`: `operation.id` string
* - `Options`: never
* - `urlSearchParamsBodySerializer`: never
* @returns Selector array
* @deprecated
*/
selector: (type: SelectorType, value?: string) => Selector;
};

export class Api implements IApi {
constructor(public meta: Plugin.Name<'@hey-api/sdk'>) {}

selector(...args: ReadonlyArray<string | undefined>): Selector {
return [this.meta.name, ...(args as Selector)];
}
}
export class Api implements IApi {}
4 changes: 1 addition & 3 deletions packages/openapi-ts/src/plugins/@hey-api/sdk/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,7 @@ import { handlerLegacy } from './plugin-legacy';
import type { HeyApiSdkPlugin } from './types';

export const defaultConfig: HeyApiSdkPlugin['Config'] = {
api: new Api({
name: '@hey-api/sdk',
}),
api: new Api(),
config: {
asClass: false,
auth: true,
Expand Down
66 changes: 43 additions & 23 deletions packages/openapi-ts/src/plugins/@hey-api/sdk/shared/class.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@ type SdkClassEntry = {
*/
className: string;
/**
* Symbol IDs for child classes located inside this class.
* Class names for child classes located inside this class.
*/
classes: Set<number>;
classes: Set<string>;
/**
* Symbol ID for the class.
*/
Expand Down Expand Up @@ -62,7 +62,10 @@ const createClientClassNodes = ({
}),
});

const symbolClient = plugin.referenceSymbol(plugin.api.selector('Client'));
const symbolClient = plugin.referenceSymbol({
category: 'external',
resource: 'client.Client',
});
const symClient = plugin.getSymbol({
category: 'client',
});
Expand Down Expand Up @@ -122,11 +125,11 @@ export const generateClassSdk = ({
const client = getClientPlugin(plugin.context.config);
const isAngularClient = client.name === '@hey-api/client-angular';
const isNuxtClient = client.name === '@hey-api/client-nuxt';
const sdkClasses = new Map<number, SdkClassEntry>();
const sdkClasses = new Map<string, SdkClassEntry>();
/**
* Track unique added classes.
*/
const generatedClasses = new Set<number>();
const generatedClasses = new Set<string>();

const clientClassNodes = plugin.config.instance
? createClientClassNodes({ plugin })
Expand Down Expand Up @@ -156,11 +159,14 @@ export const generateClassSdk = ({

for (const entry of classes.values()) {
entry.path.forEach((currentClassName, index) => {
const symbolCurrentClass = plugin.referenceSymbol(
plugin.api.selector('class', currentClassName),
);
if (!sdkClasses.has(symbolCurrentClass.id)) {
sdkClasses.set(symbolCurrentClass.id, {
const symbolCurrentClass = plugin.referenceSymbol({
category: 'utility',
resource: 'class',
resourceId: currentClassName,
tool: 'sdk',
});
if (!sdkClasses.has(symbolCurrentClass.meta!.resourceId!)) {
sdkClasses.set(symbolCurrentClass.meta!.resourceId!, {
className: currentClassName,
classes: new Set(),
id: symbolCurrentClass.id,
Expand All @@ -172,15 +178,20 @@ export const generateClassSdk = ({

const parentClassName = entry.path[index - 1];
if (parentClassName) {
const symbolParentClass = plugin.referenceSymbol(
plugin.api.selector('class', parentClassName),
);
const symbolParentClass = plugin.referenceSymbol({
category: 'utility',
resource: 'class',
resourceId: parentClassName,
tool: 'sdk',
});
if (
symbolParentClass.placeholder !== symbolCurrentClass.placeholder
) {
const parentClass = sdkClasses.get(symbolParentClass.id)!;
parentClass.classes.add(symbolCurrentClass.id);
sdkClasses.set(symbolParentClass.id, parentClass);
const parentClass = sdkClasses.get(
symbolParentClass.meta!.resourceId!,
)!;
parentClass.classes.add(symbolCurrentClass.meta!.resourceId!);
sdkClasses.set(symbolParentClass.meta!.resourceId!, parentClass);
}
}

Expand All @@ -190,7 +201,9 @@ export const generateClassSdk = ({
return;
}

const currentClass = sdkClasses.get(symbolCurrentClass.id)!;
const currentClass = sdkClasses.get(
symbolCurrentClass.meta!.resourceId!,
)!;

// avoid duplicate methods
if (currentClass.methods.has(entry.methodName)) {
Expand Down Expand Up @@ -221,8 +234,10 @@ export const generateClassSdk = ({
{
default: tsc.ots.string('$fetch'),
extends: tsc.typeNode(
plugin.referenceSymbol(plugin.api.selector('Composable'))
.placeholder,
plugin.referenceSymbol({
category: 'external',
resource: 'client.Composable',
}).placeholder,
),
name: nuxtTypeComposable,
},
Expand Down Expand Up @@ -264,7 +279,7 @@ export const generateClassSdk = ({

currentClass.methods.add(entry.methodName);

sdkClasses.set(symbolCurrentClass.id, currentClass);
sdkClasses.set(symbolCurrentClass.meta!.resourceId!, currentClass);
});
}
},
Expand All @@ -279,7 +294,7 @@ export const generateClassSdk = ({
});

const generateClass = (currentClass: SdkClassEntry) => {
if (generatedClasses.has(currentClass.id)) {
if (generatedClasses.has(currentClass.className)) {
return;
}

Expand Down Expand Up @@ -327,8 +342,13 @@ export const generateClassSdk = ({

const symbol = plugin.registerSymbol({
exported: true,
meta: {
category: 'utility',
resource: 'class',
resourceId: currentClass.className,
tool: 'sdk',
},
name: currentClass.className,
selector: plugin.api.selector('class', currentClass.className),
});
const node = tsc.classDeclaration({
decorator:
Expand All @@ -353,7 +373,7 @@ export const generateClassSdk = ({
nodes: currentClass.nodes,
});
plugin.setSymbolValue(symbol, node);
generatedClasses.add(symbol.id);
generatedClasses.add(symbol.meta!.resourceId!);
};

if (clientClassNodes.length) {
Expand Down
Loading
Loading