reladraw 0.20.0 → 0.22.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/.claude/skills/reladraw/SKILL.md +188 -0
- package/.claude/skills/reladraw/reference/syntax.md +1602 -0
- package/README.md +8 -6
- package/SYNTAX.md +40 -4
- package/dist/ast.d.ts +9 -2
- package/dist/ast.js +9 -2
- package/dist/cli.js +71 -13
- package/dist/constants.d.ts +4 -0
- package/dist/constants.js +8 -0
- package/dist/model.d.ts +13 -0
- package/dist/model.js +7 -0
- package/dist/page.d.ts +14 -0
- package/dist/page.js +412 -0
- package/dist/parser.js +21 -3
- package/dist/place.d.ts +19 -0
- package/dist/place.js +67 -8
- package/dist/render.d.ts +17 -0
- package/dist/render.js +101 -29
- package/dist/resolve.d.ts +14 -0
- package/dist/resolve.js +33 -7
- package/dist/themes.d.ts +1 -0
- package/dist/themes.js +1 -1
- package/dist/viewer.d.ts +16 -0
- package/dist/viewer.js +185 -0
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -45,7 +45,7 @@ npm install -g reladraw
|
|
|
45
45
|
reladraw render diagram.reladraw -o diagram.svg
|
|
46
46
|
```
|
|
47
47
|
|
|
48
|
-
`reladraw check diagram.reladraw` prints the warnings without writing a picture, and `reladraw format diagram.reladraw` lines its statements up in columns.
|
|
48
|
+
`reladraw check diagram.reladraw` prints the warnings without writing a picture, and `reladraw format diagram.reladraw` lines its statements up in columns. `reladraw render diagram.reladraw --page` writes a page for looking at it in a browser, with pan, zoom, full screen and the warnings beside it.
|
|
49
49
|
|
|
50
50
|
Or from a clone, which also gets you the examples:
|
|
51
51
|
|
|
@@ -75,20 +75,22 @@ Each `<reladraw-diagram>` is replaced by its SVG. Indent the source however suit
|
|
|
75
75
|
To install a skill to let your agent know how to use reladraw:
|
|
76
76
|
|
|
77
77
|
```
|
|
78
|
-
|
|
78
|
+
reladraw install-skill -g
|
|
79
79
|
```
|
|
80
80
|
|
|
81
|
-
That installs it for every agent you use (Claude Code, Codex, Cursor, Copilot and others), each in its own skills directory. Leave off `-g` to install it into the current project only. To install it for just one agent, name it with `-a`:
|
|
81
|
+
That installs the skill that came with your copy of reladraw, so it teaches what your reladraw accepts, for every agent you use (Claude Code, Codex, Cursor, Copilot and others), each in its own skills directory. It hands the work to [skills](https://www.npmjs.com/package/skills), and passes on whatever you write after `install-skill`. Leave off `-g` to install it into the current project only. To install it for just one agent, name it with `-a`:
|
|
82
82
|
|
|
83
83
|
```
|
|
84
|
-
|
|
84
|
+
reladraw install-skill -g -a claude-code
|
|
85
85
|
```
|
|
86
86
|
|
|
87
|
-
|
|
87
|
+
The skill is a copy, so after upgrading reladraw, run the command again to bring the skill up to date with it.
|
|
88
|
+
|
|
89
|
+
To install the skill from the main branch instead, which can run ahead of the release on npm, run `npx skills add reladraw/reladraw -g`.
|
|
88
90
|
|
|
89
91
|
## Status
|
|
90
92
|
|
|
91
|
-
Version 0.
|
|
93
|
+
Version 0.22.0. Early stage, but works. The parser, layout engine, and SVG renderer are written in TypeScript, with zero runtime dependencies. There is a command-line tool that turns a .reladraw text file into an SVG, and an element that does the same inside a web page.
|
|
92
94
|
|
|
93
95
|
## License
|
|
94
96
|
|
package/SYNTAX.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Syntax reference — 0.
|
|
1
|
+
# Syntax reference — 0.22.0
|
|
2
2
|
|
|
3
3
|
What the language accepts. The changelog at the end lists what changed in each published version; 0.17.0's changes are large, and its entry has a table of every old spelling and what to write instead.
|
|
4
4
|
|
|
@@ -241,7 +241,7 @@ above-left of X above-right of X below-left of X below-right of X
|
|
|
241
241
|
|
|
242
242
|
**A gap is exactly what was said.** `right of a` puts the box a `normal` gap from `a`'s right side. The gap goes in the placement's bracket, `right of a (gap: tight)`, or as a distance in front, `2 right of a`; writing both is refused as said twice. A diagonal distance is per axis: `2 below-right of a` is 2 across and 2 down.
|
|
243
243
|
|
|
244
|
-
**A lone direction also centers on its target.** `right of a` alone puts the box level with `a`'s center, because walking right from something keeps you on its center line. That half gives way as soon as another placement says how high.
|
|
244
|
+
**A lone direction also centers on its target.** `right of a` alone puts the box level with `a`'s center, because walking right from something keeps you on its center line. That half gives way as soon as another placement says how high, whichever box it is written on: with `node b right of a` and `node a even with b.1`, B goes where B.1 is level with A, rather than centered on it.
|
|
245
245
|
|
|
246
246
|
```
|
|
247
247
|
node parser
|
|
@@ -316,7 +316,7 @@ A target need not be written first, but there must be an order in which each box
|
|
|
316
316
|
|
|
317
317
|
### One anchor
|
|
318
318
|
|
|
319
|
-
Exactly one box in the file places itself, and every other is placed relative to it, directly or through others. Two unplaced boxes are refused by name. Chaining, `b right of a` then `c right of b`, is the plain way to write a few in a row; `layout:` ([Containers](#containers)) is for "these, in a line, in written order". Place against neighbors rather than hanging many boxes off one small one: a gap from a small box says nothing about the large ones also hanging off it.
|
|
319
|
+
Exactly one box in the file places itself, and every other is placed relative to it, directly or through others. Two unplaced boxes are refused by name. The anchor may be split between two boxes, one saying nothing across and the other nothing up and down: with `node a "A" even with b.1` and `node b "B" right of a`, A says nothing across, and B, once its centering on A gives way, nothing up and down. Chaining, `b right of a` then `c right of b`, is the plain way to write a few in a row; `layout:` ([Containers](#containers)) is for "these, in a line, in written order". Place against neighbors rather than hanging many boxes off one small one: a gap from a small box says nothing about the large ones also hanging off it.
|
|
320
320
|
|
|
321
321
|
### A box goes where it is placed
|
|
322
322
|
|
|
@@ -1033,6 +1033,14 @@ A key means one thing everywhere, so it can be wrong: `border:` on a node with n
|
|
|
1033
1033
|
|
|
1034
1034
|
**Changing a color never moves anything.** Size is different: a bigger text or a thicker line takes more room.
|
|
1035
1035
|
|
|
1036
|
+
### A border's bracket
|
|
1037
|
+
|
|
1038
|
+
```
|
|
1039
|
+
node host "Host" border: (color: #d2904e, thickness: thick)
|
|
1040
|
+
```
|
|
1041
|
+
|
|
1042
|
+
`border: red` is short for `border: (color: red)`. `thickness:` takes `thin`, `normal` (the default), `thick`, a multiple of normal such as `3`, or pixels such as `4px`; `border: thick` is refused with the bracket it meant. A thick border is drawn inside the box's outline and the box grows by the extra, so its padding is still measured from the inside of the stroke, a gap to its neighbor from the outside, and a line still ends on its outer edge. A stated `width:` or `height:` is the outside of the box, stroke included. A region's border is drawn inside the edge its points state, and the region doesn't grow.
|
|
1043
|
+
|
|
1036
1044
|
### Styles
|
|
1037
1045
|
|
|
1038
1046
|
```
|
|
@@ -1114,9 +1122,12 @@ A default takes the words a style does and may wear a style of its own (`default
|
|
|
1114
1122
|
|
|
1115
1123
|
```
|
|
1116
1124
|
diagram theme: nord background: #1e2229 text: (color: #e0e0e0)
|
|
1125
|
+
diagram title: "How a login reaches the database"
|
|
1117
1126
|
```
|
|
1118
1127
|
|
|
1119
|
-
`diagram` holds what covers the whole drawing: `theme`, `background` (the page behind everything), `text: (color: …)` for every text, `guides: show`,
|
|
1128
|
+
`diagram` holds what covers the whole drawing: `theme`, `background` (the page behind everything), `text: (color: …)` for every text, `guides: show`, `checks: (…)` ([Findings](#errors-and-findings)), and `title`. It has no name, since a file holds one diagram, and a second one is an error. `diagram text:` takes a color only; a text size belongs on a default.
|
|
1129
|
+
|
|
1130
|
+
`title:` names the drawing, in quotes. It isn't drawn: the SVG carries it as its own title, which a browser shows on the tab and a screen reader announces, and a page made with `--page` is headed with it.
|
|
1120
1131
|
|
|
1121
1132
|
### Destinations
|
|
1122
1133
|
|
|
@@ -1168,14 +1179,25 @@ reladraw check diagram.reladraw
|
|
|
1168
1179
|
| option | |
|
|
1169
1180
|
|---|---|
|
|
1170
1181
|
| `-o`, `--out` | where `render` writes; defaults to the input with `.svg`; `-` for standard output |
|
|
1182
|
+
| `--page` | `render` writes a page for looking at the diagram instead, defaulting to the input with `.html` |
|
|
1171
1183
|
| `--theme <name>` | render in another theme, whatever the file says |
|
|
1172
1184
|
| `--guides` | draw the guides |
|
|
1173
1185
|
| `--checks "<kind>: on, …"` | turn kinds of finding on or off, over the file |
|
|
1174
1186
|
| `--no-checks` | print no findings; errors still print |
|
|
1175
1187
|
| `-v`, `--version` | print the version |
|
|
1176
1188
|
|
|
1189
|
+
`reladraw install-skill` installs the agent skill that came with this version of reladraw, by running `npx skills add` on it with `--copy`. What follows it goes to `skills`: `-g` to install for every project, `-a claude-code` for one agent.
|
|
1190
|
+
|
|
1177
1191
|
The output is a standalone SVG: every picture is drawn into it as path data, never from a font or a linked file. A web page can draw a diagram in place with `<reladraw-diagram>`; see "In a web page" in the README.
|
|
1178
1192
|
|
|
1193
|
+
### A page for looking at a diagram
|
|
1194
|
+
|
|
1195
|
+
```
|
|
1196
|
+
reladraw render arch.reladraw --page
|
|
1197
|
+
```
|
|
1198
|
+
|
|
1199
|
+
`--page` writes `arch.html`: one self-contained file, for opening in a browser, attaching or committing, that needs nothing running and fetches nothing. The page is in the diagram's own colors, so a dark diagram doesn't sit on a white page, and it is headed with `diagram title:`, or the file's name when there is none. Drag to pan; scroll, pinch or double-click to zoom; Fit shows the whole diagram and 100% returns it to its own scale. The zoom is always shown, with "Fit" beside it while the whole diagram is in view. There is a full-screen button. The Export menu copies the SVG, or saves it or a PNG, as `render` would draw it. The findings are listed beside it in a panel that folds away, and clicking one lights up what its line drew. A box's or a line's name shows under the pointer. Keys: `+` and `-` zoom, `0` fits, `1` is actual size, `f` is full screen.
|
|
1200
|
+
|
|
1179
1201
|
### Formatting
|
|
1180
1202
|
|
|
1181
1203
|
```
|
|
@@ -1295,6 +1317,20 @@ Designed and absent from the code.
|
|
|
1295
1317
|
|
|
1296
1318
|
Pre-1.0, so the minor number is where a breaking change goes. Every removal is refused by name with the replacement quoted, rather than dropped in silence: an older file stops with an error saying what to write instead.
|
|
1297
1319
|
|
|
1320
|
+
**0.22.0**
|
|
1321
|
+
|
|
1322
|
+
- **`reladraw install-skill`** installs the agent skill that came with your reladraw, so it teaches what your copy accepts rather than what the main branch does. It hands the work to `skills`, passing on `-g`, `-a` and the rest. The npm package now carries the skill.
|
|
1323
|
+
- **The agent skill opens each diagram it draws as a page in the default browser**, with `reladraw render --page` as the last step of every drawing rather than only when asked to show it. It doesn't open one when there is no display, or when the user has said not to.
|
|
1324
|
+
- **The page says when it is showing the whole diagram**: its zoom reads "Fit · 62%" while fitted, and just the number once you zoom or pan. The Actual size button is now 100%, which is what it always did. Save SVG and Save PNG are under an Export button, which can also copy the SVG.
|
|
1325
|
+
- **The playground pans and zooms as the page does**: − and +, Fit, 100%, the wheel, a pinch, a drag, a double-click, and the keys + - 0 1, with the zoom shown between − and +. Its one Actual size button, whose label named the view you would go to rather than the one you were in, is gone. The view stays where you left it as you type. Copy SVG, Save SVG and Save PNG are now under one Export button, so the row of controls fits.
|
|
1326
|
+
|
|
1327
|
+
**0.21.0**
|
|
1328
|
+
|
|
1329
|
+
- **A diagram can have a title**: `diagram title: "How a login reaches the database"`. The SVG carries it as its own title, which a browser shows on the tab. See [The diagram](#the-diagram).
|
|
1330
|
+
- **`reladraw render --page`** writes a page for looking at a diagram: one self-contained HTML file in the diagram's colors, headed with its title, that pans, zooms, goes full screen, saves the SVG or a PNG, lists the findings and lights up what each one is about. See [A page for looking at a diagram](#a-page-for-looking-at-a-diagram).
|
|
1331
|
+
- **A border can be thicker or thinner**: `border: (color: #d2904e, thickness: thick)`, mirroring the line's bracket. A thick border is drawn inside the box, and the box grows to keep its padding, so it may move what is placed beside it. See [A border's bracket](#a-borders-bracket).
|
|
1332
|
+
- **A box can be lined up with something inside a box placed against it.** `node a "Node A" even with b.1` with `node b "Node B" right of a` used to be refused, "nothing anchors the diagram", because `right of a` also centered B on A. That centering now gives way, as it already did to a placement written on B itself, and B goes where B.1 is level with A.
|
|
1333
|
+
|
|
1298
1334
|
**0.20.0**
|
|
1299
1335
|
|
|
1300
1336
|
- **`stays above`, `stays below`, `stays left of` and `stays right of`** keep a child placed in its box's corner clear of the other children: `node laptop.mark icon: laptop inside laptop top-right stays above laptop.photos`. The laptop stays in the corner, and the box makes room. See [Against its own parent](#against-its-own-parent).
|
package/dist/ast.d.ts
CHANGED
|
@@ -354,6 +354,12 @@ export declare const TEXT_KEYS: readonly ["color", "size", "wrap", "align", "at"
|
|
|
354
354
|
* of `line: (color: red)`, and both are stored under the bare `line` key.
|
|
355
355
|
*/
|
|
356
356
|
export declare const LINE_KEYS: readonly ["color", "path", "corners", "crossing", "pattern", "thickness", "curve", "turn", "step-out"];
|
|
357
|
+
/**
|
|
358
|
+
* What a box's border takes in its bracket: `border: (color: red, thickness:
|
|
359
|
+
* thick)`, mirroring the line's. `border: red` is the short form of the color,
|
|
360
|
+
* and both are stored under the bare `border` key.
|
|
361
|
+
*/
|
|
362
|
+
export declare const BORDER_KEYS: readonly ["color", "thickness"];
|
|
357
363
|
/**
|
|
358
364
|
* The words each of the line's properties takes, the default first. Thickness
|
|
359
365
|
* takes a multiple of normal (`2`) or pixels (`3px`) as well. `turn:` takes a fraction and
|
|
@@ -655,9 +661,10 @@ export interface DiagramStmt {
|
|
|
655
661
|
* `text: (color: …)`, and sets the text color of everything at once — the
|
|
656
662
|
* theme has one text color, shared by nodes and edges, and this is that.
|
|
657
663
|
* `checks` takes a bracket too, `checks: (edge-crossings: on)`, turning kinds
|
|
658
|
-
* of finding on or off by name.
|
|
664
|
+
* of finding on or off by name. `title` is quoted, and names the drawing: the
|
|
665
|
+
* SVG carries it as its own title, and a page made with `--page` heads with it.
|
|
659
666
|
*/
|
|
660
|
-
export declare const DIAGRAM_KEYS: readonly ["theme", "background", "text", "checks", "guides"];
|
|
667
|
+
export declare const DIAGRAM_KEYS: readonly ["theme", "background", "text", "checks", "guides", "title"];
|
|
661
668
|
/**
|
|
662
669
|
* `default leaf fill: #2e5d3a` — a style that applies to every thing of one
|
|
663
670
|
* kind without being named. The more specific wins: `node` covers every node,
|
package/dist/ast.js
CHANGED
|
@@ -298,6 +298,12 @@ export const TEXT_KEYS = ['color', 'size', 'wrap', 'align', 'at'];
|
|
|
298
298
|
* of `line: (color: red)`, and both are stored under the bare `line` key.
|
|
299
299
|
*/
|
|
300
300
|
export const LINE_KEYS = ['color', 'path', 'corners', 'crossing', 'pattern', 'thickness', 'curve', 'turn', 'step-out'];
|
|
301
|
+
/**
|
|
302
|
+
* What a box's border takes in its bracket: `border: (color: red, thickness:
|
|
303
|
+
* thick)`, mirroring the line's. `border: red` is the short form of the color,
|
|
304
|
+
* and both are stored under the bare `border` key.
|
|
305
|
+
*/
|
|
306
|
+
export const BORDER_KEYS = ['color', 'thickness'];
|
|
301
307
|
/**
|
|
302
308
|
* The words each of the line's properties takes, the default first. Thickness
|
|
303
309
|
* takes a multiple of normal (`2`) or pixels (`3px`) as well. `turn:` takes a fraction and
|
|
@@ -345,9 +351,10 @@ export const REGION_KEYS = ['style', 'fill', 'opacity', 'border', 'padding', 'pa
|
|
|
345
351
|
* `text: (color: …)`, and sets the text color of everything at once — the
|
|
346
352
|
* theme has one text color, shared by nodes and edges, and this is that.
|
|
347
353
|
* `checks` takes a bracket too, `checks: (edge-crossings: on)`, turning kinds
|
|
348
|
-
* of finding on or off by name.
|
|
354
|
+
* of finding on or off by name. `title` is quoted, and names the drawing: the
|
|
355
|
+
* SVG carries it as its own title, and a page made with `--page` heads with it.
|
|
349
356
|
*/
|
|
350
|
-
export const DIAGRAM_KEYS = ['theme', 'background', 'text', 'checks', 'guides'];
|
|
357
|
+
export const DIAGRAM_KEYS = ['theme', 'background', 'text', 'checks', 'guides', 'title'];
|
|
351
358
|
export const DEFAULT_TARGETS = [
|
|
352
359
|
'node',
|
|
353
360
|
'leaf',
|
package/dist/cli.js
CHANGED
|
@@ -1,20 +1,25 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import { spawnSync } from 'node:child_process';
|
|
2
3
|
import { existsSync, readFileSync } from 'node:fs';
|
|
3
4
|
import { mkdir, readFile, writeFile } from 'node:fs/promises';
|
|
4
|
-
import { dirname, resolve as resolvePath } from 'node:path';
|
|
5
|
+
import { basename, dirname, resolve as resolvePath } from 'node:path';
|
|
6
|
+
import { fileURLToPath } from 'node:url';
|
|
5
7
|
import { nearMatch, readChecks } from './checks.js';
|
|
6
8
|
import { SourceError } from './errors.js';
|
|
7
9
|
import { format } from './format.js';
|
|
8
10
|
import { DEFAULT_FORMAT, readFormatSettings, SETTINGS_FILE, settingsFileText } from './format-settings.js';
|
|
9
11
|
import { draw } from './index.js';
|
|
12
|
+
import { drawPage } from './page.js';
|
|
10
13
|
import { THEME_NAMES, THEMES } from './themes.js';
|
|
11
14
|
const USAGE = `reladraw — draw a diagram from stated placement
|
|
12
15
|
|
|
13
16
|
reladraw render <input.reladraw> [-o <output.svg>] [options]
|
|
17
|
+
reladraw render <input.reladraw> --page [-o <output.html>] [options]
|
|
14
18
|
reladraw check <input.reladraw> [options]
|
|
15
19
|
reladraw format <input.reladraw>... [--check]
|
|
16
20
|
reladraw format - [--check]
|
|
17
21
|
reladraw format --init
|
|
22
|
+
reladraw install-skill [skills options]
|
|
18
23
|
|
|
19
24
|
render draw the diagram to an SVG, and print any findings: places
|
|
20
25
|
where the picture, drawn as written, may not read as meant.
|
|
@@ -30,9 +35,19 @@ const USAGE = `reladraw — draw a diagram from stated placement
|
|
|
30
35
|
folder up.
|
|
31
36
|
--init writes a .reladraw-format here, every setting at its
|
|
32
37
|
default with what it does.
|
|
38
|
+
install-skill
|
|
39
|
+
install the agent skill that came with this version of
|
|
40
|
+
reladraw, so it teaches what this tool accepts. It runs
|
|
41
|
+
npx skills add with --copy, and passes on what follows:
|
|
42
|
+
-g for every project, -a claude-code for one agent.
|
|
33
43
|
|
|
34
44
|
-o, --out where render writes the SVG. Defaults to the input path with
|
|
35
45
|
its extension replaced by .svg. Use - for standard output.
|
|
46
|
+
--page render writes a page for looking at the diagram instead: one
|
|
47
|
+
HTML file in the diagram's colors, headed with its title, that
|
|
48
|
+
pans, zooms, goes full screen, saves the SVG or a PNG, lists the
|
|
49
|
+
findings and names what is under the pointer. Defaults to the
|
|
50
|
+
input path with .html.
|
|
36
51
|
--theme render in this theme, whatever the file's \`diagram theme:\`
|
|
37
52
|
says. One of ${THEME_NAMES.join(', ')}.
|
|
38
53
|
--guides draw the guides: everything written with \`guide\` in front,
|
|
@@ -44,8 +59,35 @@ const USAGE = `reladraw — draw a diagram from stated placement
|
|
|
44
59
|
print the version.
|
|
45
60
|
-h, --help print this.
|
|
46
61
|
`;
|
|
47
|
-
const COMMANDS = ['render', 'check', 'format'];
|
|
62
|
+
const COMMANDS = ['render', 'check', 'format', 'install-skill'];
|
|
63
|
+
// The version of skills this was tried with, so a change there can't break it.
|
|
64
|
+
const SKILLS_PACKAGE = 'skills@1.7.6';
|
|
65
|
+
// The skill ships in the package beside dist/, as the one in the repository.
|
|
66
|
+
// skills does the work of knowing where each agent keeps its skills; --copy
|
|
67
|
+
// because an npx run leaves the package in a cache, where a link would break.
|
|
68
|
+
function installSkill(args) {
|
|
69
|
+
const skills = fileURLToPath(new URL('../.claude/skills/', import.meta.url));
|
|
70
|
+
if (!existsSync(skills)) {
|
|
71
|
+
process.stderr.write(`reladraw: the skill isn't in this install of reladraw (looked in ${skills})\n`);
|
|
72
|
+
return 1;
|
|
73
|
+
}
|
|
74
|
+
const windows = process.platform === 'win32';
|
|
75
|
+
const command = [SKILLS_PACKAGE, 'add', skills, '--copy', ...args];
|
|
76
|
+
// On Windows npx is a .cmd, which Node runs only through a shell.
|
|
77
|
+
const result = spawnSync(windows ? 'npx.cmd' : 'npx', windows ? command.map((a) => `"${a}"`) : command, {
|
|
78
|
+
stdio: 'inherit',
|
|
79
|
+
shell: windows,
|
|
80
|
+
});
|
|
81
|
+
if (result.error) {
|
|
82
|
+
process.stderr.write(`reladraw: couldn't run npx to install the skill: ${result.error.message}\n`);
|
|
83
|
+
return 1;
|
|
84
|
+
}
|
|
85
|
+
return result.status ?? 1;
|
|
86
|
+
}
|
|
48
87
|
async function main(argv) {
|
|
88
|
+
// Everything after install-skill is for skills, -h and -v included.
|
|
89
|
+
if (argv[0] === 'install-skill')
|
|
90
|
+
return installSkill(argv.slice(1));
|
|
49
91
|
if (argv.length === 0 || argv.includes('-h') || argv.includes('--help')) {
|
|
50
92
|
process.stdout.write(USAGE);
|
|
51
93
|
return argv.length === 0 ? 1 : 0;
|
|
@@ -79,6 +121,7 @@ async function main(argv) {
|
|
|
79
121
|
let checks;
|
|
80
122
|
let noChecks = false;
|
|
81
123
|
let guides = false;
|
|
124
|
+
let page = false;
|
|
82
125
|
for (let i = 1; i < argv.length; i += 1) {
|
|
83
126
|
const arg = argv[i];
|
|
84
127
|
if ((arg === '-o' || arg === '--out') && command === 'render') {
|
|
@@ -119,6 +162,13 @@ async function main(argv) {
|
|
|
119
162
|
else if (arg === '--guides') {
|
|
120
163
|
guides = true;
|
|
121
164
|
}
|
|
165
|
+
else if (arg === '--page' && command === 'render') {
|
|
166
|
+
page = true;
|
|
167
|
+
}
|
|
168
|
+
else if (arg === '--page') {
|
|
169
|
+
process.stderr.write('reladraw: check writes nothing, so it takes no --page; reladraw render --page writes one\n');
|
|
170
|
+
return 1;
|
|
171
|
+
}
|
|
122
172
|
else if (arg.startsWith('-') && arg !== '-') {
|
|
123
173
|
process.stderr.write(`reladraw: unknown option ${arg}\n`);
|
|
124
174
|
return 1;
|
|
@@ -157,16 +207,24 @@ async function main(argv) {
|
|
|
157
207
|
overChecks = (fromFile) => readChecks(written, fromFile);
|
|
158
208
|
}
|
|
159
209
|
const source = await readFile(input, 'utf8');
|
|
210
|
+
const options = {
|
|
211
|
+
...(theme === undefined ? {} : { theme: THEMES[theme] }),
|
|
212
|
+
...(guides ? { guides: true } : {}),
|
|
213
|
+
// An icon's file is found from the diagram, not from wherever the tool
|
|
214
|
+
// happens to be run.
|
|
215
|
+
readIconFile: (path) => readFileSync(resolvePath(dirname(input), path), 'utf8'),
|
|
216
|
+
...(noChecks ? { checks: false } : overChecks ? { checks: overChecks } : {}),
|
|
217
|
+
};
|
|
160
218
|
let drawn;
|
|
161
219
|
try {
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
}
|
|
220
|
+
if (page) {
|
|
221
|
+
const made = drawPage(source, basename(input).replace(/\.[^.]+$/, ''), options);
|
|
222
|
+
drawn = { text: made.html, findings: made.findings };
|
|
223
|
+
}
|
|
224
|
+
else {
|
|
225
|
+
const made = draw(source, options);
|
|
226
|
+
drawn = { text: made.svg, findings: made.findings };
|
|
227
|
+
}
|
|
170
228
|
}
|
|
171
229
|
catch (error) {
|
|
172
230
|
if (error instanceof SourceError) {
|
|
@@ -180,12 +238,12 @@ async function main(argv) {
|
|
|
180
238
|
if (command === 'check')
|
|
181
239
|
return 0;
|
|
182
240
|
if (out === '-') {
|
|
183
|
-
process.stdout.write(drawn.
|
|
241
|
+
process.stdout.write(drawn.text);
|
|
184
242
|
return 0;
|
|
185
243
|
}
|
|
186
|
-
const target = resolvePath(out ?? input.replace(/\.[^.]+$/, '') + '.svg');
|
|
244
|
+
const target = resolvePath(out ?? input.replace(/\.[^.]+$/, '') + (page ? '.html' : '.svg'));
|
|
187
245
|
await mkdir(dirname(target), { recursive: true });
|
|
188
|
-
await writeFile(target, drawn.
|
|
246
|
+
await writeFile(target, drawn.text, 'utf8');
|
|
189
247
|
process.stderr.write(`${target}\n`);
|
|
190
248
|
return 0;
|
|
191
249
|
}
|
package/dist/constants.d.ts
CHANGED
|
@@ -55,6 +55,10 @@ export declare const ARROW_MARKER_WIDTH = 7;
|
|
|
55
55
|
export declare const ARROW_LENGTH: number;
|
|
56
56
|
/** What `thickness: thin | normal | thick` draw, in pixels. `normal` is the line as it always was. */
|
|
57
57
|
export declare const THICKNESS: Record<string, number>;
|
|
58
|
+
/** A box's border as it always was, in pixels: `border: (thickness: normal)`. */
|
|
59
|
+
export declare const BORDER_WIDTH = 1;
|
|
60
|
+
/** What a border's `thickness: thin | normal | thick` draw, in pixels. */
|
|
61
|
+
export declare const BORDER_THICKNESS: Record<string, number>;
|
|
58
62
|
/**
|
|
59
63
|
* How much of a line of this thickness its arrowhead covers. The marker scales
|
|
60
64
|
* with the stroke, so a thick line gets a bigger head, and the room an edge's
|
package/dist/constants.js
CHANGED
|
@@ -65,6 +65,14 @@ export const THICKNESS = {
|
|
|
65
65
|
normal: LINE_WIDTH,
|
|
66
66
|
thick: LINE_WIDTH * 2,
|
|
67
67
|
};
|
|
68
|
+
/** A box's border as it always was, in pixels: `border: (thickness: normal)`. */
|
|
69
|
+
export const BORDER_WIDTH = 1;
|
|
70
|
+
/** What a border's `thickness: thin | normal | thick` draw, in pixels. */
|
|
71
|
+
export const BORDER_THICKNESS = {
|
|
72
|
+
thin: BORDER_WIDTH / 2,
|
|
73
|
+
normal: BORDER_WIDTH,
|
|
74
|
+
thick: BORDER_WIDTH * 2,
|
|
75
|
+
};
|
|
68
76
|
/**
|
|
69
77
|
* How much of a line of this thickness its arrowhead covers. The marker scales
|
|
70
78
|
* with the stroke, so a thick line gets a bigger head, and the room an edge's
|
package/dist/model.d.ts
CHANGED
|
@@ -30,6 +30,12 @@ export interface LayoutNode {
|
|
|
30
30
|
* a document's are read; drawing alone depends on it, never placement.
|
|
31
31
|
*/
|
|
32
32
|
corners: NodeCorners;
|
|
33
|
+
/**
|
|
34
|
+
* How wide the border is drawn, in pixels, from `border: (thickness: …)`;
|
|
35
|
+
* left out when it is the normal width. The stroke lies inside the outline,
|
|
36
|
+
* and the padding grows by the extra, so a thick border takes room.
|
|
37
|
+
*/
|
|
38
|
+
borderWidth?: number;
|
|
33
39
|
/** The text as written, before line splitting. */
|
|
34
40
|
text: string;
|
|
35
41
|
/** The text split into the lines that will be drawn, each as its runs. */
|
|
@@ -138,6 +144,8 @@ export interface LayoutMark {
|
|
|
138
144
|
names: string[];
|
|
139
145
|
appearance: Attrs;
|
|
140
146
|
guide: boolean;
|
|
147
|
+
/** A region's border width in pixels, left out when normal; drawn inside its stated edge. */
|
|
148
|
+
borderWidth?: number;
|
|
141
149
|
/** Its text, if it has one, and where that sits on the page (design.org 7.4). */
|
|
142
150
|
text?: MarkTextBox;
|
|
143
151
|
line: number;
|
|
@@ -325,6 +333,11 @@ export interface Layout {
|
|
|
325
333
|
/** How a shown guide of each kind looks: `default guide node` and the rest. */
|
|
326
334
|
guideLooks: Record<'node' | 'edge' | 'point' | 'region', Attrs>;
|
|
327
335
|
}
|
|
336
|
+
/**
|
|
337
|
+
* Whether a deck, which draws no outline of its own, was given one: a fill, or
|
|
338
|
+
* something about its border.
|
|
339
|
+
*/
|
|
340
|
+
export declare function outlineStated(appearance: Attrs): boolean;
|
|
328
341
|
/**
|
|
329
342
|
* Whether a node is joined to its container's text, directly or through
|
|
330
343
|
* siblings joined to it: one unit with the text, placed by the text's position
|
package/dist/model.js
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Whether a deck, which draws no outline of its own, was given one: a fill, or
|
|
3
|
+
* something about its border.
|
|
4
|
+
*/
|
|
5
|
+
export function outlineStated(appearance) {
|
|
6
|
+
return appearance['fill'] !== undefined || appearance['border'] !== undefined || appearance['border.thickness'] !== undefined;
|
|
7
|
+
}
|
|
1
8
|
/**
|
|
2
9
|
* Whether a node is joined to its container's text, directly or through
|
|
3
10
|
* siblings joined to it: one unit with the text, placed by the text's position
|
package/dist/page.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { type Finding } from './checks.js';
|
|
2
|
+
import type { DrawOptions } from './index.js';
|
|
3
|
+
/**
|
|
4
|
+
* `reladraw render --page`: one diagram in one self-contained HTML page, made
|
|
5
|
+
* for looking at rather than embedding. The page is the diagram's own colors,
|
|
6
|
+
* headed with its title, and it pans, zooms, goes full screen, saves the SVG
|
|
7
|
+
* or a PNG, lists the findings, and names a box under the pointer. It needs
|
|
8
|
+
* nothing running and fetches nothing, so it can be attached, mailed or
|
|
9
|
+
* committed. `name` is the file's name, the title when the file states none.
|
|
10
|
+
*/
|
|
11
|
+
export declare function drawPage(source: string, name: string, options?: DrawOptions): {
|
|
12
|
+
html: string;
|
|
13
|
+
findings: Finding[];
|
|
14
|
+
};
|