@featurevisor/core 2.11.0 → 2.12.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 +11 -0
- package/coverage/clover.xml +684 -3
- package/coverage/coverage-final.json +4 -0
- package/coverage/lcov-report/builder/allocator.ts.html +1 -1
- package/coverage/lcov-report/builder/buildScopedConditions.ts.html +1 -1
- package/coverage/lcov-report/builder/buildScopedDatafile.ts.html +1 -1
- package/coverage/lcov-report/builder/buildScopedSegments.ts.html +1 -1
- package/coverage/lcov-report/builder/index.html +1 -1
- package/coverage/lcov-report/builder/revision.ts.html +1 -1
- package/coverage/lcov-report/builder/traffic.ts.html +1 -1
- package/coverage/lcov-report/index.html +25 -10
- package/coverage/lcov-report/linter/conditionSchema.ts.html +775 -0
- package/coverage/lcov-report/linter/featureSchema.ts.html +4924 -0
- package/coverage/lcov-report/linter/index.html +161 -0
- package/coverage/lcov-report/linter/schema.ts.html +1471 -0
- package/coverage/lcov-report/linter/segmentSchema.ts.html +130 -0
- package/coverage/lcov-report/list/index.html +1 -1
- package/coverage/lcov-report/list/matrix.ts.html +1 -1
- package/coverage/lcov-report/parsers/index.html +1 -1
- package/coverage/lcov-report/parsers/json.ts.html +1 -1
- package/coverage/lcov-report/parsers/yml.ts.html +1 -1
- package/coverage/lcov-report/tester/helpers.ts.html +1 -1
- package/coverage/lcov-report/tester/index.html +1 -1
- package/coverage/lcov.info +1471 -0
- package/lib/builder/buildDatafile.js +15 -1
- package/lib/builder/buildDatafile.js.map +1 -1
- package/lib/config/projectConfig.d.ts +2 -0
- package/lib/config/projectConfig.js +3 -1
- package/lib/config/projectConfig.js.map +1 -1
- package/lib/datasource/datasource.d.ts +6 -1
- package/lib/datasource/datasource.js +16 -0
- package/lib/datasource/datasource.js.map +1 -1
- package/lib/datasource/filesystemAdapter.js +10 -0
- package/lib/datasource/filesystemAdapter.js.map +1 -1
- package/lib/generate-code/typescript.js +280 -46
- package/lib/generate-code/typescript.js.map +1 -1
- package/lib/linter/conditionSchema.spec.d.ts +1 -0
- package/lib/linter/conditionSchema.spec.js +331 -0
- package/lib/linter/conditionSchema.spec.js.map +1 -0
- package/lib/linter/featureSchema.d.ts +129 -20
- package/lib/linter/featureSchema.js +489 -48
- package/lib/linter/featureSchema.js.map +1 -1
- package/lib/linter/featureSchema.spec.d.ts +1 -0
- package/lib/linter/featureSchema.spec.js +978 -0
- package/lib/linter/featureSchema.spec.js.map +1 -0
- package/lib/linter/lintProject.js +67 -1
- package/lib/linter/lintProject.js.map +1 -1
- package/lib/linter/schema.d.ts +42 -0
- package/lib/linter/schema.js +417 -0
- package/lib/linter/schema.js.map +1 -0
- package/lib/linter/schema.spec.d.ts +1 -0
- package/lib/linter/schema.spec.js +483 -0
- package/lib/linter/schema.spec.js.map +1 -0
- package/lib/linter/segmentSchema.spec.d.ts +1 -0
- package/lib/linter/segmentSchema.spec.js +231 -0
- package/lib/linter/segmentSchema.spec.js.map +1 -0
- package/lib/tester/testFeature.js +5 -3
- package/lib/tester/testFeature.js.map +1 -1
- package/lib/utils/git.js +3 -0
- package/lib/utils/git.js.map +1 -1
- package/package.json +5 -5
- package/src/builder/buildDatafile.ts +17 -1
- package/src/config/projectConfig.ts +3 -0
- package/src/datasource/datasource.ts +23 -0
- package/src/datasource/filesystemAdapter.ts +7 -0
- package/src/generate-code/typescript.ts +330 -49
- package/src/linter/conditionSchema.spec.ts +446 -0
- package/src/linter/featureSchema.spec.ts +1218 -0
- package/src/linter/featureSchema.ts +671 -69
- package/src/linter/lintProject.ts +84 -0
- package/src/linter/schema.spec.ts +617 -0
- package/src/linter/schema.ts +462 -0
- package/src/linter/segmentSchema.spec.ts +273 -0
- package/src/tester/testFeature.ts +5 -3
- package/src/utils/git.ts +2 -0
- package/lib/linter/propertySchema.d.ts +0 -5
- package/lib/linter/propertySchema.js +0 -43
- package/lib/linter/propertySchema.js.map +0 -1
- package/src/linter/propertySchema.ts +0 -47
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.getFeatureZodSchema = getFeatureZodSchema;
|
|
4
4
|
const zod_1 = require("zod");
|
|
5
|
-
const
|
|
5
|
+
const schema_1 = require("./schema");
|
|
6
6
|
const tagRegex = /^[a-z0-9-]+$/;
|
|
7
7
|
function isArrayOfStrings(value) {
|
|
8
8
|
return Array.isArray(value) && value.every((v) => typeof v === "string");
|
|
@@ -18,6 +18,153 @@ function getVariableLabel(variableSchema, variableKey, path) {
|
|
|
18
18
|
variableSchema?.key ??
|
|
19
19
|
(path.length > 0 ? String(path[path.length - 1]) : "variable"));
|
|
20
20
|
}
|
|
21
|
+
/**
|
|
22
|
+
* Resolve variable schema to the Schema used for value validation.
|
|
23
|
+
* When variable has `schema` (reference), returns the parsed Schema from schemasByKey; otherwise returns the inline variable schema.
|
|
24
|
+
*/
|
|
25
|
+
function resolveVariableSchema(variableSchema, schemasByKey) {
|
|
26
|
+
if (variableSchema.schema) {
|
|
27
|
+
return schemasByKey?.[variableSchema.schema] ?? null;
|
|
28
|
+
}
|
|
29
|
+
return variableSchema;
|
|
30
|
+
}
|
|
31
|
+
/** Resolve a schema by following schema references (schema: key). Used for nested schemas that may have oneOf. */
|
|
32
|
+
function resolveSchemaRefs(schema, schemasByKey) {
|
|
33
|
+
if (schema.schema && schemasByKey?.[schema.schema]) {
|
|
34
|
+
return resolveSchemaRefs(schemasByKey[schema.schema], schemasByKey);
|
|
35
|
+
}
|
|
36
|
+
return schema;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Returns true if the value matches the given schema (const, enum, type, object properties, array items, or exactly one of oneOf).
|
|
40
|
+
* Used for oneOf validation: value must match exactly one branch.
|
|
41
|
+
*/
|
|
42
|
+
function valueMatchesSchema(schema, value, schemasByKey) {
|
|
43
|
+
const resolved = resolveSchemaRefs(schema, schemasByKey);
|
|
44
|
+
if (resolved.oneOf && Array.isArray(resolved.oneOf) && resolved.oneOf.length > 0) {
|
|
45
|
+
const matchCount = resolved.oneOf.filter((branch) => valueMatchesSchema(branch, value, schemasByKey)).length;
|
|
46
|
+
return matchCount === 1;
|
|
47
|
+
}
|
|
48
|
+
if (resolved.const !== undefined) {
|
|
49
|
+
return valueDeepEqual(value, resolved.const);
|
|
50
|
+
}
|
|
51
|
+
if (resolved.enum !== undefined && Array.isArray(resolved.enum)) {
|
|
52
|
+
return resolved.enum.some((e) => valueDeepEqual(value, e));
|
|
53
|
+
}
|
|
54
|
+
const type = resolved.type;
|
|
55
|
+
if (!type)
|
|
56
|
+
return false;
|
|
57
|
+
if (type === "string") {
|
|
58
|
+
if (typeof value !== "string")
|
|
59
|
+
return false;
|
|
60
|
+
const s = value;
|
|
61
|
+
if (resolved.minLength !== undefined && s.length < resolved.minLength)
|
|
62
|
+
return false;
|
|
63
|
+
if (resolved.maxLength !== undefined && s.length > resolved.maxLength)
|
|
64
|
+
return false;
|
|
65
|
+
if (resolved.pattern !== undefined) {
|
|
66
|
+
try {
|
|
67
|
+
if (!new RegExp(resolved.pattern).test(s))
|
|
68
|
+
return false;
|
|
69
|
+
}
|
|
70
|
+
catch {
|
|
71
|
+
return true;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return true;
|
|
75
|
+
}
|
|
76
|
+
if (type === "boolean")
|
|
77
|
+
return typeof value === "boolean";
|
|
78
|
+
if (type === "integer") {
|
|
79
|
+
if (typeof value !== "number" || !Number.isInteger(value))
|
|
80
|
+
return false;
|
|
81
|
+
if (resolved.minimum !== undefined && value < resolved.minimum)
|
|
82
|
+
return false;
|
|
83
|
+
if (resolved.maximum !== undefined && value > resolved.maximum)
|
|
84
|
+
return false;
|
|
85
|
+
return true;
|
|
86
|
+
}
|
|
87
|
+
if (type === "double") {
|
|
88
|
+
if (typeof value !== "number")
|
|
89
|
+
return false;
|
|
90
|
+
if (resolved.minimum !== undefined && value < resolved.minimum)
|
|
91
|
+
return false;
|
|
92
|
+
if (resolved.maximum !== undefined && value > resolved.maximum)
|
|
93
|
+
return false;
|
|
94
|
+
return true;
|
|
95
|
+
}
|
|
96
|
+
if (type === "json")
|
|
97
|
+
return typeof value === "string";
|
|
98
|
+
if (type === "object") {
|
|
99
|
+
if (typeof value !== "object" || value === null || Array.isArray(value))
|
|
100
|
+
return false;
|
|
101
|
+
const props = resolved.properties;
|
|
102
|
+
if (!props || typeof props !== "object")
|
|
103
|
+
return true;
|
|
104
|
+
const obj = value;
|
|
105
|
+
const required = new Set(resolved.required || []);
|
|
106
|
+
for (const key of required) {
|
|
107
|
+
if (!Object.prototype.hasOwnProperty.call(obj, key))
|
|
108
|
+
return false;
|
|
109
|
+
if (!valueMatchesSchema(props[key], obj[key], schemasByKey))
|
|
110
|
+
return false;
|
|
111
|
+
}
|
|
112
|
+
for (const key of Object.keys(obj)) {
|
|
113
|
+
const propSchema = props[key];
|
|
114
|
+
if (!propSchema)
|
|
115
|
+
return false;
|
|
116
|
+
if (!valueMatchesSchema(propSchema, obj[key], schemasByKey))
|
|
117
|
+
return false;
|
|
118
|
+
}
|
|
119
|
+
return true;
|
|
120
|
+
}
|
|
121
|
+
if (type === "array") {
|
|
122
|
+
if (!Array.isArray(value))
|
|
123
|
+
return false;
|
|
124
|
+
const arr = value;
|
|
125
|
+
if (resolved.minItems !== undefined && arr.length < resolved.minItems)
|
|
126
|
+
return false;
|
|
127
|
+
if (resolved.maxItems !== undefined && arr.length > resolved.maxItems)
|
|
128
|
+
return false;
|
|
129
|
+
if (resolved.uniqueItems) {
|
|
130
|
+
for (let i = 0; i < arr.length; i++) {
|
|
131
|
+
for (let j = i + 1; j < arr.length; j++) {
|
|
132
|
+
if (valueDeepEqual(arr[i], arr[j]))
|
|
133
|
+
return false;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
const itemSchema = resolved.items;
|
|
138
|
+
if (!itemSchema || typeof itemSchema !== "object")
|
|
139
|
+
return arr.every((v) => typeof v === "string");
|
|
140
|
+
return arr.every((item) => valueMatchesSchema(itemSchema, item, schemasByKey));
|
|
141
|
+
}
|
|
142
|
+
return false;
|
|
143
|
+
}
|
|
144
|
+
/** Deep equality for variable values (primitives, plain objects, arrays). */
|
|
145
|
+
function valueDeepEqual(a, b) {
|
|
146
|
+
if (a === b)
|
|
147
|
+
return true;
|
|
148
|
+
if (typeof a !== typeof b)
|
|
149
|
+
return false;
|
|
150
|
+
if (a === null || b === null)
|
|
151
|
+
return a === b;
|
|
152
|
+
if (typeof a === "object" && typeof b === "object") {
|
|
153
|
+
if (Array.isArray(a) !== Array.isArray(b))
|
|
154
|
+
return false;
|
|
155
|
+
if (Array.isArray(a) && Array.isArray(b)) {
|
|
156
|
+
if (a.length !== b.length)
|
|
157
|
+
return false;
|
|
158
|
+
return a.every((v, i) => valueDeepEqual(v, b[i]));
|
|
159
|
+
}
|
|
160
|
+
const keysA = Object.keys(a).sort();
|
|
161
|
+
const keysB = Object.keys(b).sort();
|
|
162
|
+
if (keysA.length !== keysB.length || keysA.some((k, i) => k !== keysB[i]))
|
|
163
|
+
return false;
|
|
164
|
+
return keysA.every((k) => valueDeepEqual(a[k], b[k]));
|
|
165
|
+
}
|
|
166
|
+
return false;
|
|
167
|
+
}
|
|
21
168
|
/**
|
|
22
169
|
* Recursively validates that every `required` array (at this level and in nested
|
|
23
170
|
* object/array schemas) only contains keys that exist in the same level's `properties`.
|
|
@@ -57,6 +204,14 @@ function refineRequiredKeysInSchema(schema, pathPrefix, ctx) {
|
|
|
57
204
|
if (items && typeof items === "object" && !Array.isArray(items)) {
|
|
58
205
|
refineRequiredKeysInSchema(items, [...pathPrefix, "items"], ctx);
|
|
59
206
|
}
|
|
207
|
+
const oneOf = schema.oneOf;
|
|
208
|
+
if (oneOf && Array.isArray(oneOf)) {
|
|
209
|
+
oneOf.forEach((branch, i) => {
|
|
210
|
+
if (branch && typeof branch === "object") {
|
|
211
|
+
refineRequiredKeysInSchema(branch, [...pathPrefix, "oneOf", i], ctx);
|
|
212
|
+
}
|
|
213
|
+
});
|
|
214
|
+
}
|
|
60
215
|
}
|
|
61
216
|
function typeOfValue(value) {
|
|
62
217
|
if (value === null)
|
|
@@ -70,13 +225,45 @@ function typeOfValue(value) {
|
|
|
70
225
|
/**
|
|
71
226
|
* Validates a variable value against an array schema. Recursively validates each item
|
|
72
227
|
* when the schema defines `items` (nested arrays/objects use the same refinement).
|
|
228
|
+
* Enforces minItems, maxItems, and uniqueItems when set.
|
|
73
229
|
*/
|
|
74
|
-
function refineVariableValueArray(projectConfig, variableSchema, variableValue, path, ctx, variableKey) {
|
|
230
|
+
function refineVariableValueArray(projectConfig, variableSchema, variableValue, path, ctx, variableKey, schemasByKey) {
|
|
75
231
|
const label = getVariableLabel(variableSchema, variableKey, path);
|
|
232
|
+
const minItems = variableSchema.minItems;
|
|
233
|
+
const maxItems = variableSchema.maxItems;
|
|
234
|
+
const uniqueItems = variableSchema.uniqueItems;
|
|
235
|
+
if (minItems !== undefined && variableValue.length < minItems) {
|
|
236
|
+
ctx.addIssue({
|
|
237
|
+
code: zod_1.z.ZodIssueCode.custom,
|
|
238
|
+
message: `Variable "${label}" (type array) length (${variableValue.length}) is less than \`minItems\` (${minItems}).`,
|
|
239
|
+
path,
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
if (maxItems !== undefined && variableValue.length > maxItems) {
|
|
243
|
+
ctx.addIssue({
|
|
244
|
+
code: zod_1.z.ZodIssueCode.custom,
|
|
245
|
+
message: `Variable "${label}" (type array) length (${variableValue.length}) is greater than \`maxItems\` (${maxItems}).`,
|
|
246
|
+
path,
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
if (uniqueItems) {
|
|
250
|
+
for (let i = 0; i < variableValue.length; i++) {
|
|
251
|
+
for (let j = i + 1; j < variableValue.length; j++) {
|
|
252
|
+
if (valueDeepEqual(variableValue[i], variableValue[j])) {
|
|
253
|
+
ctx.addIssue({
|
|
254
|
+
code: zod_1.z.ZodIssueCode.custom,
|
|
255
|
+
message: `Variable "${label}" (type array) has duplicate items at indices ${i} and ${j} but \`uniqueItems\` is true.`,
|
|
256
|
+
path,
|
|
257
|
+
});
|
|
258
|
+
break;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
}
|
|
76
263
|
const itemSchema = variableSchema.items;
|
|
77
264
|
if (itemSchema) {
|
|
78
265
|
variableValue.forEach((item, index) => {
|
|
79
|
-
superRefineVariableValue(projectConfig, itemSchema, item, [...path, index], ctx, variableKey);
|
|
266
|
+
superRefineVariableValue(projectConfig, itemSchema, item, [...path, index], ctx, variableKey, schemasByKey);
|
|
80
267
|
});
|
|
81
268
|
}
|
|
82
269
|
else {
|
|
@@ -103,7 +290,7 @@ function refineVariableValueArray(projectConfig, variableSchema, variableValue,
|
|
|
103
290
|
* Validates a variable value against an object schema. Recursively validates each property
|
|
104
291
|
* when the schema defines `properties` (nested objects/arrays use the same refinement).
|
|
105
292
|
*/
|
|
106
|
-
function refineVariableValueObject(projectConfig, variableSchema, variableValue, path, ctx, variableKey) {
|
|
293
|
+
function refineVariableValueObject(projectConfig, variableSchema, variableValue, path, ctx, variableKey, schemasByKey) {
|
|
107
294
|
const label = getVariableLabel(variableSchema, variableKey, path);
|
|
108
295
|
const schemaProperties = variableSchema.properties;
|
|
109
296
|
if (schemaProperties && typeof schemaProperties === "object") {
|
|
@@ -129,7 +316,7 @@ function refineVariableValueObject(projectConfig, variableSchema, variableValue,
|
|
|
129
316
|
});
|
|
130
317
|
}
|
|
131
318
|
else {
|
|
132
|
-
superRefineVariableValue(projectConfig, propSchema, variableValue[key], [...path, key], ctx, key);
|
|
319
|
+
superRefineVariableValue(projectConfig, propSchema, variableValue[key], [...path, key], ctx, key, schemasByKey);
|
|
133
320
|
}
|
|
134
321
|
}
|
|
135
322
|
}
|
|
@@ -156,7 +343,7 @@ function refineVariableValueObject(projectConfig, variableSchema, variableValue,
|
|
|
156
343
|
}
|
|
157
344
|
}
|
|
158
345
|
}
|
|
159
|
-
function superRefineVariableValue(projectConfig, variableSchema, variableValue, path, ctx, variableKey) {
|
|
346
|
+
function superRefineVariableValue(projectConfig, variableSchema, variableValue, path, ctx, variableKey, schemasByKey) {
|
|
160
347
|
const label = getVariableLabel(variableSchema, variableKey, path);
|
|
161
348
|
if (!variableSchema) {
|
|
162
349
|
const variableName = path.length > 0 && typeof path[path.length - 1] === "string"
|
|
@@ -170,6 +357,60 @@ function superRefineVariableValue(projectConfig, variableSchema, variableValue,
|
|
|
170
357
|
});
|
|
171
358
|
return;
|
|
172
359
|
}
|
|
360
|
+
const effectiveSchema = resolveVariableSchema(variableSchema, schemasByKey);
|
|
361
|
+
if (variableSchema.schema && effectiveSchema === null) {
|
|
362
|
+
ctx.addIssue({
|
|
363
|
+
code: zod_1.z.ZodIssueCode.custom,
|
|
364
|
+
message: `Schema "${variableSchema.schema}" could not be loaded for value validation.`,
|
|
365
|
+
path,
|
|
366
|
+
});
|
|
367
|
+
return;
|
|
368
|
+
}
|
|
369
|
+
if (!effectiveSchema) {
|
|
370
|
+
return;
|
|
371
|
+
}
|
|
372
|
+
const effectiveOneOf = effectiveSchema.oneOf;
|
|
373
|
+
if (effectiveOneOf !== undefined && Array.isArray(effectiveOneOf) && effectiveOneOf.length > 0) {
|
|
374
|
+
const matchCount = effectiveOneOf.filter((branch) => valueMatchesSchema(branch, variableValue, schemasByKey)).length;
|
|
375
|
+
if (matchCount === 0) {
|
|
376
|
+
ctx.addIssue({
|
|
377
|
+
code: zod_1.z.ZodIssueCode.custom,
|
|
378
|
+
message: `Variable "${label}" must match exactly one of the \`oneOf\` schemas (got ${JSON.stringify(variableValue)}; matched none).`,
|
|
379
|
+
path,
|
|
380
|
+
});
|
|
381
|
+
}
|
|
382
|
+
else if (matchCount > 1) {
|
|
383
|
+
ctx.addIssue({
|
|
384
|
+
code: zod_1.z.ZodIssueCode.custom,
|
|
385
|
+
message: `Variable "${label}" must match exactly one of the \`oneOf\` schemas (matched ${matchCount}).`,
|
|
386
|
+
path,
|
|
387
|
+
});
|
|
388
|
+
}
|
|
389
|
+
return;
|
|
390
|
+
}
|
|
391
|
+
const effectiveConst = effectiveSchema.const;
|
|
392
|
+
if (effectiveConst !== undefined) {
|
|
393
|
+
if (!valueDeepEqual(variableValue, effectiveConst)) {
|
|
394
|
+
ctx.addIssue({
|
|
395
|
+
code: zod_1.z.ZodIssueCode.custom,
|
|
396
|
+
message: `Variable "${label}" must equal the constant value defined in schema (got ${JSON.stringify(variableValue)}).`,
|
|
397
|
+
path,
|
|
398
|
+
});
|
|
399
|
+
}
|
|
400
|
+
return;
|
|
401
|
+
}
|
|
402
|
+
const effectiveEnum = effectiveSchema.enum;
|
|
403
|
+
if (effectiveEnum !== undefined && Array.isArray(effectiveEnum) && effectiveEnum.length > 0) {
|
|
404
|
+
const allowed = effectiveEnum.some((v) => valueDeepEqual(variableValue, v));
|
|
405
|
+
if (!allowed) {
|
|
406
|
+
ctx.addIssue({
|
|
407
|
+
code: zod_1.z.ZodIssueCode.custom,
|
|
408
|
+
message: `Variable "${label}" must be one of the allowed enum values (got ${JSON.stringify(variableValue)}).`,
|
|
409
|
+
path,
|
|
410
|
+
});
|
|
411
|
+
}
|
|
412
|
+
return;
|
|
413
|
+
}
|
|
173
414
|
// Require a value (no undefined) for every variable usage
|
|
174
415
|
if (variableValue === undefined) {
|
|
175
416
|
ctx.addIssue({
|
|
@@ -179,9 +420,9 @@ function superRefineVariableValue(projectConfig, variableSchema, variableValue,
|
|
|
179
420
|
});
|
|
180
421
|
return;
|
|
181
422
|
}
|
|
182
|
-
const expectedType =
|
|
423
|
+
const expectedType = effectiveSchema.type;
|
|
183
424
|
const gotType = typeOfValue(variableValue);
|
|
184
|
-
// string — only string allowed
|
|
425
|
+
// string — only string allowed; schema minLength/maxLength/pattern applied when set
|
|
185
426
|
if (expectedType === "string") {
|
|
186
427
|
if (typeof variableValue !== "string") {
|
|
187
428
|
ctx.addIssue({
|
|
@@ -191,6 +432,37 @@ function superRefineVariableValue(projectConfig, variableSchema, variableValue,
|
|
|
191
432
|
});
|
|
192
433
|
return;
|
|
193
434
|
}
|
|
435
|
+
const strMinLen = effectiveSchema.minLength;
|
|
436
|
+
const strMaxLen = effectiveSchema.maxLength;
|
|
437
|
+
const strPattern = effectiveSchema.pattern;
|
|
438
|
+
if (strMinLen !== undefined && variableValue.length < strMinLen) {
|
|
439
|
+
ctx.addIssue({
|
|
440
|
+
code: zod_1.z.ZodIssueCode.custom,
|
|
441
|
+
message: `Variable "${label}" (type string) length (${variableValue.length}) is less than \`minLength\` (${strMinLen}).`,
|
|
442
|
+
path,
|
|
443
|
+
});
|
|
444
|
+
}
|
|
445
|
+
if (strMaxLen !== undefined && variableValue.length > strMaxLen) {
|
|
446
|
+
ctx.addIssue({
|
|
447
|
+
code: zod_1.z.ZodIssueCode.custom,
|
|
448
|
+
message: `Variable "${label}" (type string) length (${variableValue.length}) is greater than \`maxLength\` (${strMaxLen}).`,
|
|
449
|
+
path,
|
|
450
|
+
});
|
|
451
|
+
}
|
|
452
|
+
if (strPattern !== undefined) {
|
|
453
|
+
try {
|
|
454
|
+
if (!new RegExp(strPattern).test(variableValue)) {
|
|
455
|
+
ctx.addIssue({
|
|
456
|
+
code: zod_1.z.ZodIssueCode.custom,
|
|
457
|
+
message: `Variable "${label}" (type string) does not match \`pattern\`.`,
|
|
458
|
+
path,
|
|
459
|
+
});
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
catch {
|
|
463
|
+
// invalid regex already reported at schema parse time
|
|
464
|
+
}
|
|
465
|
+
}
|
|
194
466
|
if (projectConfig.maxVariableStringLength &&
|
|
195
467
|
variableValue.length > projectConfig.maxVariableStringLength) {
|
|
196
468
|
ctx.addIssue({
|
|
@@ -225,6 +497,23 @@ function superRefineVariableValue(projectConfig, variableSchema, variableValue,
|
|
|
225
497
|
message: `Variable "${label}" (type integer) must be an integer; got ${variableValue}.`,
|
|
226
498
|
path,
|
|
227
499
|
});
|
|
500
|
+
return;
|
|
501
|
+
}
|
|
502
|
+
const intMin = effectiveSchema.minimum;
|
|
503
|
+
const intMax = effectiveSchema.maximum;
|
|
504
|
+
if (intMin !== undefined && variableValue < intMin) {
|
|
505
|
+
ctx.addIssue({
|
|
506
|
+
code: zod_1.z.ZodIssueCode.custom,
|
|
507
|
+
message: `Variable "${label}" (type integer) must be >= minimum (${intMin}); got ${variableValue}.`,
|
|
508
|
+
path,
|
|
509
|
+
});
|
|
510
|
+
}
|
|
511
|
+
if (intMax !== undefined && variableValue > intMax) {
|
|
512
|
+
ctx.addIssue({
|
|
513
|
+
code: zod_1.z.ZodIssueCode.custom,
|
|
514
|
+
message: `Variable "${label}" (type integer) must be <= maximum (${intMax}); got ${variableValue}.`,
|
|
515
|
+
path,
|
|
516
|
+
});
|
|
228
517
|
}
|
|
229
518
|
return;
|
|
230
519
|
}
|
|
@@ -244,6 +533,23 @@ function superRefineVariableValue(projectConfig, variableSchema, variableValue,
|
|
|
244
533
|
message: `Variable "${label}" (type double) must be a finite number; got ${variableValue}.`,
|
|
245
534
|
path,
|
|
246
535
|
});
|
|
536
|
+
return;
|
|
537
|
+
}
|
|
538
|
+
const doubleMin = effectiveSchema.minimum;
|
|
539
|
+
const doubleMax = effectiveSchema.maximum;
|
|
540
|
+
if (doubleMin !== undefined && variableValue < doubleMin) {
|
|
541
|
+
ctx.addIssue({
|
|
542
|
+
code: zod_1.z.ZodIssueCode.custom,
|
|
543
|
+
message: `Variable "${label}" (type double) must be >= minimum (${doubleMin}); got ${variableValue}.`,
|
|
544
|
+
path,
|
|
545
|
+
});
|
|
546
|
+
}
|
|
547
|
+
if (doubleMax !== undefined && variableValue > doubleMax) {
|
|
548
|
+
ctx.addIssue({
|
|
549
|
+
code: zod_1.z.ZodIssueCode.custom,
|
|
550
|
+
message: `Variable "${label}" (type double) must be <= maximum (${doubleMax}); got ${variableValue}.`,
|
|
551
|
+
path,
|
|
552
|
+
});
|
|
247
553
|
}
|
|
248
554
|
return;
|
|
249
555
|
}
|
|
@@ -268,7 +574,7 @@ function superRefineVariableValue(projectConfig, variableSchema, variableValue,
|
|
|
268
574
|
});
|
|
269
575
|
return;
|
|
270
576
|
}
|
|
271
|
-
refineVariableValueArray(projectConfig,
|
|
577
|
+
refineVariableValueArray(projectConfig, effectiveSchema, variableValue, path, ctx, variableKey, schemasByKey);
|
|
272
578
|
return;
|
|
273
579
|
}
|
|
274
580
|
// object — only plain object allowed (no null, no array)
|
|
@@ -283,7 +589,7 @@ function superRefineVariableValue(projectConfig, variableSchema, variableValue,
|
|
|
283
589
|
});
|
|
284
590
|
return;
|
|
285
591
|
}
|
|
286
|
-
refineVariableValueObject(projectConfig,
|
|
592
|
+
refineVariableValueObject(projectConfig, effectiveSchema, variableValue, path, ctx, variableKey, schemasByKey);
|
|
287
593
|
return;
|
|
288
594
|
}
|
|
289
595
|
// json — only string containing valid JSON allowed
|
|
@@ -326,7 +632,7 @@ function superRefineVariableValue(projectConfig, variableSchema, variableValue,
|
|
|
326
632
|
});
|
|
327
633
|
}
|
|
328
634
|
function refineForce({ ctx, parsedFeature, // eslint-disable-line
|
|
329
|
-
variableSchemaByKey, variationValues, force, pathPrefix, projectConfig, }) {
|
|
635
|
+
variableSchemaByKey, variationValues, force, pathPrefix, projectConfig, schemasByKey, }) {
|
|
330
636
|
force.forEach((f, fN) => {
|
|
331
637
|
// force[n].variation
|
|
332
638
|
if (f.variation) {
|
|
@@ -341,17 +647,37 @@ variableSchemaByKey, variationValues, force, pathPrefix, projectConfig, }) {
|
|
|
341
647
|
// force[n].variables[key]
|
|
342
648
|
if (f.variables) {
|
|
343
649
|
Object.keys(f.variables).forEach((variableKey) => {
|
|
344
|
-
|
|
650
|
+
const variableSchema = variableSchemaByKey[variableKey];
|
|
651
|
+
if (!variableSchema) {
|
|
652
|
+
ctx.addIssue({
|
|
653
|
+
code: zod_1.z.ZodIssueCode.custom,
|
|
654
|
+
message: `Variable "${variableKey}" is not defined in \`variablesSchema\`.`,
|
|
655
|
+
path: pathPrefix.concat([fN, "variables", variableKey]),
|
|
656
|
+
});
|
|
657
|
+
}
|
|
658
|
+
else {
|
|
659
|
+
superRefineVariableValue(projectConfig, variableSchema, f.variables[variableKey], pathPrefix.concat([fN, "variables", variableKey]), ctx, variableKey, schemasByKey);
|
|
660
|
+
}
|
|
345
661
|
});
|
|
346
662
|
}
|
|
347
663
|
});
|
|
348
664
|
}
|
|
349
|
-
function refineRules({ ctx, parsedFeature, variableSchemaByKey, variationValues, rules, pathPrefix, projectConfig, }) {
|
|
665
|
+
function refineRules({ ctx, parsedFeature, variableSchemaByKey, variationValues, rules, pathPrefix, projectConfig, schemasByKey, }) {
|
|
350
666
|
rules.forEach((rule, ruleN) => {
|
|
351
667
|
// rules[n].variables[key]
|
|
352
668
|
if (rule.variables) {
|
|
353
669
|
Object.keys(rule.variables).forEach((variableKey) => {
|
|
354
|
-
|
|
670
|
+
const variableSchema = variableSchemaByKey[variableKey];
|
|
671
|
+
if (!variableSchema) {
|
|
672
|
+
ctx.addIssue({
|
|
673
|
+
code: zod_1.z.ZodIssueCode.custom,
|
|
674
|
+
message: `Variable "${variableKey}" is not defined in \`variablesSchema\`.`,
|
|
675
|
+
path: pathPrefix.concat([ruleN, "variables", variableKey]),
|
|
676
|
+
});
|
|
677
|
+
}
|
|
678
|
+
else {
|
|
679
|
+
superRefineVariableValue(projectConfig, variableSchema, rule.variables[variableKey], pathPrefix.concat([ruleN, "variables", variableKey]), ctx, variableKey, schemasByKey);
|
|
680
|
+
}
|
|
355
681
|
});
|
|
356
682
|
}
|
|
357
683
|
// rules[n].variationWeights
|
|
@@ -406,9 +732,9 @@ function refineRules({ ctx, parsedFeature, variableSchemaByKey, variationValues,
|
|
|
406
732
|
}
|
|
407
733
|
});
|
|
408
734
|
}
|
|
409
|
-
function getFeatureZodSchema(projectConfig, conditionsZodSchema, availableAttributeKeys, availableSegmentKeys, availableFeatureKeys) {
|
|
410
|
-
const
|
|
411
|
-
const variableValueZodSchema =
|
|
735
|
+
function getFeatureZodSchema(projectConfig, conditionsZodSchema, availableAttributeKeys, availableSegmentKeys, availableFeatureKeys, availableSchemaKeys = [], schemasByKey = {}) {
|
|
736
|
+
const schemaZodSchema = (0, schema_1.getSchemaZodSchema)(availableSchemaKeys);
|
|
737
|
+
const variableValueZodSchema = schema_1.valueZodSchema;
|
|
412
738
|
const variationValueZodSchema = zod_1.z.string().min(1);
|
|
413
739
|
const plainGroupSegment = zod_1.z.string().refine((value) => value === "*" || availableSegmentKeys.includes(value), (value) => ({
|
|
414
740
|
message: `Unknown segment key "${value}"`,
|
|
@@ -534,13 +860,27 @@ function getFeatureZodSchema(projectConfig, conditionsZodSchema, availableAttrib
|
|
|
534
860
|
.record(zod_1.z
|
|
535
861
|
.object({
|
|
536
862
|
deprecated: zod_1.z.boolean().optional(),
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
//
|
|
863
|
+
// Reference to a reusable schema (mutually exclusive with type/properties/required/items)
|
|
864
|
+
schema: zod_1.z
|
|
865
|
+
.string()
|
|
866
|
+
.refine((value) => availableSchemaKeys.includes(value), (value) => ({ message: `Unknown schema "${value}"` }))
|
|
867
|
+
.optional(),
|
|
868
|
+
// Inline schema (mutually exclusive with schema)
|
|
869
|
+
type: zod_1.z.union([zod_1.z.literal("json"), schema_1.propertyTypeEnum]).optional(),
|
|
870
|
+
items: schemaZodSchema.optional(),
|
|
871
|
+
properties: zod_1.z.record(schemaZodSchema).optional(),
|
|
543
872
|
required: zod_1.z.array(zod_1.z.string()).optional(),
|
|
873
|
+
enum: zod_1.z.array(variableValueZodSchema).optional(),
|
|
874
|
+
const: variableValueZodSchema.optional(),
|
|
875
|
+
oneOf: zod_1.z.array(schemaZodSchema).min(1).optional(),
|
|
876
|
+
minimum: zod_1.z.number().optional(),
|
|
877
|
+
maximum: zod_1.z.number().optional(),
|
|
878
|
+
minLength: zod_1.z.number().optional(),
|
|
879
|
+
maxLength: zod_1.z.number().optional(),
|
|
880
|
+
pattern: zod_1.z.string().optional(),
|
|
881
|
+
minItems: zod_1.z.number().optional(),
|
|
882
|
+
maxItems: zod_1.z.number().optional(),
|
|
883
|
+
uniqueItems: zod_1.z.boolean().optional(),
|
|
544
884
|
description: zod_1.z.string().optional(),
|
|
545
885
|
defaultValue: variableValueZodSchema,
|
|
546
886
|
disabledValue: variableValueZodSchema.optional(),
|
|
@@ -548,6 +888,67 @@ function getFeatureZodSchema(projectConfig, conditionsZodSchema, availableAttrib
|
|
|
548
888
|
})
|
|
549
889
|
.strict()
|
|
550
890
|
.superRefine((variableSchema, ctx) => {
|
|
891
|
+
const hasRef = "schema" in variableSchema && variableSchema.schema != null;
|
|
892
|
+
const hasInline = "type" in variableSchema &&
|
|
893
|
+
variableSchema.type != null &&
|
|
894
|
+
variableSchema.type !== undefined;
|
|
895
|
+
const hasOneOf = "oneOf" in variableSchema &&
|
|
896
|
+
Array.isArray(variableSchema.oneOf) &&
|
|
897
|
+
variableSchema.oneOf.length > 0;
|
|
898
|
+
if (hasRef && (hasInline || hasOneOf)) {
|
|
899
|
+
ctx.addIssue({
|
|
900
|
+
code: zod_1.z.ZodIssueCode.custom,
|
|
901
|
+
message: "Variable schema cannot have both `schema` (reference) and inline properties (`type`, `oneOf`, `properties`, `required`, `items`). Use one or the other.",
|
|
902
|
+
path: [],
|
|
903
|
+
});
|
|
904
|
+
return;
|
|
905
|
+
}
|
|
906
|
+
if (hasRef) {
|
|
907
|
+
const hasInlineStructure = ("type" in variableSchema && variableSchema.type != null) ||
|
|
908
|
+
("properties" in variableSchema && variableSchema.properties != null) ||
|
|
909
|
+
("required" in variableSchema && variableSchema.required != null) ||
|
|
910
|
+
("items" in variableSchema && variableSchema.items != null) ||
|
|
911
|
+
("oneOf" in variableSchema && variableSchema.oneOf != null);
|
|
912
|
+
const hasInlineValidation = ("minimum" in variableSchema && variableSchema.minimum !== undefined) ||
|
|
913
|
+
("maximum" in variableSchema && variableSchema.maximum !== undefined) ||
|
|
914
|
+
("minLength" in variableSchema && variableSchema.minLength !== undefined) ||
|
|
915
|
+
("maxLength" in variableSchema && variableSchema.maxLength !== undefined) ||
|
|
916
|
+
("pattern" in variableSchema && variableSchema.pattern !== undefined) ||
|
|
917
|
+
("minItems" in variableSchema && variableSchema.minItems !== undefined) ||
|
|
918
|
+
("maxItems" in variableSchema && variableSchema.maxItems !== undefined) ||
|
|
919
|
+
("uniqueItems" in variableSchema && variableSchema.uniqueItems !== undefined);
|
|
920
|
+
if (hasInlineStructure) {
|
|
921
|
+
ctx.addIssue({
|
|
922
|
+
code: zod_1.z.ZodIssueCode.custom,
|
|
923
|
+
message: "When `schema` is set, do not set `type`, `oneOf`, `properties`, `required`, or `items`.",
|
|
924
|
+
path: [],
|
|
925
|
+
});
|
|
926
|
+
}
|
|
927
|
+
if (hasInlineValidation) {
|
|
928
|
+
ctx.addIssue({
|
|
929
|
+
code: zod_1.z.ZodIssueCode.custom,
|
|
930
|
+
message: "When `schema` is set, do not set `minimum`, `maximum`, `minLength`, `maxLength`, `pattern`, `minItems`, `maxItems`, or `uniqueItems`; use the referenced schema to define these.",
|
|
931
|
+
path: [],
|
|
932
|
+
});
|
|
933
|
+
}
|
|
934
|
+
return;
|
|
935
|
+
}
|
|
936
|
+
if (!hasInline && !hasOneOf) {
|
|
937
|
+
ctx.addIssue({
|
|
938
|
+
code: zod_1.z.ZodIssueCode.custom,
|
|
939
|
+
message: "Variable schema must have either `schema` (reference to a schema key), `type` (inline schema), or `oneOf` (inline oneOf schemas).",
|
|
940
|
+
path: [],
|
|
941
|
+
});
|
|
942
|
+
return;
|
|
943
|
+
}
|
|
944
|
+
if (hasInline && hasOneOf) {
|
|
945
|
+
ctx.addIssue({
|
|
946
|
+
code: zod_1.z.ZodIssueCode.custom,
|
|
947
|
+
message: "Variable schema cannot have both `type` and `oneOf` at the top level. Use one or the other.",
|
|
948
|
+
path: [],
|
|
949
|
+
});
|
|
950
|
+
return;
|
|
951
|
+
}
|
|
551
952
|
// Validate required ⊆ properties at this level and in all nested object schemas
|
|
552
953
|
refineRequiredKeysInSchema(variableSchema, [], ctx);
|
|
553
954
|
}))
|
|
@@ -620,6 +1021,10 @@ function getFeatureZodSchema(projectConfig, conditionsZodSchema, availableAttrib
|
|
|
620
1021
|
if (!value.variablesSchema) {
|
|
621
1022
|
return;
|
|
622
1023
|
}
|
|
1024
|
+
// Every variable value is validated against its schema from variablesSchema. Sources covered:
|
|
1025
|
+
// 1. variablesSchema[key].defaultValue 2. variablesSchema[key].disabledValue
|
|
1026
|
+
// 3. variations[n].variables[key] 4. variations[n].variableOverrides[key][].value
|
|
1027
|
+
// 5. rules[env][n].variables[key] 6. force[env][n].variables[key]
|
|
623
1028
|
const variableSchemaByKey = value.variablesSchema;
|
|
624
1029
|
const variationValues = [];
|
|
625
1030
|
if (value.variations) {
|
|
@@ -631,6 +1036,21 @@ function getFeatureZodSchema(projectConfig, conditionsZodSchema, availableAttrib
|
|
|
631
1036
|
const variableKeys = Object.keys(variableSchemaByKey);
|
|
632
1037
|
variableKeys.forEach((variableKey) => {
|
|
633
1038
|
const variableSchema = variableSchemaByKey[variableKey];
|
|
1039
|
+
// When type and enum are both present, all enum values must match the type
|
|
1040
|
+
const effectiveSchema = resolveVariableSchema(variableSchema, schemasByKey);
|
|
1041
|
+
if (effectiveSchema &&
|
|
1042
|
+
effectiveSchema.type &&
|
|
1043
|
+
Array.isArray(effectiveSchema.enum) &&
|
|
1044
|
+
effectiveSchema.enum.length > 0) {
|
|
1045
|
+
(0, schema_1.refineEnumMatchesType)(effectiveSchema, ["variablesSchema", variableKey], ctx);
|
|
1046
|
+
}
|
|
1047
|
+
// Inline variable schemas: validate minimum/maximum, minLength/maxLength/pattern, minItems/maxItems/uniqueItems
|
|
1048
|
+
if (!("schema" in variableSchema) || !variableSchema.schema) {
|
|
1049
|
+
const pathPrefix = ["variablesSchema", variableKey];
|
|
1050
|
+
(0, schema_1.refineMinimumMaximum)(variableSchema, pathPrefix, ctx);
|
|
1051
|
+
(0, schema_1.refineStringLengthPattern)(variableSchema, pathPrefix, ctx);
|
|
1052
|
+
(0, schema_1.refineArrayItems)(variableSchema, pathPrefix, ctx);
|
|
1053
|
+
}
|
|
634
1054
|
if (variableKey === "variation") {
|
|
635
1055
|
ctx.addIssue({
|
|
636
1056
|
code: zod_1.z.ZodIssueCode.custom,
|
|
@@ -639,38 +1059,55 @@ function getFeatureZodSchema(projectConfig, conditionsZodSchema, availableAttrib
|
|
|
639
1059
|
});
|
|
640
1060
|
}
|
|
641
1061
|
// defaultValue
|
|
642
|
-
superRefineVariableValue(projectConfig, variableSchema, variableSchema.defaultValue, ["variablesSchema", variableKey, "defaultValue"], ctx, variableKey);
|
|
1062
|
+
superRefineVariableValue(projectConfig, variableSchema, variableSchema.defaultValue, ["variablesSchema", variableKey, "defaultValue"], ctx, variableKey, schemasByKey);
|
|
643
1063
|
// disabledValue (only when present)
|
|
644
1064
|
if (variableSchema.disabledValue !== undefined) {
|
|
645
|
-
superRefineVariableValue(projectConfig, variableSchema, variableSchema.disabledValue, ["variablesSchema", variableKey, "disabledValue"], ctx, variableKey);
|
|
1065
|
+
superRefineVariableValue(projectConfig, variableSchema, variableSchema.disabledValue, ["variablesSchema", variableKey, "disabledValue"], ctx, variableKey, schemasByKey);
|
|
646
1066
|
}
|
|
647
1067
|
});
|
|
648
|
-
// variations
|
|
1068
|
+
// variations: validate variation.variables and variation.variableOverrides (each value against its variable schema)
|
|
649
1069
|
if (value.variations) {
|
|
650
1070
|
value.variations.forEach((variation, variationN) => {
|
|
651
|
-
if (!variation.variables) {
|
|
652
|
-
return;
|
|
653
|
-
}
|
|
654
1071
|
// variations[n].variables[key]
|
|
655
|
-
|
|
656
|
-
const
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
1072
|
+
if (variation.variables) {
|
|
1073
|
+
for (const variableKey of Object.keys(variation.variables)) {
|
|
1074
|
+
const variableValue = variation.variables[variableKey];
|
|
1075
|
+
const variableSchema = variableSchemaByKey[variableKey];
|
|
1076
|
+
if (!variableSchema) {
|
|
1077
|
+
ctx.addIssue({
|
|
1078
|
+
code: zod_1.z.ZodIssueCode.custom,
|
|
1079
|
+
message: `Variable "${variableKey}" is not defined in \`variablesSchema\`.`,
|
|
1080
|
+
path: ["variations", variationN, "variables", variableKey],
|
|
1081
|
+
});
|
|
1082
|
+
}
|
|
1083
|
+
else {
|
|
1084
|
+
superRefineVariableValue(projectConfig, variableSchema, variableValue, ["variations", variationN, "variables", variableKey], ctx, variableKey, schemasByKey);
|
|
1085
|
+
}
|
|
1086
|
+
}
|
|
1087
|
+
}
|
|
1088
|
+
// variations[n].variableOverrides[key][].value (validated even when variation.variables is absent)
|
|
1089
|
+
if (variation.variableOverrides) {
|
|
1090
|
+
for (const variableKey of Object.keys(variation.variableOverrides)) {
|
|
1091
|
+
const overrides = variation.variableOverrides[variableKey];
|
|
1092
|
+
const variableSchema = variableSchemaByKey[variableKey];
|
|
1093
|
+
if (!variableSchema) {
|
|
1094
|
+
ctx.addIssue({
|
|
1095
|
+
code: zod_1.z.ZodIssueCode.custom,
|
|
1096
|
+
message: `Variable "${variableKey}" is not defined in \`variablesSchema\`.`,
|
|
1097
|
+
path: ["variations", variationN, "variableOverrides", variableKey],
|
|
1098
|
+
});
|
|
1099
|
+
}
|
|
1100
|
+
else if (Array.isArray(overrides)) {
|
|
1101
|
+
overrides.forEach((override, overrideN) => {
|
|
1102
|
+
superRefineVariableValue(projectConfig, variableSchema, override.value, [
|
|
1103
|
+
"variations",
|
|
1104
|
+
variationN,
|
|
1105
|
+
"variableOverrides",
|
|
1106
|
+
variableKey,
|
|
1107
|
+
overrideN,
|
|
1108
|
+
"value",
|
|
1109
|
+
], ctx, variableKey, schemasByKey);
|
|
1110
|
+
});
|
|
674
1111
|
}
|
|
675
1112
|
}
|
|
676
1113
|
}
|
|
@@ -689,6 +1126,7 @@ function getFeatureZodSchema(projectConfig, conditionsZodSchema, availableAttrib
|
|
|
689
1126
|
pathPrefix: ["rules", environmentKey],
|
|
690
1127
|
ctx,
|
|
691
1128
|
projectConfig,
|
|
1129
|
+
schemasByKey,
|
|
692
1130
|
});
|
|
693
1131
|
}
|
|
694
1132
|
// force
|
|
@@ -701,6 +1139,7 @@ function getFeatureZodSchema(projectConfig, conditionsZodSchema, availableAttrib
|
|
|
701
1139
|
pathPrefix: ["force", environmentKey],
|
|
702
1140
|
ctx,
|
|
703
1141
|
projectConfig,
|
|
1142
|
+
schemasByKey,
|
|
704
1143
|
});
|
|
705
1144
|
}
|
|
706
1145
|
}
|
|
@@ -717,6 +1156,7 @@ function getFeatureZodSchema(projectConfig, conditionsZodSchema, availableAttrib
|
|
|
717
1156
|
pathPrefix: ["rules"],
|
|
718
1157
|
ctx,
|
|
719
1158
|
projectConfig,
|
|
1159
|
+
schemasByKey,
|
|
720
1160
|
});
|
|
721
1161
|
}
|
|
722
1162
|
// force
|
|
@@ -729,6 +1169,7 @@ function getFeatureZodSchema(projectConfig, conditionsZodSchema, availableAttrib
|
|
|
729
1169
|
pathPrefix: ["force"],
|
|
730
1170
|
ctx,
|
|
731
1171
|
projectConfig,
|
|
1172
|
+
schemasByKey,
|
|
732
1173
|
});
|
|
733
1174
|
}
|
|
734
1175
|
}
|