@redocly/openapi-core 1.16.0 → 1.17.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 +10 -0
- package/lib/bundle.d.ts +1 -1
- package/lib/config/load.d.ts +12 -3
- package/lib/config/load.js +32 -12
- package/lib/config/utils.d.ts +1 -0
- package/lib/config/utils.js +5 -1
- package/lib/lint.d.ts +1 -0
- package/lib/lint.js +3 -7
- package/lib/oas-types.d.ts +1 -1
- package/lib/types/oas3_1.js +1 -0
- package/lib/types/redocly-yaml.d.ts +3 -1
- package/lib/types/redocly-yaml.js +34 -36
- package/package.json +1 -1
- package/src/__tests__/lint.test.ts +22 -12
- package/src/config/__tests__/load.test.ts +86 -61
- package/src/config/load.ts +49 -23
- package/src/config/utils.ts +4 -0
- package/src/lint.ts +10 -9
- package/src/types/oas3_1.ts +1 -0
- package/src/types/redocly-yaml.ts +32 -33
- package/tsconfig.tsbuildinfo +1 -1
package/src/config/load.ts
CHANGED
|
@@ -4,7 +4,7 @@ import { RedoclyClient } from '../redocly';
|
|
|
4
4
|
import { isEmptyObject } from '../utils';
|
|
5
5
|
import { parseYaml } from '../js-yaml';
|
|
6
6
|
import { Config } from './config';
|
|
7
|
-
import { ConfigValidationError, transformConfig } from './utils';
|
|
7
|
+
import { ConfigValidationError, transformConfig, deepCloneMapWithJSON } from './utils';
|
|
8
8
|
import { resolveConfig, resolveConfigFileAndRefs } from './config-resolvers';
|
|
9
9
|
import { bundleConfig } from '../bundle';
|
|
10
10
|
import { BaseResolver } from '../resolve';
|
|
@@ -80,10 +80,12 @@ async function addConfigMetadata({
|
|
|
80
80
|
});
|
|
81
81
|
}
|
|
82
82
|
|
|
83
|
-
export type RawConfigProcessor = (
|
|
84
|
-
|
|
85
|
-
resolvedRefMap: ResolvedRefMap
|
|
86
|
-
|
|
83
|
+
export type RawConfigProcessor = (params: {
|
|
84
|
+
document: Document;
|
|
85
|
+
resolvedRefMap: ResolvedRefMap;
|
|
86
|
+
config: Config;
|
|
87
|
+
parsed: Document['parsed'];
|
|
88
|
+
}) => void | Promise<void>;
|
|
87
89
|
|
|
88
90
|
export async function loadConfig(
|
|
89
91
|
options: {
|
|
@@ -103,12 +105,16 @@ export async function loadConfig(
|
|
|
103
105
|
region,
|
|
104
106
|
externalRefResolver,
|
|
105
107
|
} = options;
|
|
106
|
-
|
|
108
|
+
|
|
109
|
+
const { rawConfig, document, parsed, resolvedRefMap } = await getConfig({
|
|
110
|
+
configPath,
|
|
111
|
+
externalRefResolver,
|
|
112
|
+
});
|
|
107
113
|
|
|
108
114
|
const redoclyClient = isBrowser ? undefined : new RedoclyClient();
|
|
109
115
|
const tokens = redoclyClient && redoclyClient.hasTokens() ? redoclyClient.getAllTokens() : [];
|
|
110
116
|
|
|
111
|
-
|
|
117
|
+
const config = await addConfigMetadata({
|
|
112
118
|
rawConfig,
|
|
113
119
|
customExtends,
|
|
114
120
|
configPath,
|
|
@@ -117,6 +123,24 @@ export async function loadConfig(
|
|
|
117
123
|
region,
|
|
118
124
|
externalRefResolver,
|
|
119
125
|
});
|
|
126
|
+
|
|
127
|
+
if (document && parsed && resolvedRefMap && typeof processRawConfig === 'function') {
|
|
128
|
+
try {
|
|
129
|
+
await processRawConfig({
|
|
130
|
+
document,
|
|
131
|
+
resolvedRefMap,
|
|
132
|
+
config,
|
|
133
|
+
parsed,
|
|
134
|
+
});
|
|
135
|
+
} catch (e) {
|
|
136
|
+
if (e instanceof ConfigValidationError) {
|
|
137
|
+
throw e;
|
|
138
|
+
}
|
|
139
|
+
throw new Error(`Error parsing config file at '${configPath}': ${e.message}`);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
return config;
|
|
120
144
|
}
|
|
121
145
|
|
|
122
146
|
export const CONFIG_FILE_NAMES = ['redocly.yaml', 'redocly.yml', '.redocly.yaml', '.redocly.yml'];
|
|
@@ -139,31 +163,33 @@ export function findConfig(dir?: string): string | undefined {
|
|
|
139
163
|
export async function getConfig(
|
|
140
164
|
options: {
|
|
141
165
|
configPath?: string;
|
|
142
|
-
processRawConfig?: RawConfigProcessor;
|
|
143
166
|
externalRefResolver?: BaseResolver;
|
|
144
167
|
} = {}
|
|
145
|
-
): Promise<
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
168
|
+
): Promise<{
|
|
169
|
+
rawConfig: RawConfig;
|
|
170
|
+
document?: Document;
|
|
171
|
+
parsed?: Document['parsed'];
|
|
172
|
+
resolvedRefMap?: ResolvedRefMap;
|
|
173
|
+
}> {
|
|
174
|
+
const { configPath = findConfig(), externalRefResolver = new BaseResolver() } = options;
|
|
175
|
+
if (!configPath) return { rawConfig: {} };
|
|
152
176
|
|
|
153
177
|
try {
|
|
154
178
|
const { document, resolvedRefMap } = await resolveConfigFileAndRefs({
|
|
155
179
|
configPath,
|
|
156
180
|
externalRefResolver,
|
|
157
181
|
});
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
return
|
|
182
|
+
|
|
183
|
+
const bundledRefMap = deepCloneMapWithJSON(resolvedRefMap);
|
|
184
|
+
const parsed = await bundleConfig(JSON.parse(JSON.stringify(document)), bundledRefMap);
|
|
185
|
+
|
|
186
|
+
return {
|
|
187
|
+
rawConfig: transformConfig(parsed),
|
|
188
|
+
document,
|
|
189
|
+
parsed,
|
|
190
|
+
resolvedRefMap,
|
|
191
|
+
};
|
|
163
192
|
} catch (e) {
|
|
164
|
-
if (e instanceof ConfigValidationError) {
|
|
165
|
-
throw e;
|
|
166
|
-
}
|
|
167
193
|
throw new Error(`Error parsing config file at '${configPath}': ${e.message}`);
|
|
168
194
|
}
|
|
169
195
|
}
|
package/src/config/utils.ts
CHANGED
|
@@ -364,3 +364,7 @@ export function getUniquePlugins(plugins: Plugin[]): Plugin[] {
|
|
|
364
364
|
}
|
|
365
365
|
|
|
366
366
|
export class ConfigValidationError extends Error {}
|
|
367
|
+
|
|
368
|
+
export function deepCloneMapWithJSON<K, V>(originalMap: Map<K, V>): Map<K, V> {
|
|
369
|
+
return new Map(JSON.parse(JSON.stringify([...originalMap])));
|
|
370
|
+
}
|
package/src/lint.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { BaseResolver, resolveDocument, makeDocumentFromString } from './resolve';
|
|
2
2
|
import { normalizeVisitors } from './visitors';
|
|
3
3
|
import { walkDocument } from './walk';
|
|
4
|
-
import { StyleguideConfig, Config, initRules
|
|
4
|
+
import { StyleguideConfig, Config, initRules } from './config';
|
|
5
5
|
import { normalizeTypes } from './types';
|
|
6
6
|
import { releaseAjvInstance } from './rules/ajv';
|
|
7
7
|
import { SpecVersion, getMajorSpecVersion, detectSpec, getTypes } from './oas-types';
|
|
8
|
-
import {
|
|
8
|
+
import { createConfigTypes } from './types/redocly-yaml';
|
|
9
9
|
import { Spec } from './rules/common/spec';
|
|
10
10
|
import { NoUnresolvedRefs } from './rules/no-unresolved-refs';
|
|
11
11
|
|
|
@@ -13,6 +13,7 @@ import type { Document, ResolvedRefMap } from './resolve';
|
|
|
13
13
|
import type { ProblemSeverity, WalkContext } from './walk';
|
|
14
14
|
import type { NodeType } from './types';
|
|
15
15
|
import type { NestedVisitObject, Oas3Visitor, RuleInstanceConfig } from './visitors';
|
|
16
|
+
import { rootRedoclyConfigSchema } from '@redocly/config';
|
|
16
17
|
|
|
17
18
|
export async function lint(opts: {
|
|
18
19
|
ref: string;
|
|
@@ -109,25 +110,25 @@ export async function lintDocument(opts: {
|
|
|
109
110
|
|
|
110
111
|
export async function lintConfig(opts: {
|
|
111
112
|
document: Document;
|
|
113
|
+
config: Config;
|
|
112
114
|
resolvedRefMap?: ResolvedRefMap;
|
|
113
115
|
severity?: ProblemSeverity;
|
|
114
116
|
externalRefResolver?: BaseResolver;
|
|
115
117
|
externalConfigTypes?: Record<string, NodeType>;
|
|
116
118
|
}) {
|
|
117
|
-
const { document, severity, externalRefResolver = new BaseResolver() } = opts;
|
|
119
|
+
const { document, severity, externalRefResolver = new BaseResolver(), config } = opts;
|
|
118
120
|
|
|
119
121
|
const ctx: WalkContext = {
|
|
120
122
|
problems: [],
|
|
121
123
|
oasVersion: SpecVersion.OAS3_0,
|
|
122
124
|
visitorsData: {},
|
|
123
125
|
};
|
|
124
|
-
const plugins = resolvePlugins([defaultPlugin]);
|
|
125
|
-
const config = new StyleguideConfig({
|
|
126
|
-
plugins,
|
|
127
|
-
rules: { spec: 'error' },
|
|
128
|
-
});
|
|
129
126
|
|
|
130
|
-
const types = normalizeTypes(
|
|
127
|
+
const types = normalizeTypes(
|
|
128
|
+
opts.externalConfigTypes || createConfigTypes(rootRedoclyConfigSchema, config),
|
|
129
|
+
{ doNotResolveExamples: config.styleguide.doNotResolveExamples }
|
|
130
|
+
);
|
|
131
|
+
|
|
131
132
|
const rules: (RuleInstanceConfig & {
|
|
132
133
|
visitor: NestedVisitObject<unknown, Oas3Visitor | Oas3Visitor[]>;
|
|
133
134
|
})[] = [
|
package/src/types/oas3_1.ts
CHANGED
|
@@ -170,6 +170,7 @@ const Schema: NodeType = {
|
|
|
170
170
|
format: { type: 'string' },
|
|
171
171
|
contentEncoding: { type: 'string' },
|
|
172
172
|
contentMediaType: { type: 'string' },
|
|
173
|
+
contentSchema: 'Schema',
|
|
173
174
|
default: null,
|
|
174
175
|
readOnly: { type: 'boolean' },
|
|
175
176
|
writeOnly: { type: 'boolean' },
|
|
@@ -5,6 +5,8 @@ import { getNodeTypesFromJSONSchema } from './json-schema-adapter';
|
|
|
5
5
|
|
|
6
6
|
import type { NodeType } from '.';
|
|
7
7
|
import type { JSONSchema } from 'json-schema-to-ts';
|
|
8
|
+
import { SpecVersion, getTypes } from '../oas-types';
|
|
9
|
+
import { Config } from '../config';
|
|
8
10
|
|
|
9
11
|
const builtInCommonRules = [
|
|
10
12
|
'spec',
|
|
@@ -222,8 +224,6 @@ const oas3_1NodeTypesList = [
|
|
|
222
224
|
|
|
223
225
|
export type Oas3_1NodeType = typeof oas3_1NodeTypesList[number];
|
|
224
226
|
|
|
225
|
-
const asyncNodeTypesList = ['Message'] as const;
|
|
226
|
-
|
|
227
227
|
const ConfigStyleguide: NodeType = {
|
|
228
228
|
properties: {
|
|
229
229
|
extends: {
|
|
@@ -350,35 +350,28 @@ const Schema: NodeType = {
|
|
|
350
350
|
additionalProperties: {},
|
|
351
351
|
};
|
|
352
352
|
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
...new Set([
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
return null;
|
|
372
|
-
} else {
|
|
373
|
-
return { type: 'string' };
|
|
374
|
-
}
|
|
353
|
+
function createAssertionDefinitionSubject(nodeNames: string[]): NodeType {
|
|
354
|
+
return {
|
|
355
|
+
properties: {
|
|
356
|
+
type: {
|
|
357
|
+
enum: [...new Set(['any', ...nodeNames, 'SpecExtension'])],
|
|
358
|
+
},
|
|
359
|
+
property: (value: unknown) => {
|
|
360
|
+
if (Array.isArray(value)) {
|
|
361
|
+
return { type: 'array', items: { type: 'string' } };
|
|
362
|
+
} else if (value === null) {
|
|
363
|
+
return null;
|
|
364
|
+
} else {
|
|
365
|
+
return { type: 'string' };
|
|
366
|
+
}
|
|
367
|
+
},
|
|
368
|
+
filterInParentKeys: { type: 'array', items: { type: 'string' } },
|
|
369
|
+
filterOutParentKeys: { type: 'array', items: { type: 'string' } },
|
|
370
|
+
matchParentKeys: { type: 'string' },
|
|
375
371
|
},
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
},
|
|
380
|
-
required: ['type'],
|
|
381
|
-
};
|
|
372
|
+
required: ['type'],
|
|
373
|
+
};
|
|
374
|
+
}
|
|
382
375
|
|
|
383
376
|
const AssertionDefinitionAssertions: NodeType = {
|
|
384
377
|
properties: {
|
|
@@ -1057,7 +1050,13 @@ const ConfigMockServer: NodeType = {
|
|
|
1057
1050
|
},
|
|
1058
1051
|
};
|
|
1059
1052
|
|
|
1060
|
-
export
|
|
1053
|
+
export function createConfigTypes(extraSchemas: JSONSchema, config?: Config) {
|
|
1054
|
+
const nodeNames = Object.values(SpecVersion).flatMap((version) => {
|
|
1055
|
+
const types = config?.styleguide
|
|
1056
|
+
? config.styleguide.extendTypes(getTypes(version), version)
|
|
1057
|
+
: getTypes(version);
|
|
1058
|
+
return Object.keys(types);
|
|
1059
|
+
});
|
|
1061
1060
|
// Create types based on external schemas
|
|
1062
1061
|
const nodeTypes = getNodeTypesFromJSONSchema('rootRedoclyConfigSchema', extraSchemas);
|
|
1063
1062
|
|
|
@@ -1065,9 +1064,10 @@ export const createConfigTypes = (extraSchemas: JSONSchema) => {
|
|
|
1065
1064
|
...CoreConfigTypes,
|
|
1066
1065
|
ConfigRoot: createConfigRoot(nodeTypes), // This is the REAL config root type
|
|
1067
1066
|
ConfigApisProperties: createConfigApisProperties(nodeTypes),
|
|
1067
|
+
AssertionDefinitionSubject: createAssertionDefinitionSubject(nodeNames),
|
|
1068
1068
|
...nodeTypes,
|
|
1069
1069
|
};
|
|
1070
|
-
}
|
|
1070
|
+
}
|
|
1071
1071
|
|
|
1072
1072
|
const CoreConfigTypes: Record<string, NodeType> = {
|
|
1073
1073
|
Assert,
|
|
@@ -1130,7 +1130,6 @@ const CoreConfigTypes: Record<string, NodeType> = {
|
|
|
1130
1130
|
Heading,
|
|
1131
1131
|
Typography,
|
|
1132
1132
|
AssertionDefinitionAssertions,
|
|
1133
|
-
AssertionDefinitionSubject,
|
|
1134
1133
|
};
|
|
1135
1134
|
|
|
1136
1135
|
export const ConfigTypes: Record<string, NodeType> = createConfigTypes(rootRedoclyConfigSchema);
|