Skip to content

Commit af9c742

Browse files
authored
feat(rulesets): add multiple xor (stoplightio#2614)
1 parent c32b61c commit af9c742

File tree

3 files changed

+32
-21
lines changed

3 files changed

+32
-21
lines changed

packages/functions/src/__tests__/xor.test.ts

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,24 @@ describe('Core Functions / Xor', () => {
2626
]);
2727
});
2828

29+
it('given multiple properties that do not match, should return an error message', async () => {
30+
expect(
31+
await runXor(
32+
{
33+
version: '1.0.0',
34+
title: 'Swagger Petstore',
35+
termsOfService: 'http://swagger.io/terms/',
36+
},
37+
{ properties: ['yada-yada', 'whatever', 'foo'] },
38+
),
39+
).toEqual([
40+
{
41+
message: '"yada-yada", "whatever" and "foo" must not be both defined or both undefined',
42+
path: [],
43+
},
44+
]);
45+
});
46+
2947
it('given both properties, should return an error message', async () => {
3048
expect(
3149
await runXor(
@@ -99,22 +117,12 @@ describe('Core Functions / Xor', () => {
99117
]),
100118
],
101119
],
102-
[
103-
{ properties: ['foo', 'bar', 'baz'] },
104-
[
105-
new RulesetValidationError(
106-
'invalid-function-options',
107-
'"xor" and its "properties" option support 2-item tuples, i.e. ["id", "name"]',
108-
['rules', 'my-rule', 'then', 'functionOptions', 'properties'],
109-
),
110-
],
111-
],
112120
[
113121
{ properties: ['foo', {}] },
114122
[
115123
new RulesetValidationError(
116124
'invalid-function-options',
117-
'"xor" and its "properties" option support 2-item tuples, i.e. ["id", "name"]',
125+
'"xor" and its "properties" option require at least 2-item tuples, i.e. ["id", "name"]',
118126
['rules', 'my-rule', 'then', 'functionOptions', 'properties'],
119127
),
120128
],
@@ -124,7 +132,7 @@ describe('Core Functions / Xor', () => {
124132
[
125133
new RulesetValidationError(
126134
'invalid-function-options',
127-
'"xor" and its "properties" option support 2-item tuples, i.e. ["id", "name"]',
135+
'"xor" and its "properties" option require at least 2-item tuples, i.e. ["id", "name"]',
128136
['rules', 'my-rule', 'then', 'functionOptions', 'properties'],
129137
),
130138
],
@@ -134,7 +142,7 @@ describe('Core Functions / Xor', () => {
134142
[
135143
new RulesetValidationError(
136144
'invalid-function-options',
137-
'"xor" and its "properties" option support 2-item tuples, i.e. ["id", "name"]',
145+
'"xor" and its "properties" option require at least 2-item tuples, i.e. ["id", "name"]',
138146
['rules', 'my-rule', 'then', 'functionOptions', 'properties'],
139147
),
140148
],

packages/functions/src/optionSchemas.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -207,8 +207,7 @@ export const optionSchemas: Record<string, CustomFunctionOptionsSchema> = {
207207
type: 'string',
208208
},
209209
minItems: 2,
210-
maxItems: 2,
211-
errorMessage: `"xor" and its "properties" option support 2-item tuples, i.e. ["id", "name"]`,
210+
errorMessage: `"xor" and its "properties" option require at least 2-item tuples, i.e. ["id", "name"]`,
212211
description: 'The properties to check.',
213212
},
214213
},

packages/functions/src/xor.ts

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,16 +16,20 @@ export default createRulesetFunction<Record<string, unknown>, Options>(
1616
options: optionSchemas.xor,
1717
},
1818
function xor(targetVal, { properties }) {
19-
if (properties.length !== 2) return;
20-
2119
const results: IFunctionResult[] = [];
2220

23-
const intersection = Object.keys(targetVal).filter(value => -1 !== properties.indexOf(value));
21+
const intersection = Object.keys(targetVal).filter(key => properties.includes(key));
22+
2423
if (intersection.length !== 1) {
24+
const formattedProperties = properties.map(prop => printValue(prop));
25+
26+
const lastProperty = formattedProperties.pop();
27+
let message = formattedProperties.join(', ') + (lastProperty != undefined ? ` and ${lastProperty}` : '');
28+
29+
message += ' must not be both defined or both undefined';
30+
2531
results.push({
26-
message: `${printValue(properties[0])} and ${printValue(
27-
properties[1],
28-
)} must not be both defined or both undefined`,
32+
message,
2933
});
3034
}
3135

0 commit comments

Comments
 (0)