这是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/cyan-regions-invite.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@hey-api/openapi-ts': patch
---

fix(validators): do not reference variables before they are declared
5 changes: 5 additions & 0 deletions .changeset/fast-views-attack.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@hey-api/openapi-ts': patch
---

fix(renderer): allow duplicate names when one symbol is a type
5 changes: 5 additions & 0 deletions .changeset/wet-glasses-sleep.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@hey-api/codegen-core': patch
---

feat: add `isRegistered()` method to file and symbol registry
3 changes: 2 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@
"source.fixAll.eslint": "explicit"
},
"editor.quickSuggestions": {
"strings": true
"strings": "on"
},
"eslint.format.enable": true,
"eslint.nodePath": "./node_modules",
"eslint.workingDirectories": [{ "pattern": "./packages/*/" }],
"typescript.preferences.autoImportFileExcludePatterns": ["dist/**"],
"typescript.preferences.autoImportSpecifierExcludeRegexes": ["^(node:)?os$"],
"typescript.tsdk": "node_modules/typescript/lib"
}
15 changes: 15 additions & 0 deletions packages/codegen-core/src/__tests__/files.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ describe('FileRegistry', () => {
expect(registry.get(file1.id)).toEqual(file1);
expect(registry.get(['foo'])).toEqual(file1);

// isRegistered should be true for explicitly registered files
expect(registry.isRegistered(file1.id)).toBe(true);
expect(registry.isRegistered(['foo'])).toBe(true);

// Registering again with same selector returns same file
const file1b = registry.register({ selector: ['foo'] });
expect(file1b).toEqual(file1);
Expand Down Expand Up @@ -76,6 +80,17 @@ describe('FileRegistry', () => {
expect(referenced).toContainEqual(file3);
// Once registered, file1 is not in referenced set
expect(referenced).not.toContainEqual(file1);

// Referenced-only file should not be considered registered
expect(registry.isRegistered(file3.id)).toBe(false);
// Once registered, file3 becomes registered and no longer appears in referenced()
const file3Registered = registry.register({
name: 'Baz',
selector: ['baz'],
});
expect(registry.isRegistered(file3Registered.id)).toBe(true);
const referencedAfter = Array.from(registry.referenced());
expect(referencedAfter).not.toContainEqual(file3Registered);
});

it('throws on invalid register or reference', () => {
Expand Down
13 changes: 13 additions & 0 deletions packages/codegen-core/src/__tests__/symbols.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ describe('SymbolRegistry', () => {
expect(registry.get(symbol1.id)).toEqual(symbol1);
expect(registry.get(['foo'])).toEqual(symbol1);

// isRegistered should be true for explicitly registered symbols
expect(registry.isRegistered(symbol1.id)).toBe(true);
expect(registry.isRegistered(['foo'])).toBe(true);

// Registering again with same selector returns same symbol
const symbol1b = registry.register({ selector: ['foo'] });
expect(symbol1b).toEqual(symbol1);
Expand Down Expand Up @@ -75,6 +79,15 @@ describe('SymbolRegistry', () => {
registry.setValue(symbol1.id, 42);
expect(registry.hasValue(symbol1.id)).toBe(true);
expect(registry.getValue(symbol1.id)).toBe(42);

// referenced-only symbol should not be registered until register() with data
const symRef = registry.reference(['qux']);
expect(registry.isRegistered(symRef.id)).toBe(false);
const symRegistered = registry.register({
placeholder: 'Qux',
selector: ['qux'],
});
expect(registry.isRegistered(symRegistered.id)).toBe(true);
});

it('throws on invalid register or reference', () => {
Expand Down
8 changes: 8 additions & 0 deletions packages/codegen-core/src/files/registry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,11 @@ export class FileRegistry implements IFileRegistry {
: { selector: symbolIdOrSelector };
}

isRegistered(fileIdOrSelector: number | ISelector): boolean {
const file = this.get(fileIdOrSelector);
return file ? this.registerOrder.has(file.id) : false;
}

reference(fileIdOrSelector: number | ISelector): IFileOut {
const file = this.idOrSelector(fileIdOrSelector);
return this.register(file);
Expand Down Expand Up @@ -104,6 +109,9 @@ export class FileRegistry implements IFileRegistry {

if (hasOtherKeys) {
this.registerOrder.add(id);
if (this.referenceOrder.has(id)) {
this.referenceOrder.delete(id);
}
} else {
this.referenceOrder.add(id);
}
Expand Down
7 changes: 7 additions & 0 deletions packages/codegen-core/src/files/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,13 @@ export interface IFileRegistry {
* @returns File ID before being incremented
*/
readonly id: number;
/**
* Returns whether a file is registered in the registry.
*
* @param fileIdOrSelector File ID or selector to check.
* @returns True if the file is registered, false otherwise.
*/
isRegistered(fileIdOrSelector: number | ISelector): boolean;
/**
* Returns a file by ID or selector, registering it if it doesn't exist.
*
Expand Down
5 changes: 5 additions & 0 deletions packages/codegen-core/src/symbols/registry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,11 @@ export class SymbolRegistry implements ISymbolRegistry {
: { selector: symbolIdOrSelector };
}

isRegistered(symbolIdOrSelector: number | ISelector): boolean {
const symbol = this.get(symbolIdOrSelector);
return symbol ? this.registerOrder.has(symbol.id) : false;
}

reference(symbolIdOrSelector: number | ISelector): ISymbolOut {
const symbol = this.idOrSelector(symbolIdOrSelector);
return this.register(symbol);
Expand Down
7 changes: 7 additions & 0 deletions packages/codegen-core/src/symbols/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,13 @@ export interface ISymbolRegistry {
* @returns Symbol ID before being incremented.
*/
readonly id: number;
/**
* Returns whether a symbol is registered in the registry.
*
* @param symbolIdOrSelector Symbol ID or selector to check.
* @returns True if the symbol is registered, false otherwise.
*/
isRegistered(symbolIdOrSelector: number | ISelector): boolean;
/**
* Returns a symbol by ID or selector, registering it if it doesn't exist.
*
Expand Down
3 changes: 2 additions & 1 deletion packages/config-vite-base/src/vitest.base.config.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { platform } from 'os';
import { platform } from 'node:os';

import type { ViteUserConfig } from 'vitest/config';
import { configDefaults, defineConfig, mergeConfig } from 'vitest/config';

Expand Down
4 changes: 2 additions & 2 deletions packages/custom-client/src/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,13 @@ export type IApi = {
* - `client`: never
* @returns Selector array
*/
getSelector: (type: SelectorType, value?: string) => Selector;
selector: (type: SelectorType, value?: string) => Selector;
};

export class Api implements IApi {
constructor(public meta: Pick<Config, 'name'>) {}

getSelector(...args: ReadonlyArray<string | undefined>): Selector {
selector(...args: ReadonlyArray<string | undefined>): Selector {
return [this.meta.name, ...(args as Selector)];
}
}
Expand Down
1 change: 1 addition & 0 deletions packages/openapi-ts-tests/main/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
"@tanstack/svelte-query": "5.73.3",
"@tanstack/vue-query": "5.73.3",
"@types/cross-spawn": "6.0.6",
"arktype": "2.1.23",
"axios": "1.8.2",
"cross-spawn": "7.0.6",
"eslint": "9.17.0",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,6 @@

import * as v from 'valibot';

export const vExternalSharedExternalSharedModel = v.object({
id: v.string(),
name: v.optional(v.string())
});

export const vExternalRefA = vExternalSharedExternalSharedModel;

export const vExternalRefB = vExternalSharedExternalSharedModel;

/**
* Testing multiline comments in string: First line
* Second line
Expand Down Expand Up @@ -74,15 +65,6 @@ export const vNonAsciiStringæøåÆøÅöôêÊ字符串 = v.string();
*/
export const vSimpleFile = v.string();

/**
* This is a model with one string property
*/
export const vModelWithString = v.object({
prop: v.optional(v.string())
});

export const vSimpleReference = vModelWithString;

/**
* This is a simple string
*/
Expand Down Expand Up @@ -130,16 +112,6 @@ export const vArrayWithBooleans = v.array(v.boolean());
*/
export const vArrayWithStrings = v.array(v.string());

/**
* This is a simple array with references
*/
export const vArrayWithReferences = v.array(vModelWithString);

/**
* This is a simple array containing an array
*/
export const vArrayWithArray = v.array(v.array(vModelWithString));

/**
* This is a simple array with properties
*/
Expand All @@ -153,16 +125,6 @@ export const vArrayWithProperties = v.array(v.object({
*/
export const vDictionaryWithString = v.object({});

/**
* This is a string reference
*/
export const vDictionaryWithReference = v.object({});

/**
* This is a complex dictionary
*/
export const vDictionaryWithArray = v.object({});

/**
* This is a string dictionary
*/
Expand Down Expand Up @@ -195,6 +157,35 @@ export const vModelWithBoolean = v.object({
prop: v.optional(v.boolean())
});

/**
* This is a model with one string property
*/
export const vModelWithString = v.object({
prop: v.optional(v.string())
});

export const vSimpleReference = vModelWithString;

/**
* This is a simple array with references
*/
export const vArrayWithReferences = v.array(vModelWithString);

/**
* This is a simple array containing an array
*/
export const vArrayWithArray = v.array(v.array(vModelWithString));

/**
* This is a string reference
*/
export const vDictionaryWithReference = v.object({});

/**
* This is a complex dictionary
*/
export const vDictionaryWithArray = v.object({});

/**
* This is a model with one string property
*/
Expand Down Expand Up @@ -258,30 +249,6 @@ export const vModelWithNestedEnums = v.object({
arrayWithDescription: v.optional(v.array(v.pipe(v.number(), v.integer())))
});

/**
* This is a model with one nested property
*/
export const vModelWithProperties = v.object({
required: v.string(),
requiredAndReadOnly: v.pipe(v.string(), v.readonly()),
string: v.optional(v.string()),
number: v.optional(v.number()),
boolean: v.optional(v.boolean()),
reference: v.optional(vModelWithString),
'property with space': v.optional(v.string()),
default: v.optional(v.string()),
try: v.optional(v.string()),
'@namespace.string': v.optional(v.pipe(v.string(), v.readonly())),
'@namespace.integer': v.optional(v.pipe(v.pipe(v.number(), v.integer()), v.readonly()))
});

/**
* This is a model with one property containing a reference
*/
export const vModelWithReference = v.object({
prop: v.optional(vModelWithProperties)
});

/**
* This is a model with one property containing an array
*/
Expand All @@ -307,6 +274,30 @@ export const vModelWithCircularReference: v.GenericSchema = v.object({
}))
});

/**
* This is a model with one nested property
*/
export const vModelWithProperties = v.object({
required: v.string(),
requiredAndReadOnly: v.pipe(v.string(), v.readonly()),
string: v.optional(v.string()),
number: v.optional(v.number()),
boolean: v.optional(v.boolean()),
reference: v.optional(vModelWithString),
'property with space': v.optional(v.string()),
default: v.optional(v.string()),
try: v.optional(v.string()),
'@namespace.string': v.optional(v.pipe(v.string(), v.readonly())),
'@namespace.integer': v.optional(v.pipe(v.pipe(v.number(), v.integer()), v.readonly()))
});

/**
* This is a model with one property containing a reference
*/
export const vModelWithReference = v.object({
prop: v.optional(vModelWithProperties)
});

/**
* This is a model with one nested property
*/
Expand Down Expand Up @@ -407,6 +398,15 @@ export const vFailureFailure = v.object({
reference_code: v.optional(v.string())
});

export const vExternalSharedExternalSharedModel = v.object({
id: v.string(),
name: v.optional(v.string())
});

export const vExternalRefA = vExternalSharedExternalSharedModel;

export const vExternalRefB = vExternalSharedExternalSharedModel;

/**
* This is a model with one nested property
*/
Expand Down
Loading
Loading