Skip to content

Commit d1ea0ba

Browse files
committed
chore: clean up renderer
1 parent 0b34586 commit d1ea0ba

File tree

189 files changed

+2297
-1810
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

189 files changed

+2297
-1810
lines changed

.vscode/launch.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
"runtimeArgs": ["-r", "ts-node/register/transpile-only"],
1919
"program": "${workspaceFolder}/packages/openapi-ts/src/run.ts",
2020
"env": {
21-
"DEBUG": "heyapi:*"
21+
"DEBUG": "false"
2222
}
2323
}
2424
]

dev/openapi-ts.config.ts

Lines changed: 15 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ export default defineConfig(() => {
4343
// 'invalid',
4444
// 'full.yaml',
4545
// 'object-property-names.yaml',
46-
// 'openai.yaml',
46+
'openai.yaml',
4747
// 'opencode.yaml',
4848
// 'pagination-ref.yaml',
4949
// 'sdk-instance.yaml',
@@ -53,7 +53,7 @@ export default defineConfig(() => {
5353
// 'validators.yaml',
5454
// 'validators-circular-ref.json',
5555
// 'validators-circular-ref-2.yaml',
56-
'zoom-video-sdk.json',
56+
// 'zoom-video-sdk.json',
5757
),
5858
// path: 'https://get.heyapi.dev/hey-api/backend?branch=main&version=1.0.0',
5959
// path: 'http://localhost:4000/',
@@ -237,6 +237,7 @@ export default defineConfig(() => {
237237
// error: '他們_error_{{name}}',
238238
// name: '你們_errors_{{name}}',
239239
// },
240+
// exportFromIndex: false,
240241
name: '@hey-api/typescript',
241242
// requests: '我們_data_{{name}}',
242243
// responses: {
@@ -263,7 +264,7 @@ export default defineConfig(() => {
263264
// },
264265
// include...
265266
// instance: true,
266-
// name: '@hey-api/sdk',
267+
name: '@hey-api/sdk',
267268
// operationId: false,
268269
// paramsStructure: 'flat',
269270
// responseStyle: 'data',
@@ -272,7 +273,7 @@ export default defineConfig(() => {
272273
// signature: 'object',
273274
// transformer: '@hey-api/transformers',
274275
// transformer: true,
275-
validator: 'valibot',
276+
validator: 'zod',
276277
// validator: {
277278
// request: 'zod',
278279
// response: 'zod',
@@ -371,18 +372,18 @@ export default defineConfig(() => {
371372
{
372373
// case: 'SCREAMING_SNAKE_CASE',
373374
// comments: false,
374-
// definitions: 'z{{name}}Definition',
375+
definitions: 'z{{name}}',
375376
exportFromIndex: true,
376377
// metadata: true,
377-
// name: 'valibot',
378+
name: 'valibot',
378379
// requests: {
379380
// case: 'PascalCase',
380381
// name: '{{name}}Data',
381382
// },
382-
// responses: {
383-
// // case: 'snake_case',
384-
// name: 'z{{name}}TestResponse',
385-
// },
383+
responses: {
384+
// case: 'snake_case',
385+
name: 'z{{name}}TestResponse',
386+
},
386387
// webhooks: {
387388
// name: 'q{{name}}CoolWebhook',
388389
// },
@@ -425,10 +426,7 @@ export default defineConfig(() => {
425426
validator({ $, schema, v }) {
426427
return [
427428
$.const('parsed').assign(
428-
$(v.placeholder)
429-
.attr('safeParseAsync')
430-
.call(schema.placeholder, 'data')
431-
.await(),
429+
$(v).attr('safeParseAsync').call(schema, 'data').await(),
432430
),
433431
$('parsed').return(),
434432
];
@@ -449,9 +447,9 @@ export default defineConfig(() => {
449447
// infer: 'D{{name}}ZodType',
450448
// },
451449
},
452-
// exportFromIndex: true,
450+
exportFromIndex: true,
453451
metadata: true,
454-
// name: 'zod',
452+
name: 'zod',
455453
// requests: {
456454
// // case: 'SCREAMING_SNAKE_CASE',
457455
// // name: 'z{{name}}TestData',
@@ -505,10 +503,7 @@ export default defineConfig(() => {
505503
validator({ $, schema }) {
506504
return [
507505
$.const('parsed').assign(
508-
$(schema.placeholder)
509-
.attr('safeParseAsync')
510-
.call('data')
511-
.await(),
506+
$(schema).attr('safeParseAsync').call('data').await(),
512507
),
513508
$('parsed').return(),
514509
];

packages/codegen-core/src/__tests__/symbols.test.ts

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { describe, expect, it } from 'vitest';
22

33
import { SymbolRegistry } from '../symbols/registry';
4+
import { isSymbol } from '../symbols/symbol';
45

56
describe('SymbolRegistry', () => {
67
it('covers the full public interface', () => {
@@ -260,4 +261,88 @@ describe('SymbolRegistry', () => {
260261
const newQuery = registry.query({ something: 'else' });
261262
expect(newQuery).toEqual([]);
262263
});
264+
265+
it('isSymbol covers various inputs', () => {
266+
const registry = new SymbolRegistry();
267+
268+
// real registered symbol
269+
const sym = registry.register({ meta: { a: 1 }, name: 'A' });
270+
expect(isSymbol(sym)).toBe(true);
271+
272+
// stub reference (unregistered)
273+
const stub = registry.reference({ b: 2 });
274+
expect(isSymbol(stub)).toBe(true);
275+
276+
// primitives
277+
expect(isSymbol(null)).toBe(false);
278+
expect(isSymbol(undefined)).toBe(false);
279+
expect(isSymbol(123)).toBe(false);
280+
expect(isSymbol('foo')).toBe(false);
281+
expect(isSymbol(true)).toBe(false);
282+
283+
// arrays and plain objects
284+
expect(isSymbol([])).toBe(false);
285+
expect(isSymbol({})).toBe(false);
286+
287+
// object with different tag
288+
expect(isSymbol({ '~tag': 'not-a-symbol' })).toBe(false);
289+
290+
// object masquerading as a symbol (matches tag)
291+
expect(isSymbol({ '~tag': 'heyapi.symbol' })).toBe(true);
292+
293+
// Date, Map, Set should be false
294+
expect(isSymbol(new Date())).toBe(false);
295+
expect(isSymbol(new Map())).toBe(false);
296+
expect(isSymbol(new Set())).toBe(false);
297+
298+
// Typed arrays and ArrayBuffer should be false
299+
expect(isSymbol(new Uint8Array())).toBe(false);
300+
expect(isSymbol(new ArrayBuffer(8))).toBe(false);
301+
302+
// Functions without tag should be false
303+
const fn = () => {};
304+
expect(isSymbol(fn)).toBe(false);
305+
306+
// Class instance without tag should be false
307+
class Foo {}
308+
const foo = new Foo();
309+
expect(isSymbol(foo)).toBe(false);
310+
311+
// Proxy with tag should be true if own property is present
312+
const target = {} as Record<string, unknown>;
313+
const proxied = new Proxy(target, {
314+
get(_, prop) {
315+
if (prop === '~tag') return 'heyapi.symbol';
316+
return undefined;
317+
},
318+
getOwnPropertyDescriptor(_, prop) {
319+
if (prop === '~tag')
320+
return {
321+
configurable: true,
322+
enumerable: true,
323+
value: 'heyapi.symbol',
324+
writable: false,
325+
};
326+
return undefined;
327+
},
328+
has(_, prop) {
329+
return prop === '~tag';
330+
},
331+
});
332+
// Define as own property to satisfy hasOwn
333+
Object.defineProperty(target, '~tag', {
334+
configurable: true,
335+
value: 'heyapi.symbol',
336+
});
337+
expect(isSymbol(proxied)).toBe(true);
338+
339+
// Inherited tag should be false (not own property)
340+
const proto = { '~tag': 'heyapi.symbol' };
341+
const objWithProto = Object.create(proto);
342+
expect(isSymbol(objWithProto)).toBe(false);
343+
344+
// Primitive edge cases
345+
expect(isSymbol(Symbol('x'))).toBe(false);
346+
expect(isSymbol(0n)).toBe(false);
347+
});
263348
});
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
import type { SymbolImportKind } from '../symbols/types';
2+
3+
export interface PlannedImport {
4+
/** ID of the file where the symbol lives */
5+
from: number;
6+
/** The final exported name of the symbol in its source file */
7+
importedName: string;
8+
/** Whether this import is type-only. */
9+
isTypeOnly: boolean;
10+
/** Import flavor. */
11+
kind: SymbolImportKind;
12+
/**
13+
* The name this symbol will have locally in this file.
14+
* This is where aliasing is applied:
15+
*
16+
* import { Foo as Foo$2 } from "./x"
17+
*
18+
* localName === "Foo$2"
19+
*/
20+
localName: string;
21+
/** ID of the symbol being imported */
22+
symbolId: number;
23+
}
24+
25+
export interface PlannedExport {
26+
/**
27+
* Whether the export was explicitly requested by the plugin/DSL
28+
* (e.g. symbol.exported = true) vs implicitly required (e.g. re-export).
29+
*/
30+
explicit: boolean;
31+
/**
32+
* The name this symbol will be exported under from this file.
33+
*
34+
* This may differ from the symbol's finalName if aliasing is needed:
35+
*
36+
* export { Foo as Foo2 }
37+
*
38+
* exportedName === "Foo2"
39+
*/
40+
exportedName: string;
41+
/** Whether this export is type-only. */
42+
isTypeOnly: boolean;
43+
/** Export flavor. */
44+
kind: SymbolImportKind;
45+
/** ID of the symbol being exported */
46+
symbolId: number;
47+
}
48+
49+
export interface PlannedReexport {
50+
/**
51+
* Name under which the symbol is exported in this file.
52+
*
53+
* export { Foo as Bar } from "./models"
54+
*
55+
* exportedName === "Bar"
56+
*/
57+
exportedName: string;
58+
/** ID of the source file containing the symbol */
59+
from: number;
60+
/**
61+
* The name the symbol has in the source file’s exports.
62+
*
63+
* export { Foo as Bar } from "./models"
64+
*
65+
* importedName === "Foo"
66+
*
67+
* This handles aliasing in the source file's export list.
68+
*/
69+
importedName: string;
70+
/** Whether this re-export is type-only. */
71+
isTypeOnly: boolean;
72+
/** Export flavor. */
73+
kind: SymbolImportKind;
74+
/** ID of the symbol being re-exported */
75+
symbolId: number;
76+
}

packages/codegen-core/src/debug.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import colorSupport from 'color-support';
55
colors.enabled = colorSupport().hasBasic;
66

77
const DEBUG_GROUPS = {
8+
analyzer: colors.greenBright,
89
dsl: colors.cyanBright,
910
registry: colors.blueBright,
1011
symbol: colors.magentaBright,

packages/codegen-core/src/files/registry.ts

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -99,14 +99,13 @@ export class FileRegistry implements IFileRegistry {
9999
result = {
100100
...result,
101101
...file, // clone to avoid mutation
102+
exports: result?.exports ?? [],
102103
id,
103-
localNames: new Set(),
104+
imports: result?.imports ?? [],
105+
reexports: result?.reexports ?? [],
106+
reservedNames: result?.reservedNames ?? new Map(),
104107
resolvedNames: result?.resolvedNames ?? new BiMap(),
105-
symbols: result?.symbols ?? {
106-
body: [],
107-
exports: [],
108-
imports: [],
109-
},
108+
symbols: result?.symbols ?? [],
110109
};
111110
this.values.set(id, result);
112111

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
export interface Rules {
2+
/** Whether two exported names may collide. */
3+
allowExportNameShadowing: boolean;
4+
/** Whether a local symbol can shadow another local name without error. */
5+
allowLocalNameShadowing: boolean;
6+
/** Whether the language requires file-scoped name uniqueness. */
7+
fileScopedNamesMustBeUnique: boolean;
8+
/** Whether `import { X } from "mod"` introduces a local binding `X`. */
9+
importCreatesLocalBinding: boolean;
10+
/** Whether `export { X } from "mod"` introduces a local binding `X`. */
11+
reexportCreatesLocalBinding: boolean;
12+
/** Whether the language distinguishes type-only imports. */
13+
supportsTypeImports: boolean;
14+
}

0 commit comments

Comments
 (0)