flowfig 0.7.0 → 0.8.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/README.md +28 -8
- package/dist/check.js +4 -1
- package/dist/cli.js +11 -3
- package/dist/code.d.ts +26 -0
- package/dist/code.js +568 -0
- package/dist/edges.d.ts +7 -0
- package/dist/edges.js +510 -0
- package/dist/guide.d.ts +1 -1
- package/dist/guide.js +10 -7
- package/dist/imports.d.ts +11 -0
- package/dist/imports.js +235 -0
- package/dist/mcp.js +6 -3
- package/dist/model.d.ts +5 -0
- package/dist/source.d.ts +1 -1
- package/dist/source.js +3 -3
- package/dist/type-index.d.ts +55 -0
- package/dist/type-index.js +383 -0
- package/dist/types.d.ts +32 -0
- package/dist/types.js +733 -0
- package/dist/verify.d.ts +25 -3
- package/dist/verify.js +67 -22
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -22,7 +22,7 @@ A diagram in a repo drifts from the code. Someone renames a function, and the di
|
|
|
22
22
|
check fails, so no one sees the drift.
|
|
23
23
|
|
|
24
24
|
flowfig links each part of a diagram to the code that it draws. `flowfig verify` fails when a linked file or symbol is
|
|
25
|
-
gone. Run `verify` in CI, and a stale diagram fails the pull request.
|
|
25
|
+
gone, and warns when the code does not make an edge. Run `verify` in CI, and a stale diagram fails the pull request.
|
|
26
26
|
|
|
27
27
|
## Fail CI when the diagram drifts
|
|
28
28
|
|
|
@@ -36,12 +36,14 @@ Rename `verifyPassword` to `checkPassword`. Then `verify` fails with exit code 1
|
|
|
36
36
|
|
|
37
37
|
```console
|
|
38
38
|
$ npx flowfig verify login.svg
|
|
39
|
-
error missing-symbol login.svg: box "verify" -> src/auth/login.ts#verifyPassword: symbol not
|
|
39
|
+
error missing-symbol login.svg: box "verify" -> src/auth/login.ts#verifyPassword: symbol not defined
|
|
40
40
|
1 error, 0 warnings
|
|
41
|
+
login.svg: 0 of 1 boxes defined
|
|
41
42
|
```
|
|
42
43
|
|
|
43
|
-
`verify` checks that each linked file exists and that the symbol
|
|
44
|
-
name a heading, so a process diagram can follow its SOP
|
|
44
|
+
`verify` checks that each linked file exists and that it defines the symbol. It also checks each edge against the code
|
|
45
|
+
(see [Verify in CI](#verify-in-ci)). A link to a Markdown file can name a heading, so a process diagram can follow its SOP
|
|
46
|
+
document.
|
|
45
47
|
|
|
46
48
|
The GitHub Action runs `verify` on every figure in a pull request. For each SVG that the PR changes, it comments the old
|
|
47
49
|
image, the new image and the spec changes. It also names each figure whose linked code the PR changes.
|
|
@@ -63,7 +65,7 @@ jobs:
|
|
|
63
65
|
- uses: actions/setup-node@v4
|
|
64
66
|
with:
|
|
65
67
|
node-version: 22
|
|
66
|
-
- uses: iamalvisng/flowfig@v0.
|
|
68
|
+
- uses: iamalvisng/flowfig@v0.8.0
|
|
67
69
|
with:
|
|
68
70
|
figures: 'docs/**/*.svg' # default **/*.svg
|
|
69
71
|
```
|
|
@@ -252,7 +254,7 @@ Each SVG from the CLI carries its own spec. These commands made the rail-only fi
|
|
|
252
254
|
npx flowfig --spec docs/checkout.svg > checkout.json # print the spec in the SVG
|
|
253
255
|
# edit checkout.json: set "props.rail" to "only"
|
|
254
256
|
npx flowfig checkout.json docs/checkout-rail-only.svg
|
|
255
|
-
npx flowfig verify docs/checkout.svg # check
|
|
257
|
+
npx flowfig verify docs/checkout.svg # check each source and each edge against the code
|
|
256
258
|
npx flowfig diff old.svg docs/checkout.svg # list what changed in the spec
|
|
257
259
|
```
|
|
258
260
|
|
|
@@ -431,6 +433,23 @@ fails when the file or the symbol is gone. The action runs `verify` on every fig
|
|
|
431
433
|
the new image for each SVG the PR changes, with the spec changes as a list, and it names each figure whose linked code the PR
|
|
432
434
|
changes.
|
|
433
435
|
|
|
436
|
+
`verify` prints one count line for each figure, and gives each edge one result:
|
|
437
|
+
|
|
438
|
+
```console
|
|
439
|
+
docs/login.svg: 7 of 7 boxes defined; edges: 9 found, 0 not found, 1 unsure, 1 not checked
|
|
440
|
+
```
|
|
441
|
+
|
|
442
|
+
- found: the caller code calls or references the callee through an import, the same file or a typed receiver.
|
|
443
|
+
- not found: the caller code does not. `verify` warns, and `--strict` makes it an error.
|
|
444
|
+
- unsure: `verify` cannot decide, for example when a receiver has no declared type. `verify` lists it with the reason. It never fails CI.
|
|
445
|
+
- not checked: the edge has no `source`, or the language is not supported.
|
|
446
|
+
|
|
447
|
+
A method source is `path#Owner.name`. An edge `source` names the function that makes the call.
|
|
448
|
+
|
|
449
|
+
`via` on an edge names the route, queue, topic, table, file or key that both sides use. For a `via` edge, found means that the caller code and the callee file both use that token. It does not prove that a handler serves it.
|
|
450
|
+
|
|
451
|
+
Edge checks support TypeScript/JavaScript, Python, Go, Java, C# and Rust. Other files keep the name check for boxes.
|
|
452
|
+
|
|
434
453
|
A process figure for a team links its boxes to the SOP document, not to code: `"source": "docs/sop/refunds.md#step-3-approve-or-reject"`. The symbol is the heading as a GitHub anchor. If the heading is gone, `verify` fails.
|
|
435
454
|
|
|
436
455
|
```yaml
|
|
@@ -450,7 +469,7 @@ jobs:
|
|
|
450
469
|
- uses: actions/setup-node@v4
|
|
451
470
|
with:
|
|
452
471
|
node-version: 22
|
|
453
|
-
- uses: iamalvisng/flowfig@v0.
|
|
472
|
+
- uses: iamalvisng/flowfig@v0.8.0
|
|
454
473
|
with:
|
|
455
474
|
figures: 'docs/**/*.svg' # default **/*.svg
|
|
456
475
|
```
|
|
@@ -523,7 +542,8 @@ writeFileSync('first.svg', toSvg(spec));
|
|
|
523
542
|
- `check(spec, options)` returns the findings. It also takes `width` and `minText`.
|
|
524
543
|
- `render(spec, options)` returns `{ svg, scene }`. The scene is the layout that the check reads. Its shape can change.
|
|
525
544
|
|
|
526
|
-
`flowfig/verify` is for Node only. It exports `verify`, `links`, `owners` and `parseSource`, the same checks
|
|
545
|
+
`flowfig/verify` is for Node only. It exports `verify`, `verifyReport` (the findings and the counts), `links`, `owners` and `parseSource`, the same checks
|
|
546
|
+
as `flowfig verify`.
|
|
527
547
|
|
|
528
548
|
`toSvg` does not put the spec in the SVG. Only the CLI adds the spec, which `--spec` reads back.
|
|
529
549
|
|
package/dist/check.js
CHANGED
|
@@ -44,9 +44,12 @@ export function checkSpec(fig) {
|
|
|
44
44
|
if (e.quiet && !used.has(edges[i]))
|
|
45
45
|
out.push(err('hidden-edge', [edges[i]], `edge "${edges[i]}" is quiet and no beat uses it, so the figure never shows it`));
|
|
46
46
|
});
|
|
47
|
-
for (const [who, source] of owners(fig))
|
|
47
|
+
for (const [who, source, via] of owners(fig)) {
|
|
48
48
|
if (source != null && !parseSource(source))
|
|
49
49
|
out.push(warn('bad-source', [], `${who}: source "${source}" is not path or path#symbol`));
|
|
50
|
+
if (via != null && (typeof via !== 'string' || !/^\S+$/.test(via)))
|
|
51
|
+
out.push(warn('bad-source', [], `${who}: via ${JSON.stringify(via)} is not a string of one word`));
|
|
52
|
+
}
|
|
50
53
|
const marks = nodes(fig.layout).map((n) => n.mark);
|
|
51
54
|
const starts = marks.filter((m) => m === 'start').length;
|
|
52
55
|
const ends = marks.filter((m) => m === 'end').length;
|
package/dist/cli.js
CHANGED
|
@@ -25,7 +25,7 @@ import { diff, formatDiff } from './diff.js';
|
|
|
25
25
|
import { loadSpec, reportLines, sortFindings, specOf, svgWithSpec } from './load.js';
|
|
26
26
|
import { check, render, toSvg } from './svg.js';
|
|
27
27
|
import { checkRendered } from './check.js';
|
|
28
|
-
import { links,
|
|
28
|
+
import { coverageLine, links, unsureLines, verifyReport } from './verify.js';
|
|
29
29
|
const USAGE = `usage: flowfig <-|spec.json|figure.ts> [out.svg] [--open] render a figure; a spec on stdin with -
|
|
30
30
|
flowfig check <-|spec.json|figure.ts|figure.svg> list the faults; the input can be an SVG this wrote
|
|
31
31
|
flowfig --spec figure.svg print the spec the SVG carries
|
|
@@ -120,20 +120,28 @@ if (args[0] === 'verify') {
|
|
|
120
120
|
usage('verify needs at least one figure');
|
|
121
121
|
const findings = [];
|
|
122
122
|
const all = [];
|
|
123
|
+
const coverage = [];
|
|
123
124
|
for (const input of args) {
|
|
124
125
|
const props = await load(input);
|
|
125
|
-
const
|
|
126
|
+
const report = verifyReport(props, { root });
|
|
127
|
+
const found = sortFindings([...check(props), ...report.findings], strict).map((f) => ({ ...f, figure: input }));
|
|
126
128
|
findings.push(...found);
|
|
129
|
+
coverage.push({ figure: input, ...report.coverage });
|
|
127
130
|
all.push(...links(props).map((l) => ({ ...l, figure: input })));
|
|
128
131
|
}
|
|
129
132
|
const errors = findings.filter((f) => f.severity === 'error').length;
|
|
130
133
|
if (json)
|
|
131
|
-
console.log(JSON.stringify({ findings, links: all }, null, 2));
|
|
134
|
+
console.log(JSON.stringify({ findings, links: all, coverage }, null, 2));
|
|
132
135
|
else {
|
|
133
136
|
const n = (k, word) => `${k} ${word}${k === 1 ? '' : 's'}`;
|
|
134
137
|
for (const f of findings)
|
|
135
138
|
console.log(`${f.severity.padEnd(8)} ${f.rule.padEnd(18)} ${f.figure}: ${f.message}`);
|
|
136
139
|
console.log(`${n(errors, 'error')}, ${n(findings.length - errors, 'warning')}`);
|
|
140
|
+
for (const c of coverage) {
|
|
141
|
+
console.log(coverageLine(c.figure, c));
|
|
142
|
+
for (const l of unsureLines(c))
|
|
143
|
+
console.log(l);
|
|
144
|
+
}
|
|
137
145
|
}
|
|
138
146
|
process.exit(errors ? 1 : 0);
|
|
139
147
|
}
|
package/dist/code.d.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export type Lang = 'ts' | 'py' | 'go' | 'java' | 'cs' | 'rs';
|
|
2
|
+
export type Read = {
|
|
3
|
+
(full: string): string | null;
|
|
4
|
+
files?: (root: string) => string[];
|
|
5
|
+
};
|
|
6
|
+
export type CodeFile = {
|
|
7
|
+
path: string;
|
|
8
|
+
lang: Lang;
|
|
9
|
+
text: string;
|
|
10
|
+
code: string;
|
|
11
|
+
keep: string;
|
|
12
|
+
};
|
|
13
|
+
export declare const langOf: (path: string) => Lang | null;
|
|
14
|
+
export declare const readFile: Read;
|
|
15
|
+
type Extent = [number, number];
|
|
16
|
+
export declare const esc: (s: string) => string;
|
|
17
|
+
export declare function matchClose(code: string, open: number): number;
|
|
18
|
+
export declare function pyBody(code: string, start: number): Extent;
|
|
19
|
+
export declare function outside(root: string, path: string): boolean;
|
|
20
|
+
export declare function codeFile(root: string, path: string, read?: Read, cache?: Map<string, CodeFile | null>): CodeFile | null;
|
|
21
|
+
export declare function locate(file: CodeFile, symbol: string): {
|
|
22
|
+
start: number;
|
|
23
|
+
end: number;
|
|
24
|
+
} | null;
|
|
25
|
+
export declare const isDefined: (file: CodeFile, symbol: string) => boolean;
|
|
26
|
+
export {};
|