@beehexa/hexasync-template-frontend-flow 2608.20.18 → 2608.20.32
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/dist/flow.d.ts +91 -0
- package/dist/flow.d.ts.map +1 -0
- package/dist/flow.js +237 -0
- package/dist/flow.js.map +1 -0
- package/dist/index.d.ts +23 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +23 -0
- package/dist/index.js.map +1 -0
- package/dist/liquid.d.ts +54 -0
- package/dist/liquid.d.ts.map +1 -0
- package/dist/liquid.js +75 -0
- package/dist/liquid.js.map +1 -0
- package/dist/render.d.ts +26 -0
- package/dist/render.d.ts.map +1 -0
- package/dist/render.js +73 -0
- package/dist/render.js.map +1 -0
- package/dist/routes.d.ts +117 -0
- package/dist/routes.d.ts.map +1 -0
- package/dist/routes.js +355 -0
- package/dist/routes.js.map +1 -0
- package/dist/workflows.d.ts +62 -0
- package/dist/workflows.d.ts.map +1 -0
- package/dist/workflows.js +82 -0
- package/dist/workflows.js.map +1 -0
- package/package.json +2 -2
package/dist/flow.d.ts
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { type FrontendWorkflowKey, type FrontendSurface } from './workflows.js';
|
|
2
|
+
import { type JunctionKind } from './routes.js';
|
|
3
|
+
/** Where a node came from in the authored source. Supplied by the caller; see the worker package's AC-4b note. */
|
|
4
|
+
export interface NodeLocation {
|
|
5
|
+
readonly file?: string;
|
|
6
|
+
readonly range?: {
|
|
7
|
+
readonly start: {
|
|
8
|
+
readonly line: number;
|
|
9
|
+
readonly character: number;
|
|
10
|
+
};
|
|
11
|
+
readonly end: {
|
|
12
|
+
readonly line: number;
|
|
13
|
+
readonly character: number;
|
|
14
|
+
};
|
|
15
|
+
};
|
|
16
|
+
readonly sourceText?: string;
|
|
17
|
+
}
|
|
18
|
+
export interface LocateRequest {
|
|
19
|
+
readonly workflow: FrontendWorkflowKey;
|
|
20
|
+
readonly stepKey?: string;
|
|
21
|
+
readonly address: string;
|
|
22
|
+
/**
|
|
23
|
+
* For a SYNTHESISED node: the step that produced it, and the path that reaches it (Jazz, 2026-08-17).
|
|
24
|
+
*
|
|
25
|
+
* The same pair the worker package's `LocateRequest` carries, and for the same reason — see it for the full note.
|
|
26
|
+
* `path` is relative to the step (`['metadata','then']`, `['next','else','if']`) and its tail may be synthetic, so a
|
|
27
|
+
* locator resolves the longest AUTHORED prefix.
|
|
28
|
+
*
|
|
29
|
+
* Absent for a WORKFLOW-owned junction — the START terminal and the unresolved targets every route naming one
|
|
30
|
+
* converges on. Those belong to no step, so there is no step-relative path and nothing to point a caret at; the
|
|
31
|
+
* model already declines to claim an `owner` for them.
|
|
32
|
+
*/
|
|
33
|
+
readonly ownerStepKey?: string;
|
|
34
|
+
readonly path?: readonly string[];
|
|
35
|
+
}
|
|
36
|
+
/** One node in a frontend flow. */
|
|
37
|
+
export interface FrontendFlowNode extends NodeLocation {
|
|
38
|
+
readonly address: string;
|
|
39
|
+
/**
|
|
40
|
+
* `frontend` on every node — AC-4's whole purpose.
|
|
41
|
+
*
|
|
42
|
+
* *"so no consumer can merge the two domains by accident"*. The worker package carries `runtime: 'worker'` for the
|
|
43
|
+
* same reason, and the pair only works if both sides do it.
|
|
44
|
+
*/
|
|
45
|
+
readonly runtime: 'frontend';
|
|
46
|
+
readonly workflow: FrontendWorkflowKey;
|
|
47
|
+
/** Which document declares this workflow. */
|
|
48
|
+
readonly surface: FrontendSurface;
|
|
49
|
+
readonly type?: string;
|
|
50
|
+
/** The step's human name, where it declares one — what the CLI baseline writes inside the node. */
|
|
51
|
+
readonly name?: string;
|
|
52
|
+
readonly decides: boolean;
|
|
53
|
+
readonly label?: string;
|
|
54
|
+
readonly junction?: JunctionKind;
|
|
55
|
+
readonly stepKey?: string;
|
|
56
|
+
readonly owner?: string;
|
|
57
|
+
}
|
|
58
|
+
export interface FrontendFlowEdge {
|
|
59
|
+
readonly from: string;
|
|
60
|
+
readonly to: string;
|
|
61
|
+
readonly label?: string;
|
|
62
|
+
readonly workflow: FrontendWorkflowKey;
|
|
63
|
+
}
|
|
64
|
+
/** One workflow's drawing, with its own title (AC-1). */
|
|
65
|
+
export interface FrontendWorkflowFlow {
|
|
66
|
+
readonly workflow: FrontendWorkflowKey;
|
|
67
|
+
readonly title: string;
|
|
68
|
+
readonly surface: FrontendSurface;
|
|
69
|
+
readonly address: string;
|
|
70
|
+
readonly nodes: readonly FrontendFlowNode[];
|
|
71
|
+
readonly edges: readonly FrontendFlowEdge[];
|
|
72
|
+
readonly duplicateStepKeys?: readonly string[];
|
|
73
|
+
/** Keys carrying a character the address algebra refuses, e.g. a `:`. Present only when it happened. */
|
|
74
|
+
readonly unaddressableStepKeys?: readonly string[];
|
|
75
|
+
}
|
|
76
|
+
export interface FrontendFlow {
|
|
77
|
+
readonly address: string;
|
|
78
|
+
readonly workflows: readonly FrontendWorkflowFlow[];
|
|
79
|
+
}
|
|
80
|
+
export interface FrontendFlowInput {
|
|
81
|
+
/** The parsed connector definition or template manifest. */
|
|
82
|
+
readonly document: Record<string, unknown>;
|
|
83
|
+
/** Its `id`, authored — AD-33 keeps the token rather than a composed GUID. */
|
|
84
|
+
readonly documentId?: unknown;
|
|
85
|
+
/** The collection segment the document sits under, e.g. `connectors`. */
|
|
86
|
+
readonly collection?: string;
|
|
87
|
+
readonly locate?: (request: LocateRequest) => NodeLocation | undefined;
|
|
88
|
+
}
|
|
89
|
+
/** The flow model for every frontend workflow a document declares. */
|
|
90
|
+
export declare function frontendFlow(input: FrontendFlowInput): FrontendFlow;
|
|
91
|
+
//# sourceMappingURL=flow.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"flow.d.ts","sourceRoot":"","sources":["../src/flow.ts"],"names":[],"mappings":"AAeA,OAAO,EAIL,KAAK,mBAAmB,EACxB,KAAK,eAAe,EACrB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAIL,KAAK,YAAY,EAClB,MAAM,aAAa,CAAC;AAErB,kHAAkH;AAClH,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,KAAK,CAAC,EAAE;QACf,QAAQ,CAAC,KAAK,EAAE;YAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;YAAC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;SAAE,CAAC;QACtE,QAAQ,CAAC,GAAG,EAAE;YAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;YAAC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;SAAE,CAAC;KACrE,CAAC;IACF,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,QAAQ,EAAE,mBAAmB,CAAC;IACvC,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB;;;;;;;;;;OAUG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,IAAI,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CACnC;AAED,mCAAmC;AACnC,MAAM,WAAW,gBAAiB,SAAQ,YAAY;IACpD,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB;;;;;OAKG;IACH,QAAQ,CAAC,OAAO,EAAE,UAAU,CAAC;IAC7B,QAAQ,CAAC,QAAQ,EAAE,mBAAmB,CAAC;IACvC,6CAA6C;IAC7C,QAAQ,CAAC,OAAO,EAAE,eAAe,CAAC;IAClC,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,mGAAmG;IACnG,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,QAAQ,CAAC,EAAE,YAAY,CAAC;IACjC,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,QAAQ,EAAE,mBAAmB,CAAC;CACxC;AAED,yDAAyD;AACzD,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,QAAQ,EAAE,mBAAmB,CAAC;IACvC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,OAAO,EAAE,eAAe,CAAC;IAClC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,KAAK,EAAE,SAAS,gBAAgB,EAAE,CAAC;IAC5C,QAAQ,CAAC,KAAK,EAAE,SAAS,gBAAgB,EAAE,CAAC;IAC5C,QAAQ,CAAC,iBAAiB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC/C,wGAAwG;IACxG,QAAQ,CAAC,qBAAqB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CACpD;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,SAAS,EAAE,SAAS,oBAAoB,EAAE,CAAC;CACrD;AAED,MAAM,WAAW,iBAAiB;IAChC,4DAA4D;IAC5D,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC3C,8EAA8E;IAC9E,QAAQ,CAAC,UAAU,CAAC,EAAE,OAAO,CAAC;IAC9B,yEAAyE;IACzE,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,YAAY,GAAG,SAAS,CAAC;CACxE;AAyCD,sEAAsE;AACtE,wBAAgB,YAAY,CAAC,KAAK,EAAE,iBAAiB,GAAG,YAAY,CAiBnE"}
|
package/dist/flow.js
ADDED
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A frontend workflow's flow and its node index — Story 4.2, one entry point per document.
|
|
3
|
+
*
|
|
4
|
+
* Mirrors `hexasync-template-worker-flow`'s shape on purpose: nodes and edges from one computation, AD-33 addresses on
|
|
5
|
+
* every node including synthesised ones, and source location arriving as data. What it does NOT mirror is the
|
|
6
|
+
* vocabulary — see `workflows.ts` for the four measured differences and why unifying them would be wrong.
|
|
7
|
+
*
|
|
8
|
+
* ⛔ **CORE (AD-3)**: no filesystem, no `vscode`, no Node builtin.
|
|
9
|
+
*/
|
|
10
|
+
import { keySegment, identitySegment, nodeAddress, normalizeComponentKey, } from '@beehexa/hexasync-template-model';
|
|
11
|
+
import { workflowsPresent, surfaceOf, FRONTEND_WORKFLOW_TITLES, } from './workflows.js';
|
|
12
|
+
import { frontendRouteGraph, } from './routes.js';
|
|
13
|
+
/** A step, read defensively. */
|
|
14
|
+
function stepOf(raw) {
|
|
15
|
+
if (!raw || typeof raw !== 'object' || Array.isArray(raw))
|
|
16
|
+
return undefined;
|
|
17
|
+
const step = raw;
|
|
18
|
+
/**
|
|
19
|
+
* A key is REQUIRED, and there is no positional fallback.
|
|
20
|
+
*
|
|
21
|
+
* ⚠️ The reference implementation falls back to `STEP_${index + 1}` (`connectorWorkflowMermaid.ts`'s `stepKeys`
|
|
22
|
+
* build). That is a fifth positional identity, and AD-33 exists to remove them: a keyless step would acquire an
|
|
23
|
+
* address that shifts when a step is inserted above it. A step with no key is skipped instead, exactly as the worker
|
|
24
|
+
* package does — the corpus contains one such step and it is correctly dropped there.
|
|
25
|
+
*/
|
|
26
|
+
const key = typeof step.key === 'string' ? step.key : undefined;
|
|
27
|
+
if (key === undefined || key.trim() === '')
|
|
28
|
+
return undefined;
|
|
29
|
+
// A step the composer deletes is not in the flow — the worker package's HIGH-2 finding, applied here from the start.
|
|
30
|
+
if (normalizeComponentKey(key)?.removes === true)
|
|
31
|
+
return undefined;
|
|
32
|
+
const type = typeof step.type === 'string' ? step.type : undefined;
|
|
33
|
+
return {
|
|
34
|
+
key,
|
|
35
|
+
...(step.next !== undefined ? { next: step.next } : {}),
|
|
36
|
+
...(type !== undefined ? { type } : {}),
|
|
37
|
+
...(step.metadata !== undefined ? { metadata: step.metadata } : {}),
|
|
38
|
+
...(step.onCancelled !== undefined
|
|
39
|
+
? { onCancelled: step.onCancelled }
|
|
40
|
+
: {}),
|
|
41
|
+
// The ENTRY flag. Dropped by the first version, with the whole START/entry concept (review H4).
|
|
42
|
+
...(step.root !== undefined ? { root: step.root } : {}),
|
|
43
|
+
/**
|
|
44
|
+
* The human NAME the CLI baseline labels a node with — `SHOW_CREATE_PROFILE_ERROR["Couldn't Start Profile
|
|
45
|
+
* Creation"]`. Dropped by the first version (review L1), so a renderer had only the key.
|
|
46
|
+
*/
|
|
47
|
+
...(typeof step.name === 'string' && step.name.trim() !== ''
|
|
48
|
+
? { name: step.name.trim() }
|
|
49
|
+
: {}),
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
/** The flow model for every frontend workflow a document declares. */
|
|
53
|
+
export function frontendFlow(input) {
|
|
54
|
+
const { document, documentId, collection, locate } = input;
|
|
55
|
+
const base = nodeAddress([
|
|
56
|
+
...(collection !== undefined ? [keySegment(collection)] : []),
|
|
57
|
+
identitySegment(documentId, 'id'),
|
|
58
|
+
]);
|
|
59
|
+
// Emptiness measured on what SURVIVES `stepOf`, not on raw item count — see `workflowsPresent`.
|
|
60
|
+
const workflows = workflowsPresent(document, (items) => items.reduce((count, item) => (stepOf(item) ? count + 1 : count), 0)).map((workflow) => oneWorkflow(workflow, document[workflow], base, locate));
|
|
61
|
+
return { address: base, workflows };
|
|
62
|
+
}
|
|
63
|
+
function oneWorkflow(workflow, raw, base, locate) {
|
|
64
|
+
const surface = surfaceOf(workflow);
|
|
65
|
+
/**
|
|
66
|
+
* An EMPTY base contributes nothing (Story 4.6).
|
|
67
|
+
*
|
|
68
|
+
* `collection` and `documentId` are both optional, and a caller that supplies neither — the CLI report's
|
|
69
|
+
* `creationSteps`, whose document is the composed root — leaves `base` as `''`. That used to produce a leading hole
|
|
70
|
+
* in every address: `:creationSteps:key_FORM`, rendering `__creationSteps__key_FORM`. An address with an empty
|
|
71
|
+
* segment is not a shorter address, it is a wrong one.
|
|
72
|
+
*
|
|
73
|
+
* Handled in `nodeAddress` now rather than here — a review pointed out that a `collection: ''` with a present
|
|
74
|
+
* `documentId` reproduced the same hole one segment along, so the special case fixed a symptom and left the class
|
|
75
|
+
* (Story 4.6 review, LOW-1). Written plainly again on purpose: nothing local guards it, `nodeAddress` does.
|
|
76
|
+
*/
|
|
77
|
+
const address = nodeAddress([keySegment(base), keySegment(workflow)]);
|
|
78
|
+
const nodes = [];
|
|
79
|
+
const edges = [];
|
|
80
|
+
const duplicates = [];
|
|
81
|
+
/** Keys the address algebra refused — reported rather than swallowed, like a duplicate. */
|
|
82
|
+
const unaddressable = [];
|
|
83
|
+
const steps = [];
|
|
84
|
+
for (const step of raw.map(stepOf)) {
|
|
85
|
+
if (step === undefined)
|
|
86
|
+
continue;
|
|
87
|
+
// De-duplicated for the reason the worker package records: two nodes with one address make a click resolve to
|
|
88
|
+
// nothing, and the runtime cannot address the second one either.
|
|
89
|
+
if (steps.some((s) => s.key === step.key)) {
|
|
90
|
+
duplicates.push(step.key);
|
|
91
|
+
continue;
|
|
92
|
+
}
|
|
93
|
+
steps.push(step);
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* A step whose key the ADDRESS ALGEBRA refuses is skipped (review H1).
|
|
97
|
+
*
|
|
98
|
+
* `identitySegment` returns undefined for a key carrying `:` — and `nodeAddress` DROPS an undefined segment, so the
|
|
99
|
+
* step silently inherited the workflow's own address. Two such steps then shared one address, and `addressMatches`
|
|
100
|
+
* made the phantom an ancestor of every real sibling. That is verbatim the consequence chain Story 4.1's HIGH-2
|
|
101
|
+
* records, re-opened by deduping on KEY rather than on address.
|
|
102
|
+
*
|
|
103
|
+
* 0 of 191 corpus frontend keys contain `:`, so this is structural — which is the argument `nodeAddress.ts` makes
|
|
104
|
+
* for refusing the segment in the first place.
|
|
105
|
+
*/
|
|
106
|
+
const addressOf = new Map();
|
|
107
|
+
const drawable = [];
|
|
108
|
+
for (const step of steps) {
|
|
109
|
+
const segment = identitySegment(step.key, 'key');
|
|
110
|
+
if (segment === undefined) {
|
|
111
|
+
unaddressable.push(step.key);
|
|
112
|
+
continue;
|
|
113
|
+
}
|
|
114
|
+
addressOf.set(step.key, nodeAddress([keySegment(address), segment]));
|
|
115
|
+
drawable.push(step);
|
|
116
|
+
}
|
|
117
|
+
const shared = { runtime: 'frontend', workflow, surface };
|
|
118
|
+
for (const step of drawable) {
|
|
119
|
+
const own = addressOf.get(step.key);
|
|
120
|
+
/**
|
|
121
|
+
* An `IF`/`SWITCH` STEP decides — and here that differs from the worker side, faithfully.
|
|
122
|
+
*
|
|
123
|
+
* The frontend reference routes an `IF`'s arms **straight off the step node** (`addStepEdges`: `addTargetEdge(ctx,
|
|
124
|
+
* nodeId, step.metadata.then, 'YES')`) and only synthesises a `NEXT_IF` diamond for a nested branch OBJECT. So
|
|
125
|
+
* there is no junction to carry `decides` for the common case, and the CLI's own `isDecision` — `stepType === 'IF'
|
|
126
|
+
* || 'SWITCH' || object next` — draws the STEP as the diamond.
|
|
127
|
+
*
|
|
128
|
+
* On the worker side `decides` is false on every step, because there a branch always gets its own junction. Both
|
|
129
|
+
* are right for their runtime, and getting this wrong in either direction leaves a renderer unable to tell a
|
|
130
|
+
* branch point from a plain step — which is what the first version of this file did: nothing at all was marked.
|
|
131
|
+
*/
|
|
132
|
+
/**
|
|
133
|
+
* A step is a diamond only when its ARMS LEAVE THE STEP — i.e. an `IF`/`SWITCH` routing through `metadata`.
|
|
134
|
+
*
|
|
135
|
+
* ⛔ Story 4.3 review, HIGH-2. Story 4.2's review widened this to `IF || SWITCH || object-next`, quoting the CLI's
|
|
136
|
+
* `isDecision`; but a step whose `next` is an OBJECT also gets a `…:next:if` junction, and that junction is already
|
|
137
|
+
* `decides: true`. Result on fixture 04: **9 diamonds where dashboard's baseline has 7** — `GET_LOCAL_STORAGE` and
|
|
138
|
+
* `WAIT_EXECUTION_TIME` each drawn as a diamond AND given a diamond beside them.
|
|
139
|
+
*
|
|
140
|
+
* That is exactly the defect Story 4.1's review fixed on the worker side — *"`decides` used to be true on a
|
|
141
|
+
* branching step as well, so a renderer keyed on it drew two diamonds per branch"* — left unfixed in the twin, and
|
|
142
|
+
* invisible until a renderer existed to make it visible.
|
|
143
|
+
*
|
|
144
|
+
* The two references genuinely disagree, and the disagreement resolves once junctions exist: the CLI has no
|
|
145
|
+
* junctions, so its `isDecision` must put the diamond on the step; dashboard synthesises `NEXT_IF` and draws the
|
|
146
|
+
* step as a rectangle. This model has junctions, so dashboard's split is the coherent one — and it is the baseline
|
|
147
|
+
* whose count is recorded.
|
|
148
|
+
*/
|
|
149
|
+
const type = String(step.type ?? '').toUpperCase();
|
|
150
|
+
const metadataBranches = (type === 'IF' || type === 'SWITCH') &&
|
|
151
|
+
step.metadata !== null &&
|
|
152
|
+
typeof step.metadata === 'object' &&
|
|
153
|
+
!Array.isArray(step.metadata);
|
|
154
|
+
nodes.push({
|
|
155
|
+
...shared,
|
|
156
|
+
address: own,
|
|
157
|
+
...(step.type !== undefined ? { type: step.type } : {}),
|
|
158
|
+
...(step.name !== undefined ? { name: step.name } : {}),
|
|
159
|
+
decides: metadataBranches,
|
|
160
|
+
stepKey: step.key,
|
|
161
|
+
...(locate?.({ workflow, stepKey: step.key, address: own }) ?? {}),
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
const graph = frontendRouteGraph(drawable, FRONTEND_WORKFLOW_TITLES[workflow]);
|
|
165
|
+
const junctionOf = new Map();
|
|
166
|
+
for (const point of graph.junctions) {
|
|
167
|
+
/**
|
|
168
|
+
* A junction owned by the WORKFLOW rather than by a step — the START terminal, and an unresolved target that every
|
|
169
|
+
* route naming it converges on. Its base is the workflow's address.
|
|
170
|
+
*
|
|
171
|
+
* ⚠️ Without this branch the lookup returned undefined and the node was silently `continue`d away, so the START
|
|
172
|
+
* node and every ghost vanished while their edges were dropped too. Caught by the convergence test.
|
|
173
|
+
*/
|
|
174
|
+
const owner = point.owner === '' ? address : addressOf.get(point.owner);
|
|
175
|
+
if (owner === undefined)
|
|
176
|
+
continue;
|
|
177
|
+
const own = nodeAddress([
|
|
178
|
+
keySegment(owner),
|
|
179
|
+
...point.path.map((element) => keySegment(element)),
|
|
180
|
+
]);
|
|
181
|
+
junctionOf.set(`${point.owner} ${point.path.join(' ')}`, own);
|
|
182
|
+
nodes.push({
|
|
183
|
+
...shared,
|
|
184
|
+
address: own,
|
|
185
|
+
/**
|
|
186
|
+
* An `end` is a terminal and an `unknown` is a step-shaped box; neither branches.
|
|
187
|
+
*
|
|
188
|
+
* `'expression'` DOES: a `next:` template is a decision whose arms the reader can see, so it draws as a
|
|
189
|
+
* diamond like an authored `if` (2026-08-20, reported as *"the `next` MUST ALWAYS be a diamond if it is
|
|
190
|
+
* not a step key"*). Two kinds, one shape — the kind stays distinct so a consumer can tell an authored
|
|
191
|
+
* branch from a template without reading the label.
|
|
192
|
+
*/
|
|
193
|
+
decides: point.kind === 'if' || point.kind === 'expression',
|
|
194
|
+
label: point.label,
|
|
195
|
+
junction: point.kind,
|
|
196
|
+
// A workflow-owned junction has no owning STEP to point at, and claiming one would be false.
|
|
197
|
+
...(point.owner === '' ? {} : { owner }),
|
|
198
|
+
...(locate?.({
|
|
199
|
+
workflow,
|
|
200
|
+
address: own,
|
|
201
|
+
// Withheld for a workflow-owned junction, on the same grounds `owner` is: there is no step whose document path
|
|
202
|
+
// could resolve, and handing over `''` would ask the locator to look for a step named nothing.
|
|
203
|
+
...(point.owner === ''
|
|
204
|
+
? {}
|
|
205
|
+
: { ownerStepKey: point.owner, path: point.path }),
|
|
206
|
+
}) ?? {}),
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
const endAddress = (end) => end.kind === 'step'
|
|
210
|
+
? addressOf.get(end.key)
|
|
211
|
+
: junctionOf.get(`${end.owner} ${end.path.join(' ')}`);
|
|
212
|
+
for (const edge of graph.edges) {
|
|
213
|
+
const from = endAddress(edge.from);
|
|
214
|
+
const to = endAddress(edge.to);
|
|
215
|
+
if (from === undefined || to === undefined)
|
|
216
|
+
continue;
|
|
217
|
+
edges.push({
|
|
218
|
+
from,
|
|
219
|
+
to,
|
|
220
|
+
...(edge.label !== undefined ? { label: edge.label } : {}),
|
|
221
|
+
workflow,
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
return {
|
|
225
|
+
workflow,
|
|
226
|
+
title: FRONTEND_WORKFLOW_TITLES[workflow],
|
|
227
|
+
surface,
|
|
228
|
+
address,
|
|
229
|
+
nodes,
|
|
230
|
+
edges,
|
|
231
|
+
...(duplicates.length > 0 ? { duplicateStepKeys: duplicates } : {}),
|
|
232
|
+
...(unaddressable.length > 0
|
|
233
|
+
? { unaddressableStepKeys: unaddressable }
|
|
234
|
+
: {}),
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
//# sourceMappingURL=flow.js.map
|
package/dist/flow.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"flow.js","sourceRoot":"","sources":["../src/flow.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The flow model for a frontend onboarding workflow — `creationSteps` and the five connector workflows (FR-16, FR-17).
|
|
3
|
+
*
|
|
4
|
+
* Story 4.2's own words: *"so that the frontend workflows stop being the ones nothing can draw"*. That framing needed
|
|
5
|
+
* correcting before the work started — `epic-4-ground-truth.md` records that the CLI report DOES draw `creationSteps`
|
|
6
|
+
* and dashboard draws 3 of the 5 connector workflows, but only inside a `__dev` route. The accurate claim is that **no
|
|
7
|
+
* shipped product surface draws them**, and that `connectorWorkflowMermaid.ts` is a complete reference implementation
|
|
8
|
+
* rather than a blank page.
|
|
9
|
+
*
|
|
10
|
+
* ⛔ **CORE (AD-3)**: no filesystem, no `vscode`, no Node builtin.
|
|
11
|
+
*
|
|
12
|
+
* AD-21 forbids importing the worker flow package — the two vocabularies must not be able to reach each other. ⚠️
|
|
13
|
+
* `lint:boundaries` does **not** enforce that, and this file said it did (Story 4.2 review, M4): both packages are
|
|
14
|
+
* `core` and there is no core↔core rule, so a declared cross-dependency passes it and `depcruise` alike. What enforces
|
|
15
|
+
* it is `apps/cli/src/__tests__/packageLayer.spec.ts`, which checks both manifests **and sweeps both `src/` trees** —
|
|
16
|
+
* the sweep being the part that catches a relative-path import, the shape the accident would actually take.
|
|
17
|
+
*/
|
|
18
|
+
export { CONNECTOR_WORKFLOW_KEYS, TEMPLATE_WORKFLOW_KEYS, FRONTEND_WORKFLOW_KEYS, FRONTEND_WORKFLOW_TITLES, workflowsPresent, surfaceOf, type ConnectorWorkflowKey, type TemplateWorkflowKey, type FrontendWorkflowKey, type FrontendSurface, } from './workflows.js';
|
|
19
|
+
export { frontendRouteGraph, branchArm, type FrontendStep, type FrontendRouteGraph, type Junction, type JunctionKind, type GraphEdge, type EdgeEnd, } from './routes.js';
|
|
20
|
+
export { frontendFlow, type FrontendFlow, type FrontendFlowInput, type FrontendWorkflowFlow, type FrontendFlowNode, type FrontendFlowEdge, type NodeLocation, type LocateRequest, } from './flow.js';
|
|
21
|
+
export { renderMermaid, renderMarkdown, renderDocumentMarkdown, } from './render.js';
|
|
22
|
+
export { looksLikeTemplate, templateTargets } from './liquid.js';
|
|
23
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,EACL,uBAAuB,EACvB,sBAAsB,EACtB,sBAAsB,EACtB,wBAAwB,EACxB,gBAAgB,EAChB,SAAS,EACT,KAAK,oBAAoB,EACzB,KAAK,mBAAmB,EACxB,KAAK,mBAAmB,EACxB,KAAK,eAAe,GACrB,MAAM,gBAAgB,CAAC;AAExB,OAAO,EACL,kBAAkB,EAClB,SAAS,EACT,KAAK,YAAY,EACjB,KAAK,kBAAkB,EACvB,KAAK,QAAQ,EACb,KAAK,YAAY,EACjB,KAAK,SAAS,EACd,KAAK,OAAO,GACb,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,YAAY,EACZ,KAAK,YAAY,EACjB,KAAK,iBAAiB,EACtB,KAAK,oBAAoB,EACzB,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,EACrB,KAAK,YAAY,EACjB,KAAK,aAAa,GACnB,MAAM,WAAW,CAAC;AAEnB,OAAO,EACL,aAAa,EACb,cAAc,EACd,sBAAsB,GACvB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The flow model for a frontend onboarding workflow — `creationSteps` and the five connector workflows (FR-16, FR-17).
|
|
3
|
+
*
|
|
4
|
+
* Story 4.2's own words: *"so that the frontend workflows stop being the ones nothing can draw"*. That framing needed
|
|
5
|
+
* correcting before the work started — `epic-4-ground-truth.md` records that the CLI report DOES draw `creationSteps`
|
|
6
|
+
* and dashboard draws 3 of the 5 connector workflows, but only inside a `__dev` route. The accurate claim is that **no
|
|
7
|
+
* shipped product surface draws them**, and that `connectorWorkflowMermaid.ts` is a complete reference implementation
|
|
8
|
+
* rather than a blank page.
|
|
9
|
+
*
|
|
10
|
+
* ⛔ **CORE (AD-3)**: no filesystem, no `vscode`, no Node builtin.
|
|
11
|
+
*
|
|
12
|
+
* AD-21 forbids importing the worker flow package — the two vocabularies must not be able to reach each other. ⚠️
|
|
13
|
+
* `lint:boundaries` does **not** enforce that, and this file said it did (Story 4.2 review, M4): both packages are
|
|
14
|
+
* `core` and there is no core↔core rule, so a declared cross-dependency passes it and `depcruise` alike. What enforces
|
|
15
|
+
* it is `apps/cli/src/__tests__/packageLayer.spec.ts`, which checks both manifests **and sweeps both `src/` trees** —
|
|
16
|
+
* the sweep being the part that catches a relative-path import, the shape the accident would actually take.
|
|
17
|
+
*/
|
|
18
|
+
export { CONNECTOR_WORKFLOW_KEYS, TEMPLATE_WORKFLOW_KEYS, FRONTEND_WORKFLOW_KEYS, FRONTEND_WORKFLOW_TITLES, workflowsPresent, surfaceOf, } from './workflows.js';
|
|
19
|
+
export { frontendRouteGraph, branchArm, } from './routes.js';
|
|
20
|
+
export { frontendFlow, } from './flow.js';
|
|
21
|
+
export { renderMermaid, renderMarkdown, renderDocumentMarkdown, } from './render.js';
|
|
22
|
+
export { looksLikeTemplate, templateTargets } from './liquid.js';
|
|
23
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,EACL,uBAAuB,EACvB,sBAAsB,EACtB,sBAAsB,EACtB,wBAAwB,EACxB,gBAAgB,EAChB,SAAS,GAKV,MAAM,gBAAgB,CAAC;AAExB,OAAO,EACL,kBAAkB,EAClB,SAAS,GAOV,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,YAAY,GAQb,MAAM,WAAW,CAAC;AAEnB,OAAO,EACL,aAAa,EACb,cAAc,EACd,sBAAsB,GACvB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC"}
|
package/dist/liquid.d.ts
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reading the step keys out of a Liquid `next:` template — the frontend's answer to the worker's Scriban one.
|
|
3
|
+
*
|
|
4
|
+
* ### What was undrawn, and it was recorded before it was reported
|
|
5
|
+
*
|
|
6
|
+
* `routes.ts` carried this note: *"**23 real `next` values** are Liquid templates … Both the reference and this
|
|
7
|
+
* model render each as ONE unresolved node labelled with the whole template, so ~23 genuinely reachable routes
|
|
8
|
+
* are undrawn on both sides. That is faithful, and it is a real gap."* It was deferred because *"resolving
|
|
9
|
+
* them needs its own reader and its own decision about what to draw when a branch is undecidable
|
|
10
|
+
* statically."*
|
|
11
|
+
*
|
|
12
|
+
* This is the reader. The decision came from the person reading the diagrams: *"this is actually kind of
|
|
13
|
+
* liquid syntax which has `{% ... %}` inside it, this must works similar to how scriban syntax works. and the
|
|
14
|
+
* `next` MUST ALWAYS be a diamond if it is not a step key."*
|
|
15
|
+
*
|
|
16
|
+
* ### Why splitting on the tags is the whole algorithm
|
|
17
|
+
*
|
|
18
|
+
* Liquid emits the literal text BETWEEN its tags. So in
|
|
19
|
+
* `{% assign codeSize = … %}{% if codeSize > 0 %}CHECK_PROFILE_STATUS{% else %}FILL_STORE_URL{% endif %}`
|
|
20
|
+
* the two things this template can ever produce are `CHECK_PROFILE_STATUS` and `FILL_STORE_URL` — the literal
|
|
21
|
+
* chunks — and a `next` is used as a step key verbatim. Nothing about the CONDITIONS needs understanding to
|
|
22
|
+
* know the set of possible targets, which is exactly why this does not need a Liquid engine.
|
|
23
|
+
*
|
|
24
|
+
* That is the difference from the worker: Scriban names its targets `"QUOTED"` inside the expression, so the
|
|
25
|
+
* worker reads quoted strings; Liquid names them bare, in the emitted text. Both forms are accepted here,
|
|
26
|
+
* because a `"QUOTED"` chunk costs one line and a wrong guess about which dialect a document uses costs a
|
|
27
|
+
* whole diagram.
|
|
28
|
+
*
|
|
29
|
+
* ### Measured against the corpus, 2026-08-20
|
|
30
|
+
*
|
|
31
|
+
* 20 Liquid `next` values across `LightspeedXSeries`, `SapoOmniV3PublicApp`, `ShopifyPublicApp`,
|
|
32
|
+
* `ShoplinePublicApp`, `TikTokShopGatewayV3` and `Zalo`. Every one yields 2 or 3 chunks and every chunk is a
|
|
33
|
+
* step key declared in the same workflow — see `liquid.spec.ts`, which walks the real files rather than
|
|
34
|
+
* asserting a fixture.
|
|
35
|
+
*/
|
|
36
|
+
/**
|
|
37
|
+
* Is this route text a TEMPLATE rather than a step key?
|
|
38
|
+
*
|
|
39
|
+
* Only a real tag counts. A bare unknown target (`GONE`, a typo) is not a template and must not become one:
|
|
40
|
+
* it is a broken pointer, and drawing a decision there would claim a choice the document does not make.
|
|
41
|
+
*/
|
|
42
|
+
export declare function looksLikeTemplate(text: string): boolean;
|
|
43
|
+
/**
|
|
44
|
+
* Every step key a template can emit, in the order it could emit them, without duplicates.
|
|
45
|
+
*
|
|
46
|
+
* Order matters for the diagram: the arms come out in authored order, so the arrow a reader traces first is
|
|
47
|
+
* the branch written first.
|
|
48
|
+
*
|
|
49
|
+
* A chunk that is not shaped like a step key is DROPPED rather than guessed at — `true`/`false` from a
|
|
50
|
+
* condition template, a fragment of prose, a chunk with spaces. The caller drops anything that is not a
|
|
51
|
+
* declared step on top of that, so a plausible-looking chunk still cannot invent a node.
|
|
52
|
+
*/
|
|
53
|
+
export declare function templateTargets(text: string): readonly string[];
|
|
54
|
+
//# sourceMappingURL=liquid.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"liquid.d.ts","sourceRoot":"","sources":["../src/liquid.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAQH;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEvD;AAED;;;;;;;;;GASG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,CAa/D"}
|
package/dist/liquid.js
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reading the step keys out of a Liquid `next:` template — the frontend's answer to the worker's Scriban one.
|
|
3
|
+
*
|
|
4
|
+
* ### What was undrawn, and it was recorded before it was reported
|
|
5
|
+
*
|
|
6
|
+
* `routes.ts` carried this note: *"**23 real `next` values** are Liquid templates … Both the reference and this
|
|
7
|
+
* model render each as ONE unresolved node labelled with the whole template, so ~23 genuinely reachable routes
|
|
8
|
+
* are undrawn on both sides. That is faithful, and it is a real gap."* It was deferred because *"resolving
|
|
9
|
+
* them needs its own reader and its own decision about what to draw when a branch is undecidable
|
|
10
|
+
* statically."*
|
|
11
|
+
*
|
|
12
|
+
* This is the reader. The decision came from the person reading the diagrams: *"this is actually kind of
|
|
13
|
+
* liquid syntax which has `{% ... %}` inside it, this must works similar to how scriban syntax works. and the
|
|
14
|
+
* `next` MUST ALWAYS be a diamond if it is not a step key."*
|
|
15
|
+
*
|
|
16
|
+
* ### Why splitting on the tags is the whole algorithm
|
|
17
|
+
*
|
|
18
|
+
* Liquid emits the literal text BETWEEN its tags. So in
|
|
19
|
+
* `{% assign codeSize = … %}{% if codeSize > 0 %}CHECK_PROFILE_STATUS{% else %}FILL_STORE_URL{% endif %}`
|
|
20
|
+
* the two things this template can ever produce are `CHECK_PROFILE_STATUS` and `FILL_STORE_URL` — the literal
|
|
21
|
+
* chunks — and a `next` is used as a step key verbatim. Nothing about the CONDITIONS needs understanding to
|
|
22
|
+
* know the set of possible targets, which is exactly why this does not need a Liquid engine.
|
|
23
|
+
*
|
|
24
|
+
* That is the difference from the worker: Scriban names its targets `"QUOTED"` inside the expression, so the
|
|
25
|
+
* worker reads quoted strings; Liquid names them bare, in the emitted text. Both forms are accepted here,
|
|
26
|
+
* because a `"QUOTED"` chunk costs one line and a wrong guess about which dialect a document uses costs a
|
|
27
|
+
* whole diagram.
|
|
28
|
+
*
|
|
29
|
+
* ### Measured against the corpus, 2026-08-20
|
|
30
|
+
*
|
|
31
|
+
* 20 Liquid `next` values across `LightspeedXSeries`, `SapoOmniV3PublicApp`, `ShopifyPublicApp`,
|
|
32
|
+
* `ShoplinePublicApp`, `TikTokShopGatewayV3` and `Zalo`. Every one yields 2 or 3 chunks and every chunk is a
|
|
33
|
+
* step key declared in the same workflow — see `liquid.spec.ts`, which walks the real files rather than
|
|
34
|
+
* asserting a fixture.
|
|
35
|
+
*/
|
|
36
|
+
/** Both tag forms, so a document written in either dialect reads correctly. */
|
|
37
|
+
const TAGS = /\{%[\s\S]*?%\}|\{\{[\s\S]*?\}\}/g;
|
|
38
|
+
/** A step key: what `key:` accepts, and what a `next` is compared against. */
|
|
39
|
+
const STEP_KEY = /^[A-Za-z0-9_]+$/;
|
|
40
|
+
/**
|
|
41
|
+
* Is this route text a TEMPLATE rather than a step key?
|
|
42
|
+
*
|
|
43
|
+
* Only a real tag counts. A bare unknown target (`GONE`, a typo) is not a template and must not become one:
|
|
44
|
+
* it is a broken pointer, and drawing a decision there would claim a choice the document does not make.
|
|
45
|
+
*/
|
|
46
|
+
export function looksLikeTemplate(text) {
|
|
47
|
+
return /\{%[\s\S]*?%\}/.test(text) || /\{\{[\s\S]*?\}\}/.test(text);
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Every step key a template can emit, in the order it could emit them, without duplicates.
|
|
51
|
+
*
|
|
52
|
+
* Order matters for the diagram: the arms come out in authored order, so the arrow a reader traces first is
|
|
53
|
+
* the branch written first.
|
|
54
|
+
*
|
|
55
|
+
* A chunk that is not shaped like a step key is DROPPED rather than guessed at — `true`/`false` from a
|
|
56
|
+
* condition template, a fragment of prose, a chunk with spaces. The caller drops anything that is not a
|
|
57
|
+
* declared step on top of that, so a plausible-looking chunk still cannot invent a node.
|
|
58
|
+
*/
|
|
59
|
+
export function templateTargets(text) {
|
|
60
|
+
const out = [];
|
|
61
|
+
const add = (candidate) => {
|
|
62
|
+
const value = candidate.trim();
|
|
63
|
+
if (value === '' || !STEP_KEY.test(value) || out.includes(value))
|
|
64
|
+
return;
|
|
65
|
+
out.push(value);
|
|
66
|
+
};
|
|
67
|
+
// The literal chunks — what Liquid actually emits.
|
|
68
|
+
for (const chunk of text.split(TAGS))
|
|
69
|
+
add(chunk);
|
|
70
|
+
// And any `"QUOTED"` key inside a tag, which is how the Scriban dialect names one.
|
|
71
|
+
for (const match of text.matchAll(/"([A-Za-z0-9_]+)"/g))
|
|
72
|
+
add(match[1]);
|
|
73
|
+
return out;
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=liquid.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"liquid.js","sourceRoot":"","sources":["../src/liquid.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAEH,+EAA+E;AAC/E,MAAM,IAAI,GAAG,kCAAkC,CAAC;AAEhD,8EAA8E;AAC9E,MAAM,QAAQ,GAAG,iBAAiB,CAAC;AAEnC;;;;;GAKG;AACH,MAAM,UAAU,iBAAiB,CAAC,IAAY;IAC5C,OAAO,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,kBAAkB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACtE,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,eAAe,CAAC,IAAY;IAC1C,MAAM,GAAG,GAAa,EAAE,CAAC;IACzB,MAAM,GAAG,GAAG,CAAC,SAAiB,EAAQ,EAAE;QACtC,MAAM,KAAK,GAAG,SAAS,CAAC,IAAI,EAAE,CAAC;QAC/B,IAAI,KAAK,KAAK,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC;YAAE,OAAO;QACzE,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAClB,CAAC,CAAC;IAEF,mDAAmD;IACnD,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC;QAAE,GAAG,CAAC,KAAK,CAAC,CAAC;IACjD,mFAAmF;IACnF,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,QAAQ,CAAC,oBAAoB,CAAC;QAAE,GAAG,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC,CAAC;IACxE,OAAO,GAAG,CAAC;AACb,CAAC"}
|
package/dist/render.d.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `renderMermaid` / `renderMarkdown` for a frontend workflow — Story 4.3, `PACKAGE-CONTRACT.md` §5.
|
|
3
|
+
*
|
|
4
|
+
* Thin, for the same reason as its worker twin: the emission rules live in `hexasync-template-model`, which is the one
|
|
5
|
+
* package both may import (AD-21). This file says what a FRONTEND node looks like — and the differences from the worker
|
|
6
|
+
* side are real, not incidental.
|
|
7
|
+
*/
|
|
8
|
+
import { type RenderOptions } from '@beehexa/hexasync-template-model';
|
|
9
|
+
import type { FrontendWorkflowFlow, FrontendFlow } from './flow.js';
|
|
10
|
+
/** ONE workflow, which is what a diagram shows — a document with five of them is five diagrams, not one. */
|
|
11
|
+
export declare function renderMermaid(one: FrontendWorkflowFlow, opts?: RenderOptions): string;
|
|
12
|
+
/** Markdown for one workflow — `(flow, opts)`, the same shape as the worker twin (review MEDIUM-1). */
|
|
13
|
+
export declare function renderMarkdown(one: FrontendWorkflowFlow, opts?: RenderOptions & {
|
|
14
|
+
readonly title?: string;
|
|
15
|
+
}): string;
|
|
16
|
+
/**
|
|
17
|
+
* Every workflow a document declares, each its own titled section.
|
|
18
|
+
*
|
|
19
|
+
* A connector definition carries up to five, and `epic-4-ground-truth.md` records that no shipped surface draws any of
|
|
20
|
+
* them — so a document-level entry point is what makes the set usable rather than a per-workflow call a consumer has
|
|
21
|
+
* to discover.
|
|
22
|
+
*/
|
|
23
|
+
export declare function renderDocumentMarkdown(flow: FrontendFlow, opts?: RenderOptions & {
|
|
24
|
+
readonly title?: string;
|
|
25
|
+
}): string;
|
|
26
|
+
//# sourceMappingURL=render.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../src/render.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAKL,KAAK,aAAa,EACnB,MAAM,kCAAkC,CAAC;AAC1C,OAAO,KAAK,EAAE,oBAAoB,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAiCpE,4GAA4G;AAC5G,wBAAgB,aAAa,CAC3B,GAAG,EAAE,oBAAoB,EACzB,IAAI,GAAE,aAAkB,GACvB,MAAM,CAOR;AAED,uGAAuG;AACvG,wBAAgB,cAAc,CAC5B,GAAG,EAAE,oBAAoB,EACzB,IAAI,GAAE,aAAa,GAAG;IAAE,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAO,GACrD,MAAM,CAUR;AAED;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,YAAY,EAClB,IAAI,GAAE,aAAa,GAAG;IAAE,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAO,GACrD,MAAM,CAWR"}
|