Skip to content

Commit c00f087

Browse files
RomanHotsiyJLekawa
andauthored
fix: fix resolved config had extra transformations (#2209)
* fix: fix resolved config had extra transformations * chore: add changeset * Update .changeset/modern-fishes-float.md --------- Co-authored-by: Jacek Łękawa <[email protected]>
1 parent 5f98a93 commit c00f087

File tree

7 files changed

+80
-82
lines changed

7 files changed

+80
-82
lines changed

.changeset/modern-fishes-float.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@redocly/openapi-core": patch
3+
---
4+
5+
Fixed and issue where the config resolver grouped assertions instead of returning unchanged rules.

packages/core/src/config/__tests__/__snapshots__/config-resolvers.test.ts.snap

Lines changed: 22 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -536,38 +536,34 @@ exports[`resolveConfig > should resolve extends with local file config which con
536536
},
537537
"preprocessors": {},
538538
"rules": {
539-
"assertions": [
540-
{
541-
"assertionId": "rule/path-item-get-defined",
542-
"assertions": {
543-
"defined": true,
544-
},
545-
"message": "Every path item must have a GET operation.",
546-
"subject": {
547-
"property": "get",
548-
"type": "PathItem",
549-
},
550-
},
551-
{
552-
"assertionId": "rule/tag-description",
553-
"assertions": {
554-
"minLength": 13,
555-
"pattern": "/\\.$/",
556-
},
557-
"message": "Tag description must be at least 13 characters and end with a full stop.",
558-
"severity": "error",
559-
"subject": {
560-
"property": "description",
561-
"type": "Tag",
562-
},
563-
},
564-
],
565539
"boolean-parameter-prefixes": "error",
566540
"local/operation-id-not-test": "error",
567541
"no-invalid-media-type-examples": "warn",
568542
"no-unresolved-refs": "error",
569543
"operation-2xx-response": "error",
570544
"operation-4xx-response": "off",
545+
"rule/path-item-get-defined": {
546+
"assertions": {
547+
"defined": true,
548+
},
549+
"message": "Every path item must have a GET operation.",
550+
"subject": {
551+
"property": "get",
552+
"type": "PathItem",
553+
},
554+
},
555+
"rule/tag-description": {
556+
"assertions": {
557+
"minLength": 13,
558+
"pattern": "/\\.$/",
559+
},
560+
"message": "Tag description must be at least 13 characters and end with a full stop.",
561+
"severity": "error",
562+
"subject": {
563+
"property": "description",
564+
"type": "Tag",
565+
},
566+
},
571567
"struct": "error",
572568
},
573569
}

packages/core/src/config/__tests__/__snapshots__/load.test.ts.snap

Lines changed: 19 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -62,21 +62,18 @@ Config {
6262
"preprocessors": {},
6363
"root": "resources/pets.yaml",
6464
"rules": {
65-
"assertions": [
66-
{
67-
"assertionId": "rule/test",
68-
"assertions": {
69-
"defined": true,
70-
},
71-
"severity": "warn",
72-
"subject": {
73-
"property": "x-test",
74-
"type": "Operation",
75-
},
76-
},
77-
],
7865
"no-empty-servers": "error",
7966
"operation-summary": "warn",
67+
"rule/test": {
68+
"assertions": {
69+
"defined": true,
70+
},
71+
"severity": "warn",
72+
"subject": {
73+
"property": "x-test",
74+
"type": "Operation",
75+
},
76+
},
8077
},
8178
},
8279
},
@@ -87,20 +84,17 @@ Config {
8784
},
8885
},
8986
"rules": {
90-
"assertions": [
91-
{
92-
"assertionId": "rule/test",
93-
"assertions": {
94-
"defined": true,
95-
},
96-
"subject": {
97-
"property": "x-test",
98-
"type": "Operation",
99-
},
100-
},
101-
],
10287
"no-empty-servers": "error",
10388
"operation-summary": "error",
89+
"rule/test": {
90+
"assertions": {
91+
"defined": true,
92+
},
93+
"subject": {
94+
"property": "x-test",
95+
"type": "Operation",
96+
},
97+
},
10498
},
10599
"telemetry": "on",
106100
},

packages/core/src/config/__tests__/config-resolvers.test.ts

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ import path from 'node:path';
88

99
import type { RawUniversalConfig, RawGovernanceConfig } from '../types.js';
1010
import { Source } from '../../resolve.js';
11+
import { Config } from '../config.js';
12+
import { SpecVersion } from '../../oas-types.js';
1113

1214
const __dirname = path.dirname(fileURLToPath(import.meta.url));
1315

@@ -259,11 +261,14 @@ describe('resolveConfig', () => {
259261
const rootOrApiRawConfig = {
260262
extends: ['local-config-with-custom-function.yaml'],
261263
};
262-
const { plugins } = await resolveConfig({
264+
const { plugins, resolvedConfig } = await resolveConfig({
263265
rawConfigDocument: makeDocument(rootOrApiRawConfig, configPath),
264266
configPath,
265267
});
266268

269+
// instantiate the config to register custom assertions
270+
new Config(resolvedConfig, { plugins });
271+
267272
expect(plugins).toBeDefined();
268273
expect(plugins?.length).toBe(2);
269274
expect(asserts['test-plugin/checkWordsCount' as keyof Asserts]).toBeDefined();
@@ -274,33 +279,34 @@ describe('resolveConfig', () => {
274279
extends: ['local-config-with-wrong-custom-function.yaml'],
275280
};
276281
try {
277-
await resolveConfig({
282+
const config = await resolveConfig({
278283
rawConfigDocument: makeDocument(rootOrApiRawConfig, configPath),
279284
configPath,
280285
});
286+
new Config(config.resolvedConfig, { plugins: config.plugins });
281287
} catch (e) {
282288
expect(e.message.toString()).toContain(
283289
`Plugin ${colorize.red(
284290
'test-plugin'
285291
)} doesn't export assertions function with name ${colorize.red('checkWordsCount2')}.`
286292
);
287293
}
288-
289-
expect(asserts['test-plugin/checkWordsCount' as keyof Asserts]).toBeDefined();
290294
});
291295

292296
it('should correctly merge assertions from nested config', async () => {
293297
const rootOrApiRawConfig = {
294298
extends: ['local-config-with-file.yaml'],
295299
};
296300

297-
const { resolvedConfig, plugins } = await resolveConfig({
301+
const { resolvedConfig } = await resolveConfig({
298302
rawConfigDocument: makeDocument(rootOrApiRawConfig, configPath),
299303
configPath,
300304
});
301305

302-
expect(Array.isArray(resolvedConfig.rules?.assertions)).toEqual(true);
303-
expect(resolvedConfig.rules?.assertions).toMatchObject([
306+
const config = new Config(resolvedConfig, { plugins: [] });
307+
308+
expect(Array.isArray(config.rules[SpecVersion.OAS3_1].assertions)).toEqual(true);
309+
expect(config.rules[SpecVersion.OAS3_1].assertions).toMatchObject([
304310
{
305311
subject: { type: 'PathItem', property: 'get' },
306312
message: 'Every path item must have a GET operation.',

packages/core/src/config/__tests__/fixtures/resolve-config/local-config-with-wrong-custom-function.yaml

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,14 @@ rules:
22
no-invalid-media-type-examples: warn
33
operation-4xx-response: off
44
rule/tag-description:
5-
subject: Tag
6-
property: description
5+
subject:
6+
type: Tag
7+
property: description
78
message: Tag description must have at least 3 words.
89
severity: error
9-
test-plugin/checkWordsCount2:
10-
min: 3
10+
assertions:
11+
test-plugin/checkWordsCount2:
12+
min: 3
1113
plugins:
1214
- plugin.js
1315
extends:

packages/core/src/config/config-resolvers.ts

Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -101,23 +101,13 @@ export async function resolveConfig({
101101
bundledConfig.apis = Object.fromEntries(
102102
Object.entries(bundledConfig.apis).map(([key, apiConfig]) => {
103103
const mergedConfig = mergeExtends([bundledConfig, apiConfig]);
104-
return [
105-
key,
106-
{
107-
...apiConfig,
108-
...mergedConfig,
109-
rules: groupAssertionRules(mergedConfig, resolvedPlugins),
110-
},
111-
];
104+
return [key, { ...apiConfig, ...mergedConfig }];
112105
})
113106
);
114107
}
115108

116109
return {
117-
resolvedConfig: {
118-
...bundledConfig,
119-
rules: groupAssertionRules(bundledConfig, resolvedPlugins),
120-
},
110+
resolvedConfig: bundledConfig,
121111
resolvedRefMap,
122112
plugins: resolvedPlugins,
123113
};
@@ -448,7 +438,7 @@ export function resolvePreset(presetName: string, plugins: Plugin[]): RawGoverna
448438
return preset;
449439
}
450440

451-
function groupAssertionRules(
441+
export function groupAssertionRules(
452442
config: RawGovernanceConfig,
453443
plugins: Plugin[]
454444
): Record<string, RuleConfig> {

packages/core/src/config/config.ts

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { isBrowser } from '../env.js';
77
import { getResolveConfig } from './utils.js';
88
import { isAbsoluteUrl } from '../ref-utils.js';
99
import { type Document, type ResolvedRefMap } from '../resolve.js';
10+
import { groupAssertionRules } from './config-resolvers.js';
1011

1112
import type { NormalizedProblem } from '../walk.js';
1213
import type {
@@ -81,14 +82,18 @@ export class Config {
8182
this.plugins = opts.plugins || [];
8283
this.doNotResolveExamples = !!resolvedConfig.resolve?.doNotResolveExamples;
8384

85+
const group = (rules: Record<string, RuleConfig>) => {
86+
return groupAssertionRules({ rules }, this.plugins);
87+
};
88+
8489
this.rules = {
85-
[SpecVersion.OAS2]: { ...resolvedConfig.rules, ...resolvedConfig.oas2Rules },
86-
[SpecVersion.OAS3_0]: { ...resolvedConfig.rules, ...resolvedConfig.oas3_0Rules },
87-
[SpecVersion.OAS3_1]: { ...resolvedConfig.rules, ...resolvedConfig.oas3_1Rules },
88-
[SpecVersion.Async2]: { ...resolvedConfig.rules, ...resolvedConfig.async2Rules },
89-
[SpecVersion.Async3]: { ...resolvedConfig.rules, ...resolvedConfig.async3Rules },
90-
[SpecVersion.Arazzo1]: { ...resolvedConfig.rules, ...resolvedConfig.arazzo1Rules },
91-
[SpecVersion.Overlay1]: { ...resolvedConfig.rules, ...resolvedConfig.overlay1Rules },
90+
[SpecVersion.OAS2]: group({ ...resolvedConfig.rules, ...resolvedConfig.oas2Rules }),
91+
[SpecVersion.OAS3_0]: group({ ...resolvedConfig.rules, ...resolvedConfig.oas3_0Rules }),
92+
[SpecVersion.OAS3_1]: group({ ...resolvedConfig.rules, ...resolvedConfig.oas3_1Rules }),
93+
[SpecVersion.Async2]: group({ ...resolvedConfig.rules, ...resolvedConfig.async2Rules }),
94+
[SpecVersion.Async3]: group({ ...resolvedConfig.rules, ...resolvedConfig.async3Rules }),
95+
[SpecVersion.Arazzo1]: group({ ...resolvedConfig.rules, ...resolvedConfig.arazzo1Rules }),
96+
[SpecVersion.Overlay1]: group({ ...resolvedConfig.rules, ...resolvedConfig.overlay1Rules }),
9297
};
9398

9499
this.preprocessors = {

0 commit comments

Comments
 (0)