@featurevisor/core 1.5.1 → 1.6.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/.eslintcache +1 -1
- package/CHANGELOG.md +11 -0
- package/coverage/clover.xml +2 -2
- package/coverage/lcov-report/index.html +1 -1
- package/coverage/lcov-report/lib/builder/allocator.js.html +1 -1
- package/coverage/lcov-report/lib/builder/index.html +1 -1
- package/coverage/lcov-report/lib/builder/traffic.js.html +1 -1
- package/coverage/lcov-report/lib/tester/checkIfObjectsAreEqual.js.html +1 -1
- package/coverage/lcov-report/lib/tester/index.html +1 -1
- package/coverage/lcov-report/lib/tester/matrix.js.html +1 -1
- package/coverage/lcov-report/src/builder/allocator.ts.html +1 -1
- package/coverage/lcov-report/src/builder/index.html +1 -1
- package/coverage/lcov-report/src/builder/traffic.ts.html +1 -1
- package/coverage/lcov-report/src/tester/checkIfObjectsAreEqual.ts.html +1 -1
- package/coverage/lcov-report/src/tester/index.html +1 -1
- package/coverage/lcov-report/src/tester/matrix.ts.html +1 -1
- package/lib/linter/attributeSchema.d.ts +17 -2
- package/lib/linter/attributeSchema.js +13 -11
- package/lib/linter/attributeSchema.js.map +1 -1
- package/lib/linter/checkPercentageExceedingSlot.d.ts +3 -0
- package/lib/linter/checkPercentageExceedingSlot.js +86 -0
- package/lib/linter/checkPercentageExceedingSlot.js.map +1 -0
- package/lib/linter/conditionSchema.d.ts +2 -2
- package/lib/linter/conditionSchema.js +112 -57
- package/lib/linter/conditionSchema.js.map +1 -1
- package/lib/linter/featureSchema.d.ts +229 -2
- package/lib/linter/featureSchema.js +195 -139
- package/lib/linter/featureSchema.js.map +1 -1
- package/lib/linter/groupSchema.d.ts +32 -2
- package/lib/linter/groupSchema.js +28 -97
- package/lib/linter/groupSchema.js.map +1 -1
- package/lib/linter/lintProject.js +169 -118
- package/lib/linter/lintProject.js.map +1 -1
- package/lib/linter/printError.d.ts +2 -0
- package/lib/linter/printError.js +20 -0
- package/lib/linter/printError.js.map +1 -0
- package/lib/linter/segmentSchema.d.ts +14 -2
- package/lib/linter/segmentSchema.js +12 -10
- package/lib/linter/segmentSchema.js.map +1 -1
- package/lib/linter/testSchema.d.ts +90 -2
- package/lib/linter/testSchema.js +49 -38
- package/lib/linter/testSchema.js.map +1 -1
- package/lib/tester/cliFormat.d.ts +1 -0
- package/lib/tester/cliFormat.js +2 -1
- package/lib/tester/cliFormat.js.map +1 -1
- package/package.json +4 -4
- package/src/linter/attributeSchema.ts +11 -9
- package/src/linter/checkPercentageExceedingSlot.ts +41 -0
- package/src/linter/conditionSchema.ts +120 -97
- package/src/linter/featureSchema.ts +241 -177
- package/src/linter/groupSchema.ts +38 -54
- package/src/linter/lintProject.ts +144 -62
- package/src/linter/printError.ts +21 -0
- package/src/linter/segmentSchema.ts +10 -8
- package/src/linter/testSchema.ts +67 -50
- package/src/tester/cliFormat.ts +1 -0
- package/lib/linter/printJoiError.d.ts +0 -2
- package/lib/linter/printJoiError.js +0 -14
- package/lib/linter/printJoiError.js.map +0 -1
- package/src/linter/printJoiError.ts +0 -11
package/lib/linter/testSchema.js
CHANGED
|
@@ -1,48 +1,59 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
4
|
-
var
|
|
5
|
-
function
|
|
6
|
-
var
|
|
7
|
-
|
|
8
|
-
segment: (
|
|
9
|
-
.
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
3
|
+
exports.getTestsZodSchema = void 0;
|
|
4
|
+
var zod_1 = require("zod");
|
|
5
|
+
function getTestsZodSchema(projectConfig, availableFeatureKeys, availableSegmentKeys) {
|
|
6
|
+
var segmentTestZodSchema = zod_1.z
|
|
7
|
+
.object({
|
|
8
|
+
segment: zod_1.z.string().refine(function (value) { return availableSegmentKeys.includes(value); }, function (value) { return ({
|
|
9
|
+
message: "Unknown segment \"".concat(value, "\""),
|
|
10
|
+
}); }),
|
|
11
|
+
assertions: zod_1.z.array(zod_1.z
|
|
12
|
+
.object({
|
|
13
|
+
matrix: zod_1.z.record(zod_1.z.unknown()).optional(),
|
|
14
|
+
description: zod_1.z.string().optional(),
|
|
15
|
+
context: zod_1.z.record(zod_1.z.unknown()),
|
|
16
|
+
expectedToMatch: zod_1.z.boolean(),
|
|
17
|
+
})
|
|
18
|
+
.strict()),
|
|
19
|
+
})
|
|
20
|
+
.strict();
|
|
21
|
+
var featureTestZodSchema = zod_1.z
|
|
22
|
+
.object({
|
|
23
|
+
feature: zod_1.z.string().refine(function (value) { return availableFeatureKeys.includes(value); }, function (value) { return ({
|
|
24
|
+
message: "Unknown feature \"".concat(value, "\""),
|
|
25
|
+
}); }),
|
|
26
|
+
assertions: zod_1.z.array(zod_1.z
|
|
27
|
+
.object({
|
|
28
|
+
matrix: zod_1.z.record(zod_1.z.unknown()).optional(),
|
|
29
|
+
description: zod_1.z.string().optional(),
|
|
30
|
+
at: zod_1.z.union([
|
|
31
|
+
zod_1.z.number().min(0).max(100),
|
|
32
|
+
// because of supporting matrix
|
|
33
|
+
zod_1.z.string(),
|
|
34
|
+
]),
|
|
35
|
+
environment: zod_1.z.string().refine(function (value) {
|
|
28
36
|
if (value.indexOf("${{") === 0) {
|
|
29
37
|
// allow unknown strings for matrix
|
|
30
|
-
return
|
|
38
|
+
return true;
|
|
31
39
|
}
|
|
32
40
|
// otherwise only known environments should be passed
|
|
33
41
|
if (projectConfig.environments.includes(value)) {
|
|
34
|
-
return
|
|
42
|
+
return true;
|
|
35
43
|
}
|
|
36
|
-
return
|
|
37
|
-
})
|
|
38
|
-
.
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
44
|
+
return false;
|
|
45
|
+
}, function (value) { return ({
|
|
46
|
+
message: "Unknown environment \"".concat(value, "\""),
|
|
47
|
+
}); }),
|
|
48
|
+
context: zod_1.z.record(zod_1.z.unknown()),
|
|
49
|
+
expectedToBeEnabled: zod_1.z.boolean(),
|
|
50
|
+
expectedVariation: zod_1.z.string().optional(),
|
|
51
|
+
expectedVariables: zod_1.z.record(zod_1.z.unknown()).optional(),
|
|
52
|
+
})
|
|
53
|
+
.strict()),
|
|
54
|
+
})
|
|
55
|
+
.strict();
|
|
56
|
+
return zod_1.z.union([segmentTestZodSchema, featureTestZodSchema]);
|
|
46
57
|
}
|
|
47
|
-
exports.
|
|
58
|
+
exports.getTestsZodSchema = getTestsZodSchema;
|
|
48
59
|
//# sourceMappingURL=testSchema.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"testSchema.js","sourceRoot":"","sources":["../../src/linter/testSchema.ts"],"names":[],"mappings":";;;AAAA,
|
|
1
|
+
{"version":3,"file":"testSchema.js","sourceRoot":"","sources":["../../src/linter/testSchema.ts"],"names":[],"mappings":"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"}
|
package/lib/tester/cliFormat.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.CLI_FORMAT_BOLD = exports.CLI_FORMAT_GREEN = exports.CLI_FORMAT_RED = void 0;
|
|
3
|
+
exports.CLI_FORMAT_UNDERLINE = exports.CLI_FORMAT_BOLD = exports.CLI_FORMAT_GREEN = exports.CLI_FORMAT_RED = void 0;
|
|
4
4
|
exports.CLI_FORMAT_RED = "\x1b[31m%s\x1b[0m";
|
|
5
5
|
exports.CLI_FORMAT_GREEN = "\x1b[32m%s\x1b[0m";
|
|
6
6
|
exports.CLI_FORMAT_BOLD = "\x1b[1m%s\x1b[0m";
|
|
7
|
+
exports.CLI_FORMAT_UNDERLINE = "\x1b[4m%s\x1b[0m";
|
|
7
8
|
//# sourceMappingURL=cliFormat.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cliFormat.js","sourceRoot":"","sources":["../../src/tester/cliFormat.ts"],"names":[],"mappings":";;;AAAa,QAAA,cAAc,GAAG,mBAAmB,CAAC;AACrC,QAAA,gBAAgB,GAAG,mBAAmB,CAAC;AAEvC,QAAA,eAAe,GAAG,kBAAkB,CAAC"}
|
|
1
|
+
{"version":3,"file":"cliFormat.js","sourceRoot":"","sources":["../../src/tester/cliFormat.ts"],"names":[],"mappings":";;;AAAa,QAAA,cAAc,GAAG,mBAAmB,CAAC;AACrC,QAAA,gBAAgB,GAAG,mBAAmB,CAAC;AAEvC,QAAA,eAAe,GAAG,kBAAkB,CAAC;AACrC,QAAA,oBAAoB,GAAG,kBAAkB,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@featurevisor/core",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.6.0",
|
|
4
4
|
"description": "Core package of Featurevisor for Node.js usage",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"types": "lib/index.d.ts",
|
|
@@ -48,14 +48,14 @@
|
|
|
48
48
|
"@featurevisor/site": "^1.5.1",
|
|
49
49
|
"@featurevisor/types": "^1.3.0",
|
|
50
50
|
"axios": "^1.3.4",
|
|
51
|
-
"joi": "^17.8.3",
|
|
52
51
|
"js-yaml": "^4.1.0",
|
|
53
52
|
"mkdirp": "^2.1.3",
|
|
54
|
-
"tar": "^6.1.13"
|
|
53
|
+
"tar": "^6.1.13",
|
|
54
|
+
"zod": "^3.22.4"
|
|
55
55
|
},
|
|
56
56
|
"devDependencies": {
|
|
57
57
|
"@types/js-yaml": "^4.0.5",
|
|
58
58
|
"@types/tar": "^6.1.4"
|
|
59
59
|
},
|
|
60
|
-
"gitHead": "
|
|
60
|
+
"gitHead": "9d9a317843b028cc68ec0ff4ce060fe1404368d8"
|
|
61
61
|
}
|
|
@@ -1,12 +1,14 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { z } from "zod";
|
|
2
2
|
|
|
3
|
-
export function
|
|
4
|
-
const
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
3
|
+
export function getAttributeZodSchema() {
|
|
4
|
+
const attributeZodSchema = z
|
|
5
|
+
.object({
|
|
6
|
+
archived: z.boolean().optional(),
|
|
7
|
+
type: z.enum(["boolean", "string", "integer", "double", "date", "semver"]),
|
|
8
|
+
description: z.string(),
|
|
9
|
+
capture: z.boolean().optional(),
|
|
10
|
+
})
|
|
11
|
+
.strict();
|
|
10
12
|
|
|
11
|
-
return
|
|
13
|
+
return attributeZodSchema;
|
|
12
14
|
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { Group } from "@featurevisor/types";
|
|
2
|
+
|
|
3
|
+
import { Datasource } from "../datasource";
|
|
4
|
+
|
|
5
|
+
// @TODO: ideally in future, this check should be done from Feature level,
|
|
6
|
+
// as well as Group level as done here
|
|
7
|
+
export async function checkForFeatureExceedingGroupSlotPercentage(
|
|
8
|
+
datasource: Datasource,
|
|
9
|
+
group: Group,
|
|
10
|
+
availableFeatureKeys: string[],
|
|
11
|
+
) {
|
|
12
|
+
for (const slot of group.slots) {
|
|
13
|
+
const maxPercentageForRule = slot.percentage;
|
|
14
|
+
|
|
15
|
+
if (slot.feature) {
|
|
16
|
+
const featureKey = slot.feature;
|
|
17
|
+
const featureExists = availableFeatureKeys.indexOf(featureKey) > -1;
|
|
18
|
+
|
|
19
|
+
if (!featureExists) {
|
|
20
|
+
throw new Error(`Unknown feature "${featureKey}"`);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const parsedFeature = await datasource.readFeature(featureKey);
|
|
24
|
+
|
|
25
|
+
const environmentKeys = Object.keys(parsedFeature.environments);
|
|
26
|
+
for (const environmentKey of environmentKeys) {
|
|
27
|
+
const environment = parsedFeature.environments[environmentKey];
|
|
28
|
+
const rules = environment.rules;
|
|
29
|
+
|
|
30
|
+
for (const rule of rules) {
|
|
31
|
+
if (rule.percentage > maxPercentageForRule) {
|
|
32
|
+
// @TODO: this does not help with same feature belonging to multiple slots. fix that.
|
|
33
|
+
throw new Error(
|
|
34
|
+
`Feature ${featureKey}'s rule ${rule.key} in ${environmentKey} has a percentage of ${rule.percentage} which is greater than the maximum percentage of ${maxPercentageForRule} for the slot`,
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -1,114 +1,137 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { z } from "zod";
|
|
2
2
|
|
|
3
3
|
import { ProjectConfig } from "../config";
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
const commonOperators: [string, ...string[]] = ["equals", "notEquals"];
|
|
6
|
+
const numericOperators = ["greaterThan", "greaterThanOrEquals", "lessThan", "lessThanOrEquals"];
|
|
7
|
+
const stringOperators = ["contains", "notContains", "startsWith", "endsWith"];
|
|
8
|
+
const semverOperators = [
|
|
9
|
+
"semverEquals",
|
|
10
|
+
"semverNotEquals",
|
|
11
|
+
"semverGreaterThan",
|
|
12
|
+
"semverGreaterThanOrEquals",
|
|
13
|
+
"semverLessThan",
|
|
14
|
+
"semverLessThanOrEquals",
|
|
15
|
+
];
|
|
16
|
+
const dateOperators = ["before", "after"];
|
|
17
|
+
const arrayOperators = ["in", "notIn"];
|
|
18
|
+
|
|
19
|
+
export function getConditionsZodSchema(
|
|
6
20
|
projectConfig: ProjectConfig,
|
|
7
|
-
availableAttributeKeys: string[],
|
|
21
|
+
availableAttributeKeys: [string, ...string[]],
|
|
8
22
|
) {
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
.
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
23
|
+
const plainConditionZodSchema = z
|
|
24
|
+
.object({
|
|
25
|
+
attribute: z.string().refine(
|
|
26
|
+
(value) => availableAttributeKeys.includes(value),
|
|
27
|
+
(value) => ({
|
|
28
|
+
message: `Unknown attribute "${value}"`,
|
|
29
|
+
}),
|
|
30
|
+
),
|
|
31
|
+
operator: z.enum([
|
|
32
|
+
...commonOperators,
|
|
33
|
+
...numericOperators,
|
|
34
|
+
...stringOperators,
|
|
35
|
+
...semverOperators,
|
|
36
|
+
...dateOperators,
|
|
37
|
+
...arrayOperators,
|
|
38
|
+
]),
|
|
39
|
+
value: z.union([
|
|
40
|
+
z.string(),
|
|
41
|
+
z.array(z.string()),
|
|
42
|
+
z.number(),
|
|
43
|
+
z.boolean(),
|
|
44
|
+
z.date(),
|
|
45
|
+
z.null(),
|
|
46
|
+
]),
|
|
47
|
+
})
|
|
48
|
+
.superRefine((data, context) => {
|
|
49
|
+
// common
|
|
50
|
+
if (
|
|
51
|
+
commonOperators.includes(data.operator) &&
|
|
52
|
+
!(
|
|
53
|
+
data.value === null ||
|
|
54
|
+
typeof data.value === "string" ||
|
|
55
|
+
typeof data.value === "number" ||
|
|
56
|
+
typeof data.value === "boolean" ||
|
|
57
|
+
data.value instanceof Date ||
|
|
58
|
+
data.value === null
|
|
59
|
+
)
|
|
60
|
+
) {
|
|
61
|
+
context.addIssue({
|
|
62
|
+
code: z.ZodIssueCode.custom,
|
|
63
|
+
message: `when operator is "${data.operator}", value has to be either a string, number, boolean, date or null`,
|
|
64
|
+
path: ["value"],
|
|
65
|
+
});
|
|
66
|
+
}
|
|
17
67
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
68
|
+
// numeric
|
|
69
|
+
if (numericOperators.includes(data.operator) && typeof data.value !== "number") {
|
|
70
|
+
context.addIssue({
|
|
71
|
+
code: z.ZodIssueCode.custom,
|
|
72
|
+
message: `when operator is "${data.operator}", value must be a number`,
|
|
73
|
+
path: ["value"],
|
|
74
|
+
});
|
|
75
|
+
}
|
|
23
76
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
77
|
+
// string
|
|
78
|
+
if (stringOperators.includes(data.operator) && typeof data.value !== "string") {
|
|
79
|
+
context.addIssue({
|
|
80
|
+
code: z.ZodIssueCode.custom,
|
|
81
|
+
message: `when operator is "${data.operator}", value must be a string`,
|
|
82
|
+
path: ["value"],
|
|
83
|
+
});
|
|
84
|
+
}
|
|
29
85
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
86
|
+
// semver
|
|
87
|
+
if (semverOperators.includes(data.operator) && typeof data.value !== "string") {
|
|
88
|
+
context.addIssue({
|
|
89
|
+
code: z.ZodIssueCode.custom,
|
|
90
|
+
message: `when operator is "${data.operator}", value must be a string`,
|
|
91
|
+
path: ["value"],
|
|
92
|
+
});
|
|
93
|
+
}
|
|
37
94
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
95
|
+
// date
|
|
96
|
+
if (dateOperators.includes(data.operator) && !(data.value instanceof Date)) {
|
|
97
|
+
context.addIssue({
|
|
98
|
+
code: z.ZodIssueCode.custom,
|
|
99
|
+
message: `when operator is "${data.operator}", value must be a date`,
|
|
100
|
+
path: ["value"],
|
|
101
|
+
});
|
|
102
|
+
}
|
|
41
103
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
.
|
|
55
|
-
|
|
56
|
-
"greaterThan",
|
|
57
|
-
"greaterThanOrEquals",
|
|
58
|
-
"lessThan",
|
|
59
|
-
"lessThanOrEquals",
|
|
60
|
-
),
|
|
61
|
-
then: Joi.number().required(),
|
|
62
|
-
})
|
|
63
|
-
.when("operator", {
|
|
64
|
-
is: Joi.string().valid("contains", "notContains", "startsWith", "endsWith"),
|
|
65
|
-
then: Joi.string().required(),
|
|
104
|
+
// array
|
|
105
|
+
if (arrayOperators.includes(data.operator) && !Array.isArray(data.value)) {
|
|
106
|
+
context.addIssue({
|
|
107
|
+
code: z.ZodIssueCode.custom,
|
|
108
|
+
message: `when operator is "${data.operator}", value must be an array of strings`,
|
|
109
|
+
path: ["value"],
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
const andOrNotConditionZodSchema = z.union([
|
|
115
|
+
z
|
|
116
|
+
.object({
|
|
117
|
+
and: z.array(z.lazy(() => conditionZodSchema)),
|
|
66
118
|
})
|
|
67
|
-
.
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
"semverGreaterThan",
|
|
72
|
-
"semverGreaterThanOrEquals",
|
|
73
|
-
"semverLessThan",
|
|
74
|
-
"semverLessThanOrEquals",
|
|
75
|
-
),
|
|
76
|
-
then: Joi.string().required(),
|
|
119
|
+
.strict(),
|
|
120
|
+
z
|
|
121
|
+
.object({
|
|
122
|
+
or: z.array(z.lazy(() => conditionZodSchema)),
|
|
77
123
|
})
|
|
78
|
-
.
|
|
79
|
-
|
|
80
|
-
|
|
124
|
+
.strict(),
|
|
125
|
+
z
|
|
126
|
+
.object({
|
|
127
|
+
not: z.array(z.lazy(() => conditionZodSchema)),
|
|
81
128
|
})
|
|
82
|
-
.
|
|
83
|
-
|
|
84
|
-
then: Joi.array().items(Joi.string()).required(),
|
|
85
|
-
}),
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
const andOrNotConditionJoiSchema = Joi.alternatives()
|
|
89
|
-
.try(
|
|
90
|
-
Joi.object({
|
|
91
|
-
and: Joi.array().items(Joi.link("#andOrNotCondition"), plainConditionJoiSchema),
|
|
92
|
-
}),
|
|
93
|
-
Joi.object({
|
|
94
|
-
or: Joi.array().items(Joi.link("#andOrNotCondition"), plainConditionJoiSchema),
|
|
95
|
-
}),
|
|
96
|
-
Joi.object({
|
|
97
|
-
// @TODO: allow plainConditionJoiSchema as well?
|
|
98
|
-
not: Joi.array().items(Joi.link("#andOrNotCondition"), plainConditionJoiSchema),
|
|
99
|
-
}),
|
|
100
|
-
)
|
|
101
|
-
.id("andOrNotCondition");
|
|
129
|
+
.strict(),
|
|
130
|
+
]);
|
|
102
131
|
|
|
103
|
-
const
|
|
104
|
-
andOrNotConditionJoiSchema,
|
|
105
|
-
plainConditionJoiSchema,
|
|
106
|
-
);
|
|
132
|
+
const conditionZodSchema = z.union([andOrNotConditionZodSchema, plainConditionZodSchema]);
|
|
107
133
|
|
|
108
|
-
const
|
|
109
|
-
conditionJoiSchema,
|
|
110
|
-
Joi.array().items(conditionJoiSchema),
|
|
111
|
-
);
|
|
134
|
+
const conditionsZodSchema = z.union([conditionZodSchema, z.array(conditionZodSchema)]);
|
|
112
135
|
|
|
113
|
-
return
|
|
136
|
+
return conditionsZodSchema;
|
|
114
137
|
}
|