@showwhat/core 2.0.0 → 2.1.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/dist/index.js CHANGED
@@ -74,9 +74,32 @@ var ConditionError = class extends ShowwhatError {
74
74
  this.name = "ConditionError";
75
75
  }
76
76
  };
77
+ var UnknownConditionTypeError = class extends ShowwhatError {
78
+ constructor(conditionType, condition) {
79
+ super(`Unknown condition type "${conditionType}".`);
80
+ this.conditionType = conditionType;
81
+ this.condition = condition;
82
+ this.name = "UnknownConditionTypeError";
83
+ }
84
+ };
85
+
86
+ // src/conditions/types.ts
87
+ import { z as z2 } from "zod";
88
+
89
+ // src/schemas/value.ts
90
+ import { z } from "zod";
91
+ var DataPrimitiveSchema = z.union([z.string(), z.number(), z.boolean()]);
92
+ var DataValueSchema = z.union([
93
+ DataPrimitiveSchema,
94
+ z.array(DataPrimitiveSchema),
95
+ z.lazy(() => z.record(z.string(), DataValueSchema))
96
+ ]);
77
97
 
78
98
  // src/conditions/types.ts
99
+ var AnnotationValueSchema = DataValueSchema;
100
+ var AnnotationsSchema = z2.record(z2.string(), AnnotationValueSchema);
79
101
  var defaultCreateRegex = (pattern) => new RegExp(pattern);
102
+ var FALLBACK_EVALUATOR_KEY = /* @__PURE__ */ Symbol("fallback");
80
103
  var noConditionEvaluator = async () => false;
81
104
 
82
105
  // src/conditions/string.ts
@@ -93,7 +116,8 @@ async function evaluateString(condition, ctx, createRegex = defaultCreateRegex)
93
116
  case "in":
94
117
  return condition.value.includes(actual);
95
118
  case "nin":
96
- return !condition.value.includes(actual);
119
+ const incl = condition.value.includes(actual);
120
+ return !incl;
97
121
  case "regex": {
98
122
  const pattern = condition.value;
99
123
  let regex;
@@ -141,8 +165,8 @@ async function evaluateNumber(condition, ctx) {
141
165
  var numberEvaluator = ({ condition, context }) => evaluateNumber(condition, context);
142
166
 
143
167
  // src/conditions/utils.ts
144
- import { z } from "zod";
145
- var IsoUtcDatetime = z.iso.datetime();
168
+ import { z as z3 } from "zod";
169
+ var IsoUtcDatetime = z3.iso.datetime();
146
170
  function parseDate(key, raw) {
147
171
  if (!IsoUtcDatetime.safeParse(raw).success) {
148
172
  throw new InvalidContextError(key, raw);
@@ -152,9 +176,13 @@ function parseDate(key, raw) {
152
176
 
153
177
  // src/conditions/datetime.ts
154
178
  async function evaluateDatetime(condition, ctx) {
155
- if (!Object.hasOwn(ctx, condition.key)) return false;
179
+ if (!Object.hasOwn(ctx, condition.key)) {
180
+ return false;
181
+ }
156
182
  const raw = ctx[condition.key];
157
- if (typeof raw !== "string") return false;
183
+ if (typeof raw !== "string") {
184
+ return false;
185
+ }
158
186
  const actual = parseDate(condition.key, raw);
159
187
  const expected = new Date(condition.value);
160
188
  switch (condition.op) {
@@ -174,14 +202,21 @@ var datetimeEvaluator = ({ condition, context }) => evaluateDatetime(condition,
174
202
 
175
203
  // src/conditions/bool.ts
176
204
  async function evaluateBool(condition, ctx) {
177
- if (!Object.hasOwn(ctx, condition.key)) return false;
205
+ if (!Object.hasOwn(ctx, condition.key)) {
206
+ return false;
207
+ }
178
208
  const raw = ctx[condition.key];
179
209
  if (typeof raw === "boolean") {
180
210
  return raw === condition.value;
181
211
  }
182
- if (typeof raw === "string") {
183
- if (raw === "true") return condition.value === true;
184
- if (raw === "false") return condition.value === false;
212
+ if (typeof raw !== "string") {
213
+ return false;
214
+ }
215
+ if (raw === "true") {
216
+ return condition.value === true;
217
+ }
218
+ if (raw === "false") {
219
+ return condition.value === false;
185
220
  }
186
221
  return false;
187
222
  }
@@ -224,139 +259,6 @@ async function evaluateEndAt(condition, ctx) {
224
259
  }
225
260
  var endAtEvaluator = ({ condition, context }) => evaluateEndAt(condition, context);
226
261
 
227
- // src/schemas/condition.ts
228
- import { z as z2 } from "zod";
229
- var PRIMITIVE_CONDITION_TYPES = {
230
- string: "string",
231
- number: "number",
232
- bool: "bool",
233
- datetime: "datetime"
234
- };
235
- var CONDITION_TYPES = {
236
- ...PRIMITIVE_CONDITION_TYPES,
237
- env: "env",
238
- startAt: "startAt",
239
- endAt: "endAt",
240
- and: "and",
241
- or: "or"
242
- };
243
- var CONTEXT_KEYS = {
244
- env: "env",
245
- at: "at"
246
- };
247
- var StringConditionSchema = z2.object({
248
- id: z2.string().optional(),
249
- type: z2.literal("string"),
250
- key: z2.string().min(1),
251
- op: z2.enum(["eq", "neq", "in", "nin", "regex"]),
252
- value: z2.union([z2.string(), z2.array(z2.string())])
253
- }).superRefine((val, ctx) => {
254
- const isArrayOp = val.op === "in" || val.op === "nin";
255
- const isArray = Array.isArray(val.value);
256
- if (isArrayOp && !isArray) {
257
- ctx.addIssue({
258
- code: "custom",
259
- message: `"${val.op}" operator requires an array value`,
260
- path: ["value"]
261
- });
262
- }
263
- if (!isArrayOp && isArray) {
264
- ctx.addIssue({
265
- code: "custom",
266
- message: `"${val.op}" operator requires a string value`,
267
- path: ["value"]
268
- });
269
- }
270
- });
271
- var NumberConditionSchema = z2.object({
272
- id: z2.string().optional(),
273
- type: z2.literal("number"),
274
- key: z2.string().min(1),
275
- op: z2.enum(["eq", "neq", "gt", "gte", "lt", "lte", "in", "nin"]),
276
- value: z2.union([z2.number(), z2.array(z2.number())])
277
- }).superRefine((val, ctx) => {
278
- const isArrayOp = val.op === "in" || val.op === "nin";
279
- const isArray = Array.isArray(val.value);
280
- if (isArrayOp && !isArray) {
281
- ctx.addIssue({
282
- code: "custom",
283
- message: `"${val.op}" operator requires an array value`,
284
- path: ["value"]
285
- });
286
- }
287
- if (!isArrayOp && isArray) {
288
- ctx.addIssue({
289
- code: "custom",
290
- message: `"${val.op}" operator requires a number value`,
291
- path: ["value"]
292
- });
293
- }
294
- });
295
- var DatetimeConditionSchema = z2.object({
296
- id: z2.string().optional(),
297
- type: z2.literal("datetime"),
298
- key: z2.string().min(1),
299
- op: z2.enum(["eq", "gt", "gte", "lt", "lte"]),
300
- value: z2.iso.datetime({ message: '"datetime" must be a valid ISO 8601 datetime' })
301
- });
302
- var BoolConditionSchema = z2.object({
303
- id: z2.string().optional(),
304
- type: z2.literal("bool"),
305
- key: z2.string().min(1),
306
- op: z2.literal("eq").optional(),
307
- value: z2.boolean()
308
- });
309
- var EnvConditionSchema = z2.object({
310
- id: z2.string().optional(),
311
- type: z2.literal("env"),
312
- op: z2.literal("eq").optional(),
313
- value: z2.union([z2.string(), z2.array(z2.string())])
314
- });
315
- var StartAtConditionSchema = z2.object({
316
- id: z2.string().optional(),
317
- type: z2.literal("startAt"),
318
- value: z2.iso.datetime({ message: '"startAt" must be a valid ISO 8601 datetime' })
319
- });
320
- var EndAtConditionSchema = z2.object({
321
- id: z2.string().optional(),
322
- type: z2.literal("endAt"),
323
- value: z2.iso.datetime({ message: '"endAt" must be a valid ISO 8601 datetime' })
324
- });
325
- var BuiltinConditionSchema = z2.discriminatedUnion("type", [
326
- StringConditionSchema,
327
- NumberConditionSchema,
328
- DatetimeConditionSchema,
329
- BoolConditionSchema,
330
- EnvConditionSchema,
331
- StartAtConditionSchema,
332
- EndAtConditionSchema
333
- ]);
334
- var AndConditionSchema = z2.object({
335
- id: z2.string().optional(),
336
- type: z2.literal("and"),
337
- conditions: z2.array(z2.lazy(() => ConditionSchema)).min(1)
338
- });
339
- var OrConditionSchema = z2.object({
340
- id: z2.string().optional(),
341
- type: z2.literal("or"),
342
- conditions: z2.array(z2.lazy(() => ConditionSchema)).min(1)
343
- });
344
- var BLOCKED_OPEN_UNION_TYPES = new Set(Object.values(CONDITION_TYPES));
345
- var ConditionSchema = z2.union([
346
- BuiltinConditionSchema,
347
- AndConditionSchema,
348
- OrConditionSchema,
349
- z2.looseObject({ type: z2.string() }).refine((val) => !BLOCKED_OPEN_UNION_TYPES.has(val.type), {
350
- message: "Reserved condition type"
351
- })
352
- ]);
353
- function isAndCondition(c) {
354
- return c.type === CONDITION_TYPES.and;
355
- }
356
- function isOrCondition(c) {
357
- return c.type === CONDITION_TYPES.or;
358
- }
359
-
360
262
  // src/logger.ts
361
263
  var noopLogger = {
362
264
  debug() {
@@ -369,7 +271,7 @@ var noopLogger = {
369
271
  }
370
272
  };
371
273
 
372
- // src/conditions/composite.ts
274
+ // src/conditions/evaluate.ts
373
275
  async function evaluateCondition({
374
276
  condition,
375
277
  context,
@@ -378,71 +280,22 @@ async function evaluateCondition({
378
280
  deps = {},
379
281
  depth = "",
380
282
  logger = noopLogger,
381
- fallback,
382
283
  createRegex = defaultCreateRegex
383
284
  }) {
384
- if (isAndCondition(condition)) {
385
- for (let i = 0; i < condition.conditions.length; i++) {
386
- const childDepth = depth === "" ? `${i}` : `${depth}.${i}`;
387
- const result2 = await evaluateCondition({
388
- condition: condition.conditions[i],
389
- context,
390
- evaluators,
391
- annotations,
392
- deps,
393
- depth: childDepth,
394
- logger,
395
- fallback,
396
- createRegex
397
- });
398
- if (!result2) {
399
- logger.debug("and condition short-circuited (child returned false)", {
400
- childType: condition.conditions[i].type,
401
- depth: childDepth
402
- });
403
- return false;
404
- }
405
- }
406
- return true;
407
- }
408
- if (isOrCondition(condition)) {
409
- for (let i = 0; i < condition.conditions.length; i++) {
410
- const childDepth = depth === "" ? `${i}` : `${depth}.${i}`;
411
- const result2 = await evaluateCondition({
412
- condition: condition.conditions[i],
413
- context,
414
- evaluators,
415
- annotations,
416
- deps,
417
- depth: childDepth,
418
- logger,
419
- fallback,
420
- createRegex
421
- });
422
- if (result2) {
423
- logger.debug("or condition short-circuited (child returned true)", {
424
- childType: condition.conditions[i].type,
425
- depth: childDepth
426
- });
427
- return true;
428
- }
429
- }
430
- return false;
431
- }
432
- const evaluator = evaluators[condition.type];
285
+ const evaluator = evaluators[condition.type] ?? evaluators[FALLBACK_EVALUATOR_KEY];
433
286
  if (!evaluator) {
434
- if (fallback) {
435
- const result2 = await fallback({ condition, context, annotations, deps, depth, createRegex });
436
- logger.debug("condition evaluated (fallback)", {
437
- type: condition.type,
438
- depth,
439
- result: result2
440
- });
441
- return result2;
442
- }
443
- throw new ShowwhatError(`Unknown condition type "${condition.type}".`);
287
+ throw new UnknownConditionTypeError(condition.type, condition);
444
288
  }
445
- const result = await evaluator({ condition, context, annotations, deps, depth, createRegex });
289
+ const result = await evaluator({
290
+ condition,
291
+ context,
292
+ annotations,
293
+ deps,
294
+ depth,
295
+ createRegex,
296
+ logger,
297
+ evaluators
298
+ });
446
299
  logger.debug("condition evaluated", {
447
300
  type: condition.type,
448
301
  depth,
@@ -451,6 +304,74 @@ async function evaluateCondition({
451
304
  return result;
452
305
  }
453
306
 
307
+ // src/conditions/and.ts
308
+ var andEvaluator = async (args) => {
309
+ const { conditions } = args.condition;
310
+ const { depth } = args;
311
+ for (let i = 0; i < conditions.length; i++) {
312
+ const childDepth = depth === "" ? `${i}` : `${depth}.${i}`;
313
+ const result = await evaluateCondition({
314
+ ...args,
315
+ condition: conditions[i],
316
+ depth: childDepth
317
+ });
318
+ if (!result) {
319
+ args.logger?.debug("and condition short-circuited (child returned false)", {
320
+ childType: conditions[i].type,
321
+ depth: childDepth
322
+ });
323
+ return false;
324
+ }
325
+ }
326
+ return true;
327
+ };
328
+
329
+ // src/conditions/or.ts
330
+ var orEvaluator = async (args) => {
331
+ const { conditions } = args.condition;
332
+ const { depth } = args;
333
+ for (let i = 0; i < conditions.length; i++) {
334
+ const childDepth = depth === "" ? `${i}` : `${depth}.${i}`;
335
+ const result = await evaluateCondition({
336
+ ...args,
337
+ condition: conditions[i],
338
+ depth: childDepth
339
+ });
340
+ if (result) {
341
+ args.logger?.debug("or condition short-circuited (child returned true)", {
342
+ childType: conditions[i].type,
343
+ depth: childDepth
344
+ });
345
+ return true;
346
+ }
347
+ }
348
+ return false;
349
+ };
350
+
351
+ // src/conditions/check-annotations.ts
352
+ var checkAnnotationsEvaluator = async (args) => {
353
+ const { conditions } = args.condition;
354
+ const { depth, annotations: annotationsAsContext } = args;
355
+ for (let i = 0; i < conditions.length; i++) {
356
+ const childDepth = depth === "" ? `${i}` : `${depth}.${i}`;
357
+ const result = await evaluateCondition({
358
+ ...args,
359
+ condition: conditions[i],
360
+ context: annotationsAsContext,
361
+ annotations: {},
362
+ depth: childDepth
363
+ });
364
+ if (!result) {
365
+ args.logger?.debug("checkAnnotations condition short-circuited (child returned false)", {
366
+ childType: conditions[i].type,
367
+ depth: childDepth
368
+ });
369
+ return false;
370
+ }
371
+ }
372
+ return true;
373
+ };
374
+
454
375
  // src/conditions/index.ts
455
376
  var builtinEvaluators = {
456
377
  string: stringEvaluator,
@@ -459,7 +380,10 @@ var builtinEvaluators = {
459
380
  bool: boolEvaluator,
460
381
  env: envEvaluator,
461
382
  startAt: startAtEvaluator,
462
- endAt: endAtEvaluator
383
+ endAt: endAtEvaluator,
384
+ and: andEvaluator,
385
+ or: orEvaluator,
386
+ checkAnnotations: checkAnnotationsEvaluator
463
387
  };
464
388
 
465
389
  // src/resolver.ts
@@ -467,6 +391,9 @@ function getEvaluators(options) {
467
391
  if (!options?.evaluators) {
468
392
  throw new ShowwhatError("No evaluators registered. Pass evaluators via options.");
469
393
  }
394
+ if (options.fallback) {
395
+ return { ...options.evaluators, [FALLBACK_EVALUATOR_KEY]: options.fallback };
396
+ }
470
397
  return options.evaluators;
471
398
  }
472
399
  function getLogger(options) {
@@ -476,61 +403,44 @@ async function resolveVariation({
476
403
  variations,
477
404
  context,
478
405
  deps,
479
- options
406
+ options,
407
+ definitionKey
480
408
  }) {
481
409
  const evaluators = getEvaluators(options);
482
410
  const logger = getLogger(options);
483
411
  for (let i = 0; i < variations.length; i++) {
484
412
  const variation = variations[i];
485
- const conditionList = Array.isArray(variation.conditions) ? variation.conditions : [];
486
- if (conditionList.length === 0) {
413
+ const conditions = Array.isArray(variation.conditions) ? variation.conditions : [];
414
+ const annotations = options?.createAnnotations?.(definitionKey) ?? {};
415
+ if (conditions.length === 0) {
487
416
  logger.debug("variation matched (no conditions)", { variationIndex: i });
488
- return { variation, variationIndex: i, annotations: {} };
417
+ return { variation, variationIndex: i, annotations };
489
418
  }
490
- const annotations = {};
491
419
  const rulesMatch = await evaluateCondition({
492
- condition: { type: "and", conditions: conditionList },
420
+ condition: { type: "and", conditions },
493
421
  context,
494
422
  evaluators,
495
423
  annotations,
496
424
  deps: deps ?? {},
497
425
  logger,
498
- fallback: options?.fallback,
499
- createRegex: options?.createRegex
426
+ createRegex: options?.createRegex ?? defaultCreateRegex
500
427
  });
501
428
  if (!rulesMatch) {
502
429
  logger.debug("variation did not match", {
503
430
  variationIndex: i,
504
- conditionCount: conditionList.length
431
+ conditionCount: conditions.length
505
432
  });
506
433
  continue;
507
434
  }
508
435
  logger.debug("variation matched", {
509
436
  variationIndex: i,
510
- conditionCount: conditionList.length
437
+ conditionCount: conditions.length
511
438
  });
512
439
  return { variation, variationIndex: i, annotations };
513
440
  }
514
441
  logger.debug("no variation matched", { variationCount: variations.length });
515
442
  return null;
516
443
  }
517
- function toResolution(key, result) {
518
- const conditionCount = Array.isArray(result.variation.conditions) ? result.variation.conditions.length : 0;
519
- return {
520
- success: true,
521
- key,
522
- value: result.variation.value,
523
- meta: {
524
- variation: {
525
- index: result.variationIndex,
526
- id: result.variation.id,
527
- description: result.variation.description,
528
- conditionCount
529
- },
530
- annotations: result.annotations
531
- }
532
- };
533
- }
534
444
  async function resolveKey(key, definitions, context, deps, options) {
535
445
  const logger = getLogger(options);
536
446
  const definition = definitions[key];
@@ -550,7 +460,8 @@ async function resolveKey(key, definitions, context, deps, options) {
550
460
  variations: definition.variations,
551
461
  context,
552
462
  deps,
553
- options
463
+ options,
464
+ definitionKey: key
554
465
  });
555
466
  if (!result) {
556
467
  logger.warn("no matching variation", { key });
@@ -561,7 +472,21 @@ async function resolveKey(key, definitions, context, deps, options) {
561
472
  variationIndex: result.variationIndex,
562
473
  value: result.variation.value
563
474
  });
564
- return toResolution(key, result);
475
+ const conditionCount = Array.isArray(result.variation.conditions) ? result.variation.conditions.length : 0;
476
+ return {
477
+ success: true,
478
+ key,
479
+ value: result.variation.value,
480
+ meta: {
481
+ variation: {
482
+ index: result.variationIndex,
483
+ id: result.variation.id,
484
+ description: result.variation.description,
485
+ conditionCount
486
+ },
487
+ annotations: result.annotations
488
+ }
489
+ };
565
490
  }
566
491
  async function resolve({
567
492
  definitions,
@@ -587,36 +512,175 @@ async function resolve({
587
512
  // src/parsers.ts
588
513
  import yaml from "js-yaml";
589
514
 
590
- // src/schemas/context.ts
591
- import { z as z3 } from "zod";
592
- var ContextPrimitiveSchema = z3.union([z3.string(), z3.number(), z3.boolean()]);
593
- var ContextValueSchema = z3.union([
594
- ContextPrimitiveSchema,
595
- z3.array(ContextPrimitiveSchema),
596
- z3.lazy(() => z3.record(z3.string(), ContextValueSchema))
515
+ // src/schemas/condition.ts
516
+ import { z as z4 } from "zod";
517
+ var PRIMITIVE_CONDITION_TYPES = {
518
+ string: "string",
519
+ number: "number",
520
+ bool: "bool",
521
+ datetime: "datetime"
522
+ };
523
+ var CONDITION_TYPES = {
524
+ ...PRIMITIVE_CONDITION_TYPES,
525
+ env: "env",
526
+ startAt: "startAt",
527
+ endAt: "endAt",
528
+ and: "and",
529
+ or: "or",
530
+ checkAnnotations: "checkAnnotations"
531
+ };
532
+ var CONTEXT_KEYS = {
533
+ env: "env",
534
+ at: "at"
535
+ };
536
+ var StringConditionSchema = z4.object({
537
+ id: z4.string().optional(),
538
+ type: z4.literal("string"),
539
+ key: z4.string().min(1),
540
+ op: z4.enum(["eq", "neq", "in", "nin", "regex"]),
541
+ value: z4.union([z4.string(), z4.array(z4.string())])
542
+ }).superRefine((val, ctx) => {
543
+ const isArrayOp = val.op === "in" || val.op === "nin";
544
+ const isArray = Array.isArray(val.value);
545
+ if (isArrayOp && !isArray) {
546
+ ctx.addIssue({
547
+ code: "custom",
548
+ message: `"${val.op}" operator requires an array value`,
549
+ path: ["value"]
550
+ });
551
+ }
552
+ if (!isArrayOp && isArray) {
553
+ ctx.addIssue({
554
+ code: "custom",
555
+ message: `"${val.op}" operator requires a string value`,
556
+ path: ["value"]
557
+ });
558
+ }
559
+ });
560
+ var NumberConditionSchema = z4.object({
561
+ id: z4.string().optional(),
562
+ type: z4.literal("number"),
563
+ key: z4.string().min(1),
564
+ op: z4.enum(["eq", "neq", "gt", "gte", "lt", "lte", "in", "nin"]),
565
+ value: z4.union([z4.number(), z4.array(z4.number())])
566
+ }).superRefine((val, ctx) => {
567
+ const isArrayOp = val.op === "in" || val.op === "nin";
568
+ const isArray = Array.isArray(val.value);
569
+ if (isArrayOp && !isArray) {
570
+ ctx.addIssue({
571
+ code: "custom",
572
+ message: `"${val.op}" operator requires an array value`,
573
+ path: ["value"]
574
+ });
575
+ }
576
+ if (!isArrayOp && isArray) {
577
+ ctx.addIssue({
578
+ code: "custom",
579
+ message: `"${val.op}" operator requires a number value`,
580
+ path: ["value"]
581
+ });
582
+ }
583
+ });
584
+ var DatetimeConditionSchema = z4.object({
585
+ id: z4.string().optional(),
586
+ type: z4.literal("datetime"),
587
+ key: z4.string().min(1),
588
+ op: z4.enum(["eq", "gt", "gte", "lt", "lte"]),
589
+ value: z4.iso.datetime({ message: '"datetime" must be a valid ISO 8601 datetime' })
590
+ });
591
+ var BoolConditionSchema = z4.object({
592
+ id: z4.string().optional(),
593
+ type: z4.literal("bool"),
594
+ key: z4.string().min(1),
595
+ op: z4.literal("eq").optional(),
596
+ value: z4.boolean()
597
+ });
598
+ var EnvConditionSchema = z4.object({
599
+ id: z4.string().optional(),
600
+ type: z4.literal("env"),
601
+ op: z4.literal("eq").optional(),
602
+ value: z4.union([z4.string(), z4.array(z4.string())])
603
+ });
604
+ var StartAtConditionSchema = z4.object({
605
+ id: z4.string().optional(),
606
+ type: z4.literal("startAt"),
607
+ value: z4.iso.datetime({ message: '"startAt" must be a valid ISO 8601 datetime' })
608
+ });
609
+ var EndAtConditionSchema = z4.object({
610
+ id: z4.string().optional(),
611
+ type: z4.literal("endAt"),
612
+ value: z4.iso.datetime({ message: '"endAt" must be a valid ISO 8601 datetime' })
613
+ });
614
+ var BuiltinConditionSchema = z4.discriminatedUnion("type", [
615
+ StringConditionSchema,
616
+ NumberConditionSchema,
617
+ DatetimeConditionSchema,
618
+ BoolConditionSchema,
619
+ EnvConditionSchema,
620
+ StartAtConditionSchema,
621
+ EndAtConditionSchema
597
622
  ]);
598
- var ContextSchema = z3.record(z3.string(), ContextValueSchema);
623
+ var AndConditionSchema = z4.object({
624
+ id: z4.string().optional(),
625
+ type: z4.literal("and"),
626
+ conditions: z4.array(z4.lazy(() => ConditionSchema)).min(1)
627
+ });
628
+ var OrConditionSchema = z4.object({
629
+ id: z4.string().optional(),
630
+ type: z4.literal("or"),
631
+ conditions: z4.array(z4.lazy(() => ConditionSchema)).min(1)
632
+ });
633
+ var CheckAnnotationsConditionSchema = z4.object({
634
+ id: z4.string().optional(),
635
+ type: z4.literal("checkAnnotations"),
636
+ conditions: z4.array(z4.lazy(() => ConditionSchema)).min(1)
637
+ });
638
+ var BLOCKED_OPEN_UNION_TYPES = new Set(Object.values(CONDITION_TYPES));
639
+ var ConditionSchema = z4.union([
640
+ BuiltinConditionSchema,
641
+ AndConditionSchema,
642
+ OrConditionSchema,
643
+ CheckAnnotationsConditionSchema,
644
+ z4.looseObject({ type: z4.string() }).refine((val) => !BLOCKED_OPEN_UNION_TYPES.has(val.type), {
645
+ message: "Reserved condition type"
646
+ })
647
+ ]);
648
+ function isAndCondition(c) {
649
+ return c.type === CONDITION_TYPES.and;
650
+ }
651
+ function isOrCondition(c) {
652
+ return c.type === CONDITION_TYPES.or;
653
+ }
654
+ function isCheckAnnotationsCondition(c) {
655
+ return c.type === CONDITION_TYPES.checkAnnotations;
656
+ }
657
+
658
+ // src/schemas/context.ts
659
+ import { z as z5 } from "zod";
660
+ var ContextValueSchema = DataValueSchema;
661
+ var ContextSchema = z5.record(z5.string(), ContextValueSchema);
599
662
 
600
663
  // src/schemas/variation.ts
601
- import { z as z4 } from "zod";
602
- var VariationValueSchema = z4.unknown();
603
- var VariationSchema = z4.object({
604
- id: z4.string().optional(),
664
+ import { z as z6 } from "zod";
665
+ var VariationValueSchema = z6.unknown();
666
+ var VariationSchema = z6.object({
667
+ id: z6.string().optional(),
605
668
  value: VariationValueSchema,
606
- conditions: z4.array(ConditionSchema).optional(),
607
- description: z4.string().optional()
669
+ conditions: z6.array(ConditionSchema).optional(),
670
+ description: z6.string().optional()
608
671
  });
609
672
 
610
673
  // src/schemas/definition.ts
611
- import { z as z6 } from "zod";
674
+ import { z as z8 } from "zod";
612
675
 
613
676
  // src/schemas/preset.ts
614
- import { z as z5 } from "zod";
677
+ import { z as z7 } from "zod";
615
678
  var PRIMITIVE_TYPES = new Set(Object.values(PRIMITIVE_CONDITION_TYPES));
616
- var PresetDefinitionSchema = z5.object({
617
- type: z5.string().min(1),
618
- key: z5.string().min(1).optional(),
619
- overrides: z5.record(z5.string(), z5.unknown()).optional()
679
+ var COMPOSITE_TYPES = /* @__PURE__ */ new Set(["and", "or", "checkAnnotations"]);
680
+ var PresetDefinitionSchema = z7.object({
681
+ type: z7.string().min(1),
682
+ key: z7.string().min(1).optional(),
683
+ overrides: z7.record(z7.string(), z7.unknown()).optional()
620
684
  }).superRefine((val, ctx) => {
621
685
  if (PRIMITIVE_TYPES.has(val.type) && !val.key) {
622
686
  ctx.addIssue({
@@ -625,35 +689,57 @@ var PresetDefinitionSchema = z5.object({
625
689
  path: ["key"]
626
690
  });
627
691
  }
692
+ if (COMPOSITE_TYPES.has(val.type)) {
693
+ const conditions = val.overrides?.conditions;
694
+ if (!Array.isArray(conditions) || conditions.length === 0) {
695
+ ctx.addIssue({
696
+ code: "custom",
697
+ message: `"overrides.conditions" must be a non-empty array for composite type ("${val.type}")`,
698
+ path: ["overrides", "conditions"]
699
+ });
700
+ return;
701
+ }
702
+ for (let i = 0; i < conditions.length; i++) {
703
+ const result = ConditionSchema.safeParse(conditions[i]);
704
+ if (!result.success) {
705
+ for (const issue of result.error.issues) {
706
+ ctx.addIssue({
707
+ ...issue,
708
+ path: ["overrides", "conditions", i, ...issue.path]
709
+ });
710
+ }
711
+ }
712
+ }
713
+ }
628
714
  });
629
- var PresetsSchema = z5.record(z5.string(), PresetDefinitionSchema);
715
+ var PresetsSchema = z7.record(z7.string(), PresetDefinitionSchema);
630
716
 
631
717
  // src/schemas/definition.ts
632
- var DefinitionSchema = z6.object({
633
- id: z6.string().optional(),
634
- active: z6.boolean().optional(),
635
- description: z6.string().optional(),
636
- variations: z6.array(VariationSchema).min(1)
718
+ var DefinitionSchema = z8.object({
719
+ id: z8.string().optional(),
720
+ active: z8.boolean().optional(),
721
+ description: z8.string().optional(),
722
+ variations: z8.array(VariationSchema).min(1)
637
723
  });
638
- var DefinitionsSchema = z6.record(z6.string().min(1), DefinitionSchema);
639
- var FileFormatSchema = z6.object({
724
+ var DefinitionsSchema = z8.record(z8.string().min(1), DefinitionSchema);
725
+ var FileFormatSchema = z8.object({
640
726
  definitions: DefinitionsSchema,
641
727
  presets: PresetsSchema.optional()
642
728
  }).strict();
643
729
 
644
730
  // src/schemas/resolution.ts
645
- import { z as z7 } from "zod";
646
- var ResolutionSchema = z7.object({
647
- key: z7.string(),
731
+ import { z as z9 } from "zod";
732
+ var ResolutionSchema = z9.object({
733
+ key: z9.string(),
648
734
  value: VariationValueSchema,
649
- meta: z7.object({
650
- variation: z7.object({
651
- index: z7.number().int().nonnegative(),
652
- id: z7.string().optional(),
653
- description: z7.string().optional(),
654
- conditionCount: z7.number().int().nonnegative()
735
+ meta: z9.object({
736
+ variation: z9.object({
737
+ index: z9.number().int().nonnegative(),
738
+ id: z9.string().optional(),
739
+ description: z9.string().optional(),
740
+ conditionCount: z9.number().int().nonnegative()
655
741
  }),
656
- annotations: z7.record(z7.string(), z7.unknown())
742
+ annotations: z9.record(z9.string(), z9.unknown())
657
743
  })
658
744
  });
659
745
 
@@ -731,47 +817,44 @@ var MemoryData = class _MemoryData {
731
817
  async listKeys() {
732
818
  return Object.keys(this.#flags);
733
819
  }
734
- async getPresets() {
820
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
821
+ async getPresets(_key) {
735
822
  return structuredClone(this.#presets);
736
823
  }
737
824
  };
738
825
 
739
826
  // src/presets.ts
740
827
  var RESERVED_CONDITION_TYPES = /* @__PURE__ */ new Set([...Object.values(CONDITION_TYPES), "__custom"]);
741
- var BUILTIN_EVALUATORS = {
742
- string: stringEvaluator,
743
- number: numberEvaluator,
744
- bool: boolEvaluator,
745
- datetime: datetimeEvaluator
746
- };
747
828
  function createPresetConditions(presets) {
748
829
  const result = {};
749
830
  for (const [name, preset] of Object.entries(presets)) {
750
831
  if (RESERVED_CONDITION_TYPES.has(name)) {
751
832
  throw new Error(`Preset name "${name}" collides with a built-in or reserved condition type`);
752
833
  }
753
- if (!PRIMITIVE_TYPES.has(preset.type)) {
754
- continue;
755
- }
756
- const primitiveType = preset.type;
757
- const delegateEvaluator = BUILTIN_EVALUATORS[primitiveType];
758
- const presetKey = preset.key;
759
834
  const overrides = preset.overrides ?? {};
760
- const evaluator = ({
835
+ const evaluator = async ({
761
836
  condition,
762
837
  context,
763
838
  annotations,
764
839
  deps,
765
840
  depth,
766
- createRegex
841
+ createRegex,
842
+ evaluators,
843
+ logger
767
844
  }) => {
768
845
  const rec = condition;
769
- return delegateEvaluator({
770
- condition: { ...rec, ...overrides, type: primitiveType, key: presetKey },
846
+ const rewritten = { ...rec, ...overrides, type: preset.type };
847
+ if (preset.key) {
848
+ rewritten.key = preset.key;
849
+ }
850
+ return evaluateCondition({
851
+ condition: rewritten,
771
852
  context,
853
+ evaluators,
772
854
  annotations,
773
855
  deps,
774
856
  depth,
857
+ logger,
775
858
  createRegex
776
859
  });
777
860
  };
@@ -780,6 +863,8 @@ function createPresetConditions(presets) {
780
863
  return result;
781
864
  }
782
865
  export {
866
+ AnnotationValueSchema,
867
+ AnnotationsSchema,
783
868
  BoolConditionSchema,
784
869
  BuiltinConditionSchema,
785
870
  CONDITION_TYPES,
@@ -787,7 +872,9 @@ export {
787
872
  ConditionError,
788
873
  ConditionSchema,
789
874
  ContextSchema,
875
+ ContextValueSchema,
790
876
  DataError,
877
+ DataValueSchema,
791
878
  DatetimeConditionSchema,
792
879
  DefinitionInactiveError,
793
880
  DefinitionNotFoundError,
@@ -795,12 +882,12 @@ export {
795
882
  DefinitionsSchema,
796
883
  EndAtConditionSchema,
797
884
  EnvConditionSchema,
885
+ FALLBACK_EVALUATOR_KEY,
798
886
  FileFormatSchema,
799
887
  InvalidContextError,
800
888
  MemoryData,
801
889
  NumberConditionSchema,
802
890
  PRIMITIVE_CONDITION_TYPES,
803
- PRIMITIVE_TYPES,
804
891
  ParseError,
805
892
  PresetsSchema,
806
893
  ResolutionSchema,
@@ -808,6 +895,7 @@ export {
808
895
  ShowwhatError,
809
896
  StartAtConditionSchema,
810
897
  StringConditionSchema,
898
+ UnknownConditionTypeError,
811
899
  ValidationError,
812
900
  VariationNotFoundError,
813
901
  VariationSchema,
@@ -817,6 +905,7 @@ export {
817
905
  defaultCreateRegex,
818
906
  evaluateCondition,
819
907
  isAndCondition,
908
+ isCheckAnnotationsCondition,
820
909
  isOrCondition,
821
910
  isWritable,
822
911
  noConditionEvaluator,