reladraw 0.15.1 → 0.17.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/dist/lexer.d.ts CHANGED
@@ -5,6 +5,12 @@ export interface Token {
5
5
  quoted: boolean;
6
6
  /** True when the string was written between `"""` marks. */
7
7
  triple?: boolean;
8
+ /**
9
+ * The whole word as written, on a key split from its value: `gap:tight` lexes
10
+ * as `gap:` and `tight`, and this is `gap:tight` on the first. Kept so an error
11
+ * about the word can quote what the author typed.
12
+ */
13
+ joined?: string;
8
14
  }
9
15
  /**
10
16
  * A `"""` string still open at the end of the text given. `parse` catches this
@@ -37,5 +43,11 @@ export declare class OpenString extends SourceError {
37
43
  * Returns an empty array for a blank or comment-only line.
38
44
  */
39
45
  export declare function tokenizeLine(line: string, lineNumber: number, depth?: number): Token[];
46
+ /**
47
+ * The character in a word that a name may not hold, if any. A colon makes the
48
+ * word a key, written with or without its space, and `;` is kept free so it
49
+ * could one day separate clauses without changing what any file means.
50
+ */
51
+ export declare function nameMark(token: Token): ':' | ';' | undefined;
40
52
  /** A bare token ending in `:` opens the attribute section of a statement. */
41
53
  export declare function isAttrKey(token: Token): boolean;
package/dist/lexer.js CHANGED
@@ -1,4 +1,10 @@
1
1
  import { SourceError } from './errors.js';
2
+ /**
3
+ * A key written against its value. The key part is spelled as the highlighter's
4
+ * attribute pattern spells one, and a value opening with a slash is left whole,
5
+ * so a file name such as `C:/icons/disk.svg` is not torn at the drive letter.
6
+ */
7
+ const JOINED_KEY = /^([A-Za-z][A-Za-z0-9_-]*:)([^/\\].*)$/;
2
8
  /**
3
9
  * A `"""` string still open at the end of the text given. `parse` catches this
4
10
  * one, adds the next line and tries again, which is how a string runs over
@@ -93,6 +99,7 @@ export function tokenizeLine(line, lineNumber, depth = 0) {
93
99
  tokens.push({ text, quoted: true });
94
100
  continue;
95
101
  }
102
+ const start = i;
96
103
  let text = '';
97
104
  while (i < line.length) {
98
105
  const c = line[i];
@@ -105,10 +112,37 @@ export function tokenizeLine(line, lineNumber, depth = 0) {
105
112
  text += c;
106
113
  i += 1;
107
114
  }
115
+ // `gap:tight` is `gap: tight` with no space, since how much whitespace there
116
+ // is never matters. A word straight after a key is its value and is left
117
+ // whole, so `icon: a:b` still names an icon called `a:b`. The rest of the
118
+ // word is read again from just past the colon rather than kept as one
119
+ // token, so `line:(color:red)` opens its bracket as `line: (color: red)` does.
120
+ const previous = tokens[tokens.length - 1];
121
+ const joined = previous && isAttrKey(previous) ? null : JOINED_KEY.exec(text);
122
+ if (joined) {
123
+ tokens.push({ text: joined[1], quoted: false, joined: text });
124
+ i = start + joined[1].length;
125
+ continue;
126
+ }
108
127
  tokens.push({ text, quoted: false });
109
128
  }
110
129
  return tokens;
111
130
  }
131
+ /**
132
+ * The character in a word that a name may not hold, if any. A colon makes the
133
+ * word a key, written with or without its space, and `;` is kept free so it
134
+ * could one day separate clauses without changing what any file means.
135
+ */
136
+ export function nameMark(token) {
137
+ const written = token.joined ?? token.text;
138
+ if (token.quoted)
139
+ return undefined;
140
+ if (written.includes(':'))
141
+ return ':';
142
+ if (written.includes(';'))
143
+ return ';';
144
+ return undefined;
145
+ }
112
146
  /** A bare token ending in `:` opens the attribute section of a statement. */
113
147
  export function isAttrKey(token) {
114
148
  return !token.quoted && token.text.length > 1 && token.text.endsWith(':');
@@ -0,0 +1,96 @@
1
+ import type { Layout, LayoutEdge, LayoutNode } from './model.js';
2
+ export interface Point {
3
+ x: number;
4
+ y: number;
5
+ }
6
+ /** A rectangle as drawn: the node's face, which differs from its box only for a deck. */
7
+ export interface Face {
8
+ x: number;
9
+ y: number;
10
+ width: number;
11
+ height: number;
12
+ /** A circle is drawn in this square, so a line meets the circle. */
13
+ round: boolean;
14
+ }
15
+ export type Side = 'top' | 'bottom' | 'left' | 'right';
16
+ /** One piece of a drawn line, from where the last one ended: straight, or a cubic. */
17
+ export type Piece = {
18
+ to: Point;
19
+ } | {
20
+ c1: Point;
21
+ c2: Point;
22
+ to: Point;
23
+ };
24
+ /** One line, worked out. */
25
+ export interface Route {
26
+ edge: LayoutEdge;
27
+ /** Where the line starts; each piece runs on from the end of the one before. */
28
+ start: Point;
29
+ pieces: Piece[];
30
+ /**
31
+ * The line's corners, ends included: two points for a straight line, the
32
+ * square route's corners for a square one, and for a curved one the points
33
+ * the curve passes through.
34
+ */
35
+ points: Point[];
36
+ /** Each named leg, as drawn, in the direction the line travels. */
37
+ legs: Map<string, Point[]>;
38
+ /** Each stop the line passes, as written, and the points it put on the line: `req b top` finds its run here (4.6). */
39
+ stops: {
40
+ written: string;
41
+ points: Point[];
42
+ }[];
43
+ /**
44
+ * Pieces not drawn, as [first, past the last]: a member's way along a
45
+ * collapsed bundle, which the bus draws once (6.6). The line still travels
46
+ * there, so the trace and every finding include them.
47
+ */
48
+ hidden?: [number, number][];
49
+ }
50
+ /** Where every line in the layout goes. */
51
+ export declare function planLines(layout: Layout): Map<LayoutEdge, Route>;
52
+ /** The ends sharing one side of one box, in their order along it. */
53
+ export interface SideEnds {
54
+ node: LayoutNode;
55
+ side: Side;
56
+ /** Where each end landed, in order along the side, the line it belongs to, and which of the line's ends it is. */
57
+ ends: {
58
+ at: Point;
59
+ edge: LayoutEdge;
60
+ which: 'from' | 'to';
61
+ }[];
62
+ }
63
+ /** Every line, and every side two or more ends share, for the findings to measure. */
64
+ export declare function planSides(layout: Layout): {
65
+ routes: Map<LayoutEdge, Route>;
66
+ sides: SideEnds[];
67
+ };
68
+ /** The drawn rectangle of a node. */
69
+ export declare function faceOfNode(node: LayoutNode): Face;
70
+ /** The point a share of the way along a polyline, bends included, or its start or end. */
71
+ export declare function alongLength(trace: Point[], at: number | 'start' | 'end'): Point;
72
+ export declare function centerOf(face: Face): Point;
73
+ /** The points with repeats and points in line with both neighbors dropped. */
74
+ export declare function tidyCorners(points: Point[]): Point[];
75
+ /** The line as drawn, as a polyline: curves flattened, everything else its own points. */
76
+ export declare function traceRoute(route: Route): Point[];
77
+ /** A line's pieces with those along a collapsed bundle left out, as the runs either side of each. */
78
+ export declare function visibleRuns(route: Route): {
79
+ start: Point;
80
+ pieces: Route['pieces'];
81
+ }[];
82
+ /** The line as drawn, as polylines: its trace with any stretch along a collapsed bundle left out. */
83
+ export declare function traceVisible(route: Route): Point[][];
84
+ /**
85
+ * Where two drawn lines cross, with the way each runs there. Lines that only
86
+ * touch or run together don't cross, and nor do two lines nearer than `clear`
87
+ * to an end of either: that is two lines meeting at a box, not passing each
88
+ * other. The renderer jumps these and the `edge-crossings` finding counts
89
+ * them, so the two agree.
90
+ */
91
+ export declare function crossingPoints(a: Point[], b: Point[], clear: number): {
92
+ at: Point;
93
+ along: Point;
94
+ other: Point;
95
+ }[];
96
+ export declare function describeEdge(edge: LayoutEdge): string;