@smthrs/plan 0.0.0-stage → 1.0.0-rc.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +189 -0
- package/LICENSE +21 -0
- package/README.md +230 -2
- package/THIRD_PARTY_NOTICES.md +48 -0
- package/dist/cjs/CachePolicy.d.ts +131 -0
- package/dist/cjs/CachePolicy.d.ts.map +1 -0
- package/dist/cjs/CachePolicy.js +50 -0
- package/dist/cjs/CachePolicy.js.map +7 -0
- package/dist/cjs/Effects.d.ts +258 -0
- package/dist/cjs/Effects.d.ts.map +1 -0
- package/dist/cjs/Effects.js +76 -0
- package/dist/cjs/Effects.js.map +7 -0
- package/dist/cjs/FileSet.d.ts +366 -0
- package/dist/cjs/FileSet.d.ts.map +1 -0
- package/dist/cjs/FileSet.js +196 -0
- package/dist/cjs/FileSet.js.map +7 -0
- package/dist/cjs/GraphBuildError.d.ts +120 -0
- package/dist/cjs/GraphBuildError.d.ts.map +1 -0
- package/dist/cjs/GraphBuildError.js +71 -0
- package/dist/cjs/GraphBuildError.js.map +7 -0
- package/dist/cjs/KeyMaterial.d.ts +107 -0
- package/dist/cjs/KeyMaterial.d.ts.map +1 -0
- package/dist/cjs/KeyMaterial.js +64 -0
- package/dist/cjs/KeyMaterial.js.map +7 -0
- package/dist/cjs/Node.d.ts +685 -0
- package/dist/cjs/Node.d.ts.map +1 -0
- package/dist/cjs/Node.js +230 -0
- package/dist/cjs/Node.js.map +7 -0
- package/dist/cjs/Placement.d.ts +117 -0
- package/dist/cjs/Placement.d.ts.map +1 -0
- package/dist/cjs/Placement.js +46 -0
- package/dist/cjs/Placement.js.map +7 -0
- package/dist/cjs/Plan.d.ts +489 -0
- package/dist/cjs/Plan.d.ts.map +1 -0
- package/dist/cjs/Plan.js +511 -0
- package/dist/cjs/Plan.js.map +7 -0
- package/dist/cjs/PlanDiff.d.ts +77 -0
- package/dist/cjs/PlanDiff.d.ts.map +1 -0
- package/dist/cjs/PlanDiff.js +149 -0
- package/dist/cjs/PlanDiff.js.map +7 -0
- package/dist/cjs/Planned.d.ts +121 -0
- package/dist/cjs/Planned.d.ts.map +1 -0
- package/dist/cjs/Planned.js +72 -0
- package/dist/cjs/Planned.js.map +7 -0
- package/dist/cjs/Repetition.d.ts +31 -0
- package/dist/cjs/Repetition.d.ts.map +1 -0
- package/dist/cjs/Repetition.js +36 -0
- package/dist/cjs/Repetition.js.map +7 -0
- package/dist/cjs/Scheduling.d.ts +89 -0
- package/dist/cjs/Scheduling.d.ts.map +1 -0
- package/dist/cjs/Scheduling.js +76 -0
- package/dist/cjs/Scheduling.js.map +7 -0
- package/dist/cjs/StepKey.d.ts +354 -0
- package/dist/cjs/StepKey.d.ts.map +1 -0
- package/dist/cjs/StepKey.js +313 -0
- package/dist/cjs/StepKey.js.map +7 -0
- package/dist/cjs/index.d.ts +91 -0
- package/dist/cjs/index.d.ts.map +1 -0
- package/dist/cjs/index.js +59 -0
- package/dist/cjs/index.js.map +7 -0
- package/dist/cjs/internal/ConflictAnnotation.d.ts +59 -0
- package/dist/cjs/internal/ConflictAnnotation.d.ts.map +1 -0
- package/dist/cjs/internal/ConflictAnnotation.js +247 -0
- package/dist/cjs/internal/ConflictAnnotation.js.map +7 -0
- package/dist/cjs/internal/EffectCandidates.d.ts +19 -0
- package/dist/cjs/internal/EffectCandidates.d.ts.map +1 -0
- package/dist/cjs/internal/EffectCandidates.js +92 -0
- package/dist/cjs/internal/EffectCandidates.js.map +7 -0
- package/dist/cjs/internal/JsonMirror.d.ts +34 -0
- package/dist/cjs/internal/JsonMirror.d.ts.map +1 -0
- package/dist/cjs/internal/JsonMirror.js +195 -0
- package/dist/cjs/internal/JsonMirror.js.map +7 -0
- package/dist/cjs/internal/SchemaIdentity.d.ts +140 -0
- package/dist/cjs/internal/SchemaIdentity.d.ts.map +1 -0
- package/dist/cjs/internal/SchemaIdentity.js +718 -0
- package/dist/cjs/internal/SchemaIdentity.js.map +7 -0
- package/dist/cjs/internal/effects.d.ts +245 -0
- package/dist/cjs/internal/effects.d.ts.map +1 -0
- package/dist/cjs/internal/effects.js +290 -0
- package/dist/cjs/internal/effects.js.map +7 -0
- package/dist/cjs/internal/node.d.ts +526 -0
- package/dist/cjs/internal/node.d.ts.map +1 -0
- package/dist/cjs/internal/node.js +313 -0
- package/dist/cjs/internal/node.js.map +7 -0
- package/dist/cjs/package.json +1 -0
- package/dist/cjs/test/PlanFixtures.d.ts +127 -0
- package/dist/cjs/test/PlanFixtures.d.ts.map +1 -0
- package/dist/cjs/test/PlanFixtures.js +59 -0
- package/dist/cjs/test/PlanFixtures.js.map +7 -0
- package/dist/esm/CachePolicy.d.ts +131 -0
- package/dist/esm/CachePolicy.d.ts.map +1 -0
- package/dist/esm/CachePolicy.js +117 -0
- package/dist/esm/CachePolicy.js.map +1 -0
- package/dist/esm/Effects.d.ts +258 -0
- package/dist/esm/Effects.d.ts.map +1 -0
- package/dist/esm/Effects.js +178 -0
- package/dist/esm/Effects.js.map +1 -0
- package/dist/esm/FileSet.d.ts +366 -0
- package/dist/esm/FileSet.d.ts.map +1 -0
- package/dist/esm/FileSet.js +398 -0
- package/dist/esm/FileSet.js.map +1 -0
- package/dist/esm/GraphBuildError.d.ts +120 -0
- package/dist/esm/GraphBuildError.d.ts.map +1 -0
- package/dist/esm/GraphBuildError.js +145 -0
- package/dist/esm/GraphBuildError.js.map +1 -0
- package/dist/esm/KeyMaterial.d.ts +107 -0
- package/dist/esm/KeyMaterial.d.ts.map +1 -0
- package/dist/esm/KeyMaterial.js +92 -0
- package/dist/esm/KeyMaterial.js.map +1 -0
- package/dist/esm/Node.d.ts +685 -0
- package/dist/esm/Node.d.ts.map +1 -0
- package/dist/esm/Node.js +591 -0
- package/dist/esm/Node.js.map +1 -0
- package/dist/esm/Placement.d.ts +117 -0
- package/dist/esm/Placement.d.ts.map +1 -0
- package/dist/esm/Placement.js +65 -0
- package/dist/esm/Placement.js.map +1 -0
- package/dist/esm/Plan.d.ts +489 -0
- package/dist/esm/Plan.d.ts.map +1 -0
- package/dist/esm/Plan.js +718 -0
- package/dist/esm/Plan.js.map +1 -0
- package/dist/esm/PlanDiff.d.ts +77 -0
- package/dist/esm/PlanDiff.d.ts.map +1 -0
- package/dist/esm/PlanDiff.js +205 -0
- package/dist/esm/PlanDiff.js.map +1 -0
- package/dist/esm/Planned.d.ts +121 -0
- package/dist/esm/Planned.d.ts.map +1 -0
- package/dist/esm/Planned.js +147 -0
- package/dist/esm/Planned.js.map +1 -0
- package/dist/esm/Repetition.d.ts +31 -0
- package/dist/esm/Repetition.d.ts.map +1 -0
- package/dist/esm/Repetition.js +24 -0
- package/dist/esm/Repetition.js.map +1 -0
- package/dist/esm/Scheduling.d.ts +89 -0
- package/dist/esm/Scheduling.d.ts.map +1 -0
- package/dist/esm/Scheduling.js +82 -0
- package/dist/esm/Scheduling.js.map +1 -0
- package/dist/esm/StepKey.d.ts +354 -0
- package/dist/esm/StepKey.d.ts.map +1 -0
- package/dist/esm/StepKey.js +503 -0
- package/dist/esm/StepKey.js.map +1 -0
- package/dist/esm/index.d.ts +91 -0
- package/dist/esm/index.d.ts.map +1 -0
- package/dist/esm/index.js +91 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/internal/ConflictAnnotation.d.ts +59 -0
- package/dist/esm/internal/ConflictAnnotation.d.ts.map +1 -0
- package/dist/esm/internal/ConflictAnnotation.js +332 -0
- package/dist/esm/internal/ConflictAnnotation.js.map +1 -0
- package/dist/esm/internal/EffectCandidates.d.ts +19 -0
- package/dist/esm/internal/EffectCandidates.d.ts.map +1 -0
- package/dist/esm/internal/EffectCandidates.js +86 -0
- package/dist/esm/internal/EffectCandidates.js.map +1 -0
- package/dist/esm/internal/JsonMirror.d.ts +34 -0
- package/dist/esm/internal/JsonMirror.d.ts.map +1 -0
- package/dist/esm/internal/JsonMirror.js +204 -0
- package/dist/esm/internal/JsonMirror.js.map +1 -0
- package/dist/esm/internal/SchemaIdentity.d.ts +140 -0
- package/dist/esm/internal/SchemaIdentity.d.ts.map +1 -0
- package/dist/esm/internal/SchemaIdentity.js +1002 -0
- package/dist/esm/internal/SchemaIdentity.js.map +1 -0
- package/dist/esm/internal/effects.d.ts +245 -0
- package/dist/esm/internal/effects.d.ts.map +1 -0
- package/dist/esm/internal/effects.js +459 -0
- package/dist/esm/internal/effects.js.map +1 -0
- package/dist/esm/internal/node.d.ts +526 -0
- package/dist/esm/internal/node.d.ts.map +1 -0
- package/dist/esm/internal/node.js +565 -0
- package/dist/esm/internal/node.js.map +1 -0
- package/dist/esm/test/PlanFixtures.d.ts +127 -0
- package/dist/esm/test/PlanFixtures.d.ts.map +1 -0
- package/dist/esm/test/PlanFixtures.js +60 -0
- package/dist/esm/test/PlanFixtures.js.map +1 -0
- package/docs/README.md +167 -0
- package/docs/api.md +1485 -0
- package/docs/concepts/authoring-ast.md +204 -0
- package/docs/concepts/effects-and-conflicts.md +135 -0
- package/docs/concepts/plan-value.md +168 -0
- package/docs/concepts/step-keys.md +179 -0
- package/docs/guides/author-a-node-graph.md +182 -0
- package/docs/guides/compile-a-plan.md +146 -0
- package/docs/guides/declare-file-effects.md +143 -0
- package/docs/guides/diff-two-plans.md +310 -0
- package/docs/installation.md +75 -0
- package/docs/quickstart.md +128 -0
- package/docs/testing.md +73 -0
- package/docs/troubleshooting.md +314 -0
- package/package.json +255 -3
- package/src/CachePolicy.ts +143 -0
- package/src/Effects.ts +302 -0
- package/src/FileSet.ts +493 -0
- package/src/GraphBuildError.ts +156 -0
- package/src/KeyMaterial.ts +111 -0
- package/src/Node.ts +974 -0
- package/src/Placement.ts +99 -0
- package/src/Plan.ts +911 -0
- package/src/PlanDiff.ts +244 -0
- package/src/Planned.ts +208 -0
- package/src/Repetition.ts +33 -0
- package/src/Scheduling.ts +154 -0
- package/src/StepKey.ts +736 -0
- package/src/index.ts +103 -0
- package/src/internal/ConflictAnnotation.ts +374 -0
- package/src/internal/EffectCandidates.ts +89 -0
- package/src/internal/JsonMirror.ts +255 -0
- package/src/internal/SchemaIdentity.ts +1096 -0
- package/src/internal/effects.ts +543 -0
- package/src/internal/node.ts +859 -0
- package/src/test/PlanFixtures.ts +76 -0
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
var CachePolicy_exports = {};
|
|
30
|
+
__export(CachePolicy_exports, {
|
|
31
|
+
CachePolicy: () => CachePolicy,
|
|
32
|
+
CachePolicyAnnotation: () => CachePolicyAnnotation,
|
|
33
|
+
CacheScope: () => CacheScope,
|
|
34
|
+
annotate: () => annotate,
|
|
35
|
+
cachePolicyOf: () => cachePolicyOf
|
|
36
|
+
});
|
|
37
|
+
module.exports = __toCommonJS(CachePolicy_exports);
|
|
38
|
+
var Context = __toESM(require("effect/Context"), 1);
|
|
39
|
+
var Option = __toESM(require("effect/Option"), 1);
|
|
40
|
+
var Schema = __toESM(require("effect/Schema"), 1);
|
|
41
|
+
const CacheScope = Schema.Literals(["run", "flow", "shared"]);
|
|
42
|
+
const PositiveMillis = Schema.Int.check(Schema.isGreaterThan(0));
|
|
43
|
+
const CachePolicy = Schema.Struct({
|
|
44
|
+
ttlMs: Schema.optionalKey(PositiveMillis),
|
|
45
|
+
scope: Schema.optionalKey(CacheScope)
|
|
46
|
+
});
|
|
47
|
+
const CachePolicyAnnotation = Context.Service("@smthrs/flow/Action/CachePolicy");
|
|
48
|
+
const cachePolicyOf = (annotations) => Option.getOrUndefined(Context.getOption(annotations, CachePolicyAnnotation));
|
|
49
|
+
const annotate = (declaration, policy) => declaration.annotate(CachePolicyAnnotation, policy);
|
|
50
|
+
//# sourceMappingURL=CachePolicy.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/CachePolicy.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * The caller-declared cache policy: how far a recorded sealed result may\n * travel, and how long it stays servable.\n *\n * This is the ONE cache-policy model. `@smthrs/flow` publishes it as\n * `CacheEnvironment.CachePolicy` and the engine reads it off a dispatched\n * action; `@smthrs/patterns` declares it over a flow as `WithCache.Policy`. It\n * used to be two declarations in those two packages, tied together by nothing\n * but a re-typed identifier string, so a field added on one side was invisible\n * to the other. It lives here because `@smthrs/plan` is the package both\n * already depend on.\n *\n * The annotation key still reads `\"@smthrs/flow/Action/CachePolicy\"`.\n * `@smthrs/engine-store`'s `ActionPersistence` reads the policy off stored and\n * dispatched actions by that identifier, so retagging it would make every\n * policy already written invisible at dispatch. The identifier is a wire\n * value, not a location.\n *\n * @since 1.0.0-rc.0\n */\n\nimport * as Context from \"effect/Context\"\nimport * as Option from \"effect/Option\"\nimport * as Schema from \"effect/Schema\"\n\n/**\n * How far a recorded sealed result may travel.\n *\n * `shared` is the content-addressed default: the key names the inputs and the\n * environment, so any run on any host that would have produced the same bytes\n * may reuse the row. `run` and `flow` narrow that on purpose \u2014 a step whose\n * result is only meaningful inside one execution, or inside one flow, folds\n * that identity into its key so a sibling never reads it.\n *\n * The old scope vocabulary was `run | workflow | global`; `flow` and `shared`\n * are the same three levels named after the current concepts.\n *\n * @category models\n * @since 1.0.0-rc.0\n */\nexport const CacheScope = Schema.Literals([\"run\", \"flow\", \"shared\"])\n\n/**\n * The value form of {@link CacheScope}.\n *\n * @category models\n * @since 1.0.0-rc.0\n */\nexport type CacheScope = typeof CacheScope.Type\n\n/**\n * A positive whole number of milliseconds.\n *\n * @private\n * @since 1.0.0-rc.0\n */\nconst PositiveMillis = Schema.Int.check(Schema.isGreaterThan(0))\n\n/**\n * The caller's declaration about the decay and the reach of a sealed result.\n *\n * `ttlMs` bounds the age of a row the engine may serve: past it the dispatch\n * executes again and journals `cache-expired`, so the refusal is durable\n * evidence a replay reads rather than a fresh clock reading. `scope` decides\n * what the key names besides the inputs.\n *\n * Both fields are optional and both defaults are the pre-policy behavior: no\n * age bound, and the reach the composition's cache environment already\n * granted.\n *\n * @category schemas\n * @since 1.0.0-rc.0\n */\nexport const CachePolicy = Schema.Struct({\n ttlMs: Schema.optionalKey(PositiveMillis),\n scope: Schema.optionalKey(CacheScope)\n})\n\n/**\n * The value form of {@link CachePolicy}.\n *\n * @category models\n * @since 1.0.0-rc.0\n */\nexport type CachePolicy = typeof CachePolicy.Type\n\n/**\n * Annotation key carrying a declaration's {@link CachePolicy}.\n *\n * It is an annotation, not a field on the declaration, for the same reason\n * placement and effects are: the policy is data that travels with the\n * declaration and is read by whoever executes it, and adding it changes no\n * existing call site.\n *\n * @category annotations\n * @since 1.0.0-rc.0\n */\nexport const CachePolicyAnnotation = Context.Service<CachePolicy>(\"@smthrs/flow/Action/CachePolicy\")\n\n/**\n * Reads the cache policy an annotation bag carries, or `undefined` when it\n * carries none.\n *\n * @category getters\n * @since 1.0.0-rc.0\n */\nexport const cachePolicyOf = (annotations: Context.Context<never>): CachePolicy | undefined =>\n Option.getOrUndefined(Context.getOption(annotations, CachePolicyAnnotation))\n\n/**\n * Attaches a cache policy to a declaration that can carry annotations.\n *\n * The declaration is not mutated: `annotate` answers a new one carrying the\n * policy, which is what a plan captures. It is written against the `annotate`\n * method rather than against an action or a flow type so the one declaration\n * serves both, which is what `@smthrs/flow` publishes as\n * `CacheEnvironment.withCache`.\n *\n * @example\n * ```ts\n * import { CachePolicy } from \"@smthrs/plan\"\n * import { Action } from \"@smthrs/flow\"\n * import * as Effect from \"effect/Effect\"\n * import * as Schema from \"effect/Schema\"\n *\n * const compile = CachePolicy.annotate(\n * Action.make({\n * name: \"build/compile\",\n * success: Schema.String,\n * tier: \"sealed\",\n * execute: Effect.succeed(\"dist/server.js\")\n * }),\n * { ttlMs: 60_000, scope: \"shared\" }\n * )\n * ```\n *\n * @category combinators\n * @since 1.0.0-rc.0\n */\nexport const annotate = <A extends { annotate: (key: typeof CachePolicyAnnotation, value: CachePolicy) => A }>(\n declaration: A,\n policy: CachePolicy\n): A => declaration.annotate(CachePolicyAnnotation, policy)\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAqBA,cAAyB;AACzB,aAAwB;AACxB,aAAwB;AAiBjB,MAAM,aAAa,OAAO,SAAS,CAAC,OAAO,QAAQ,QAAQ,CAAC;AAgBnE,MAAM,iBAAiB,OAAO,IAAI,MAAM,OAAO,cAAc,CAAC,CAAC;AAiBxD,MAAM,cAAc,OAAO,OAAO;AAAA,EACvC,OAAO,OAAO,YAAY,cAAc;AAAA,EACxC,OAAO,OAAO,YAAY,UAAU;AACtC,CAAC;AAqBM,MAAM,wBAAwB,QAAQ,QAAqB,iCAAiC;AAS5F,MAAM,gBAAgB,CAAC,gBAC5B,OAAO,eAAe,QAAQ,UAAU,aAAa,qBAAqB,CAAC;AAgCtE,MAAM,WAAW,CACtB,aACA,WACM,YAAY,SAAS,uBAAuB,MAAM;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure effect declarations used to describe flow read and write envelopes.
|
|
3
|
+
*
|
|
4
|
+
* This is the ONE effect-envelope model. `@smthrs/flow` enforces it while it
|
|
5
|
+
* builds a graph, `@smthrs/core` re-exports it, and `@smthrs/patterns` reads it
|
|
6
|
+
* to intersect a decorator's declaration with the flow it wraps. It lives here
|
|
7
|
+
* because `@smthrs/plan` is the lowest package all three depend on, beside the
|
|
8
|
+
* `tier` and `onConflict` vocabularies a plan already speaks.
|
|
9
|
+
*
|
|
10
|
+
* Two layers: the declaration API, which a flow author and a catalog use, and
|
|
11
|
+
* the prepared matching API below it, which a graph builder uses to check one
|
|
12
|
+
* envelope against many steps without re-reading the envelope each time.
|
|
13
|
+
*
|
|
14
|
+
* Governing contract: `packages/smithers/flows/plan/docs/api.md`, published as
|
|
15
|
+
* https://smithers.sh/docs/reference/api/plan.
|
|
16
|
+
*
|
|
17
|
+
* @since 0.0.0
|
|
18
|
+
*/
|
|
19
|
+
import * as Context from "effect/Context";
|
|
20
|
+
import * as Schema from "effect/Schema";
|
|
21
|
+
/**
|
|
22
|
+
* How reversible the work beneath a declaration is.
|
|
23
|
+
*
|
|
24
|
+
* This is the ONE tier vocabulary. `KeyMaterial.kind` is this schema, and so
|
|
25
|
+
* is `@smthrs/flow`'s `Action.Tier`: an action's durability and a declared
|
|
26
|
+
* envelope's ceiling are the same three words, and a fourth spelling of them
|
|
27
|
+
* in one of the three places would fork identity silently.
|
|
28
|
+
*
|
|
29
|
+
* @category schemas
|
|
30
|
+
* @since 1.0.0-rc.0
|
|
31
|
+
*/
|
|
32
|
+
export declare const Tier: Schema.Literals<readonly ["sealed", "compensable", "irreversible"]>;
|
|
33
|
+
/**
|
|
34
|
+
* The value form of {@link Tier}.
|
|
35
|
+
*
|
|
36
|
+
* @category models
|
|
37
|
+
* @since 1.0.0-rc.0
|
|
38
|
+
*/
|
|
39
|
+
export type Tier = typeof Tier.Type;
|
|
40
|
+
/**
|
|
41
|
+
* How hermetic the work beneath a declaration is.
|
|
42
|
+
*
|
|
43
|
+
* This is the ONE mode vocabulary: the two words were written out in
|
|
44
|
+
* `Declaration`, in `MakeOptions`, and twice more inside the matcher.
|
|
45
|
+
*
|
|
46
|
+
* @category schemas
|
|
47
|
+
* @since 1.0.0-rc.0
|
|
48
|
+
*/
|
|
49
|
+
export declare const Mode: Schema.Literals<readonly ["hermetic", "expected"]>;
|
|
50
|
+
/**
|
|
51
|
+
* The value form of {@link Mode}.
|
|
52
|
+
*
|
|
53
|
+
* @category models
|
|
54
|
+
* @since 1.0.0-rc.0
|
|
55
|
+
*/
|
|
56
|
+
export type Mode = typeof Mode.Type;
|
|
57
|
+
/**
|
|
58
|
+
* What a plan does when two nodes write the same path.
|
|
59
|
+
*
|
|
60
|
+
* This is the ONE conflict vocabulary: `Declaration.onConflict` declares it and
|
|
61
|
+
* `Plan.PairStrategy` is this same schema, resolved per pair by
|
|
62
|
+
* `Plan.compile`.
|
|
63
|
+
*
|
|
64
|
+
* @category schemas
|
|
65
|
+
* @since 1.0.0-rc.0
|
|
66
|
+
*/
|
|
67
|
+
export declare const ConflictStrategy: Schema.Literals<readonly ["serialize", "lane", "fail"]>;
|
|
68
|
+
/**
|
|
69
|
+
* The value form of {@link ConflictStrategy}.
|
|
70
|
+
*
|
|
71
|
+
* @category models
|
|
72
|
+
* @since 1.0.0-rc.0
|
|
73
|
+
*/
|
|
74
|
+
export type ConflictStrategy = typeof ConflictStrategy.Type;
|
|
75
|
+
/**
|
|
76
|
+
* The annotation key a flow's declared effect ENVELOPE is carried under.
|
|
77
|
+
*
|
|
78
|
+
* One key, here, because two graph builders read it: `@smthrs/flow`'s
|
|
79
|
+
* `Graph.build` enforces the envelope it names, and `@smthrs/core` re-exports
|
|
80
|
+
* this key as `Annotations.Effects`. While they were separate keys a flow
|
|
81
|
+
* annotated for one builder was invisible to the other.
|
|
82
|
+
*
|
|
83
|
+
* It is a `Context` key, not hashed material: annotating a flow with an
|
|
84
|
+
* envelope changes what a build ADMITS, and the declaration reaches identity
|
|
85
|
+
* only through `KeyMaterial.kind`.
|
|
86
|
+
*
|
|
87
|
+
* @category annotations
|
|
88
|
+
* @since 1.0.0-rc.0
|
|
89
|
+
*/
|
|
90
|
+
export declare const Envelope: Context.Service<Declaration, Declaration>;
|
|
91
|
+
/**
|
|
92
|
+
* The prepared matching API: what a graph builder needs to check one envelope
|
|
93
|
+
* against every step it encloses, and to find the write overlaps between two
|
|
94
|
+
* declarations, at the cost the public functions above pay once rather than
|
|
95
|
+
* once per step.
|
|
96
|
+
*
|
|
97
|
+
* {@link prepareEnvelope} reads an envelope once into the form
|
|
98
|
+
* {@link narrowPrepared} answers from, which is what makes a wide envelope cost
|
|
99
|
+
* its size per build rather than per node. {@link indexPaths},
|
|
100
|
+
* {@link rankPaths} and {@link overlapRanks} are the same decomposition for
|
|
101
|
+
* write overlap, which {@link overlaps} wraps for the pairwise case.
|
|
102
|
+
* {@link boundedEffects} snapshots a declaration into builder-owned data,
|
|
103
|
+
* refusing through the caller's own error before the copy grows past its limit,
|
|
104
|
+
* and {@link maximumPathLength} and {@link maximumGlobs} are the per-path bounds
|
|
105
|
+
* that refusal enforces.
|
|
106
|
+
*
|
|
107
|
+
* @category matching
|
|
108
|
+
* @since 1.0.0-rc.0
|
|
109
|
+
*/
|
|
110
|
+
export type { PathIndex, PreparedEnvelope, Ranked } from "./internal/effects.ts";
|
|
111
|
+
/**
|
|
112
|
+
* The prepared matching API. See the type re-exports above for what each member
|
|
113
|
+
* is for.
|
|
114
|
+
*
|
|
115
|
+
* @category matching
|
|
116
|
+
* @since 1.0.0-rc.0
|
|
117
|
+
*/
|
|
118
|
+
export { boundedEffects, indexPaths, maximumGlobs, maximumPathLength, narrowPrepared, overlapRanks, prepareEnvelope, rankPaths } from "./internal/effects.ts";
|
|
119
|
+
/**
|
|
120
|
+
* A normalized description of the resources a flow or step may read and
|
|
121
|
+
* write. Build one with {@link make}.
|
|
122
|
+
*
|
|
123
|
+
* @category models
|
|
124
|
+
* @since 0.0.0
|
|
125
|
+
*/
|
|
126
|
+
export interface Declaration {
|
|
127
|
+
/** Readable paths or envelope patterns, sorted and duplicate-free. */
|
|
128
|
+
readonly reads: ReadonlyArray<string>;
|
|
129
|
+
/** Writable paths or envelope patterns, sorted and duplicate-free. */
|
|
130
|
+
readonly writes: ReadonlyArray<string>;
|
|
131
|
+
/** `hermetic` or `expected` enforcement. */
|
|
132
|
+
readonly mode: Mode;
|
|
133
|
+
/** What a plan does when another node writes an overlapping path. */
|
|
134
|
+
readonly onConflict: ConflictStrategy;
|
|
135
|
+
/** The effect tier. Absent means `sealed`. */
|
|
136
|
+
readonly tier?: Tier | undefined;
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Input accepted by {@link make}. Iterables are normalized into sorted,
|
|
140
|
+
* duplicate-free arrays so declarations are deterministic key material.
|
|
141
|
+
* Envelope entries and declared paths must already be path-normalized: no
|
|
142
|
+
* separator or dot-segment rewriting is performed. A declared path containing
|
|
143
|
+
* a whole `.` or `..` segment is never covered and therefore surfaces from
|
|
144
|
+
* {@link narrow} as an `effect_outside_envelope` diagnostic.
|
|
145
|
+
*
|
|
146
|
+
* @category models
|
|
147
|
+
* @since 0.0.0
|
|
148
|
+
*/
|
|
149
|
+
export interface MakeOptions {
|
|
150
|
+
readonly reads: Iterable<string>;
|
|
151
|
+
readonly writes: Iterable<string>;
|
|
152
|
+
readonly mode: Mode;
|
|
153
|
+
readonly onConflict: ConflictStrategy;
|
|
154
|
+
readonly tier?: Tier | undefined;
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* A result of checking that a step declaration narrows a flow envelope.
|
|
158
|
+
*
|
|
159
|
+
* On failure, `code` names the first rule broken, checked in this order:
|
|
160
|
+
* `effect_outside_envelope` (with the uncovered read and write paths, sorted),
|
|
161
|
+
* `effect_mode_widening`, then `effect_tier_widening` (both with empty
|
|
162
|
+
* `paths`).
|
|
163
|
+
*
|
|
164
|
+
* @category models
|
|
165
|
+
* @since 0.0.0
|
|
166
|
+
*/
|
|
167
|
+
export type NarrowResult = {
|
|
168
|
+
readonly ok: true;
|
|
169
|
+
} | {
|
|
170
|
+
readonly ok: false;
|
|
171
|
+
readonly code: "effect_outside_envelope" | "effect_mode_widening" | "effect_tier_widening";
|
|
172
|
+
readonly paths: ReadonlyArray<string>;
|
|
173
|
+
};
|
|
174
|
+
/**
|
|
175
|
+
* Constructs a deterministic effect declaration: `reads` and `writes` are
|
|
176
|
+
* collected, deduplicated, and sorted; an absent `tier` is omitted. Paths are
|
|
177
|
+
* not validated or rewritten.
|
|
178
|
+
*
|
|
179
|
+
* @param input - The paths, mode, conflict strategy, and optional tier.
|
|
180
|
+
* @returns The normalized declaration.
|
|
181
|
+
* @category constructors
|
|
182
|
+
* @since 0.0.0
|
|
183
|
+
*/
|
|
184
|
+
export declare const make: (input: MakeOptions) => Declaration;
|
|
185
|
+
/**
|
|
186
|
+
* Checks whether `path` is covered by an envelope entry.
|
|
187
|
+
*
|
|
188
|
+
* The grammar is exhaustive: an exact path matches itself; `*` and `**` match
|
|
189
|
+
* everything; `prefix*` matches by string prefix; and `prefix/**` matches
|
|
190
|
+
* `prefix/` and everything below it, but not bare `prefix`. This is
|
|
191
|
+
* intentionally not full minimatch syntax. Envelope entries and declared paths
|
|
192
|
+
* must be normalized. A path containing a whole `.` or `..` segment is never
|
|
193
|
+
* covered, so {@link narrow} reports it as `effect_outside_envelope` rather
|
|
194
|
+
* than silently accepting an escape.
|
|
195
|
+
*
|
|
196
|
+
* @param envelope - One envelope entry.
|
|
197
|
+
* @param path - One declared path.
|
|
198
|
+
* @returns `true` when the entry covers the path.
|
|
199
|
+
* @category predicates
|
|
200
|
+
* @since 0.0.0
|
|
201
|
+
*/
|
|
202
|
+
export declare const covers: (envelope: string, path: string) => boolean;
|
|
203
|
+
/**
|
|
204
|
+
* Verifies that a step declaration stays within an enclosing flow envelope.
|
|
205
|
+
*
|
|
206
|
+
* Read and write paths must be covered independently. A step may tighten
|
|
207
|
+
* `expected` to `hermetic`, but cannot widen `hermetic` to `expected`.
|
|
208
|
+
* Effect tiers narrow from irreversible to compensable to sealed.
|
|
209
|
+
*
|
|
210
|
+
* The envelope's lists are prepared once: exact entries go into a set and
|
|
211
|
+
* covering patterns collapse to their outermost prefixes, sorted, so each step
|
|
212
|
+
* path costs one dot-segment scan, one lookup, and one binary search ending in
|
|
213
|
+
* one prefix comparison, whatever the envelope's width or how many of its
|
|
214
|
+
* patterns nest. A graph build prepares each envelope once for every node it
|
|
215
|
+
* encloses.
|
|
216
|
+
*
|
|
217
|
+
* @param envelope - The flow's declaration.
|
|
218
|
+
* @param step - The step's declaration.
|
|
219
|
+
* @returns `{ ok: true }`, or the first rule the step breaks.
|
|
220
|
+
* @category validation
|
|
221
|
+
* @since 0.0.0
|
|
222
|
+
*/
|
|
223
|
+
export declare const narrow: (envelope: Declaration, step: Declaration) => NarrowResult;
|
|
224
|
+
/**
|
|
225
|
+
* Returns the concrete or narrower write declarations shared by two effect
|
|
226
|
+
* declarations. The result is sorted and duplicate-free.
|
|
227
|
+
*
|
|
228
|
+
* Two declarations of the same literal path always overlap, including a path
|
|
229
|
+
* {@link covers} refuses to match because it carries a `.` or `..` segment.
|
|
230
|
+
* Glob coverage stays strict for those paths, so an unnormalized declaration
|
|
231
|
+
* still escapes no envelope, but two writers naming the same unnormalized path
|
|
232
|
+
* are still detected as writing the same resource.
|
|
233
|
+
*
|
|
234
|
+
* The union of both declarations is indexed once: the distinct paths are
|
|
235
|
+
* sorted, each is scanned once for a dot segment, and each pattern's prefix
|
|
236
|
+
* is located by binary search. Exact paths then match through a merge of two
|
|
237
|
+
* rank lists and each covering pattern enumerates the other declaration's
|
|
238
|
+
* ranks inside its interval, so the cost is linear in the two declarations
|
|
239
|
+
* plus the matches, whatever the paths' lengths or how many patterns nest.
|
|
240
|
+
*
|
|
241
|
+
* @param a - One declaration.
|
|
242
|
+
* @param b - The other declaration.
|
|
243
|
+
* @returns The shared write paths; empty when the writes are disjoint.
|
|
244
|
+
* @category analysis
|
|
245
|
+
* @since 0.0.0
|
|
246
|
+
*/
|
|
247
|
+
export declare const overlaps: (a: Declaration, b: Declaration) => ReadonlyArray<string>;
|
|
248
|
+
/**
|
|
249
|
+
* Returns a sealed, hermetic copy of an effect declaration, normalized by
|
|
250
|
+
* {@link make}. Paths and `onConflict` are kept.
|
|
251
|
+
*
|
|
252
|
+
* @param declaration - The declaration to copy.
|
|
253
|
+
* @returns The copy with `mode: "hermetic"` and `tier: "sealed"`.
|
|
254
|
+
* @category constructors
|
|
255
|
+
* @since 0.0.0
|
|
256
|
+
*/
|
|
257
|
+
export declare const sealed: (declaration: Declaration) => Declaration;
|
|
258
|
+
//# sourceMappingURL=Effects.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Effects.d.ts","sourceRoot":"","sources":["../../src/Effects.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
var Effects_exports = {};
|
|
30
|
+
__export(Effects_exports, {
|
|
31
|
+
ConflictStrategy: () => ConflictStrategy,
|
|
32
|
+
Envelope: () => Envelope,
|
|
33
|
+
Mode: () => Mode,
|
|
34
|
+
Tier: () => Tier,
|
|
35
|
+
boundedEffects: () => import_effects.boundedEffects,
|
|
36
|
+
covers: () => covers,
|
|
37
|
+
indexPaths: () => import_effects.indexPaths,
|
|
38
|
+
make: () => make,
|
|
39
|
+
maximumGlobs: () => import_effects.maximumGlobs,
|
|
40
|
+
maximumPathLength: () => import_effects.maximumPathLength,
|
|
41
|
+
narrow: () => narrow,
|
|
42
|
+
narrowPrepared: () => import_effects.narrowPrepared,
|
|
43
|
+
overlapRanks: () => import_effects.overlapRanks,
|
|
44
|
+
overlaps: () => overlaps,
|
|
45
|
+
prepareEnvelope: () => import_effects.prepareEnvelope,
|
|
46
|
+
rankPaths: () => import_effects.rankPaths,
|
|
47
|
+
sealed: () => sealed
|
|
48
|
+
});
|
|
49
|
+
module.exports = __toCommonJS(Effects_exports);
|
|
50
|
+
var Context = __toESM(require("effect/Context"), 1);
|
|
51
|
+
var Schema = __toESM(require("effect/Schema"), 1);
|
|
52
|
+
var Index = __toESM(require("./internal/effects.js"), 1);
|
|
53
|
+
var import_effects = require("./internal/effects.js");
|
|
54
|
+
const Tier = Schema.Literals(["sealed", "compensable", "irreversible"]);
|
|
55
|
+
const Mode = Schema.Literals(["hermetic", "expected"]);
|
|
56
|
+
const ConflictStrategy = Schema.Literals(["serialize", "lane", "fail"]);
|
|
57
|
+
const Envelope = Context.Service("@smthrs/plan/Effects/Envelope");
|
|
58
|
+
const normalize = (paths) => [...new Set(paths)].sort();
|
|
59
|
+
const make = (input) => ({
|
|
60
|
+
reads: normalize(input.reads),
|
|
61
|
+
writes: normalize(input.writes),
|
|
62
|
+
mode: input.mode,
|
|
63
|
+
onConflict: input.onConflict,
|
|
64
|
+
...input.tier === void 0 ? {} : { tier: input.tier }
|
|
65
|
+
});
|
|
66
|
+
const covers = (envelope, path) => {
|
|
67
|
+
if (Index.hasDotSegment(path)) return false;
|
|
68
|
+
return envelope === path || Index.isGlob(envelope) && path.startsWith(Index.globPrefix(envelope));
|
|
69
|
+
};
|
|
70
|
+
const narrow = (envelope, step) => Index.narrowPrepared(Index.prepareEnvelope(envelope), step);
|
|
71
|
+
const overlaps = (a, b) => {
|
|
72
|
+
const indexed = Index.indexPaths([a.writes, b.writes]);
|
|
73
|
+
return Index.overlapRanks(indexed, Index.rankPaths(indexed, a.writes), Index.rankPaths(indexed, b.writes)).map((rank) => indexed.paths[rank]);
|
|
74
|
+
};
|
|
75
|
+
const sealed = (declaration) => make({ ...declaration, mode: "hermetic", tier: "sealed" });
|
|
76
|
+
//# sourceMappingURL=Effects.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/Effects.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Pure effect declarations used to describe flow read and write envelopes.\n *\n * This is the ONE effect-envelope model. `@smthrs/flow` enforces it while it\n * builds a graph, `@smthrs/core` re-exports it, and `@smthrs/patterns` reads it\n * to intersect a decorator's declaration with the flow it wraps. It lives here\n * because `@smthrs/plan` is the lowest package all three depend on, beside the\n * `tier` and `onConflict` vocabularies a plan already speaks.\n *\n * Two layers: the declaration API, which a flow author and a catalog use, and\n * the prepared matching API below it, which a graph builder uses to check one\n * envelope against many steps without re-reading the envelope each time.\n *\n * Governing contract: `packages/smithers/flows/plan/docs/api.md`, published as\n * https://smithers.sh/docs/reference/api/plan.\n *\n * @since 0.0.0\n */\n\nimport * as Context from \"effect/Context\"\nimport * as Schema from \"effect/Schema\"\nimport * as Index from \"./internal/effects.ts\"\n\n/**\n * How reversible the work beneath a declaration is.\n *\n * This is the ONE tier vocabulary. `KeyMaterial.kind` is this schema, and so\n * is `@smthrs/flow`'s `Action.Tier`: an action's durability and a declared\n * envelope's ceiling are the same three words, and a fourth spelling of them\n * in one of the three places would fork identity silently.\n *\n * @category schemas\n * @since 1.0.0-rc.0\n */\nexport const Tier = Schema.Literals([\"sealed\", \"compensable\", \"irreversible\"])\n\n/**\n * The value form of {@link Tier}.\n *\n * @category models\n * @since 1.0.0-rc.0\n */\nexport type Tier = typeof Tier.Type\n\n/**\n * How hermetic the work beneath a declaration is.\n *\n * This is the ONE mode vocabulary: the two words were written out in\n * `Declaration`, in `MakeOptions`, and twice more inside the matcher.\n *\n * @category schemas\n * @since 1.0.0-rc.0\n */\nexport const Mode = Schema.Literals([\"hermetic\", \"expected\"])\n\n/**\n * The value form of {@link Mode}.\n *\n * @category models\n * @since 1.0.0-rc.0\n */\nexport type Mode = typeof Mode.Type\n\n/**\n * What a plan does when two nodes write the same path.\n *\n * This is the ONE conflict vocabulary: `Declaration.onConflict` declares it and\n * `Plan.PairStrategy` is this same schema, resolved per pair by\n * `Plan.compile`.\n *\n * @category schemas\n * @since 1.0.0-rc.0\n */\nexport const ConflictStrategy = Schema.Literals([\"serialize\", \"lane\", \"fail\"])\n\n/**\n * The value form of {@link ConflictStrategy}.\n *\n * @category models\n * @since 1.0.0-rc.0\n */\nexport type ConflictStrategy = typeof ConflictStrategy.Type\n\n/**\n * The annotation key a flow's declared effect ENVELOPE is carried under.\n *\n * One key, here, because two graph builders read it: `@smthrs/flow`'s\n * `Graph.build` enforces the envelope it names, and `@smthrs/core` re-exports\n * this key as `Annotations.Effects`. While they were separate keys a flow\n * annotated for one builder was invisible to the other.\n *\n * It is a `Context` key, not hashed material: annotating a flow with an\n * envelope changes what a build ADMITS, and the declaration reaches identity\n * only through `KeyMaterial.kind`.\n *\n * @category annotations\n * @since 1.0.0-rc.0\n */\nexport const Envelope = Context.Service<Declaration>(\"@smthrs/plan/Effects/Envelope\")\n\n/**\n * The prepared matching API: what a graph builder needs to check one envelope\n * against every step it encloses, and to find the write overlaps between two\n * declarations, at the cost the public functions above pay once rather than\n * once per step.\n *\n * {@link prepareEnvelope} reads an envelope once into the form\n * {@link narrowPrepared} answers from, which is what makes a wide envelope cost\n * its size per build rather than per node. {@link indexPaths},\n * {@link rankPaths} and {@link overlapRanks} are the same decomposition for\n * write overlap, which {@link overlaps} wraps for the pairwise case.\n * {@link boundedEffects} snapshots a declaration into builder-owned data,\n * refusing through the caller's own error before the copy grows past its limit,\n * and {@link maximumPathLength} and {@link maximumGlobs} are the per-path bounds\n * that refusal enforces.\n *\n * @category matching\n * @since 1.0.0-rc.0\n */\nexport type { PathIndex, PreparedEnvelope, Ranked } from \"./internal/effects.ts\"\n\n/**\n * The prepared matching API. See the type re-exports above for what each member\n * is for.\n *\n * @category matching\n * @since 1.0.0-rc.0\n */\nexport {\n boundedEffects,\n indexPaths,\n maximumGlobs,\n maximumPathLength,\n narrowPrepared,\n overlapRanks,\n prepareEnvelope,\n rankPaths\n} from \"./internal/effects.ts\"\n\n/**\n * A normalized description of the resources a flow or step may read and\n * write. Build one with {@link make}.\n *\n * @category models\n * @since 0.0.0\n */\nexport interface Declaration {\n /** Readable paths or envelope patterns, sorted and duplicate-free. */\n readonly reads: ReadonlyArray<string>\n /** Writable paths or envelope patterns, sorted and duplicate-free. */\n readonly writes: ReadonlyArray<string>\n /** `hermetic` or `expected` enforcement. */\n readonly mode: Mode\n /** What a plan does when another node writes an overlapping path. */\n readonly onConflict: ConflictStrategy\n /** The effect tier. Absent means `sealed`. */\n readonly tier?: Tier | undefined\n}\n\n/**\n * Input accepted by {@link make}. Iterables are normalized into sorted,\n * duplicate-free arrays so declarations are deterministic key material.\n * Envelope entries and declared paths must already be path-normalized: no\n * separator or dot-segment rewriting is performed. A declared path containing\n * a whole `.` or `..` segment is never covered and therefore surfaces from\n * {@link narrow} as an `effect_outside_envelope` diagnostic.\n *\n * @category models\n * @since 0.0.0\n */\nexport interface MakeOptions {\n readonly reads: Iterable<string>\n readonly writes: Iterable<string>\n readonly mode: Mode\n readonly onConflict: ConflictStrategy\n readonly tier?: Tier | undefined\n}\n\n/**\n * A result of checking that a step declaration narrows a flow envelope.\n *\n * On failure, `code` names the first rule broken, checked in this order:\n * `effect_outside_envelope` (with the uncovered read and write paths, sorted),\n * `effect_mode_widening`, then `effect_tier_widening` (both with empty\n * `paths`).\n *\n * @category models\n * @since 0.0.0\n */\nexport type NarrowResult =\n | { readonly ok: true }\n | {\n readonly ok: false\n readonly code: \"effect_outside_envelope\" | \"effect_mode_widening\" | \"effect_tier_widening\"\n readonly paths: ReadonlyArray<string>\n }\n\nconst normalize = (paths: Iterable<string>): ReadonlyArray<string> => [...new Set(paths)].sort()\n\n/**\n * Constructs a deterministic effect declaration: `reads` and `writes` are\n * collected, deduplicated, and sorted; an absent `tier` is omitted. Paths are\n * not validated or rewritten.\n *\n * @param input - The paths, mode, conflict strategy, and optional tier.\n * @returns The normalized declaration.\n * @category constructors\n * @since 0.0.0\n */\nexport const make = (input: MakeOptions): Declaration => ({\n reads: normalize(input.reads),\n writes: normalize(input.writes),\n mode: input.mode,\n onConflict: input.onConflict,\n ...(input.tier === undefined ? {} : { tier: input.tier })\n})\n\n/**\n * Checks whether `path` is covered by an envelope entry.\n *\n * The grammar is exhaustive: an exact path matches itself; `*` and `**` match\n * everything; `prefix*` matches by string prefix; and `prefix/**` matches\n * `prefix/` and everything below it, but not bare `prefix`. This is\n * intentionally not full minimatch syntax. Envelope entries and declared paths\n * must be normalized. A path containing a whole `.` or `..` segment is never\n * covered, so {@link narrow} reports it as `effect_outside_envelope` rather\n * than silently accepting an escape.\n *\n * @param envelope - One envelope entry.\n * @param path - One declared path.\n * @returns `true` when the entry covers the path.\n * @category predicates\n * @since 0.0.0\n */\nexport const covers = (envelope: string, path: string): boolean => {\n if (Index.hasDotSegment(path)) return false\n return envelope === path || (Index.isGlob(envelope) && path.startsWith(Index.globPrefix(envelope)))\n}\n\n/**\n * Verifies that a step declaration stays within an enclosing flow envelope.\n *\n * Read and write paths must be covered independently. A step may tighten\n * `expected` to `hermetic`, but cannot widen `hermetic` to `expected`.\n * Effect tiers narrow from irreversible to compensable to sealed.\n *\n * The envelope's lists are prepared once: exact entries go into a set and\n * covering patterns collapse to their outermost prefixes, sorted, so each step\n * path costs one dot-segment scan, one lookup, and one binary search ending in\n * one prefix comparison, whatever the envelope's width or how many of its\n * patterns nest. A graph build prepares each envelope once for every node it\n * encloses.\n *\n * @param envelope - The flow's declaration.\n * @param step - The step's declaration.\n * @returns `{ ok: true }`, or the first rule the step breaks.\n * @category validation\n * @since 0.0.0\n */\nexport const narrow = (envelope: Declaration, step: Declaration): NarrowResult =>\n Index.narrowPrepared(Index.prepareEnvelope(envelope), step)\n\n/**\n * Returns the concrete or narrower write declarations shared by two effect\n * declarations. The result is sorted and duplicate-free.\n *\n * Two declarations of the same literal path always overlap, including a path\n * {@link covers} refuses to match because it carries a `.` or `..` segment.\n * Glob coverage stays strict for those paths, so an unnormalized declaration\n * still escapes no envelope, but two writers naming the same unnormalized path\n * are still detected as writing the same resource.\n *\n * The union of both declarations is indexed once: the distinct paths are\n * sorted, each is scanned once for a dot segment, and each pattern's prefix\n * is located by binary search. Exact paths then match through a merge of two\n * rank lists and each covering pattern enumerates the other declaration's\n * ranks inside its interval, so the cost is linear in the two declarations\n * plus the matches, whatever the paths' lengths or how many patterns nest.\n *\n * @param a - One declaration.\n * @param b - The other declaration.\n * @returns The shared write paths; empty when the writes are disjoint.\n * @category analysis\n * @since 0.0.0\n */\nexport const overlaps = (a: Declaration, b: Declaration): ReadonlyArray<string> => {\n const indexed = Index.indexPaths([a.writes, b.writes])\n return Index.overlapRanks(indexed, Index.rankPaths(indexed, a.writes), Index.rankPaths(indexed, b.writes))\n .map((rank) => indexed.paths[rank]!)\n}\n\n/**\n * Returns a sealed, hermetic copy of an effect declaration, normalized by\n * {@link make}. Paths and `onConflict` are kept.\n *\n * @param declaration - The declaration to copy.\n * @returns The copy with `mode: \"hermetic\"` and `tier: \"sealed\"`.\n * @category constructors\n * @since 0.0.0\n */\nexport const sealed = (declaration: Declaration): Declaration =>\n make({ ...declaration, mode: \"hermetic\", tier: \"sealed\" })\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAmBA,cAAyB;AACzB,aAAwB;AACxB,YAAuB;AA2GvB,qBASO;AAvGA,MAAM,OAAO,OAAO,SAAS,CAAC,UAAU,eAAe,cAAc,CAAC;AAmBtE,MAAM,OAAO,OAAO,SAAS,CAAC,YAAY,UAAU,CAAC;AAoBrD,MAAM,mBAAmB,OAAO,SAAS,CAAC,aAAa,QAAQ,MAAM,CAAC;AAyBtE,MAAM,WAAW,QAAQ,QAAqB,+BAA+B;AAmGpF,MAAM,YAAY,CAAC,UAAmD,CAAC,GAAG,IAAI,IAAI,KAAK,CAAC,EAAE,KAAK;AAYxF,MAAM,OAAO,CAAC,WAAqC;AAAA,EACxD,OAAO,UAAU,MAAM,KAAK;AAAA,EAC5B,QAAQ,UAAU,MAAM,MAAM;AAAA,EAC9B,MAAM,MAAM;AAAA,EACZ,YAAY,MAAM;AAAA,EAClB,GAAI,MAAM,SAAS,SAAY,CAAC,IAAI,EAAE,MAAM,MAAM,KAAK;AACzD;AAmBO,MAAM,SAAS,CAAC,UAAkB,SAA0B;AACjE,MAAI,MAAM,cAAc,IAAI,EAAG,QAAO;AACtC,SAAO,aAAa,QAAS,MAAM,OAAO,QAAQ,KAAK,KAAK,WAAW,MAAM,WAAW,QAAQ,CAAC;AACnG;AAsBO,MAAM,SAAS,CAAC,UAAuB,SAC5C,MAAM,eAAe,MAAM,gBAAgB,QAAQ,GAAG,IAAI;AAyBrD,MAAM,WAAW,CAAC,GAAgB,MAA0C;AACjF,QAAM,UAAU,MAAM,WAAW,CAAC,EAAE,QAAQ,EAAE,MAAM,CAAC;AACrD,SAAO,MAAM,aAAa,SAAS,MAAM,UAAU,SAAS,EAAE,MAAM,GAAG,MAAM,UAAU,SAAS,EAAE,MAAM,CAAC,EACtG,IAAI,CAAC,SAAS,QAAQ,MAAM,IAAI,CAAE;AACvC;AAWO,MAAM,SAAS,CAAC,gBACrB,KAAK,EAAE,GAAG,aAAa,MAAM,YAAY,MAAM,SAAS,CAAC;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|