@apollohg/react-native-rich-text-editor 2.0.0 → 2.0.2
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 +8 -116
- package/THIRD_PARTY_NOTICES.md +1 -1
- package/android/build.gradle +3 -0
- package/android/src/main/java/com/apollohg/editor/EditorEditTextImages.kt +25 -0
- package/android/src/main/java/com/apollohg/editor/EditorV2RenderValidation.kt +1 -0
- package/android/src/main/java/com/apollohg/editor/ImageResizeOverlayView.kt +101 -33
- package/android/src/main/java/com/apollohg/editor/RenderMediaSpans.kt +15 -3
- package/android/src/main/java/com/apollohg/editor/RichTextEditorView.kt +14 -0
- package/android/src/main/java/com/apollohg/editor/viewer/AndroidProseLayoutEngine.kt +1 -1
- package/app.plugin.js +42 -39
- package/dist/AtomHost.js +18 -11
- package/dist/EditorAddon.js +4 -2
- package/dist/EditorAddonNormalization.js +17 -9
- package/dist/EditorMentionThemeNormalization.js +6 -3
- package/dist/EditorMentionThemeValidation.js +28 -11
- package/dist/EditorStyleSheetNormalization.js +85 -38
- package/dist/EditorStyleSheetTypes.d.ts +1 -1
- package/dist/EditorTheme.d.ts +4 -0
- package/dist/EditorTheme.js +5 -3
- package/dist/EditorToolbarComponent.d.ts +1 -1
- package/dist/EditorToolbarComponent.js +1 -1
- package/dist/EditorToolbarRegistry.js +5 -5
- package/dist/EditorToolbarTypes.d.ts +12 -12
- package/dist/EditorToolbarVisuals.js +1 -1
- package/dist/ExternalTextComposition.js +89 -43
- package/dist/ImageLoadingPolicy.d.ts +1 -1
- package/dist/NativeEditorBoundaryError.d.ts +7 -7
- package/dist/NativeEditorBoundaryError.js +9 -5
- package/dist/NativeEditorCollaborationTransport.d.ts +7 -7
- package/dist/NativeEditorCollaborationTransport.js +28 -15
- package/dist/NativeEditorCreateConfig.js +11 -6
- package/dist/NativeEditorCreateJson.js +51 -25
- package/dist/NativeEditorCreateValidation.js +11 -6
- package/dist/NativeEditorDocumentBridge.d.ts +1 -1
- package/dist/NativeEditorDocumentBridge.js +32 -18
- package/dist/NativeEditorDocumentHandle.d.ts +4 -4
- package/dist/NativeEditorDocumentHandle.js +1 -1
- package/dist/NativeEditorLocalAwareness.js +25 -13
- package/dist/NativeEditorNativeModule.d.ts +8 -1
- package/dist/NativeEditorNativeModule.js +7 -5
- package/dist/NativeEditorRenderNormalization.js +66 -25
- package/dist/NativeEditorResultNormalization.js +53 -29
- package/dist/NativeEditorTypes.d.ts +10 -10
- package/dist/NativeEditorV2Decimal.js +6 -3
- package/dist/NativeProseViewer.js +11 -3
- package/dist/ResourceLimits.d.ts +2 -2
- package/dist/ResourceLimits.js +7 -2
- package/dist/RichTextEditor.js +1 -1
- package/dist/RichTextEditorNativeTypes.d.ts +1 -1
- package/dist/RichTextEditorNativeView.d.ts +1 -3
- package/dist/RichTextEditorSerialization.js +24 -14
- package/dist/RichTextEditorTypes.d.ts +1 -1
- package/dist/YjsCollaboration.d.ts +7 -7
- package/dist/YjsCollaboration.js +42 -26
- package/dist/addons.d.ts +4 -4
- package/dist/addons.js +3 -3
- package/dist/atomInstances.js +6 -3
- package/dist/atomUpdates.js +7 -4
- package/dist/atoms.js +20 -12
- package/dist/attributeValidation.js +55 -24
- package/dist/contentExpression.js +80 -42
- package/dist/listMarkers.d.ts +1 -1
- package/dist/listMarkers.js +1 -1
- package/dist/schemaDefinition.d.ts +1 -1
- package/dist/schemaDefinition.js +23 -14
- package/dist/schemaDocument.js +1 -1
- package/dist/schemaDocumentConstruction.js +25 -14
- package/dist/schemaNormalization.js +51 -29
- package/dist/schemaPresets.d.ts +1 -1
- package/dist/schemaPresets.js +9 -4
- package/dist/schemaResolution.js +46 -25
- package/dist/specs/PreparedProseViewerNativeComponent.d.ts +4 -0
- package/dist/useEditorToolbarInteractions.d.ts +2 -2
- package/dist/useEditorToolbarInteractions.js +45 -23
- package/dist/useEditorToolbarItems.d.ts +1 -1
- package/dist/useEditorToolbarItems.js +4 -3
- package/dist/useEditorToolbarPresentation.d.ts +3 -3
- package/dist/useEditorToolbarPresentation.js +4 -4
- package/dist/useEditorToolbarState.d.ts +1 -1
- package/dist/useEditorToolbarState.js +1 -1
- package/dist/useFocusPreservingFrames.js +11 -8
- package/dist/useNativeEditor.d.ts +1 -1
- package/dist/useNativeEditor.js +21 -11
- package/dist/useRichTextEditorCommands.d.ts +2 -2
- package/dist/useRichTextEditorCommands.js +59 -29
- package/dist/useRichTextEditorEvents.d.ts +3 -3
- package/dist/useRichTextEditorEvents.js +75 -32
- package/dist/useRichTextEditorMentions.d.ts +4 -4
- package/dist/useRichTextEditorMentions.js +48 -29
- package/dist/useRichTextEditorPresentation.d.ts +4 -4
- package/dist/useRichTextEditorPresentation.js +25 -23
- package/dist/useRichTextEditorState.d.ts +3 -3
- package/dist/useRichTextEditorState.js +20 -15
- package/dist/useRichTextEditorUpdates.d.ts +1 -1
- package/dist/useRichTextEditorUpdates.js +99 -41
- package/dist/useViewerAtoms.js +63 -36
- package/ios/EditorCore.xcframework/ios-arm64/libeditor_core.a +0 -0
- package/ios/EditorCore.xcframework/ios-arm64_x86_64-simulator/libeditor_core.a +0 -0
- package/ios/EditorInteractionOverlays.swift +114 -122
- package/ios/EditorLayoutManager.swift +13 -3
- package/ios/EditorStyleSheet.swift +12 -1
- package/ios/EditorTextView+Images.swift +32 -10
- package/ios/EditorTextView.swift +1 -1
- package/ios/EditorV2Adapter+RenderValidation.swift +2 -2
- package/ios/NativeToolbar+ButtonStyle.swift +17 -5
- package/ios/NativeToolbar+Diagnostics.swift +15 -0
- package/ios/RenderBridge+Atoms.swift +0 -1
- package/ios/RenderBridge+Attachments.swift +0 -29
- package/ios/RichTextEditorView.swift +4 -12
- package/ios/Viewer/CoreTextProseLayoutEngine+AttributedText.swift +3 -2
- package/package.json +11 -3
- package/react-native.config.js +1 -1
- package/rust/android/arm64-v8a/libeditor_core.so +0 -0
- package/rust/android/armeabi-v7a/libeditor_core.so +0 -0
- package/rust/android/x86/libeditor_core.so +0 -0
- package/rust/android/x86_64/libeditor_core.so +0 -0
- package/src/AtomHost.tsx +58 -28
- package/src/EditorAddon.ts +18 -8
- package/src/EditorAddonNormalization.ts +40 -11
- package/src/EditorMentionThemeNormalization.ts +15 -4
- package/src/EditorMentionThemeValidation.ts +51 -14
- package/src/EditorStyleSheet.ts +1 -0
- package/src/EditorStyleSheetNormalization.ts +195 -64
- package/src/EditorStyleSheetTypes.ts +1 -1
- package/src/EditorTheme.ts +13 -5
- package/src/EditorToolbarComponent.tsx +2 -1
- package/src/EditorToolbarRegistry.tsx +23 -13
- package/src/EditorToolbarTypes.tsx +12 -12
- package/src/EditorToolbarVisuals.tsx +6 -3
- package/src/EditorUpdateRevision.ts +1 -0
- package/src/ExternalTextComposition.ts +259 -49
- package/src/ImageLoadingPolicy.ts +3 -1
- package/src/NativeEditorBoundaryError.ts +38 -11
- package/src/NativeEditorCollaborationTransport.ts +108 -27
- package/src/NativeEditorCreateConfig.ts +92 -19
- package/src/NativeEditorCreateJson.ts +163 -26
- package/src/NativeEditorCreateValidation.ts +33 -12
- package/src/NativeEditorDocumentBridge.ts +111 -19
- package/src/NativeEditorDocumentHandle.ts +9 -4
- package/src/NativeEditorLocalAwareness.ts +70 -15
- package/src/NativeEditorNativeModule.ts +13 -9
- package/src/NativeEditorRenderNormalization.ts +128 -29
- package/src/NativeEditorResultNormalization.ts +143 -32
- package/src/NativeEditorTypes.ts +12 -11
- package/src/NativeEditorV2Decimal.ts +12 -3
- package/src/NativeProseViewer.tsx +46 -16
- package/src/ResourceLimits.ts +15 -8
- package/src/RichTextEditor.tsx +3 -1
- package/src/RichTextEditorNativeTypes.tsx +1 -1
- package/src/RichTextEditorNativeView.tsx +2 -8
- package/src/RichTextEditorSerialization.tsx +70 -24
- package/src/RichTextEditorTypes.tsx +1 -1
- package/src/YjsCollaboration.ts +143 -47
- package/src/addons.ts +12 -8
- package/src/atomInstances.ts +25 -5
- package/src/atomUpdates.ts +23 -6
- package/src/atoms.ts +85 -18
- package/src/attributeValidation.ts +97 -33
- package/src/contentExpression.ts +218 -63
- package/src/listMarkers.ts +1 -1
- package/src/schemaDefinition.ts +82 -20
- package/src/schemaDocument.ts +15 -1
- package/src/schemaDocumentConstruction.ts +80 -16
- package/src/schemaNormalization.ts +155 -41
- package/src/schemaPresets.ts +37 -31
- package/src/schemaResolution.ts +126 -27
- package/src/specs/PreparedProseViewerNativeComponent.ts +4 -2
- package/src/useEditorToolbarInteractions.tsx +85 -36
- package/src/useEditorToolbarItems.tsx +50 -22
- package/src/useEditorToolbarPresentation.tsx +81 -58
- package/src/useEditorToolbarState.tsx +8 -6
- package/src/useFocusPreservingFrames.ts +43 -15
- package/src/useNativeEditor.ts +111 -51
- package/src/useRichTextEditorCommands.tsx +127 -54
- package/src/useRichTextEditorEvents.tsx +144 -42
- package/src/useRichTextEditorMentions.tsx +118 -37
- package/src/useRichTextEditorPresentation.tsx +128 -114
- package/src/useRichTextEditorState.tsx +76 -40
- package/src/useRichTextEditorUpdates.tsx +207 -56
- package/src/useViewerAtoms.tsx +162 -66
package/src/contentExpression.ts
CHANGED
|
@@ -19,8 +19,13 @@ function collectExpressionSymbols(expression: Expression, symbols: Set<string>):
|
|
|
19
19
|
if (expression.kind === 'symbol') {
|
|
20
20
|
symbols.add(expression.symbol);
|
|
21
21
|
} else if (expression.kind !== 'empty') {
|
|
22
|
-
if (expression.kind === 'repeat')
|
|
23
|
-
|
|
22
|
+
if (expression.kind === 'repeat') {
|
|
23
|
+
collectExpressionSymbols(expression.expression, symbols);
|
|
24
|
+
} else {
|
|
25
|
+
for (const nested of expression.expressions) {
|
|
26
|
+
collectExpressionSymbols(nested, symbols);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
24
29
|
}
|
|
25
30
|
}
|
|
26
31
|
|
|
@@ -32,7 +37,8 @@ export function contentExpressionSymbols(content: string): string[] | null {
|
|
|
32
37
|
compiler.compile(expression);
|
|
33
38
|
const symbols = new Set<string>();
|
|
34
39
|
collectExpressionSymbols(expression, symbols);
|
|
35
|
-
|
|
40
|
+
|
|
41
|
+
return [ ...symbols ];
|
|
36
42
|
} catch {
|
|
37
43
|
return null;
|
|
38
44
|
}
|
|
@@ -40,40 +46,66 @@ export function contentExpressionSymbols(content: string): string[] | null {
|
|
|
40
46
|
|
|
41
47
|
class ContentExpressionParser {
|
|
42
48
|
private position = 0;
|
|
49
|
+
|
|
43
50
|
private depth = 0;
|
|
44
51
|
|
|
45
|
-
constructor(private readonly source: string) {
|
|
52
|
+
constructor(private readonly source: string) {
|
|
53
|
+
}
|
|
46
54
|
|
|
47
55
|
parse(): Expression {
|
|
48
|
-
if (this.source.trim() === '')
|
|
56
|
+
if (this.source.trim() === '') {
|
|
57
|
+
return { kind: 'empty' };
|
|
58
|
+
}
|
|
59
|
+
|
|
49
60
|
const expression = this.parseAlternation();
|
|
50
61
|
this.skipWhitespace();
|
|
51
|
-
|
|
62
|
+
|
|
63
|
+
if (!this.atEnd()) {
|
|
64
|
+
throw new Error(`unexpected '${this.peek()}'`);
|
|
65
|
+
}
|
|
66
|
+
|
|
52
67
|
return expression;
|
|
53
68
|
}
|
|
54
69
|
|
|
55
70
|
private parseAlternation(): Expression {
|
|
56
|
-
const expressions = [this.parseSequence()];
|
|
71
|
+
const expressions = [ this.parseSequence() ];
|
|
72
|
+
|
|
57
73
|
while (true) {
|
|
58
74
|
this.skipWhitespace();
|
|
59
|
-
|
|
75
|
+
|
|
76
|
+
if (!this.consume('|')) {
|
|
77
|
+
break;
|
|
78
|
+
}
|
|
79
|
+
|
|
60
80
|
this.skipWhitespace();
|
|
81
|
+
|
|
61
82
|
if (this.atEnd() || this.peek() === ')' || this.peek() === '|') {
|
|
62
|
-
throw new Error(
|
|
83
|
+
throw new Error('missing expression after \'|\'');
|
|
63
84
|
}
|
|
85
|
+
|
|
64
86
|
expressions.push(this.parseSequence());
|
|
65
87
|
}
|
|
88
|
+
|
|
66
89
|
return expressions.length === 1 ? expressions[0] : { kind: 'alternation', expressions };
|
|
67
90
|
}
|
|
68
91
|
|
|
69
92
|
private parseSequence(): Expression {
|
|
70
93
|
const expressions: Expression[] = [];
|
|
94
|
+
|
|
71
95
|
while (true) {
|
|
72
96
|
this.skipWhitespace();
|
|
73
|
-
|
|
97
|
+
|
|
98
|
+
if (this.atEnd() || this.peek() === ')' || this.peek() === '|') {
|
|
99
|
+
break;
|
|
100
|
+
}
|
|
101
|
+
|
|
74
102
|
expressions.push(this.parseRepeated());
|
|
75
103
|
}
|
|
76
|
-
|
|
104
|
+
|
|
105
|
+
if (expressions.length === 0) {
|
|
106
|
+
throw new Error('expected expression');
|
|
107
|
+
}
|
|
108
|
+
|
|
77
109
|
return expressions.length === 1 ? expressions[0] : { kind: 'sequence', expressions };
|
|
78
110
|
}
|
|
79
111
|
|
|
@@ -81,31 +113,50 @@ class ContentExpressionParser {
|
|
|
81
113
|
const atom = this.parseAtom();
|
|
82
114
|
this.skipWhitespace();
|
|
83
115
|
let expression = atom;
|
|
84
|
-
|
|
85
|
-
|
|
116
|
+
|
|
117
|
+
if (this.consume('?')) {
|
|
118
|
+
expression = { kind: 'repeat', expression: atom, min: 0, max: 1 };
|
|
119
|
+
} else if (this.consume('*')) {
|
|
86
120
|
expression = { kind: 'repeat', expression: atom, min: 0, max: null };
|
|
87
|
-
else if (this.consume('+'))
|
|
121
|
+
} else if (this.consume('+')) {
|
|
88
122
|
expression = { kind: 'repeat', expression: atom, min: 1, max: null };
|
|
89
|
-
else if (this.consume('{'))
|
|
123
|
+
} else if (this.consume('{')) {
|
|
124
|
+
expression = this.parseRange(atom);
|
|
125
|
+
}
|
|
126
|
+
|
|
90
127
|
this.skipWhitespace();
|
|
91
|
-
|
|
128
|
+
|
|
129
|
+
if ([ '?', '*', '+', '{' ].includes(this.peek() ?? '')) {
|
|
92
130
|
throw new Error('multiple quantifiers');
|
|
93
131
|
}
|
|
132
|
+
|
|
94
133
|
return expression;
|
|
95
134
|
}
|
|
96
135
|
|
|
97
136
|
private parseAtom(): Expression {
|
|
98
137
|
this.skipWhitespace();
|
|
138
|
+
|
|
99
139
|
if (this.consume('(')) {
|
|
100
|
-
if (this.depth >= CONTENT_EXPRESSION_MAX_DEPTH)
|
|
140
|
+
if (this.depth >= CONTENT_EXPRESSION_MAX_DEPTH) {
|
|
101
141
|
throw new Error('expression nesting too deep');
|
|
142
|
+
}
|
|
143
|
+
|
|
102
144
|
this.depth += 1;
|
|
145
|
+
|
|
103
146
|
try {
|
|
104
147
|
this.skipWhitespace();
|
|
105
|
-
|
|
148
|
+
|
|
149
|
+
if (this.peek() === ')') {
|
|
150
|
+
throw new Error('empty group');
|
|
151
|
+
}
|
|
152
|
+
|
|
106
153
|
const expression = this.parseAlternation();
|
|
107
154
|
this.skipWhitespace();
|
|
108
|
-
|
|
155
|
+
|
|
156
|
+
if (!this.consume(')')) {
|
|
157
|
+
throw new Error('missing \')\'');
|
|
158
|
+
}
|
|
159
|
+
|
|
109
160
|
return expression;
|
|
110
161
|
} finally {
|
|
111
162
|
this.depth -= 1;
|
|
@@ -113,39 +164,75 @@ class ContentExpressionParser {
|
|
|
113
164
|
}
|
|
114
165
|
|
|
115
166
|
const start = this.position;
|
|
116
|
-
|
|
117
|
-
|
|
167
|
+
|
|
168
|
+
while (this.peek() != null && /[A-Za-z0-9_-]/.test(this.peek()!)) {
|
|
169
|
+
this.position += 1;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
if (start === this.position) {
|
|
173
|
+
throw new Error('expected node or group name');
|
|
174
|
+
}
|
|
175
|
+
|
|
118
176
|
return { kind: 'symbol', symbol: this.source.slice(start, this.position) };
|
|
119
177
|
}
|
|
120
178
|
|
|
121
179
|
private parseRange(expression: Expression): Expression {
|
|
122
180
|
const min = this.parseNumber();
|
|
123
181
|
let max: number | null;
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
182
|
+
|
|
183
|
+
if (this.consume('}')) {
|
|
184
|
+
max = min;
|
|
185
|
+
} else {
|
|
186
|
+
if (!this.consume(',')) {
|
|
187
|
+
throw new Error('expected \',\' or \'}\'');
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
if (this.consume('}')) {
|
|
191
|
+
max = null;
|
|
192
|
+
} else {
|
|
129
193
|
max = this.parseNumber();
|
|
130
|
-
|
|
194
|
+
|
|
195
|
+
if (!this.consume('}')) {
|
|
196
|
+
throw new Error('expected \'}\'');
|
|
197
|
+
}
|
|
131
198
|
}
|
|
132
199
|
}
|
|
133
|
-
|
|
134
|
-
if (
|
|
200
|
+
|
|
201
|
+
if (max != null && max < min) {
|
|
202
|
+
throw new Error('range maximum is smaller than minimum');
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
if ((max ?? min) > MAX_REPETITION_BOUND) {
|
|
206
|
+
throw new Error('repetition bound too large');
|
|
207
|
+
}
|
|
208
|
+
|
|
135
209
|
return { kind: 'repeat', expression, min, max };
|
|
136
210
|
}
|
|
137
211
|
|
|
138
212
|
private parseNumber(): number {
|
|
139
213
|
const start = this.position;
|
|
140
|
-
|
|
141
|
-
|
|
214
|
+
|
|
215
|
+
while (this.peek() != null && /[0-9]/.test(this.peek()!)) {
|
|
216
|
+
this.position += 1;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
if (start === this.position) {
|
|
220
|
+
throw new Error('expected number');
|
|
221
|
+
}
|
|
222
|
+
|
|
142
223
|
const value = Number(this.source.slice(start, this.position));
|
|
143
|
-
|
|
224
|
+
|
|
225
|
+
if (!Number.isSafeInteger(value) || value > 0xffff_ffff) {
|
|
226
|
+
throw new Error('invalid count');
|
|
227
|
+
}
|
|
228
|
+
|
|
144
229
|
return value;
|
|
145
230
|
}
|
|
146
231
|
|
|
147
232
|
private skipWhitespace(): void {
|
|
148
|
-
while (this.peek() != null && /\s/.test(this.peek()!))
|
|
233
|
+
while (this.peek() != null && /\s/.test(this.peek()!)) {
|
|
234
|
+
this.position += 1;
|
|
235
|
+
}
|
|
149
236
|
}
|
|
150
237
|
|
|
151
238
|
private peek(): string | undefined {
|
|
@@ -153,8 +240,12 @@ class ContentExpressionParser {
|
|
|
153
240
|
}
|
|
154
241
|
|
|
155
242
|
private consume(character: string): boolean {
|
|
156
|
-
if (this.peek() !== character)
|
|
243
|
+
if (this.peek() !== character) {
|
|
244
|
+
return false;
|
|
245
|
+
}
|
|
246
|
+
|
|
157
247
|
this.position += 1;
|
|
248
|
+
|
|
158
249
|
return true;
|
|
159
250
|
}
|
|
160
251
|
|
|
@@ -167,39 +258,52 @@ class ContentExpressionCompiler {
|
|
|
167
258
|
readonly states: State[] = [];
|
|
168
259
|
|
|
169
260
|
compile(expression: Expression, depth = 0): [number, number] {
|
|
170
|
-
if (depth > CONTENT_EXPRESSION_MAX_DEPTH)
|
|
261
|
+
if (depth > CONTENT_EXPRESSION_MAX_DEPTH) {
|
|
262
|
+
throw new Error('expression nesting too deep');
|
|
263
|
+
}
|
|
264
|
+
|
|
171
265
|
if (expression.kind === 'empty') {
|
|
172
266
|
const start = this.state();
|
|
173
267
|
const end = this.state();
|
|
174
268
|
this.states[start].epsilon.push(end);
|
|
175
|
-
|
|
269
|
+
|
|
270
|
+
return [ start, end ];
|
|
176
271
|
}
|
|
272
|
+
|
|
177
273
|
if (expression.kind === 'symbol') {
|
|
178
274
|
const start = this.state();
|
|
179
275
|
const end = this.state();
|
|
180
276
|
this.states[start].transitions.push({ symbol: expression.symbol, target: end });
|
|
181
|
-
|
|
277
|
+
|
|
278
|
+
return [ start, end ];
|
|
182
279
|
}
|
|
280
|
+
|
|
183
281
|
if (expression.kind === 'sequence') {
|
|
184
282
|
const start = this.state();
|
|
185
283
|
let tail = start;
|
|
284
|
+
|
|
186
285
|
for (const nested of expression.expressions) {
|
|
187
|
-
const [nestedStart, nestedEnd] = this.compile(nested, depth + 1);
|
|
286
|
+
const [ nestedStart, nestedEnd ] = this.compile(nested, depth + 1);
|
|
188
287
|
this.states[tail].epsilon.push(nestedStart);
|
|
189
288
|
tail = nestedEnd;
|
|
190
289
|
}
|
|
191
|
-
|
|
290
|
+
|
|
291
|
+
return [ start, tail ];
|
|
192
292
|
}
|
|
293
|
+
|
|
193
294
|
if (expression.kind === 'alternation') {
|
|
194
295
|
const start = this.state();
|
|
195
296
|
const end = this.state();
|
|
297
|
+
|
|
196
298
|
for (const nested of expression.expressions) {
|
|
197
|
-
const [nestedStart, nestedEnd] = this.compile(nested, depth + 1);
|
|
299
|
+
const [ nestedStart, nestedEnd ] = this.compile(nested, depth + 1);
|
|
198
300
|
this.states[start].epsilon.push(nestedStart);
|
|
199
301
|
this.states[nestedEnd].epsilon.push(end);
|
|
200
302
|
}
|
|
201
|
-
|
|
303
|
+
|
|
304
|
+
return [ start, end ];
|
|
202
305
|
}
|
|
306
|
+
|
|
203
307
|
return this.compileRepeat(expression.expression, expression.min, expression.max, depth + 1);
|
|
204
308
|
}
|
|
205
309
|
|
|
@@ -212,45 +316,58 @@ class ContentExpressionCompiler {
|
|
|
212
316
|
const start = this.state();
|
|
213
317
|
const end = this.state();
|
|
214
318
|
let tail = start;
|
|
319
|
+
|
|
215
320
|
for (let count = 0; count < min; count += 1) {
|
|
216
|
-
const [itemStart, itemEnd] = this.compile(expression, depth);
|
|
321
|
+
const [ itemStart, itemEnd ] = this.compile(expression, depth);
|
|
217
322
|
this.states[tail].epsilon.push(itemStart);
|
|
218
323
|
tail = itemEnd;
|
|
219
324
|
}
|
|
325
|
+
|
|
220
326
|
if (max == null) {
|
|
221
327
|
this.states[tail].epsilon.push(end);
|
|
222
|
-
const [itemStart, itemEnd] = this.compile(expression, depth);
|
|
328
|
+
const [ itemStart, itemEnd ] = this.compile(expression, depth);
|
|
223
329
|
this.states[tail].epsilon.push(itemStart);
|
|
224
330
|
this.states[itemEnd].epsilon.push(tail);
|
|
225
331
|
} else {
|
|
226
332
|
for (let count = min; count < max; count += 1) {
|
|
227
333
|
this.states[tail].epsilon.push(end);
|
|
228
|
-
const [itemStart, itemEnd] = this.compile(expression, depth);
|
|
334
|
+
const [ itemStart, itemEnd ] = this.compile(expression, depth);
|
|
229
335
|
this.states[tail].epsilon.push(itemStart);
|
|
230
336
|
tail = itemEnd;
|
|
231
337
|
}
|
|
338
|
+
|
|
232
339
|
this.states[tail].epsilon.push(end);
|
|
233
340
|
}
|
|
234
|
-
|
|
341
|
+
|
|
342
|
+
return [ start, end ];
|
|
235
343
|
}
|
|
236
344
|
|
|
237
345
|
private state(): number {
|
|
238
|
-
if (this.states.length >= MAX_AUTOMATON_STATES)
|
|
346
|
+
if (this.states.length >= MAX_AUTOMATON_STATES) {
|
|
239
347
|
throw new Error('too many automaton states');
|
|
348
|
+
}
|
|
349
|
+
|
|
240
350
|
this.states.push({ epsilon: [], transitions: [] });
|
|
351
|
+
|
|
241
352
|
return this.states.length - 1;
|
|
242
353
|
}
|
|
243
354
|
}
|
|
244
355
|
|
|
245
356
|
function epsilonClosure(states: State[], initial: Iterable<number>): Set<number> {
|
|
246
357
|
const result = new Set<number>();
|
|
247
|
-
const pending = [...initial];
|
|
358
|
+
const pending = [ ...initial ];
|
|
359
|
+
|
|
248
360
|
while (pending.length > 0) {
|
|
249
361
|
const state = pending.pop()!;
|
|
250
|
-
|
|
362
|
+
|
|
363
|
+
if (result.has(state)) {
|
|
364
|
+
continue;
|
|
365
|
+
}
|
|
366
|
+
|
|
251
367
|
result.add(state);
|
|
252
368
|
pending.push(...states[state].epsilon);
|
|
253
369
|
}
|
|
370
|
+
|
|
254
371
|
return result;
|
|
255
372
|
}
|
|
256
373
|
|
|
@@ -263,24 +380,32 @@ export function acceptingContentSymbols(
|
|
|
263
380
|
try {
|
|
264
381
|
const expression = new ContentExpressionParser(content).parse();
|
|
265
382
|
const compiler = new ContentExpressionCompiler();
|
|
266
|
-
const [start] = compiler.compile(expression);
|
|
267
|
-
let current = epsilonClosure(compiler.states, [start]);
|
|
383
|
+
const [ start ] = compiler.compile(expression);
|
|
384
|
+
let current = epsilonClosure(compiler.states, [ start ]);
|
|
385
|
+
|
|
268
386
|
for (const childType of existingChildTypes) {
|
|
269
387
|
const next = new Set<number>();
|
|
388
|
+
|
|
270
389
|
for (const state of current) {
|
|
271
390
|
for (const transition of compiler.states[state].transitions) {
|
|
272
|
-
if (symbolMatches(childType, transition.symbol))
|
|
391
|
+
if (symbolMatches(childType, transition.symbol)) {
|
|
392
|
+
next.add(transition.target);
|
|
393
|
+
}
|
|
273
394
|
}
|
|
274
395
|
}
|
|
396
|
+
|
|
275
397
|
current = epsilonClosure(compiler.states, next);
|
|
276
398
|
}
|
|
399
|
+
|
|
277
400
|
const symbols = new Set<string>();
|
|
401
|
+
|
|
278
402
|
for (const state of current) {
|
|
279
403
|
for (const transition of compiler.states[state].transitions) {
|
|
280
404
|
symbols.add(transition.symbol);
|
|
281
405
|
}
|
|
282
406
|
}
|
|
283
|
-
|
|
407
|
+
|
|
408
|
+
return [ ...symbols ].sort();
|
|
284
409
|
} catch {
|
|
285
410
|
return [];
|
|
286
411
|
}
|
|
@@ -294,43 +419,73 @@ export function minimalContentMatch<T>(
|
|
|
294
419
|
try {
|
|
295
420
|
const expression = new ContentExpressionParser(content).parse();
|
|
296
421
|
const compiler = new ContentExpressionCompiler();
|
|
297
|
-
const [start, accept] = compiler.compile(expression);
|
|
422
|
+
const [ start, accept ] = compiler.compile(expression);
|
|
298
423
|
interface Path {
|
|
299
424
|
value: T;
|
|
300
425
|
previous?: Path;
|
|
301
426
|
}
|
|
302
|
-
let current = new Map<number, Path | undefined>([[start, undefined]]);
|
|
427
|
+
let current = new Map<number, Path | undefined>([ [ start, undefined ] ]);
|
|
303
428
|
const visited = new Set<number>();
|
|
429
|
+
|
|
304
430
|
while (current.size > 0) {
|
|
305
431
|
const closure = new Map<number, Path | undefined>();
|
|
306
|
-
const pending = [...current.entries()];
|
|
432
|
+
const pending = [ ...current.entries() ];
|
|
433
|
+
|
|
307
434
|
while (pending.length > 0) {
|
|
308
|
-
if (!consumeWork())
|
|
309
|
-
|
|
310
|
-
|
|
435
|
+
if (!consumeWork()) {
|
|
436
|
+
return undefined;
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
const [ state, path ] = pending.pop()!;
|
|
440
|
+
|
|
441
|
+
if (closure.has(state)) {
|
|
442
|
+
continue;
|
|
443
|
+
}
|
|
444
|
+
|
|
311
445
|
closure.set(state, path);
|
|
312
|
-
|
|
446
|
+
|
|
447
|
+
for (const target of compiler.states[state].epsilon) {
|
|
448
|
+
pending.push([ target, path ]);
|
|
449
|
+
}
|
|
313
450
|
}
|
|
451
|
+
|
|
314
452
|
const accepted = closure.get(accept);
|
|
453
|
+
|
|
315
454
|
if (closure.has(accept)) {
|
|
316
455
|
const result: T[] = [];
|
|
317
|
-
|
|
456
|
+
|
|
457
|
+
for (let path = accepted; path; path = path.previous) {
|
|
458
|
+
result.push(path.value);
|
|
459
|
+
}
|
|
460
|
+
|
|
318
461
|
return result.reverse();
|
|
319
462
|
}
|
|
463
|
+
|
|
320
464
|
const next = new Map<number, Path | undefined>();
|
|
321
|
-
|
|
322
|
-
|
|
465
|
+
|
|
466
|
+
for (const [ state, path ] of closure) {
|
|
467
|
+
if (visited.has(state)) {
|
|
468
|
+
continue;
|
|
469
|
+
}
|
|
470
|
+
|
|
323
471
|
visited.add(state);
|
|
472
|
+
|
|
324
473
|
for (const transition of compiler.states[state].transitions) {
|
|
325
|
-
if (!consumeWork())
|
|
474
|
+
if (!consumeWork()) {
|
|
475
|
+
return undefined;
|
|
476
|
+
}
|
|
477
|
+
|
|
326
478
|
const value = choose(transition.symbol);
|
|
479
|
+
|
|
327
480
|
if (value !== undefined && !next.has(transition.target)) {
|
|
328
481
|
next.set(transition.target, { value, previous: path });
|
|
329
482
|
}
|
|
330
483
|
}
|
|
331
484
|
}
|
|
485
|
+
|
|
332
486
|
current = next;
|
|
333
487
|
}
|
|
488
|
+
|
|
334
489
|
return undefined;
|
|
335
490
|
} catch {
|
|
336
491
|
return undefined;
|
package/src/listMarkers.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* CROSS-LAYER CONTRACT: these values must match the Rust core
|
|
5
5
|
* (rust/editor-core/src/render/mod.rs: task_list_marker_string /
|
|
6
|
-
* list_marker_string
|
|
6
|
+
* list_marker_string : pinned by marker_strings_are_the_cross_layer_contract
|
|
7
7
|
* in render_test.rs), Android (LayoutConstants.TASK_LIST_MARKER_* /
|
|
8
8
|
* UNORDERED_LIST_BULLET), and iOS (RenderBridge.listMarkerString). The
|
|
9
9
|
* marker's scalar length feeds position mapping; a mismatch corrupts
|