@pfdsl/core 0.0.1
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 +150 -0
- package/dist/index.d.ts +432 -0
- package/dist/index.js +2386 -0
- package/package.json +35 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 takasek
|
|
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
ADDED
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
# @pfdsl/core
|
|
2
|
+
|
|
3
|
+
Core pipeline for the PFDSL process-flow DSL: lex → parse → normalize → build graph → validate → sort → format.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pnpm add @pfdsl/core
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Requires Node ≥ 18 (ESM only).
|
|
12
|
+
|
|
13
|
+
## Quick start
|
|
14
|
+
|
|
15
|
+
```ts
|
|
16
|
+
import { format } from '@pfdsl/core';
|
|
17
|
+
|
|
18
|
+
const source = `
|
|
19
|
+
[requirement, constraint] >> design -> spec
|
|
20
|
+
spec >>? design
|
|
21
|
+
`;
|
|
22
|
+
|
|
23
|
+
const { output, diagnostics } = format(source);
|
|
24
|
+
const errors = diagnostics.filter(d => d.severity === 'error');
|
|
25
|
+
|
|
26
|
+
if (errors.length === 0) {
|
|
27
|
+
console.log(output);
|
|
28
|
+
}
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
`format()` is idempotent: `format(format(x).output).output === format(x).output`.
|
|
32
|
+
|
|
33
|
+
## API
|
|
34
|
+
|
|
35
|
+
### `format(source: string): FormatResult`
|
|
36
|
+
|
|
37
|
+
Run the full pipeline and return canonical text plus all diagnostics.
|
|
38
|
+
|
|
39
|
+
```ts
|
|
40
|
+
interface FormatResult {
|
|
41
|
+
output: string; // canonical edge list, one edge per line
|
|
42
|
+
diagnostics: Diagnostic[]; // frontmatter + lex + parse + normalize + validate
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### Stage-by-stage API
|
|
47
|
+
|
|
48
|
+
For tools that need intermediate state (LSP, exporters):
|
|
49
|
+
|
|
50
|
+
```ts
|
|
51
|
+
import {
|
|
52
|
+
parse, // source → { document, frontmatter, diagnostics }
|
|
53
|
+
normalizeDocument, // document → { edges, nodeKinds, diagnostics }
|
|
54
|
+
buildGraph, // edges → graph (primary + feedback + nodes)
|
|
55
|
+
validateGraph, // graph → diagnostics
|
|
56
|
+
sortEdges, // edges + graph → canonically sorted edges
|
|
57
|
+
formatEdges, // sorted edges → text
|
|
58
|
+
} from '@pfdsl/core';
|
|
59
|
+
|
|
60
|
+
const { document, frontmatter, diagnostics: parseDiags } = parse(source);
|
|
61
|
+
const { edges, nodeKinds } = normalizeDocument(document, frontmatter);
|
|
62
|
+
const graph = buildGraph(edges, nodeKinds);
|
|
63
|
+
const validateDiags = validateGraph(edges, graph, frontmatter);
|
|
64
|
+
const sorted = sortEdges(edges, graph);
|
|
65
|
+
const text = formatEdges(sorted);
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
All AST / token / diagnostic / graph types are exported as type-only.
|
|
69
|
+
|
|
70
|
+
## DSL syntax (cheat sheet)
|
|
71
|
+
|
|
72
|
+
```pfdsl
|
|
73
|
+
--- # optional YAML frontmatter
|
|
74
|
+
artifact:
|
|
75
|
+
spec:
|
|
76
|
+
label: 仕様書
|
|
77
|
+
process:
|
|
78
|
+
design:
|
|
79
|
+
label: 設計
|
|
80
|
+
build:
|
|
81
|
+
label: 実装
|
|
82
|
+
parts: [design] # composition (build is decomposed into design)
|
|
83
|
+
---
|
|
84
|
+
|
|
85
|
+
# Edges
|
|
86
|
+
A >> P # A is input to process P
|
|
87
|
+
P -> B # P produces artifact B
|
|
88
|
+
A >>? P # feedback edge (semantic only)
|
|
89
|
+
|
|
90
|
+
# Chain
|
|
91
|
+
A >> P -> B >> Q -> C # A→P→B→Q→C, multiple segments
|
|
92
|
+
|
|
93
|
+
# Set notation (Cartesian product)
|
|
94
|
+
[a, b] >> P -> [x, y] # 2 inputs × 2 outputs = 4 edges
|
|
95
|
+
|
|
96
|
+
# Line continuation
|
|
97
|
+
[a, b, c]
|
|
98
|
+
>> P -> result # leading-op continuation OK
|
|
99
|
+
A >> P
|
|
100
|
+
-> B # continuation before -> OK
|
|
101
|
+
|
|
102
|
+
# Comments and blank lines
|
|
103
|
+
# this is a comment
|
|
104
|
+
[a, b] # blank line below would terminate the statement
|
|
105
|
+
>> P -> X
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
Full grammar and validation rules: see [docs/spec/spec.md](../../docs/spec/spec.md).
|
|
109
|
+
|
|
110
|
+
## Diagnostics
|
|
111
|
+
|
|
112
|
+
Errors and warnings are returned in `diagnostics` arrays, never thrown.
|
|
113
|
+
Each diagnostic carries:
|
|
114
|
+
|
|
115
|
+
```ts
|
|
116
|
+
interface Diagnostic {
|
|
117
|
+
severity: 'error' | 'warning' | 'info';
|
|
118
|
+
code: string; // FM001, L001, P005, N002, V003, ...
|
|
119
|
+
message: string;
|
|
120
|
+
range: { start: Position; end: Position };
|
|
121
|
+
}
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
Code prefixes: `FM` frontmatter, `L` lexer, `P` parser, `N` normalizer, `V` validator.
|
|
125
|
+
|
|
126
|
+
## Validation rules
|
|
127
|
+
|
|
128
|
+
- **V001** Each artifact must have at most one producing process (single source).
|
|
129
|
+
- **V002 / V003** Every process must have ≥1 input and ≥1 output.
|
|
130
|
+
- **V004 – V006** `parts:` declarations must reference processes, must not self-reference, and must not form cycles.
|
|
131
|
+
|
|
132
|
+
## Canonical ordering
|
|
133
|
+
|
|
134
|
+
`sortEdges` produces a stable order independent of input ordering:
|
|
135
|
+
|
|
136
|
+
1. Connected component (by smallest node ID in component)
|
|
137
|
+
2. Topological rank (longest path from a source artifact)
|
|
138
|
+
3. Edge kind (`input` < `feedback` < `output`)
|
|
139
|
+
4. Lexicographic tiebreak
|
|
140
|
+
|
|
141
|
+
This makes `format()` output suitable for diffing and version control.
|
|
142
|
+
|
|
143
|
+
## Development
|
|
144
|
+
|
|
145
|
+
```bash
|
|
146
|
+
pnpm install
|
|
147
|
+
pnpm --filter @pfdsl/core build
|
|
148
|
+
pnpm --filter @pfdsl/core test
|
|
149
|
+
pnpm --filter @pfdsl/core typecheck
|
|
150
|
+
```
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,432 @@
|
|
|
1
|
+
type TokenType = "ARROW_FEEDBACK" | "ARROW_INPUT" | "ARROW_OUTPUT" | "LBRACKET" | "RBRACKET" | "COMMA" | "SEMICOLON" | "NEWLINE" | "COMMENT" | "ID" | "EOF";
|
|
2
|
+
interface Position {
|
|
3
|
+
line: number;
|
|
4
|
+
column: number;
|
|
5
|
+
offset: number;
|
|
6
|
+
}
|
|
7
|
+
interface Token {
|
|
8
|
+
type: TokenType;
|
|
9
|
+
value: string;
|
|
10
|
+
raw: string;
|
|
11
|
+
start: Position;
|
|
12
|
+
end: Position;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
type DiagnosticSeverity = "error" | "warning" | "info";
|
|
16
|
+
interface Range {
|
|
17
|
+
start: Position;
|
|
18
|
+
end: Position;
|
|
19
|
+
}
|
|
20
|
+
interface Diagnostic {
|
|
21
|
+
severity: DiagnosticSeverity;
|
|
22
|
+
code: string;
|
|
23
|
+
message: string;
|
|
24
|
+
range: Range;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
declare const STATUS_VALUES: readonly ["done", "wip", "todo", "blocked"];
|
|
28
|
+
type Status = (typeof STATUS_VALUES)[number];
|
|
29
|
+
declare const STYLE_ATTRS: readonly ["fillcolor", "color", "fontcolor", "style", "penwidth"];
|
|
30
|
+
type StyleAttr = (typeof STYLE_ATTRS)[number];
|
|
31
|
+
type NodeStyle = Partial<Record<StyleAttr, string>>;
|
|
32
|
+
interface ArtifactMeta {
|
|
33
|
+
label?: string;
|
|
34
|
+
description?: string;
|
|
35
|
+
owner?: string;
|
|
36
|
+
externalStakeholders?: string[];
|
|
37
|
+
parts?: string[];
|
|
38
|
+
/** Optional positive-integer node index (pfd-tools D{index}). Namespace independent from processes. */
|
|
39
|
+
index?: number;
|
|
40
|
+
status?: Status;
|
|
41
|
+
tags?: string[];
|
|
42
|
+
group?: string;
|
|
43
|
+
criteria?: string;
|
|
44
|
+
location?: string | string[];
|
|
45
|
+
revises?: string;
|
|
46
|
+
[key: string]: unknown;
|
|
47
|
+
}
|
|
48
|
+
interface ProcessMeta {
|
|
49
|
+
label?: string;
|
|
50
|
+
description?: string;
|
|
51
|
+
owner?: string;
|
|
52
|
+
externalStakeholders?: string[];
|
|
53
|
+
/** Optional positive-integer node index (pfd-tools P{index}). Namespace independent from artifacts. */
|
|
54
|
+
index?: number;
|
|
55
|
+
group?: string;
|
|
56
|
+
tags?: string[];
|
|
57
|
+
command?: string;
|
|
58
|
+
/** Relative path to a child .pfdsl expanded as a subflow view-link (§2.9.3). */
|
|
59
|
+
subflow?: string;
|
|
60
|
+
/** Optional 1:1 boundary rename map (parent id → child id) for a subflow (§2.9.3). */
|
|
61
|
+
boundary?: Record<string, string>;
|
|
62
|
+
[key: string]: unknown;
|
|
63
|
+
}
|
|
64
|
+
interface GroupMeta {
|
|
65
|
+
label?: string;
|
|
66
|
+
color?: string;
|
|
67
|
+
parent?: string;
|
|
68
|
+
[key: string]: unknown;
|
|
69
|
+
}
|
|
70
|
+
interface TagMeta {
|
|
71
|
+
label?: string;
|
|
72
|
+
description?: string;
|
|
73
|
+
style?: NodeStyle;
|
|
74
|
+
[key: string]: unknown;
|
|
75
|
+
}
|
|
76
|
+
interface Frontmatter {
|
|
77
|
+
title?: string;
|
|
78
|
+
version?: string | number;
|
|
79
|
+
dslVersion?: string;
|
|
80
|
+
description?: string;
|
|
81
|
+
tags?: string[];
|
|
82
|
+
layout?: {
|
|
83
|
+
direction?: "LR" | "RL" | "TB" | "BT";
|
|
84
|
+
maxWidth?: number;
|
|
85
|
+
[key: string]: unknown;
|
|
86
|
+
};
|
|
87
|
+
artifact?: Record<string, ArtifactMeta>;
|
|
88
|
+
process?: Record<string, ProcessMeta>;
|
|
89
|
+
group?: Record<string, GroupMeta>;
|
|
90
|
+
tag?: Record<string, TagMeta>;
|
|
91
|
+
statusStyles?: Partial<Record<Status, NodeStyle>>;
|
|
92
|
+
/** Relative path(s) to preset file(s) inherited for presentation keys (§2.9.4). */
|
|
93
|
+
extends?: string | string[];
|
|
94
|
+
[key: string]: unknown;
|
|
95
|
+
}
|
|
96
|
+
interface LoadResult {
|
|
97
|
+
frontmatter: Frontmatter | null;
|
|
98
|
+
body: string;
|
|
99
|
+
bodyStartLine: number;
|
|
100
|
+
diagnostics: Diagnostic[];
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
interface IdNode {
|
|
104
|
+
type: "id";
|
|
105
|
+
value: string;
|
|
106
|
+
raw: string;
|
|
107
|
+
start: Position;
|
|
108
|
+
end: Position;
|
|
109
|
+
}
|
|
110
|
+
interface ArtifactExpr {
|
|
111
|
+
type: "artifact-expr";
|
|
112
|
+
ids: IdNode[];
|
|
113
|
+
start: Position;
|
|
114
|
+
end: Position;
|
|
115
|
+
}
|
|
116
|
+
interface ChainSegment {
|
|
117
|
+
op: ">>" | ">>?";
|
|
118
|
+
process: IdNode;
|
|
119
|
+
/** null when chain ends with bare `>> process` (output defined elsewhere) */
|
|
120
|
+
output: ArtifactExpr | null;
|
|
121
|
+
}
|
|
122
|
+
interface ChainStatement {
|
|
123
|
+
type: "chain";
|
|
124
|
+
head: ArtifactExpr;
|
|
125
|
+
segments: ChainSegment[];
|
|
126
|
+
start: Position;
|
|
127
|
+
end: Position;
|
|
128
|
+
}
|
|
129
|
+
interface InputEdgeStatement {
|
|
130
|
+
type: "input-edge";
|
|
131
|
+
artifact: ArtifactExpr;
|
|
132
|
+
process: IdNode;
|
|
133
|
+
start: Position;
|
|
134
|
+
end: Position;
|
|
135
|
+
}
|
|
136
|
+
interface FeedbackEdgeStatement {
|
|
137
|
+
type: "feedback-edge";
|
|
138
|
+
artifact: ArtifactExpr;
|
|
139
|
+
process: IdNode;
|
|
140
|
+
start: Position;
|
|
141
|
+
end: Position;
|
|
142
|
+
}
|
|
143
|
+
interface OutputEdgeStatement {
|
|
144
|
+
type: "output-edge";
|
|
145
|
+
process: IdNode;
|
|
146
|
+
artifact: ArtifactExpr;
|
|
147
|
+
start: Position;
|
|
148
|
+
end: Position;
|
|
149
|
+
}
|
|
150
|
+
interface NodeDeclStatement {
|
|
151
|
+
type: "node-decl";
|
|
152
|
+
id: IdNode;
|
|
153
|
+
start: Position;
|
|
154
|
+
end: Position;
|
|
155
|
+
}
|
|
156
|
+
type Statement = ChainStatement | InputEdgeStatement | FeedbackEdgeStatement | OutputEdgeStatement | NodeDeclStatement;
|
|
157
|
+
interface Document {
|
|
158
|
+
type: "document";
|
|
159
|
+
statements: Statement[];
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
type NormalizedEdge = {
|
|
163
|
+
kind: "input";
|
|
164
|
+
artifact: string;
|
|
165
|
+
process: string;
|
|
166
|
+
} | {
|
|
167
|
+
kind: "feedback";
|
|
168
|
+
artifact: string;
|
|
169
|
+
process: string;
|
|
170
|
+
} | {
|
|
171
|
+
kind: "output";
|
|
172
|
+
process: string;
|
|
173
|
+
artifact: string;
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
type NodeKind = "artifact" | "process" | "group";
|
|
177
|
+
interface PrimaryEdge {
|
|
178
|
+
from: string;
|
|
179
|
+
to: string;
|
|
180
|
+
kind: "input" | "output";
|
|
181
|
+
}
|
|
182
|
+
interface FeedbackEdge {
|
|
183
|
+
artifact: string;
|
|
184
|
+
process: string;
|
|
185
|
+
}
|
|
186
|
+
interface Graph {
|
|
187
|
+
nodes: Map<string, NodeKind>;
|
|
188
|
+
primaryEdges: PrimaryEdge[];
|
|
189
|
+
feedbackEdges: FeedbackEdge[];
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
interface AuditResult {
|
|
193
|
+
/** Artifacts produced by a process but not consumed by any process */
|
|
194
|
+
terminals: string[];
|
|
195
|
+
/** Artifacts consumed by a process but not produced by any process */
|
|
196
|
+
externalInputs: string[];
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Inspect the primary graph for terminal artifacts and external inputs.
|
|
200
|
+
*
|
|
201
|
+
* Feedback edges are ignored: only `input` and `output` edges count as
|
|
202
|
+
* production/consumption in the primary graph.
|
|
203
|
+
*
|
|
204
|
+
* Artifacts with a non-empty `externalStakeholders` list are treated as
|
|
205
|
+
* having an external consumer and are excluded from terminals.
|
|
206
|
+
*/
|
|
207
|
+
declare function auditGraph(edges: NormalizedEdge[], nodeKinds: Map<string, NodeKind>, artifactMeta?: Record<string, ArtifactMeta>): AuditResult;
|
|
208
|
+
|
|
209
|
+
declare function formatEdges(sortedEdges: NormalizedEdge[], sortedIsolated?: string[]): string;
|
|
210
|
+
declare function formatAsFlows(sortedEdges: NormalizedEdge[], sortedIsolated?: string[]): string;
|
|
211
|
+
|
|
212
|
+
declare function loadFrontmatter(source: string): LoadResult;
|
|
213
|
+
|
|
214
|
+
declare function buildGraph(edges: NormalizedEdge[], nodeKinds: Map<string, NodeKind>): Graph;
|
|
215
|
+
|
|
216
|
+
interface NormalizeResult {
|
|
217
|
+
edges: NormalizedEdge[];
|
|
218
|
+
nodeKinds: Map<string, "artifact" | "process" | "group">;
|
|
219
|
+
isolatedNodes: Set<string>;
|
|
220
|
+
diagnostics: Diagnostic[];
|
|
221
|
+
}
|
|
222
|
+
declare function normalize(doc: Document, fm: Frontmatter | null): NormalizeResult;
|
|
223
|
+
|
|
224
|
+
declare function sortIsolated(isolatedNodes: Set<string>): string[];
|
|
225
|
+
declare function sortEdges(edges: NormalizedEdge[], graph: Graph): NormalizedEdge[];
|
|
226
|
+
|
|
227
|
+
interface ValidateOptions {
|
|
228
|
+
strict?: boolean;
|
|
229
|
+
source?: string;
|
|
230
|
+
}
|
|
231
|
+
declare function validate(edges: NormalizedEdge[], nodeKinds: Map<string, NodeKind>, fm: Frontmatter | null, options?: ValidateOptions): Diagnostic[];
|
|
232
|
+
|
|
233
|
+
interface DiffReport {
|
|
234
|
+
addedNodes: string[];
|
|
235
|
+
removedNodes: string[];
|
|
236
|
+
changedNodes: string[];
|
|
237
|
+
addedEdges: string[];
|
|
238
|
+
removedEdges: string[];
|
|
239
|
+
addedFeedback: string[];
|
|
240
|
+
removedFeedback: string[];
|
|
241
|
+
}
|
|
242
|
+
declare function diffGraphs(a: Graph, b: Graph, fmA?: Frontmatter | null, fmB?: Frontmatter | null): DiffReport;
|
|
243
|
+
|
|
244
|
+
declare const ID_PATTERN: RegExp;
|
|
245
|
+
interface LexResult {
|
|
246
|
+
tokens: Token[];
|
|
247
|
+
diagnostics: Diagnostic[];
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
interface ParseResult {
|
|
251
|
+
document: Document;
|
|
252
|
+
diagnostics: Diagnostic[];
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
interface IndexChange {
|
|
256
|
+
kind: NodeKind;
|
|
257
|
+
id: string;
|
|
258
|
+
/** Existing index, or null when the node had none. */
|
|
259
|
+
from: number | null;
|
|
260
|
+
to: number;
|
|
261
|
+
}
|
|
262
|
+
interface ReindexResult {
|
|
263
|
+
/** Source with index: assignments applied (unchanged on error). */
|
|
264
|
+
output: string;
|
|
265
|
+
/** Nodes whose index was assigned or changed (unchanged ones omitted). */
|
|
266
|
+
changes: IndexChange[];
|
|
267
|
+
diagnostics: Diagnostic[];
|
|
268
|
+
}
|
|
269
|
+
interface ReindexOptions {
|
|
270
|
+
/** Reassign every node from 1 (default: keep existing, fill only gaps). */
|
|
271
|
+
renumber?: boolean;
|
|
272
|
+
}
|
|
273
|
+
/**
|
|
274
|
+
* Assign integer `index:` values to nodes in topological order, with
|
|
275
|
+
* independent counters for processes and artifacts. Default mode fills only
|
|
276
|
+
* nodes lacking an index; `renumber` reassigns all from 1. Edits are applied
|
|
277
|
+
* surgically to the front matter text to preserve comments and formatting.
|
|
278
|
+
*/
|
|
279
|
+
declare function reindex(source: string, opts?: ReindexOptions): ReindexResult;
|
|
280
|
+
|
|
281
|
+
type SortKey = "index" | "topological" | "group" | "id";
|
|
282
|
+
interface SortOptions {
|
|
283
|
+
by: SortKey[];
|
|
284
|
+
}
|
|
285
|
+
interface SortResult {
|
|
286
|
+
output: string;
|
|
287
|
+
changed: boolean;
|
|
288
|
+
diagnostics: Diagnostic[];
|
|
289
|
+
}
|
|
290
|
+
declare function sort(source: string, opts: SortOptions): SortResult;
|
|
291
|
+
|
|
292
|
+
declare function resolveMeta(fm: Frontmatter | null | undefined, kind: "artifact", id: string): ArtifactMeta | undefined;
|
|
293
|
+
declare function resolveMeta(fm: Frontmatter | null | undefined, kind: "process", id: string): ProcessMeta | undefined;
|
|
294
|
+
declare function resolveMeta(fm: Frontmatter | null | undefined, kind: "group", id: string): GroupMeta | undefined;
|
|
295
|
+
declare function resolveMeta(fm: Frontmatter | null | undefined, kind: "artifact" | "process", id: string): ArtifactMeta | ProcessMeta | undefined;
|
|
296
|
+
declare function resolveMeta(fm: Frontmatter | null | undefined, kind: NodeKind, id: string): ArtifactMeta | ProcessMeta | GroupMeta | undefined;
|
|
297
|
+
|
|
298
|
+
/**
|
|
299
|
+
* Result of resolving a cross-file reference (`subflow:` / `extends:`).
|
|
300
|
+
* Relative paths resolve against the containing file's directory (§2.9.2).
|
|
301
|
+
* Absolute paths and URLs are rejected.
|
|
302
|
+
*/
|
|
303
|
+
type RefResult = {
|
|
304
|
+
ok: true;
|
|
305
|
+
path: string;
|
|
306
|
+
} | {
|
|
307
|
+
ok: false;
|
|
308
|
+
reason: "absolute" | "url";
|
|
309
|
+
};
|
|
310
|
+
/**
|
|
311
|
+
* Resolve a relative cross-file reference against the containing file (§2.9.2).
|
|
312
|
+
* Absolute paths and URLs (`://`) are not permitted.
|
|
313
|
+
*/
|
|
314
|
+
declare function resolveRefPath(fromFile: string, ref: string): RefResult;
|
|
315
|
+
/** A subflow reference: the declaring process id and the child path. */
|
|
316
|
+
interface SubflowRef {
|
|
317
|
+
process: string;
|
|
318
|
+
ref: string;
|
|
319
|
+
}
|
|
320
|
+
/** Collect the `extends:` preset references from a frontmatter, in order (§2.9.4). */
|
|
321
|
+
declare function collectExtendsRefs(fm: Frontmatter): string[];
|
|
322
|
+
/** Collect the `subflow:` references declared by processes (§2.9.3). */
|
|
323
|
+
declare function collectSubflowRefs(fm: Frontmatter): SubflowRef[];
|
|
324
|
+
/** A document with at least its parsed frontmatter (what the loader walks). */
|
|
325
|
+
interface DocWithFrontmatter {
|
|
326
|
+
frontmatter: Frontmatter | null;
|
|
327
|
+
}
|
|
328
|
+
interface LoadedGraph<T> {
|
|
329
|
+
/** Resolved absolute path → loaded document, including the entry. */
|
|
330
|
+
docs: Map<string, T>;
|
|
331
|
+
/** Cross-file diagnostics: missing path (V021), circular subflow (V022). */
|
|
332
|
+
diagnostics: Diagnostic[];
|
|
333
|
+
}
|
|
334
|
+
/**
|
|
335
|
+
* Recursively load an entry .pfdsl and its `subflow:` children (§2.9.3 / §15.11).
|
|
336
|
+
* `load` reads + analyzes a file by absolute path, returning null when absent.
|
|
337
|
+
* Detects self-referential and multi-hop subflow cycles (V022) and missing
|
|
338
|
+
* paths (V021). Shared children reached by multiple parents load once.
|
|
339
|
+
*/
|
|
340
|
+
declare function loadSubflowGraph<T extends DocWithFrontmatter>(entryPath: string, load: (path: string) => T | null): LoadedGraph<T>;
|
|
341
|
+
/**
|
|
342
|
+
* Compute the set of "open input" artifacts in a flow:
|
|
343
|
+
* artifacts that appear in the flow but have NO output edge producing them (§15.11).
|
|
344
|
+
*/
|
|
345
|
+
declare function computeOpenInputs(edges: NormalizedEdge[]): Set<string>;
|
|
346
|
+
/**
|
|
347
|
+
* Compute the set of "terminal" artifacts in a flow:
|
|
348
|
+
* artifacts that appear in the flow but are consumed by NEITHER `>>` (input) NOR `>>?` (feedback) (§15.11).
|
|
349
|
+
*/
|
|
350
|
+
declare function computeTerminals(edges: NormalizedEdge[]): Set<string>;
|
|
351
|
+
/** Context for validating a single subflow boundary (§15.11). */
|
|
352
|
+
interface SubflowBoundaryContext {
|
|
353
|
+
processId: string;
|
|
354
|
+
/** Artifact IDs from parent's `>>` (normal input, NOT feedback) edges into this process. */
|
|
355
|
+
parentNormalInputs: Set<string>;
|
|
356
|
+
/** Artifact IDs from parent's `->` (output) edges from this process. */
|
|
357
|
+
parentOutputs: Set<string>;
|
|
358
|
+
/** boundary: map from frontmatter (parent_id → child_id). Empty object if no boundary. */
|
|
359
|
+
boundaryMap: Record<string, string>;
|
|
360
|
+
childOpenInputs: Set<string>;
|
|
361
|
+
childTerminals: Set<string>;
|
|
362
|
+
}
|
|
363
|
+
/**
|
|
364
|
+
* Validate the boundary between a parent process and its subflow child (§15.11).
|
|
365
|
+
* Returns V025 diagnostics for any violations.
|
|
366
|
+
*/
|
|
367
|
+
declare function validateSubflowBoundary(ctx: SubflowBoundaryContext): Diagnostic[];
|
|
368
|
+
/**
|
|
369
|
+
* Recursively load an entry file and its `extends:` preset chain (§2.9.4 / §15.12).
|
|
370
|
+
* `load` reads + analyzes a file by absolute path, returning null when absent.
|
|
371
|
+
* Detects self-referential and multi-hop extends cycles (V027) and missing
|
|
372
|
+
* paths / invalid paths (V026). Diamond-shaped presets (same file reachable via
|
|
373
|
+
* multiple paths) are loaded only once — not treated as a cycle.
|
|
374
|
+
*/
|
|
375
|
+
declare function loadExtendsChain<T extends DocWithFrontmatter>(entryPath: string, load: (path: string) => T | null): LoadedGraph<T>;
|
|
376
|
+
/**
|
|
377
|
+
* Validate that a preset file only contains presentation-layer keys (§2.9.5).
|
|
378
|
+
* Returns V028 diagnostics for every forbidden key found.
|
|
379
|
+
*/
|
|
380
|
+
declare function validatePresetKeys(path: string, fm: Frontmatter | null): Diagnostic[];
|
|
381
|
+
/** The merged presentation values resolved from an extends chain. */
|
|
382
|
+
interface ResolvedPresentation {
|
|
383
|
+
statusStyles: Frontmatter["statusStyles"];
|
|
384
|
+
tag: Frontmatter["tag"];
|
|
385
|
+
group: Frontmatter["group"];
|
|
386
|
+
}
|
|
387
|
+
/**
|
|
388
|
+
* Merge statusStyles / tag / group from a sequence of frontmatters in order
|
|
389
|
+
* (lowest priority first, local last). Each element's values override the
|
|
390
|
+
* previous at attribute level (§2.9.4 "属性レベル深マージ").
|
|
391
|
+
*/
|
|
392
|
+
declare function resolvePresentation(chain: {
|
|
393
|
+
path: string;
|
|
394
|
+
fm: Frontmatter | null;
|
|
395
|
+
}[]): ResolvedPresentation;
|
|
396
|
+
|
|
397
|
+
interface ParseDocResult {
|
|
398
|
+
document: Document;
|
|
399
|
+
frontmatter: Frontmatter | null;
|
|
400
|
+
bodyStartLine: number;
|
|
401
|
+
diagnostics: Diagnostic[];
|
|
402
|
+
}
|
|
403
|
+
interface FormatResult {
|
|
404
|
+
output: string;
|
|
405
|
+
diagnostics: Diagnostic[];
|
|
406
|
+
}
|
|
407
|
+
interface AnalyzeResult {
|
|
408
|
+
document: Document;
|
|
409
|
+
frontmatter: Frontmatter | null;
|
|
410
|
+
bodyStartLine: number;
|
|
411
|
+
edges: NormalizedEdge[];
|
|
412
|
+
nodeKinds: Map<string, NodeKind>;
|
|
413
|
+
isolatedNodes: Set<string>;
|
|
414
|
+
graph: Graph;
|
|
415
|
+
diagnostics: Diagnostic[];
|
|
416
|
+
}
|
|
417
|
+
declare function parse(source: string): ParseDocResult;
|
|
418
|
+
|
|
419
|
+
declare function hasErrors(diags: readonly Diagnostic[]): boolean;
|
|
420
|
+
|
|
421
|
+
interface AnalyzeOptions {
|
|
422
|
+
strict?: boolean;
|
|
423
|
+
}
|
|
424
|
+
declare function analyze(source: string, opts?: AnalyzeOptions): AnalyzeResult;
|
|
425
|
+
interface FormatOptions {
|
|
426
|
+
style?: "flat" | "flows";
|
|
427
|
+
skipValidation?: boolean;
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
declare function format(source: string, opts?: FormatOptions): FormatResult;
|
|
431
|
+
|
|
432
|
+
export { type AnalyzeOptions, type AnalyzeResult, type ArtifactExpr, type ArtifactMeta, type AuditResult, type ChainSegment, type ChainStatement, type Diagnostic, type DiagnosticSeverity, type DiffReport, type DocWithFrontmatter, type Document, type FeedbackEdge, type FeedbackEdgeStatement, type FormatOptions, type FormatResult, type Frontmatter, type Graph, type GroupMeta, ID_PATTERN, type IdNode, type IndexChange, type InputEdgeStatement, type LexResult, type LoadResult, type LoadedGraph, type NodeDeclStatement, type NodeKind, type NodeStyle, type NormalizeResult, type NormalizedEdge, type OutputEdgeStatement, type ParseDocResult, type ParseResult, type Position, type PrimaryEdge, type ProcessMeta, type Range, type ReindexOptions, type ReindexResult, type ResolvedPresentation, STATUS_VALUES, STYLE_ATTRS, type SortKey, type SortOptions, type SortResult, type Statement, type Status, type StyleAttr, type SubflowBoundaryContext, type SubflowRef, type Token, type TokenType, type ValidateOptions, analyze, auditGraph, buildGraph, collectExtendsRefs, collectSubflowRefs, computeOpenInputs, computeTerminals, diffGraphs, format, formatAsFlows, formatEdges, hasErrors, loadExtendsChain, loadFrontmatter, loadSubflowGraph, normalize as normalizeDocument, parse, reindex, resolveMeta, resolvePresentation, resolveRefPath, sort, sortEdges, sortIsolated, validate as validateGraph, validatePresetKeys, validateSubflowBoundary };
|