@featurevisor/core 2.24.0 → 2.26.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.
Files changed (104) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/coverage/clover.xml +1499 -1476
  3. package/coverage/coverage-final.json +18 -17
  4. package/coverage/lcov-report/builder/allocator.ts.html +1 -1
  5. package/coverage/lcov-report/builder/buildDatafile.ts.html +1 -1
  6. package/coverage/lcov-report/builder/buildScopedConditions.ts.html +1 -1
  7. package/coverage/lcov-report/builder/buildScopedDatafile.ts.html +1 -1
  8. package/coverage/lcov-report/builder/buildScopedSegments.ts.html +1 -1
  9. package/coverage/lcov-report/builder/convertToV1.ts.html +1 -1
  10. package/coverage/lcov-report/builder/getFeatureRanges.ts.html +1 -1
  11. package/coverage/lcov-report/builder/hashes.ts.html +1 -1
  12. package/coverage/lcov-report/builder/index.html +1 -1
  13. package/coverage/lcov-report/builder/mutateVariables.ts.html +1 -1
  14. package/coverage/lcov-report/builder/mutator.ts.html +52 -52
  15. package/coverage/lcov-report/builder/revision.ts.html +1 -1
  16. package/coverage/lcov-report/builder/traffic.ts.html +1 -1
  17. package/coverage/lcov-report/config/index.html +1 -1
  18. package/coverage/lcov-report/config/index.ts.html +1 -1
  19. package/coverage/lcov-report/config/projectConfig.ts.html +15 -15
  20. package/coverage/lcov-report/datasource/adapter.ts.html +1 -1
  21. package/coverage/lcov-report/datasource/datasource.ts.html +18 -18
  22. package/coverage/lcov-report/datasource/filesystemAdapter.ts.html +43 -43
  23. package/coverage/lcov-report/datasource/index.html +1 -1
  24. package/coverage/lcov-report/datasource/index.ts.html +1 -1
  25. package/coverage/lcov-report/generate-code/index.html +1 -1
  26. package/coverage/lcov-report/generate-code/typescript.ts.html +1 -1
  27. package/coverage/lcov-report/index.html +18 -18
  28. package/coverage/lcov-report/linter/attributeSchema.ts.html +130 -130
  29. package/coverage/lcov-report/linter/checkCircularDependency.ts.html +11 -11
  30. package/coverage/lcov-report/linter/checkPercentageExceedingSlot.ts.html +15 -15
  31. package/coverage/lcov-report/linter/conditionSchema.ts.html +150 -150
  32. package/coverage/lcov-report/linter/featureSchema.ts.html +458 -443
  33. package/coverage/lcov-report/linter/groupSchema.ts.html +24 -27
  34. package/coverage/lcov-report/linter/index.html +83 -68
  35. package/coverage/lcov-report/linter/lintProject.ts.html +158 -158
  36. package/coverage/lcov-report/linter/mutationNotation.ts.html +104 -104
  37. package/coverage/lcov-report/linter/printError.ts.html +79 -28
  38. package/coverage/lcov-report/linter/schema.ts.html +129 -135
  39. package/coverage/lcov-report/linter/segmentSchema.ts.html +15 -9
  40. package/coverage/lcov-report/linter/testSchema.ts.html +67 -94
  41. package/coverage/lcov-report/linter/zodHelpers.ts.html +133 -0
  42. package/coverage/lcov-report/list/index.html +1 -1
  43. package/coverage/lcov-report/list/matrix.ts.html +1 -1
  44. package/coverage/lcov-report/tester/cliFormat.ts.html +6 -6
  45. package/coverage/lcov-report/tester/helpers.ts.html +1 -1
  46. package/coverage/lcov-report/tester/index.html +1 -1
  47. package/coverage/lcov-report/utils/extractKeys.ts.html +1 -1
  48. package/coverage/lcov-report/utils/git.ts.html +1 -1
  49. package/coverage/lcov-report/utils/index.html +1 -1
  50. package/coverage/lcov-report/utils/index.ts.html +1 -1
  51. package/coverage/lcov-report/utils/pretty.ts.html +1 -1
  52. package/coverage/lcov.info +3031 -2984
  53. package/lib/linter/attributeSchema.d.ts +19 -352
  54. package/lib/linter/attributeSchema.spec.js.map +1 -1
  55. package/lib/linter/conditionSchema.d.ts +1 -1
  56. package/lib/linter/conditionSchema.js +2 -3
  57. package/lib/linter/conditionSchema.js.map +1 -1
  58. package/lib/linter/conditionSchema.spec.js.map +1 -1
  59. package/lib/linter/featureSchema.d.ts +75 -964
  60. package/lib/linter/featureSchema.js +64 -53
  61. package/lib/linter/featureSchema.js.map +1 -1
  62. package/lib/linter/featureSchema.spec.js +28 -0
  63. package/lib/linter/featureSchema.spec.js.map +1 -1
  64. package/lib/linter/groupSchema.d.ts +4 -28
  65. package/lib/linter/groupSchema.js +3 -5
  66. package/lib/linter/groupSchema.js.map +1 -1
  67. package/lib/linter/lintProject.spec.js +101 -13
  68. package/lib/linter/lintProject.spec.js.map +1 -1
  69. package/lib/linter/printError.js +21 -7
  70. package/lib/linter/printError.js.map +1 -1
  71. package/lib/linter/schema.d.ts +9 -2
  72. package/lib/linter/schema.js +2 -6
  73. package/lib/linter/schema.js.map +1 -1
  74. package/lib/linter/schema.spec.js +3 -2
  75. package/lib/linter/schema.spec.js.map +1 -1
  76. package/lib/linter/segmentSchema.d.ts +1 -9
  77. package/lib/linter/segmentSchema.js +3 -1
  78. package/lib/linter/segmentSchema.js.map +1 -1
  79. package/lib/linter/segmentSchema.spec.js.map +1 -1
  80. package/lib/linter/testSchema.d.ts +16 -222
  81. package/lib/linter/testSchema.js +23 -38
  82. package/lib/linter/testSchema.js.map +1 -1
  83. package/lib/linter/testSchema.spec.d.ts +1 -0
  84. package/lib/linter/testSchema.spec.js +162 -0
  85. package/lib/linter/testSchema.spec.js.map +1 -0
  86. package/lib/linter/zodHelpers.d.ts +2 -0
  87. package/lib/linter/zodHelpers.js +15 -0
  88. package/lib/linter/zodHelpers.js.map +1 -0
  89. package/package.json +4 -3
  90. package/src/linter/attributeSchema.spec.ts +3 -3
  91. package/src/linter/conditionSchema.spec.ts +3 -3
  92. package/src/linter/conditionSchema.ts +4 -4
  93. package/src/linter/featureSchema.spec.ts +39 -4
  94. package/src/linter/featureSchema.ts +82 -77
  95. package/src/linter/groupSchema.ts +11 -12
  96. package/src/linter/lintProject.spec.ts +121 -13
  97. package/src/linter/printError.ts +27 -10
  98. package/src/linter/schema.spec.ts +12 -11
  99. package/src/linter/schema.ts +7 -9
  100. package/src/linter/segmentSchema.spec.ts +5 -5
  101. package/src/linter/segmentSchema.ts +3 -1
  102. package/src/linter/testSchema.spec.ts +193 -0
  103. package/src/linter/testSchema.ts +36 -45
  104. package/src/linter/zodHelpers.ts +16 -0
@@ -2,9 +2,10 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getTestsZodSchema = getTestsZodSchema;
4
4
  const zod_1 = require("zod");
5
+ const zodHelpers_1 = require("./zodHelpers");
5
6
  function getTestsZodSchema(projectConfig, availableFeatureKeys, availableSegmentKeys) {
6
7
  const scopeNames = projectConfig.scopes ? projectConfig.scopes.map((scope) => scope.name) : [];
7
- const matrixZodSchema = zod_1.z.record(zod_1.z.array(zod_1.z.union([
8
+ const matrixZodSchema = zod_1.z.record(zod_1.z.string(), zod_1.z.array(zod_1.z.union([
8
9
  // allowed values in arrays
9
10
  zod_1.z.string(),
10
11
  zod_1.z.number(),
@@ -13,14 +14,12 @@ function getTestsZodSchema(projectConfig, availableFeatureKeys, availableSegment
13
14
  ])));
14
15
  const segmentTestZodSchema = zod_1.z
15
16
  .object({
16
- segment: zod_1.z.string().refine((value) => availableSegmentKeys.includes(value), (value) => ({
17
- message: `Unknown segment "${value}"`,
18
- })),
17
+ segment: (0, zodHelpers_1.refineWithMessage)(zod_1.z.string(), (value) => availableSegmentKeys.includes(value), (value) => `Unknown segment "${value}"`),
19
18
  assertions: zod_1.z.array(zod_1.z
20
19
  .object({
21
20
  matrix: matrixZodSchema.optional(),
22
21
  description: zod_1.z.string().optional(),
23
- context: zod_1.z.record(zod_1.z.unknown()),
22
+ context: zod_1.z.record(zod_1.z.string(), zod_1.z.unknown()),
24
23
  expectedToMatch: zod_1.z.boolean(),
25
24
  })
26
25
  .strict()),
@@ -28,9 +27,7 @@ function getTestsZodSchema(projectConfig, availableFeatureKeys, availableSegment
28
27
  .strict();
29
28
  const featureTestZodSchema = zod_1.z
30
29
  .object({
31
- feature: zod_1.z.string().refine((value) => availableFeatureKeys.includes(value), (value) => ({
32
- message: `Unknown feature "${value}"`,
33
- })),
30
+ feature: (0, zodHelpers_1.refineWithMessage)(zod_1.z.string(), (value) => availableFeatureKeys.includes(value), (value) => `Unknown feature "${value}"`),
34
31
  assertions: zod_1.z.array(zod_1.z
35
32
  .object({
36
33
  matrix: matrixZodSchema.optional(),
@@ -41,7 +38,7 @@ function getTestsZodSchema(projectConfig, availableFeatureKeys, availableSegment
41
38
  zod_1.z.string(),
42
39
  ]),
43
40
  environment: Array.isArray(projectConfig.environments)
44
- ? zod_1.z.string().refine((value) => {
41
+ ? (0, zodHelpers_1.refineWithMessage)(zod_1.z.string(), (value) => {
45
42
  if (value.indexOf("${{") === 0) {
46
43
  // allow unknown strings for matrix
47
44
  return true;
@@ -52,52 +49,40 @@ function getTestsZodSchema(projectConfig, availableFeatureKeys, availableSegment
52
49
  return true;
53
50
  }
54
51
  return false;
55
- }, (value) => ({
56
- message: `Unknown environment "${value}"`,
57
- }))
52
+ }, (value) => `Unknown environment "${value}"`)
58
53
  : zod_1.z.never().optional(),
59
- tag: zod_1.z
60
- .string()
61
- .refine((value) => projectConfig.tags.includes(value), (value) => ({
62
- message: `Unknown tag "${value}"`,
63
- }))
64
- .optional(),
65
- scope: zod_1.z
66
- .string()
67
- .refine((value) => scopeNames.includes(value), (value) => ({
68
- message: `Unknown scope "${value}"`,
69
- }))
70
- .optional(),
54
+ tag: (0, zodHelpers_1.refineWithMessage)(zod_1.z.string(), (value) => projectConfig.tags.includes(value), (value) => `Unknown tag "${value}"`).optional(),
55
+ scope: (0, zodHelpers_1.refineWithMessage)(zod_1.z.string(), (value) => scopeNames.includes(value), (value) => `Unknown scope "${value}"`).optional(),
71
56
  // parent
72
- sticky: zod_1.z.record(zod_1.z.record(zod_1.z.any())).optional(),
73
- context: zod_1.z.record(zod_1.z.unknown()).optional(),
57
+ sticky: zod_1.z.record(zod_1.z.string(), zod_1.z.record(zod_1.z.string(), zod_1.z.any())).optional(),
58
+ context: zod_1.z.record(zod_1.z.string(), zod_1.z.unknown()).optional(),
74
59
  defaultVariationValue: zod_1.z.string().optional(),
75
- defaultVariableValues: zod_1.z.record(zod_1.z.unknown()).optional(),
60
+ defaultVariableValues: zod_1.z.record(zod_1.z.string(), zod_1.z.unknown()).optional(),
76
61
  expectedToBeEnabled: zod_1.z.boolean().optional(),
77
62
  expectedVariation: zod_1.z.string().nullable().optional(),
78
- expectedVariables: zod_1.z.record(zod_1.z.unknown()).optional(),
63
+ expectedVariables: zod_1.z.record(zod_1.z.string(), zod_1.z.unknown()).optional(),
79
64
  expectedEvaluations: zod_1.z
80
65
  .object({
81
- flag: zod_1.z.record(zod_1.z.any()).optional(),
82
- variation: zod_1.z.record(zod_1.z.any()).optional(),
83
- variables: zod_1.z.record(zod_1.z.record(zod_1.z.any())).optional(),
66
+ flag: zod_1.z.record(zod_1.z.string(), zod_1.z.any()).optional(),
67
+ variation: zod_1.z.record(zod_1.z.string(), zod_1.z.any()).optional(),
68
+ variables: zod_1.z.record(zod_1.z.string(), zod_1.z.record(zod_1.z.string(), zod_1.z.any())).optional(),
84
69
  })
85
70
  .optional(),
86
71
  children: zod_1.z
87
72
  .array(zod_1.z.object({
88
73
  // copied from parent
89
- sticky: zod_1.z.record(zod_1.z.record(zod_1.z.any())).optional(),
90
- context: zod_1.z.record(zod_1.z.unknown()).optional(),
74
+ sticky: zod_1.z.record(zod_1.z.string(), zod_1.z.record(zod_1.z.string(), zod_1.z.any())).optional(),
75
+ context: zod_1.z.record(zod_1.z.string(), zod_1.z.unknown()).optional(),
91
76
  defaultVariationValue: zod_1.z.string().optional(),
92
- defaultVariableValues: zod_1.z.record(zod_1.z.unknown()).optional(),
77
+ defaultVariableValues: zod_1.z.record(zod_1.z.string(), zod_1.z.unknown()).optional(),
93
78
  expectedToBeEnabled: zod_1.z.boolean().optional(),
94
79
  expectedVariation: zod_1.z.string().nullable().optional(),
95
- expectedVariables: zod_1.z.record(zod_1.z.unknown()).optional(),
80
+ expectedVariables: zod_1.z.record(zod_1.z.string(), zod_1.z.unknown()).optional(),
96
81
  expectedEvaluations: zod_1.z
97
82
  .object({
98
- flag: zod_1.z.record(zod_1.z.any()).optional(),
99
- variation: zod_1.z.record(zod_1.z.any()).optional(),
100
- variables: zod_1.z.record(zod_1.z.record(zod_1.z.any())).optional(),
83
+ flag: zod_1.z.record(zod_1.z.string(), zod_1.z.any()).optional(),
84
+ variation: zod_1.z.record(zod_1.z.string(), zod_1.z.any()).optional(),
85
+ variables: zod_1.z.record(zod_1.z.string(), zod_1.z.record(zod_1.z.string(), zod_1.z.any())).optional(),
101
86
  })
102
87
  .optional(),
103
88
  }))
@@ -1 +1 @@
1
- {"version":3,"file":"testSchema.js","sourceRoot":"","sources":["../../src/linter/testSchema.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"testSchema.js","sourceRoot":"","sources":["../../src/linter/testSchema.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,162 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const printError_1 = require("./printError");
4
+ const testSchema_1 = require("./testSchema");
5
+ function minimalProjectConfig(overrides = {}) {
6
+ return {
7
+ featuresDirectoryPath: "",
8
+ segmentsDirectoryPath: "",
9
+ attributesDirectoryPath: "",
10
+ groupsDirectoryPath: "",
11
+ schemasDirectoryPath: "",
12
+ testsDirectoryPath: "",
13
+ stateDirectoryPath: "",
14
+ datafilesDirectoryPath: "",
15
+ datafileNamePattern: "",
16
+ revisionFileName: "",
17
+ siteExportDirectoryPath: "",
18
+ environmentsDirectoryPath: "",
19
+ environments: ["staging", "production"],
20
+ splitByEnvironment: false,
21
+ tags: ["all", "beta"],
22
+ adapter: {},
23
+ plugins: [],
24
+ defaultBucketBy: "userId",
25
+ parser: "yml",
26
+ prettyState: true,
27
+ prettyDatafile: false,
28
+ stringify: true,
29
+ ...overrides,
30
+ };
31
+ }
32
+ function getSchema(projectConfig = minimalProjectConfig()) {
33
+ return (0, testSchema_1.getTestsZodSchema)(projectConfig, ["checkout"], ["desktop"]);
34
+ }
35
+ function parseTest(input) {
36
+ return getSchema().safeParse(input);
37
+ }
38
+ function expectTestSuccess(input) {
39
+ const result = parseTest(input);
40
+ expect(result.success).toBe(true);
41
+ if (!result.success) {
42
+ const error = result.error;
43
+ throw new Error(error.issues.map((issue) => issue.message).join("; "));
44
+ }
45
+ }
46
+ function expectTestFailure(input, messageSubstring) {
47
+ const result = parseTest(input);
48
+ expect(result.success).toBe(false);
49
+ if (result.success) {
50
+ throw new Error("Expected test schema to fail");
51
+ }
52
+ const error = result.error;
53
+ expect(error.issues.map((issue) => issue.message).join(" ")).toContain(messageSubstring);
54
+ return error;
55
+ }
56
+ describe("testSchema.ts :: getTestsZodSchema", () => {
57
+ it("accepts a valid feature test with matrix, context, sticky, and expected evaluations", () => {
58
+ expectTestSuccess({
59
+ feature: "checkout",
60
+ assertions: [
61
+ {
62
+ matrix: {
63
+ country: ["nl", "de"],
64
+ loggedIn: [true, false],
65
+ score: [1, 2],
66
+ empty: [null],
67
+ },
68
+ description: "feature assertion",
69
+ at: "${{ score }}",
70
+ environment: "staging",
71
+ tag: "all",
72
+ sticky: {
73
+ flag: { checkout: "cached" },
74
+ },
75
+ context: {
76
+ userId: "user-1",
77
+ },
78
+ defaultVariableValues: {
79
+ title: "Fallback",
80
+ },
81
+ expectedToBeEnabled: true,
82
+ expectedVariation: "control",
83
+ expectedVariables: {
84
+ title: "Checkout",
85
+ },
86
+ expectedEvaluations: {
87
+ flag: { reason: "rule" },
88
+ variation: { reason: "bucketed" },
89
+ variables: { title: { reason: "default" } },
90
+ },
91
+ children: [
92
+ {
93
+ context: {
94
+ userId: "child-1",
95
+ },
96
+ expectedToBeEnabled: false,
97
+ expectedVariation: null,
98
+ },
99
+ ],
100
+ },
101
+ ],
102
+ });
103
+ });
104
+ it("accepts matrix placeholders for environment values", () => {
105
+ expectTestSuccess({
106
+ feature: "checkout",
107
+ assertions: [
108
+ {
109
+ matrix: {
110
+ environment: ["staging", "production"],
111
+ },
112
+ at: 1,
113
+ environment: "${{ environment }}",
114
+ },
115
+ ],
116
+ });
117
+ });
118
+ it("rejects unknown environments with a precise path", () => {
119
+ const error = expectTestFailure({
120
+ feature: "checkout",
121
+ assertions: [
122
+ {
123
+ at: 1,
124
+ environment: "qa",
125
+ },
126
+ ],
127
+ }, 'Unknown environment "qa"');
128
+ expect(error.issues.some((issue) => issue.path.join(".") === "assertions.0.environment")).toBe(true);
129
+ });
130
+ it("rejects unknown feature and segment keys", () => {
131
+ expectTestFailure({
132
+ feature: "not-real",
133
+ assertions: [{ at: 1, environment: "staging" }],
134
+ }, 'Unknown feature "not-real"');
135
+ expectTestFailure({
136
+ segment: "not-real",
137
+ assertions: [
138
+ {
139
+ context: {},
140
+ expectedToMatch: true,
141
+ },
142
+ ],
143
+ }, 'Unknown segment "not-real"');
144
+ });
145
+ it("rejects invalid matrix values", () => {
146
+ const error = expectTestFailure({
147
+ feature: "checkout",
148
+ assertions: [
149
+ {
150
+ matrix: {
151
+ country: [{ code: "nl" }],
152
+ },
153
+ at: 1,
154
+ environment: "staging",
155
+ },
156
+ ],
157
+ }, "Invalid input");
158
+ const lintIssues = (0, printError_1.getLintIssuesFromZodError)(error);
159
+ expect(lintIssues.some((issue) => issue.path.join(".").includes("matrix.country.0"))).toBe(true);
160
+ });
161
+ });
162
+ //# sourceMappingURL=testSchema.spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"testSchema.spec.js","sourceRoot":"","sources":["../../src/linter/testSchema.spec.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import { z } from "zod";
2
+ export declare function refineWithMessage<T>(schema: z.ZodType<T>, predicate: (value: T) => boolean, getMessage: (value: T) => string): z.ZodType<T, unknown, z.core.$ZodTypeInternals<T, unknown>>;
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.refineWithMessage = refineWithMessage;
4
+ const zod_1 = require("zod");
5
+ function refineWithMessage(schema, predicate, getMessage) {
6
+ return schema.superRefine((value, ctx) => {
7
+ if (!predicate(value)) {
8
+ ctx.addIssue({
9
+ code: zod_1.z.ZodIssueCode.custom,
10
+ message: getMessage(value),
11
+ });
12
+ }
13
+ });
14
+ }
15
+ //# sourceMappingURL=zodHelpers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"zodHelpers.js","sourceRoot":"","sources":["../../src/linter/zodHelpers.ts"],"names":[],"mappings":";;AAEA,8CAaC;AAfD,6BAAwB;AAExB,SAAgB,iBAAiB,CAC/B,MAAoB,EACpB,SAAgC,EAChC,UAAgC;IAEhC,OAAO,MAAM,CAAC,WAAW,CAAC,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE;QACvC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC;YACtB,GAAG,CAAC,QAAQ,CAAC;gBACX,IAAI,EAAE,OAAC,CAAC,YAAY,CAAC,MAAM;gBAC3B,OAAO,EAAE,UAAU,CAAC,KAAK,CAAC;aAC3B,CAAC,CAAC;QACL,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@featurevisor/core",
3
- "version": "2.24.0",
3
+ "version": "2.26.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",
@@ -40,13 +40,14 @@
40
40
  },
41
41
  "license": "MIT",
42
42
  "dependencies": {
43
+ "@featurevisor/parsers": "2.24.0",
43
44
  "@featurevisor/sdk": "2.23.0",
44
45
  "@featurevisor/site": "2.23.0",
45
46
  "@featurevisor/types": "2.23.0",
46
47
  "axios": "^1.3.4",
47
48
  "tar": "^7.5.7",
48
49
  "yargs": "^17.7.2",
49
- "zod": "^3.22.4"
50
+ "zod": "^4.0.17"
50
51
  },
51
- "gitHead": "f4f4cb31622b5384aec16ae2299713878946e340"
52
+ "gitHead": "27068c0b515c56a11bea79bacd128a64d7543325"
52
53
  }
@@ -2,7 +2,7 @@ import { z } from "zod";
2
2
 
3
3
  import { getAttributeZodSchema } from "./attributeSchema";
4
4
 
5
- function parseAttribute(input: unknown): z.SafeParseReturnType<unknown, unknown> {
5
+ function parseAttribute(input: unknown): z.ZodSafeParseResult<unknown> {
6
6
  return getAttributeZodSchema().safeParse(input);
7
7
  }
8
8
 
@@ -10,7 +10,7 @@ function expectAttributeSuccess(input: unknown): void {
10
10
  const result = parseAttribute(input);
11
11
  expect(result.success).toBe(true);
12
12
  if (!result.success) {
13
- const error = (result as z.SafeParseError<unknown>).error;
13
+ const error = (result as z.ZodSafeParseError<unknown>).error;
14
14
  const msg = error.issues.map((issue) => issue.message).join("; ");
15
15
  throw new Error(`Expected attribute to pass: ${msg}`);
16
16
  }
@@ -23,7 +23,7 @@ function expectAttributeFailure(input: unknown, messageSubstring?: string): z.Zo
23
23
  throw new Error("Expected attribute to fail");
24
24
  }
25
25
 
26
- const error = (result as z.SafeParseError<unknown>).error;
26
+ const error = (result as z.ZodSafeParseError<unknown>).error;
27
27
 
28
28
  if (messageSubstring) {
29
29
  const messages = error.issues.map((issue) => issue.message).join(" ");
@@ -115,7 +115,7 @@ function getConditionsSchema() {
115
115
  return getConditionsZodSchema(minimalProjectConfig(), TEST_ATTRIBUTES);
116
116
  }
117
117
 
118
- function parseConditions(input: unknown): z.SafeParseReturnType<unknown, unknown> {
118
+ function parseConditions(input: unknown): z.ZodSafeParseResult<unknown> {
119
119
  return getConditionsSchema().safeParse(input);
120
120
  }
121
121
 
@@ -123,7 +123,7 @@ function expectConditionsSuccess(input: unknown): void {
123
123
  const result = parseConditions(input);
124
124
  expect(result.success).toBe(true);
125
125
  if (!result.success) {
126
- const err = (result as z.SafeParseError<unknown>).error;
126
+ const err = (result as z.ZodSafeParseError<unknown>).error;
127
127
  const msg = err.issues.map((i) => `${i.path.join(".")}: ${i.message}`).join("; ");
128
128
  throw new Error(`Expected conditions to pass: ${msg}`);
129
129
  }
@@ -133,7 +133,7 @@ function expectConditionsFailure(input: unknown, messageSubstring?: string): z.Z
133
133
  const result = parseConditions(input);
134
134
  expect(result.success).toBe(false);
135
135
  if (result.success) throw new Error("Expected conditions to fail");
136
- const err = (result as z.SafeParseError<unknown>).error;
136
+ const err = (result as z.ZodSafeParseError<unknown>).error;
137
137
  if (messageSubstring) {
138
138
  const messages = err.issues
139
139
  .map((i) => (typeof i.message === "string" ? i.message : ""))
@@ -2,6 +2,7 @@ import type { Attribute, AttributeProperty, Schema } from "@featurevisor/types";
2
2
  import { z } from "zod";
3
3
 
4
4
  import { ProjectConfig } from "../config";
5
+ import { refineWithMessage } from "./zodHelpers";
5
6
 
6
7
  const commonOperators: [string, ...string[]] = ["equals", "notEquals"];
7
8
  const numericOperators = ["greaterThan", "greaterThanOrEquals", "lessThan", "lessThanOrEquals"];
@@ -551,11 +552,10 @@ export function getConditionsZodSchema(
551
552
  ) {
552
553
  const plainConditionZodSchema = z
553
554
  .object({
554
- attribute: z.string().refine(
555
+ attribute: refineWithMessage(
556
+ z.string(),
555
557
  (value) => resolveAttributePath(value, attributesByKey, schemasByKey) !== null,
556
- (value) => ({
557
- message: `Unknown attribute "${value}"`,
558
- }),
558
+ (value) => `Unknown attribute "${value}"`,
559
559
  ),
560
560
  operator: z.enum([
561
561
  ...commonOperators,
@@ -135,7 +135,7 @@ function baseFeature(overrides: Record<string, unknown> = {}) {
135
135
  };
136
136
  }
137
137
 
138
- function parseFeature(feature: unknown): z.SafeParseReturnType<unknown, unknown> {
138
+ function parseFeature(feature: unknown): z.ZodSafeParseResult<unknown> {
139
139
  return getFeatureSchema().safeParse(feature);
140
140
  }
141
141
 
@@ -143,7 +143,7 @@ function expectParseSuccess(feature: unknown): void {
143
143
  const result = parseFeature(feature);
144
144
  expect(result.success).toBe(true);
145
145
  if (!result.success) {
146
- const err = (result as z.SafeParseError<unknown>).error;
146
+ const err = (result as z.ZodSafeParseError<unknown>).error;
147
147
  const msg = err.issues.map((i) => `${i.path.join(".")}: ${i.message}`).join("; ");
148
148
  throw new Error(`Expected success but got: ${msg}`);
149
149
  }
@@ -153,7 +153,7 @@ function expectParseFailure(feature: unknown, messageSubstring?: string): z.ZodE
153
153
  const result = parseFeature(feature);
154
154
  expect(result.success).toBe(false);
155
155
  if (result.success) throw new Error("Expected parse failure");
156
- const err = (result as z.SafeParseError<unknown>).error;
156
+ const err = (result as z.ZodSafeParseError<unknown>).error;
157
157
  if (messageSubstring) {
158
158
  const messages = err.issues
159
159
  .map((i) => (typeof i.message === "string" ? i.message : ""))
@@ -317,7 +317,7 @@ describe("featureSchema.ts :: getFeatureZodSchema (variablesSchema and variable
317
317
  );
318
318
  expect(result.success).toBe(false);
319
319
  if (result.success) return;
320
- const messages = (result as z.SafeParseError<unknown>).error.issues
320
+ const messages = (result as z.ZodSafeParseError<unknown>).error.issues
321
321
  .map((i) => (typeof i.message === "string" ? i.message : ""))
322
322
  .join(" ");
323
323
  expect(messages).toContain("could not be loaded");
@@ -1099,6 +1099,41 @@ describe("featureSchema.ts :: getFeatureZodSchema (variablesSchema and variable
1099
1099
  });
1100
1100
  });
1101
1101
 
1102
+ describe("environment maps", () => {
1103
+ it("allows a subset of configured environments in rules, force, and expose", () => {
1104
+ expectParseSuccess(
1105
+ baseFeature({
1106
+ expose: {
1107
+ staging: true,
1108
+ },
1109
+ force: {
1110
+ staging: [{ segments: "*", variation: "control" }],
1111
+ },
1112
+ variations: [
1113
+ { value: "control", weight: 50 },
1114
+ { value: "treatment", weight: 50 },
1115
+ ],
1116
+ rules: {
1117
+ staging: [{ key: "r1", segments: "*", percentage: 100 }],
1118
+ },
1119
+ }),
1120
+ );
1121
+ });
1122
+
1123
+ it("rejects unknown environment keys in rules", () => {
1124
+ const err = expectParseFailure(
1125
+ baseFeature({
1126
+ rules: {
1127
+ qa: [{ key: "r1", segments: "*", percentage: 100 }],
1128
+ },
1129
+ }),
1130
+ );
1131
+
1132
+ expect(err.issues.some((issue) => issue.path.join(".").includes("rules"))).toBe(true);
1133
+ expect(err.issues.some((issue) => issue.code === "invalid_key")).toBe(true);
1134
+ });
1135
+ });
1136
+
1102
1137
  describe("oneOf: value must match exactly one branch", () => {
1103
1138
  it("rejects defaultValue that matches no oneOf branch", () => {
1104
1139
  expectParseFailure(