@elicdavis/node-flow 0.1.14 → 0.1.16
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/.mocharc.json +5 -0
- package/dist/index.d.mts +62 -1
- package/dist/index.d.ts +62 -1
- package/dist/index.js +3197 -3337
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +3189 -3337
- package/dist/index.mjs.map +1 -1
- package/package.json +4 -2
- package/src/graph.ts +7 -0
- package/src/index.ts +66 -40
- package/src/markdown/entry.ts +21 -2
- package/src/markdown/lexicalParser.ts +22 -32
- package/src/markdown/syntaxParser.ts +93 -68
- package/src/node.ts +61 -25
- package/src/nodes/subsystem.ts +7 -7
- package/src/organize.ts +276 -181
- package/src/port.ts +130 -7
- package/src/styles/text.ts +8 -0
- package/src/types/text.ts +6 -4
- package/src/utils/string.ts +7 -1
- package/src/widgets/color.ts +5 -6
- package/src/widgets/factory.ts +1 -1
- package/src/widgets/number.ts +2 -2
- package/src/widgets/slider.ts +2 -2
- package/src/widgets/string.ts +2 -2
- package/src/widgets/toggle.ts +2 -2
- package/src/widgets/widget.ts +22 -0
- package/test/markdown.test.ts +165 -0
- package/test/organize.test.ts +156 -0
- package/test/port.test.ts +125 -0
- package/tsconfig.json +6 -2
- package/dist/web/NodeFlow.js +0 -8
- package/dist/web/NodeFlow.js.map +0 -7
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@elicdavis/node-flow",
|
|
3
3
|
"description": "build node graphs",
|
|
4
4
|
"author": "Eli C Davis",
|
|
5
|
-
"version": "0.1.
|
|
5
|
+
"version": "0.1.16",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"keywords": [
|
|
8
8
|
"nodes",
|
|
@@ -15,7 +15,9 @@
|
|
|
15
15
|
"scripts": {
|
|
16
16
|
"build": "ts-node ./esbuild.ts",
|
|
17
17
|
"watch": "npm run build -- --watch",
|
|
18
|
-
"package": "tsup"
|
|
18
|
+
"package": "tsup",
|
|
19
|
+
"test": "mocha",
|
|
20
|
+
"typecheck": "tsc --noEmit"
|
|
19
21
|
},
|
|
20
22
|
"homepage": "https://github.com/EliCDavis/node-flow",
|
|
21
23
|
"repository": {
|
package/src/graph.ts
CHANGED
|
@@ -403,6 +403,13 @@ export class NodeFlowGraph {
|
|
|
403
403
|
this.#camera.setOrientation(orientation);
|
|
404
404
|
}
|
|
405
405
|
|
|
406
|
+
/**
|
|
407
|
+
* Resets the camera to the default orientation (origin, zoom 1).
|
|
408
|
+
*/
|
|
409
|
+
resetCamera(): void {
|
|
410
|
+
this.#camera.reset();
|
|
411
|
+
}
|
|
412
|
+
|
|
406
413
|
/**
|
|
407
414
|
* Adjusts camera position and zoom so all nodes fit in view (~10% padding).
|
|
408
415
|
* Falls back to camera.reset() when there are no nodes.
|
package/src/index.ts
CHANGED
|
@@ -1,40 +1,66 @@
|
|
|
1
|
-
export * from './graph';
|
|
2
|
-
export * from './node';
|
|
3
|
-
|
|
4
|
-
import { ContextMenuConfig, ContextMenuItemConfig, ContextMenuItemState } from './contextMenu';
|
|
5
|
-
export { ContextMenuConfig, ContextMenuItemConfig, ContextMenuItemState };
|
|
6
|
-
|
|
7
|
-
import { Theme } from './theme';
|
|
8
|
-
export { Theme };
|
|
9
|
-
|
|
10
|
-
import { Publisher, PublisherConfig } from './nodes/publisher';
|
|
11
|
-
export { Publisher, PublisherConfig };
|
|
12
|
-
|
|
13
|
-
import { FlowNote, FlowNoteConfig, NoteContentChangeCallback, NoteWidthChangeCallback } from './notes/note';
|
|
14
|
-
export { FlowNote, FlowNoteConfig, NoteContentChangeCallback, NoteWidthChangeCallback };
|
|
15
|
-
|
|
16
|
-
import {
|
|
17
|
-
NoteAddedCallback, NoteDragStartCallback, NoteDragStopCallback,
|
|
18
|
-
NoteRemovedCallback, NoteSubsystemConfig
|
|
19
|
-
} from './notes/subsystem';
|
|
20
|
-
export {
|
|
21
|
-
NoteAddedCallback, NoteDragStartCallback, NoteDragStopCallback,
|
|
22
|
-
NoteRemovedCallback, NoteSubsystemConfig
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
//
|
|
26
|
-
import {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
import {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
1
|
+
export * from './graph';
|
|
2
|
+
export * from './node';
|
|
3
|
+
|
|
4
|
+
import { ContextMenuConfig, ContextMenuItemConfig, ContextMenuItemState } from './contextMenu';
|
|
5
|
+
export { ContextMenuConfig, ContextMenuItemConfig, ContextMenuItemState };
|
|
6
|
+
|
|
7
|
+
import { Theme } from './theme';
|
|
8
|
+
export { Theme };
|
|
9
|
+
|
|
10
|
+
import { Publisher, PublisherConfig } from './nodes/publisher';
|
|
11
|
+
export { Publisher, PublisherConfig };
|
|
12
|
+
|
|
13
|
+
import { FlowNote, FlowNoteConfig, NoteContentChangeCallback, NoteWidthChangeCallback } from './notes/note';
|
|
14
|
+
export { FlowNote, FlowNoteConfig, NoteContentChangeCallback, NoteWidthChangeCallback };
|
|
15
|
+
|
|
16
|
+
import {
|
|
17
|
+
NoteAddedCallback, NoteDragStartCallback, NoteDragStopCallback,
|
|
18
|
+
NoteRemovedCallback, NoteSubsystemConfig
|
|
19
|
+
} from './notes/subsystem';
|
|
20
|
+
export {
|
|
21
|
+
NoteAddedCallback, NoteDragStartCallback, NoteDragStopCallback,
|
|
22
|
+
NoteRemovedCallback, NoteSubsystemConfig
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
// Ports
|
|
26
|
+
import { Port, PortConfig, PortStyle, PortType, portsCompatible } from './port';
|
|
27
|
+
export { Port, PortConfig, PortStyle, PortType, portsCompatible };
|
|
28
|
+
|
|
29
|
+
// Connections
|
|
30
|
+
import {
|
|
31
|
+
Connection, ConnectionRenderer, ConnectionRendererParams, DefaultConnectionRenderer
|
|
32
|
+
} from './connection';
|
|
33
|
+
export { Connection, ConnectionRenderer, ConnectionRendererParams, DefaultConnectionRenderer };
|
|
34
|
+
|
|
35
|
+
// Node factory
|
|
36
|
+
import { NodeCreatedCallback, NodeFactory, NodeFactoryConfig } from './nodes/factory';
|
|
37
|
+
export { NodeCreatedCallback, NodeFactory, NodeFactoryConfig };
|
|
38
|
+
|
|
39
|
+
// Widgets
|
|
40
|
+
import { Widget } from './widgets/widget';
|
|
41
|
+
import { NumberWidget, NumberWidgetConfig } from './widgets/number';
|
|
42
|
+
import { ColorWidget, ColorWidgetConfig } from './widgets/color';
|
|
43
|
+
import { StringWidget, StringWidgetConfig } from './widgets/string';
|
|
44
|
+
import { TextWidget, TextWidgetConfig } from './widgets/text';
|
|
45
|
+
import { ButtonWidget, ButtonWidgetConfig } from './widgets/button';
|
|
46
|
+
import { ToggleWidget, ToggleWidgetConfig, ToggleStyleConfig } from './widgets/toggle';
|
|
47
|
+
import { SliderWidget, SliderWidgetConfig } from './widgets/slider';
|
|
48
|
+
import { ImageWidget, ImageWidgetConfig } from './widgets/image';
|
|
49
|
+
export {
|
|
50
|
+
Widget,
|
|
51
|
+
NumberWidget, ColorWidget, StringWidget, TextWidget,
|
|
52
|
+
ButtonWidget, ToggleWidget, SliderWidget, ImageWidget
|
|
53
|
+
};
|
|
54
|
+
export type {
|
|
55
|
+
NumberWidgetConfig, ColorWidgetConfig, StringWidgetConfig, TextWidgetConfig,
|
|
56
|
+
ButtonWidgetConfig, ToggleWidgetConfig, ToggleStyleConfig, SliderWidgetConfig,
|
|
57
|
+
ImageWidgetConfig
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
import { GlobalWidgetFactory, WidgetBuilder, WidgetFactory } from './widgets/factory';
|
|
61
|
+
export { GlobalWidgetFactory, WidgetFactory };
|
|
62
|
+
export type { WidgetBuilder };
|
|
63
|
+
|
|
64
|
+
import { Box } from './types/box';
|
|
65
|
+
import { Vector2 } from './types/vector2';
|
|
66
|
+
export type { Box, Vector2 };
|
package/src/markdown/entry.ts
CHANGED
|
@@ -7,6 +7,13 @@ export interface MarkdownEntry {
|
|
|
7
7
|
render(ctx: CanvasRenderingContext2D, position: Vector2, scale: number, maxWidth: number): number
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
+
function onFontsLoaded(callback: () => void): void {
|
|
11
|
+
if (typeof document === "undefined" || document.fonts === undefined) {
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
document.fonts.addEventListener("loadingdone", () => callback());
|
|
15
|
+
}
|
|
16
|
+
|
|
10
17
|
export class CodeBlockEntry {
|
|
11
18
|
|
|
12
19
|
#text: Text
|
|
@@ -17,6 +24,10 @@ export class CodeBlockEntry {
|
|
|
17
24
|
|
|
18
25
|
#calculatedForWidth: number;
|
|
19
26
|
|
|
27
|
+
text(): Text {
|
|
28
|
+
return this.#text;
|
|
29
|
+
}
|
|
30
|
+
|
|
20
31
|
constructor(text: Text) {
|
|
21
32
|
this.#text = text;
|
|
22
33
|
this.#calculatedForWidth = -1
|
|
@@ -24,7 +35,7 @@ export class CodeBlockEntry {
|
|
|
24
35
|
this.#calculatedEntries = new List<Text>();
|
|
25
36
|
this.#calculatedPositions = new List<Vector2>();
|
|
26
37
|
|
|
27
|
-
|
|
38
|
+
onFontsLoaded(() => {
|
|
28
39
|
this.#calculatedForWidth = -1
|
|
29
40
|
});
|
|
30
41
|
}
|
|
@@ -113,6 +124,10 @@ export class UnorderedListMarkdownEntry {
|
|
|
113
124
|
this.#entries = entries;
|
|
114
125
|
}
|
|
115
126
|
|
|
127
|
+
entries(): ReadonlyArray<BasicMarkdownEntry> {
|
|
128
|
+
return this.#entries;
|
|
129
|
+
}
|
|
130
|
+
|
|
116
131
|
render(ctx: CanvasRenderingContext2D, position: Vector2, scale: number, maxWidth: number): number {
|
|
117
132
|
let offset = 0;
|
|
118
133
|
let shift = 20;
|
|
@@ -152,6 +167,10 @@ export class BasicMarkdownEntry {
|
|
|
152
167
|
|
|
153
168
|
#calculatedForWidth: number;
|
|
154
169
|
|
|
170
|
+
lines(): ReadonlyArray<Text> {
|
|
171
|
+
return this.#entries;
|
|
172
|
+
}
|
|
173
|
+
|
|
155
174
|
constructor(lines: Array<Text>, underline: boolean, background: boolean) {
|
|
156
175
|
this.#entries = lines;
|
|
157
176
|
this.#underline = underline;
|
|
@@ -161,7 +180,7 @@ export class BasicMarkdownEntry {
|
|
|
161
180
|
this.#calculatedEntries = new List<Text>();
|
|
162
181
|
this.#calculatedPositions = new List<Vector2>();
|
|
163
182
|
|
|
164
|
-
|
|
183
|
+
onFontsLoaded(() => {
|
|
165
184
|
this.#calculatedForWidth = -1
|
|
166
185
|
});
|
|
167
186
|
}
|
|
@@ -37,32 +37,27 @@ export class MarkdownLexicalParser {
|
|
|
37
37
|
return this.#body.charAt(this.#index);
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
-
#
|
|
41
|
-
|
|
42
|
-
#addToken(token: MarkdownTokenType, lexeme: string): void {
|
|
43
|
-
this.#tokens.push(new MarkdownToken(token, lexeme, this.#lastToken, this.#index));
|
|
44
|
-
this.#lastToken = this.#index;
|
|
45
|
-
}
|
|
40
|
+
#tokenStart = 0;
|
|
46
41
|
|
|
47
|
-
#
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
this.#addToken(MarkdownTokenType.H3, "###");
|
|
42
|
+
#addToken(token: MarkdownTokenType, lexeme: string, start?: number): void {
|
|
43
|
+
this.#tokens.push(new MarkdownToken(token, lexeme, start ?? this.#tokenStart, this.#index));
|
|
44
|
+
}
|
|
51
45
|
|
|
52
|
-
|
|
46
|
+
#header(): void {
|
|
47
|
+
let count = 0;
|
|
48
|
+
while (this.#current() === "#") {
|
|
49
|
+
count++;
|
|
53
50
|
this.#inc();
|
|
54
|
-
} else {
|
|
55
|
-
this.#addToken(MarkdownTokenType.H2, "##");
|
|
56
51
|
}
|
|
57
|
-
}
|
|
58
52
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
this.#addToken(MarkdownTokenType.H1, "#");
|
|
53
|
+
let type = MarkdownTokenType.H3;
|
|
54
|
+
if (count === 1) {
|
|
55
|
+
type = MarkdownTokenType.H1;
|
|
56
|
+
} else if (count === 2) {
|
|
57
|
+
type = MarkdownTokenType.H2;
|
|
65
58
|
}
|
|
59
|
+
|
|
60
|
+
this.#addToken(type, "#".repeat(count));
|
|
66
61
|
}
|
|
67
62
|
|
|
68
63
|
#whiteSpace(): void {
|
|
@@ -110,34 +105,29 @@ export class MarkdownLexicalParser {
|
|
|
110
105
|
}
|
|
111
106
|
|
|
112
107
|
if (started != -1) {
|
|
113
|
-
this.#addToken(MarkdownTokenType.Text, this.#body.substring(started, this.#index))
|
|
108
|
+
this.#addToken(MarkdownTokenType.Text, this.#body.substring(started, this.#index), started)
|
|
114
109
|
}
|
|
115
110
|
}
|
|
116
111
|
|
|
117
|
-
// S( ) => S
|
|
118
|
-
// S(\t) => S
|
|
119
|
-
// S(#) => H1
|
|
120
|
-
// H1(#) => H2
|
|
121
|
-
// H1(!#) => S
|
|
122
|
-
// H2(#) => H3
|
|
123
|
-
// H2(#) => H3
|
|
124
112
|
parse(): void {
|
|
125
113
|
let char = this.#current();
|
|
126
114
|
|
|
127
115
|
while (char !== "") {
|
|
116
|
+
this.#tokenStart = this.#index;
|
|
117
|
+
|
|
128
118
|
if (char === " " || char === "\t") {
|
|
129
119
|
this.#whiteSpace();
|
|
130
120
|
} else if (char === "#") {
|
|
131
|
-
this.#
|
|
121
|
+
this.#header();
|
|
132
122
|
} else if (char === "\n") {
|
|
133
|
-
this.#addToken(MarkdownTokenType.NewLine, "\n");
|
|
134
123
|
this.#inc();
|
|
124
|
+
this.#addToken(MarkdownTokenType.NewLine, "\n");
|
|
135
125
|
} else if (char === "*") {
|
|
136
|
-
this.#addToken(MarkdownTokenType.Star, "*");
|
|
137
126
|
this.#inc();
|
|
127
|
+
this.#addToken(MarkdownTokenType.Star, "*");
|
|
138
128
|
} else if (char === "`") {
|
|
139
|
-
this.#addToken(MarkdownTokenType.BackTick, "`");
|
|
140
129
|
this.#inc();
|
|
130
|
+
this.#addToken(MarkdownTokenType.BackTick, "`");
|
|
141
131
|
} else {
|
|
142
132
|
this.#text();
|
|
143
133
|
}
|
|
@@ -31,21 +31,18 @@ export class MarkdownSyntaxParser {
|
|
|
31
31
|
|
|
32
32
|
#next(): MarkdownToken | null {
|
|
33
33
|
this.#index++
|
|
34
|
-
if (this.#index >= this.#tokens.length
|
|
34
|
+
if (this.#index >= this.#tokens.length) {
|
|
35
35
|
return null
|
|
36
36
|
}
|
|
37
37
|
return this.#tokens[this.#index];
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
#peak(): MarkdownToken | null {
|
|
41
|
-
|
|
42
|
-
return null
|
|
43
|
-
}
|
|
44
|
-
return this.#tokens[this.#index + 1];
|
|
41
|
+
return this.#peakInto(1);
|
|
45
42
|
}
|
|
46
43
|
|
|
47
44
|
#peakInto(amount: number): MarkdownToken | null {
|
|
48
|
-
if (this.#index + amount >= this.#tokens.length
|
|
45
|
+
if (this.#index + amount >= this.#tokens.length) {
|
|
49
46
|
return null
|
|
50
47
|
}
|
|
51
48
|
return this.#tokens[this.#index + amount];
|
|
@@ -53,82 +50,107 @@ export class MarkdownSyntaxParser {
|
|
|
53
50
|
|
|
54
51
|
#emphasis(): Array<Text> {
|
|
55
52
|
|
|
56
|
-
//
|
|
57
|
-
//
|
|
58
|
-
//
|
|
59
|
-
//
|
|
60
|
-
//
|
|
61
|
-
//
|
|
62
|
-
//
|
|
63
|
-
|
|
64
|
-
//
|
|
65
|
-
//
|
|
66
|
-
//
|
|
67
|
-
|
|
68
|
-
// 11. * Test: <ul>Test</ul>
|
|
69
|
-
|
|
70
|
-
let token = this.#next();
|
|
71
|
-
if (token?.type() === MarkdownTokenType.Space) {
|
|
53
|
+
// Count the stars either side of the content and match as many as
|
|
54
|
+
// both ends can supply; the rest stay on the line as characters.
|
|
55
|
+
//
|
|
56
|
+
// *a* -> <i>a</i> **a* -> *<i>a</i>
|
|
57
|
+
// **a** -> <b>a</b> *a** -> <i>a</i>*
|
|
58
|
+
// **a f** -> <b>a f</b> *a -> *a
|
|
59
|
+
// ** a ** -> ** a ** **a ** -> **a **
|
|
60
|
+
|
|
61
|
+
// A star with a space after it opens nothing, so leave the space
|
|
62
|
+
// where it is rather than consuming it - the caller still has to
|
|
63
|
+
// read it as part of the line.
|
|
64
|
+
if (this.#peak()?.type() === MarkdownTokenType.Space) {
|
|
72
65
|
return [new Text("*")];
|
|
73
66
|
}
|
|
74
67
|
|
|
75
|
-
|
|
76
|
-
// Read off all leading stars
|
|
77
|
-
while (token !== null && token.type() === MarkdownTokenType.Star) {
|
|
78
|
-
bold = true;
|
|
79
|
-
token = this.#next();
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
let textContent = "";
|
|
68
|
+
const openers = this.#runOfStars();
|
|
83
69
|
|
|
84
|
-
let
|
|
85
|
-
let
|
|
86
|
-
|
|
87
|
-
|
|
70
|
+
let content = "";
|
|
71
|
+
let closers = 0;
|
|
72
|
+
while (true) {
|
|
73
|
+
const token = this.#current();
|
|
74
|
+
if (token === null || token.type() === MarkdownTokenType.NewLine) {
|
|
75
|
+
break;
|
|
76
|
+
}
|
|
88
77
|
if (token.type() === MarkdownTokenType.Star) {
|
|
78
|
+
closers = this.#runOfStars();
|
|
79
|
+
break;
|
|
80
|
+
}
|
|
81
|
+
content += token.lexeme();
|
|
82
|
+
this.#inc();
|
|
83
|
+
}
|
|
89
84
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
break;
|
|
94
|
-
}
|
|
85
|
+
// Leave the reader on the last token taken, since the caller steps
|
|
86
|
+
// forward once more before looking at anything.
|
|
87
|
+
this.#index--;
|
|
95
88
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
89
|
+
// A run of stars only emphasises what it hugs. With a space against
|
|
90
|
+
// the inside of either end, or nothing between them at all, the
|
|
91
|
+
// stars are just stars.
|
|
92
|
+
const hugsContent = content !== ""
|
|
93
|
+
&& content.trimStart() === content
|
|
94
|
+
&& content.trimEnd() === content;
|
|
102
95
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
96
|
+
const matched = hugsContent ? Math.min(openers, closers) : 0;
|
|
97
|
+
if (matched === 0) {
|
|
98
|
+
return [new Text("*".repeat(openers) + content + "*".repeat(closers))];
|
|
99
|
+
}
|
|
106
100
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
101
|
+
const style: TextStyleConfig = {};
|
|
102
|
+
if (matched >= 2) {
|
|
103
|
+
style.weight = FontWeight.Bold;
|
|
104
|
+
} else {
|
|
105
|
+
style.style = FontStyle.Italic;
|
|
106
|
+
}
|
|
112
107
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
108
|
+
// Stars past the pair that matched were never part of the emphasis,
|
|
109
|
+
// so they stay on the line as the characters they are.
|
|
110
|
+
const runs = new Array<Text>();
|
|
111
|
+
if (openers > matched) {
|
|
112
|
+
runs.push(new Text("*".repeat(openers - matched)));
|
|
113
|
+
}
|
|
114
|
+
runs.push(new Text(content, style));
|
|
115
|
+
if (closers > matched) {
|
|
116
|
+
runs.push(new Text("*".repeat(closers - matched)));
|
|
117
|
+
}
|
|
118
|
+
return runs;
|
|
119
|
+
}
|
|
117
120
|
|
|
118
|
-
|
|
121
|
+
/** Consumes a run of stars, leaving the reader on the token after it. */
|
|
122
|
+
#runOfStars(): number {
|
|
123
|
+
let count = 0;
|
|
124
|
+
while (this.#current()?.type() === MarkdownTokenType.Star) {
|
|
125
|
+
count++;
|
|
126
|
+
this.#inc();
|
|
119
127
|
}
|
|
128
|
+
return count;
|
|
129
|
+
}
|
|
120
130
|
|
|
121
|
-
|
|
131
|
+
/**
|
|
132
|
+
* Reads `code` up to the closing backtick on the same line. An opening
|
|
133
|
+
* backtick with no partner is only a backtick.
|
|
134
|
+
*/
|
|
135
|
+
#inlineCode(): Array<Text> {
|
|
136
|
+
const opened = this.#index;
|
|
122
137
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
138
|
+
this.#inc();
|
|
139
|
+
let content = "";
|
|
140
|
+
while (true) {
|
|
141
|
+
const token = this.#current();
|
|
142
|
+
if (token === null || token.type() === MarkdownTokenType.NewLine) {
|
|
143
|
+
this.#index = opened;
|
|
144
|
+
return [new Text("`")];
|
|
128
145
|
}
|
|
146
|
+
if (token.type() === MarkdownTokenType.BackTick) {
|
|
147
|
+
break;
|
|
148
|
+
}
|
|
149
|
+
content += token.lexeme();
|
|
150
|
+
this.#inc();
|
|
129
151
|
}
|
|
130
152
|
|
|
131
|
-
return [new Text(
|
|
153
|
+
return [new Text(content, { font: "monospace" })];
|
|
132
154
|
}
|
|
133
155
|
|
|
134
156
|
#text(): Array<Text> {
|
|
@@ -153,13 +175,16 @@ export class MarkdownSyntaxParser {
|
|
|
153
175
|
break;
|
|
154
176
|
|
|
155
177
|
case MarkdownTokenType.Star:
|
|
178
|
+
case MarkdownTokenType.BackTick:
|
|
156
179
|
if (textContent !== "") {
|
|
157
180
|
contents.push(new Text(textContent))
|
|
158
181
|
textContent = "";
|
|
159
182
|
}
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
183
|
+
const runs = token.type() === MarkdownTokenType.Star
|
|
184
|
+
? this.#emphasis()
|
|
185
|
+
: this.#inlineCode();
|
|
186
|
+
for (let i = 0; i < runs.length; i++) {
|
|
187
|
+
contents.push(runs[i]);
|
|
163
188
|
}
|
|
164
189
|
break;
|
|
165
190
|
}
|