Skip to content

Commit d9da43b

Browse files
committed
chore: oas spec fixes, to satisfy spectral rules (without modifying the actual oas state from Xano)
1 parent 1f32c90 commit d9da43b

File tree

3 files changed

+76
-0
lines changed

3 files changed

+76
-0
lines changed

.changeset/tangy-windows-taste.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
---
2+
'@calycode/core': patch
3+
'@calycode/cli': patch
4+
---
5+
6+
chore: extract the tags from the paths to the global to comply better with OAS
7+
chore: set maxLength to strings on the error codes (owasp:api4:2019-string-limit)
8+
chore: set type to strings (owasp:api4:2019-string-restricted)
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
function extractTagsToGlobal(paths) {
2+
// 1. Collect all tags used in operations
3+
const tagSet = new Set();
4+
for (const [path, methods] of Object.entries(paths || {})) {
5+
for (const [method, operation] of Object.entries(methods)) {
6+
if (operation.tags && Array.isArray(operation.tags)) {
7+
operation.tags.forEach((tag) => tagSet.add(tag));
8+
}
9+
}
10+
}
11+
12+
// 2. Build the global tags array if not present
13+
let tags = Array.from(tagSet).map((tag) => ({
14+
name: tag,
15+
description: `Auto-generated tag for ${tag}`,
16+
}));
17+
18+
// (Optional) If you want to preserve existing tags and only add missing ones:
19+
const existingTags = (tags || []).map((t) => t.name);
20+
const allTags = Array.from(new Set([...existingTags, ...tagSet]));
21+
tags = allTags.map((tag) => ({
22+
name: tag,
23+
description: `Auto-generated tag for ${tag}`,
24+
}));
25+
26+
return tags;
27+
}
28+
29+
export { extractTagsToGlobal };

packages/core/src/features/oas/generate/methods/patch-oas-spec.ts

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { cleanupResponseSchemas } from './cleanup-response-schemas';
2+
import { extractTagsToGlobal } from './extract-tags-to-global-level';
23
import { generateTableSchemas } from '..';
34

45
async function patchOasSpec({
@@ -15,6 +16,8 @@ async function patchOasSpec({
1516

1617
newOas.openapi = '3.1.1';
1718

19+
newOas.tags = extractTagsToGlobal(newOas.paths);
20+
1821
newOas.components = {
1922
...(oas.components ?? {}),
2023

@@ -89,16 +92,22 @@ async function patchOasSpec({
8992
properties: {
9093
code: {
9194
type: 'string',
95+
format: 'const',
96+
maxLength: 64,
9297
example: 'ERROR_CODE_ACCESS_DENIED',
9398
},
9499
message: {
95100
type: 'string',
101+
format: 'const',
102+
maxLength: 256,
96103
example: 'Forbidden access.',
97104
},
98105
payload: {
99106
anyOf: [
100107
{
101108
type: 'string',
109+
format: 'const',
110+
maxLength: 1024,
102111
},
103112
{ type: 'null' },
104113
{ type: 'object', properties: {}, additionalProperties: true },
@@ -112,16 +121,22 @@ async function patchOasSpec({
112121
properties: {
113122
code: {
114123
type: 'string',
124+
format: 'const',
125+
maxLength: 64,
115126
example: 'ERROR_CODE_UNAUTHORIZED',
116127
},
117128
message: {
118129
type: 'string',
130+
format: 'const',
131+
maxLength: 256,
119132
example: 'Authentication required.',
120133
},
121134
payload: {
122135
anyOf: [
123136
{
124137
type: 'string',
138+
format: 'const',
139+
maxLength: 1024,
125140
},
126141
{ type: 'null' },
127142
{ type: 'object', properties: {}, additionalProperties: true },
@@ -135,16 +150,22 @@ async function patchOasSpec({
135150
properties: {
136151
code: {
137152
type: 'string',
153+
format: 'const',
154+
maxLength: 64,
138155
example: 'ERROR_FATAL',
139156
},
140157
message: {
141158
type: 'string',
159+
format: 'const',
160+
maxLength: 256,
142161
example: 'Something went wrong.',
143162
},
144163
payload: {
145164
anyOf: [
146165
{
147166
type: 'string',
167+
format: 'const',
168+
maxLength: 1024,
148169
},
149170
{ type: 'null' },
150171
{ type: 'object', properties: {}, additionalProperties: true },
@@ -158,16 +179,22 @@ async function patchOasSpec({
158179
properties: {
159180
code: {
160181
type: 'string',
182+
format: 'const',
183+
maxLength: 64,
161184
example: 'ERROR_CODE_TOO_MANY_REQUESTS',
162185
},
163186
message: {
164187
type: 'string',
188+
format: 'const',
189+
maxLength: 256,
165190
example: 'Hit quota limits.',
166191
},
167192
payload: {
168193
anyOf: [
169194
{
170195
type: 'string',
196+
format: 'const',
197+
maxLength: 1024,
171198
},
172199
{ type: 'null' },
173200
{ type: 'object', properties: {}, additionalProperties: true },
@@ -181,16 +208,22 @@ async function patchOasSpec({
181208
properties: {
182209
code: {
183210
type: 'string',
211+
format: 'const',
212+
maxLength: 64,
184213
example: 'ERROR_CODE_NOT_FOUND',
185214
},
186215
message: {
187216
type: 'string',
217+
format: 'const',
218+
maxLength: 256,
188219
example: 'The requested resource cannot be found.',
189220
},
190221
payload: {
191222
anyOf: [
192223
{
193224
type: 'string',
225+
format: 'const',
226+
maxLength: 1024,
194227
},
195228
{ type: 'null' },
196229
{ type: 'object', properties: {}, additionalProperties: true },
@@ -204,16 +237,22 @@ async function patchOasSpec({
204237
properties: {
205238
code: {
206239
type: 'string',
240+
format: 'const',
241+
maxLength: 64,
207242
example: 'ERROR_CODE_BAD_REQUEST',
208243
},
209244
message: {
210245
type: 'string',
246+
format: 'const',
247+
maxLength: 256,
211248
example: 'The provided inputs are not correct.',
212249
},
213250
payload: {
214251
anyOf: [
215252
{
216253
type: 'string',
254+
format: 'const',
255+
maxLength: 1024,
217256
},
218257
{ type: 'null' },
219258
{ type: 'object', properties: {}, additionalProperties: true },

0 commit comments

Comments
 (0)