@nmnmcc/ability 2.0.5 → 2.0.6

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 (49) hide show
  1. package/dist/Condition.d.ts +4 -4
  2. package/dist/Condition.d.ts.map +1 -1
  3. package/dist/Condition.js.map +1 -1
  4. package/dist/Domain.d.ts +1 -1
  5. package/dist/Policy.d.ts +2 -2
  6. package/dist/Policy.d.ts.map +1 -1
  7. package/dist/Policy.js.map +1 -1
  8. package/dist/internal/algebra.js +28 -6
  9. package/dist/internal/algebra.js.map +1 -1
  10. package/dist/internal/authorizer.d.ts.map +1 -1
  11. package/dist/internal/authorizer.js +37 -14
  12. package/dist/internal/authorizer.js.map +1 -1
  13. package/dist/internal/bind.js +7 -8
  14. package/dist/internal/bind.js.map +1 -1
  15. package/dist/internal/catalog.d.ts +6 -0
  16. package/dist/internal/catalog.d.ts.map +1 -1
  17. package/dist/internal/catalog.js +12 -9
  18. package/dist/internal/catalog.js.map +1 -1
  19. package/dist/internal/decide.js +1 -1
  20. package/dist/internal/domain.js +1 -1
  21. package/dist/internal/json.js +2 -10
  22. package/dist/internal/json.js.map +1 -1
  23. package/dist/internal/nodes.d.ts +4 -1
  24. package/dist/internal/nodes.d.ts.map +1 -1
  25. package/dist/internal/nodes.js +17 -7
  26. package/dist/internal/nodes.js.map +1 -1
  27. package/dist/internal/patterns.js +1 -1
  28. package/dist/internal/patterns.js.map +1 -1
  29. package/dist/internal/policy-json.js +2 -8
  30. package/dist/internal/policy-json.js.map +1 -1
  31. package/dist/internal/policy-nodes.d.ts +4 -1
  32. package/dist/internal/policy-nodes.d.ts.map +1 -1
  33. package/dist/internal/policy-nodes.js +13 -4
  34. package/dist/internal/policy-nodes.js.map +1 -1
  35. package/dist/internal/search.js +4 -4
  36. package/dist/internal/search.js.map +1 -1
  37. package/package.json +1 -1
  38. package/src/Condition.ts +5 -2
  39. package/src/Policy.ts +1 -2
  40. package/src/internal/algebra.ts +44 -8
  41. package/src/internal/authorizer.ts +56 -14
  42. package/src/internal/bind.ts +18 -14
  43. package/src/internal/catalog.ts +40 -27
  44. package/src/internal/json.ts +2 -11
  45. package/src/internal/nodes.ts +21 -11
  46. package/src/internal/patterns.ts +7 -3
  47. package/src/internal/policy-json.ts +2 -9
  48. package/src/internal/policy-nodes.ts +14 -6
  49. package/src/internal/search.ts +13 -10
@@ -1,10 +1,10 @@
1
1
  import { catalogFields, exceeded } from "./limits.js";
2
+ import * as HashMap from "effect/HashMap";
3
+ import * as HashSet from "effect/HashSet";
2
4
  import * as Schema from "effect/Schema";
3
5
  import * as Arr from "effect/Array";
4
6
  import { hasProperty } from "effect/Predicate";
5
7
  import * as Option from "effect/Option";
6
- import * as HashMap from "effect/HashMap";
7
- import * as HashSet from "effect/HashSet";
8
8
  import * as SchemaAST from "effect/SchemaAST";
9
9
  // src/internal/catalog.ts
10
10
  /**
@@ -58,7 +58,7 @@ const joinKinds = (left, right) => ({
58
58
  string: left.string || right.string,
59
59
  number: numberOrder.indexOf(left.number) >= numberOrder.indexOf(right.number) ? left.number : right.number,
60
60
  object: left.object || right.object,
61
- literals: Arr.dedupe([...left.literals, ...right.literals])
61
+ literals: Array.from(/* @__PURE__ */ new Set([...left.literals, ...right.literals]))
62
62
  });
63
63
  /** Tests if a number fits the numbers of a field. */
64
64
  const fitsNumber = (number, value) => {
@@ -183,20 +183,20 @@ const nameOf = (signature) => typeof signature.name === "symbol" ? void 0 : Stri
183
183
  /**
184
184
  * The properties of a struct by name. A walk makes it one time for each
185
185
  * struct of a place, so a struct with very many fields does not take a
186
- * search for each name.
186
+ * search for each name. It is a native `Map`, as `Branch.names` is.
187
187
  */
188
- const propertiesOf = (struct) => HashMap.fromIterable(Arr.flatMap(struct.propertySignatures, (signature) => {
188
+ const propertiesOf = (struct) => new Map(Arr.flatMap(struct.propertySignatures, (signature) => {
189
189
  const name = nameOf(signature);
190
190
  return name === void 0 ? [] : [[name, signature]];
191
191
  }));
192
192
  /** The names of the fields of the structs, in the order that they first come. */
193
- const namesOf = (structs) => Arr.dedupe(Arr.flatMap(structs, (struct) => Arr.flatMap(struct.propertySignatures, (signature) => {
193
+ const namesOf = (structs) => Array.from(new Set(Arr.flatMap(structs, (struct) => Arr.flatMap(struct.propertySignatures, (signature) => {
194
194
  const name = nameOf(signature);
195
195
  if (name === void 0) return [];
196
196
  if (name.includes(".")) throw new Error(`A field name may not have a dot: "${name}"`);
197
197
  if (name === "") throw new Error("A field name may not be empty");
198
198
  return [name];
199
- })));
199
+ }))));
200
200
  /**
201
201
  * Makes the branch of a place, with the branches below it. `count` is the
202
202
  * number of fields so far. It belongs to one walk, and it stops a Schema with
@@ -232,13 +232,16 @@ const branchOf = (place, count) => {
232
232
  const structProperties = Arr.map(structs, propertiesOf);
233
233
  const classProperties = Arr.map(classes, propertiesOf);
234
234
  const children = Arr.map(namesOf(structs), (name) => {
235
- const properties = Arr.flatMap(structProperties, (named) => Option.toArray(HashMap.get(named, name)));
235
+ const properties = Arr.flatMap(structProperties, (named) => {
236
+ const property = named.get(name);
237
+ return property === void 0 ? [] : [property];
238
+ });
236
239
  const below = {
237
240
  path: [...place.path, name],
238
241
  schemas: Arr.flatMap(properties, (property) => alternatives(property.type, /* @__PURE__ */ new Set())),
239
242
  missing: place.missing || values.length > 0 || Arr.some(properties, (property) => SchemaAST.isOptional(property.type)),
240
243
  top: place.top || valueKinds.object || properties.length < structs.length,
241
- plain: place.plain && !valueKinds.object && Arr.every(classProperties, (named) => HashMap.has(named, name))
244
+ plain: place.plain && !valueKinds.object && Arr.every(classProperties, (named) => named.has(name))
242
245
  };
243
246
  return [name, branchOf(below, count)];
244
247
  });
@@ -1 +1 @@
1
- {"version":3,"file":"catalog.js","names":["Limits.exceeded","Limits.catalogFields"],"sources":["../../src/internal/catalog.ts"],"sourcesContent":["/**\n * The catalog of the fields of a Schema. One walk over the Schema makes it,\n * and every question about the fields of a resource or of the principal reads\n * it: which names a rule may use, which values a field may hold, which fields\n * a pattern fits, and which fields a list of permitted fields shows.\n *\n * The catalog describes the shape of the values, not the checks of the\n * Schema. A check, such as a minimum length, only keeps some values out, so a\n * catalog that leaves the checks out holds every real value and more. An\n * answer that holds for all of these values, as `All` and `None` of a\n * coverage do, then holds for the real values too.\n */\nimport * as Arr from \"effect/Array\"\nimport * as HashMap from \"effect/HashMap\"\nimport * as HashSet from \"effect/HashSet\"\nimport * as Option from \"effect/Option\"\nimport { hasProperty } from \"effect/Predicate\"\nimport * as Schema from \"effect/Schema\"\nimport * as SchemaAST from \"effect/SchemaAST\"\nimport * as Limits from \"./limits.ts\"\n\n/** The kinds of values that a field may hold. */\nexport interface Kinds {\n\t/** The field may be `null`, `undefined` or missing. */\n\treadonly null: boolean\n\treadonly boolean: boolean\n\t/** The field may hold any string. */\n\treadonly string: boolean\n\t/** The numbers that the field may hold. */\n\treadonly number: \"none\" | \"integer\" | \"finite\" | \"any\"\n\t/** The field may hold an object, or a value that is not a scalar. */\n\treadonly object: boolean\n\t/** Single values that the field may hold, other than the ones above. */\n\treadonly literals: ReadonlyArray<string | number | boolean>\n}\n\n/** No value: the kinds of a field of `Schema.Never`. */\nexport const noKinds: Kinds = {\n\tnull: false,\n\tboolean: false,\n\tstring: false,\n\tnumber: \"none\",\n\tobject: false,\n\tliterals: [],\n}\n\n/** Any value. */\nexport const anyKinds: Kinds = {\n\tnull: true,\n\tboolean: true,\n\tstring: true,\n\tnumber: \"any\",\n\tobject: true,\n\tliterals: [],\n}\n\nconst nullKinds: Kinds = { ...noKinds, null: true }\nconst objectKinds: Kinds = { ...noKinds, object: true }\n\nconst numberOrder = [\"none\", \"integer\", \"finite\", \"any\"] as const\n\n/** The kinds of a field that may hold a value of `left` or of `right`. */\nexport const joinKinds = (left: Kinds, right: Kinds): Kinds => ({\n\tnull: left.null || right.null,\n\tboolean: left.boolean || right.boolean,\n\tstring: left.string || right.string,\n\tnumber:\n\t\tnumberOrder.indexOf(left.number) >= numberOrder.indexOf(right.number)\n\t\t\t? left.number\n\t\t\t: right.number,\n\tobject: left.object || right.object,\n\tliterals: Arr.dedupe([...left.literals, ...right.literals]),\n})\n\n/** Tests if a number fits the numbers of a field. */\nexport const fitsNumber = (number: Kinds[\"number\"], value: number): boolean => {\n\tswitch (number) {\n\t\tcase \"none\":\n\t\t\treturn false\n\t\tcase \"integer\":\n\t\t\treturn Number.isInteger(value)\n\t\tcase \"finite\":\n\t\t\treturn Number.isFinite(value)\n\t\tcase \"any\":\n\t\t\treturn true\n\t}\n}\n\n/**\n * Tests if a field with these kinds may hold a value. A missing value and\n * `undefined` are `null`.\n */\nexport const accepts = (kinds: Kinds, value: unknown): boolean => {\n\tif (value === null || value === undefined) {\n\t\treturn kinds.null\n\t}\n\tswitch (typeof value) {\n\t\tcase \"boolean\":\n\t\t\treturn kinds.boolean || kinds.literals.includes(value)\n\t\tcase \"string\":\n\t\t\treturn kinds.string || kinds.literals.includes(value)\n\t\tcase \"number\":\n\t\t\treturn fitsNumber(kinds.number, value) || kinds.literals.includes(value)\n\t\tdefault:\n\t\t\treturn kinds.object\n\t}\n}\n\n/** A part of a field path that stands for any key of a record. */\nexport interface Key {\n\treadonly _tag: \"Key\"\n\t/** The Schemas of the keys. A key must fit one of them. */\n\treadonly parameters: ReadonlyArray<SchemaAST.AST>\n}\n\n/** One part of a field path: a name, or any key of a record. */\nexport type Segment = string | Key\n\n/** One field of a catalog. */\nexport interface Field {\n\treadonly path: ReadonlyArray<Segment>\n\t/** The path with dots, and `*` for a key of a record. */\n\treadonly text: string\n\treadonly kinds: Kinds\n\t/**\n\t * The field holds a value that a list of fields shows as one field: a\n\t * scalar, a record, an array, or a struct at the last part a path may have.\n\t */\n\treadonly listed: boolean\n\t/** The field may hold parts that the Schema does not name, as a record may. */\n\treadonly open: boolean\n\t/**\n\t * A read of the field finds only plain data. It is `false` when a value\n\t * above the field may be an object that does not have it as a data field:\n\t * a class without the field, which may have a getter of that name, a\n\t * value such as a date or a list, or any object, as of `Schema.Unknown`.\n\t * A decode or a `make` copies a struct or a record into a plain object,\n\t * so a struct without the field gives `null` for it.\n\t */\n\treadonly plain: boolean\n}\n\n/** A place in the tree of a catalog, with the places below it. */\nexport interface Branch {\n\t/** The field at this place. The root has none. */\n\treadonly field: Field | undefined\n\t/** The places below, by name, in the order of the Schema. */\n\treadonly children: ReadonlyArray<readonly [string, Branch]>\n\treadonly names: HashMap.HashMap<string, Branch>\n\t/** The place for the keys of a record, when the value may be a record. */\n\treadonly key: Key | undefined\n\treadonly keyBranch: Branch | undefined\n}\n\n/** The catalog of the fields of a Schema. */\nexport interface Catalog {\n\t/** Every field, a field before the fields below it. */\n\treadonly fields: ReadonlyArray<Field>\n\treadonly root: Branch\n}\n\n/**\n * Tests if a key of an object fits the Schemas of the keys of a record. A key\n * of an object is a string, also a key that a number Schema takes: `{ 1: \"a\" }`\n * has the key `\"1\"`. So a key that is the text of a number is tried as that\n * number too.\n */\nexport const keyFits = (key: Key, name: string): boolean =>\n\tArr.some(key.parameters, (parameter) => {\n\t\tconst is = Schema.is(Schema.make(parameter))\n\t\treturn (\n\t\t\tis(name) ||\n\t\t\t(name !== \"\" && String(Number(name)) === name && is(Number(name)))\n\t\t)\n\t})\n\n/**\n * Gives the struct of a `Schema.Class`. A class is a declaration with one\n * struct as its type parameter, and Effect marks it with a `\"~constructor\"`\n * annotation, also through more codec steps, as in\n * `Schema.fromJsonString(User)`. Other declarations, such as `Schema.Option`\n * or `Schema.ReadonlyMap`, have no such mark, and the fields of their type\n * parameter are not fields of the value.\n */\nconst classStruct = (\n\tast: SchemaAST.Declaration,\n): SchemaAST.Objects | undefined => {\n\tconst [inner] = ast.typeParameters\n\treturn ast.annotations?.[\"~constructor\"] !== undefined &&\n\t\tast.typeParameters.length === 1 &&\n\t\tinner?._tag === \"Objects\"\n\t\t? inner\n\t\t: undefined\n}\n\n/**\n * Gives the Schemas that a value at one place may fit: it opens unions and\n * `Schema.suspend`. A class stays a class: see {@link structOf}. The open suspend nodes are in a native `Set`,\n * because the walk must find a node by the node itself: `Equal` compares\n * Schema nodes by structure, and a recursive Schema has no end. A suspend\n * node that gives itself again, with no step on the path, gives nothing.\n */\nconst alternatives = (\n\tast: SchemaAST.AST,\n\topen: ReadonlySet<SchemaAST.AST>,\n): ReadonlyArray<SchemaAST.AST> => {\n\tswitch (ast._tag) {\n\t\tcase \"Union\":\n\t\t\treturn Arr.flatMap(ast.types, (type) => alternatives(type, open))\n\t\tcase \"Suspend\":\n\t\t\treturn open.has(ast)\n\t\t\t\t? []\n\t\t\t\t: alternatives(ast.thunk(), new Set([...open, ast]))\n\t\tdefault:\n\t\t\treturn [ast]\n\t}\n}\n\n/** The struct of a Schema: a struct, or the struct of a class. */\nconst structOf = (ast: SchemaAST.AST): SchemaAST.Objects | undefined =>\n\tast._tag === \"Objects\"\n\t\t? ast\n\t\t: ast._tag === \"Declaration\"\n\t\t\t? classStruct(ast)\n\t\t\t: undefined\n\nconst hasCheck = (\n\tchecks: ReadonlyArray<SchemaAST.Check<never>>,\n\tid: string,\n): boolean =>\n\tArr.some(\n\t\tchecks,\n\t\t(check) =>\n\t\t\tcheck.annotations?.representation?.id === id ||\n\t\t\t(check._tag === \"FilterGroup\" && hasCheck(check.checks, id)),\n\t)\n\n/** A struct with named fields, or with the keys of a record. */\nconst isStruct = (\n\tast: SchemaAST.Objects | undefined,\n): ast is SchemaAST.Objects =>\n\tast !== undefined &&\n\t(ast.propertySignatures.length > 0 || ast.indexSignatures.length > 0)\n\n/** The kinds of the values of a Schema that is not a struct. */\nconst kindsOf = (ast: SchemaAST.AST): Kinds => {\n\tswitch (ast._tag) {\n\t\tcase \"Null\":\n\t\tcase \"Undefined\":\n\t\t\treturn nullKinds\n\t\tcase \"Never\":\n\t\t\treturn noKinds\n\t\tcase \"String\":\n\t\tcase \"TemplateLiteral\":\n\t\t\treturn { ...noKinds, string: true }\n\t\tcase \"Boolean\":\n\t\t\treturn { ...noKinds, boolean: true }\n\t\tcase \"Number\": {\n\t\t\t// The two checks that a search uses. Effect names a number with\n\t\t\t// them, as `Schema.Int` and `Schema.Finite`; other checks are left\n\t\t\t// out, as all checks are.\n\t\t\tconst checks = ast.checks ?? []\n\t\t\treturn {\n\t\t\t\t...noKinds,\n\t\t\t\tnumber: hasCheck(checks, \"effect/schema/isInt\")\n\t\t\t\t\t? \"integer\"\n\t\t\t\t\t: hasCheck(checks, \"effect/schema/isFinite\")\n\t\t\t\t\t\t? \"finite\"\n\t\t\t\t\t\t: \"any\",\n\t\t\t}\n\t\t}\n\t\tcase \"Literal\":\n\t\t\treturn typeof ast.literal === \"bigint\"\n\t\t\t\t? objectKinds\n\t\t\t\t: { ...noKinds, literals: [ast.literal] }\n\t\tcase \"Enum\":\n\t\t\treturn { ...noKinds, literals: Arr.map(ast.enums, ([, value]) => value) }\n\t\tcase \"Arrays\":\n\t\tcase \"ObjectKeyword\":\n\t\tcase \"BigInt\":\n\t\tcase \"Symbol\":\n\t\tcase \"UniqueSymbol\":\n\t\t\treturn objectKinds\n\t\tcase \"Declaration\":\n\t\t\t// A declaration of Effect in `objectDeclarations` holds an object,\n\t\t\t// such as a `Date`. Another declaration may hold any value, as\n\t\t\t// `Schema.Json` or one from `Schema.declare` may.\n\t\t\treturn HashSet.has(objectDeclarations, declarationId(ast))\n\t\t\t\t? objectKinds\n\t\t\t\t: anyKinds\n\t\tdefault:\n\t\t\t// `Schema.Unknown`, `Schema.Void`, and `Struct({})`, which takes a\n\t\t\t// string too: these may hold any value.\n\t\t\treturn anyKinds\n\t}\n}\n\n/**\n * The ids of the declarations of Effect that hold only objects. Effect puts\n * the id in the `representation` annotation. A declaration that is not in\n * this list may hold a scalar, as `Schema.Json` may, so its kinds are any\n * value.\n */\nconst objectDeclarations = HashSet.make(\n\t\"effect/schema/Date\",\n\t\"effect/schema/URL\",\n\t\"effect/schema/Uint8Array\",\n\t\"effect/schema/Duration\",\n\t\"effect/schema/DateTimeUtc\",\n\t\"effect/schema/DateTimeZoned\",\n\t\"effect/schema/BigDecimal\",\n\t\"effect/schema/Redacted\",\n\t\"effect/schema/Cause\",\n\t\"effect/schema/Chunk\",\n\t\"effect/schema/HashMap\",\n\t\"effect/schema/HashSet\",\n\t\"effect/schema/ReadonlyMap\",\n\t\"effect/schema/ReadonlySet\",\n\t\"effect/schema/Option\",\n\t\"effect/schema/Result\",\n\t\"effect/schema/Exit\",\n\t\"effect/schema/File\",\n\t\"effect/schema/FormData\",\n\t\"effect/schema/RegExp\",\n\t\"effect/schema/URLSearchParams\",\n)\n\nconst declarationId = (ast: SchemaAST.Declaration): string | undefined => {\n\tconst representation: unknown = ast.annotations?.[\"representation\"]\n\treturn hasProperty(representation, \"id\") &&\n\t\ttypeof representation.id === \"string\"\n\t\t? representation.id\n\t\t: undefined\n}\n\n/** The things that a walk of the catalog knows at one place. */\ninterface Place {\n\treadonly path: ReadonlyArray<Segment>\n\treadonly schemas: ReadonlyArray<SchemaAST.AST>\n\t/** The value may be missing. */\n\treadonly missing: boolean\n\t/** The value may be anything, as an extra field of a struct may be. */\n\treadonly top: boolean\n\t/** A read here finds only plain data: see {@link Field.plain}. */\n\treadonly plain: boolean\n}\n\nconst textOf = (path: ReadonlyArray<Segment>): string =>\n\tArr.map(path, (segment) =>\n\t\ttypeof segment === \"string\" ? segment : \"*\",\n\t).join(\".\")\n\n/**\n * The name of a property as a part of a path. A key of an object is a string,\n * so a number key, as from `Schema.Record(Schema.Literal(1), ...)`, has the\n * name `\"1\"`. A symbol key is not a field.\n */\nconst nameOf = (signature: SchemaAST.PropertySignature): string | undefined =>\n\ttypeof signature.name === \"symbol\" ? undefined : String(signature.name)\n\n/**\n * The properties of a struct by name. A walk makes it one time for each\n * struct of a place, so a struct with very many fields does not take a\n * search for each name.\n */\nconst propertiesOf = (\n\tstruct: SchemaAST.Objects,\n): HashMap.HashMap<string, SchemaAST.PropertySignature> =>\n\tHashMap.fromIterable(\n\t\tArr.flatMap(struct.propertySignatures, (signature) => {\n\t\t\tconst name = nameOf(signature)\n\t\t\treturn name === undefined ? [] : [[name, signature] as const]\n\t\t}),\n\t)\n\n/** The names of the fields of the structs, in the order that they first come. */\nconst namesOf = (\n\tstructs: ReadonlyArray<SchemaAST.Objects>,\n): ReadonlyArray<string> =>\n\tArr.dedupe(\n\t\tArr.flatMap(structs, (struct) =>\n\t\t\tArr.flatMap(struct.propertySignatures, (signature) => {\n\t\t\t\tconst name = nameOf(signature)\n\t\t\t\tif (name === undefined) {\n\t\t\t\t\treturn []\n\t\t\t\t}\n\t\t\t\t// A dot in a path is the step into a nested field. A field name with\n\t\t\t\t// a dot would make two fields have one path, so it is a defect.\n\t\t\t\tif (name.includes(\".\")) {\n\t\t\t\t\tthrow new Error(`A field name may not have a dot: \"${name}\"`)\n\t\t\t\t}\n\t\t\t\t// An empty name would make an empty part in a path, such as\n\t\t\t\t// `.secret`.\n\t\t\t\tif (name === \"\") {\n\t\t\t\t\tthrow new Error(\"A field name may not be empty\")\n\t\t\t\t}\n\t\t\t\treturn [name]\n\t\t\t}),\n\t\t),\n\t)\n\n/**\n * Makes the branch of a place, with the branches below it. `count` is the\n * number of fields so far. It belongs to one walk, and it stops a Schema with\n * very many fields before the walk is done.\n */\nconst branchOf = (place: Place, count: { size: number }): Branch => {\n\tconst structs = Arr.filter(Arr.map(place.schemas, structOf), isStruct)\n\t// The structs of classes. A value of a class is not copied into a plain\n\t// object, so it keeps its getters and methods.\n\tconst classes = Arr.filter(\n\t\tArr.map(\n\t\t\tArr.filter(place.schemas, (schema) => schema._tag === \"Declaration\"),\n\t\t\tstructOf,\n\t\t),\n\t\tisStruct,\n\t)\n\tconst values = Arr.filter(\n\t\tplace.schemas,\n\t\t(schema) => !isStruct(structOf(schema)),\n\t)\n\tconst valueKinds = Arr.reduce(values, noKinds, (kinds, schema) =>\n\t\tjoinKinds(kinds, kindsOf(structOf(schema) ?? schema)),\n\t)\n\tconst kinds = place.top\n\t\t? anyKinds\n\t\t: joinKinds(\n\t\t\t\tjoinKinds(valueKinds, structs.length > 0 ? objectKinds : noKinds),\n\t\t\t\tplace.missing ? nullKinds : noKinds,\n\t\t\t)\n\tconst records = Arr.filter(\n\t\tstructs,\n\t\t(struct) => struct.indexSignatures.length > 0,\n\t)\n\t// The last part that a path may have: the walk does not go below it.\n\tconst last = place.path.length === Limits.fieldPathParts\n\tconst field: Field | undefined =\n\t\tplace.path.length === 0\n\t\t\t? undefined\n\t\t\t: {\n\t\t\t\t\tpath: place.path,\n\t\t\t\t\ttext: textOf(place.path),\n\t\t\t\t\tkinds,\n\t\t\t\t\tlisted:\n\t\t\t\t\t\tvalues.length > 0 ||\n\t\t\t\t\t\trecords.length > 0 ||\n\t\t\t\t\t\t(last && structs.length > 0),\n\t\t\t\t\t// A field that is a scalar in one branch of a union and a struct\n\t\t\t\t\t// in another holds parts too.\n\t\t\t\t\topen:\n\t\t\t\t\t\trecords.length > 0 ||\n\t\t\t\t\t\tstructs.length > 0 ||\n\t\t\t\t\t\tvalueKinds.object ||\n\t\t\t\t\t\tplace.top,\n\t\t\t\t\tplain: place.plain,\n\t\t\t\t}\n\tif (field !== undefined) {\n\t\tcount.size += 1\n\t\tif (count.size > Limits.catalogFields) {\n\t\t\tthrow Limits.exceeded(\n\t\t\t\t\"A Schema\",\n\t\t\t\t\"catalogFields\",\n\t\t\t\t\"fields\",\n\t\t\t\tcount.size,\n\t\t\t\tLimits.catalogFields,\n\t\t\t)\n\t\t}\n\t}\n\tif (last) {\n\t\treturn {\n\t\t\tfield,\n\t\t\tchildren: [],\n\t\t\tnames: HashMap.empty(),\n\t\t\tkey: undefined,\n\t\t\tkeyBranch: undefined,\n\t\t}\n\t}\n\tconst structProperties = Arr.map(structs, propertiesOf)\n\tconst classProperties = Arr.map(classes, propertiesOf)\n\tconst children = Arr.map(namesOf(structs), (name) => {\n\t\tconst properties = Arr.flatMap(structProperties, (named) =>\n\t\t\tOption.toArray(HashMap.get(named, name)),\n\t\t)\n\t\tconst below: Place = {\n\t\t\tpath: [...place.path, name],\n\t\t\tschemas: Arr.flatMap(properties, (property) =>\n\t\t\t\talternatives(property.type, new Set()),\n\t\t\t),\n\t\t\t// A field below a value that is not a struct reads `null`, and so\n\t\t\t// does a field that may be missing.\n\t\t\tmissing:\n\t\t\t\tplace.missing ||\n\t\t\t\tvalues.length > 0 ||\n\t\t\t\tArr.some(properties, (property) => SchemaAST.isOptional(property.type)),\n\t\t\t// A struct without the name may still have it as an extra field,\n\t\t\t// with any value: only a decode takes extra fields away. A value\n\t\t\t// that may be any object, as one of `Schema.Unknown` may, may have\n\t\t\t// the name with any value too.\n\t\t\ttop: place.top || valueKinds.object || properties.length < structs.length,\n\t\t\tplain:\n\t\t\t\tplace.plain &&\n\t\t\t\t!valueKinds.object &&\n\t\t\t\tArr.every(classProperties, (named) => HashMap.has(named, name)),\n\t\t}\n\t\treturn [name, branchOf(below, count)] as const\n\t})\n\tconst names = HashMap.fromIterable(children)\n\tconst signatures = Arr.flatMap(records, (struct) => struct.indexSignatures)\n\tif (signatures.length === 0) {\n\t\treturn { field, children, names, key: undefined, keyBranch: undefined }\n\t}\n\tconst key: Key = {\n\t\t_tag: \"Key\",\n\t\tparameters: Arr.map(signatures, (signature) => signature.parameter),\n\t}\n\tconst keyBranch = branchOf(\n\t\t{\n\t\t\tpath: [...place.path, key],\n\t\t\tschemas: Arr.flatMap(signatures, (signature) =>\n\t\t\t\talternatives(signature.type, new Set()),\n\t\t\t),\n\t\t\t// A record may not have a given key.\n\t\t\tmissing: true,\n\t\t\ttop: place.top || valueKinds.object || records.length < structs.length,\n\t\t\tplain:\n\t\t\t\tplace.plain &&\n\t\t\t\t!valueKinds.object &&\n\t\t\t\tArr.every(classes, (struct) => struct.indexSignatures.length > 0),\n\t\t},\n\t\tcount,\n\t)\n\treturn { field, children, names, key, keyBranch }\n}\n\nconst fieldsOf = (branch: Branch): ReadonlyArray<Field> => [\n\t...(branch.field === undefined ? [] : [branch.field]),\n\t...Arr.flatMap(branch.children, ([, child]) => fieldsOf(child)),\n\t...(branch.keyBranch === undefined ? [] : fieldsOf(branch.keyBranch)),\n]\n\n/**\n * Makes the catalog of a Schema. It throws when a field name has a dot or is\n * empty, and when the Schema has more fields than `catalogFields`.\n */\nexport const catalogOf = (ast: SchemaAST.AST): Catalog => {\n\tconst root = branchOf(\n\t\t{\n\t\t\tpath: [],\n\t\t\tschemas: alternatives(ast, new Set()),\n\t\t\tmissing: false,\n\t\t\ttop: false,\n\t\t\tplain: true,\n\t\t},\n\t\t{ size: 0 },\n\t)\n\treturn { fields: fieldsOf(root), root }\n}\n\n/** Gives the field of a catalog at a path with dots, if the catalog has it. */\nexport const lookup = (catalog: Catalog, path: string): Field | undefined => {\n\tconst names = path.split(\".\", Limits.fieldPathParts + 1)\n\tif (names.length > Limits.fieldPathParts) {\n\t\treturn undefined\n\t}\n\tconst branch = Arr.reduce(\n\t\tnames,\n\t\tcatalog.root as Branch | undefined,\n\t\t(current, name) => {\n\t\t\tif (current === undefined) {\n\t\t\t\treturn undefined\n\t\t\t}\n\t\t\tconst named = HashMap.get(current.names, name)\n\t\t\tif (Option.isSome(named)) {\n\t\t\t\treturn named.value\n\t\t\t}\n\t\t\treturn current.key !== undefined && keyFits(current.key, name)\n\t\t\t\t? current.keyBranch\n\t\t\t\t: undefined\n\t\t},\n\t)\n\treturn branch?.field\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAqCA,MAAa,UAAiB;CAC7B,MAAM;CACN,SAAS;CACT,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,UAAU,CAAC;AACZ;;AAGA,MAAa,WAAkB;CAC9B,MAAM;CACN,SAAS;CACT,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,UAAU,CAAC;AACZ;AAEA,MAAM,YAAmB;CAAE,GAAG;CAAS,MAAM;AAAK;AAClD,MAAM,cAAqB;CAAE,GAAG;CAAS,QAAQ;AAAK;AAEtD,MAAM,cAAc;CAAC;CAAQ;CAAW;CAAU;AAAK;;AAGvD,MAAa,aAAa,MAAa,WAAyB;CAC/D,MAAM,KAAK,QAAQ,MAAM;CACzB,SAAS,KAAK,WAAW,MAAM;CAC/B,QAAQ,KAAK,UAAU,MAAM;CAC7B,QACC,YAAY,QAAQ,KAAK,MAAM,KAAK,YAAY,QAAQ,MAAM,MAAM,IACjE,KAAK,SACL,MAAM;CACV,QAAQ,KAAK,UAAU,MAAM;CAC7B,UAAU,IAAI,OAAO,CAAC,GAAG,KAAK,UAAU,GAAG,MAAM,QAAQ,CAAC;AAC3D;;AAGA,MAAa,cAAc,QAAyB,UAA2B;CAC9E,QAAQ,QAAR;EACC,KAAK,QACJ,OAAO;EACR,KAAK,WACJ,OAAO,OAAO,UAAU,KAAK;EAC9B,KAAK,UACJ,OAAO,OAAO,SAAS,KAAK;EAC7B,KAAK,OACJ,OAAO;CACT;AACD;;;;;AAMA,MAAa,WAAW,OAAc,UAA4B;CACjE,IAAI,UAAU,QAAQ,UAAU,KAAA,GAC/B,OAAO,MAAM;CAEd,QAAQ,OAAO,OAAf;EACC,KAAK,WACJ,OAAO,MAAM,WAAW,MAAM,SAAS,SAAS,KAAK;EACtD,KAAK,UACJ,OAAO,MAAM,UAAU,MAAM,SAAS,SAAS,KAAK;EACrD,KAAK,UACJ,OAAO,WAAW,MAAM,QAAQ,KAAK,KAAK,MAAM,SAAS,SAAS,KAAK;EACxE,SACC,OAAO,MAAM;CACf;AACD;;;;;;;AA6DA,MAAa,WAAW,KAAU,SACjC,IAAI,KAAK,IAAI,aAAa,cAAc;CACvC,MAAM,KAAK,OAAO,GAAG,OAAO,KAAK,SAAS,CAAC;CAC3C,OACC,GAAG,IAAI,KACN,SAAS,MAAM,OAAO,OAAO,IAAI,CAAC,MAAM,QAAQ,GAAG,OAAO,IAAI,CAAC;AAElE,CAAC;;;;;;;;;AAUF,MAAM,eACL,QACmC;CACnC,MAAM,CAAC,SAAS,IAAI;CACpB,OAAO,IAAI,cAAc,oBAAoB,KAAA,KAC5C,IAAI,eAAe,WAAW,KAC9B,OAAO,SAAS,YACd,QACA,KAAA;AACJ;;;;;;;;AASA,MAAM,gBACL,KACA,SACkC;CAClC,QAAQ,IAAI,MAAZ;EACC,KAAK,SACJ,OAAO,IAAI,QAAQ,IAAI,QAAQ,SAAS,aAAa,MAAM,IAAI,CAAC;EACjE,KAAK,WACJ,OAAO,KAAK,IAAI,GAAG,IAChB,CAAC,IACD,aAAa,IAAI,MAAM,mBAAG,IAAI,IAAI,CAAC,GAAG,MAAM,GAAG,CAAC,CAAC;EACrD,SACC,OAAO,CAAC,GAAG;CACb;AACD;;AAGA,MAAM,YAAY,QACjB,IAAI,SAAS,YACV,MACA,IAAI,SAAS,gBACZ,YAAY,GAAG,IACf,KAAA;AAEL,MAAM,YACL,QACA,OAEA,IAAI,KACH,SACC,UACA,MAAM,aAAa,gBAAgB,OAAO,MACzC,MAAM,SAAS,iBAAiB,SAAS,MAAM,QAAQ,EAAE,CAC5D;;AAGD,MAAM,YACL,QAEA,QAAQ,KAAA,MACP,IAAI,mBAAmB,SAAS,KAAK,IAAI,gBAAgB,SAAS;;AAGpE,MAAM,WAAW,QAA8B;CAC9C,QAAQ,IAAI,MAAZ;EACC,KAAK;EACL,KAAK,aACJ,OAAO;EACR,KAAK,SACJ,OAAO;EACR,KAAK;EACL,KAAK,mBACJ,OAAO;GAAE,GAAG;GAAS,QAAQ;EAAK;EACnC,KAAK,WACJ,OAAO;GAAE,GAAG;GAAS,SAAS;EAAK;EACpC,KAAK,UAAU;GAId,MAAM,SAAS,IAAI,UAAU,CAAC;GAC9B,OAAO;IACN,GAAG;IACH,QAAQ,SAAS,QAAQ,qBAAqB,IAC3C,YACA,SAAS,QAAQ,wBAAwB,IACxC,WACA;GACL;EACD;EACA,KAAK,WACJ,OAAO,OAAO,IAAI,YAAY,WAC3B,cACA;GAAE,GAAG;GAAS,UAAU,CAAC,IAAI,OAAO;EAAE;EAC1C,KAAK,QACJ,OAAO;GAAE,GAAG;GAAS,UAAU,IAAI,IAAI,IAAI,QAAQ,GAAG,WAAW,KAAK;EAAE;EACzE,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK,gBACJ,OAAO;EACR,KAAK,eAIJ,OAAO,QAAQ,IAAI,oBAAoB,cAAc,GAAG,CAAC,IACtD,cACA;EACJ,SAGC,OAAO;CACT;AACD;;;;;;;AAQA,MAAM,qBAAqB,QAAQ,KAClC,sBACA,qBACA,4BACA,0BACA,6BACA,+BACA,4BACA,0BACA,uBACA,uBACA,yBACA,yBACA,6BACA,6BACA,wBACA,wBACA,sBACA,sBACA,0BACA,wBACA,+BACD;AAEA,MAAM,iBAAiB,QAAmD;CACzE,MAAM,iBAA0B,IAAI,cAAc;CAClD,OAAO,YAAY,gBAAgB,IAAI,KACtC,OAAO,eAAe,OAAO,WAC3B,eAAe,KACf,KAAA;AACJ;AAcA,MAAM,UAAU,SACf,IAAI,IAAI,OAAO,YACd,OAAO,YAAY,WAAW,UAAU,GACzC,CAAC,CAAC,KAAK,GAAG;;;;;;AAOX,MAAM,UAAU,cACf,OAAO,UAAU,SAAS,WAAW,KAAA,IAAY,OAAO,UAAU,IAAI;;;;;;AAOvE,MAAM,gBACL,WAEA,QAAQ,aACP,IAAI,QAAQ,OAAO,qBAAqB,cAAc;CACrD,MAAM,OAAO,OAAO,SAAS;CAC7B,OAAO,SAAS,KAAA,IAAY,CAAC,IAAI,CAAC,CAAC,MAAM,SAAS,CAAU;AAC7D,CAAC,CACF;;AAGD,MAAM,WACL,YAEA,IAAI,OACH,IAAI,QAAQ,UAAU,WACrB,IAAI,QAAQ,OAAO,qBAAqB,cAAc;CACrD,MAAM,OAAO,OAAO,SAAS;CAC7B,IAAI,SAAS,KAAA,GACZ,OAAO,CAAC;CAIT,IAAI,KAAK,SAAS,GAAG,GACpB,MAAM,IAAI,MAAM,qCAAqC,KAAK,EAAE;CAI7D,IAAI,SAAS,IACZ,MAAM,IAAI,MAAM,+BAA+B;CAEhD,OAAO,CAAC,IAAI;AACb,CAAC,CACF,CACD;;;;;;AAOD,MAAM,YAAY,OAAc,UAAoC;CACnE,MAAM,UAAU,IAAI,OAAO,IAAI,IAAI,MAAM,SAAS,QAAQ,GAAG,QAAQ;CAGrE,MAAM,UAAU,IAAI,OACnB,IAAI,IACH,IAAI,OAAO,MAAM,UAAU,WAAW,OAAO,SAAS,aAAa,GACnE,QACD,GACA,QACD;CACA,MAAM,SAAS,IAAI,OAClB,MAAM,UACL,WAAW,CAAC,SAAS,SAAS,MAAM,CAAC,CACvC;CACA,MAAM,aAAa,IAAI,OAAO,QAAQ,UAAU,OAAO,WACtD,UAAU,OAAO,QAAQ,SAAS,MAAM,KAAK,MAAM,CAAC,CACrD;CACA,MAAM,QAAQ,MAAM,MACjB,WACA,UACA,UAAU,YAAY,QAAQ,SAAS,IAAI,cAAc,OAAO,GAChE,MAAM,UAAU,YAAY,OAC7B;CACF,MAAM,UAAU,IAAI,OACnB,UACC,WAAW,OAAO,gBAAgB,SAAS,CAC7C;CAEA,MAAM,OAAO,MAAM,KAAK,WAAW;CACnC,MAAM,QACL,MAAM,KAAK,WAAW,IACnB,KAAA,IACA;EACA,MAAM,MAAM;EACZ,MAAM,OAAO,MAAM,IAAI;EACvB;EACA,QACC,OAAO,SAAS,KAChB,QAAQ,SAAS,KAChB,QAAQ,QAAQ,SAAS;EAG3B,MACC,QAAQ,SAAS,KACjB,QAAQ,SAAS,KACjB,WAAW,UACX,MAAM;EACP,OAAO,MAAM;CACd;CACH,IAAI,UAAU,KAAA,GAAW;EACxB,MAAM,QAAQ;EACd,IAAI,MAAM,OAAO,KAChB,MAAMA,SACL,YACA,iBACA,UACA,MAAM,MACNC,aACD;CAEF;CACA,IAAI,MACH,OAAO;EACN;EACA,UAAU,CAAC;EACX,OAAO,QAAQ,MAAM;EACrB,KAAK,KAAA;EACL,WAAW,KAAA;CACZ;CAED,MAAM,mBAAmB,IAAI,IAAI,SAAS,YAAY;CACtD,MAAM,kBAAkB,IAAI,IAAI,SAAS,YAAY;CACrD,MAAM,WAAW,IAAI,IAAI,QAAQ,OAAO,IAAI,SAAS;EACpD,MAAM,aAAa,IAAI,QAAQ,mBAAmB,UACjD,OAAO,QAAQ,QAAQ,IAAI,OAAO,IAAI,CAAC,CACxC;EACA,MAAM,QAAe;GACpB,MAAM,CAAC,GAAG,MAAM,MAAM,IAAI;GAC1B,SAAS,IAAI,QAAQ,aAAa,aACjC,aAAa,SAAS,sBAAM,IAAI,IAAI,CAAC,CACtC;GAGA,SACC,MAAM,WACN,OAAO,SAAS,KAChB,IAAI,KAAK,aAAa,aAAa,UAAU,WAAW,SAAS,IAAI,CAAC;GAKvE,KAAK,MAAM,OAAO,WAAW,UAAU,WAAW,SAAS,QAAQ;GACnE,OACC,MAAM,SACN,CAAC,WAAW,UACZ,IAAI,MAAM,kBAAkB,UAAU,QAAQ,IAAI,OAAO,IAAI,CAAC;EAChE;EACA,OAAO,CAAC,MAAM,SAAS,OAAO,KAAK,CAAC;CACrC,CAAC;CACD,MAAM,QAAQ,QAAQ,aAAa,QAAQ;CAC3C,MAAM,aAAa,IAAI,QAAQ,UAAU,WAAW,OAAO,eAAe;CAC1E,IAAI,WAAW,WAAW,GACzB,OAAO;EAAE;EAAO;EAAU;EAAO,KAAK,KAAA;EAAW,WAAW,KAAA;CAAU;CAEvE,MAAM,MAAW;EAChB,MAAM;EACN,YAAY,IAAI,IAAI,aAAa,cAAc,UAAU,SAAS;CACnE;CAiBA,OAAO;EAAE;EAAO;EAAU;EAAO;EAAK,WAhBpB,SACjB;GACC,MAAM,CAAC,GAAG,MAAM,MAAM,GAAG;GACzB,SAAS,IAAI,QAAQ,aAAa,cACjC,aAAa,UAAU,sBAAM,IAAI,IAAI,CAAC,CACvC;GAEA,SAAS;GACT,KAAK,MAAM,OAAO,WAAW,UAAU,QAAQ,SAAS,QAAQ;GAChE,OACC,MAAM,SACN,CAAC,WAAW,UACZ,IAAI,MAAM,UAAU,WAAW,OAAO,gBAAgB,SAAS,CAAC;EAClE,GACA,KAE6C;CAAE;AACjD;AAEA,MAAM,YAAY,WAAyC;CAC1D,GAAI,OAAO,UAAU,KAAA,IAAY,CAAC,IAAI,CAAC,OAAO,KAAK;CACnD,GAAG,IAAI,QAAQ,OAAO,WAAW,GAAG,WAAW,SAAS,KAAK,CAAC;CAC9D,GAAI,OAAO,cAAc,KAAA,IAAY,CAAC,IAAI,SAAS,OAAO,SAAS;AACpE;;;;;AAMA,MAAa,aAAa,QAAgC;CACzD,MAAM,OAAO,SACZ;EACC,MAAM,CAAC;EACP,SAAS,aAAa,qBAAK,IAAI,IAAI,CAAC;EACpC,SAAS;EACT,KAAK;EACL,OAAO;CACR,GACA,EAAE,MAAM,EAAE,CACX;CACA,OAAO;EAAE,QAAQ,SAAS,IAAI;EAAG;CAAK;AACvC;;AAGA,MAAa,UAAU,SAAkB,SAAoC;CAC5E,MAAM,QAAQ,KAAK,MAAM,KAAK,CAAyB;CACvD,IAAI,MAAM,SAAS,GAClB;CAkBD,OAhBe,IAAI,OAClB,OACA,QAAQ,OACP,SAAS,SAAS;EAClB,IAAI,YAAY,KAAA,GACf;EAED,MAAM,QAAQ,QAAQ,IAAI,QAAQ,OAAO,IAAI;EAC7C,IAAI,OAAO,OAAO,KAAK,GACtB,OAAO,MAAM;EAEd,OAAO,QAAQ,QAAQ,KAAA,KAAa,QAAQ,QAAQ,KAAK,IAAI,IAC1D,QAAQ,YACR,KAAA;CACJ,CAEW,CAAC,EAAE;AAChB"}
1
+ {"version":3,"file":"catalog.js","names":["Limits.exceeded","Limits.catalogFields"],"sources":["../../src/internal/catalog.ts"],"sourcesContent":["/**\n * The catalog of the fields of a Schema. One walk over the Schema makes it,\n * and every question about the fields of a resource or of the principal reads\n * it: which names a rule may use, which values a field may hold, which fields\n * a pattern fits, and which fields a list of permitted fields shows.\n *\n * The catalog describes the shape of the values, not the checks of the\n * Schema. A check, such as a minimum length, only keeps some values out, so a\n * catalog that leaves the checks out holds every real value and more. An\n * answer that holds for all of these values, as `All` and `None` of a\n * coverage do, then holds for the real values too.\n */\nimport * as Arr from \"effect/Array\"\nimport * as HashMap from \"effect/HashMap\"\nimport * as HashSet from \"effect/HashSet\"\nimport * as Option from \"effect/Option\"\nimport { hasProperty } from \"effect/Predicate\"\nimport * as Schema from \"effect/Schema\"\nimport * as SchemaAST from \"effect/SchemaAST\"\nimport * as Limits from \"./limits.ts\"\n\n/** The kinds of values that a field may hold. */\nexport interface Kinds {\n\t/** The field may be `null`, `undefined` or missing. */\n\treadonly null: boolean\n\treadonly boolean: boolean\n\t/** The field may hold any string. */\n\treadonly string: boolean\n\t/** The numbers that the field may hold. */\n\treadonly number: \"none\" | \"integer\" | \"finite\" | \"any\"\n\t/** The field may hold an object, or a value that is not a scalar. */\n\treadonly object: boolean\n\t/** Single values that the field may hold, other than the ones above. */\n\treadonly literals: ReadonlyArray<string | number | boolean>\n}\n\n/** No value: the kinds of a field of `Schema.Never`. */\nexport const noKinds: Kinds = {\n\tnull: false,\n\tboolean: false,\n\tstring: false,\n\tnumber: \"none\",\n\tobject: false,\n\tliterals: [],\n}\n\n/** Any value. */\nexport const anyKinds: Kinds = {\n\tnull: true,\n\tboolean: true,\n\tstring: true,\n\tnumber: \"any\",\n\tobject: true,\n\tliterals: [],\n}\n\nconst nullKinds: Kinds = { ...noKinds, null: true }\nconst objectKinds: Kinds = { ...noKinds, object: true }\n\nconst numberOrder = [\"none\", \"integer\", \"finite\", \"any\"] as const\n\n/** The kinds of a field that may hold a value of `left` or of `right`. */\nexport const joinKinds = (left: Kinds, right: Kinds): Kinds => ({\n\tnull: left.null || right.null,\n\tboolean: left.boolean || right.boolean,\n\tstring: left.string || right.string,\n\tnumber:\n\t\tnumberOrder.indexOf(left.number) >= numberOrder.indexOf(right.number)\n\t\t\t? left.number\n\t\t\t: right.number,\n\tobject: left.object || right.object,\n\t// A native `Set` finds copies about ten times as fast as `Arr.dedupe`. It\n\t// takes `0` and `-0` as one, as `includes` does when a test reads them.\n\tliterals: Array.from(new Set([...left.literals, ...right.literals])),\n})\n\n/** Tests if a number fits the numbers of a field. */\nexport const fitsNumber = (number: Kinds[\"number\"], value: number): boolean => {\n\tswitch (number) {\n\t\tcase \"none\":\n\t\t\treturn false\n\t\tcase \"integer\":\n\t\t\treturn Number.isInteger(value)\n\t\tcase \"finite\":\n\t\t\treturn Number.isFinite(value)\n\t\tcase \"any\":\n\t\t\treturn true\n\t}\n}\n\n/**\n * Tests if a field with these kinds may hold a value. A missing value and\n * `undefined` are `null`.\n */\nexport const accepts = (kinds: Kinds, value: unknown): boolean => {\n\tif (value === null || value === undefined) {\n\t\treturn kinds.null\n\t}\n\tswitch (typeof value) {\n\t\tcase \"boolean\":\n\t\t\treturn kinds.boolean || kinds.literals.includes(value)\n\t\tcase \"string\":\n\t\t\treturn kinds.string || kinds.literals.includes(value)\n\t\tcase \"number\":\n\t\t\treturn fitsNumber(kinds.number, value) || kinds.literals.includes(value)\n\t\tdefault:\n\t\t\treturn kinds.object\n\t}\n}\n\n/** A part of a field path that stands for any key of a record. */\nexport interface Key {\n\treadonly _tag: \"Key\"\n\t/** The Schemas of the keys. A key must fit one of them. */\n\treadonly parameters: ReadonlyArray<SchemaAST.AST>\n}\n\n/** One part of a field path: a name, or any key of a record. */\nexport type Segment = string | Key\n\n/** One field of a catalog. */\nexport interface Field {\n\treadonly path: ReadonlyArray<Segment>\n\t/** The path with dots, and `*` for a key of a record. */\n\treadonly text: string\n\treadonly kinds: Kinds\n\t/**\n\t * The field holds a value that a list of fields shows as one field: a\n\t * scalar, a record, an array, or a struct at the last part a path may have.\n\t */\n\treadonly listed: boolean\n\t/** The field may hold parts that the Schema does not name, as a record may. */\n\treadonly open: boolean\n\t/**\n\t * A read of the field finds only plain data. It is `false` when a value\n\t * above the field may be an object that does not have it as a data field:\n\t * a class without the field, which may have a getter of that name, a\n\t * value such as a date or a list, or any object, as of `Schema.Unknown`.\n\t * A decode or a `make` copies a struct or a record into a plain object,\n\t * so a struct without the field gives `null` for it.\n\t */\n\treadonly plain: boolean\n}\n\n/** A place in the tree of a catalog, with the places below it. */\nexport interface Branch {\n\t/** The field at this place. The root has none. */\n\treadonly field: Field | undefined\n\t/** The places below, by name, in the order of the Schema. */\n\treadonly children: ReadonlyArray<readonly [string, Branch]>\n\t/**\n\t * The places below, by name. A lookup gets each name from `split`, as a\n\t * new string, and a `HashMap` finds a new string about 20% faster than a\n\t * native `Map`. The names come from the Schema, so a name from a policy\n\t * can not make a long list of names with one hash here.\n\t */\n\treadonly names: HashMap.HashMap<string, Branch>\n\t/** The place for the keys of a record, when the value may be a record. */\n\treadonly key: Key | undefined\n\treadonly keyBranch: Branch | undefined\n}\n\n/** The catalog of the fields of a Schema. */\nexport interface Catalog {\n\t/** Every field, a field before the fields below it. */\n\treadonly fields: ReadonlyArray<Field>\n\treadonly root: Branch\n}\n\n/**\n * Tests if a key of an object fits the Schemas of the keys of a record. A key\n * of an object is a string, also a key that a number Schema takes: `{ 1: \"a\" }`\n * has the key `\"1\"`. So a key that is the text of a number is tried as that\n * number too.\n */\nexport const keyFits = (key: Key, name: string): boolean =>\n\tArr.some(key.parameters, (parameter) => {\n\t\tconst is = Schema.is(Schema.make(parameter))\n\t\treturn (\n\t\t\tis(name) ||\n\t\t\t(name !== \"\" && String(Number(name)) === name && is(Number(name)))\n\t\t)\n\t})\n\n/**\n * Gives the struct of a `Schema.Class`. A class is a declaration with one\n * struct as its type parameter, and Effect marks it with a `\"~constructor\"`\n * annotation, also through more codec steps, as in\n * `Schema.fromJsonString(User)`. Other declarations, such as `Schema.Option`\n * or `Schema.ReadonlyMap`, have no such mark, and the fields of their type\n * parameter are not fields of the value.\n */\nconst classStruct = (\n\tast: SchemaAST.Declaration,\n): SchemaAST.Objects | undefined => {\n\tconst [inner] = ast.typeParameters\n\treturn ast.annotations?.[\"~constructor\"] !== undefined &&\n\t\tast.typeParameters.length === 1 &&\n\t\tinner?._tag === \"Objects\"\n\t\t? inner\n\t\t: undefined\n}\n\n/**\n * Gives the Schemas that a value at one place may fit: it opens unions and\n * `Schema.suspend`. A class stays a class: see {@link structOf}. The open suspend nodes are in a native `Set`,\n * because the walk must find a node by the node itself: `Equal` compares\n * Schema nodes by structure, and a recursive Schema has no end. A suspend\n * node that gives itself again, with no step on the path, gives nothing.\n */\nconst alternatives = (\n\tast: SchemaAST.AST,\n\topen: ReadonlySet<SchemaAST.AST>,\n): ReadonlyArray<SchemaAST.AST> => {\n\tswitch (ast._tag) {\n\t\tcase \"Union\":\n\t\t\treturn Arr.flatMap(ast.types, (type) => alternatives(type, open))\n\t\tcase \"Suspend\":\n\t\t\treturn open.has(ast)\n\t\t\t\t? []\n\t\t\t\t: alternatives(ast.thunk(), new Set([...open, ast]))\n\t\tdefault:\n\t\t\treturn [ast]\n\t}\n}\n\n/** The struct of a Schema: a struct, or the struct of a class. */\nconst structOf = (ast: SchemaAST.AST): SchemaAST.Objects | undefined =>\n\tast._tag === \"Objects\"\n\t\t? ast\n\t\t: ast._tag === \"Declaration\"\n\t\t\t? classStruct(ast)\n\t\t\t: undefined\n\nconst hasCheck = (\n\tchecks: ReadonlyArray<SchemaAST.Check<never>>,\n\tid: string,\n): boolean =>\n\tArr.some(\n\t\tchecks,\n\t\t(check) =>\n\t\t\tcheck.annotations?.representation?.id === id ||\n\t\t\t(check._tag === \"FilterGroup\" && hasCheck(check.checks, id)),\n\t)\n\n/** A struct with named fields, or with the keys of a record. */\nconst isStruct = (\n\tast: SchemaAST.Objects | undefined,\n): ast is SchemaAST.Objects =>\n\tast !== undefined &&\n\t(ast.propertySignatures.length > 0 || ast.indexSignatures.length > 0)\n\n/** The kinds of the values of a Schema that is not a struct. */\nconst kindsOf = (ast: SchemaAST.AST): Kinds => {\n\tswitch (ast._tag) {\n\t\tcase \"Null\":\n\t\tcase \"Undefined\":\n\t\t\treturn nullKinds\n\t\tcase \"Never\":\n\t\t\treturn noKinds\n\t\tcase \"String\":\n\t\tcase \"TemplateLiteral\":\n\t\t\treturn { ...noKinds, string: true }\n\t\tcase \"Boolean\":\n\t\t\treturn { ...noKinds, boolean: true }\n\t\tcase \"Number\": {\n\t\t\t// The two checks that a search uses. Effect names a number with\n\t\t\t// them, as `Schema.Int` and `Schema.Finite`; other checks are left\n\t\t\t// out, as all checks are.\n\t\t\tconst checks = ast.checks ?? []\n\t\t\treturn {\n\t\t\t\t...noKinds,\n\t\t\t\tnumber: hasCheck(checks, \"effect/schema/isInt\")\n\t\t\t\t\t? \"integer\"\n\t\t\t\t\t: hasCheck(checks, \"effect/schema/isFinite\")\n\t\t\t\t\t\t? \"finite\"\n\t\t\t\t\t\t: \"any\",\n\t\t\t}\n\t\t}\n\t\tcase \"Literal\":\n\t\t\treturn typeof ast.literal === \"bigint\"\n\t\t\t\t? objectKinds\n\t\t\t\t: { ...noKinds, literals: [ast.literal] }\n\t\tcase \"Enum\":\n\t\t\treturn { ...noKinds, literals: Arr.map(ast.enums, ([, value]) => value) }\n\t\tcase \"Arrays\":\n\t\tcase \"ObjectKeyword\":\n\t\tcase \"BigInt\":\n\t\tcase \"Symbol\":\n\t\tcase \"UniqueSymbol\":\n\t\t\treturn objectKinds\n\t\tcase \"Declaration\":\n\t\t\t// A declaration of Effect in `objectDeclarations` holds an object,\n\t\t\t// such as a `Date`. Another declaration may hold any value, as\n\t\t\t// `Schema.Json` or one from `Schema.declare` may.\n\t\t\treturn HashSet.has(objectDeclarations, declarationId(ast))\n\t\t\t\t? objectKinds\n\t\t\t\t: anyKinds\n\t\tdefault:\n\t\t\t// `Schema.Unknown`, `Schema.Void`, and `Struct({})`, which takes a\n\t\t\t// string too: these may hold any value.\n\t\t\treturn anyKinds\n\t}\n}\n\n/**\n * The ids of the declarations of Effect that hold only objects. Effect puts\n * the id in the `representation` annotation. A declaration that is not in\n * this list may hold a scalar, as `Schema.Json` may, so its kinds are any\n * value.\n */\nconst objectDeclarations = HashSet.make(\n\t\"effect/schema/Date\",\n\t\"effect/schema/URL\",\n\t\"effect/schema/Uint8Array\",\n\t\"effect/schema/Duration\",\n\t\"effect/schema/DateTimeUtc\",\n\t\"effect/schema/DateTimeZoned\",\n\t\"effect/schema/BigDecimal\",\n\t\"effect/schema/Redacted\",\n\t\"effect/schema/Cause\",\n\t\"effect/schema/Chunk\",\n\t\"effect/schema/HashMap\",\n\t\"effect/schema/HashSet\",\n\t\"effect/schema/ReadonlyMap\",\n\t\"effect/schema/ReadonlySet\",\n\t\"effect/schema/Option\",\n\t\"effect/schema/Result\",\n\t\"effect/schema/Exit\",\n\t\"effect/schema/File\",\n\t\"effect/schema/FormData\",\n\t\"effect/schema/RegExp\",\n\t\"effect/schema/URLSearchParams\",\n)\n\nconst declarationId = (ast: SchemaAST.Declaration): string | undefined => {\n\tconst representation: unknown = ast.annotations?.[\"representation\"]\n\treturn hasProperty(representation, \"id\") &&\n\t\ttypeof representation.id === \"string\"\n\t\t? representation.id\n\t\t: undefined\n}\n\n/** The things that a walk of the catalog knows at one place. */\ninterface Place {\n\treadonly path: ReadonlyArray<Segment>\n\treadonly schemas: ReadonlyArray<SchemaAST.AST>\n\t/** The value may be missing. */\n\treadonly missing: boolean\n\t/** The value may be anything, as an extra field of a struct may be. */\n\treadonly top: boolean\n\t/** A read here finds only plain data: see {@link Field.plain}. */\n\treadonly plain: boolean\n}\n\nconst textOf = (path: ReadonlyArray<Segment>): string =>\n\tArr.map(path, (segment) =>\n\t\ttypeof segment === \"string\" ? segment : \"*\",\n\t).join(\".\")\n\n/**\n * The name of a property as a part of a path. A key of an object is a string,\n * so a number key, as from `Schema.Record(Schema.Literal(1), ...)`, has the\n * name `\"1\"`. A symbol key is not a field.\n */\nconst nameOf = (signature: SchemaAST.PropertySignature): string | undefined =>\n\ttypeof signature.name === \"symbol\" ? undefined : String(signature.name)\n\n/**\n * The properties of a struct by name. A walk makes it one time for each\n * struct of a place, so a struct with very many fields does not take a\n * search for each name. It is a native `Map`, as `Branch.names` is.\n */\nconst propertiesOf = (\n\tstruct: SchemaAST.Objects,\n): ReadonlyMap<string, SchemaAST.PropertySignature> =>\n\tnew Map(\n\t\tArr.flatMap(struct.propertySignatures, (signature) => {\n\t\t\tconst name = nameOf(signature)\n\t\t\treturn name === undefined ? [] : [[name, signature] as const]\n\t\t}),\n\t)\n\n/** The names of the fields of the structs, in the order that they first come. */\nconst namesOf = (\n\tstructs: ReadonlyArray<SchemaAST.Objects>,\n): ReadonlyArray<string> =>\n\t// A native `Set` keeps the first copy of each name, in order, about ten\n\t// times as fast as `Arr.dedupe`.\n\tArray.from(\n\t\tnew Set(\n\t\t\tArr.flatMap(structs, (struct) =>\n\t\t\t\tArr.flatMap(struct.propertySignatures, (signature) => {\n\t\t\t\t\tconst name = nameOf(signature)\n\t\t\t\t\tif (name === undefined) {\n\t\t\t\t\t\treturn []\n\t\t\t\t\t}\n\t\t\t\t\t// A dot in a path is the step into a nested field. A field name with\n\t\t\t\t\t// a dot would make two fields have one path, so it is a defect.\n\t\t\t\t\tif (name.includes(\".\")) {\n\t\t\t\t\t\tthrow new Error(`A field name may not have a dot: \"${name}\"`)\n\t\t\t\t\t}\n\t\t\t\t\t// An empty name would make an empty part in a path, such as\n\t\t\t\t\t// `.secret`.\n\t\t\t\t\tif (name === \"\") {\n\t\t\t\t\t\tthrow new Error(\"A field name may not be empty\")\n\t\t\t\t\t}\n\t\t\t\t\treturn [name]\n\t\t\t\t}),\n\t\t\t),\n\t\t),\n\t)\n\n/**\n * Makes the branch of a place, with the branches below it. `count` is the\n * number of fields so far. It belongs to one walk, and it stops a Schema with\n * very many fields before the walk is done.\n */\nconst branchOf = (place: Place, count: { size: number }): Branch => {\n\tconst structs = Arr.filter(Arr.map(place.schemas, structOf), isStruct)\n\t// The structs of classes. A value of a class is not copied into a plain\n\t// object, so it keeps its getters and methods.\n\tconst classes = Arr.filter(\n\t\tArr.map(\n\t\t\tArr.filter(place.schemas, (schema) => schema._tag === \"Declaration\"),\n\t\t\tstructOf,\n\t\t),\n\t\tisStruct,\n\t)\n\tconst values = Arr.filter(\n\t\tplace.schemas,\n\t\t(schema) => !isStruct(structOf(schema)),\n\t)\n\tconst valueKinds = Arr.reduce(values, noKinds, (kinds, schema) =>\n\t\tjoinKinds(kinds, kindsOf(structOf(schema) ?? schema)),\n\t)\n\tconst kinds = place.top\n\t\t? anyKinds\n\t\t: joinKinds(\n\t\t\t\tjoinKinds(valueKinds, structs.length > 0 ? objectKinds : noKinds),\n\t\t\t\tplace.missing ? nullKinds : noKinds,\n\t\t\t)\n\tconst records = Arr.filter(\n\t\tstructs,\n\t\t(struct) => struct.indexSignatures.length > 0,\n\t)\n\t// The last part that a path may have: the walk does not go below it.\n\tconst last = place.path.length === Limits.fieldPathParts\n\tconst field: Field | undefined =\n\t\tplace.path.length === 0\n\t\t\t? undefined\n\t\t\t: {\n\t\t\t\t\tpath: place.path,\n\t\t\t\t\ttext: textOf(place.path),\n\t\t\t\t\tkinds,\n\t\t\t\t\tlisted:\n\t\t\t\t\t\tvalues.length > 0 ||\n\t\t\t\t\t\trecords.length > 0 ||\n\t\t\t\t\t\t(last && structs.length > 0),\n\t\t\t\t\t// A field that is a scalar in one branch of a union and a struct\n\t\t\t\t\t// in another holds parts too.\n\t\t\t\t\topen:\n\t\t\t\t\t\trecords.length > 0 ||\n\t\t\t\t\t\tstructs.length > 0 ||\n\t\t\t\t\t\tvalueKinds.object ||\n\t\t\t\t\t\tplace.top,\n\t\t\t\t\tplain: place.plain,\n\t\t\t\t}\n\tif (field !== undefined) {\n\t\tcount.size += 1\n\t\tif (count.size > Limits.catalogFields) {\n\t\t\tthrow Limits.exceeded(\n\t\t\t\t\"A Schema\",\n\t\t\t\t\"catalogFields\",\n\t\t\t\t\"fields\",\n\t\t\t\tcount.size,\n\t\t\t\tLimits.catalogFields,\n\t\t\t)\n\t\t}\n\t}\n\tif (last) {\n\t\treturn {\n\t\t\tfield,\n\t\t\tchildren: [],\n\t\t\tnames: HashMap.empty(),\n\t\t\tkey: undefined,\n\t\t\tkeyBranch: undefined,\n\t\t}\n\t}\n\tconst structProperties = Arr.map(structs, propertiesOf)\n\tconst classProperties = Arr.map(classes, propertiesOf)\n\tconst children = Arr.map(namesOf(structs), (name) => {\n\t\tconst properties = Arr.flatMap(structProperties, (named) => {\n\t\t\tconst property = named.get(name)\n\t\t\treturn property === undefined ? [] : [property]\n\t\t})\n\t\tconst below: Place = {\n\t\t\tpath: [...place.path, name],\n\t\t\tschemas: Arr.flatMap(properties, (property) =>\n\t\t\t\talternatives(property.type, new Set()),\n\t\t\t),\n\t\t\t// A field below a value that is not a struct reads `null`, and so\n\t\t\t// does a field that may be missing.\n\t\t\tmissing:\n\t\t\t\tplace.missing ||\n\t\t\t\tvalues.length > 0 ||\n\t\t\t\tArr.some(properties, (property) => SchemaAST.isOptional(property.type)),\n\t\t\t// A struct without the name may still have it as an extra field,\n\t\t\t// with any value: only a decode takes extra fields away. A value\n\t\t\t// that may be any object, as one of `Schema.Unknown` may, may have\n\t\t\t// the name with any value too.\n\t\t\ttop: place.top || valueKinds.object || properties.length < structs.length,\n\t\t\tplain:\n\t\t\t\tplace.plain &&\n\t\t\t\t!valueKinds.object &&\n\t\t\t\tArr.every(classProperties, (named) => named.has(name)),\n\t\t}\n\t\treturn [name, branchOf(below, count)] as const\n\t})\n\tconst names = HashMap.fromIterable(children)\n\tconst signatures = Arr.flatMap(records, (struct) => struct.indexSignatures)\n\tif (signatures.length === 0) {\n\t\treturn { field, children, names, key: undefined, keyBranch: undefined }\n\t}\n\tconst key: Key = {\n\t\t_tag: \"Key\",\n\t\tparameters: Arr.map(signatures, (signature) => signature.parameter),\n\t}\n\tconst keyBranch = branchOf(\n\t\t{\n\t\t\tpath: [...place.path, key],\n\t\t\tschemas: Arr.flatMap(signatures, (signature) =>\n\t\t\t\talternatives(signature.type, new Set()),\n\t\t\t),\n\t\t\t// A record may not have a given key.\n\t\t\tmissing: true,\n\t\t\ttop: place.top || valueKinds.object || records.length < structs.length,\n\t\t\tplain:\n\t\t\t\tplace.plain &&\n\t\t\t\t!valueKinds.object &&\n\t\t\t\tArr.every(classes, (struct) => struct.indexSignatures.length > 0),\n\t\t},\n\t\tcount,\n\t)\n\treturn { field, children, names, key, keyBranch }\n}\n\nconst fieldsOf = (branch: Branch): ReadonlyArray<Field> => [\n\t...(branch.field === undefined ? [] : [branch.field]),\n\t...Arr.flatMap(branch.children, ([, child]) => fieldsOf(child)),\n\t...(branch.keyBranch === undefined ? [] : fieldsOf(branch.keyBranch)),\n]\n\n/**\n * Makes the catalog of a Schema. It throws when a field name has a dot or is\n * empty, and when the Schema has more fields than `catalogFields`.\n */\nexport const catalogOf = (ast: SchemaAST.AST): Catalog => {\n\tconst root = branchOf(\n\t\t{\n\t\t\tpath: [],\n\t\t\tschemas: alternatives(ast, new Set()),\n\t\t\tmissing: false,\n\t\t\ttop: false,\n\t\t\tplain: true,\n\t\t},\n\t\t{ size: 0 },\n\t)\n\treturn { fields: fieldsOf(root), root }\n}\n\n/** Gives the field of a catalog at a path with dots, if the catalog has it. */\nexport const lookup = (catalog: Catalog, path: string): Field | undefined => {\n\tconst names = path.split(\".\", Limits.fieldPathParts + 1)\n\tif (names.length > Limits.fieldPathParts) {\n\t\treturn undefined\n\t}\n\tconst branch = Arr.reduce(\n\t\tnames,\n\t\tcatalog.root as Branch | undefined,\n\t\t(current, name) => {\n\t\t\tif (current === undefined) {\n\t\t\t\treturn undefined\n\t\t\t}\n\t\t\tconst named = HashMap.get(current.names, name)\n\t\t\tif (Option.isSome(named)) {\n\t\t\t\treturn named.value\n\t\t\t}\n\t\t\treturn current.key !== undefined && keyFits(current.key, name)\n\t\t\t\t? current.keyBranch\n\t\t\t\t: undefined\n\t\t},\n\t)\n\treturn branch?.field\n}\n"],"mappings":"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"}
@@ -5,10 +5,10 @@ import { evaluate } from "../Condition.js";
5
5
  import { descriptorOf } from "./domain.js";
6
6
  import { fitsOf, matchesInside, matchesTarget } from "./rule.js";
7
7
  import { nodeOf } from "./policy.js";
8
+ import * as Chunk from "effect/Chunk";
8
9
  import * as Effect from "effect/Effect";
9
10
  import * as Arr from "effect/Array";
10
11
  import * as Option from "effect/Option";
11
- import * as Chunk from "effect/Chunk";
12
12
  import * as Ref from "effect/Ref";
13
13
  // src/internal/decide.ts
14
14
  /**
@@ -1,9 +1,9 @@
1
1
  import { catalogOf } from "./catalog.js";
2
2
  import { descriptor } from "./resource.js";
3
+ import * as HashMap from "effect/HashMap";
3
4
  import * as Data from "effect/Data";
4
5
  import * as Arr from "effect/Array";
5
6
  import * as Option from "effect/Option";
6
- import * as HashMap from "effect/HashMap";
7
7
  // src/internal/domain.ts
8
8
  /**
9
9
  * The values of domains. The types are in `Domain.ts`.
@@ -1,5 +1,5 @@
1
1
  import { LimitExceeded, jsonNodes } from "./limits.js";
2
- import { And, Compare, Exists, In, Not, Or, Under, always, isScalar, literal, never, principalRef, toJson as toJson$1 } from "./nodes.js";
2
+ import { And, Compare, Exists, In, Not, Or, Under, always, isCompareOperator, isScalar, literal, never, principalRef, toJson as toJson$1 } from "./nodes.js";
3
3
  import { readPart } from "./read.js";
4
4
  import * as Result from "effect/Result";
5
5
  import * as Data from "effect/Data";
@@ -66,14 +66,6 @@ const decodeOperands = (input, name, path, budget) => Arr.map(readList(input, na
66
66
  name,
67
67
  index
68
68
  ]));
69
- const compareOperators = [
70
- "eq",
71
- "ne",
72
- "lt",
73
- "lte",
74
- "gt",
75
- "gte"
76
- ];
77
69
  const decodeNode = (input, path, depth, budget) => {
78
70
  if (depth > 500) throw problem(path, `A condition has more than ${String(500)} levels. The most is ${String(500)}.`);
79
71
  if (typeof input !== "object" || input === null) throw problem(path, "A condition node must be an object");
@@ -96,7 +88,7 @@ const makeNode = (input, path, depth, budget, children) => {
96
88
  case "False": return never;
97
89
  case "Compare": {
98
90
  const op = readString(input, "op", path);
99
- if (!compareOperators.includes(op)) throw problem([...path, "op"], `"${op}" is not a compare operator`);
91
+ if (!isCompareOperator(op)) throw problem([...path, "op"], `"${op}" is not a compare operator`);
100
92
  return new Compare({
101
93
  op,
102
94
  field: readString(input, "field", path),
@@ -1 +1 @@
1
- {"version":3,"file":"json.js","names":["Nodes.toJson","Limits.jsonNodes","Nodes.isScalar","Nodes.literal","Nodes.principalRef","Limits.LimitExceeded","Nodes.always","Nodes.never","Nodes.Compare","Nodes.In","Nodes.Exists","Nodes.Under","Nodes.And","Nodes.Or","Nodes.Not"],"sources":["../../src/internal/json.ts"],"sourcesContent":["/**\n * The JSON form of a condition. The decoder is a plain walk with two limits:\n * it goes at most `conditionDepth` levels down, and it reads at most\n * `jsonNodes` objects and array items, with a shared object counted for each\n * place. So no input can fill the stack or take a very long time. It makes\n * each node with its constructor, and it reads only the own data fields of\n * the input, as a condition reads a value.\n */\nimport * as Arr from \"effect/Array\"\nimport * as Data from \"effect/Data\"\nimport * as Result from \"effect/Result\"\nimport type * as SchemaIssue from \"effect/SchemaIssue\"\nimport * as Limits from \"./limits.ts\"\nimport * as Nodes from \"./nodes.ts\"\nimport { readPart } from \"./read.ts\"\n\ntype Node = Nodes.Node\n\n/** Gives the JSON form of a condition with no predicate. See `Nodes.toJson`. */\nexport const toJson = (node: Node): unknown => Nodes.toJson(node)\n\n/** A problem of an input, with the path of the problem. */\nexport class Problem extends Data.TaggedError(\"Problem\")<{\n\treadonly path: ReadonlyArray<PropertyKey>\n\treadonly message: string\n\t/** The issue of a Schema that the decode used, as for `meta`. */\n\treadonly issue?: SchemaIssue.Issue | undefined\n}> {}\n\n/** The count of the objects and items that one decode has read. It belongs to one decode. */\nexport interface Budget {\n\tused: number\n}\n\nexport const problem = (path: ReadonlyArray<PropertyKey>, message: string) =>\n\tnew Problem({ path, message })\n\n/** Counts `count` more objects or items, and stops past the limit. */\nexport const spend = (\n\tbudget: Budget,\n\tcount: number,\n\tpath: ReadonlyArray<PropertyKey>,\n): void => {\n\tbudget.used += count\n\tif (budget.used > Limits.jsonNodes) {\n\t\tthrow problem(\n\t\t\tpath,\n\t\t\t`The input has more than ${String(Limits.jsonNodes)} objects and items. The most is ${String(Limits.jsonNodes)}.`,\n\t\t)\n\t}\n}\n\n/** Reads a field of the input. A field that is not plain data is a problem. */\nexport const read = (\n\tinput: unknown,\n\tname: string,\n\tpath: ReadonlyArray<PropertyKey>,\n): unknown => {\n\ttry {\n\t\treturn readPart(input, name)\n\t} catch {\n\t\tthrow problem([...path, name], `The field \"${name}\" is not plain data`)\n\t}\n}\n\nexport const readString = (\n\tinput: unknown,\n\tname: string,\n\tpath: ReadonlyArray<PropertyKey>,\n): string => {\n\tconst value = read(input, name, path)\n\tif (typeof value !== \"string\") {\n\t\tthrow problem([...path, name], `The field \"${name}\" must be a string`)\n\t}\n\treturn value\n}\n\n/** Reads the items of an array. */\nexport const readList = (\n\tinput: unknown,\n\tname: string,\n\tpath: ReadonlyArray<PropertyKey>,\n\tbudget: Budget,\n): ReadonlyArray<unknown> => {\n\tconst value = read(input, name, path)\n\tconst at = [...path, name]\n\tif (!Array.isArray(value)) {\n\t\tthrow problem(at, `The field \"${name}\" must be an array`)\n\t}\n\tconst list: ReadonlyArray<unknown> = value\n\tspend(budget, list.length, at)\n\t// `Array.makeBy` of Effect gives at least one item, so it can not make an\n\t// empty list. An array-like object with a length makes one with no read\n\t// of the items before the read rule.\n\treturn Array.from({ length: list.length }, (_, index) =>\n\t\tread(list, String(index), at),\n\t)\n}\n\nconst isJsonScalar = (value: unknown): value is Nodes.Scalar =>\n\tNodes.isScalar(value) && (typeof value !== \"number\" || Number.isFinite(value))\n\nconst decodeOperand = (\n\tinput: unknown,\n\tpath: ReadonlyArray<PropertyKey>,\n): Nodes.Operand => {\n\tconst tag = read(input, \"_tag\", path)\n\tif (tag === \"Literal\") {\n\t\t// A missing value is not `null`: a test with `null` has its own\n\t\t// meaning, and a lost value must not become one.\n\t\tconst own =\n\t\t\ttypeof input === \"object\" && input !== null\n\t\t\t\t? Object.getOwnPropertyDescriptor(input, \"value\")\n\t\t\t\t: undefined\n\t\tif (own === undefined || (\"value\" in own && own.value === undefined)) {\n\t\t\tthrow problem([...path, \"value\"], \"A fixed value is missing\")\n\t\t}\n\t\tconst value = read(input, \"value\", path)\n\t\tif (!isJsonScalar(value)) {\n\t\t\tthrow problem(\n\t\t\t\t[...path, \"value\"],\n\t\t\t\t\"A fixed value must be a string, a finite number, a boolean or null\",\n\t\t\t)\n\t\t}\n\t\treturn Nodes.literal(value)\n\t}\n\tif (tag === \"Principal\") {\n\t\treturn Nodes.principalRef(readString(input, \"path\", path))\n\t}\n\tthrow problem(\n\t\t[...path, \"_tag\"],\n\t\t'An operand must have the tag \"Literal\" or \"Principal\"',\n\t)\n}\n\nconst decodeOperands = (\n\tinput: unknown,\n\tname: string,\n\tpath: ReadonlyArray<PropertyKey>,\n\tbudget: Budget,\n): ReadonlyArray<Nodes.Operand> =>\n\tArr.map(readList(input, name, path, budget), (operand, index) =>\n\t\tdecodeOperand(operand, [...path, name, index]),\n\t)\n\nconst compareOperators: ReadonlyArray<string> = [\n\t\"eq\",\n\t\"ne\",\n\t\"lt\",\n\t\"lte\",\n\t\"gt\",\n\t\"gte\",\n]\n\nconst decodeNode = (\n\tinput: unknown,\n\tpath: ReadonlyArray<PropertyKey>,\n\tdepth: number,\n\tbudget: Budget,\n): Node => {\n\tif (depth > Limits.conditionDepth) {\n\t\tthrow problem(\n\t\t\tpath,\n\t\t\t`A condition has more than ${String(Limits.conditionDepth)} levels. The most is ${String(Limits.conditionDepth)}.`,\n\t\t)\n\t}\n\tif (typeof input !== \"object\" || input === null) {\n\t\tthrow problem(path, \"A condition node must be an object\")\n\t}\n\tspend(budget, 1, path)\n\tconst children = (name: string) =>\n\t\tArr.map(readList(input, name, path, budget), (child, index) =>\n\t\t\tdecodeNode(child, [...path, name, index], depth + 1, budget),\n\t\t)\n\ttry {\n\t\treturn makeNode(input, path, depth, budget, children)\n\t} catch (error) {\n\t\t// A node past a limit, such as a field path with too many parts, is a\n\t\t// problem at its place.\n\t\tif (error instanceof Limits.LimitExceeded) {\n\t\t\tthrow problem(path, error.message)\n\t\t}\n\t\tthrow error\n\t}\n}\n\nconst makeNode = (\n\tinput: object,\n\tpath: ReadonlyArray<PropertyKey>,\n\tdepth: number,\n\tbudget: Budget,\n\tchildren: (name: string) => ReadonlyArray<Node>,\n): Node => {\n\tconst tag = read(input, \"_tag\", path)\n\tswitch (tag) {\n\t\tcase \"True\":\n\t\t\treturn Nodes.always\n\t\tcase \"False\":\n\t\t\treturn Nodes.never\n\t\tcase \"Compare\": {\n\t\t\tconst op = readString(input, \"op\", path)\n\t\t\tif (!compareOperators.includes(op)) {\n\t\t\t\tthrow problem([...path, \"op\"], `\"${op}\" is not a compare operator`)\n\t\t\t}\n\t\t\treturn new Nodes.Compare({\n\t\t\t\top: op as Nodes.CompareOperator,\n\t\t\t\tfield: readString(input, \"field\", path),\n\t\t\t\tvalue: decodeOperand(read(input, \"value\", path), [...path, \"value\"]),\n\t\t\t})\n\t\t}\n\t\tcase \"In\":\n\t\t\treturn new Nodes.In({\n\t\t\t\tfield: readString(input, \"field\", path),\n\t\t\t\tvalues: decodeOperands(input, \"values\", path, budget),\n\t\t\t})\n\t\tcase \"Exists\":\n\t\t\treturn new Nodes.Exists({ field: readString(input, \"field\", path) })\n\t\tcase \"Under\":\n\t\t\treturn new Nodes.Under({\n\t\t\t\tprefix: decodeOperands(input, \"prefix\", path, budget),\n\t\t\t})\n\t\tcase \"And\":\n\t\t\treturn new Nodes.And(children(\"conditions\"))\n\t\tcase \"Or\":\n\t\t\treturn new Nodes.Or(children(\"conditions\"))\n\t\tcase \"Not\":\n\t\t\treturn new Nodes.Not(\n\t\t\t\tdecodeNode(\n\t\t\t\t\tread(input, \"condition\", path),\n\t\t\t\t\t[...path, \"condition\"],\n\t\t\t\t\tdepth + 1,\n\t\t\t\t\tbudget,\n\t\t\t\t),\n\t\t\t)\n\t\tdefault:\n\t\t\tthrow problem([...path, \"_tag\"], \"The node has no known tag\")\n\t}\n}\n\n/**\n * Decodes the JSON form of a condition at a path, with the budget of a larger\n * decode. It throws a {@link Problem}.\n */\nexport const decodeAt = (\n\tinput: unknown,\n\tpath: ReadonlyArray<PropertyKey>,\n\tbudget: Budget,\n): Node => decodeNode(input, path, 1, budget)\n\n/** Decodes the JSON form of a condition. */\nexport const decode = (input: unknown): Result.Result<Node, Problem> => {\n\ttry {\n\t\treturn Result.succeed(decodeNode(input, [], 1, { used: 0 }))\n\t} catch (error) {\n\t\tif (error instanceof Problem) {\n\t\t\treturn Result.fail(error)\n\t\t}\n\t\tthrow error\n\t}\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"json.js","names":["Nodes.toJson","Limits.jsonNodes","Nodes.isScalar","Nodes.literal","Nodes.principalRef","Limits.LimitExceeded","Nodes.always","Nodes.never","Nodes.isCompareOperator","Nodes.Compare","Nodes.In","Nodes.Exists","Nodes.Under","Nodes.And","Nodes.Or","Nodes.Not"],"sources":["../../src/internal/json.ts"],"sourcesContent":["/**\n * The JSON form of a condition. The decoder is a plain walk with two limits:\n * it goes at most `conditionDepth` levels down, and it reads at most\n * `jsonNodes` objects and array items, with a shared object counted for each\n * place. So no input can fill the stack or take a very long time. It makes\n * each node with its constructor, and it reads only the own data fields of\n * the input, as a condition reads a value.\n */\nimport * as Arr from \"effect/Array\"\nimport * as Data from \"effect/Data\"\nimport * as Result from \"effect/Result\"\nimport type * as SchemaIssue from \"effect/SchemaIssue\"\nimport * as Limits from \"./limits.ts\"\nimport * as Nodes from \"./nodes.ts\"\nimport { readPart } from \"./read.ts\"\n\ntype Node = Nodes.Node\n\n/** Gives the JSON form of a condition with no predicate. See `Nodes.toJson`. */\nexport const toJson = (node: Node): unknown => Nodes.toJson(node)\n\n/** A problem of an input, with the path of the problem. */\nexport class Problem extends Data.TaggedError(\"Problem\")<{\n\treadonly path: ReadonlyArray<PropertyKey>\n\treadonly message: string\n\t/** The issue of a Schema that the decode used, as for `meta`. */\n\treadonly issue?: SchemaIssue.Issue | undefined\n}> {}\n\n/** The count of the objects and items that one decode has read. It belongs to one decode. */\nexport interface Budget {\n\tused: number\n}\n\nexport const problem = (path: ReadonlyArray<PropertyKey>, message: string) =>\n\tnew Problem({ path, message })\n\n/** Counts `count` more objects or items, and stops past the limit. */\nexport const spend = (\n\tbudget: Budget,\n\tcount: number,\n\tpath: ReadonlyArray<PropertyKey>,\n): void => {\n\tbudget.used += count\n\tif (budget.used > Limits.jsonNodes) {\n\t\tthrow problem(\n\t\t\tpath,\n\t\t\t`The input has more than ${String(Limits.jsonNodes)} objects and items. The most is ${String(Limits.jsonNodes)}.`,\n\t\t)\n\t}\n}\n\n/** Reads a field of the input. A field that is not plain data is a problem. */\nexport const read = (\n\tinput: unknown,\n\tname: string,\n\tpath: ReadonlyArray<PropertyKey>,\n): unknown => {\n\ttry {\n\t\treturn readPart(input, name)\n\t} catch {\n\t\tthrow problem([...path, name], `The field \"${name}\" is not plain data`)\n\t}\n}\n\nexport const readString = (\n\tinput: unknown,\n\tname: string,\n\tpath: ReadonlyArray<PropertyKey>,\n): string => {\n\tconst value = read(input, name, path)\n\tif (typeof value !== \"string\") {\n\t\tthrow problem([...path, name], `The field \"${name}\" must be a string`)\n\t}\n\treturn value\n}\n\n/** Reads the items of an array. */\nexport const readList = (\n\tinput: unknown,\n\tname: string,\n\tpath: ReadonlyArray<PropertyKey>,\n\tbudget: Budget,\n): ReadonlyArray<unknown> => {\n\tconst value = read(input, name, path)\n\tconst at = [...path, name]\n\tif (!Array.isArray(value)) {\n\t\tthrow problem(at, `The field \"${name}\" must be an array`)\n\t}\n\tconst list: ReadonlyArray<unknown> = value\n\tspend(budget, list.length, at)\n\t// `Array.makeBy` of Effect gives at least one item, so it can not make an\n\t// empty list. An array-like object with a length makes one with no read\n\t// of the items before the read rule.\n\treturn Array.from({ length: list.length }, (_, index) =>\n\t\tread(list, String(index), at),\n\t)\n}\n\nconst isJsonScalar = (value: unknown): value is Nodes.Scalar =>\n\tNodes.isScalar(value) && (typeof value !== \"number\" || Number.isFinite(value))\n\nconst decodeOperand = (\n\tinput: unknown,\n\tpath: ReadonlyArray<PropertyKey>,\n): Nodes.Operand => {\n\tconst tag = read(input, \"_tag\", path)\n\tif (tag === \"Literal\") {\n\t\t// A missing value is not `null`: a test with `null` has its own\n\t\t// meaning, and a lost value must not become one.\n\t\tconst own =\n\t\t\ttypeof input === \"object\" && input !== null\n\t\t\t\t? Object.getOwnPropertyDescriptor(input, \"value\")\n\t\t\t\t: undefined\n\t\tif (own === undefined || (\"value\" in own && own.value === undefined)) {\n\t\t\tthrow problem([...path, \"value\"], \"A fixed value is missing\")\n\t\t}\n\t\tconst value = read(input, \"value\", path)\n\t\tif (!isJsonScalar(value)) {\n\t\t\tthrow problem(\n\t\t\t\t[...path, \"value\"],\n\t\t\t\t\"A fixed value must be a string, a finite number, a boolean or null\",\n\t\t\t)\n\t\t}\n\t\treturn Nodes.literal(value)\n\t}\n\tif (tag === \"Principal\") {\n\t\treturn Nodes.principalRef(readString(input, \"path\", path))\n\t}\n\tthrow problem(\n\t\t[...path, \"_tag\"],\n\t\t'An operand must have the tag \"Literal\" or \"Principal\"',\n\t)\n}\n\nconst decodeOperands = (\n\tinput: unknown,\n\tname: string,\n\tpath: ReadonlyArray<PropertyKey>,\n\tbudget: Budget,\n): ReadonlyArray<Nodes.Operand> =>\n\tArr.map(readList(input, name, path, budget), (operand, index) =>\n\t\tdecodeOperand(operand, [...path, name, index]),\n\t)\n\nconst decodeNode = (\n\tinput: unknown,\n\tpath: ReadonlyArray<PropertyKey>,\n\tdepth: number,\n\tbudget: Budget,\n): Node => {\n\tif (depth > Limits.conditionDepth) {\n\t\tthrow problem(\n\t\t\tpath,\n\t\t\t`A condition has more than ${String(Limits.conditionDepth)} levels. The most is ${String(Limits.conditionDepth)}.`,\n\t\t)\n\t}\n\tif (typeof input !== \"object\" || input === null) {\n\t\tthrow problem(path, \"A condition node must be an object\")\n\t}\n\tspend(budget, 1, path)\n\tconst children = (name: string) =>\n\t\tArr.map(readList(input, name, path, budget), (child, index) =>\n\t\t\tdecodeNode(child, [...path, name, index], depth + 1, budget),\n\t\t)\n\ttry {\n\t\treturn makeNode(input, path, depth, budget, children)\n\t} catch (error) {\n\t\t// A node past a limit, such as a field path with too many parts, is a\n\t\t// problem at its place.\n\t\tif (error instanceof Limits.LimitExceeded) {\n\t\t\tthrow problem(path, error.message)\n\t\t}\n\t\tthrow error\n\t}\n}\n\nconst makeNode = (\n\tinput: object,\n\tpath: ReadonlyArray<PropertyKey>,\n\tdepth: number,\n\tbudget: Budget,\n\tchildren: (name: string) => ReadonlyArray<Node>,\n): Node => {\n\tconst tag = read(input, \"_tag\", path)\n\tswitch (tag) {\n\t\tcase \"True\":\n\t\t\treturn Nodes.always\n\t\tcase \"False\":\n\t\t\treturn Nodes.never\n\t\tcase \"Compare\": {\n\t\t\tconst op = readString(input, \"op\", path)\n\t\t\tif (!Nodes.isCompareOperator(op)) {\n\t\t\t\tthrow problem([...path, \"op\"], `\"${op}\" is not a compare operator`)\n\t\t\t}\n\t\t\treturn new Nodes.Compare({\n\t\t\t\top,\n\t\t\t\tfield: readString(input, \"field\", path),\n\t\t\t\tvalue: decodeOperand(read(input, \"value\", path), [...path, \"value\"]),\n\t\t\t})\n\t\t}\n\t\tcase \"In\":\n\t\t\treturn new Nodes.In({\n\t\t\t\tfield: readString(input, \"field\", path),\n\t\t\t\tvalues: decodeOperands(input, \"values\", path, budget),\n\t\t\t})\n\t\tcase \"Exists\":\n\t\t\treturn new Nodes.Exists({ field: readString(input, \"field\", path) })\n\t\tcase \"Under\":\n\t\t\treturn new Nodes.Under({\n\t\t\t\tprefix: decodeOperands(input, \"prefix\", path, budget),\n\t\t\t})\n\t\tcase \"And\":\n\t\t\treturn new Nodes.And(children(\"conditions\"))\n\t\tcase \"Or\":\n\t\t\treturn new Nodes.Or(children(\"conditions\"))\n\t\tcase \"Not\":\n\t\t\treturn new Nodes.Not(\n\t\t\t\tdecodeNode(\n\t\t\t\t\tread(input, \"condition\", path),\n\t\t\t\t\t[...path, \"condition\"],\n\t\t\t\t\tdepth + 1,\n\t\t\t\t\tbudget,\n\t\t\t\t),\n\t\t\t)\n\t\tdefault:\n\t\t\tthrow problem([...path, \"_tag\"], \"The node has no known tag\")\n\t}\n}\n\n/**\n * Decodes the JSON form of a condition at a path, with the budget of a larger\n * decode. It throws a {@link Problem}.\n */\nexport const decodeAt = (\n\tinput: unknown,\n\tpath: ReadonlyArray<PropertyKey>,\n\tbudget: Budget,\n): Node => decodeNode(input, path, 1, budget)\n\n/** Decodes the JSON form of a condition. */\nexport const decode = (input: unknown): Result.Result<Node, Problem> => {\n\ttry {\n\t\treturn Result.succeed(decodeNode(input, [], 1, { used: 0 }))\n\t} catch (error) {\n\t\tif (error instanceof Problem) {\n\t\t\treturn Result.fail(error)\n\t\t}\n\t\tthrow error\n\t}\n}\n"],"mappings":"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"}
@@ -1,8 +1,11 @@
1
1
  import * as Effect from "effect/Effect";
2
+ import * as Schema from "effect/Schema";
2
3
  import * as Data from "effect/Data";
3
4
  /** A value that a condition can compare. */
4
5
  export type Scalar = string | number | boolean | null;
5
- export type CompareOperator = "eq" | "ne" | "lt" | "lte" | "gt" | "gte";
6
+ /** The operators of a `Compare` test. The decoders read this list too. */
7
+ export declare const CompareOperator: Schema.Literals<readonly ["eq", "ne", "lt", "lte", "gt", "gte"]>;
8
+ export type CompareOperator = typeof CompareOperator.Type;
6
9
  /** A fixed value. */
7
10
  export interface Literal {
8
11
  readonly _tag: "Literal";
@@ -1 +1 @@
1
- {"version":3,"file":"nodes.d.ts","names":[],"sources":["../../src/internal/nodes.ts"],"mappings":";;;YA0BY;YAEA;;iBAGK;WACP;WACA,OAAO;;;iBAIA;WACP;WACA;;YAGE,UAAU,UAAU;UAwEtB;WACA;WACA;WACA;;;uBAoCK,aAAa,KAAK;;;;;;;EAMhC;EAMA,YAAY,eAAe,OAAO;;MAM9B;;MAKA;;MAKA;;;qBAMQ,aAAa;WAChB;EACT;;;qBAMY,cAAc;WACjB;EACT;;;qBAMY,gBAAgB;WACnB;WACQ,IAAI;WACJ;WACA,OAAO;EACxB,YAAY;aACF,IAAI;aACJ;aACA,OAAO;;;;qBAiBL,WAAW;WACd;WACQ;WACA,QAAQ,cAAc;EACvC,YAAY;aACF;aACA,QAAQ,cAAc;;;;qBAUpB,eAAe;WAClB;WACQ;EACjB,YAAY;aAAkB;;;;qBAMlB,cAAc;WACjB;WACQ,QAAQ,cAAc;EACvC,YAAY;aAAkB,QAAQ,cAAc;;;qBAgBxC,YAAY;WACf;WACQ,YAAY,cAAc;EAC3C,YAAY,YAAY,cAAc;;qBAM1B,WAAW;WACd;WACQ,YAAY,cAAc;EAC3C,YAAY,YAAY,cAAc;;qBAM1B,YAAY;WACf;WACQ,WAAW;EAC5B,YAAY,WAAW;;;YASZ,OACX,gBACA,uBACI,OAAO;;;;;;qBAOC,kBAAkB;WACrB;WACQ;WACA,MAChB,cACA,qBACI,OAAO;EACZ,YAAY;aAAkB;aAAuB,KAAK;;;;YAe/C,OACX,OAAO,QAAQ,UAAU,KAAK,SAAS,QAAQ,MAAM,KAAK,MAAM"}
1
+ {"version":3,"file":"nodes.d.ts","names":[],"sources":["../../src/internal/nodes.ts"],"mappings":";;;;YA2BY;;qBAGC,iBAAe,OAAA;YAShB,yBAAyB,gBAAgB;;iBAWpC;WACP;WACA,OAAO;;;iBAIA;WACP;WACA;;YAGE,UAAU,UAAU;UA+DtB;WACA;WACA;WACA;;;uBAoCK,aAAa,KAAK;;;;;;;EAMhC;EAMA,YAAY,eAAe,OAAO;;MAM9B;;MAKA;;MAKA;;;qBAMQ,aAAa;WAChB;EACT;;;qBAMY,cAAc;WACjB;EACT;;;qBAMY,gBAAgB;WACnB;WACQ,IAAI;WACJ;WACA,OAAO;EACxB,YAAY;aACF,IAAI;aACJ;aACA,OAAO;;;;qBAiBL,WAAW;WACd;WACQ;WACA,QAAQ,cAAc;EACvC,YAAY;aACF;aACA,QAAQ,cAAc;;;;qBAUpB,eAAe;WAClB;WACQ;EACjB,YAAY;aAAkB;;;;qBAMlB,cAAc;WACjB;WACQ,QAAQ,cAAc;EACvC,YAAY;aAAkB,QAAQ,cAAc;;;qBAgBxC,YAAY;WACf;WACQ,YAAY,cAAc;EAC3C,YAAY,YAAY,cAAc;;qBAM1B,WAAW;WACd;WACQ,YAAY,cAAc;EAC3C,YAAY,YAAY,cAAc;;qBAM1B,YAAY;WACf;WACQ,WAAW;EAC5B,YAAY,WAAW;;;YASZ,OACX,gBACA,uBACI,OAAO;;;;;;qBAOC,kBAAkB;WACrB;WACQ;WACA,MAChB,cACA,qBACI,OAAO;EACZ,YAAY;aAAkB;aAAuB,KAAK;;;;YAe/C,OACX,OAAO,QAAQ,UAAU,KAAK,SAAS,QAAQ,MAAM,KAAK,MAAM"}
@@ -1,5 +1,6 @@
1
1
  import { __exportAll } from "../_virtual/_rolldown/runtime.js";
2
2
  import { conditionNodes, exceeded } from "./limits.js";
3
+ import * as Schema from "effect/Schema";
3
4
  import * as Data from "effect/Data";
4
5
  import * as Arr from "effect/Array";
5
6
  import { hasProperty } from "effect/Predicate";
@@ -23,6 +24,7 @@ import { hasProperty } from "effect/Predicate";
23
24
  var nodes_exports = /* @__PURE__ */ __exportAll({
24
25
  And: () => And,
25
26
  Compare: () => Compare,
27
+ CompareOperator: () => CompareOperator,
26
28
  Exists: () => Exists,
27
29
  False: () => False,
28
30
  In: () => In,
@@ -32,6 +34,7 @@ var nodes_exports = /* @__PURE__ */ __exportAll({
32
34
  True: () => True,
33
35
  Under: () => Under,
34
36
  always: () => always,
37
+ isCompareOperator: () => isCompareOperator,
35
38
  isNode: () => isNode,
36
39
  isScalar: () => isScalar,
37
40
  literal: () => literal,
@@ -41,17 +44,24 @@ var nodes_exports = /* @__PURE__ */ __exportAll({
41
44
  toJson: () => toJson,
42
45
  toNode: () => toNode
43
46
  });
44
- const operands = Data.taggedEnum();
45
- const literal = (value) => operands.Literal({ value });
46
- const principalRef = (path) => operands.Principal({ path });
47
- const compareOperators = [
47
+ /** The operators of a `Compare` test. The decoders read this list too. */
48
+ const CompareOperator = Schema.Literals([
48
49
  "eq",
49
50
  "ne",
50
51
  "lt",
51
52
  "lte",
52
53
  "gt",
53
54
  "gte"
54
- ];
55
+ ]);
56
+ /**
57
+ * Tests if a value is an operator. It reads the list of the Schema with
58
+ * `includes`: for a short list, this is about twice as fast as
59
+ * `Schema.is`, and a decoder tests each node of a large input.
60
+ */
61
+ const isCompareOperator = (u) => CompareOperator.literals.includes(u);
62
+ const operands = Data.taggedEnum();
63
+ const literal = (value) => operands.Literal({ value });
64
+ const principalRef = (path) => operands.Principal({ path });
55
65
  /** Tests if a value is a scalar. Any number is one, also `NaN`. */
56
66
  const isScalar = (value) => value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean";
57
67
  /**
@@ -139,7 +149,7 @@ var False = class extends Base {
139
149
  var Compare = class extends Base {
140
150
  _tag = "Compare";
141
151
  constructor(props) {
142
- if (!compareOperators.includes(props.op)) throw new Error(`"${String(props.op)}" is not a compare operator`);
152
+ if (!isCompareOperator(props.op)) throw new Error(`"${String(props.op)}" is not a compare operator`);
143
153
  super({
144
154
  op: props.op,
145
155
  field: checkPath(props.field),
@@ -272,6 +282,6 @@ const toNode = (u) => {
272
282
  };
273
283
  const always = new True();
274
284
  const never = new False();
275
- export { And, Compare, Exists, False, In, Not, Or, Predicate, True, Under, always, isNode, isScalar, literal, never, nodes_exports, principalRef, runOf, toJson, toNode };
285
+ export { And, Compare, CompareOperator, Exists, False, In, Not, Or, Predicate, True, Under, always, isCompareOperator, isNode, isScalar, literal, never, nodes_exports, principalRef, runOf, toJson, toNode };
276
286
 
277
287
  //# sourceMappingURL=nodes.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"nodes.js","names":["Limits.exceeded","Limits.conditionNodes"],"sources":["../../src/internal/nodes.ts"],"sourcesContent":["/**\n * The nodes of a condition. Each node is a class, and only its constructor\n * makes one, also when a condition comes from JSON. The constructor checks the\n * data of the node and works out three facts once:\n * - `size`: the number of nodes, with a shared child counted for each place;\n * - `depth`: the number of levels;\n * - `opaque`: the node has a predicate.\n *\n * The constructor stops a node that goes past `conditionNodes` or\n * `conditionDepth`. So a walk over any condition visits at most\n * `conditionNodes` nodes and goes at most `conditionDepth` levels down, and it\n * needs no memo.\n *\n * The facts are private fields, so `Equal` and `Hash` do not read them: two\n * nodes with the same data are equal.\n */\n// A predicate gives an Effect with an error type and a service type that the\n// nodes do not know, so they are `unknown` here.\n// @effect-diagnostics anyUnknownInErrorContext:off\nimport * as Arr from \"effect/Array\"\nimport * as Data from \"effect/Data\"\nimport type * as Effect from \"effect/Effect\"\nimport { hasProperty } from \"effect/Predicate\"\nimport * as Limits from \"./limits.ts\"\n\n/** A value that a condition can compare. */\nexport type Scalar = string | number | boolean | null\n\nexport type CompareOperator = \"eq\" | \"ne\" | \"lt\" | \"lte\" | \"gt\" | \"gte\"\n\n/** A fixed value. */\nexport interface Literal {\n\treadonly _tag: \"Literal\"\n\treadonly value: Scalar\n}\n\n/** A field of the principal. */\nexport interface PrincipalRef {\n\treadonly _tag: \"Principal\"\n\treadonly path: string\n}\n\nexport type Operand = Literal | PrincipalRef\n\nconst operands = Data.taggedEnum<Operand>()\n\nexport const literal = (value: Scalar): Literal => operands.Literal({ value })\n\nexport const principalRef = (path: string): PrincipalRef =>\n\toperands.Principal({ path })\n\nconst compareOperators: ReadonlyArray<string> = [\n\t\"eq\",\n\t\"ne\",\n\t\"lt\",\n\t\"lte\",\n\t\"gt\",\n\t\"gte\",\n]\n\n/** Tests if a value is a scalar. Any number is one, also `NaN`. */\nexport const isScalar = (value: unknown): value is Scalar =>\n\tvalue === null ||\n\ttypeof value === \"string\" ||\n\ttypeof value === \"number\" ||\n\ttypeof value === \"boolean\"\n\n/**\n * Checks a field path: a string with at most `fieldPathParts` parts. A longer\n * path is never a field of a resource or of the principal.\n */\nconst checkPath = (path: unknown): string => {\n\tif (typeof path !== \"string\") {\n\t\tthrow new Error(\"A field path must be a string\")\n\t}\n\tconst parts = path.split(\".\", Limits.fieldPathParts + 1).length\n\tif (parts > Limits.fieldPathParts) {\n\t\tthrow Limits.exceeded(\n\t\t\t\"A field path\",\n\t\t\t\"fieldPathParts\",\n\t\t\t\"parts\",\n\t\t\tparts,\n\t\t\tLimits.fieldPathParts,\n\t\t)\n\t}\n\treturn path\n}\n\n/** Checks an operand, and gives a new one with only its data. */\nconst checkOperand = (operand: unknown): Operand => {\n\tif (hasProperty(operand, \"_tag\")) {\n\t\tif (\n\t\t\toperand._tag === \"Literal\" &&\n\t\t\thasProperty(operand, \"value\") &&\n\t\t\tisScalar(operand.value)\n\t\t) {\n\t\t\treturn literal(operand.value)\n\t\t}\n\t\tif (operand._tag === \"Principal\" && hasProperty(operand, \"path\")) {\n\t\t\treturn principalRef(checkPath(operand.path))\n\t\t}\n\t}\n\tthrow new Error(\n\t\t\"An operand must be a fixed scalar value or a field of the principal\",\n\t)\n}\n\nconst checkOperands = (values: unknown): ReadonlyArray<Operand> => {\n\tif (!Array.isArray(values)) {\n\t\tthrow new Error(\"A list of operands must be an array\")\n\t}\n\treturn Object.freeze(Arr.map(Array.from(values), checkOperand))\n}\n\ninterface Facts {\n\treadonly size: number\n\treadonly depth: number\n\treadonly opaque: boolean\n}\n\nconst leaf: Facts = { size: 1, depth: 1, opaque: false }\n\n/** The facts of a node with children. It stops a node past the limits. */\nconst factsOf = (children: ReadonlyArray<Node>): Facts => {\n\tconst size = Arr.reduce(children, 1, (total, child) => total + child.size)\n\tif (size > Limits.conditionNodes) {\n\t\tthrow Limits.exceeded(\n\t\t\t\"A condition\",\n\t\t\t\"conditionNodes\",\n\t\t\t\"nodes\",\n\t\t\tsize,\n\t\t\tLimits.conditionNodes,\n\t\t)\n\t}\n\tconst depth =\n\t\t1 + Arr.reduce(children, 0, (top, child) => Math.max(top, child.depth))\n\tif (depth > Limits.conditionDepth) {\n\t\tthrow Limits.exceeded(\n\t\t\t\"A condition\",\n\t\t\t\"conditionDepth\",\n\t\t\t\"levels\",\n\t\t\tdepth,\n\t\t\tLimits.conditionDepth,\n\t\t)\n\t}\n\treturn {\n\t\tsize,\n\t\tdepth,\n\t\topaque: Arr.some(children, (child) => child.opaque),\n\t}\n}\n\n/** The base of every node. It keeps the facts. */\nabstract class Base extends Data.Class {\n\t/**\n\t * The JSON form of the node, for `JSON.stringify`. A number that JSON can\n\t * not hold, as `Infinity`, becomes an object that no decoder takes, in\n\t * place of `null`, which would change the test.\n\t */\n\ttoJSON(): unknown {\n\t\treturn toJson(this as unknown as Node)\n\t}\n\n\treadonly #facts: Facts\n\n\tconstructor(props: object, facts: Facts) {\n\t\tsuper(props as never)\n\t\tthis.#facts = facts\n\t}\n\n\t/** The number of nodes, with a shared child counted for each place. */\n\tget size(): number {\n\t\treturn this.#facts.size\n\t}\n\n\t/** The number of levels. */\n\tget depth(): number {\n\t\treturn this.#facts.depth\n\t}\n\n\t/** The node has a predicate. */\n\tget opaque(): boolean {\n\t\treturn this.#facts.opaque\n\t}\n}\n\n/** Always true. */\nexport class True extends Base {\n\treadonly _tag = \"True\"\n\tconstructor() {\n\t\tsuper({}, leaf)\n\t}\n}\n\n/** Always false. */\nexport class False extends Base {\n\treadonly _tag = \"False\"\n\tconstructor() {\n\t\tsuper({}, leaf)\n\t}\n}\n\n/** Compares a field with a value. */\nexport class Compare extends Base {\n\treadonly _tag = \"Compare\"\n\tdeclare readonly op: CompareOperator\n\tdeclare readonly field: string\n\tdeclare readonly value: Operand\n\tconstructor(props: {\n\t\treadonly op: CompareOperator\n\t\treadonly field: string\n\t\treadonly value: Operand\n\t}) {\n\t\tif (!compareOperators.includes(props.op)) {\n\t\t\tthrow new Error(`\"${String(props.op)}\" is not a compare operator`)\n\t\t}\n\t\tsuper(\n\t\t\t{\n\t\t\t\top: props.op,\n\t\t\t\tfield: checkPath(props.field),\n\t\t\t\tvalue: checkOperand(props.value),\n\t\t\t},\n\t\t\tleaf,\n\t\t)\n\t}\n}\n\n/** True when a field is equal to one of the values. */\nexport class In extends Base {\n\treadonly _tag = \"In\"\n\tdeclare readonly field: string\n\tdeclare readonly values: ReadonlyArray<Operand>\n\tconstructor(props: {\n\t\treadonly field: string\n\t\treadonly values: ReadonlyArray<Operand>\n\t}) {\n\t\tsuper(\n\t\t\t{ field: checkPath(props.field), values: checkOperands(props.values) },\n\t\t\tleaf,\n\t\t)\n\t}\n}\n\n/** True when a field is not `null` and not missing. */\nexport class Exists extends Base {\n\treadonly _tag = \"Exists\"\n\tdeclare readonly field: string\n\tconstructor(props: { readonly field: string }) {\n\t\tsuper({ field: checkPath(props.field) }, leaf)\n\t}\n}\n\n/** True when the path of the resource starts with the prefix. */\nexport class Under extends Base {\n\treadonly _tag = \"Under\"\n\tdeclare readonly prefix: ReadonlyArray<Operand>\n\tconstructor(props: { readonly prefix: ReadonlyArray<Operand> }) {\n\t\tsuper({ prefix: checkOperands(props.prefix) }, leaf)\n\t}\n}\n\nconst checkChildren = (conditions: unknown): ReadonlyArray<Node> => {\n\tif (!Array.isArray(conditions)) {\n\t\tthrow new Error(\"The children of a node must be an array\")\n\t}\n\tconst children = Array.from(conditions as ReadonlyArray<unknown>)\n\tif (!Arr.every(children, isNode)) {\n\t\tthrow notNode()\n\t}\n\treturn Object.freeze(children)\n}\n\nexport class And extends Base {\n\treadonly _tag = \"And\"\n\tdeclare readonly conditions: ReadonlyArray<Node>\n\tconstructor(conditions: ReadonlyArray<Node>) {\n\t\tconst children = checkChildren(conditions)\n\t\tsuper({ conditions: children }, factsOf(children))\n\t}\n}\n\nexport class Or extends Base {\n\treadonly _tag = \"Or\"\n\tdeclare readonly conditions: ReadonlyArray<Node>\n\tconstructor(conditions: ReadonlyArray<Node>) {\n\t\tconst children = checkChildren(conditions)\n\t\tsuper({ conditions: children }, factsOf(children))\n\t}\n}\n\nexport class Not extends Base {\n\treadonly _tag = \"Not\"\n\tdeclare readonly condition: Node\n\tconstructor(condition: Node) {\n\t\tif (!isNode(condition)) {\n\t\t\tthrow notNode()\n\t\t}\n\t\tsuper({ condition }, factsOf([condition]))\n\t}\n}\n\n/** The test of a predicate, with no types. */\nexport type Run = (\n\tvalue: unknown,\n\tprincipal: unknown,\n) => Effect.Effect<boolean, unknown, unknown>\n\n/**\n * A test that runs an `Effect`. Its test takes inputs of the type `never`, so\n * no code can call it with a value of the wrong type: `Condition.evaluate`\n * checks the input. Use {@link runOf} inside the library.\n */\nexport class Predicate extends Base {\n\treadonly _tag = \"Predicate\"\n\tdeclare readonly name: string\n\tdeclare readonly run: (\n\t\tvalue: never,\n\t\tprincipal: never,\n\t) => Effect.Effect<boolean, unknown, unknown>\n\tconstructor(props: { readonly name: string; readonly run: Run }) {\n\t\tif (typeof props.name !== \"string\" || typeof props.run !== \"function\") {\n\t\t\tthrow new Error(\"A predicate needs a name and a test\")\n\t\t}\n\t\tsuper(\n\t\t\t{ name: props.name, run: props.run },\n\t\t\t{ size: 1, depth: 1, opaque: true },\n\t\t)\n\t}\n}\n\n/** Gives the test of a predicate, with no types. */\nexport const runOf = (node: Predicate): Run => node.run as Run\n\n/** A node of a condition. */\nexport type Node =\n\tTrue | False | Compare | In | Exists | Under | And | Or | Not | Predicate\n\nconst operandJson = (operand: Operand): unknown =>\n\toperand._tag === \"Literal\"\n\t\t? {\n\t\t\t\t_tag: \"Literal\",\n\t\t\t\t// JSON has no `Infinity`, `-Infinity` or `NaN`. Such a number\n\t\t\t\t// becomes an object that the decoder does not take.\n\t\t\t\tvalue:\n\t\t\t\t\ttypeof operand.value === \"number\" && !Number.isFinite(operand.value)\n\t\t\t\t\t\t? { nonFinite: String(operand.value) }\n\t\t\t\t\t\t: operand.value,\n\t\t\t}\n\t\t: { _tag: \"Principal\", path: operand.path }\n\n/** Gives the JSON form of a condition with no predicate. */\nexport const toJson = (node: Node): unknown => {\n\tswitch (node._tag) {\n\t\tcase \"True\":\n\t\tcase \"False\":\n\t\t\treturn { _tag: node._tag }\n\t\tcase \"Compare\":\n\t\t\treturn {\n\t\t\t\t_tag: \"Compare\",\n\t\t\t\top: node.op,\n\t\t\t\tfield: node.field,\n\t\t\t\tvalue: operandJson(node.value),\n\t\t\t}\n\t\tcase \"In\":\n\t\t\treturn {\n\t\t\t\t_tag: \"In\",\n\t\t\t\tfield: node.field,\n\t\t\t\tvalues: Arr.map(node.values, operandJson),\n\t\t\t}\n\t\tcase \"Exists\":\n\t\t\treturn { _tag: \"Exists\", field: node.field }\n\t\tcase \"Under\":\n\t\t\treturn { _tag: \"Under\", prefix: Arr.map(node.prefix, operandJson) }\n\t\tcase \"And\":\n\t\tcase \"Or\":\n\t\t\treturn { _tag: node._tag, conditions: Arr.map(node.conditions, toJson) }\n\t\tcase \"Not\":\n\t\t\treturn { _tag: \"Not\", condition: toJson(node.condition) }\n\t\tcase \"Predicate\":\n\t\t\tthrow new Error(\n\t\t\t\t`The predicate \"${node.name}\" can not become JSON. A condition with a predicate has no JSON form.`,\n\t\t\t)\n\t}\n}\n\n/** Tests if a value is a node. Only a constructor of a node makes one. */\nexport const isNode = (u: unknown): u is Node => u instanceof Base\n\nconst notNode = (): Error =>\n\tnew Error(\n\t\t\"A condition must be made with a builder or a function of Condition. A plain object is not a condition\",\n\t)\n\n/** Gives a value as a node, or throws when it is not a node. */\nexport const toNode = (u: unknown): Node => {\n\tif (!isNode(u)) {\n\t\tthrow notNode()\n\t}\n\treturn u\n}\n\nexport const always: Node = new True()\n\nexport const never: Node = new False()\n"],"mappings":"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"}
1
+ {"version":3,"file":"nodes.js","names":["Limits.exceeded","Limits.conditionNodes"],"sources":["../../src/internal/nodes.ts"],"sourcesContent":["/**\n * The nodes of a condition. Each node is a class, and only its constructor\n * makes one, also when a condition comes from JSON. The constructor checks the\n * data of the node and works out three facts once:\n * - `size`: the number of nodes, with a shared child counted for each place;\n * - `depth`: the number of levels;\n * - `opaque`: the node has a predicate.\n *\n * The constructor stops a node that goes past `conditionNodes` or\n * `conditionDepth`. So a walk over any condition visits at most\n * `conditionNodes` nodes and goes at most `conditionDepth` levels down, and it\n * needs no memo.\n *\n * The facts are private fields, so `Equal` and `Hash` do not read them: two\n * nodes with the same data are equal.\n */\n// A predicate gives an Effect with an error type and a service type that the\n// nodes do not know, so they are `unknown` here.\n// @effect-diagnostics anyUnknownInErrorContext:off\nimport * as Arr from \"effect/Array\"\nimport * as Data from \"effect/Data\"\nimport type * as Effect from \"effect/Effect\"\nimport { hasProperty } from \"effect/Predicate\"\nimport * as Schema from \"effect/Schema\"\nimport * as Limits from \"./limits.ts\"\n\n/** A value that a condition can compare. */\nexport type Scalar = string | number | boolean | null\n\n/** The operators of a `Compare` test. The decoders read this list too. */\nexport const CompareOperator = Schema.Literals([\n\t\"eq\",\n\t\"ne\",\n\t\"lt\",\n\t\"lte\",\n\t\"gt\",\n\t\"gte\",\n])\n\nexport type CompareOperator = typeof CompareOperator.Type\n\n/**\n * Tests if a value is an operator. It reads the list of the Schema with\n * `includes`: for a short list, this is about twice as fast as\n * `Schema.is`, and a decoder tests each node of a large input.\n */\nexport const isCompareOperator = (u: unknown): u is CompareOperator =>\n\t(CompareOperator.literals as ReadonlyArray<unknown>).includes(u)\n\n/** A fixed value. */\nexport interface Literal {\n\treadonly _tag: \"Literal\"\n\treadonly value: Scalar\n}\n\n/** A field of the principal. */\nexport interface PrincipalRef {\n\treadonly _tag: \"Principal\"\n\treadonly path: string\n}\n\nexport type Operand = Literal | PrincipalRef\n\nconst operands = Data.taggedEnum<Operand>()\n\nexport const literal = (value: Scalar): Literal => operands.Literal({ value })\n\nexport const principalRef = (path: string): PrincipalRef =>\n\toperands.Principal({ path })\n\n/** Tests if a value is a scalar. Any number is one, also `NaN`. */\nexport const isScalar = (value: unknown): value is Scalar =>\n\tvalue === null ||\n\ttypeof value === \"string\" ||\n\ttypeof value === \"number\" ||\n\ttypeof value === \"boolean\"\n\n/**\n * Checks a field path: a string with at most `fieldPathParts` parts. A longer\n * path is never a field of a resource or of the principal.\n */\nconst checkPath = (path: unknown): string => {\n\tif (typeof path !== \"string\") {\n\t\tthrow new Error(\"A field path must be a string\")\n\t}\n\tconst parts = path.split(\".\", Limits.fieldPathParts + 1).length\n\tif (parts > Limits.fieldPathParts) {\n\t\tthrow Limits.exceeded(\n\t\t\t\"A field path\",\n\t\t\t\"fieldPathParts\",\n\t\t\t\"parts\",\n\t\t\tparts,\n\t\t\tLimits.fieldPathParts,\n\t\t)\n\t}\n\treturn path\n}\n\n/** Checks an operand, and gives a new one with only its data. */\nconst checkOperand = (operand: unknown): Operand => {\n\tif (hasProperty(operand, \"_tag\")) {\n\t\tif (\n\t\t\toperand._tag === \"Literal\" &&\n\t\t\thasProperty(operand, \"value\") &&\n\t\t\tisScalar(operand.value)\n\t\t) {\n\t\t\treturn literal(operand.value)\n\t\t}\n\t\tif (operand._tag === \"Principal\" && hasProperty(operand, \"path\")) {\n\t\t\treturn principalRef(checkPath(operand.path))\n\t\t}\n\t}\n\tthrow new Error(\n\t\t\"An operand must be a fixed scalar value or a field of the principal\",\n\t)\n}\n\nconst checkOperands = (values: unknown): ReadonlyArray<Operand> => {\n\tif (!Array.isArray(values)) {\n\t\tthrow new Error(\"A list of operands must be an array\")\n\t}\n\treturn Object.freeze(Arr.map(Array.from(values), checkOperand))\n}\n\ninterface Facts {\n\treadonly size: number\n\treadonly depth: number\n\treadonly opaque: boolean\n}\n\nconst leaf: Facts = { size: 1, depth: 1, opaque: false }\n\n/** The facts of a node with children. It stops a node past the limits. */\nconst factsOf = (children: ReadonlyArray<Node>): Facts => {\n\tconst size = Arr.reduce(children, 1, (total, child) => total + child.size)\n\tif (size > Limits.conditionNodes) {\n\t\tthrow Limits.exceeded(\n\t\t\t\"A condition\",\n\t\t\t\"conditionNodes\",\n\t\t\t\"nodes\",\n\t\t\tsize,\n\t\t\tLimits.conditionNodes,\n\t\t)\n\t}\n\tconst depth =\n\t\t1 + Arr.reduce(children, 0, (top, child) => Math.max(top, child.depth))\n\tif (depth > Limits.conditionDepth) {\n\t\tthrow Limits.exceeded(\n\t\t\t\"A condition\",\n\t\t\t\"conditionDepth\",\n\t\t\t\"levels\",\n\t\t\tdepth,\n\t\t\tLimits.conditionDepth,\n\t\t)\n\t}\n\treturn {\n\t\tsize,\n\t\tdepth,\n\t\topaque: Arr.some(children, (child) => child.opaque),\n\t}\n}\n\n/** The base of every node. It keeps the facts. */\nabstract class Base extends Data.Class {\n\t/**\n\t * The JSON form of the node, for `JSON.stringify`. A number that JSON can\n\t * not hold, as `Infinity`, becomes an object that no decoder takes, in\n\t * place of `null`, which would change the test.\n\t */\n\ttoJSON(): unknown {\n\t\treturn toJson(this as unknown as Node)\n\t}\n\n\treadonly #facts: Facts\n\n\tconstructor(props: object, facts: Facts) {\n\t\tsuper(props as never)\n\t\tthis.#facts = facts\n\t}\n\n\t/** The number of nodes, with a shared child counted for each place. */\n\tget size(): number {\n\t\treturn this.#facts.size\n\t}\n\n\t/** The number of levels. */\n\tget depth(): number {\n\t\treturn this.#facts.depth\n\t}\n\n\t/** The node has a predicate. */\n\tget opaque(): boolean {\n\t\treturn this.#facts.opaque\n\t}\n}\n\n/** Always true. */\nexport class True extends Base {\n\treadonly _tag = \"True\"\n\tconstructor() {\n\t\tsuper({}, leaf)\n\t}\n}\n\n/** Always false. */\nexport class False extends Base {\n\treadonly _tag = \"False\"\n\tconstructor() {\n\t\tsuper({}, leaf)\n\t}\n}\n\n/** Compares a field with a value. */\nexport class Compare extends Base {\n\treadonly _tag = \"Compare\"\n\tdeclare readonly op: CompareOperator\n\tdeclare readonly field: string\n\tdeclare readonly value: Operand\n\tconstructor(props: {\n\t\treadonly op: CompareOperator\n\t\treadonly field: string\n\t\treadonly value: Operand\n\t}) {\n\t\tif (!isCompareOperator(props.op)) {\n\t\t\tthrow new Error(`\"${String(props.op)}\" is not a compare operator`)\n\t\t}\n\t\tsuper(\n\t\t\t{\n\t\t\t\top: props.op,\n\t\t\t\tfield: checkPath(props.field),\n\t\t\t\tvalue: checkOperand(props.value),\n\t\t\t},\n\t\t\tleaf,\n\t\t)\n\t}\n}\n\n/** True when a field is equal to one of the values. */\nexport class In extends Base {\n\treadonly _tag = \"In\"\n\tdeclare readonly field: string\n\tdeclare readonly values: ReadonlyArray<Operand>\n\tconstructor(props: {\n\t\treadonly field: string\n\t\treadonly values: ReadonlyArray<Operand>\n\t}) {\n\t\tsuper(\n\t\t\t{ field: checkPath(props.field), values: checkOperands(props.values) },\n\t\t\tleaf,\n\t\t)\n\t}\n}\n\n/** True when a field is not `null` and not missing. */\nexport class Exists extends Base {\n\treadonly _tag = \"Exists\"\n\tdeclare readonly field: string\n\tconstructor(props: { readonly field: string }) {\n\t\tsuper({ field: checkPath(props.field) }, leaf)\n\t}\n}\n\n/** True when the path of the resource starts with the prefix. */\nexport class Under extends Base {\n\treadonly _tag = \"Under\"\n\tdeclare readonly prefix: ReadonlyArray<Operand>\n\tconstructor(props: { readonly prefix: ReadonlyArray<Operand> }) {\n\t\tsuper({ prefix: checkOperands(props.prefix) }, leaf)\n\t}\n}\n\nconst checkChildren = (conditions: unknown): ReadonlyArray<Node> => {\n\tif (!Array.isArray(conditions)) {\n\t\tthrow new Error(\"The children of a node must be an array\")\n\t}\n\tconst children = Array.from(conditions as ReadonlyArray<unknown>)\n\tif (!Arr.every(children, isNode)) {\n\t\tthrow notNode()\n\t}\n\treturn Object.freeze(children)\n}\n\nexport class And extends Base {\n\treadonly _tag = \"And\"\n\tdeclare readonly conditions: ReadonlyArray<Node>\n\tconstructor(conditions: ReadonlyArray<Node>) {\n\t\tconst children = checkChildren(conditions)\n\t\tsuper({ conditions: children }, factsOf(children))\n\t}\n}\n\nexport class Or extends Base {\n\treadonly _tag = \"Or\"\n\tdeclare readonly conditions: ReadonlyArray<Node>\n\tconstructor(conditions: ReadonlyArray<Node>) {\n\t\tconst children = checkChildren(conditions)\n\t\tsuper({ conditions: children }, factsOf(children))\n\t}\n}\n\nexport class Not extends Base {\n\treadonly _tag = \"Not\"\n\tdeclare readonly condition: Node\n\tconstructor(condition: Node) {\n\t\tif (!isNode(condition)) {\n\t\t\tthrow notNode()\n\t\t}\n\t\tsuper({ condition }, factsOf([condition]))\n\t}\n}\n\n/** The test of a predicate, with no types. */\nexport type Run = (\n\tvalue: unknown,\n\tprincipal: unknown,\n) => Effect.Effect<boolean, unknown, unknown>\n\n/**\n * A test that runs an `Effect`. Its test takes inputs of the type `never`, so\n * no code can call it with a value of the wrong type: `Condition.evaluate`\n * checks the input. Use {@link runOf} inside the library.\n */\nexport class Predicate extends Base {\n\treadonly _tag = \"Predicate\"\n\tdeclare readonly name: string\n\tdeclare readonly run: (\n\t\tvalue: never,\n\t\tprincipal: never,\n\t) => Effect.Effect<boolean, unknown, unknown>\n\tconstructor(props: { readonly name: string; readonly run: Run }) {\n\t\tif (typeof props.name !== \"string\" || typeof props.run !== \"function\") {\n\t\t\tthrow new Error(\"A predicate needs a name and a test\")\n\t\t}\n\t\tsuper(\n\t\t\t{ name: props.name, run: props.run },\n\t\t\t{ size: 1, depth: 1, opaque: true },\n\t\t)\n\t}\n}\n\n/** Gives the test of a predicate, with no types. */\nexport const runOf = (node: Predicate): Run => node.run as Run\n\n/** A node of a condition. */\nexport type Node =\n\tTrue | False | Compare | In | Exists | Under | And | Or | Not | Predicate\n\nconst operandJson = (operand: Operand): unknown =>\n\toperand._tag === \"Literal\"\n\t\t? {\n\t\t\t\t_tag: \"Literal\",\n\t\t\t\t// JSON has no `Infinity`, `-Infinity` or `NaN`. Such a number\n\t\t\t\t// becomes an object that the decoder does not take.\n\t\t\t\tvalue:\n\t\t\t\t\ttypeof operand.value === \"number\" && !Number.isFinite(operand.value)\n\t\t\t\t\t\t? { nonFinite: String(operand.value) }\n\t\t\t\t\t\t: operand.value,\n\t\t\t}\n\t\t: { _tag: \"Principal\", path: operand.path }\n\n/** Gives the JSON form of a condition with no predicate. */\nexport const toJson = (node: Node): unknown => {\n\tswitch (node._tag) {\n\t\tcase \"True\":\n\t\tcase \"False\":\n\t\t\treturn { _tag: node._tag }\n\t\tcase \"Compare\":\n\t\t\treturn {\n\t\t\t\t_tag: \"Compare\",\n\t\t\t\top: node.op,\n\t\t\t\tfield: node.field,\n\t\t\t\tvalue: operandJson(node.value),\n\t\t\t}\n\t\tcase \"In\":\n\t\t\treturn {\n\t\t\t\t_tag: \"In\",\n\t\t\t\tfield: node.field,\n\t\t\t\tvalues: Arr.map(node.values, operandJson),\n\t\t\t}\n\t\tcase \"Exists\":\n\t\t\treturn { _tag: \"Exists\", field: node.field }\n\t\tcase \"Under\":\n\t\t\treturn { _tag: \"Under\", prefix: Arr.map(node.prefix, operandJson) }\n\t\tcase \"And\":\n\t\tcase \"Or\":\n\t\t\treturn { _tag: node._tag, conditions: Arr.map(node.conditions, toJson) }\n\t\tcase \"Not\":\n\t\t\treturn { _tag: \"Not\", condition: toJson(node.condition) }\n\t\tcase \"Predicate\":\n\t\t\tthrow new Error(\n\t\t\t\t`The predicate \"${node.name}\" can not become JSON. A condition with a predicate has no JSON form.`,\n\t\t\t)\n\t}\n}\n\n/** Tests if a value is a node. Only a constructor of a node makes one. */\nexport const isNode = (u: unknown): u is Node => u instanceof Base\n\nconst notNode = (): Error =>\n\tnew Error(\n\t\t\"A condition must be made with a builder or a function of Condition. A plain object is not a condition\",\n\t)\n\n/** Gives a value as a node, or throws when it is not a node. */\nexport const toNode = (u: unknown): Node => {\n\tif (!isNode(u)) {\n\t\tthrow notNode()\n\t}\n\treturn u\n}\n\nexport const always: Node = new True()\n\nexport const never: Node = new False()\n"],"mappings":"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"}
@@ -66,7 +66,7 @@ const partFits = (part, segment) => {
66
66
  }
67
67
  };
68
68
  /** Adds the place after each `**`, since a `**` may match no names. */
69
- const close = (pattern, states) => Arr.dedupe(Arr.flatMap(states, (state) => pattern[state]?._tag === "Globstar" ? [state, state + 1] : [state]));
69
+ const close = (pattern, states) => Array.from(new Set(Arr.flatMap(states, (state) => pattern[state]?._tag === "Globstar" ? [state, state + 1] : [state])));
70
70
  const start = (pattern) => close(pattern, [0]);
71
71
  /** Gives the places after one more segment. A `**` that takes it stays. */
72
72
  const step = (pattern, states, segment) => close(pattern, Arr.flatMap(states, (state) => {
@@ -1 +1 @@
1
- {"version":3,"file":"patterns.js","names":["Catalog.keyFits"],"sources":["../../src/internal/patterns.ts"],"sourcesContent":["/**\n * Field patterns, as in `settings.*`, `secret*` or `**.secret`. A pattern is\n * a list of parts with dots between them:\n * - A name with no star matches that name.\n * - A part with stars matches a name, and each star matches any text with no\n * dot, as `secret*` matches `secretKey`.\n * - `**` matches any number of names, also none. It must be a whole part.\n *\n * A pattern that matches a field matches each field below it too. So `pay`\n * matches `pay.amount`, as `pay.**` does.\n *\n * The match goes one name at a time, and it keeps the set of places in the\n * pattern that it may be at. It does not go back, so the time is at most the\n * number of names times the number of parts.\n */\nimport * as Arr from \"effect/Array\"\nimport * as Result from \"effect/Result\"\nimport * as Catalog from \"./catalog.ts\"\nimport * as Limits from \"./limits.ts\"\n\n/** One part of a pattern. */\nexport type Part =\n\t| { readonly _tag: \"Name\"; readonly name: string }\n\t/** The texts between the stars of the part. */\n\t| { readonly _tag: \"Glob\"; readonly pieces: ReadonlyArray<string> }\n\t| { readonly _tag: \"Globstar\" }\n\n/** A pattern, as a list of parts. Two `**` parts are never next to each other. */\nexport type Pattern = ReadonlyArray<Part>\n\nconst globstar: Part = { _tag: \"Globstar\" }\n\nconst partOf = (text: string): Part =>\n\ttext === \"**\"\n\t\t? globstar\n\t\t: text.includes(\"*\")\n\t\t\t? { _tag: \"Glob\", pieces: text.split(\"*\") }\n\t\t\t: { _tag: \"Name\", name: text }\n\n/**\n * Reads a pattern. It fails with the problem when the pattern has `**`\n * inside a part, or has more parts than `patternParts`.\n */\nexport const parse = (text: string): Result.Result<Pattern, string> => {\n\tconst texts = text.split(\".\", Limits.patternParts + 1)\n\tif (texts.length > Limits.patternParts) {\n\t\treturn Result.fail(\n\t\t\t`The field pattern \"${text}\" has more than ${String(Limits.patternParts)} parts. The most is ${String(Limits.patternParts)}.`,\n\t\t)\n\t}\n\tif (Arr.some(texts, (part) => part !== \"**\" && part.includes(\"**\"))) {\n\t\treturn Result.fail(\n\t\t\t`The field pattern \"${text}\" has \"**\" inside a part. \"**\" must be a whole part`,\n\t\t)\n\t}\n\t// `a.**.**` matches what `a.**` matches.\n\treturn Result.succeed(\n\t\tArr.dedupeAdjacentWith(\n\t\t\tArr.map(texts, partOf),\n\t\t\t(left, right) => left._tag === \"Globstar\" && right._tag === \"Globstar\",\n\t\t),\n\t)\n}\n\n/**\n * Reads a pattern of a bound rule. The binding of the rule took the pattern,\n * so a problem here is a defect.\n */\nexport const parseBound = (text: string): Pattern =>\n\tResult.getOrThrowWith(parse(text), (problem) => new Error(problem))\n\n/** Tests if a name matches the pieces of a part with stars. */\nconst globMatches = (pieces: ReadonlyArray<string>, name: string): boolean => {\n\tconst first = pieces[0]!\n\tconst last = pieces[pieces.length - 1]!\n\tconst middle = pieces.slice(1, -1)\n\tif (\n\t\tname.length < first.length + last.length ||\n\t\t!name.startsWith(first) ||\n\t\t!name.endsWith(last)\n\t) {\n\t\treturn false\n\t}\n\t// Each piece in the middle is found as early as it can be. An earlier\n\t// place never leaves less room for the pieces after it.\n\tconst end = name.length - last.length\n\tconst place = Arr.reduce(middle, first.length as number, (at, piece) => {\n\t\tif (at < 0) {\n\t\t\treturn at\n\t\t}\n\t\tconst found = name.indexOf(piece, at)\n\t\treturn found < 0 || found + piece.length > end ? -1 : found + piece.length\n\t})\n\treturn place >= 0\n}\n\n/**\n * Tests if a part matches one segment of a path. A part with stars matches\n * any key of a record. A name matches a key of a record when the Schema of\n * the keys takes it.\n */\nconst partFits = (part: Part, segment: Catalog.Segment): boolean => {\n\tswitch (part._tag) {\n\t\tcase \"Globstar\":\n\t\t\treturn true\n\t\tcase \"Glob\":\n\t\t\treturn typeof segment !== \"string\" || globMatches(part.pieces, segment)\n\t\tcase \"Name\":\n\t\t\treturn typeof segment === \"string\"\n\t\t\t\t? part.name === segment\n\t\t\t\t: Catalog.keyFits(segment, part.name)\n\t}\n}\n\n/** The places of a match: the parts that it may take next. */\ntype States = ReadonlyArray<number>\n\n/** Adds the place after each `**`, since a `**` may match no names. */\nconst close = (pattern: Pattern, states: States): States =>\n\tArr.dedupe(\n\t\tArr.flatMap(states, (state) =>\n\t\t\tpattern[state]?._tag === \"Globstar\" ? [state, state + 1] : [state],\n\t\t),\n\t)\n\nconst start = (pattern: Pattern): States => close(pattern, [0])\n\n/** Gives the places after one more segment. A `**` that takes it stays. */\nconst step = (\n\tpattern: Pattern,\n\tstates: States,\n\tsegment: Catalog.Segment,\n): States =>\n\tclose(\n\t\tpattern,\n\t\tArr.flatMap(states, (state) => {\n\t\t\tconst part = pattern[state]\n\t\t\treturn part === undefined\n\t\t\t\t? []\n\t\t\t\t: part._tag === \"Globstar\"\n\t\t\t\t\t? [state]\n\t\t\t\t\t: partFits(part, segment)\n\t\t\t\t\t\t? [state + 1]\n\t\t\t\t\t\t: []\n\t\t}),\n\t)\n\nconst isDone = (pattern: Pattern, states: States): boolean =>\n\tstates.includes(pattern.length)\n\n/**\n * Tests if a pattern matches a field, or a field above it. The field is a\n * list of names.\n */\nexport const matches = (\n\tpattern: Pattern,\n\tnames: ReadonlyArray<string>,\n): boolean => {\n\tconst found = Arr.reduce(\n\t\tnames,\n\t\t{ states: start(pattern), done: isDone(pattern, start(pattern)) },\n\t\t(before, name) => {\n\t\t\tif (before.done || before.states.length === 0) {\n\t\t\t\treturn before\n\t\t\t}\n\t\t\tconst states = step(pattern, before.states, name)\n\t\t\treturn { states, done: isDone(pattern, states) }\n\t\t},\n\t)\n\treturn found.done\n}\n\n/**\n * Tests if a pattern may match a field below a field, with more names after\n * the names of the field.\n */\nexport const matchesBelow = (\n\tpattern: Pattern,\n\tnames: ReadonlyArray<string>,\n): boolean =>\n\tArr.some(\n\t\tArr.reduce(names, start(pattern), (states, name) =>\n\t\t\tstep(pattern, states, name),\n\t\t),\n\t\t(state) => state < pattern.length,\n\t)\n\n/** Tests if a pattern matches some field of a catalog. */\nexport const fitsCatalog = (\n\tpattern: Pattern,\n\tcatalog: Catalog.Catalog,\n): boolean => {\n\tconst below = (branch: Catalog.Branch, states: States): boolean =>\n\t\tstates.length > 0 &&\n\t\t(Arr.some(branch.children, ([name, child]) => visit(child, name, states)) ||\n\t\t\t(branch.key !== undefined &&\n\t\t\t\tbranch.keyBranch !== undefined &&\n\t\t\t\tvisit(branch.keyBranch, branch.key, states)))\n\tconst visit = (\n\t\tbranch: Catalog.Branch,\n\t\tsegment: Catalog.Segment,\n\t\tbefore: States,\n\t): boolean => {\n\t\tconst states = step(pattern, before, segment)\n\t\treturn (\n\t\t\t(branch.field !== undefined && isDone(pattern, states)) ||\n\t\t\tbelow(branch, states)\n\t\t)\n\t}\n\treturn below(catalog.root, start(pattern))\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"patterns.js","names":["Catalog.keyFits"],"sources":["../../src/internal/patterns.ts"],"sourcesContent":["/**\n * Field patterns, as in `settings.*`, `secret*` or `**.secret`. A pattern is\n * a list of parts with dots between them:\n * - A name with no star matches that name.\n * - A part with stars matches a name, and each star matches any text with no\n * dot, as `secret*` matches `secretKey`.\n * - `**` matches any number of names, also none. It must be a whole part.\n *\n * A pattern that matches a field matches each field below it too. So `pay`\n * matches `pay.amount`, as `pay.**` does.\n *\n * The match goes one name at a time, and it keeps the set of places in the\n * pattern that it may be at. It does not go back, so the time is at most the\n * number of names times the number of parts.\n */\nimport * as Arr from \"effect/Array\"\nimport * as Result from \"effect/Result\"\nimport * as Catalog from \"./catalog.ts\"\nimport * as Limits from \"./limits.ts\"\n\n/** One part of a pattern. */\nexport type Part =\n\t| { readonly _tag: \"Name\"; readonly name: string }\n\t/** The texts between the stars of the part. */\n\t| { readonly _tag: \"Glob\"; readonly pieces: ReadonlyArray<string> }\n\t| { readonly _tag: \"Globstar\" }\n\n/** A pattern, as a list of parts. Two `**` parts are never next to each other. */\nexport type Pattern = ReadonlyArray<Part>\n\nconst globstar: Part = { _tag: \"Globstar\" }\n\nconst partOf = (text: string): Part =>\n\ttext === \"**\"\n\t\t? globstar\n\t\t: text.includes(\"*\")\n\t\t\t? { _tag: \"Glob\", pieces: text.split(\"*\") }\n\t\t\t: { _tag: \"Name\", name: text }\n\n/**\n * Reads a pattern. It fails with the problem when the pattern has `**`\n * inside a part, or has more parts than `patternParts`.\n */\nexport const parse = (text: string): Result.Result<Pattern, string> => {\n\tconst texts = text.split(\".\", Limits.patternParts + 1)\n\tif (texts.length > Limits.patternParts) {\n\t\treturn Result.fail(\n\t\t\t`The field pattern \"${text}\" has more than ${String(Limits.patternParts)} parts. The most is ${String(Limits.patternParts)}.`,\n\t\t)\n\t}\n\tif (Arr.some(texts, (part) => part !== \"**\" && part.includes(\"**\"))) {\n\t\treturn Result.fail(\n\t\t\t`The field pattern \"${text}\" has \"**\" inside a part. \"**\" must be a whole part`,\n\t\t)\n\t}\n\t// `a.**.**` matches what `a.**` matches.\n\treturn Result.succeed(\n\t\tArr.dedupeAdjacentWith(\n\t\t\tArr.map(texts, partOf),\n\t\t\t(left, right) => left._tag === \"Globstar\" && right._tag === \"Globstar\",\n\t\t),\n\t)\n}\n\n/**\n * Reads a pattern of a bound rule. The binding of the rule took the pattern,\n * so a problem here is a defect.\n */\nexport const parseBound = (text: string): Pattern =>\n\tResult.getOrThrowWith(parse(text), (problem) => new Error(problem))\n\n/** Tests if a name matches the pieces of a part with stars. */\nconst globMatches = (pieces: ReadonlyArray<string>, name: string): boolean => {\n\tconst first = pieces[0]!\n\tconst last = pieces[pieces.length - 1]!\n\tconst middle = pieces.slice(1, -1)\n\tif (\n\t\tname.length < first.length + last.length ||\n\t\t!name.startsWith(first) ||\n\t\t!name.endsWith(last)\n\t) {\n\t\treturn false\n\t}\n\t// Each piece in the middle is found as early as it can be. An earlier\n\t// place never leaves less room for the pieces after it.\n\tconst end = name.length - last.length\n\tconst place = Arr.reduce(middle, first.length as number, (at, piece) => {\n\t\tif (at < 0) {\n\t\t\treturn at\n\t\t}\n\t\tconst found = name.indexOf(piece, at)\n\t\treturn found < 0 || found + piece.length > end ? -1 : found + piece.length\n\t})\n\treturn place >= 0\n}\n\n/**\n * Tests if a part matches one segment of a path. A part with stars matches\n * any key of a record. A name matches a key of a record when the Schema of\n * the keys takes it.\n */\nconst partFits = (part: Part, segment: Catalog.Segment): boolean => {\n\tswitch (part._tag) {\n\t\tcase \"Globstar\":\n\t\t\treturn true\n\t\tcase \"Glob\":\n\t\t\treturn typeof segment !== \"string\" || globMatches(part.pieces, segment)\n\t\tcase \"Name\":\n\t\t\treturn typeof segment === \"string\"\n\t\t\t\t? part.name === segment\n\t\t\t\t: Catalog.keyFits(segment, part.name)\n\t}\n}\n\n/** The places of a match: the parts that it may take next. */\ntype States = ReadonlyArray<number>\n\n/** Adds the place after each `**`, since a `**` may match no names. */\nconst close = (pattern: Pattern, states: States): States =>\n\t// A native `Set` keeps the first copy of each place, in order. It is\n\t// faster than `Arr.dedupe`, and this is on the path of each match.\n\tArray.from(\n\t\tnew Set(\n\t\t\tArr.flatMap(states, (state) =>\n\t\t\t\tpattern[state]?._tag === \"Globstar\" ? [state, state + 1] : [state],\n\t\t\t),\n\t\t),\n\t)\n\nconst start = (pattern: Pattern): States => close(pattern, [0])\n\n/** Gives the places after one more segment. A `**` that takes it stays. */\nconst step = (\n\tpattern: Pattern,\n\tstates: States,\n\tsegment: Catalog.Segment,\n): States =>\n\tclose(\n\t\tpattern,\n\t\tArr.flatMap(states, (state) => {\n\t\t\tconst part = pattern[state]\n\t\t\treturn part === undefined\n\t\t\t\t? []\n\t\t\t\t: part._tag === \"Globstar\"\n\t\t\t\t\t? [state]\n\t\t\t\t\t: partFits(part, segment)\n\t\t\t\t\t\t? [state + 1]\n\t\t\t\t\t\t: []\n\t\t}),\n\t)\n\nconst isDone = (pattern: Pattern, states: States): boolean =>\n\tstates.includes(pattern.length)\n\n/**\n * Tests if a pattern matches a field, or a field above it. The field is a\n * list of names.\n */\nexport const matches = (\n\tpattern: Pattern,\n\tnames: ReadonlyArray<string>,\n): boolean => {\n\tconst found = Arr.reduce(\n\t\tnames,\n\t\t{ states: start(pattern), done: isDone(pattern, start(pattern)) },\n\t\t(before, name) => {\n\t\t\tif (before.done || before.states.length === 0) {\n\t\t\t\treturn before\n\t\t\t}\n\t\t\tconst states = step(pattern, before.states, name)\n\t\t\treturn { states, done: isDone(pattern, states) }\n\t\t},\n\t)\n\treturn found.done\n}\n\n/**\n * Tests if a pattern may match a field below a field, with more names after\n * the names of the field.\n */\nexport const matchesBelow = (\n\tpattern: Pattern,\n\tnames: ReadonlyArray<string>,\n): boolean =>\n\tArr.some(\n\t\tArr.reduce(names, start(pattern), (states, name) =>\n\t\t\tstep(pattern, states, name),\n\t\t),\n\t\t(state) => state < pattern.length,\n\t)\n\n/** Tests if a pattern matches some field of a catalog. */\nexport const fitsCatalog = (\n\tpattern: Pattern,\n\tcatalog: Catalog.Catalog,\n): boolean => {\n\tconst below = (branch: Catalog.Branch, states: States): boolean =>\n\t\tstates.length > 0 &&\n\t\t(Arr.some(branch.children, ([name, child]) => visit(child, name, states)) ||\n\t\t\t(branch.key !== undefined &&\n\t\t\t\tbranch.keyBranch !== undefined &&\n\t\t\t\tvisit(branch.keyBranch, branch.key, states)))\n\tconst visit = (\n\t\tbranch: Catalog.Branch,\n\t\tsegment: Catalog.Segment,\n\t\tbefore: States,\n\t): boolean => {\n\t\tconst states = step(pattern, before, segment)\n\t\treturn (\n\t\t\t(branch.field !== undefined && isDone(pattern, states)) ||\n\t\t\tbelow(branch, states)\n\t\t)\n\t}\n\treturn below(catalog.root, start(pattern))\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AA8BA,MAAM,WAAiB,EAAE,MAAM,WAAW;AAE1C,MAAM,UAAU,SACf,SAAS,OACN,WACA,KAAK,SAAS,GAAG,IAChB;CAAE,MAAM;CAAQ,QAAQ,KAAK,MAAM,GAAG;AAAE,IACxC;CAAE,MAAM;CAAQ,MAAM;AAAK;;;;;AAMhC,MAAa,SAAS,SAAiD;CACtE,MAAM,QAAQ,KAAK,MAAM,KAAK,EAAuB;CACrD,IAAI,MAAM,SAAS,IAClB,OAAO,OAAO,KACb,sBAAsB,KAAK,kBAAkB,OAAO,EAAmB,EAAE,sBAAsB,OAAO,EAAmB,EAAE,EAC5H;CAED,IAAI,IAAI,KAAK,QAAQ,SAAS,SAAS,QAAQ,KAAK,SAAS,IAAI,CAAC,GACjE,OAAO,OAAO,KACb,sBAAsB,KAAK,oDAC5B;CAGD,OAAO,OAAO,QACb,IAAI,mBACH,IAAI,IAAI,OAAO,MAAM,IACpB,MAAM,UAAU,KAAK,SAAS,cAAc,MAAM,SAAS,UAC7D,CACD;AACD;;;;;AAMA,MAAa,cAAc,SAC1B,OAAO,eAAe,MAAM,IAAI,IAAI,YAAY,IAAI,MAAM,OAAO,CAAC;;AAGnE,MAAM,eAAe,QAA+B,SAA0B;CAC7E,MAAM,QAAQ,OAAO;CACrB,MAAM,OAAO,OAAO,OAAO,SAAS;CACpC,MAAM,SAAS,OAAO,MAAM,GAAG,EAAE;CACjC,IACC,KAAK,SAAS,MAAM,SAAS,KAAK,UAClC,CAAC,KAAK,WAAW,KAAK,KACtB,CAAC,KAAK,SAAS,IAAI,GAEnB,OAAO;CAIR,MAAM,MAAM,KAAK,SAAS,KAAK;CAQ/B,OAPc,IAAI,OAAO,QAAQ,MAAM,SAAmB,IAAI,UAAU;EACvE,IAAI,KAAK,GACR,OAAO;EAER,MAAM,QAAQ,KAAK,QAAQ,OAAO,EAAE;EACpC,OAAO,QAAQ,KAAK,QAAQ,MAAM,SAAS,MAAM,KAAK,QAAQ,MAAM;CACrE,CACW,KAAK;AACjB;;;;;;AAOA,MAAM,YAAY,MAAY,YAAsC;CACnE,QAAQ,KAAK,MAAb;EACC,KAAK,YACJ,OAAO;EACR,KAAK,QACJ,OAAO,OAAO,YAAY,YAAY,YAAY,KAAK,QAAQ,OAAO;EACvE,KAAK,QACJ,OAAO,OAAO,YAAY,WACvB,KAAK,SAAS,UACdA,QAAgB,SAAS,KAAK,IAAI;CACvC;AACD;;AAMA,MAAM,SAAS,SAAkB,WAGhC,MAAM,KACL,IAAI,IACH,IAAI,QAAQ,SAAS,UACpB,QAAQ,MAAM,EAAE,SAAS,aAAa,CAAC,OAAO,QAAQ,CAAC,IAAI,CAAC,KAAK,CAClE,CACD,CACD;AAED,MAAM,SAAS,YAA6B,MAAM,SAAS,CAAC,CAAC,CAAC;;AAG9D,MAAM,QACL,SACA,QACA,YAEA,MACC,SACA,IAAI,QAAQ,SAAS,UAAU;CAC9B,MAAM,OAAO,QAAQ;CACrB,OAAO,SAAS,KAAA,IACb,CAAC,IACD,KAAK,SAAS,aACb,CAAC,KAAK,IACN,SAAS,MAAM,OAAO,IACrB,CAAC,QAAQ,CAAC,IACV,CAAC;AACP,CAAC,CACF;AAED,MAAM,UAAU,SAAkB,WACjC,OAAO,SAAS,QAAQ,MAAM;;;;;AAM/B,MAAa,WACZ,SACA,UACa;CAYb,OAXc,IAAI,OACjB,OACA;EAAE,QAAQ,MAAM,OAAO;EAAG,MAAM,OAAO,SAAS,MAAM,OAAO,CAAC;CAAE,IAC/D,QAAQ,SAAS;EACjB,IAAI,OAAO,QAAQ,OAAO,OAAO,WAAW,GAC3C,OAAO;EAER,MAAM,SAAS,KAAK,SAAS,OAAO,QAAQ,IAAI;EAChD,OAAO;GAAE;GAAQ,MAAM,OAAO,SAAS,MAAM;EAAE;CAChD,CAEU,CAAC,CAAC;AACd;;;;;AAMA,MAAa,gBACZ,SACA,UAEA,IAAI,KACH,IAAI,OAAO,OAAO,MAAM,OAAO,IAAI,QAAQ,SAC1C,KAAK,SAAS,QAAQ,IAAI,CAC3B,IACC,UAAU,QAAQ,QAAQ,MAC5B;;AAGD,MAAa,eACZ,SACA,YACa;CACb,MAAM,SAAS,QAAwB,WACtC,OAAO,SAAS,MACf,IAAI,KAAK,OAAO,WAAW,CAAC,MAAM,WAAW,MAAM,OAAO,MAAM,MAAM,CAAC,KACtE,OAAO,QAAQ,KAAA,KACf,OAAO,cAAc,KAAA,KACrB,MAAM,OAAO,WAAW,OAAO,KAAK,MAAM;CAC7C,MAAM,SACL,QACA,SACA,WACa;EACb,MAAM,SAAS,KAAK,SAAS,QAAQ,OAAO;EAC5C,OACE,OAAO,UAAU,KAAA,KAAa,OAAO,SAAS,MAAM,KACrD,MAAM,QAAQ,MAAM;CAEtB;CACA,OAAO,MAAM,QAAQ,MAAM,MAAM,OAAO,CAAC;AAC1C"}
@@ -2,7 +2,7 @@ import { LimitExceeded, policyNodes } from "./limits.js";
2
2
  import { Problem, decodeAt, problem, read, readList, readString, spend, toJson as toJson$1 } from "./json.js";
3
3
  import { at, pathOf } from "./place.js";
4
4
  import { make } from "./rule.js";
5
- import { Ceiling, Rules, policy_nodes_exports, rulesOf } from "./policy-nodes.js";
5
+ import { Ceiling, Rules, isAlgorithm, policy_nodes_exports, rulesOf } from "./policy-nodes.js";
6
6
  import * as Effect from "effect/Effect";
7
7
  import * as Schema from "effect/Schema";
8
8
  import * as Arr from "effect/Array";
@@ -81,12 +81,6 @@ const encode = (node, meta) => Effect.gen(function* () {
81
81
  const forms = new Map(encoded);
82
82
  return toJson(node, (rule) => forms.get(rule));
83
83
  });
84
- const algorithms = [
85
- "denyOverrides",
86
- "permitOverrides",
87
- "firstApplicable",
88
- "lastApplicable"
89
- ];
90
84
  /** Reads a list of strings. */
91
85
  const readStrings = (input, name, path, budget) => Arr.map(readList(input, name, path, budget), (value, index) => {
92
86
  if (typeof value !== "string") throw problem([
@@ -175,7 +169,7 @@ const readTree = (input, path, place, depth, budget, rules) => {
175
169
  switch (tag) {
176
170
  case "Rules": {
177
171
  const algorithm = readString(input, "algorithm", path);
178
- if (!algorithms.includes(algorithm)) throw problem([...path, "algorithm"], `"${algorithm}" is not a combining algorithm`);
172
+ if (!isAlgorithm(algorithm)) throw problem([...path, "algorithm"], `"${algorithm}" is not a combining algorithm`);
179
173
  const found = Arr.map(readList(input, "rules", path, budget), (rule, index) => rules.push({
180
174
  input: rule,
181
175
  place: at(place, "rules", index)