@redocly/openapi-core 1.2.0 → 1.3.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 +17 -0
- package/README.md +250 -7
- package/lib/bundle.d.ts +10 -4
- package/lib/bundle.js +10 -2
- package/lib/config/load.d.ts +3 -2
- package/lib/config/load.js +5 -2
- package/lib/config/types.d.ts +1 -0
- package/lib/config/utils.d.ts +2 -0
- package/lib/config/utils.js +4 -1
- package/lib/index.d.ts +3 -2
- package/lib/index.js +5 -2
- package/lib/rules/common/assertions/asserts.js +12 -4
- package/lib/rules/oas3/no-server-example.com.js +3 -2
- package/lib/types/asyncapi.js +8 -1
- package/lib/types/oas3_1.js +8 -1
- package/package.json +3 -2
- package/src/__tests__/__snapshots__/bundle.test.ts.snap +1 -1
- package/src/__tests__/bundle.test.ts +65 -25
- package/src/__tests__/fixtures/lint/openapi.yaml +10 -0
- package/src/__tests__/fixtures/redocly.yaml +2 -0
- package/src/__tests__/lint.test.ts +31 -2
- package/src/bundle.ts +35 -7
- package/src/config/__tests__/load.test.ts +35 -2
- package/src/config/load.ts +15 -5
- package/src/config/types.ts +3 -0
- package/src/config/utils.ts +2 -0
- package/src/index.ts +3 -1
- package/src/rules/common/assertions/asserts.ts +16 -4
- package/src/rules/oas3/__tests__/no-server-example.com.test.ts +36 -1
- package/src/rules/oas3/__tests__/spec/spec.test.ts +1 -1
- package/src/rules/oas3/no-server-example.com.ts +3 -2
- package/src/types/asyncapi.ts +7 -1
- package/src/types/oas3_1.ts +7 -1
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -1,11 +1,32 @@
|
|
|
1
1
|
import outdent from 'outdent';
|
|
2
2
|
import * as path from 'path';
|
|
3
3
|
|
|
4
|
-
import { bundleDocument, bundle } from '../bundle';
|
|
4
|
+
import { bundleDocument, bundle, bundleFromString } from '../bundle';
|
|
5
5
|
import { parseYamlToDocument, yamlSerializer, makeConfig } from '../../__tests__/utils';
|
|
6
|
-
import { StyleguideConfig, Config, ResolvedConfig } from '../config';
|
|
6
|
+
import { StyleguideConfig, Config, ResolvedConfig, createConfig, loadConfig } from '../config';
|
|
7
7
|
import { BaseResolver } from '../resolve';
|
|
8
8
|
|
|
9
|
+
const stringDocument = outdent`
|
|
10
|
+
openapi: 3.0.0
|
|
11
|
+
paths:
|
|
12
|
+
/pet:
|
|
13
|
+
get:
|
|
14
|
+
operationId: get
|
|
15
|
+
parameters:
|
|
16
|
+
- $ref: '#/components/parameters/shared_a'
|
|
17
|
+
- name: get_b
|
|
18
|
+
post:
|
|
19
|
+
operationId: post
|
|
20
|
+
parameters:
|
|
21
|
+
- $ref: '#/components/parameters/shared_a'
|
|
22
|
+
components:
|
|
23
|
+
parameters:
|
|
24
|
+
shared_a:
|
|
25
|
+
name: shared-a
|
|
26
|
+
`;
|
|
27
|
+
|
|
28
|
+
const testDocument = parseYamlToDocument(stringDocument, '');
|
|
29
|
+
|
|
9
30
|
describe('bundle', () => {
|
|
10
31
|
const fetchMock = jest.fn(() =>
|
|
11
32
|
Promise.resolve({
|
|
@@ -19,28 +40,6 @@ describe('bundle', () => {
|
|
|
19
40
|
|
|
20
41
|
expect.addSnapshotSerializer(yamlSerializer);
|
|
21
42
|
|
|
22
|
-
const testDocument = parseYamlToDocument(
|
|
23
|
-
outdent`
|
|
24
|
-
openapi: 3.0.0
|
|
25
|
-
paths:
|
|
26
|
-
/pet:
|
|
27
|
-
get:
|
|
28
|
-
operationId: get
|
|
29
|
-
parameters:
|
|
30
|
-
- $ref: '#/components/parameters/shared_a'
|
|
31
|
-
- name: get_b
|
|
32
|
-
post:
|
|
33
|
-
operationId: post
|
|
34
|
-
parameters:
|
|
35
|
-
- $ref: '#/components/parameters/shared_a'
|
|
36
|
-
components:
|
|
37
|
-
parameters:
|
|
38
|
-
shared_a:
|
|
39
|
-
name: shared-a
|
|
40
|
-
`,
|
|
41
|
-
''
|
|
42
|
-
);
|
|
43
|
-
|
|
44
43
|
it('change nothing with only internal refs', async () => {
|
|
45
44
|
const { bundle, problems } = await bundleDocument({
|
|
46
45
|
document: testDocument,
|
|
@@ -97,7 +96,7 @@ describe('bundle', () => {
|
|
|
97
96
|
expect(res.parsed).toMatchSnapshot();
|
|
98
97
|
});
|
|
99
98
|
|
|
100
|
-
it('should not place
|
|
99
|
+
it('should not place referenced schema inline when component in question is not of type "schemas"', async () => {
|
|
101
100
|
const { bundle: res, problems } = await bundle({
|
|
102
101
|
config: new Config({} as ResolvedConfig),
|
|
103
102
|
ref: path.join(__dirname, 'fixtures/refs/external-request-body.yaml'),
|
|
@@ -233,4 +232,45 @@ describe('bundle', () => {
|
|
|
233
232
|
|
|
234
233
|
`);
|
|
235
234
|
});
|
|
235
|
+
|
|
236
|
+
it('should throw an error when there is no document to bundle', () => {
|
|
237
|
+
const wrapper = () =>
|
|
238
|
+
bundle({
|
|
239
|
+
config: new Config({} as ResolvedConfig),
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
expect(wrapper()).rejects.toThrowError('Document or reference is required.\n');
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
it('should bundle with a doc provided', async () => {
|
|
246
|
+
const {
|
|
247
|
+
bundle: { parsed },
|
|
248
|
+
problems,
|
|
249
|
+
} = await bundle({
|
|
250
|
+
config: await loadConfig({ configPath: path.join(__dirname, 'fixtures/redocly.yaml') }),
|
|
251
|
+
doc: testDocument,
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
const origCopy = JSON.parse(JSON.stringify(testDocument.parsed));
|
|
255
|
+
|
|
256
|
+
expect(problems).toHaveLength(0);
|
|
257
|
+
expect(parsed).toEqual(origCopy);
|
|
258
|
+
});
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
describe('bundleFromString', () => {
|
|
262
|
+
it('should bundle from string using bundleFromString', async () => {
|
|
263
|
+
const {
|
|
264
|
+
bundle: { parsed, ...rest },
|
|
265
|
+
problems,
|
|
266
|
+
} = await bundleFromString({
|
|
267
|
+
config: await createConfig(`
|
|
268
|
+
extends:
|
|
269
|
+
- recommended
|
|
270
|
+
`),
|
|
271
|
+
source: testDocument.source.body,
|
|
272
|
+
});
|
|
273
|
+
expect(problems).toHaveLength(0);
|
|
274
|
+
expect(rest.source.body).toEqual(stringDocument);
|
|
275
|
+
});
|
|
236
276
|
});
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as path from 'path';
|
|
2
2
|
import { outdent } from 'outdent';
|
|
3
3
|
|
|
4
|
-
import { lintFromString, lintConfig, lintDocument } from '../lint';
|
|
4
|
+
import { lintFromString, lintConfig, lintDocument, lint } from '../lint';
|
|
5
5
|
import { BaseResolver } from '../resolve';
|
|
6
6
|
import { loadConfig } from '../config/load';
|
|
7
7
|
import { parseYamlToDocument, replaceSourceWithRef, makeConfig } from '../../__tests__/utils';
|
|
@@ -20,7 +20,7 @@ describe('lint', () => {
|
|
|
20
20
|
license: Fail
|
|
21
21
|
|
|
22
22
|
servers:
|
|
23
|
-
- url: http://example.com
|
|
23
|
+
- url: http://redocly-example.com
|
|
24
24
|
paths: {}
|
|
25
25
|
`,
|
|
26
26
|
config: await loadConfig(),
|
|
@@ -46,6 +46,35 @@ describe('lint', () => {
|
|
|
46
46
|
`);
|
|
47
47
|
});
|
|
48
48
|
|
|
49
|
+
it('lint should work', async () => {
|
|
50
|
+
const results = await lint({
|
|
51
|
+
ref: path.join(__dirname, 'fixtures/lint/openapi.yaml'),
|
|
52
|
+
config: await loadConfig({
|
|
53
|
+
configPath: path.join(__dirname, 'fixtures/redocly.yaml'),
|
|
54
|
+
}),
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
expect(replaceSourceWithRef(results, path.join(__dirname, 'fixtures/lint/')))
|
|
58
|
+
.toMatchInlineSnapshot(`
|
|
59
|
+
Array [
|
|
60
|
+
Object {
|
|
61
|
+
"from": undefined,
|
|
62
|
+
"location": Array [
|
|
63
|
+
Object {
|
|
64
|
+
"pointer": "#/info/license",
|
|
65
|
+
"reportOnKey": false,
|
|
66
|
+
"source": "openapi.yaml",
|
|
67
|
+
},
|
|
68
|
+
],
|
|
69
|
+
"message": "Expected type \`License\` (object) but got \`string\`",
|
|
70
|
+
"ruleId": "spec",
|
|
71
|
+
"severity": "error",
|
|
72
|
+
"suggest": Array [],
|
|
73
|
+
},
|
|
74
|
+
]
|
|
75
|
+
`);
|
|
76
|
+
});
|
|
77
|
+
|
|
49
78
|
it('lintConfig should work', async () => {
|
|
50
79
|
const document = parseYamlToDocument(
|
|
51
80
|
outdent`
|
package/src/bundle.ts
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
import isEqual = require('lodash.isequal');
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
BaseResolver,
|
|
4
|
+
resolveDocument,
|
|
5
|
+
Document,
|
|
6
|
+
ResolvedRefMap,
|
|
7
|
+
makeRefId,
|
|
8
|
+
makeDocumentFromString,
|
|
9
|
+
} from './resolve';
|
|
3
10
|
import { Oas3Rule, normalizeVisitors, Oas3Visitor, Oas2Visitor } from './visitors';
|
|
4
11
|
import { NormalizedNodeType, normalizeTypes, NodeType } from './types';
|
|
5
12
|
import { WalkContext, walkDocument, UserContext, ResolveResult, NormalizedProblem } from './walk';
|
|
@@ -22,10 +29,7 @@ export enum OasVersion {
|
|
|
22
29
|
Version3_0 = 'oas3_0',
|
|
23
30
|
Version3_1 = 'oas3_1',
|
|
24
31
|
}
|
|
25
|
-
|
|
26
|
-
export async function bundle(opts: {
|
|
27
|
-
ref?: string;
|
|
28
|
-
doc?: Document;
|
|
32
|
+
export type BundleOptions = {
|
|
29
33
|
externalRefResolver?: BaseResolver;
|
|
30
34
|
config: Config;
|
|
31
35
|
dereference?: boolean;
|
|
@@ -33,7 +37,14 @@ export async function bundle(opts: {
|
|
|
33
37
|
skipRedoclyRegistryRefs?: boolean;
|
|
34
38
|
removeUnusedComponents?: boolean;
|
|
35
39
|
keepUrlRefs?: boolean;
|
|
36
|
-
}
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
export async function bundle(
|
|
43
|
+
opts: {
|
|
44
|
+
ref?: string;
|
|
45
|
+
doc?: Document;
|
|
46
|
+
} & BundleOptions
|
|
47
|
+
) {
|
|
37
48
|
const {
|
|
38
49
|
ref,
|
|
39
50
|
doc,
|
|
@@ -45,7 +56,7 @@ export async function bundle(opts: {
|
|
|
45
56
|
}
|
|
46
57
|
|
|
47
58
|
const document =
|
|
48
|
-
doc
|
|
59
|
+
doc === undefined ? await externalRefResolver.resolveDocument(base, ref!, true) : doc;
|
|
49
60
|
|
|
50
61
|
if (document instanceof Error) {
|
|
51
62
|
throw document;
|
|
@@ -59,6 +70,23 @@ export async function bundle(opts: {
|
|
|
59
70
|
});
|
|
60
71
|
}
|
|
61
72
|
|
|
73
|
+
export async function bundleFromString(
|
|
74
|
+
opts: {
|
|
75
|
+
source: string;
|
|
76
|
+
absoluteRef?: string;
|
|
77
|
+
} & BundleOptions
|
|
78
|
+
) {
|
|
79
|
+
const { source, absoluteRef, externalRefResolver = new BaseResolver(opts.config.resolve) } = opts;
|
|
80
|
+
const document = makeDocumentFromString(source, absoluteRef || '/');
|
|
81
|
+
|
|
82
|
+
return bundleDocument({
|
|
83
|
+
document,
|
|
84
|
+
...opts,
|
|
85
|
+
externalRefResolver,
|
|
86
|
+
config: opts.config.styleguide,
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
|
|
62
90
|
type BundleContext = WalkContext;
|
|
63
91
|
|
|
64
92
|
export type BundleResult = {
|
|
@@ -73,8 +73,8 @@ describe('findConfig', () => {
|
|
|
73
73
|
.spyOn(fs, 'existsSync')
|
|
74
74
|
.mockImplementation((name) => name === 'redocly.yaml' || name === '.redocly.yaml');
|
|
75
75
|
expect(findConfig).toThrow(`
|
|
76
|
-
Multiple configuration files are not allowed.
|
|
77
|
-
Found the following files: redocly.yaml, .redocly.yaml.
|
|
76
|
+
Multiple configuration files are not allowed.
|
|
77
|
+
Found the following files: redocly.yaml, .redocly.yaml.
|
|
78
78
|
Please use 'redocly.yaml' instead.
|
|
79
79
|
`);
|
|
80
80
|
});
|
|
@@ -124,6 +124,39 @@ describe('createConfig', () => {
|
|
|
124
124
|
overridesRules: rawConfig.rules as Record<string, RuleConfig>,
|
|
125
125
|
});
|
|
126
126
|
});
|
|
127
|
+
|
|
128
|
+
it('should create config from object with a custom plugin', async () => {
|
|
129
|
+
const testCustomRule = jest.fn();
|
|
130
|
+
const rawConfig: FlatRawConfig = {
|
|
131
|
+
extends: [],
|
|
132
|
+
plugins: [
|
|
133
|
+
{
|
|
134
|
+
id: 'my-plugin',
|
|
135
|
+
rules: {
|
|
136
|
+
oas3: {
|
|
137
|
+
'test-rule': testCustomRule,
|
|
138
|
+
},
|
|
139
|
+
},
|
|
140
|
+
},
|
|
141
|
+
],
|
|
142
|
+
rules: {
|
|
143
|
+
'my-plugin/test-rule': 'error',
|
|
144
|
+
},
|
|
145
|
+
};
|
|
146
|
+
const config = await createConfig(rawConfig);
|
|
147
|
+
|
|
148
|
+
expect(config.styleguide.plugins[0]).toEqual({
|
|
149
|
+
id: 'my-plugin',
|
|
150
|
+
rules: {
|
|
151
|
+
oas3: {
|
|
152
|
+
'my-plugin/test-rule': testCustomRule,
|
|
153
|
+
},
|
|
154
|
+
},
|
|
155
|
+
});
|
|
156
|
+
expect(config.styleguide.rules.oas3_0).toEqual({
|
|
157
|
+
'my-plugin/test-rule': 'error',
|
|
158
|
+
});
|
|
159
|
+
});
|
|
127
160
|
});
|
|
128
161
|
|
|
129
162
|
function verifyExtendedConfig(
|
package/src/config/load.ts
CHANGED
|
@@ -4,10 +4,16 @@ import { RedoclyClient } from '../redocly';
|
|
|
4
4
|
import { isEmptyObject, loadYaml, doesYamlFileExist } from '../utils';
|
|
5
5
|
import { parseYaml } from '../js-yaml';
|
|
6
6
|
import { Config, DOMAINS } from './config';
|
|
7
|
-
import { transformConfig } from './utils';
|
|
7
|
+
import { ConfigValidationError, transformConfig } from './utils';
|
|
8
8
|
import { resolveConfig } from './config-resolvers';
|
|
9
9
|
|
|
10
|
-
import type {
|
|
10
|
+
import type {
|
|
11
|
+
DeprecatedInRawConfig,
|
|
12
|
+
FlatRawConfig,
|
|
13
|
+
RawConfig,
|
|
14
|
+
RawUniversalConfig,
|
|
15
|
+
Region,
|
|
16
|
+
} from './types';
|
|
11
17
|
import { RegionalTokenWithValidity } from '../redocly/redocly-client-types';
|
|
12
18
|
|
|
13
19
|
async function addConfigMetadata({
|
|
@@ -101,8 +107,8 @@ export function findConfig(dir?: string): string | undefined {
|
|
|
101
107
|
).filter(fs.existsSync);
|
|
102
108
|
if (existingConfigFiles.length > 1) {
|
|
103
109
|
throw new Error(`
|
|
104
|
-
Multiple configuration files are not allowed.
|
|
105
|
-
Found the following files: ${existingConfigFiles.join(', ')}.
|
|
110
|
+
Multiple configuration files are not allowed.
|
|
111
|
+
Found the following files: ${existingConfigFiles.join(', ')}.
|
|
106
112
|
Please use 'redocly.yaml' instead.
|
|
107
113
|
`);
|
|
108
114
|
}
|
|
@@ -122,6 +128,9 @@ export async function getConfig(
|
|
|
122
128
|
}
|
|
123
129
|
return transformConfig(rawConfig);
|
|
124
130
|
} catch (e) {
|
|
131
|
+
if (e instanceof ConfigValidationError) {
|
|
132
|
+
throw e;
|
|
133
|
+
}
|
|
125
134
|
throw new Error(`Error parsing config file at '${configPath}': ${e.message}`);
|
|
126
135
|
}
|
|
127
136
|
}
|
|
@@ -129,10 +138,11 @@ export async function getConfig(
|
|
|
129
138
|
type CreateConfigOptions = {
|
|
130
139
|
extends?: string[];
|
|
131
140
|
tokens?: RegionalTokenWithValidity[];
|
|
141
|
+
configPath?: string;
|
|
132
142
|
};
|
|
133
143
|
|
|
134
144
|
export async function createConfig(
|
|
135
|
-
config: string |
|
|
145
|
+
config: string | RawUniversalConfig,
|
|
136
146
|
options?: CreateConfigOptions
|
|
137
147
|
): Promise<Config> {
|
|
138
148
|
return addConfigMetadata({
|
package/src/config/types.ts
CHANGED
|
@@ -185,6 +185,9 @@ export type RawConfig = {
|
|
|
185
185
|
telemetry?: Telemetry;
|
|
186
186
|
} & ThemeConfig;
|
|
187
187
|
|
|
188
|
+
// RawConfig is legacy, use RawUniversalConfig in public APIs
|
|
189
|
+
export type RawUniversalConfig = Omit<RawConfig, 'styleguide'> & StyleguideRawConfig;
|
|
190
|
+
|
|
188
191
|
export type FlatApi = Omit<Api, 'styleguide'> &
|
|
189
192
|
Omit<ApiStyleguideRawConfig, 'doNotResolveExamples'>;
|
|
190
193
|
|
package/src/config/utils.ts
CHANGED
package/src/index.ts
CHANGED
|
@@ -2,6 +2,7 @@ export { BundleOutputFormat, readFileFromUrl, slash, doesYamlFileExist, isTruthy
|
|
|
2
2
|
export { Oas3_1Types } from './types/oas3_1';
|
|
3
3
|
export { Oas3Types } from './types/oas3';
|
|
4
4
|
export { Oas2Types } from './types/oas2';
|
|
5
|
+
export { AsyncApi2Types } from './types/asyncapi';
|
|
5
6
|
export { ConfigTypes } from './types/redocly-yaml';
|
|
6
7
|
export type {
|
|
7
8
|
Oas3Definition,
|
|
@@ -26,6 +27,7 @@ export {
|
|
|
26
27
|
Config,
|
|
27
28
|
StyleguideConfig,
|
|
28
29
|
RawConfig,
|
|
30
|
+
RawUniversalConfig,
|
|
29
31
|
IGNORE_FILE,
|
|
30
32
|
Region,
|
|
31
33
|
getMergedConfig,
|
|
@@ -74,4 +76,4 @@ export {
|
|
|
74
76
|
export { getAstNodeByPointer, getLineColLocation } from './format/codeframes';
|
|
75
77
|
export { formatProblems, OutputFormat, getTotals, Totals } from './format/format';
|
|
76
78
|
export { lint, lint as validate, lintDocument, lintFromString, lintConfig } from './lint';
|
|
77
|
-
export { bundle, bundleDocument, mapTypeToComponent } from './bundle';
|
|
79
|
+
export { bundle, bundleDocument, mapTypeToComponent, bundleFromString } from './bundle';
|
|
@@ -66,7 +66,11 @@ export const runOnValuesSet = new Set<keyof Asserts>([
|
|
|
66
66
|
]);
|
|
67
67
|
|
|
68
68
|
export const asserts: Asserts = {
|
|
69
|
-
pattern: (
|
|
69
|
+
pattern: (
|
|
70
|
+
value: string | string[],
|
|
71
|
+
condition: string,
|
|
72
|
+
{ baseLocation, rawValue }: AssertionFnContext
|
|
73
|
+
) => {
|
|
70
74
|
if (typeof value === 'undefined' || isPlainObject(value)) return []; // property doesn't exist or is an object, no need to lint it with this assert
|
|
71
75
|
const values = Array.isArray(value) ? value : [value];
|
|
72
76
|
const regex = regexFromString(condition);
|
|
@@ -76,7 +80,11 @@ export const asserts: Asserts = {
|
|
|
76
80
|
(_val) =>
|
|
77
81
|
!regex?.test(_val) && {
|
|
78
82
|
message: `"${_val}" should match a regex ${condition}`,
|
|
79
|
-
location: runOnValue(value)
|
|
83
|
+
location: runOnValue(value)
|
|
84
|
+
? baseLocation
|
|
85
|
+
: isPlainObject(rawValue)
|
|
86
|
+
? baseLocation.child(_val).key()
|
|
87
|
+
: baseLocation.key(),
|
|
80
88
|
}
|
|
81
89
|
)
|
|
82
90
|
.filter(isTruthy);
|
|
@@ -84,7 +92,7 @@ export const asserts: Asserts = {
|
|
|
84
92
|
notPattern: (
|
|
85
93
|
value: string | string[],
|
|
86
94
|
condition: string,
|
|
87
|
-
{ baseLocation }: AssertionFnContext
|
|
95
|
+
{ baseLocation, rawValue }: AssertionFnContext
|
|
88
96
|
) => {
|
|
89
97
|
if (typeof value === 'undefined' || isPlainObject(value)) return []; // property doesn't exist or is an object, no need to lint it with this assert
|
|
90
98
|
const values = Array.isArray(value) ? value : [value];
|
|
@@ -95,7 +103,11 @@ export const asserts: Asserts = {
|
|
|
95
103
|
(_val) =>
|
|
96
104
|
regex?.test(_val) && {
|
|
97
105
|
message: `"${_val}" should not match a regex ${condition}`,
|
|
98
|
-
location: runOnValue(value)
|
|
106
|
+
location: runOnValue(value)
|
|
107
|
+
? baseLocation
|
|
108
|
+
: isPlainObject(rawValue)
|
|
109
|
+
? baseLocation.child(_val).key()
|
|
110
|
+
: baseLocation.key(),
|
|
99
111
|
}
|
|
100
112
|
)
|
|
101
113
|
.filter(isTruthy);
|
|
@@ -30,7 +30,7 @@ describe('Oas3 oas3-no-server-example.com', () => {
|
|
|
30
30
|
"source": "foobar.yaml",
|
|
31
31
|
},
|
|
32
32
|
],
|
|
33
|
-
"message": "Server \`url\` should not point
|
|
33
|
+
"message": "Server \`url\` should not point to example.com or localhost.",
|
|
34
34
|
"ruleId": "no-server-example.com",
|
|
35
35
|
"severity": "error",
|
|
36
36
|
"suggest": Array [],
|
|
@@ -57,4 +57,39 @@ describe('Oas3 oas3-no-server-example.com', () => {
|
|
|
57
57
|
|
|
58
58
|
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`Array []`);
|
|
59
59
|
});
|
|
60
|
+
|
|
61
|
+
it('oas3-no-server-example.com: should report on server object with "foo.example.com" url', async () => {
|
|
62
|
+
const document = parseYamlToDocument(
|
|
63
|
+
outdent`
|
|
64
|
+
openapi: 3.0.0
|
|
65
|
+
servers:
|
|
66
|
+
- url: foo.example.com
|
|
67
|
+
`,
|
|
68
|
+
'foobar.yaml'
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
const results = await lintDocument({
|
|
72
|
+
externalRefResolver: new BaseResolver(),
|
|
73
|
+
document,
|
|
74
|
+
config: await makeConfig({ 'no-server-example.com': 'error' }),
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
expect(replaceSourceWithRef(results)).toMatchInlineSnapshot(`
|
|
78
|
+
Array [
|
|
79
|
+
Object {
|
|
80
|
+
"location": Array [
|
|
81
|
+
Object {
|
|
82
|
+
"pointer": "#/servers/0/url",
|
|
83
|
+
"reportOnKey": false,
|
|
84
|
+
"source": "foobar.yaml",
|
|
85
|
+
},
|
|
86
|
+
],
|
|
87
|
+
"message": "Server \`url\` should not point to example.com or localhost.",
|
|
88
|
+
"ruleId": "no-server-example.com",
|
|
89
|
+
"severity": "error",
|
|
90
|
+
"suggest": Array [],
|
|
91
|
+
},
|
|
92
|
+
]
|
|
93
|
+
`);
|
|
94
|
+
});
|
|
60
95
|
});
|
|
@@ -3,9 +3,10 @@ import { Oas3Rule } from '../../visitors';
|
|
|
3
3
|
export const NoServerExample: Oas3Rule = () => {
|
|
4
4
|
return {
|
|
5
5
|
Server(server, { report, location }) {
|
|
6
|
-
|
|
6
|
+
const pattern = /^(.*[\/.])?(example\.com|localhost)([\/:?].*|$)/;
|
|
7
|
+
if (server.url && pattern.test(server.url)) {
|
|
7
8
|
report({
|
|
8
|
-
message: 'Server `url` should not point
|
|
9
|
+
message: 'Server `url` should not point to example.com or localhost.',
|
|
9
10
|
location: location.child(['url']),
|
|
10
11
|
});
|
|
11
12
|
}
|
package/src/types/asyncapi.ts
CHANGED
|
@@ -390,7 +390,13 @@ const Schema: NodeType = {
|
|
|
390
390
|
maxContains: { type: 'integer', minimum: 0 },
|
|
391
391
|
patternProperties: { type: 'object' },
|
|
392
392
|
propertyNames: 'Schema',
|
|
393
|
-
unevaluatedItems:
|
|
393
|
+
unevaluatedItems: (value: unknown) => {
|
|
394
|
+
if (typeof value === 'boolean') {
|
|
395
|
+
return { type: 'boolean' };
|
|
396
|
+
} else {
|
|
397
|
+
return 'Schema';
|
|
398
|
+
}
|
|
399
|
+
},
|
|
394
400
|
unevaluatedProperties: (value: unknown) => {
|
|
395
401
|
if (typeof value === 'boolean') {
|
|
396
402
|
return { type: 'boolean' };
|
package/src/types/oas3_1.ts
CHANGED
|
@@ -137,7 +137,13 @@ const Schema: NodeType = {
|
|
|
137
137
|
maxContains: { type: 'integer', minimum: 0 },
|
|
138
138
|
patternProperties: { type: 'object' },
|
|
139
139
|
propertyNames: 'Schema',
|
|
140
|
-
unevaluatedItems:
|
|
140
|
+
unevaluatedItems: (value: unknown) => {
|
|
141
|
+
if (typeof value === 'boolean') {
|
|
142
|
+
return { type: 'boolean' };
|
|
143
|
+
} else {
|
|
144
|
+
return 'Schema';
|
|
145
|
+
}
|
|
146
|
+
},
|
|
141
147
|
unevaluatedProperties: (value: unknown) => {
|
|
142
148
|
if (typeof value === 'boolean') {
|
|
143
149
|
return { type: 'boolean' };
|