@redocly/openapi-core 1.0.2 → 1.1.0
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.
- package/CHANGELOG.md +12 -0
- package/lib/bundle.d.ts +1 -1
- package/lib/format/codeframes.d.ts +1 -1
- package/lib/rules/common/no-path-trailing-slash.js +2 -2
- package/lib/rules/common/tags-alphabetical.js +5 -2
- package/lib/rules/oas2/remove-unused-components.js +4 -1
- package/lib/rules/oas3/remove-unused-components.js +4 -1
- package/lib/rules/utils.d.ts +1 -1
- package/lib/types/portal-config-schema.d.ts +2533 -0
- package/lib/types/portal-config-schema.js +304 -0
- package/lib/types/redocly-yaml.js +23 -20
- package/lib/types/{config-external-schemas.d.ts → theme-config.d.ts} +140 -575
- package/lib/types/{config-external-schemas.js → theme-config.js} +55 -261
- package/package.json +2 -2
- package/src/__tests__/lint.test.ts +2 -0
- package/src/rules/common/__tests__/no-path-trailing-slash.test.ts +41 -0
- package/src/rules/common/__tests__/tags-alphabetical.test.ts +58 -0
- package/src/rules/common/no-path-trailing-slash.ts +2 -2
- package/src/rules/common/tags-alphabetical.ts +8 -4
- package/src/rules/oas2/__tests__/remove-unused-components.test.ts +155 -0
- package/src/rules/oas2/remove-unused-components.ts +6 -1
- package/src/rules/oas3/__tests__/remove-unused-components.test.ts +171 -0
- package/src/rules/oas3/remove-unused-components.ts +6 -1
- package/src/types/portal-config-schema.ts +343 -0
- package/src/types/redocly-yaml.ts +20 -34
- package/src/types/{config-external-schemas.ts → theme-config.ts} +60 -294
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -1,242 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
4
|
-
const config_1 = require("../config");
|
|
5
|
-
const oidcIssuerMetadataSchema = {
|
|
6
|
-
type: 'object',
|
|
7
|
-
properties: {
|
|
8
|
-
end_session_endpoint: { type: 'string' },
|
|
9
|
-
token_endpoint: { type: 'string' },
|
|
10
|
-
authorization_endpoint: { type: 'string' },
|
|
11
|
-
},
|
|
12
|
-
required: ['token_endpoint', 'authorization_endpoint'],
|
|
13
|
-
additionalProperties: true,
|
|
14
|
-
};
|
|
15
|
-
const oidcProviderConfigSchema = {
|
|
16
|
-
type: 'object',
|
|
17
|
-
properties: {
|
|
18
|
-
type: { type: 'string', const: config_1.AuthProviderType.OIDC },
|
|
19
|
-
title: { type: 'string' },
|
|
20
|
-
configurationUrl: { type: 'string', minLength: 1 },
|
|
21
|
-
configuration: oidcIssuerMetadataSchema,
|
|
22
|
-
clientId: { type: 'string', minLength: 1 },
|
|
23
|
-
clientSecret: { type: 'string', minLength: 1 },
|
|
24
|
-
teamsClaimName: { type: 'string' },
|
|
25
|
-
defaultTeams: { type: 'array', items: { type: 'string' } },
|
|
26
|
-
scopes: { type: 'array', items: { type: 'string' } },
|
|
27
|
-
tokenExpirationTime: { type: 'number' },
|
|
28
|
-
authorizationRequestCustomParams: { type: 'object', additionalProperties: { type: 'string' } },
|
|
29
|
-
tokenRequestCustomParams: { type: 'object', additionalProperties: { type: 'string' } },
|
|
30
|
-
},
|
|
31
|
-
required: ['type', 'clientId', 'clientSecret'],
|
|
32
|
-
oneOf: [{ required: ['configurationUrl'] }, { required: ['configuration'] }],
|
|
33
|
-
additionalProperties: false,
|
|
34
|
-
};
|
|
35
|
-
const saml2ProviderConfigSchema = {
|
|
36
|
-
type: 'object',
|
|
37
|
-
properties: {
|
|
38
|
-
type: { type: 'string', const: config_1.AuthProviderType.SAML2 },
|
|
39
|
-
title: { type: 'string' },
|
|
40
|
-
issuerId: { type: 'string' },
|
|
41
|
-
entityId: { type: 'string' },
|
|
42
|
-
ssoUrl: { type: 'string' },
|
|
43
|
-
x509PublicCert: { type: 'string' },
|
|
44
|
-
teamsAttributeName: { type: 'string', default: config_1.DEFAULT_TEAM_CLAIM_NAME },
|
|
45
|
-
teamsAttributeMap: { type: 'object', additionalProperties: { type: 'string' } },
|
|
46
|
-
defaultTeams: { type: 'array', items: { type: 'string' } },
|
|
47
|
-
},
|
|
48
|
-
additionalProperties: false,
|
|
49
|
-
required: ['type', 'issuerId', 'ssoUrl', 'x509PublicCert'],
|
|
50
|
-
};
|
|
51
|
-
const basicAuthProviderConfigSchema = {
|
|
52
|
-
type: 'object',
|
|
53
|
-
properties: {
|
|
54
|
-
type: { type: 'string', const: config_1.AuthProviderType.BASIC },
|
|
55
|
-
title: { type: 'string' },
|
|
56
|
-
credentials: {
|
|
57
|
-
type: 'array',
|
|
58
|
-
items: {
|
|
59
|
-
type: 'object',
|
|
60
|
-
properties: {
|
|
61
|
-
username: { type: 'string' },
|
|
62
|
-
password: { type: 'string' },
|
|
63
|
-
passwordHash: { type: 'string' },
|
|
64
|
-
teams: { type: 'array', items: { type: 'string' } },
|
|
65
|
-
},
|
|
66
|
-
required: ['username'],
|
|
67
|
-
additionalProperties: false,
|
|
68
|
-
},
|
|
69
|
-
},
|
|
70
|
-
},
|
|
71
|
-
required: ['type', 'credentials'],
|
|
72
|
-
additionalProperties: false,
|
|
73
|
-
};
|
|
74
|
-
const authProviderConfigSchema = {
|
|
75
|
-
oneOf: [oidcProviderConfigSchema, saml2ProviderConfigSchema, basicAuthProviderConfigSchema],
|
|
76
|
-
discriminator: { propertyName: 'type' },
|
|
77
|
-
};
|
|
78
|
-
const rbacScopeItemsSchema = { type: 'object', additionalProperties: { type: 'string' } };
|
|
79
|
-
exports.rbacConfigSchema = {
|
|
80
|
-
type: 'object',
|
|
81
|
-
properties: {
|
|
82
|
-
defaults: rbacScopeItemsSchema,
|
|
83
|
-
},
|
|
84
|
-
additionalProperties: rbacScopeItemsSchema,
|
|
85
|
-
};
|
|
86
|
-
exports.ssoConfigSchema = {
|
|
87
|
-
type: 'object',
|
|
88
|
-
additionalProperties: authProviderConfigSchema,
|
|
89
|
-
};
|
|
90
|
-
exports.redirectConfigSchema = {
|
|
91
|
-
type: 'object',
|
|
92
|
-
properties: {
|
|
93
|
-
to: { type: 'string' },
|
|
94
|
-
type: { type: 'number', default: 301 },
|
|
95
|
-
},
|
|
96
|
-
required: ['to'],
|
|
97
|
-
additionalProperties: false,
|
|
98
|
-
};
|
|
99
|
-
exports.seoConfigSchema = {
|
|
100
|
-
type: 'object',
|
|
101
|
-
properties: {
|
|
102
|
-
title: { type: 'string' },
|
|
103
|
-
description: { type: 'string' },
|
|
104
|
-
siteUrl: { type: 'string' },
|
|
105
|
-
image: { type: 'string' },
|
|
106
|
-
keywords: { type: 'array', items: { type: 'string' } },
|
|
107
|
-
lang: { type: 'string' },
|
|
108
|
-
jsonLd: { type: 'object' },
|
|
109
|
-
meta: {
|
|
110
|
-
type: 'array',
|
|
111
|
-
items: {
|
|
112
|
-
type: 'object',
|
|
113
|
-
properties: {
|
|
114
|
-
name: { type: 'string' },
|
|
115
|
-
content: { type: 'string' },
|
|
116
|
-
},
|
|
117
|
-
required: ['name', 'content'],
|
|
118
|
-
additionalProperties: false,
|
|
119
|
-
},
|
|
120
|
-
},
|
|
121
|
-
},
|
|
122
|
-
additionalProperties: false,
|
|
123
|
-
};
|
|
124
|
-
const apigeeAdapterAuthOauth2Schema = {
|
|
125
|
-
type: 'object',
|
|
126
|
-
properties: {
|
|
127
|
-
type: { type: 'string', const: config_1.ApigeeDevOnboardingIntegrationAuthType.OAUTH2 },
|
|
128
|
-
tokenEndpoint: { type: 'string' },
|
|
129
|
-
clientId: { type: 'string' },
|
|
130
|
-
clientSecret: { type: 'string' },
|
|
131
|
-
},
|
|
132
|
-
additionalProperties: false,
|
|
133
|
-
required: ['type', 'tokenEndpoint', 'clientId', 'clientSecret'],
|
|
134
|
-
};
|
|
135
|
-
const apigeeAdapterAuthServiceAccountSchema = {
|
|
136
|
-
type: 'object',
|
|
137
|
-
properties: {
|
|
138
|
-
type: { type: 'string', const: config_1.ApigeeDevOnboardingIntegrationAuthType.SERVICE_ACCOUNT },
|
|
139
|
-
serviceAccountEmail: { type: 'string' },
|
|
140
|
-
serviceAccountPrivateKey: { type: 'string' },
|
|
141
|
-
},
|
|
142
|
-
additionalProperties: false,
|
|
143
|
-
required: ['type', 'serviceAccountEmail', 'serviceAccountPrivateKey'],
|
|
144
|
-
};
|
|
145
|
-
const apigeeXAdapterConfigSchema = {
|
|
146
|
-
type: 'object',
|
|
147
|
-
properties: {
|
|
148
|
-
type: { type: 'string', const: 'APIGEE_X' },
|
|
149
|
-
apiUrl: { type: 'string' },
|
|
150
|
-
stage: { type: 'string', default: 'non-production' },
|
|
151
|
-
organizationName: { type: 'string' },
|
|
152
|
-
ignoreApiProducts: { type: 'array', items: { type: 'string' } },
|
|
153
|
-
allowApiProductsOutsideCatalog: { type: 'boolean', default: false },
|
|
154
|
-
auth: {
|
|
155
|
-
type: 'object',
|
|
156
|
-
oneOf: [apigeeAdapterAuthOauth2Schema, apigeeAdapterAuthServiceAccountSchema],
|
|
157
|
-
discriminator: { propertyName: 'type' },
|
|
158
|
-
},
|
|
159
|
-
},
|
|
160
|
-
additionalProperties: false,
|
|
161
|
-
required: ['type', 'organizationName', 'auth'],
|
|
162
|
-
};
|
|
163
|
-
const apigeeEdgeAdapterConfigSchema = Object.assign(Object.assign({}, apigeeXAdapterConfigSchema), { properties: Object.assign(Object.assign({}, apigeeXAdapterConfigSchema.properties), { type: { type: 'string', const: 'APIGEE_EDGE' } }) });
|
|
164
|
-
const graviteeAdapterConfigSchema = {
|
|
165
|
-
type: 'object',
|
|
166
|
-
properties: {
|
|
167
|
-
type: { type: 'string', const: 'GRAVITEE' },
|
|
168
|
-
apiBaseUrl: { type: 'string' },
|
|
169
|
-
env: { type: 'string' },
|
|
170
|
-
allowApiProductsOutsideCatalog: { type: 'boolean', default: false },
|
|
171
|
-
stage: { type: 'string', default: 'non-production' },
|
|
172
|
-
auth: { type: 'object', properties: { static: { type: 'string' } } },
|
|
173
|
-
},
|
|
174
|
-
additionalProperties: false,
|
|
175
|
-
required: ['type', 'apiBaseUrl'],
|
|
176
|
-
};
|
|
177
|
-
const devOnboardingAdapterConfigSchema = {
|
|
178
|
-
type: 'object',
|
|
179
|
-
oneOf: [apigeeXAdapterConfigSchema, apigeeEdgeAdapterConfigSchema, graviteeAdapterConfigSchema],
|
|
180
|
-
discriminator: { propertyName: 'type' },
|
|
181
|
-
};
|
|
182
|
-
exports.devOnboardingConfigSchema = {
|
|
183
|
-
type: 'object',
|
|
184
|
-
required: ['adapters'],
|
|
185
|
-
additionalProperties: false,
|
|
186
|
-
properties: {
|
|
187
|
-
adapters: {
|
|
188
|
-
type: 'array',
|
|
189
|
-
items: devOnboardingAdapterConfigSchema,
|
|
190
|
-
},
|
|
191
|
-
},
|
|
192
|
-
};
|
|
193
|
-
exports.responseHeaderSchema = {
|
|
194
|
-
type: 'object',
|
|
195
|
-
properties: {
|
|
196
|
-
name: { type: 'string' },
|
|
197
|
-
value: { type: 'string' },
|
|
198
|
-
},
|
|
199
|
-
additionalProperties: false,
|
|
200
|
-
required: ['name', 'value'],
|
|
201
|
-
};
|
|
202
|
-
exports.i18nConfigSchema = {
|
|
203
|
-
type: 'object',
|
|
204
|
-
properties: {
|
|
205
|
-
defaultLocale: {
|
|
206
|
-
type: 'string',
|
|
207
|
-
},
|
|
208
|
-
locales: {
|
|
209
|
-
type: 'array',
|
|
210
|
-
items: {
|
|
211
|
-
type: 'object',
|
|
212
|
-
properties: {
|
|
213
|
-
code: {
|
|
214
|
-
type: 'string',
|
|
215
|
-
},
|
|
216
|
-
name: {
|
|
217
|
-
type: 'string',
|
|
218
|
-
},
|
|
219
|
-
},
|
|
220
|
-
required: ['code'],
|
|
221
|
-
},
|
|
222
|
-
},
|
|
223
|
-
},
|
|
224
|
-
required: ['defaultLocale', 'locales'],
|
|
225
|
-
};
|
|
226
|
-
exports.mockServerConfigSchema = {
|
|
227
|
-
type: 'object',
|
|
228
|
-
properties: {
|
|
229
|
-
off: { type: 'boolean', default: false },
|
|
230
|
-
position: { type: 'string', enum: ['first', 'last', 'replace', 'off'], default: 'first' },
|
|
231
|
-
strictExamples: { type: 'boolean', default: false },
|
|
232
|
-
errorIfForcedExampleNotFound: { type: 'boolean', default: false },
|
|
233
|
-
description: { type: 'string' },
|
|
234
|
-
},
|
|
235
|
-
};
|
|
3
|
+
exports.ScorecardStatus = exports.productThemeOverrideSchema = exports.themeConfigSchema = void 0;
|
|
236
4
|
const logoConfigSchema = {
|
|
237
5
|
type: 'object',
|
|
238
6
|
properties: {
|
|
239
7
|
image: { type: 'string' },
|
|
8
|
+
srcSet: { type: 'string' },
|
|
240
9
|
altText: { type: 'string' },
|
|
241
10
|
link: { type: 'string' },
|
|
242
11
|
favicon: { type: 'string' },
|
|
@@ -316,7 +85,7 @@ const markdownConfigSchema = {
|
|
|
316
85
|
},
|
|
317
86
|
editPage: {
|
|
318
87
|
type: 'object',
|
|
319
|
-
properties: Object.assign({ baseUrl: { type: 'string' }
|
|
88
|
+
properties: Object.assign({ baseUrl: { type: 'string' } }, hideConfigSchema.properties),
|
|
320
89
|
additionalProperties: false,
|
|
321
90
|
default: {},
|
|
322
91
|
},
|
|
@@ -404,35 +173,14 @@ const googleAnalyticsConfigSchema = {
|
|
|
404
173
|
properties: {
|
|
405
174
|
includeInDevelopment: { type: 'boolean' },
|
|
406
175
|
trackingId: { type: 'string' },
|
|
176
|
+
conversionId: { type: 'string' },
|
|
177
|
+
floodlightId: { type: 'string' },
|
|
407
178
|
head: { type: 'boolean' },
|
|
408
179
|
respectDNT: { type: 'boolean' },
|
|
409
|
-
anonymize: { type: 'boolean' },
|
|
410
180
|
exclude: { type: 'array', items: { type: 'string' } },
|
|
411
181
|
optimizeId: { type: 'string' },
|
|
412
|
-
|
|
413
|
-
variationId: { type: 'string' },
|
|
414
|
-
enableWebVitalsTracking: { type: 'boolean' },
|
|
415
|
-
defer: { type: 'boolean' },
|
|
416
|
-
sampleRate: { type: 'number' },
|
|
417
|
-
name: { type: 'string' },
|
|
418
|
-
clientId: { type: 'string' },
|
|
419
|
-
siteSpeedSampleRate: { type: 'number' },
|
|
420
|
-
alwaysSendReferrer: { type: 'boolean' },
|
|
421
|
-
allowAnchor: { type: 'boolean' },
|
|
422
|
-
cookieName: { type: 'string' },
|
|
423
|
-
cookieFlags: { type: 'string' },
|
|
424
|
-
cookieDomain: { type: 'string' },
|
|
182
|
+
anonymizeIp: { type: 'boolean' },
|
|
425
183
|
cookieExpires: { type: 'number' },
|
|
426
|
-
storeGac: { type: 'boolean' },
|
|
427
|
-
legacyCookieDomain: { type: 'string' },
|
|
428
|
-
legacyHistoryImport: { type: 'boolean' },
|
|
429
|
-
allowLinker: { type: 'boolean' },
|
|
430
|
-
storage: { type: 'string' },
|
|
431
|
-
allowAdFeatures: { type: 'boolean' },
|
|
432
|
-
dataSource: { type: 'string' },
|
|
433
|
-
queueTime: { type: 'number' },
|
|
434
|
-
forceSSL: { type: 'boolean' },
|
|
435
|
-
transport: { type: 'string' },
|
|
436
184
|
},
|
|
437
185
|
additionalProperties: false,
|
|
438
186
|
required: ['trackingId'],
|
|
@@ -456,6 +204,11 @@ const navItemSchema = {
|
|
|
456
204
|
label: { type: 'string' },
|
|
457
205
|
separator: { type: 'string' },
|
|
458
206
|
separatorLine: { type: 'boolean' },
|
|
207
|
+
linePosition: {
|
|
208
|
+
type: 'string',
|
|
209
|
+
enum: ['top', 'bottom'],
|
|
210
|
+
default: 'top',
|
|
211
|
+
},
|
|
459
212
|
version: { type: 'string' },
|
|
460
213
|
menuStyle: { type: 'string', enum: ['drilldown'] },
|
|
461
214
|
expanded: { type: 'string', const: 'always' },
|
|
@@ -511,6 +264,14 @@ const scorecardConfigSchema = {
|
|
|
511
264
|
required: ['levels'],
|
|
512
265
|
properties: {
|
|
513
266
|
failBuildIfBelowMinimum: { type: 'boolean', default: false },
|
|
267
|
+
teamMetadataProperty: {
|
|
268
|
+
type: 'object',
|
|
269
|
+
properties: {
|
|
270
|
+
property: { type: 'string' },
|
|
271
|
+
label: { type: 'string' },
|
|
272
|
+
default: { type: 'string' },
|
|
273
|
+
},
|
|
274
|
+
},
|
|
514
275
|
levels: {
|
|
515
276
|
type: 'array',
|
|
516
277
|
items: {
|
|
@@ -553,11 +314,15 @@ const scorecardConfigSchema = {
|
|
|
553
314
|
const catalogSchema = {
|
|
554
315
|
type: 'object',
|
|
555
316
|
additionalProperties: true,
|
|
556
|
-
required: ['slug', '
|
|
317
|
+
required: ['slug', 'items'],
|
|
557
318
|
properties: {
|
|
558
319
|
slug: { type: 'string' },
|
|
559
320
|
filters: { type: 'array', items: catalogFilterSchema },
|
|
560
321
|
groupByFirstFilter: { type: 'boolean' },
|
|
322
|
+
filterValuesCasing: {
|
|
323
|
+
type: 'string',
|
|
324
|
+
enum: ['sentence', 'original', 'lowercase', 'uppercase'],
|
|
325
|
+
},
|
|
561
326
|
items: navItemsSchema,
|
|
562
327
|
requiredPermission: { type: 'string' },
|
|
563
328
|
separateVersions: { type: 'boolean' },
|
|
@@ -593,10 +358,24 @@ exports.themeConfigSchema = {
|
|
|
593
358
|
},
|
|
594
359
|
footer: {
|
|
595
360
|
type: 'object',
|
|
596
|
-
properties: Object.assign({ items: navItemsSchema, copyrightText: { type: 'string' } }, hideConfigSchema.properties),
|
|
361
|
+
properties: Object.assign({ items: navItemsSchema, copyrightText: { type: 'string' }, logo: hideConfigSchema }, hideConfigSchema.properties),
|
|
597
362
|
additionalProperties: false,
|
|
598
363
|
},
|
|
599
|
-
sidebar:
|
|
364
|
+
sidebar: {
|
|
365
|
+
type: 'object',
|
|
366
|
+
properties: Object.assign({ separatorLine: { type: 'boolean' }, linePosition: {
|
|
367
|
+
type: 'string',
|
|
368
|
+
enum: ['top', 'bottom'],
|
|
369
|
+
default: 'bottom',
|
|
370
|
+
} }, hideConfigSchema.properties),
|
|
371
|
+
additionalProperties: false,
|
|
372
|
+
},
|
|
373
|
+
seo: {
|
|
374
|
+
type: 'object',
|
|
375
|
+
properties: {
|
|
376
|
+
title: { type: 'string' },
|
|
377
|
+
},
|
|
378
|
+
},
|
|
600
379
|
scripts: {
|
|
601
380
|
type: 'object',
|
|
602
381
|
properties: {
|
|
@@ -762,6 +541,15 @@ exports.themeConfigSchema = {
|
|
|
762
541
|
additionalProperties: false,
|
|
763
542
|
default: {},
|
|
764
543
|
},
|
|
544
|
+
versionPicker: {
|
|
545
|
+
type: 'object',
|
|
546
|
+
properties: {
|
|
547
|
+
hide: { type: 'boolean' },
|
|
548
|
+
showForUnversioned: {
|
|
549
|
+
type: 'boolean',
|
|
550
|
+
},
|
|
551
|
+
},
|
|
552
|
+
},
|
|
765
553
|
breadcrumbs: {
|
|
766
554
|
type: 'object',
|
|
767
555
|
properties: {
|
|
@@ -803,3 +591,9 @@ exports.productThemeOverrideSchema = {
|
|
|
803
591
|
additionalProperties: true,
|
|
804
592
|
default: {},
|
|
805
593
|
};
|
|
594
|
+
var ScorecardStatus;
|
|
595
|
+
(function (ScorecardStatus) {
|
|
596
|
+
ScorecardStatus["BelowMinimum"] = "Below minimum";
|
|
597
|
+
ScorecardStatus["Highest"] = "Highest";
|
|
598
|
+
ScorecardStatus["Minimum"] = "Minimum";
|
|
599
|
+
})(ScorecardStatus = exports.ScorecardStatus || (exports.ScorecardStatus = {}));
|
package/package.json
CHANGED
|
@@ -111,6 +111,7 @@ describe('lint', () => {
|
|
|
111
111
|
"severity": "error",
|
|
112
112
|
"suggest": Array [
|
|
113
113
|
"theme",
|
|
114
|
+
"env",
|
|
114
115
|
"seo",
|
|
115
116
|
"sso",
|
|
116
117
|
],
|
|
@@ -178,6 +179,7 @@ describe('lint', () => {
|
|
|
178
179
|
"apis",
|
|
179
180
|
"seo",
|
|
180
181
|
"sso",
|
|
182
|
+
"env",
|
|
181
183
|
],
|
|
182
184
|
},
|
|
183
185
|
]
|
|
@@ -41,6 +41,47 @@ describe('no-path-trailing-slash', () => {
|
|
|
41
41
|
`);
|
|
42
42
|
});
|
|
43
43
|
|
|
44
|
+
it('should report on trailing slash in path on key when referencing', async () => {
|
|
45
|
+
const document = parseYamlToDocument(
|
|
46
|
+
outdent`
|
|
47
|
+
openapi: 3.0.0
|
|
48
|
+
paths:
|
|
49
|
+
'/bad/':
|
|
50
|
+
$ref: '#/components/pathItems/MyItem'
|
|
51
|
+
components:
|
|
52
|
+
pathItems:
|
|
53
|
+
MyItem:
|
|
54
|
+
get:
|
|
55
|
+
summary: List all pets
|
|
56
|
+
`,
|
|
57
|
+
'foobar.yaml'
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
const results = await lintDocument({
|
|
61
|
+
externalRefResolver: new BaseResolver(),
|
|
62
|
+
document,
|
|
63
|
+
config: await makeConfig({ 'no-path-trailing-slash': 'error' }),
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
|
|
67
|
+
Array [
|
|
68
|
+
Object {
|
|
69
|
+
"location": Array [
|
|
70
|
+
Object {
|
|
71
|
+
"pointer": "#/paths/~1bad~1",
|
|
72
|
+
"reportOnKey": true,
|
|
73
|
+
"source": "foobar.yaml",
|
|
74
|
+
},
|
|
75
|
+
],
|
|
76
|
+
"message": "\`/bad/\` should not have a trailing slash.",
|
|
77
|
+
"ruleId": "no-path-trailing-slash",
|
|
78
|
+
"severity": "error",
|
|
79
|
+
"suggest": Array [],
|
|
80
|
+
},
|
|
81
|
+
]
|
|
82
|
+
`);
|
|
83
|
+
});
|
|
84
|
+
|
|
44
85
|
it('should not report on if no trailing slash in path', async () => {
|
|
45
86
|
const document = parseYamlToDocument(
|
|
46
87
|
outdent`
|
|
@@ -61,4 +61,62 @@ describe('Oas3 tags-alphabetical', () => {
|
|
|
61
61
|
|
|
62
62
|
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`Array []`);
|
|
63
63
|
});
|
|
64
|
+
|
|
65
|
+
it('should report on tags object if not sorted alphabetically not ignoring case', async () => {
|
|
66
|
+
const document = parseYamlToDocument(
|
|
67
|
+
outdent`
|
|
68
|
+
openapi: 3.0.0
|
|
69
|
+
paths: {}
|
|
70
|
+
tags:
|
|
71
|
+
- name: a
|
|
72
|
+
- name: B
|
|
73
|
+
`,
|
|
74
|
+
'foobar.yaml'
|
|
75
|
+
);
|
|
76
|
+
|
|
77
|
+
const results = await lintDocument({
|
|
78
|
+
externalRefResolver: new BaseResolver(),
|
|
79
|
+
document,
|
|
80
|
+
config: await makeConfig({ 'tags-alphabetical': 'error' }),
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
|
|
84
|
+
Array [
|
|
85
|
+
Object {
|
|
86
|
+
"location": Array [
|
|
87
|
+
Object {
|
|
88
|
+
"pointer": "#/tags/0",
|
|
89
|
+
"reportOnKey": false,
|
|
90
|
+
"source": "foobar.yaml",
|
|
91
|
+
},
|
|
92
|
+
],
|
|
93
|
+
"message": "The \`tags\` array should be in alphabetical order.",
|
|
94
|
+
"ruleId": "tags-alphabetical",
|
|
95
|
+
"severity": "error",
|
|
96
|
+
"suggest": Array [],
|
|
97
|
+
},
|
|
98
|
+
]
|
|
99
|
+
`);
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
it('should not report on tags object if sorted alphabetically ignoring case', async () => {
|
|
103
|
+
const document = parseYamlToDocument(
|
|
104
|
+
outdent`
|
|
105
|
+
openapi: 3.0.0
|
|
106
|
+
paths: {}
|
|
107
|
+
tags:
|
|
108
|
+
- name: a
|
|
109
|
+
- name: B
|
|
110
|
+
`,
|
|
111
|
+
'foobar.yaml'
|
|
112
|
+
);
|
|
113
|
+
|
|
114
|
+
const results = await lintDocument({
|
|
115
|
+
externalRefResolver: new BaseResolver(),
|
|
116
|
+
document,
|
|
117
|
+
config: await makeConfig({ 'tags-alphabetical': { severity: 'error', ignoreCase: true } }),
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`Array []`);
|
|
121
|
+
});
|
|
64
122
|
});
|
|
@@ -3,11 +3,11 @@ import { UserContext } from '../../walk';
|
|
|
3
3
|
|
|
4
4
|
export const NoPathTrailingSlash: Oas3Rule | Oas2Rule = () => {
|
|
5
5
|
return {
|
|
6
|
-
PathItem(_path: any, { report, key,
|
|
6
|
+
PathItem(_path: any, { report, key, rawLocation }: UserContext) {
|
|
7
7
|
if ((key as string).endsWith('/') && key !== '/') {
|
|
8
8
|
report({
|
|
9
9
|
message: `\`${key}\` should not have a trailing slash.`,
|
|
10
|
-
location:
|
|
10
|
+
location: rawLocation.key(),
|
|
11
11
|
});
|
|
12
12
|
}
|
|
13
13
|
},
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { Oas3Rule, Oas2Rule } from '../../visitors';
|
|
2
|
-
import { Oas2Definition } from '../../typings/swagger';
|
|
3
|
-
import { Oas3Definition } from '../../typings/openapi';
|
|
2
|
+
import { Oas2Definition, Oas2Tag } from '../../typings/swagger';
|
|
3
|
+
import { Oas3Definition, Oas3Tag } from '../../typings/openapi';
|
|
4
4
|
import { UserContext } from '../../walk';
|
|
5
5
|
|
|
6
|
-
export const TagsAlphabetical: Oas3Rule | Oas2Rule = () => {
|
|
6
|
+
export const TagsAlphabetical: Oas3Rule | Oas2Rule = ({ ignoreCase = false }) => {
|
|
7
7
|
return {
|
|
8
8
|
Root(root: Oas2Definition | Oas3Definition, { report, location }: UserContext) {
|
|
9
9
|
if (!root.tags) return;
|
|
10
10
|
for (let i = 0; i < root.tags.length - 1; i++) {
|
|
11
|
-
if (root.tags[i]
|
|
11
|
+
if (getTagName(root.tags[i], ignoreCase) > getTagName(root.tags[i + 1], ignoreCase)) {
|
|
12
12
|
report({
|
|
13
13
|
message: 'The `tags` array should be in alphabetical order.',
|
|
14
14
|
location: location.child(['tags', i]),
|
|
@@ -18,3 +18,7 @@ export const TagsAlphabetical: Oas3Rule | Oas2Rule = () => {
|
|
|
18
18
|
},
|
|
19
19
|
};
|
|
20
20
|
};
|
|
21
|
+
|
|
22
|
+
function getTagName(tag: Oas2Tag | Oas3Tag, ignoreCase: boolean): string {
|
|
23
|
+
return ignoreCase ? tag.name.toLowerCase() : tag.name;
|
|
24
|
+
}
|