@scfloworg/actions 0.0.0-stage → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +60 -2
- package/dist/batch.d.ts +44 -0
- package/dist/batch.d.ts.map +1 -0
- package/dist/batch.js +132 -0
- package/dist/batch.js.map +1 -0
- package/dist/describe.d.ts +27 -0
- package/dist/describe.d.ts.map +1 -0
- package/dist/describe.js +104 -0
- package/dist/describe.js.map +1 -0
- package/dist/errors.d.ts +30 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +43 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -0
- package/dist/json.d.ts +11 -0
- package/dist/json.d.ts.map +1 -0
- package/dist/json.js +44 -0
- package/dist/json.js.map +1 -0
- package/dist/parameters.d.ts +31 -0
- package/dist/parameters.d.ts.map +1 -0
- package/dist/parameters.js +141 -0
- package/dist/parameters.js.map +1 -0
- package/dist/registry.d.ts +38 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/registry.js +113 -0
- package/dist/registry.js.map +1 -0
- package/dist/tools.d.ts +51 -0
- package/dist/tools.d.ts.map +1 -0
- package/dist/tools.js +106 -0
- package/dist/tools.js.map +1 -0
- package/dist/types.d.ts +118 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +7 -0
- package/dist/types.js.map +1 -0
- package/docs/actions.md +212 -0
- package/package.json +39 -4
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 SCFlow Core contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,61 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @scfloworg/actions
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
The neutral action package: the action type aligned on MCP tools, the check of
|
|
4
|
+
parameters by a standard JSON Schema validator, a registry, batches of calls,
|
|
5
|
+
the export of actions as AI tools, and the run log of executed actions.
|
|
6
|
+
|
|
7
|
+
It depends on no other SCFlow package and knows no model, so a host that is not
|
|
8
|
+
MCL, such as an application framework, uses it as it is. Its only dependency is
|
|
9
|
+
[Ajv](https://ajv.js.org). The engine plugs in what needs a dataset: the
|
|
10
|
+
resolution of `ref` values, the context of bodies, the steps `when`, `each` and
|
|
11
|
+
`fail` of a batch, and the transaction. The rules are in the specification
|
|
12
|
+
([Action](../core/docs/spec/meta-model.md#action) and
|
|
13
|
+
[Action Package](../core/docs/spec/typescript-reference-implementation.md#action-package)),
|
|
14
|
+
and the use of the package in [docs/actions.md](docs/actions.md).
|
|
15
|
+
|
|
16
|
+
```ts
|
|
17
|
+
import { createActionRegistry, createRunLog, runBatch, toAiTools } from "@scfloworg/actions";
|
|
18
|
+
|
|
19
|
+
const registry = createActionRegistry();
|
|
20
|
+
registry.register({
|
|
21
|
+
id: "demo/create_actor",
|
|
22
|
+
title: "Create an actor",
|
|
23
|
+
description: "Creates an actor and returns it",
|
|
24
|
+
parameters: {
|
|
25
|
+
type: "object",
|
|
26
|
+
properties: { display_name: { type: "string" }, parent: { type: "string", ref: "actor" } },
|
|
27
|
+
required: ["display_name"],
|
|
28
|
+
},
|
|
29
|
+
run(params, trace) {
|
|
30
|
+
const actor = { id: "a1", ...params };
|
|
31
|
+
trace.command({ create: "actor", input: params }, { after: [actor] });
|
|
32
|
+
return actor;
|
|
33
|
+
},
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
const log = createRunLog();
|
|
37
|
+
const { result } = await registry.run("demo/create_actor", { display_name: "Plant" }, { onEntry: log.record });
|
|
38
|
+
|
|
39
|
+
await runBatch(registry, {
|
|
40
|
+
commands: [
|
|
41
|
+
{ call: "demo/create_actor", with: { display_name: "Plant" }, as: "plant" },
|
|
42
|
+
{ call: "demo/create_actor", with: { display_name: "Line", parent: "${plant.id}" } },
|
|
43
|
+
],
|
|
44
|
+
}, { onEntry: log.record });
|
|
45
|
+
|
|
46
|
+
const tools = toAiTools(registry.list()); // MCP tool definitions, hidden actions left out
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
| Part | Gives |
|
|
50
|
+
| --- | --- |
|
|
51
|
+
| `Action`, `ActionDefinition` | The declaration of an action, as a manifest holds it, and its body `run(params, context)` |
|
|
52
|
+
| `validateParameters` | The check of parameters against their JSON Schema, with defaults and `ref` resolution |
|
|
53
|
+
| `createActionRegistry` | `register`, `get`, `list` and `run`: one call, checked and recorded |
|
|
54
|
+
| `runBatch` | A batch of `call` steps with `${name.path}` references |
|
|
55
|
+
| `toAiTools`, `toolName`, `actionIdOfTool` | The export to AI tools, in the schema AI providers accept; `languages` names the languages of the project in localized parameters |
|
|
56
|
+
| `RunEntry`, `createRunLog`, `canonicalJson` | The run log of the specification, in canonical JSON |
|
|
57
|
+
| `ActionError` | The error of the package; callers branch on `.code` |
|
|
58
|
+
|
|
59
|
+
The cases of the language it follows are in `@scfloworg/conformance`, as
|
|
60
|
+
`runActionConformanceSuite`, which `tests/conformance.test.ts` runs against this
|
|
61
|
+
package.
|
package/dist/batch.d.ts
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { ActionRegistry } from "./registry.js";
|
|
2
|
+
import type { RunEntry, RunHost, RunTrace } from "./types.js";
|
|
3
|
+
/**
|
|
4
|
+
* A step of a batch run by this package: a call of an action by id, with its
|
|
5
|
+
* parameters in `with`, its result named by `as`.
|
|
6
|
+
*/
|
|
7
|
+
export interface BatchCall {
|
|
8
|
+
readonly call: string;
|
|
9
|
+
readonly with?: unknown;
|
|
10
|
+
readonly as?: string;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* A batch: a script whose steps call actions, with no parameters
|
|
14
|
+
* (`packages/core/docs/spec/model-command-language.md`, section Script). This
|
|
15
|
+
* package runs the batches whose steps are only calls; a batch with `when`,
|
|
16
|
+
* `each` or `fail` runs through the script runner of the engine.
|
|
17
|
+
*/
|
|
18
|
+
export interface Batch {
|
|
19
|
+
readonly commands: readonly BatchCall[];
|
|
20
|
+
/** A placeholder giving the result of the batch; the result of its last call when absent. */
|
|
21
|
+
readonly result?: string;
|
|
22
|
+
}
|
|
23
|
+
/** What a batch gives: its result, and the entry of each of its calls, in order. */
|
|
24
|
+
export interface BatchOutcome {
|
|
25
|
+
readonly result: unknown;
|
|
26
|
+
readonly entries: readonly RunEntry[];
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Runs a batch of calls in order through a registry, each a run of
|
|
30
|
+
* `registry.run` with the host, so the run log gets one entry per call.
|
|
31
|
+
* Before each call, the placeholders of its `with` are resolved against the
|
|
32
|
+
* results named by the `as` of earlier calls.
|
|
33
|
+
*
|
|
34
|
+
* The batch is checked whole before any call: a step that is not a `call`
|
|
35
|
+
* with only `with` and `as`, or a batch with `parameters`, is refused with
|
|
36
|
+
* `invalid_script_step`. A placeholder naming an `as` name not set yet is
|
|
37
|
+
* refused with `unknown_reference`. A refused call stops the batch and its
|
|
38
|
+
* exception is thrown as is.
|
|
39
|
+
*
|
|
40
|
+
* It opens no transaction: the host runs the whole batch in one, and rolls it
|
|
41
|
+
* back when the batch throws, so a batch can be undone as one.
|
|
42
|
+
*/
|
|
43
|
+
export declare function runBatch<C = RunTrace>(registry: ActionRegistry<C>, batch: Batch, host?: RunHost<C>): Promise<BatchOutcome>;
|
|
44
|
+
//# sourceMappingURL=batch.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"batch.d.ts","sourceRoot":"","sources":["../src/batch.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AACpD,OAAO,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE9D;;;GAGG;AACH,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;;;GAKG;AACH,MAAM,WAAW,KAAK;IACpB,QAAQ,CAAC,QAAQ,EAAE,SAAS,SAAS,EAAE,CAAC;IACxC,6FAA6F;IAC7F,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,oFAAoF;AACpF,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,OAAO,EAAE,SAAS,QAAQ,EAAE,CAAC;CACvC;AA4FD;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,QAAQ,CAAC,CAAC,GAAG,QAAQ,EACzC,QAAQ,EAAE,cAAc,CAAC,CAAC,CAAC,EAC3B,KAAK,EAAE,KAAK,EACZ,IAAI,GAAE,OAAO,CAAC,CAAC,CAAM,GACpB,OAAO,CAAC,YAAY,CAAC,CAkBvB"}
|
package/dist/batch.js
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import { actionError } from "./errors.js";
|
|
2
|
+
import { canonicalJson } from "./json.js";
|
|
3
|
+
const IDENTIFIER = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
4
|
+
const STEP_KEYS = new Set(["call", "with", "as"]);
|
|
5
|
+
/** A placeholder whose content is a path: a name, then segments that are identifiers, indexes or `*`. */
|
|
6
|
+
const PATH = /^[A-Za-z_][A-Za-z0-9_]*(?:\.(?:[A-Za-z0-9_]+|\*))*$/;
|
|
7
|
+
const WHOLE = /^\$\{([^}]*)\}$/;
|
|
8
|
+
const ANY = /\$\{([^}]*)\}/g;
|
|
9
|
+
/** Checks the shape of a batch before any call runs. */
|
|
10
|
+
function checkBatch(batch) {
|
|
11
|
+
if (batch === null || typeof batch !== "object" || Array.isArray(batch)) {
|
|
12
|
+
throw actionError("invalid_script_step", "a batch is an object with commands");
|
|
13
|
+
}
|
|
14
|
+
if ("parameters" in batch)
|
|
15
|
+
throw actionError("invalid_script_step", "a batch has no parameters");
|
|
16
|
+
const { commands, result } = batch;
|
|
17
|
+
if (!Array.isArray(commands))
|
|
18
|
+
throw actionError("invalid_script_step", "a batch has an array of commands");
|
|
19
|
+
if (result !== undefined && typeof result !== "string") {
|
|
20
|
+
throw actionError("invalid_script_step", "the result of a batch is a placeholder");
|
|
21
|
+
}
|
|
22
|
+
commands.forEach((step, index) => {
|
|
23
|
+
const where = `step ${index}`;
|
|
24
|
+
if (step === null || typeof step !== "object" || Array.isArray(step)) {
|
|
25
|
+
throw actionError("invalid_script_step", `${where} is not a call`);
|
|
26
|
+
}
|
|
27
|
+
const keys = Object.keys(step);
|
|
28
|
+
const other = keys.find((key) => !STEP_KEYS.has(key));
|
|
29
|
+
if (other !== undefined || typeof step.call !== "string") {
|
|
30
|
+
throw actionError("invalid_script_step", `${where} is not a call with only with and as${other ? ` (it has ${other})` : ""}; ` +
|
|
31
|
+
"a batch with commands, when, each or fail runs through the script runner of the engine");
|
|
32
|
+
}
|
|
33
|
+
const { as } = step;
|
|
34
|
+
if (as !== undefined && (typeof as !== "string" || !IDENTIFIER.test(as))) {
|
|
35
|
+
throw actionError("invalid_script_step", `${where}: as must be an identifier`);
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
return batch;
|
|
39
|
+
}
|
|
40
|
+
/** Follows the segments of a path from a value, by the rules of placeholders on arrays. */
|
|
41
|
+
function follow(value, segments) {
|
|
42
|
+
if (segments.length === 0)
|
|
43
|
+
return value;
|
|
44
|
+
if (value === null || value === undefined)
|
|
45
|
+
return undefined;
|
|
46
|
+
const [segment, ...rest] = segments;
|
|
47
|
+
if (Array.isArray(value)) {
|
|
48
|
+
if (/^\d+$/.test(segment))
|
|
49
|
+
return follow(value[Number(segment)], rest);
|
|
50
|
+
if (segment === "*")
|
|
51
|
+
return value.map((entry) => follow(entry, rest));
|
|
52
|
+
return follow(value[0], segments);
|
|
53
|
+
}
|
|
54
|
+
if (typeof value === "object")
|
|
55
|
+
return follow(value[segment], rest);
|
|
56
|
+
return undefined;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Resolves the `${name.path}` placeholders of a value against the results
|
|
60
|
+
* named so far. A placeholder that is the whole string gives the value it
|
|
61
|
+
* reaches, of any type; one inside text gives its text. A placeholder that is
|
|
62
|
+
* not a path, such as `${now()}`, is kept for the called action.
|
|
63
|
+
*/
|
|
64
|
+
function resolve(value, names) {
|
|
65
|
+
const lookup = (path) => {
|
|
66
|
+
const [name, ...segments] = path.split(".");
|
|
67
|
+
if (!names.has(name))
|
|
68
|
+
throw actionError("unknown_reference", `\${${path}}: ${name} is not set yet`);
|
|
69
|
+
return follow(names.get(name), segments);
|
|
70
|
+
};
|
|
71
|
+
if (typeof value === "string") {
|
|
72
|
+
const whole = WHOLE.exec(value);
|
|
73
|
+
if (whole && PATH.test(whole[1]))
|
|
74
|
+
return lookup(whole[1]);
|
|
75
|
+
return value.replace(ANY, (text, content) => {
|
|
76
|
+
if (!PATH.test(content))
|
|
77
|
+
return text;
|
|
78
|
+
const found = lookup(content);
|
|
79
|
+
if (found === null || found === undefined)
|
|
80
|
+
return "";
|
|
81
|
+
return typeof found === "object" ? canonicalJson(found) : String(found);
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
if (Array.isArray(value))
|
|
85
|
+
return value.map((entry) => resolve(entry, names));
|
|
86
|
+
if (value !== null && typeof value === "object") {
|
|
87
|
+
const resolved = {};
|
|
88
|
+
for (const [key, entry] of Object.entries(value)) {
|
|
89
|
+
const result = resolve(entry, names);
|
|
90
|
+
if (result !== undefined)
|
|
91
|
+
resolved[key] = result;
|
|
92
|
+
}
|
|
93
|
+
return resolved;
|
|
94
|
+
}
|
|
95
|
+
return value;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Runs a batch of calls in order through a registry, each a run of
|
|
99
|
+
* `registry.run` with the host, so the run log gets one entry per call.
|
|
100
|
+
* Before each call, the placeholders of its `with` are resolved against the
|
|
101
|
+
* results named by the `as` of earlier calls.
|
|
102
|
+
*
|
|
103
|
+
* The batch is checked whole before any call: a step that is not a `call`
|
|
104
|
+
* with only `with` and `as`, or a batch with `parameters`, is refused with
|
|
105
|
+
* `invalid_script_step`. A placeholder naming an `as` name not set yet is
|
|
106
|
+
* refused with `unknown_reference`. A refused call stops the batch and its
|
|
107
|
+
* exception is thrown as is.
|
|
108
|
+
*
|
|
109
|
+
* It opens no transaction: the host runs the whole batch in one, and rolls it
|
|
110
|
+
* back when the batch throws, so a batch can be undone as one.
|
|
111
|
+
*/
|
|
112
|
+
export async function runBatch(registry, batch, host = {}) {
|
|
113
|
+
const { commands, result } = checkBatch(batch);
|
|
114
|
+
const entries = [];
|
|
115
|
+
const recording = {
|
|
116
|
+
...host,
|
|
117
|
+
onEntry(entry) {
|
|
118
|
+
entries.push(entry);
|
|
119
|
+
host.onEntry?.(entry);
|
|
120
|
+
},
|
|
121
|
+
};
|
|
122
|
+
const names = new Map();
|
|
123
|
+
let last;
|
|
124
|
+
for (const step of commands) {
|
|
125
|
+
const params = step.with === undefined ? undefined : resolve(step.with, names);
|
|
126
|
+
last = (await registry.run(step.call, params, recording)).result;
|
|
127
|
+
if (step.as !== undefined)
|
|
128
|
+
names.set(step.as, last);
|
|
129
|
+
}
|
|
130
|
+
return { result: result === undefined ? last : resolve(result, names), entries };
|
|
131
|
+
}
|
|
132
|
+
//# sourceMappingURL=batch.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"batch.js","sourceRoot":"","sources":["../src/batch.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { ActionDefinition } from "./types.js";
|
|
2
|
+
/** What a host plugs in to describe a call: the names of objects and the translations. */
|
|
3
|
+
export interface DescribeOptions {
|
|
4
|
+
/**
|
|
5
|
+
* The name of the instance of `schema` whose key is `id`, or `undefined` when
|
|
6
|
+
* it has none. This package reads no instance: the host does.
|
|
7
|
+
*/
|
|
8
|
+
label?(schema: string, id: string): string | undefined | Promise<string | undefined>;
|
|
9
|
+
/**
|
|
10
|
+
* The translation of `key` with `vars`, or `undefined` when there is none.
|
|
11
|
+
* The keys are `action.<id>.title`, `action.<id>.param.<name>` and
|
|
12
|
+
* `action.<id>.summary`, whose variables are the parameters as they are shown.
|
|
13
|
+
*/
|
|
14
|
+
t?(key: string, vars?: Readonly<Record<string, string>>): string | undefined;
|
|
15
|
+
/** The language of the localized texts, tried first. */
|
|
16
|
+
language?: string;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* The call of an action as a short line for a person who approves it: the
|
|
20
|
+
* title of the action, then its parameters by name and value. A value that
|
|
21
|
+
* names an instance (`ref`) is shown by the name `options.label` gives, never
|
|
22
|
+
* by its uuid; a uuid that is not found is cut to its last four characters.
|
|
23
|
+
* Texts come from `options.t`, then from the `title` of the action, then from
|
|
24
|
+
* its id.
|
|
25
|
+
*/
|
|
26
|
+
export declare function describeCall(action: ActionDefinition, params: unknown, options?: DescribeOptions): Promise<string>;
|
|
27
|
+
//# sourceMappingURL=describe.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"describe.d.ts","sourceRoot":"","sources":["../src/describe.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAEnD,0FAA0F;AAC1F,MAAM,WAAW,eAAe;IAC9B;;;OAGG;IACH,KAAK,CAAC,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IACrF;;;;OAIG;IACH,CAAC,CAAC,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,GAAG,MAAM,GAAG,SAAS,CAAC;IAC7E,wDAAwD;IACxD,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAiFD;;;;;;;GAOG;AACH,wBAAsB,YAAY,CAChC,MAAM,EAAE,gBAAgB,EACxB,MAAM,EAAE,OAAO,EACf,OAAO,GAAE,eAAoB,GAC5B,OAAO,CAAC,MAAM,CAAC,CAUjB"}
|
package/dist/describe.js
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { parametersSchema } from "./parameters.js";
|
|
2
|
+
const UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
3
|
+
const MAX_TEXT = 48;
|
|
4
|
+
const MAX_ITEMS = 3;
|
|
5
|
+
const isNode = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
6
|
+
/** The id of a call as people read it: no module namespace, spaces for underscores. */
|
|
7
|
+
function readableId(id) {
|
|
8
|
+
const name = id.slice(id.lastIndexOf("/") + 1).replace(/_/g, " ");
|
|
9
|
+
return name.charAt(0).toUpperCase() + name.slice(1);
|
|
10
|
+
}
|
|
11
|
+
function clip(text) {
|
|
12
|
+
return text.length > MAX_TEXT ? `${text.slice(0, MAX_TEXT - 1)}…` : text;
|
|
13
|
+
}
|
|
14
|
+
/** The subschemas of `schema` that apply to a value, through `anyOf`, `oneOf` and `allOf`. */
|
|
15
|
+
function variants(schema) {
|
|
16
|
+
if (!schema)
|
|
17
|
+
return [];
|
|
18
|
+
const nested = ["anyOf", "oneOf", "allOf"].flatMap((keyword) => {
|
|
19
|
+
const list = schema[keyword];
|
|
20
|
+
return Array.isArray(list) ? list.filter(isNode).flatMap((item) => variants(item)) : [];
|
|
21
|
+
});
|
|
22
|
+
return [schema, ...nested];
|
|
23
|
+
}
|
|
24
|
+
class Describer {
|
|
25
|
+
options;
|
|
26
|
+
constructor(options) {
|
|
27
|
+
this.options = options;
|
|
28
|
+
}
|
|
29
|
+
/** A value as it is shown; `schema` is the schema of the value, which names an object when it has `ref`. */
|
|
30
|
+
async show(value, schema) {
|
|
31
|
+
if (typeof value === "string") {
|
|
32
|
+
const ref = variants(schema).find((variant) => typeof variant.ref === "string")?.ref;
|
|
33
|
+
if (ref !== undefined && this.options.label) {
|
|
34
|
+
const label = await this.options.label(ref, value);
|
|
35
|
+
if (label !== undefined)
|
|
36
|
+
return clip(label);
|
|
37
|
+
}
|
|
38
|
+
if (UUID.test(value))
|
|
39
|
+
return "…" + value.slice(-4);
|
|
40
|
+
return clip(value);
|
|
41
|
+
}
|
|
42
|
+
if (Array.isArray(value)) {
|
|
43
|
+
const items = variants(schema).find((variant) => isNode(variant.items))?.items;
|
|
44
|
+
const shown = await Promise.all(value.slice(0, MAX_ITEMS).map((item) => this.show(item, items)));
|
|
45
|
+
return shown.join(", ") + (value.length > MAX_ITEMS ? `, +${value.length - MAX_ITEMS}` : "");
|
|
46
|
+
}
|
|
47
|
+
if (isNode(value)) {
|
|
48
|
+
const language = this.options.language;
|
|
49
|
+
const texts = Object.entries(value);
|
|
50
|
+
// A localized text is a map of language to string: only one language is shown.
|
|
51
|
+
if (texts.length > 0 && texts.every(([, text]) => typeof text === "string")) {
|
|
52
|
+
const preferred = language === undefined ? undefined : value[language];
|
|
53
|
+
return clip(String(preferred ?? texts[0][1]));
|
|
54
|
+
}
|
|
55
|
+
const properties = variants(schema).find((variant) => isNode(variant.properties))?.properties;
|
|
56
|
+
const parts = await this.parts(value, properties);
|
|
57
|
+
return `{${parts.join(", ")}}`;
|
|
58
|
+
}
|
|
59
|
+
return String(value);
|
|
60
|
+
}
|
|
61
|
+
/** The `name value` parts of an object, without the empty values. */
|
|
62
|
+
async parts(params, properties, action) {
|
|
63
|
+
const parts = [];
|
|
64
|
+
for (const [name, value] of Object.entries(params)) {
|
|
65
|
+
if (value === undefined || value === null || value === "")
|
|
66
|
+
continue;
|
|
67
|
+
const property = isNode(properties?.[name]) ? properties[name] : undefined;
|
|
68
|
+
const label = (action && this.options.t?.(`action.${action}.param.${name}`)) || name;
|
|
69
|
+
parts.push(`${label}=${await this.show(value, property)}`);
|
|
70
|
+
}
|
|
71
|
+
return parts;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* The call of an action as a short line for a person who approves it: the
|
|
76
|
+
* title of the action, then its parameters by name and value. A value that
|
|
77
|
+
* names an instance (`ref`) is shown by the name `options.label` gives, never
|
|
78
|
+
* by its uuid; a uuid that is not found is cut to its last four characters.
|
|
79
|
+
* Texts come from `options.t`, then from the `title` of the action, then from
|
|
80
|
+
* its id.
|
|
81
|
+
*/
|
|
82
|
+
export async function describeCall(action, params, options = {}) {
|
|
83
|
+
const describer = new Describer(options);
|
|
84
|
+
const schemaProperties = parametersSchema(action).properties;
|
|
85
|
+
const properties = isNode(schemaProperties) ? schemaProperties : undefined;
|
|
86
|
+
const title = options.t?.(`action.${action.id}.title`) ?? action.title ?? readableId(action.id);
|
|
87
|
+
if (!isNode(params))
|
|
88
|
+
return title;
|
|
89
|
+
const parts = await describer.parts(params, properties, action.id);
|
|
90
|
+
if (parts.length === 0)
|
|
91
|
+
return title;
|
|
92
|
+
const summary = options.t?.(`action.${action.id}.summary`, await shownVariables(describer, params, properties));
|
|
93
|
+
return summary ?? `${title}: ${parts.join(", ")}`;
|
|
94
|
+
}
|
|
95
|
+
async function shownVariables(describer, params, properties) {
|
|
96
|
+
const vars = {};
|
|
97
|
+
for (const [name, value] of Object.entries(params)) {
|
|
98
|
+
if (value === undefined || value === null || value === "")
|
|
99
|
+
continue;
|
|
100
|
+
vars[name] = await describer.show(value, isNode(properties?.[name]) ? properties[name] : undefined);
|
|
101
|
+
}
|
|
102
|
+
return vars;
|
|
103
|
+
}
|
|
104
|
+
//# sourceMappingURL=describe.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"describe.js","sourceRoot":"","sources":["../src/describe.ts"],"names":[],"mappings":"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"}
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/** Every code an `ActionError` carries, each with the condition that raises it. */
|
|
2
|
+
export declare const ActionErrorCode: {
|
|
3
|
+
/** The parameters break the JSON Schema of the action, or a `ref` matches no instance or several. */
|
|
4
|
+
readonly invalid_parameters: "invalid_parameters";
|
|
5
|
+
/** An id names no action of the registry. */
|
|
6
|
+
readonly unknown_action: "unknown_action";
|
|
7
|
+
/** An action is registered with the id of another one. */
|
|
8
|
+
readonly duplicate_name: "duplicate_name";
|
|
9
|
+
/** An action is registered with an id or parameters that are not valid. */
|
|
10
|
+
readonly constraint_violation: "constraint_violation";
|
|
11
|
+
/** A step of a batch is not a `call` with only `with` and `as`, or a batch has `parameters`. */
|
|
12
|
+
readonly invalid_script_step: "invalid_script_step";
|
|
13
|
+
/** A placeholder of a batch names an `as` name that is not set yet. */
|
|
14
|
+
readonly unknown_reference: "unknown_reference";
|
|
15
|
+
};
|
|
16
|
+
/** The name of one code of `ActionErrorCode`. */
|
|
17
|
+
export type ActionErrorCodeName = keyof typeof ActionErrorCode;
|
|
18
|
+
/**
|
|
19
|
+
* The error this package throws: `code` names the cause, with the names the
|
|
20
|
+
* engine uses for the same causes, so a caller branches on `.code` alike.
|
|
21
|
+
*/
|
|
22
|
+
export declare class ActionError extends Error {
|
|
23
|
+
readonly code: ActionErrorCodeName;
|
|
24
|
+
constructor(code: ActionErrorCodeName, message?: string);
|
|
25
|
+
}
|
|
26
|
+
/** Builds an `ActionError`; `message` defaults to the code. */
|
|
27
|
+
export declare function actionError(code: ActionErrorCodeName, message?: string): ActionError;
|
|
28
|
+
/** The code of an exception when it has one, otherwise its message: the `error` of a refused run entry. */
|
|
29
|
+
export declare function errorCodeOf(error: unknown): string;
|
|
30
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,mFAAmF;AACnF,eAAO,MAAM,eAAe;IAC1B,qGAAqG;;IAErG,6CAA6C;;IAE7C,0DAA0D;;IAE1D,2EAA2E;;IAE3E,gGAAgG;;IAEhG,uEAAuE;;CAE/D,CAAC;AAEX,iDAAiD;AACjD,MAAM,MAAM,mBAAmB,GAAG,MAAM,OAAO,eAAe,CAAC;AAE/D;;;GAGG;AACH,qBAAa,WAAY,SAAQ,KAAK;IACpC,QAAQ,CAAC,IAAI,EAAE,mBAAmB,CAAC;gBAEvB,IAAI,EAAE,mBAAmB,EAAE,OAAO,CAAC,EAAE,MAAM;CAKxD;AAED,+DAA+D;AAC/D,wBAAgB,WAAW,CAAC,IAAI,EAAE,mBAAmB,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,WAAW,CAEpF;AAED,2GAA2G;AAC3G,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAOlD"}
|
package/dist/errors.js
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/** Every code an `ActionError` carries, each with the condition that raises it. */
|
|
2
|
+
export const ActionErrorCode = {
|
|
3
|
+
/** The parameters break the JSON Schema of the action, or a `ref` matches no instance or several. */
|
|
4
|
+
invalid_parameters: "invalid_parameters",
|
|
5
|
+
/** An id names no action of the registry. */
|
|
6
|
+
unknown_action: "unknown_action",
|
|
7
|
+
/** An action is registered with the id of another one. */
|
|
8
|
+
duplicate_name: "duplicate_name",
|
|
9
|
+
/** An action is registered with an id or parameters that are not valid. */
|
|
10
|
+
constraint_violation: "constraint_violation",
|
|
11
|
+
/** A step of a batch is not a `call` with only `with` and `as`, or a batch has `parameters`. */
|
|
12
|
+
invalid_script_step: "invalid_script_step",
|
|
13
|
+
/** A placeholder of a batch names an `as` name that is not set yet. */
|
|
14
|
+
unknown_reference: "unknown_reference",
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* The error this package throws: `code` names the cause, with the names the
|
|
18
|
+
* engine uses for the same causes, so a caller branches on `.code` alike.
|
|
19
|
+
*/
|
|
20
|
+
export class ActionError extends Error {
|
|
21
|
+
code;
|
|
22
|
+
constructor(code, message) {
|
|
23
|
+
super(message ?? code);
|
|
24
|
+
this.name = "ActionError";
|
|
25
|
+
this.code = code;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
/** Builds an `ActionError`; `message` defaults to the code. */
|
|
29
|
+
export function actionError(code, message) {
|
|
30
|
+
return new ActionError(code, message);
|
|
31
|
+
}
|
|
32
|
+
/** The code of an exception when it has one, otherwise its message: the `error` of a refused run entry. */
|
|
33
|
+
export function errorCodeOf(error) {
|
|
34
|
+
if (error !== null && typeof error === "object") {
|
|
35
|
+
const { code, message } = error;
|
|
36
|
+
if (typeof code === "string")
|
|
37
|
+
return code;
|
|
38
|
+
if (typeof message === "string")
|
|
39
|
+
return message;
|
|
40
|
+
}
|
|
41
|
+
return String(error);
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,mFAAmF;AACnF,MAAM,CAAC,MAAM,eAAe,GAAG;IAC7B,qGAAqG;IACrG,kBAAkB,EAAE,oBAAoB;IACxC,6CAA6C;IAC7C,cAAc,EAAE,gBAAgB;IAChC,0DAA0D;IAC1D,cAAc,EAAE,gBAAgB;IAChC,2EAA2E;IAC3E,oBAAoB,EAAE,sBAAsB;IAC5C,gGAAgG;IAChG,mBAAmB,EAAE,qBAAqB;IAC1C,uEAAuE;IACvE,iBAAiB,EAAE,mBAAmB;CAC9B,CAAC;AAKX;;;GAGG;AACH,MAAM,OAAO,WAAY,SAAQ,KAAK;IAC3B,IAAI,CAAsB;IAEnC,YAAY,IAAyB,EAAE,OAAgB;QACrD,KAAK,CAAC,OAAO,IAAI,IAAI,CAAC,CAAC;QACvB,IAAI,CAAC,IAAI,GAAG,aAAa,CAAC;QAC1B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACnB,CAAC;CACF;AAED,+DAA+D;AAC/D,MAAM,UAAU,WAAW,CAAC,IAAyB,EAAE,OAAgB;IACrE,OAAO,IAAI,WAAW,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;AACxC,CAAC;AAED,2GAA2G;AAC3G,MAAM,UAAU,WAAW,CAAC,KAAc;IACxC,IAAI,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAChD,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,KAA8C,CAAC;QACzE,IAAI,OAAO,IAAI,KAAK,QAAQ;YAAE,OAAO,IAAI,CAAC;QAC1C,IAAI,OAAO,OAAO,KAAK,QAAQ;YAAE,OAAO,OAAO,CAAC;IAClD,CAAC;IACD,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC;AACvB,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@scfloworg/actions`, the neutral action package: the action type aligned on
|
|
3
|
+
* MCP tools, the check of parameters by a JSON Schema validator, a registry,
|
|
4
|
+
* the batches made only of calls, the export to AI tools and the run log. It
|
|
5
|
+
* depends on no other SCFlow package; the engine plugs in what needs a dataset
|
|
6
|
+
* (see `docs/actions.md`).
|
|
7
|
+
*/
|
|
8
|
+
export type { Action, ActionDefinition, JsonSchema, RefMatches, RefResolver, RunEntry, RunHost, RunOutcome, RunStep, RunTrace, } from "./types.js";
|
|
9
|
+
export { ActionError, ActionErrorCode, actionError, errorCodeOf } from "./errors.js";
|
|
10
|
+
export type { ActionErrorCodeName } from "./errors.js";
|
|
11
|
+
export { canonicalJson } from "./json.js";
|
|
12
|
+
export { compileParameters, parametersSchema, validateParameters } from "./parameters.js";
|
|
13
|
+
export { createActionRegistry, createRunLog, entryOfRefusal } from "./registry.js";
|
|
14
|
+
export type { ActionRegistry, RunLog } from "./registry.js";
|
|
15
|
+
export { runBatch } from "./batch.js";
|
|
16
|
+
export type { Batch, BatchCall, BatchOutcome } from "./batch.js";
|
|
17
|
+
export { actionIdOfTool, languagesNote, parametersWithLanguages, toAiTool, toAiTools, toolName } from "./tools.js";
|
|
18
|
+
export type { AiTool, ToolOptions } from "./tools.js";
|
|
19
|
+
export { describeCall } from "./describe.js";
|
|
20
|
+
export type { DescribeOptions } from "./describe.js";
|
|
21
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,YAAY,EACV,MAAM,EACN,gBAAgB,EAChB,UAAU,EACV,UAAU,EACV,WAAW,EACX,QAAQ,EACR,OAAO,EACP,UAAU,EACV,OAAO,EACP,QAAQ,GACT,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AACrF,YAAY,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AACvD,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAC1F,OAAO,EAAE,oBAAoB,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AACnF,YAAY,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAC5D,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,YAAY,EAAE,KAAK,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AACjE,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,uBAAuB,EAAE,QAAQ,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACnH,YAAY,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACtD,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC7C,YAAY,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { ActionError, ActionErrorCode, actionError, errorCodeOf } from "./errors.js";
|
|
2
|
+
export { canonicalJson } from "./json.js";
|
|
3
|
+
export { compileParameters, parametersSchema, validateParameters } from "./parameters.js";
|
|
4
|
+
export { createActionRegistry, createRunLog, entryOfRefusal } from "./registry.js";
|
|
5
|
+
export { runBatch } from "./batch.js";
|
|
6
|
+
export { actionIdOfTool, languagesNote, parametersWithLanguages, toAiTool, toAiTools, toolName } from "./tools.js";
|
|
7
|
+
export { describeCall } from "./describe.js";
|
|
8
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAmBA,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAErF,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAC1F,OAAO,EAAE,oBAAoB,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAEnF,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAEtC,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,uBAAuB,EAAE,QAAQ,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAEnH,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC"}
|
package/dist/json.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The canonical form of JSON, in which the run log holds parameters and
|
|
3
|
+
* results and a replay compares steps: the keys of every object sorted, no
|
|
4
|
+
* white space. As in `JSON.stringify`, a property whose value is `undefined`
|
|
5
|
+
* or a function is left out, and such a value in an array becomes `null`.
|
|
6
|
+
* `undefined` itself gives `null`.
|
|
7
|
+
*/
|
|
8
|
+
export declare function canonicalJson(value: unknown): string;
|
|
9
|
+
/** A deep copy of JSON data, through its JSON text. */
|
|
10
|
+
export declare function copyJson<T>(value: T): T;
|
|
11
|
+
//# sourceMappingURL=json.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"json.d.ts","sourceRoot":"","sources":["../src/json.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAEpD;AA+BD,uDAAuD;AACvD,wBAAgB,QAAQ,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,GAAG,CAAC,CAEvC"}
|
package/dist/json.js
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The canonical form of JSON, in which the run log holds parameters and
|
|
3
|
+
* results and a replay compares steps: the keys of every object sorted, no
|
|
4
|
+
* white space. As in `JSON.stringify`, a property whose value is `undefined`
|
|
5
|
+
* or a function is left out, and such a value in an array becomes `null`.
|
|
6
|
+
* `undefined` itself gives `null`.
|
|
7
|
+
*/
|
|
8
|
+
export function canonicalJson(value) {
|
|
9
|
+
return write(value) ?? "null";
|
|
10
|
+
}
|
|
11
|
+
function write(value) {
|
|
12
|
+
if (value === null)
|
|
13
|
+
return "null";
|
|
14
|
+
if (typeof value === "object" && typeof value.toJSON === "function") {
|
|
15
|
+
return write(value.toJSON());
|
|
16
|
+
}
|
|
17
|
+
switch (typeof value) {
|
|
18
|
+
case "string":
|
|
19
|
+
case "number":
|
|
20
|
+
case "boolean":
|
|
21
|
+
return JSON.stringify(value);
|
|
22
|
+
case "bigint":
|
|
23
|
+
throw new TypeError("canonicalJson: a bigint has no JSON form");
|
|
24
|
+
case "object": {
|
|
25
|
+
if (Array.isArray(value))
|
|
26
|
+
return `[${value.map((entry) => write(entry) ?? "null").join(",")}]`;
|
|
27
|
+
const record = value;
|
|
28
|
+
const members = Object.keys(record)
|
|
29
|
+
.sort()
|
|
30
|
+
.flatMap((key) => {
|
|
31
|
+
const text = write(record[key]);
|
|
32
|
+
return text === undefined ? [] : [`${JSON.stringify(key)}:${text}`];
|
|
33
|
+
});
|
|
34
|
+
return `{${members.join(",")}}`;
|
|
35
|
+
}
|
|
36
|
+
default:
|
|
37
|
+
return undefined;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
/** A deep copy of JSON data, through its JSON text. */
|
|
41
|
+
export function copyJson(value) {
|
|
42
|
+
return value === undefined ? value : JSON.parse(JSON.stringify(value));
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=json.js.map
|
package/dist/json.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"json.js","sourceRoot":"","sources":["../src/json.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,MAAM,UAAU,aAAa,CAAC,KAAc;IAC1C,OAAO,KAAK,CAAC,KAAK,CAAC,IAAI,MAAM,CAAC;AAChC,CAAC;AAED,SAAS,KAAK,CAAC,KAAc;IAC3B,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,MAAM,CAAC;IAClC,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,OAAQ,KAA8B,CAAC,MAAM,KAAK,UAAU,EAAE,CAAC;QAC9F,OAAO,KAAK,CAAE,KAA+B,CAAC,MAAM,EAAE,CAAC,CAAC;IAC1D,CAAC;IACD,QAAQ,OAAO,KAAK,EAAE,CAAC;QACrB,KAAK,QAAQ,CAAC;QACd,KAAK,QAAQ,CAAC;QACd,KAAK,SAAS;YACZ,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;QAC/B,KAAK,QAAQ;YACX,MAAM,IAAI,SAAS,CAAC,0CAA0C,CAAC,CAAC;QAClE,KAAK,QAAQ,CAAC,CAAC,CAAC;YACd,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;gBACtB,OAAO,IAAI,KAAK,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,MAAM,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;YACvE,MAAM,MAAM,GAAG,KAAgC,CAAC;YAChD,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC;iBAChC,IAAI,EAAE;iBACN,OAAO,CAAC,CAAC,GAAG,EAAE,EAAE;gBACf,MAAM,IAAI,GAAG,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;gBAChC,OAAO,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC;YACtE,CAAC,CAAC,CAAC;YACL,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;QAClC,CAAC;QACD;YACE,OAAO,SAAS,CAAC;IACrB,CAAC;AACH,CAAC;AAED,uDAAuD;AACvD,MAAM,UAAU,QAAQ,CAAI,KAAQ;IAClC,OAAO,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAO,CAAC;AAChF,CAAC"}
|