nuxt-openapi-hyperfetch 0.2.7-alpha.1 → 0.2.8-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/.editorconfig +26 -26
  2. package/.prettierignore +17 -17
  3. package/CONTRIBUTING.md +291 -291
  4. package/INSTRUCTIONS.md +327 -327
  5. package/LICENSE +202 -202
  6. package/README.md +231 -231
  7. package/dist/cli/config.d.ts +9 -2
  8. package/dist/cli/config.js +1 -1
  9. package/dist/cli/logo.js +5 -5
  10. package/dist/cli/messages.d.ts +1 -0
  11. package/dist/cli/messages.js +2 -0
  12. package/dist/cli/prompts.d.ts +5 -0
  13. package/dist/cli/prompts.js +12 -0
  14. package/dist/cli/types.d.ts +1 -1
  15. package/dist/generators/components/connector-generator/templates.js +12 -12
  16. package/dist/generators/use-async-data/templates.js +17 -17
  17. package/dist/generators/use-fetch/templates.js +14 -14
  18. package/dist/index.js +39 -27
  19. package/dist/module/index.js +19 -0
  20. package/dist/module/types.d.ts +7 -0
  21. package/docs/API-REFERENCE.md +886 -886
  22. package/docs/generated-components.md +615 -615
  23. package/docs/headless-composables-ui.md +569 -569
  24. package/eslint.config.js +85 -85
  25. package/package.json +1 -1
  26. package/src/cli/config.ts +147 -140
  27. package/src/cli/logger.ts +124 -124
  28. package/src/cli/logo.ts +25 -25
  29. package/src/cli/messages.ts +4 -0
  30. package/src/cli/prompts.ts +14 -1
  31. package/src/cli/types.ts +50 -50
  32. package/src/generators/components/connector-generator/generator.ts +138 -138
  33. package/src/generators/components/connector-generator/templates.ts +254 -254
  34. package/src/generators/components/connector-generator/types.ts +34 -34
  35. package/src/generators/components/schema-analyzer/index.ts +44 -44
  36. package/src/generators/components/schema-analyzer/intent-detector.ts +187 -187
  37. package/src/generators/components/schema-analyzer/openapi-reader.ts +96 -96
  38. package/src/generators/components/schema-analyzer/resource-grouper.ts +166 -166
  39. package/src/generators/components/schema-analyzer/schema-field-mapper.ts +268 -268
  40. package/src/generators/components/schema-analyzer/types.ts +177 -177
  41. package/src/generators/nuxt-server/generator.ts +272 -272
  42. package/src/generators/shared/runtime/apiHelpers.ts +535 -535
  43. package/src/generators/shared/runtime/pagination.ts +323 -323
  44. package/src/generators/shared/runtime/useDeleteConnector.ts +109 -109
  45. package/src/generators/shared/runtime/useDetailConnector.ts +64 -64
  46. package/src/generators/shared/runtime/useFormConnector.ts +139 -139
  47. package/src/generators/shared/runtime/useListConnector.ts +148 -148
  48. package/src/generators/shared/runtime/zod-error-merger.ts +119 -119
  49. package/src/generators/shared/templates/api-callbacks-plugin.ts +399 -399
  50. package/src/generators/shared/templates/api-pagination-plugin.ts +158 -158
  51. package/src/generators/use-async-data/generator.ts +205 -205
  52. package/src/generators/use-async-data/runtime/useApiAsyncData.ts +329 -329
  53. package/src/generators/use-async-data/runtime/useApiAsyncDataRaw.ts +324 -324
  54. package/src/generators/use-async-data/templates.ts +257 -257
  55. package/src/generators/use-fetch/generator.ts +170 -170
  56. package/src/generators/use-fetch/runtime/useApiRequest.ts +354 -354
  57. package/src/generators/use-fetch/templates.ts +214 -214
  58. package/src/index.ts +305 -303
  59. package/src/module/index.ts +158 -133
  60. package/src/module/types.ts +39 -31
@@ -1,187 +1,187 @@
1
- import type { EndpointInfo, Intent, OpenApiOperation, OpenApiPropertySchema } from './types.js';
2
-
3
- // HTTP methods we care about
4
- const MUTATING_METHODS = new Set(['POST', 'PUT', 'PATCH']);
5
- const HTTP_METHODS = ['GET', 'POST', 'PUT', 'PATCH', 'DELETE'] as const;
6
- type HttpMethod = (typeof HTTP_METHODS)[number];
7
-
8
- // ─── Path analysis helpers ────────────────────────────────────────────────────
9
-
10
- /** Returns path parameter names found in a path, e.g. '/pets/{id}' → ['id'] */
11
- function extractPathParams(path: string): string[] {
12
- const matches = path.match(/\{([^}]+)\}/g) ?? [];
13
- return matches.map((m) => m.slice(1, -1));
14
- }
15
-
16
- /** True when the path ends with a path parameter: /pets/{id} */
17
- function endsWithPathParam(path: string): boolean {
18
- return /\/\{[^}]+\}$/.test(path);
19
- }
20
-
21
- // ─── Response schema analysis ─────────────────────────────────────────────────
22
-
23
- /**
24
- * Return the resolved schema for the first 2xx response that has
25
- * an application/json body, or undefined.
26
- */
27
- function getSuccessResponseSchema(operation: OpenApiOperation): OpenApiPropertySchema | undefined {
28
- if (!operation.responses) {
29
- return undefined;
30
- }
31
-
32
- for (const [statusCode, response] of Object.entries(operation.responses)) {
33
- const code = parseInt(statusCode, 10);
34
- if (isNaN(code) || code < 200 || code >= 300) {
35
- continue;
36
- }
37
-
38
- const jsonContent = response.content?.['application/json'];
39
- if (jsonContent?.schema) {
40
- return jsonContent.schema;
41
- }
42
- }
43
-
44
- return undefined;
45
- }
46
-
47
- /** True when schema represents an array (type: array, or items present) */
48
- function isArraySchema(schema: OpenApiPropertySchema): boolean {
49
- return schema.type === 'array' || schema.items !== undefined;
50
- }
51
-
52
- // ─── Request body schema ──────────────────────────────────────────────────────
53
-
54
- function getRequestBodySchema(operation: OpenApiOperation): OpenApiPropertySchema | undefined {
55
- if (!operation.requestBody?.content) {
56
- return undefined;
57
- }
58
-
59
- const jsonContent = operation.requestBody.content['application/json'];
60
- if (jsonContent?.schema) {
61
- return jsonContent.schema;
62
- }
63
-
64
- // Fallback to form-urlencoded
65
- const formContent = operation.requestBody.content['application/x-www-form-urlencoded'];
66
- return formContent?.schema;
67
- }
68
-
69
- // ─── Intent detection ─────────────────────────────────────────────────────────
70
-
71
- /**
72
- * Detect the CRUD intent of a single endpoint.
73
- *
74
- * Priority:
75
- * 1. x-nxh-intent extension on the operation (developer override)
76
- * 2. HTTP method + path pattern + response schema
77
- */
78
- export function detectIntent(
79
- method: HttpMethod,
80
- path: string,
81
- operation: OpenApiOperation
82
- ): Intent {
83
- // 1. Developer override via OpenAPI extension
84
- const override = operation['x-nxh-intent'];
85
- if (override) {
86
- return override;
87
- }
88
-
89
- const hasPathParam = extractPathParams(path).length > 0;
90
- const responseSchema = getSuccessResponseSchema(operation);
91
-
92
- switch (method) {
93
- case 'DELETE':
94
- return 'delete';
95
-
96
- case 'POST':
97
- // POST /resource → create
98
- // POST /resource/{id}/action → unknown (custom action, not CRUD)
99
- return !endsWithPathParam(path) ? 'create' : 'unknown';
100
-
101
- case 'PUT':
102
- case 'PATCH':
103
- return 'update';
104
-
105
- case 'GET': {
106
- // A GET without a JSON response (e.g. binary download) is not a CRUD intent
107
- if (!responseSchema) {
108
- return 'unknown';
109
- }
110
-
111
- // Array response ( type: 'array' OR has 'items' ) → always a list
112
- if (isArraySchema(responseSchema)) {
113
- return 'list';
114
- }
115
-
116
- // Object response — distinguish list vs detail by path structure:
117
- // GET /pets/{id} → has path param → detail (single item fetch)
118
- // GET /pets → no path param → list (likely paginated envelope: { data: [], total: n })
119
- if (hasPathParam) {
120
- return 'detail';
121
- }
122
-
123
- return 'list';
124
- }
125
-
126
- default:
127
- return 'unknown';
128
- }
129
- }
130
-
131
- // ─── Endpoint extraction ──────────────────────────────────────────────────────
132
-
133
- /**
134
- * Extract all endpoints from a single path item as EndpointInfo[].
135
- * The spec must already be $ref-resolved before calling this.
136
- */
137
- export function extractEndpoints(
138
- path: string,
139
- pathItem: Record<string, OpenApiOperation>
140
- ): EndpointInfo[] {
141
- const results: EndpointInfo[] = [];
142
- const pathParams = extractPathParams(path);
143
-
144
- for (const method of HTTP_METHODS) {
145
- const operation: OpenApiOperation | undefined = pathItem[method.toLowerCase()];
146
-
147
- if (!operation) {
148
- continue;
149
- }
150
-
151
- const intent = detectIntent(method, path, operation);
152
-
153
- const endpoint: EndpointInfo = {
154
- // Fallback operationId when the spec omits it: 'get_/pets/{id}' → 'get__pets__id_'
155
- // This rarely produces a ideal composable name, but avoids a crash.
156
- operationId: operation.operationId ?? `${method.toLowerCase()}_${path.replace(/\//g, '_')}`,
157
- method,
158
- path,
159
- tags: operation.tags ?? [],
160
- summary: operation.summary,
161
- description: operation.description,
162
- intent,
163
- hasPathParams: pathParams.length > 0,
164
- pathParams,
165
- };
166
-
167
- // Attach response schema for GET intents
168
- if (method === 'GET') {
169
- const schema = getSuccessResponseSchema(operation);
170
- if (schema) {
171
- endpoint.responseSchema = schema as import('./types.js').OpenApiSchema;
172
- }
173
- }
174
-
175
- // Attach request body schema for mutating methods
176
- if (MUTATING_METHODS.has(method)) {
177
- const schema = getRequestBodySchema(operation);
178
- if (schema) {
179
- endpoint.requestBodySchema = schema as import('./types.js').OpenApiSchema;
180
- }
181
- }
182
-
183
- results.push(endpoint);
184
- }
185
-
186
- return results;
187
- }
1
+ import type { EndpointInfo, Intent, OpenApiOperation, OpenApiPropertySchema } from './types.js';
2
+
3
+ // HTTP methods we care about
4
+ const MUTATING_METHODS = new Set(['POST', 'PUT', 'PATCH']);
5
+ const HTTP_METHODS = ['GET', 'POST', 'PUT', 'PATCH', 'DELETE'] as const;
6
+ type HttpMethod = (typeof HTTP_METHODS)[number];
7
+
8
+ // ─── Path analysis helpers ────────────────────────────────────────────────────
9
+
10
+ /** Returns path parameter names found in a path, e.g. '/pets/{id}' → ['id'] */
11
+ function extractPathParams(path: string): string[] {
12
+ const matches = path.match(/\{([^}]+)\}/g) ?? [];
13
+ return matches.map((m) => m.slice(1, -1));
14
+ }
15
+
16
+ /** True when the path ends with a path parameter: /pets/{id} */
17
+ function endsWithPathParam(path: string): boolean {
18
+ return /\/\{[^}]+\}$/.test(path);
19
+ }
20
+
21
+ // ─── Response schema analysis ─────────────────────────────────────────────────
22
+
23
+ /**
24
+ * Return the resolved schema for the first 2xx response that has
25
+ * an application/json body, or undefined.
26
+ */
27
+ function getSuccessResponseSchema(operation: OpenApiOperation): OpenApiPropertySchema | undefined {
28
+ if (!operation.responses) {
29
+ return undefined;
30
+ }
31
+
32
+ for (const [statusCode, response] of Object.entries(operation.responses)) {
33
+ const code = parseInt(statusCode, 10);
34
+ if (isNaN(code) || code < 200 || code >= 300) {
35
+ continue;
36
+ }
37
+
38
+ const jsonContent = response.content?.['application/json'];
39
+ if (jsonContent?.schema) {
40
+ return jsonContent.schema;
41
+ }
42
+ }
43
+
44
+ return undefined;
45
+ }
46
+
47
+ /** True when schema represents an array (type: array, or items present) */
48
+ function isArraySchema(schema: OpenApiPropertySchema): boolean {
49
+ return schema.type === 'array' || schema.items !== undefined;
50
+ }
51
+
52
+ // ─── Request body schema ──────────────────────────────────────────────────────
53
+
54
+ function getRequestBodySchema(operation: OpenApiOperation): OpenApiPropertySchema | undefined {
55
+ if (!operation.requestBody?.content) {
56
+ return undefined;
57
+ }
58
+
59
+ const jsonContent = operation.requestBody.content['application/json'];
60
+ if (jsonContent?.schema) {
61
+ return jsonContent.schema;
62
+ }
63
+
64
+ // Fallback to form-urlencoded
65
+ const formContent = operation.requestBody.content['application/x-www-form-urlencoded'];
66
+ return formContent?.schema;
67
+ }
68
+
69
+ // ─── Intent detection ─────────────────────────────────────────────────────────
70
+
71
+ /**
72
+ * Detect the CRUD intent of a single endpoint.
73
+ *
74
+ * Priority:
75
+ * 1. x-nxh-intent extension on the operation (developer override)
76
+ * 2. HTTP method + path pattern + response schema
77
+ */
78
+ export function detectIntent(
79
+ method: HttpMethod,
80
+ path: string,
81
+ operation: OpenApiOperation
82
+ ): Intent {
83
+ // 1. Developer override via OpenAPI extension
84
+ const override = operation['x-nxh-intent'];
85
+ if (override) {
86
+ return override;
87
+ }
88
+
89
+ const hasPathParam = extractPathParams(path).length > 0;
90
+ const responseSchema = getSuccessResponseSchema(operation);
91
+
92
+ switch (method) {
93
+ case 'DELETE':
94
+ return 'delete';
95
+
96
+ case 'POST':
97
+ // POST /resource → create
98
+ // POST /resource/{id}/action → unknown (custom action, not CRUD)
99
+ return !endsWithPathParam(path) ? 'create' : 'unknown';
100
+
101
+ case 'PUT':
102
+ case 'PATCH':
103
+ return 'update';
104
+
105
+ case 'GET': {
106
+ // A GET without a JSON response (e.g. binary download) is not a CRUD intent
107
+ if (!responseSchema) {
108
+ return 'unknown';
109
+ }
110
+
111
+ // Array response ( type: 'array' OR has 'items' ) → always a list
112
+ if (isArraySchema(responseSchema)) {
113
+ return 'list';
114
+ }
115
+
116
+ // Object response — distinguish list vs detail by path structure:
117
+ // GET /pets/{id} → has path param → detail (single item fetch)
118
+ // GET /pets → no path param → list (likely paginated envelope: { data: [], total: n })
119
+ if (hasPathParam) {
120
+ return 'detail';
121
+ }
122
+
123
+ return 'list';
124
+ }
125
+
126
+ default:
127
+ return 'unknown';
128
+ }
129
+ }
130
+
131
+ // ─── Endpoint extraction ──────────────────────────────────────────────────────
132
+
133
+ /**
134
+ * Extract all endpoints from a single path item as EndpointInfo[].
135
+ * The spec must already be $ref-resolved before calling this.
136
+ */
137
+ export function extractEndpoints(
138
+ path: string,
139
+ pathItem: Record<string, OpenApiOperation>
140
+ ): EndpointInfo[] {
141
+ const results: EndpointInfo[] = [];
142
+ const pathParams = extractPathParams(path);
143
+
144
+ for (const method of HTTP_METHODS) {
145
+ const operation: OpenApiOperation | undefined = pathItem[method.toLowerCase()];
146
+
147
+ if (!operation) {
148
+ continue;
149
+ }
150
+
151
+ const intent = detectIntent(method, path, operation);
152
+
153
+ const endpoint: EndpointInfo = {
154
+ // Fallback operationId when the spec omits it: 'get_/pets/{id}' → 'get__pets__id_'
155
+ // This rarely produces a ideal composable name, but avoids a crash.
156
+ operationId: operation.operationId ?? `${method.toLowerCase()}_${path.replace(/\//g, '_')}`,
157
+ method,
158
+ path,
159
+ tags: operation.tags ?? [],
160
+ summary: operation.summary,
161
+ description: operation.description,
162
+ intent,
163
+ hasPathParams: pathParams.length > 0,
164
+ pathParams,
165
+ };
166
+
167
+ // Attach response schema for GET intents
168
+ if (method === 'GET') {
169
+ const schema = getSuccessResponseSchema(operation);
170
+ if (schema) {
171
+ endpoint.responseSchema = schema as import('./types.js').OpenApiSchema;
172
+ }
173
+ }
174
+
175
+ // Attach request body schema for mutating methods
176
+ if (MUTATING_METHODS.has(method)) {
177
+ const schema = getRequestBodySchema(operation);
178
+ if (schema) {
179
+ endpoint.requestBodySchema = schema as import('./types.js').OpenApiSchema;
180
+ }
181
+ }
182
+
183
+ results.push(endpoint);
184
+ }
185
+
186
+ return results;
187
+ }
@@ -1,96 +1,96 @@
1
- import { readFileSync } from 'node:fs';
2
- import * as path from 'node:path';
3
- import { load as loadYaml } from 'js-yaml';
4
- import type { OpenApiSpec, OpenApiPropertySchema } from './types.js';
5
-
6
- /**
7
- * Read an OpenAPI spec from a YAML or JSON file.
8
- * Returns the parsed spec with all $ref values resolved inline.
9
- */
10
- export function readOpenApiSpec(filePath: string): OpenApiSpec {
11
- const absPath = path.resolve(filePath);
12
- const content = readFileSync(absPath, 'utf-8');
13
-
14
- const raw = filePath.endsWith('.json')
15
- ? (JSON.parse(content) as OpenApiSpec)
16
- : (loadYaml(content) as OpenApiSpec);
17
-
18
- if (!raw || typeof raw !== 'object' || !raw.openapi || !raw.paths) {
19
- throw new Error(`Invalid OpenAPI spec: ${absPath}`);
20
- }
21
-
22
- return resolveRefs(raw, raw) as OpenApiSpec;
23
- }
24
-
25
- // ─── $ref resolver ────────────────────────────────────────────────────────────
26
-
27
- /**
28
- * Recursively walk the document and replace every { $ref: '#/...' } with the
29
- * referenced value (deep-cloned to avoid circular references).
30
- * Only local JSON Pointer refs (#/...) are supported.
31
- */
32
- function resolveRefs(node: unknown, root: OpenApiSpec, visited = new Set<string>()): unknown {
33
- if (node === null || typeof node !== 'object') {
34
- return node;
35
- }
36
-
37
- if (Array.isArray(node)) {
38
- return node.map((item) => resolveRefs(item, root, visited));
39
- }
40
-
41
- const obj = node as Record<string, unknown>;
42
-
43
- if (typeof obj['$ref'] === 'string') {
44
- const ref = obj['$ref'];
45
-
46
- if (visited.has(ref)) {
47
- // Circular ref protection — return empty object rather than infinite loop
48
- return {};
49
- }
50
-
51
- const resolved = resolvePointer(root, ref);
52
- const newVisited = new Set(visited);
53
- newVisited.add(ref);
54
- return resolveRefs(resolved, root, newVisited);
55
- }
56
-
57
- const result: Record<string, unknown> = {};
58
- for (const [key, value] of Object.entries(obj)) {
59
- result[key] = resolveRefs(value, root, visited);
60
- }
61
- return result;
62
- }
63
-
64
- /**
65
- * Resolve a JSON Pointer like '#/components/schemas/Pet' against the root doc.
66
- */
67
- function resolvePointer(root: unknown, ref: string): unknown {
68
- if (!ref.startsWith('#/')) {
69
- throw new Error(`Only local $ref values are supported (got: ${ref})`);
70
- }
71
-
72
- const parts = ref
73
- .slice(2)
74
- .split('/')
75
- .map((p) => p.replace(/~1/g, '/').replace(/~0/g, '~'));
76
-
77
- let current: Record<string, unknown> = root as Record<string, unknown>;
78
- for (const part of parts) {
79
- if (current === null || typeof current !== 'object' || !(part in current)) {
80
- throw new Error(`Cannot resolve $ref: ${ref}`);
81
- }
82
- current = current[part] as Record<string, unknown>;
83
- }
84
- return current;
85
- }
86
-
87
- /**
88
- * Resolve a single inline schema that may still have $ref (convenience helper
89
- * used by other modules that receive already-partially-resolved specs).
90
- */
91
- export function resolveSchema(
92
- schema: OpenApiPropertySchema,
93
- root: OpenApiSpec
94
- ): OpenApiPropertySchema {
95
- return resolveRefs(schema, root) as OpenApiPropertySchema;
96
- }
1
+ import { readFileSync } from 'node:fs';
2
+ import * as path from 'node:path';
3
+ import { load as loadYaml } from 'js-yaml';
4
+ import type { OpenApiSpec, OpenApiPropertySchema } from './types.js';
5
+
6
+ /**
7
+ * Read an OpenAPI spec from a YAML or JSON file.
8
+ * Returns the parsed spec with all $ref values resolved inline.
9
+ */
10
+ export function readOpenApiSpec(filePath: string): OpenApiSpec {
11
+ const absPath = path.resolve(filePath);
12
+ const content = readFileSync(absPath, 'utf-8');
13
+
14
+ const raw = filePath.endsWith('.json')
15
+ ? (JSON.parse(content) as OpenApiSpec)
16
+ : (loadYaml(content) as OpenApiSpec);
17
+
18
+ if (!raw || typeof raw !== 'object' || !raw.openapi || !raw.paths) {
19
+ throw new Error(`Invalid OpenAPI spec: ${absPath}`);
20
+ }
21
+
22
+ return resolveRefs(raw, raw) as OpenApiSpec;
23
+ }
24
+
25
+ // ─── $ref resolver ────────────────────────────────────────────────────────────
26
+
27
+ /**
28
+ * Recursively walk the document and replace every { $ref: '#/...' } with the
29
+ * referenced value (deep-cloned to avoid circular references).
30
+ * Only local JSON Pointer refs (#/...) are supported.
31
+ */
32
+ function resolveRefs(node: unknown, root: OpenApiSpec, visited = new Set<string>()): unknown {
33
+ if (node === null || typeof node !== 'object') {
34
+ return node;
35
+ }
36
+
37
+ if (Array.isArray(node)) {
38
+ return node.map((item) => resolveRefs(item, root, visited));
39
+ }
40
+
41
+ const obj = node as Record<string, unknown>;
42
+
43
+ if (typeof obj['$ref'] === 'string') {
44
+ const ref = obj['$ref'];
45
+
46
+ if (visited.has(ref)) {
47
+ // Circular ref protection — return empty object rather than infinite loop
48
+ return {};
49
+ }
50
+
51
+ const resolved = resolvePointer(root, ref);
52
+ const newVisited = new Set(visited);
53
+ newVisited.add(ref);
54
+ return resolveRefs(resolved, root, newVisited);
55
+ }
56
+
57
+ const result: Record<string, unknown> = {};
58
+ for (const [key, value] of Object.entries(obj)) {
59
+ result[key] = resolveRefs(value, root, visited);
60
+ }
61
+ return result;
62
+ }
63
+
64
+ /**
65
+ * Resolve a JSON Pointer like '#/components/schemas/Pet' against the root doc.
66
+ */
67
+ function resolvePointer(root: unknown, ref: string): unknown {
68
+ if (!ref.startsWith('#/')) {
69
+ throw new Error(`Only local $ref values are supported (got: ${ref})`);
70
+ }
71
+
72
+ const parts = ref
73
+ .slice(2)
74
+ .split('/')
75
+ .map((p) => p.replace(/~1/g, '/').replace(/~0/g, '~'));
76
+
77
+ let current: Record<string, unknown> = root as Record<string, unknown>;
78
+ for (const part of parts) {
79
+ if (current === null || typeof current !== 'object' || !(part in current)) {
80
+ throw new Error(`Cannot resolve $ref: ${ref}`);
81
+ }
82
+ current = current[part] as Record<string, unknown>;
83
+ }
84
+ return current;
85
+ }
86
+
87
+ /**
88
+ * Resolve a single inline schema that may still have $ref (convenience helper
89
+ * used by other modules that receive already-partially-resolved specs).
90
+ */
91
+ export function resolveSchema(
92
+ schema: OpenApiPropertySchema,
93
+ root: OpenApiSpec
94
+ ): OpenApiPropertySchema {
95
+ return resolveRefs(schema, root) as OpenApiPropertySchema;
96
+ }