@nmnmcc/ability 2.0.5 → 2.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -5
- package/dist/Condition.d.ts +6 -6
- package/dist/Condition.d.ts.map +1 -1
- package/dist/Condition.js.map +1 -1
- package/dist/Domain.d.ts +1 -1
- package/dist/Policy.d.ts +2 -2
- package/dist/Policy.d.ts.map +1 -1
- package/dist/Policy.js.map +1 -1
- package/dist/internal/algebra.js +128 -79
- package/dist/internal/algebra.js.map +1 -1
- package/dist/internal/analysis.js +1 -1
- package/dist/internal/analysis.js.map +1 -1
- package/dist/internal/authorizer.d.ts.map +1 -1
- package/dist/internal/authorizer.js +38 -14
- package/dist/internal/authorizer.js.map +1 -1
- package/dist/internal/bind.js +59 -43
- package/dist/internal/bind.js.map +1 -1
- package/dist/internal/catalog.d.ts +6 -0
- package/dist/internal/catalog.d.ts.map +1 -1
- package/dist/internal/catalog.js +17 -14
- package/dist/internal/catalog.js.map +1 -1
- package/dist/internal/decide.js +1 -1
- package/dist/internal/domain.js +1 -1
- package/dist/internal/json.js +2 -10
- package/dist/internal/json.js.map +1 -1
- package/dist/internal/nodes.d.ts +11 -1
- package/dist/internal/nodes.d.ts.map +1 -1
- package/dist/internal/nodes.js +51 -11
- package/dist/internal/nodes.js.map +1 -1
- package/dist/internal/patterns.js +1 -1
- package/dist/internal/patterns.js.map +1 -1
- package/dist/internal/policy-json.js +2 -8
- package/dist/internal/policy-json.js.map +1 -1
- package/dist/internal/policy-nodes.d.ts +4 -1
- package/dist/internal/policy-nodes.d.ts.map +1 -1
- package/dist/internal/policy-nodes.js +14 -5
- package/dist/internal/policy-nodes.js.map +1 -1
- package/dist/internal/search.js +4 -4
- package/dist/internal/search.js.map +1 -1
- package/dist/internal/trampoline.js +75 -0
- package/dist/internal/trampoline.js.map +1 -0
- package/package.json +1 -1
- package/src/Condition.ts +5 -2
- package/src/Policy.ts +1 -2
- package/src/internal/algebra.ts +262 -143
- package/src/internal/analysis.ts +3 -1
- package/src/internal/authorizer.ts +59 -14
- package/src/internal/bind.ts +149 -71
- package/src/internal/catalog.ts +54 -50
- package/src/internal/json.ts +2 -11
- package/src/internal/nodes.ts +58 -24
- package/src/internal/patterns.ts +7 -3
- package/src/internal/policy-json.ts +2 -9
- package/src/internal/policy-nodes.ts +16 -7
- package/src/internal/search.ts +13 -10
- package/src/internal/trampoline.ts +147 -0
package/dist/internal/catalog.js
CHANGED
|
@@ -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:
|
|
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) =>
|
|
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) =>
|
|
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
|
|
@@ -204,7 +204,6 @@ const namesOf = (structs) => Arr.dedupe(Arr.flatMap(structs, (struct) => Arr.fla
|
|
|
204
204
|
*/
|
|
205
205
|
const branchOf = (place, count) => {
|
|
206
206
|
const structs = Arr.filter(Arr.map(place.schemas, structOf), isStruct);
|
|
207
|
-
const classes = Arr.filter(Arr.map(Arr.filter(place.schemas, (schema) => schema._tag === "Declaration"), structOf), isStruct);
|
|
208
207
|
const values = Arr.filter(place.schemas, (schema) => !isStruct(structOf(schema)));
|
|
209
208
|
const valueKinds = Arr.reduce(values, noKinds, (kinds, schema) => joinKinds(kinds, kindsOf(structOf(schema) ?? schema)));
|
|
210
209
|
const kinds = place.top ? anyKinds : joinKinds(joinKinds(valueKinds, structs.length > 0 ? objectKinds : noKinds), place.missing ? nullKinds : noKinds);
|
|
@@ -230,15 +229,18 @@ const branchOf = (place, count) => {
|
|
|
230
229
|
keyBranch: void 0
|
|
231
230
|
};
|
|
232
231
|
const structProperties = Arr.map(structs, propertiesOf);
|
|
233
|
-
const classProperties = Arr.map(classes, propertiesOf);
|
|
234
232
|
const children = Arr.map(namesOf(structs), (name) => {
|
|
235
|
-
const properties = Arr.flatMap(structProperties, (named) =>
|
|
233
|
+
const properties = Arr.flatMap(structProperties, (named) => {
|
|
234
|
+
const property = named.get(name);
|
|
235
|
+
return property === void 0 ? [] : [property];
|
|
236
|
+
});
|
|
237
|
+
const top = place.top || valueKinds.object || properties.length < structs.length;
|
|
236
238
|
const below = {
|
|
237
239
|
path: [...place.path, name],
|
|
238
240
|
schemas: Arr.flatMap(properties, (property) => alternatives(property.type, /* @__PURE__ */ new Set())),
|
|
239
241
|
missing: place.missing || values.length > 0 || Arr.some(properties, (property) => SchemaAST.isOptional(property.type)),
|
|
240
|
-
top
|
|
241
|
-
plain: place.plain && !
|
|
242
|
+
top,
|
|
243
|
+
plain: place.plain && !top
|
|
242
244
|
};
|
|
243
245
|
return [name, branchOf(below, count)];
|
|
244
246
|
});
|
|
@@ -251,6 +253,7 @@ const branchOf = (place, count) => {
|
|
|
251
253
|
key: void 0,
|
|
252
254
|
keyBranch: void 0
|
|
253
255
|
};
|
|
256
|
+
const keyTop = place.top || valueKinds.object || records.length < structs.length;
|
|
254
257
|
const key = {
|
|
255
258
|
_tag: "Key",
|
|
256
259
|
parameters: Arr.map(signatures, (signature) => signature.parameter)
|
|
@@ -264,8 +267,8 @@ const branchOf = (place, count) => {
|
|
|
264
267
|
path: [...place.path, key],
|
|
265
268
|
schemas: Arr.flatMap(signatures, (signature) => alternatives(signature.type, /* @__PURE__ */ new Set())),
|
|
266
269
|
missing: true,
|
|
267
|
-
top:
|
|
268
|
-
plain: place.plain && !
|
|
270
|
+
top: keyTop,
|
|
271
|
+
plain: place.plain && !keyTop
|
|
269
272
|
}, count)
|
|
270
273
|
};
|
|
271
274
|
};
|
|
@@ -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":"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"}
|
|
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\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 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\t// A struct without the name may still have it as an extra field, with\n\t\t// any value: only a decode or a `make` takes extra fields away, and a\n\t\t// decision may get a value made by hand. A value that may be any\n\t\t// object, as one of `Schema.Unknown` may, may have the name with any\n\t\t// value too.\n\t\tconst top =\n\t\t\tplace.top || valueKinds.object || properties.length < structs.length\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\ttop,\n\t\t\t// A value that may be anything may be a list, or have a getter, so\n\t\t\t// a read below it may not find plain data.\n\t\t\tplain: place.plain && !top,\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 keyTop =\n\t\tplace.top || valueKinds.object || records.length < structs.length\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: keyTop,\n\t\t\tplain: place.plain && !keyTop,\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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"}
|
package/dist/internal/decide.js
CHANGED
|
@@ -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
|
/**
|
package/dist/internal/domain.js
CHANGED
|
@@ -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`.
|
package/dist/internal/json.js
CHANGED
|
@@ -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 (!
|
|
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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"}
|
package/dist/internal/nodes.d.ts
CHANGED
|
@@ -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
|
-
|
|
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";
|
|
@@ -16,6 +19,7 @@ export interface PrincipalRef {
|
|
|
16
19
|
export type Operand = Literal | PrincipalRef;
|
|
17
20
|
interface Facts {
|
|
18
21
|
readonly size: number;
|
|
22
|
+
readonly weight: number;
|
|
19
23
|
readonly depth: number;
|
|
20
24
|
readonly opaque: boolean;
|
|
21
25
|
}
|
|
@@ -31,6 +35,12 @@ declare abstract class Base extends Data.Class {
|
|
|
31
35
|
constructor(props: object, facts: Facts);
|
|
32
36
|
/** The number of nodes, with a shared child counted for each place. */
|
|
33
37
|
get size(): number;
|
|
38
|
+
/**
|
|
39
|
+
* The number of nodes and of the values of their `In` and `Under` tests,
|
|
40
|
+
* with a shared child counted for each place. A walk that reads the tests
|
|
41
|
+
* does this much work, so the limits of the nodes count it.
|
|
42
|
+
*/
|
|
43
|
+
get weight(): number;
|
|
34
44
|
/** The number of levels. */
|
|
35
45
|
get depth(): number;
|
|
36
46
|
/** The node has a predicate. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"nodes.d.ts","names":[],"sources":["../../src/internal/nodes.ts"],"mappings":"
|
|
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;WACA;;;uBAmDK,aAAa,KAAK;;;;;;;EAMhC;EAMA,YAAY,eAAe,OAAO;;MAM9B;;;;;;MASA;;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;;;;qBAQpB,eAAe;WAClB;WACQ;EACjB,YAAY;aAAkB;;;;qBAMlB,cAAc;WACjB;WACQ,QAAQ,cAAc;EACvC,YAAY;aAAkB,QAAQ,cAAc;;;qBAiBxC,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"}
|
package/dist/internal/nodes.js
CHANGED
|
@@ -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
|
-
|
|
45
|
-
const
|
|
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
|
/**
|
|
@@ -78,17 +88,36 @@ const checkOperands = (values) => {
|
|
|
78
88
|
};
|
|
79
89
|
const leaf = {
|
|
80
90
|
size: 1,
|
|
91
|
+
weight: 1,
|
|
81
92
|
depth: 1,
|
|
82
93
|
opaque: false
|
|
83
94
|
};
|
|
95
|
+
/**
|
|
96
|
+
* The facts of a test with values, as `In` and `Under`. Each value counts in
|
|
97
|
+
* the weight, since a walk that reads the test reads its values too. It stops
|
|
98
|
+
* a test past the limits.
|
|
99
|
+
*/
|
|
100
|
+
const valuesFacts = (values) => checkWeight({
|
|
101
|
+
...leaf,
|
|
102
|
+
weight: 1 + values.length
|
|
103
|
+
});
|
|
104
|
+
const checkWeight = (facts) => {
|
|
105
|
+
if (facts.weight > 1e5) throw exceeded("A condition", "conditionNodes", "nodes and values", facts.weight, conditionNodes);
|
|
106
|
+
return facts;
|
|
107
|
+
};
|
|
84
108
|
/** The facts of a node with children. It stops a node past the limits. */
|
|
85
109
|
const factsOf = (children) => {
|
|
86
110
|
const size = Arr.reduce(children, 1, (total, child) => total + child.size);
|
|
87
|
-
|
|
111
|
+
const weight = Arr.reduce(children, 1, (total, child) => total + child.weight);
|
|
112
|
+
checkWeight({
|
|
113
|
+
...leaf,
|
|
114
|
+
weight
|
|
115
|
+
});
|
|
88
116
|
const depth = 1 + Arr.reduce(children, 0, (top, child) => Math.max(top, child.depth));
|
|
89
117
|
if (depth > 500) throw exceeded("A condition", "conditionDepth", "levels", depth, 500);
|
|
90
118
|
return {
|
|
91
119
|
size,
|
|
120
|
+
weight,
|
|
92
121
|
depth,
|
|
93
122
|
opaque: Arr.some(children, (child) => child.opaque)
|
|
94
123
|
};
|
|
@@ -112,6 +141,14 @@ var Base = class extends Data.Class {
|
|
|
112
141
|
get size() {
|
|
113
142
|
return this.#facts.size;
|
|
114
143
|
}
|
|
144
|
+
/**
|
|
145
|
+
* The number of nodes and of the values of their `In` and `Under` tests,
|
|
146
|
+
* with a shared child counted for each place. A walk that reads the tests
|
|
147
|
+
* does this much work, so the limits of the nodes count it.
|
|
148
|
+
*/
|
|
149
|
+
get weight() {
|
|
150
|
+
return this.#facts.weight;
|
|
151
|
+
}
|
|
115
152
|
/** The number of levels. */
|
|
116
153
|
get depth() {
|
|
117
154
|
return this.#facts.depth;
|
|
@@ -139,7 +176,7 @@ var False = class extends Base {
|
|
|
139
176
|
var Compare = class extends Base {
|
|
140
177
|
_tag = "Compare";
|
|
141
178
|
constructor(props) {
|
|
142
|
-
if (!
|
|
179
|
+
if (!isCompareOperator(props.op)) throw new Error(`"${String(props.op)}" is not a compare operator`);
|
|
143
180
|
super({
|
|
144
181
|
op: props.op,
|
|
145
182
|
field: checkPath(props.field),
|
|
@@ -151,10 +188,11 @@ var Compare = class extends Base {
|
|
|
151
188
|
var In = class extends Base {
|
|
152
189
|
_tag = "In";
|
|
153
190
|
constructor(props) {
|
|
191
|
+
const values = checkOperands(props.values);
|
|
154
192
|
super({
|
|
155
193
|
field: checkPath(props.field),
|
|
156
|
-
values
|
|
157
|
-
},
|
|
194
|
+
values
|
|
195
|
+
}, valuesFacts(values));
|
|
158
196
|
}
|
|
159
197
|
};
|
|
160
198
|
/** True when a field is not `null` and not missing. */
|
|
@@ -168,7 +206,8 @@ var Exists = class extends Base {
|
|
|
168
206
|
var Under = class extends Base {
|
|
169
207
|
_tag = "Under";
|
|
170
208
|
constructor(props) {
|
|
171
|
-
|
|
209
|
+
const prefix = checkOperands(props.prefix);
|
|
210
|
+
super({ prefix }, valuesFacts(prefix));
|
|
172
211
|
}
|
|
173
212
|
};
|
|
174
213
|
const checkChildren = (conditions) => {
|
|
@@ -212,6 +251,7 @@ var Predicate = class extends Base {
|
|
|
212
251
|
run: props.run
|
|
213
252
|
}, {
|
|
214
253
|
size: 1,
|
|
254
|
+
weight: 1,
|
|
215
255
|
depth: 1,
|
|
216
256
|
opaque: true
|
|
217
257
|
});
|
|
@@ -272,6 +312,6 @@ const toNode = (u) => {
|
|
|
272
312
|
};
|
|
273
313
|
const always = new True();
|
|
274
314
|
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 };
|
|
315
|
+
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
316
|
|
|
277
317
|
//# sourceMappingURL=nodes.js.map
|