@flow-as-code/core 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 +202 -0
- package/README.md +30 -0
- package/SPEC.md +92 -0
- package/dist/actions.d.ts +87 -0
- package/dist/actions.d.ts.map +1 -0
- package/dist/actions.js +204 -0
- package/dist/actions.js.map +1 -0
- package/dist/aws.d.ts +27 -0
- package/dist/aws.d.ts.map +1 -0
- package/dist/aws.js +32 -0
- package/dist/aws.js.map +1 -0
- package/dist/blocks.d.ts +287 -0
- package/dist/blocks.d.ts.map +1 -0
- package/dist/blocks.js +352 -0
- package/dist/blocks.js.map +1 -0
- package/dist/codegen.d.ts +21 -0
- package/dist/codegen.d.ts.map +1 -0
- package/dist/codegen.js +1027 -0
- package/dist/codegen.js.map +1 -0
- package/dist/export.d.ts +256 -0
- package/dist/export.d.ts.map +1 -0
- package/dist/export.js +799 -0
- package/dist/export.js.map +1 -0
- package/dist/flow.d.ts +41 -0
- package/dist/flow.d.ts.map +1 -0
- package/dist/flow.js +85 -0
- package/dist/flow.js.map +1 -0
- package/dist/flowdoc.d.ts +111 -0
- package/dist/flowdoc.d.ts.map +1 -0
- package/dist/flowdoc.js +139 -0
- package/dist/flowdoc.js.map +1 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +26 -0
- package/dist/index.js.map +1 -0
- package/dist/layout.d.ts +11 -0
- package/dist/layout.d.ts.map +1 -0
- package/dist/layout.js +49 -0
- package/dist/layout.js.map +1 -0
- package/dist/lint/engine.d.ts +16 -0
- package/dist/lint/engine.d.ts.map +1 -0
- package/dist/lint/engine.js +37 -0
- package/dist/lint/engine.js.map +1 -0
- package/dist/lint/graph.d.ts +34 -0
- package/dist/lint/graph.d.ts.map +1 -0
- package/dist/lint/graph.js +79 -0
- package/dist/lint/graph.js.map +1 -0
- package/dist/lint/index.d.ts +7 -0
- package/dist/lint/index.d.ts.map +1 -0
- package/dist/lint/index.js +5 -0
- package/dist/lint/index.js.map +1 -0
- package/dist/lint/reporters.d.ts +6 -0
- package/dist/lint/reporters.d.ts.map +1 -0
- package/dist/lint/reporters.js +30 -0
- package/dist/lint/reporters.js.map +1 -0
- package/dist/lint/rules/action-allowed-in-flow-type.d.ts +11 -0
- package/dist/lint/rules/action-allowed-in-flow-type.d.ts.map +1 -0
- package/dist/lint/rules/action-allowed-in-flow-type.js +32 -0
- package/dist/lint/rules/action-allowed-in-flow-type.js.map +1 -0
- package/dist/lint/rules/action-count.d.ts +16 -0
- package/dist/lint/rules/action-count.d.ts.map +1 -0
- package/dist/lint/rules/action-count.js +32 -0
- package/dist/lint/rules/action-count.js.map +1 -0
- package/dist/lint/rules/error-branches.d.ts +10 -0
- package/dist/lint/rules/error-branches.d.ts.map +1 -0
- package/dist/lint/rules/error-branches.js +39 -0
- package/dist/lint/rules/error-branches.js.map +1 -0
- package/dist/lint/rules/index.d.ts +17 -0
- package/dist/lint/rules/index.d.ts.map +1 -0
- package/dist/lint/rules/index.js +36 -0
- package/dist/lint/rules/index.js.map +1 -0
- package/dist/lint/rules/module-depth-5.d.ts +14 -0
- package/dist/lint/rules/module-depth-5.d.ts.map +1 -0
- package/dist/lint/rules/module-depth-5.js +67 -0
- package/dist/lint/rules/module-depth-5.js.map +1 -0
- package/dist/lint/rules/no-literal-arn.d.ts +21 -0
- package/dist/lint/rules/no-literal-arn.d.ts.map +1 -0
- package/dist/lint/rules/no-literal-arn.js +58 -0
- package/dist/lint/rules/no-literal-arn.js.map +1 -0
- package/dist/lint/rules/no-unresolved-token.d.ts +8 -0
- package/dist/lint/rules/no-unresolved-token.d.ts.map +1 -0
- package/dist/lint/rules/no-unresolved-token.js +71 -0
- package/dist/lint/rules/no-unresolved-token.js.map +1 -0
- package/dist/lint/rules/prompt-length-3000.d.ts +16 -0
- package/dist/lint/rules/prompt-length-3000.d.ts.map +1 -0
- package/dist/lint/rules/prompt-length-3000.js +61 -0
- package/dist/lint/rules/prompt-length-3000.js.map +1 -0
- package/dist/lint/rules/reachable-blocks.d.ts +7 -0
- package/dist/lint/rules/reachable-blocks.d.ts.map +1 -0
- package/dist/lint/rules/reachable-blocks.js +45 -0
- package/dist/lint/rules/reachable-blocks.js.map +1 -0
- package/dist/lint/rules/recording-consent-before-record.d.ts +3 -0
- package/dist/lint/rules/recording-consent-before-record.d.ts.map +1 -0
- package/dist/lint/rules/recording-consent-before-record.js +87 -0
- package/dist/lint/rules/recording-consent-before-record.js.map +1 -0
- package/dist/lint/rules/terminal-blocks.d.ts +8 -0
- package/dist/lint/rules/terminal-blocks.d.ts.map +1 -0
- package/dist/lint/rules/terminal-blocks.js +40 -0
- package/dist/lint/rules/terminal-blocks.js.map +1 -0
- package/dist/lint/rules/unique-names.d.ts +7 -0
- package/dist/lint/rules/unique-names.d.ts.map +1 -0
- package/dist/lint/rules/unique-names.js +40 -0
- package/dist/lint/rules/unique-names.js.map +1 -0
- package/dist/lint/types.d.ts +30 -0
- package/dist/lint/types.d.ts.map +1 -0
- package/dist/lint/types.js +11 -0
- package/dist/lint/types.js.map +1 -0
- package/dist/materialize.d.ts +31 -0
- package/dist/materialize.d.ts.map +1 -0
- package/dist/materialize.js +192 -0
- package/dist/materialize.js.map +1 -0
- package/dist/package-names.d.ts +11 -0
- package/dist/package-names.d.ts.map +1 -0
- package/dist/package-names.js +25 -0
- package/dist/package-names.js.map +1 -0
- package/dist/refs.d.ts +35 -0
- package/dist/refs.d.ts.map +1 -0
- package/dist/refs.js +69 -0
- package/dist/refs.js.map +1 -0
- package/dist/serialize.d.ts +13 -0
- package/dist/serialize.d.ts.map +1 -0
- package/dist/serialize.js +86 -0
- package/dist/serialize.js.map +1 -0
- package/dist/simulate.d.ts +446 -0
- package/dist/simulate.d.ts.map +1 -0
- package/dist/simulate.js +1115 -0
- package/dist/simulate.js.map +1 -0
- package/dist/synth.d.ts +25 -0
- package/dist/synth.d.ts.map +1 -0
- package/dist/synth.js +93 -0
- package/dist/synth.js.map +1 -0
- package/package.json +73 -0
- package/src/actions.ts +221 -0
- package/src/aws.ts +55 -0
- package/src/blocks.ts +619 -0
- package/src/codegen.ts +1144 -0
- package/src/export.ts +1190 -0
- package/src/flow.ts +108 -0
- package/src/flowdoc.ts +261 -0
- package/src/index.ts +31 -0
- package/src/layout.ts +54 -0
- package/src/lint/engine.ts +56 -0
- package/src/lint/graph.ts +86 -0
- package/src/lint/index.ts +10 -0
- package/src/lint/reporters.ts +44 -0
- package/src/lint/rules/action-allowed-in-flow-type.ts +32 -0
- package/src/lint/rules/action-count.ts +35 -0
- package/src/lint/rules/error-branches.ts +45 -0
- package/src/lint/rules/index.ts +53 -0
- package/src/lint/rules/module-depth-5.ts +70 -0
- package/src/lint/rules/no-literal-arn.ts +64 -0
- package/src/lint/rules/no-unresolved-token.ts +80 -0
- package/src/lint/rules/prompt-length-3000.ts +66 -0
- package/src/lint/rules/reachable-blocks.ts +50 -0
- package/src/lint/rules/recording-consent-before-record.ts +90 -0
- package/src/lint/rules/terminal-blocks.ts +45 -0
- package/src/lint/rules/unique-names.ts +44 -0
- package/src/lint/types.ts +43 -0
- package/src/materialize.ts +230 -0
- package/src/package-names.ts +26 -0
- package/src/refs.ts +93 -0
- package/src/serialize.ts +97 -0
- package/src/simulate.ts +1610 -0
- package/src/synth.ts +110 -0
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2026 The flow-as-code Authors
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*/
|
|
5
|
+
// Materialization: FlowDoc in, deployable Flow language content out.
|
|
6
|
+
//
|
|
7
|
+
// Two backends resolve `${cdref:...}` tokens (SPEC.md, Materialization):
|
|
8
|
+
// - materializeWithMap: strict lookup in a token -> value map; every missing
|
|
9
|
+
// token is reported at once in a MaterializeError.
|
|
10
|
+
// - materializeWithBinder: the binder returns opaque strings (CDK or
|
|
11
|
+
// CloudFormation tokens). They pass through byte-for-byte with no
|
|
12
|
+
// validation and no arn-shape checks, because intrinsics are resolved by
|
|
13
|
+
// CloudFormation long after this code runs.
|
|
14
|
+
//
|
|
15
|
+
// Both backends emit content ONLY: `layout`, `refs`, and `meta` are tool
|
|
16
|
+
// metadata and are dropped. Before dropping, `layout` is projected into
|
|
17
|
+
// `content.Metadata` so the flow lays out correctly in the Connect console
|
|
18
|
+
// (docs/01-flowdoc-spec.md). The Metadata shape follows the Flow language
|
|
19
|
+
// example, which uses EntryPointPosition and ActionMetadata.<id>.Position:
|
|
20
|
+
// https://docs.aws.amazon.com/connect/latest/devguide/flow-language-example.html
|
|
21
|
+
import { InvalidFlowDocError, assertFlowDoc } from "./flowdoc.js";
|
|
22
|
+
import { autoLayout } from "./layout.js";
|
|
23
|
+
import { collectRefs, parseToken } from "./refs.js";
|
|
24
|
+
import { canonicalAction, ordered, sortKeys } from "./serialize.js";
|
|
25
|
+
/**
|
|
26
|
+
* Strict map materialization failed: one or more tokens in the document have
|
|
27
|
+
* no entry in the resource map. `missingTokens` is sorted and complete, so a
|
|
28
|
+
* caller fixes the map once, not one missing key per run.
|
|
29
|
+
*/
|
|
30
|
+
export class MaterializeError extends Error {
|
|
31
|
+
missingTokens;
|
|
32
|
+
constructor(missingTokens, reason) {
|
|
33
|
+
super(reason === undefined
|
|
34
|
+
? `Cannot materialize: ${String(missingTokens.length)} unmapped token(s): ` +
|
|
35
|
+
missingTokens.join(", ")
|
|
36
|
+
: `Cannot materialize: ${reason} Offending token(s): ${missingTokens.join(", ")}`);
|
|
37
|
+
this.name = "MaterializeError";
|
|
38
|
+
this.missingTokens = missingTokens;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* A reference token occupies an entire field value and is never interpolated
|
|
43
|
+
* into a longer string (FlowDoc invariant 4), so replacement only ever swaps
|
|
44
|
+
* whole string values. Binder output is inserted exactly as returned.
|
|
45
|
+
*/
|
|
46
|
+
function resolveDeep(value, resolve) {
|
|
47
|
+
if (typeof value === "string") {
|
|
48
|
+
const entry = parseToken(value);
|
|
49
|
+
return entry === undefined ? value : resolve(entry);
|
|
50
|
+
}
|
|
51
|
+
if (Array.isArray(value))
|
|
52
|
+
return value.map((v) => resolveDeep(v, resolve));
|
|
53
|
+
if (value !== null && typeof value === "object") {
|
|
54
|
+
return Object.fromEntries(Object.entries(value).map(([k, v]) => [
|
|
55
|
+
k,
|
|
56
|
+
resolveDeep(v, resolve),
|
|
57
|
+
]));
|
|
58
|
+
}
|
|
59
|
+
return value;
|
|
60
|
+
}
|
|
61
|
+
/** How far left of the StartAction block the console entry point marker sits. */
|
|
62
|
+
const ENTRY_POINT_OFFSET_X = 100;
|
|
63
|
+
/**
|
|
64
|
+
* Projects `layout` into the Metadata shape the console reads. Positions come
|
|
65
|
+
* from the document's layout; any action without one gets the same
|
|
66
|
+
* deterministic auto-layout synth would have assigned. Keys an imported
|
|
67
|
+
* document may already carry in content.Metadata are preserved; only the
|
|
68
|
+
* position keys are overwritten, because `layout` is the single source of
|
|
69
|
+
* truth for position (docs/01-flowdoc-spec.md).
|
|
70
|
+
*/
|
|
71
|
+
function projectLayout(doc, resolve) {
|
|
72
|
+
const actions = doc.content.Actions;
|
|
73
|
+
const layout = doc.layout ?? {};
|
|
74
|
+
const missing = actions.some((a) => layout[a.Identifier] === undefined);
|
|
75
|
+
const auto = missing ? autoLayout(actions) : {};
|
|
76
|
+
// Pre-existing Metadata (an imported document, say) is carried through, and
|
|
77
|
+
// it is RESOLVED like everything else: the strictness check scans the whole
|
|
78
|
+
// content, so substitution must cover the whole content too, or a token
|
|
79
|
+
// could survive into deployable output.
|
|
80
|
+
const existing = resolveDeep(doc.content.Metadata ?? {}, resolve);
|
|
81
|
+
const existingRaw = existing.ActionMetadata;
|
|
82
|
+
const existingActionMetadata = existingRaw !== null && typeof existingRaw === "object" && !Array.isArray(existingRaw)
|
|
83
|
+
? existingRaw
|
|
84
|
+
: {};
|
|
85
|
+
// Start from what was already there (entries for unknown ids survive; never
|
|
86
|
+
// drop content), then overlay Position per action: layout is the single
|
|
87
|
+
// source of truth for position, but sibling keys inside an entry are kept.
|
|
88
|
+
const actionMetadata = { ...existingActionMetadata };
|
|
89
|
+
const positions = {};
|
|
90
|
+
for (const a of actions) {
|
|
91
|
+
const p = layout[a.Identifier] ?? auto[a.Identifier] ?? { x: 0, y: 0 };
|
|
92
|
+
positions[a.Identifier] = p;
|
|
93
|
+
const prior = actionMetadata[a.Identifier];
|
|
94
|
+
const priorEntry = prior !== null && typeof prior === "object" && !Array.isArray(prior)
|
|
95
|
+
? prior
|
|
96
|
+
: {};
|
|
97
|
+
actionMetadata[a.Identifier] = { ...priorEntry, Position: { x: p.x, y: p.y } };
|
|
98
|
+
}
|
|
99
|
+
// The example places the entry point marker left of the first block
|
|
100
|
+
// (EntryPointPosition x=88 vs first Action x=270).
|
|
101
|
+
const start = positions[doc.content.StartAction] ?? { x: 0, y: 0 };
|
|
102
|
+
const entryPointPosition = { x: Math.max(start.x - ENTRY_POINT_OFFSET_X, 0), y: start.y };
|
|
103
|
+
return {
|
|
104
|
+
...existing,
|
|
105
|
+
EntryPointPosition: entryPointPosition,
|
|
106
|
+
ActionMetadata: actionMetadata,
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
function materialize(doc, resolve) {
|
|
110
|
+
// A module requires a top-level Settings in its deployable content; Connect
|
|
111
|
+
// rejects the create without it. Default to {} when the doc does not carry
|
|
112
|
+
// one; resolve tokens in it for consistency with the rest of the content.
|
|
113
|
+
const settings = doc.kind === "module" || doc.content.Settings !== undefined
|
|
114
|
+
? resolveDeep(doc.content.Settings ?? {}, resolve)
|
|
115
|
+
: undefined;
|
|
116
|
+
return {
|
|
117
|
+
Version: doc.content.Version,
|
|
118
|
+
StartAction: doc.content.StartAction,
|
|
119
|
+
...(settings === undefined ? {} : { Settings: settings }),
|
|
120
|
+
Metadata: projectLayout(doc, resolve),
|
|
121
|
+
Actions: doc.content.Actions.map((a) => resolveDeep(a, resolve)),
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Strict materialization against a token -> value map. Every token in the
|
|
126
|
+
* content must have an entry; otherwise a MaterializeError lists ALL missing
|
|
127
|
+
* tokens (sorted), not just the first. Mapped values are not validated: at
|
|
128
|
+
* this point literal ARNs are the goal, not a mistake.
|
|
129
|
+
*/
|
|
130
|
+
export function materializeWithMap(doc, resourceMap) {
|
|
131
|
+
assertFlowDoc(doc, "materializeWithMap");
|
|
132
|
+
if (typeof resourceMap !== "object" || resourceMap === null || Array.isArray(resourceMap)) {
|
|
133
|
+
throw new InvalidFlowDocError("materializeWithMap expects a token to value map object as its second argument.");
|
|
134
|
+
}
|
|
135
|
+
const missing = collectRefs(doc.content)
|
|
136
|
+
.map((e) => e.token)
|
|
137
|
+
.filter((t) => !Object.hasOwn(resourceMap, t));
|
|
138
|
+
if (missing.length > 0)
|
|
139
|
+
throw new MaterializeError(missing);
|
|
140
|
+
const content = materialize(doc, (entry) => resourceMap[entry.token]);
|
|
141
|
+
// Completeness is not enough. collectRefs finds a token anywhere in a string
|
|
142
|
+
// while substitution only replaces a whole-value token, so an interpolated
|
|
143
|
+
// token used to satisfy the check above and then survive into deployable
|
|
144
|
+
// output as literal text that Connect would read aloud. Refusing here means
|
|
145
|
+
// render and emit, which do not run lint, cannot ship one either.
|
|
146
|
+
const leaked = [...new Set(JSON.stringify(content).match(/\$\{cdref:[^}"]*\}/g) ?? [])].sort();
|
|
147
|
+
if (leaked.length > 0) {
|
|
148
|
+
throw new MaterializeError(leaked, "Token(s) survived materialization because they are embedded in a longer string. " +
|
|
149
|
+
"A reference must be the entire field value (FlowDoc invariant 4).");
|
|
150
|
+
}
|
|
151
|
+
return content;
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Binder materialization for IaC backends (@flow-as-code/cdk). The binder returns an
|
|
155
|
+
* opaque string per reference, typically a CDK token that CloudFormation later
|
|
156
|
+
* resolves to an ARN. Output passes through exactly as returned, with no
|
|
157
|
+
* validation and no arn-shape lint (SPEC.md, Materialization).
|
|
158
|
+
*/
|
|
159
|
+
export function materializeWithBinder(doc, binder) {
|
|
160
|
+
assertFlowDoc(doc, "materializeWithBinder");
|
|
161
|
+
if (typeof binder !== "function") {
|
|
162
|
+
throw new InvalidFlowDocError("materializeWithBinder expects a binder function as its second argument.");
|
|
163
|
+
}
|
|
164
|
+
return materialize(doc, binder);
|
|
165
|
+
}
|
|
166
|
+
// --- Deterministic serialization of deployable content -----------------------
|
|
167
|
+
// Mirrors serialize.ts: fixed first-class key order, alphabetical for the
|
|
168
|
+
// rest, two-space indent, trailing newline. Byte-identical for the same
|
|
169
|
+
// content regardless of insertion order.
|
|
170
|
+
/**
|
|
171
|
+
* Canonical JSON text of deployable content, two-space indented, newline
|
|
172
|
+
* terminated. Metadata leads with EntryPointPosition then ActionMetadata,
|
|
173
|
+
* matching the Flow language example; everything nested is key-sorted.
|
|
174
|
+
*/
|
|
175
|
+
export function serializeContent(content) {
|
|
176
|
+
const canonical = ordered({
|
|
177
|
+
Version: content.Version,
|
|
178
|
+
StartAction: content.StartAction,
|
|
179
|
+
...(content.Settings === undefined ? {} : { Settings: sortKeys(content.Settings) }),
|
|
180
|
+
...(content.Metadata === undefined
|
|
181
|
+
? {}
|
|
182
|
+
: {
|
|
183
|
+
Metadata: ordered(sortKeys(content.Metadata), [
|
|
184
|
+
"EntryPointPosition",
|
|
185
|
+
"ActionMetadata",
|
|
186
|
+
]),
|
|
187
|
+
}),
|
|
188
|
+
Actions: content.Actions.map(canonicalAction),
|
|
189
|
+
}, ["Version", "StartAction", "Settings", "Metadata", "Actions"]);
|
|
190
|
+
return JSON.stringify(canonical, null, 2) + "\n";
|
|
191
|
+
}
|
|
192
|
+
//# sourceMappingURL=materialize.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"materialize.js","sourceRoot":"","sources":["../src/materialize.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/** The npm scope every package publishes under. */
|
|
2
|
+
export declare const PACKAGE_SCOPE = "@flow-as-code";
|
|
3
|
+
/** Published package names, keyed by their short names. */
|
|
4
|
+
export declare const PACKAGE_NAMES: {
|
|
5
|
+
readonly core: "@flow-as-code/core";
|
|
6
|
+
readonly cdk: "@flow-as-code/cdk";
|
|
7
|
+
readonly cli: "@flow-as-code/cli";
|
|
8
|
+
readonly tf: "@flow-as-code/tf";
|
|
9
|
+
readonly studio: "@flow-as-code/studio";
|
|
10
|
+
};
|
|
11
|
+
//# sourceMappingURL=package-names.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"package-names.d.ts","sourceRoot":"","sources":["../src/package-names.ts"],"names":[],"mappings":"AAeA,mDAAmD;AACnD,eAAO,MAAM,aAAa,kBAAkB,CAAC;AAE7C,2DAA2D;AAC3D,eAAO,MAAM,aAAa;;;;;;CAMhB,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2026 The flow-as-code Authors
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*/
|
|
5
|
+
// The one place the npm package names are written down as values.
|
|
6
|
+
//
|
|
7
|
+
// Everything that embeds a package name in its output, rather than importing
|
|
8
|
+
// it, reads it from here: codegen's default import, the cdk stack scaffold,
|
|
9
|
+
// the tf "generated by" banner, and the CLI's studio asset resolution. A
|
|
10
|
+
// rename is then one edit to PACKAGE_SCOPE plus the package.json files, and a
|
|
11
|
+
// test in core keeps this file honest against those manifests.
|
|
12
|
+
//
|
|
13
|
+
// The hosted demo build (docs/05-hosted-demo.md) aliases this module to a
|
|
14
|
+
// neutral placeholder so no package name reaches the deployed artifact.
|
|
15
|
+
/** The npm scope every package publishes under. */
|
|
16
|
+
export const PACKAGE_SCOPE = "@flow-as-code";
|
|
17
|
+
/** Published package names, keyed by their short names. */
|
|
18
|
+
export const PACKAGE_NAMES = {
|
|
19
|
+
core: `${PACKAGE_SCOPE}/core`,
|
|
20
|
+
cdk: `${PACKAGE_SCOPE}/cdk`,
|
|
21
|
+
cli: `${PACKAGE_SCOPE}/cli`,
|
|
22
|
+
tf: `${PACKAGE_SCOPE}/tf`,
|
|
23
|
+
studio: `${PACKAGE_SCOPE}/studio`,
|
|
24
|
+
};
|
|
25
|
+
//# sourceMappingURL=package-names.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"package-names.js","sourceRoot":"","sources":["../src/package-names.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,kEAAkE;AAClE,EAAE;AACF,6EAA6E;AAC7E,4EAA4E;AAC5E,yEAAyE;AACzE,8EAA8E;AAC9E,+DAA+D;AAC/D,EAAE;AACF,0EAA0E;AAC1E,wEAAwE;AAExE,mDAAmD;AACnD,MAAM,CAAC,MAAM,aAAa,GAAG,eAAe,CAAC;AAE7C,2DAA2D;AAC3D,MAAM,CAAC,MAAM,aAAa,GAAG;IAC3B,IAAI,EAAE,GAAG,aAAa,OAAO;IAC7B,GAAG,EAAE,GAAG,aAAa,MAAM;IAC3B,GAAG,EAAE,GAAG,aAAa,MAAM;IAC3B,EAAE,EAAE,GAAG,aAAa,KAAK;IACzB,MAAM,EAAE,GAAG,aAAa,SAAS;CACzB,CAAC"}
|
package/dist/refs.d.ts
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { RefEntry, RefType } from "./flowdoc.js";
|
|
2
|
+
/**
|
|
3
|
+
* A reference token, branded with the kind of resource it points at, so a
|
|
4
|
+
* queue cannot be passed where a Lambda is expected.
|
|
5
|
+
*/
|
|
6
|
+
export type Ref<T extends RefType = RefType> = string & {
|
|
7
|
+
readonly __ref: T;
|
|
8
|
+
};
|
|
9
|
+
/** A single JSONPath identifier, the dynamic alternative to a reference. */
|
|
10
|
+
export type JsonPath = string & {
|
|
11
|
+
readonly __jsonPath: true;
|
|
12
|
+
};
|
|
13
|
+
/** A value legal in a reference-bearing parameter. */
|
|
14
|
+
export type RefValue<T extends RefType> = Ref<T> | JsonPath;
|
|
15
|
+
export declare const TOKEN_PATTERN: RegExp;
|
|
16
|
+
export declare const Refs: {
|
|
17
|
+
readonly queue: (name: string) => Ref<"queue">;
|
|
18
|
+
readonly hours: (name: string) => Ref<"hours">;
|
|
19
|
+
readonly lambda: (name: string) => Ref<"lambda">;
|
|
20
|
+
readonly lex: (name: string) => Ref<"lex">;
|
|
21
|
+
readonly prompt: (name: string) => Ref<"prompt">;
|
|
22
|
+
readonly flow: (name: string) => Ref<"flow">;
|
|
23
|
+
/** Module references carry an alias so a flow can pin which version it invokes. */
|
|
24
|
+
readonly module: (name: string, alias: string) => Ref<"module">;
|
|
25
|
+
};
|
|
26
|
+
/** Wraps a JSONPath expression for use in a reference-bearing parameter. */
|
|
27
|
+
export declare function jsonPath(path: string): JsonPath;
|
|
28
|
+
export declare function isToken(value: unknown): value is Ref;
|
|
29
|
+
export declare function parseToken(value: string): RefEntry | undefined;
|
|
30
|
+
/**
|
|
31
|
+
* Derived index of every token in a document, sorted by token so the output is
|
|
32
|
+
* stable. Regenerated on save; never hand-maintained.
|
|
33
|
+
*/
|
|
34
|
+
export declare function collectRefs(value: unknown): RefEntry[];
|
|
35
|
+
//# sourceMappingURL=refs.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"refs.d.ts","sourceRoot":"","sources":["../src/refs.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAGtD;;;GAGG;AACH,MAAM,MAAM,GAAG,CAAC,CAAC,SAAS,OAAO,GAAG,OAAO,IAAI,MAAM,GAAG;IAAE,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAA;CAAE,CAAC;AAE9E,4EAA4E;AAC5E,MAAM,MAAM,QAAQ,GAAG,MAAM,GAAG;IAAE,QAAQ,CAAC,UAAU,EAAE,IAAI,CAAA;CAAE,CAAC;AAE9D,sDAAsD;AACtD,MAAM,MAAM,QAAQ,CAAC,CAAC,SAAS,OAAO,IAAI,GAAG,CAAC,CAAC,CAAC,GAAG,QAAQ,CAAC;AAE5D,eAAO,MAAM,aAAa,QAC8F,CAAC;AAsBzH,eAAO,MAAM,IAAI;2BACD,MAAM,KAAG,GAAG,CAAC,OAAO,CAAC;2BACrB,MAAM,KAAG,GAAG,CAAC,OAAO,CAAC;4BACpB,MAAM,KAAG,GAAG,CAAC,QAAQ,CAAC;yBACzB,MAAM,KAAG,GAAG,CAAC,KAAK,CAAC;4BAChB,MAAM,KAAG,GAAG,CAAC,QAAQ,CAAC;0BACxB,MAAM,KAAG,GAAG,CAAC,MAAM,CAAC;IACjC,mFAAmF;4BACpE,MAAM,SAAS,MAAM,KAAG,GAAG,CAAC,QAAQ,CAAC;CAC5C,CAAC;AAEX,4EAA4E;AAC5E,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,QAAQ,CAO/C;AAED,wBAAgB,OAAO,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,GAAG,CAEpD;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,QAAQ,GAAG,SAAS,CAO9D;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,QAAQ,EAAE,CAOtD"}
|
package/dist/refs.js
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2026 The flow-as-code Authors
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*/
|
|
5
|
+
// Reference tokens. A reference occupies an entire field value and is never
|
|
6
|
+
// interpolated into a longer string: Connect requires the fields that hold
|
|
7
|
+
// references to be "either fully static or a single valid JSONPath
|
|
8
|
+
// identifier". See conformance/flow-language/actions.md.
|
|
9
|
+
import { SLUG_PATTERN } from "./flowdoc.js";
|
|
10
|
+
export const TOKEN_PATTERN = /^\$\{cdref:(queue|hours|lambda|lex|prompt|flow|module):([a-z0-9]+(?:-[a-z0-9]+)*)(?:@([a-z0-9]+(?:-[a-z0-9]+)*))?\}$/;
|
|
11
|
+
/** Matches tokens anywhere in a string, for building the refs index. */
|
|
12
|
+
const TOKEN_SCAN = /\$\{cdref:[a-z]+:[^}]+\}/g;
|
|
13
|
+
const JSONPATH_PATTERN = /^\$\.[A-Za-z0-9_$.[\]'-]+$/;
|
|
14
|
+
function assertSlug(kind, value) {
|
|
15
|
+
if (!SLUG_PATTERN.test(value)) {
|
|
16
|
+
throw new Error(`Invalid ${kind} "${value}". Names must be lowercase words separated by single hyphens.`);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
function token(type, name, alias) {
|
|
20
|
+
assertSlug(`${type} name`, name);
|
|
21
|
+
if (alias !== undefined)
|
|
22
|
+
assertSlug("module alias", alias);
|
|
23
|
+
const suffix = alias === undefined ? "" : `@${alias}`;
|
|
24
|
+
return `\${cdref:${type}:${name}${suffix}}`;
|
|
25
|
+
}
|
|
26
|
+
export const Refs = {
|
|
27
|
+
queue: (name) => token("queue", name),
|
|
28
|
+
hours: (name) => token("hours", name),
|
|
29
|
+
lambda: (name) => token("lambda", name),
|
|
30
|
+
lex: (name) => token("lex", name),
|
|
31
|
+
prompt: (name) => token("prompt", name),
|
|
32
|
+
flow: (name) => token("flow", name),
|
|
33
|
+
/** Module references carry an alias so a flow can pin which version it invokes. */
|
|
34
|
+
module: (name, alias) => token("module", name, alias),
|
|
35
|
+
};
|
|
36
|
+
/** Wraps a JSONPath expression for use in a reference-bearing parameter. */
|
|
37
|
+
export function jsonPath(path) {
|
|
38
|
+
if (!JSONPATH_PATTERN.test(path)) {
|
|
39
|
+
throw new Error(`Invalid JSONPath "${path}". Expected a single identifier such as $.Attributes.queueId.`);
|
|
40
|
+
}
|
|
41
|
+
return path;
|
|
42
|
+
}
|
|
43
|
+
export function isToken(value) {
|
|
44
|
+
return typeof value === "string" && TOKEN_PATTERN.test(value);
|
|
45
|
+
}
|
|
46
|
+
export function parseToken(value) {
|
|
47
|
+
const m = TOKEN_PATTERN.exec(value);
|
|
48
|
+
if (!m)
|
|
49
|
+
return undefined;
|
|
50
|
+
const [, type, name, alias] = m;
|
|
51
|
+
const entry = { token: value, type: type, name: name };
|
|
52
|
+
if (alias !== undefined)
|
|
53
|
+
entry.alias = alias;
|
|
54
|
+
return entry;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Derived index of every token in a document, sorted by token so the output is
|
|
58
|
+
* stable. Regenerated on save; never hand-maintained.
|
|
59
|
+
*/
|
|
60
|
+
export function collectRefs(value) {
|
|
61
|
+
const found = new Map();
|
|
62
|
+
for (const raw of JSON.stringify(value ?? null).match(TOKEN_SCAN) ?? []) {
|
|
63
|
+
const entry = parseToken(raw);
|
|
64
|
+
if (entry)
|
|
65
|
+
found.set(entry.token, entry);
|
|
66
|
+
}
|
|
67
|
+
return [...found.values()].sort((a, b) => (a.token < b.token ? -1 : a.token > b.token ? 1 : 0));
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=refs.js.map
|
package/dist/refs.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"refs.js","sourceRoot":"","sources":["../src/refs.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { FlowAction, FlowDoc } from "./flowdoc.js";
|
|
2
|
+
/** Recursively sorts object keys. Arrays keep their order, which is meaningful. */
|
|
3
|
+
export declare function sortKeys(value: unknown): unknown;
|
|
4
|
+
/** Emits keys in the given order, then anything else alphabetically. */
|
|
5
|
+
export declare function ordered<T extends Record<string, unknown>>(value: T, keys: (keyof T)[]): T;
|
|
6
|
+
export declare function canonicalAction(a: FlowAction): FlowAction;
|
|
7
|
+
/**
|
|
8
|
+
* Canonical in-memory form. Key order below is the byte order of the output.
|
|
9
|
+
*/
|
|
10
|
+
export declare function canonicalize(doc: FlowDoc): FlowDoc;
|
|
11
|
+
/** Canonical JSON text, two-space indented, newline terminated. */
|
|
12
|
+
export declare function serialize(doc: FlowDoc): string;
|
|
13
|
+
//# sourceMappingURL=serialize.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"serialize.d.ts","sourceRoot":"","sources":["../src/serialize.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,UAAU,EAAE,OAAO,EAAe,MAAM,cAAc,CAAC;AAErE,mFAAmF;AACnF,wBAAgB,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAOhD;AAED,wEAAwE;AACxE,wBAAgB,OAAO,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,MAAM,CAAC,CAAC,EAAE,GAAG,CAAC,CASzF;AA0BD,wBAAgB,eAAe,CAAC,CAAC,EAAE,UAAU,GAAG,UAAU,CAQzD;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAsBlD;AAED,mEAAmE;AACnE,wBAAgB,SAAS,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,CAE9C"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2026 The flow-as-code Authors
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*/
|
|
5
|
+
// Deterministic serialization. Invariant 1 of the FlowDoc spec: same inputs,
|
|
6
|
+
// byte-identical output. Two authorings of the same flow must produce the same
|
|
7
|
+
// bytes, so key order is fixed rather than insertion-dependent.
|
|
8
|
+
/** Recursively sorts object keys. Arrays keep their order, which is meaningful. */
|
|
9
|
+
export function sortKeys(value) {
|
|
10
|
+
if (Array.isArray(value))
|
|
11
|
+
return value.map(sortKeys);
|
|
12
|
+
if (value === null || typeof value !== "object")
|
|
13
|
+
return value;
|
|
14
|
+
const entries = Object.entries(value).sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0);
|
|
15
|
+
return Object.fromEntries(entries.map(([k, v]) => [k, sortKeys(v)]));
|
|
16
|
+
}
|
|
17
|
+
/** Emits keys in the given order, then anything else alphabetically. */
|
|
18
|
+
export function ordered(value, keys) {
|
|
19
|
+
const out = {};
|
|
20
|
+
for (const k of keys) {
|
|
21
|
+
if (value[k] !== undefined)
|
|
22
|
+
out[k] = value[k];
|
|
23
|
+
}
|
|
24
|
+
for (const k of Object.keys(value).sort()) {
|
|
25
|
+
if (!keys.includes(k) && value[k] !== undefined)
|
|
26
|
+
out[k] = value[k];
|
|
27
|
+
}
|
|
28
|
+
return out;
|
|
29
|
+
}
|
|
30
|
+
function canonicalTransitions(t) {
|
|
31
|
+
// The arrays' ELEMENTS need canonicalizing too. Ordering only the top level
|
|
32
|
+
// copied Errors and Conditions by reference, so { ErrorType, NextAction } and
|
|
33
|
+
// { NextAction, ErrorType } serialized to different bytes: two authorings of
|
|
34
|
+
// the same flow produced different output, and downstream a different
|
|
35
|
+
// CloudFormation logical id.
|
|
36
|
+
const canonical = { ...t };
|
|
37
|
+
if (t.Errors !== undefined) {
|
|
38
|
+
canonical.Errors = t.Errors.map((e) => ordered({ ...e }, ["ErrorType", "NextAction"]));
|
|
39
|
+
}
|
|
40
|
+
if (t.Conditions !== undefined) {
|
|
41
|
+
canonical.Conditions = t.Conditions.map((c) => ordered({
|
|
42
|
+
NextAction: c.NextAction,
|
|
43
|
+
Condition: ordered({ ...c.Condition }, ["Operator", "Operands"]),
|
|
44
|
+
}, ["NextAction", "Condition"]));
|
|
45
|
+
}
|
|
46
|
+
return ordered(canonical, ["NextAction", "Errors", "Conditions"]);
|
|
47
|
+
}
|
|
48
|
+
export function canonicalAction(a) {
|
|
49
|
+
return {
|
|
50
|
+
Identifier: a.Identifier,
|
|
51
|
+
Type: a.Type,
|
|
52
|
+
// Parameters are opaque to us for GenericBlocks, so sort for stability.
|
|
53
|
+
Parameters: sortKeys(a.Parameters),
|
|
54
|
+
Transitions: canonicalTransitions(a.Transitions),
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Canonical in-memory form. Key order below is the byte order of the output.
|
|
59
|
+
*/
|
|
60
|
+
export function canonicalize(doc) {
|
|
61
|
+
const out = {
|
|
62
|
+
flowdoc: doc.flowdoc,
|
|
63
|
+
kind: doc.kind,
|
|
64
|
+
name: doc.name,
|
|
65
|
+
connectType: doc.connectType,
|
|
66
|
+
content: ordered({
|
|
67
|
+
Version: doc.content.Version,
|
|
68
|
+
StartAction: doc.content.StartAction,
|
|
69
|
+
...(doc.content.Settings === undefined ? {} : { Settings: sortKeys(doc.content.Settings) }),
|
|
70
|
+
...(doc.content.Metadata === undefined ? {} : { Metadata: sortKeys(doc.content.Metadata) }),
|
|
71
|
+
Actions: doc.content.Actions.map(canonicalAction),
|
|
72
|
+
}, ["Version", "StartAction", "Settings", "Metadata", "Actions"]),
|
|
73
|
+
};
|
|
74
|
+
if (doc.layout !== undefined)
|
|
75
|
+
out.layout = sortKeys(doc.layout);
|
|
76
|
+
if (doc.refs !== undefined)
|
|
77
|
+
out.refs = doc.refs.map((r) => ordered({ ...r }, ["token", "type", "name", "alias"]));
|
|
78
|
+
if (doc.meta !== undefined)
|
|
79
|
+
out.meta = sortKeys(doc.meta);
|
|
80
|
+
return out;
|
|
81
|
+
}
|
|
82
|
+
/** Canonical JSON text, two-space indented, newline terminated. */
|
|
83
|
+
export function serialize(doc) {
|
|
84
|
+
return JSON.stringify(canonicalize(doc), null, 2) + "\n";
|
|
85
|
+
}
|
|
86
|
+
//# sourceMappingURL=serialize.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"serialize.js","sourceRoot":"","sources":["../src/serialize.ts"],"names":[],"mappings":"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"}
|