@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.
Files changed (180) hide show
  1. package/README.md +8 -116
  2. package/THIRD_PARTY_NOTICES.md +1 -1
  3. package/android/build.gradle +3 -0
  4. package/android/src/main/java/com/apollohg/editor/EditorEditTextImages.kt +25 -0
  5. package/android/src/main/java/com/apollohg/editor/EditorV2RenderValidation.kt +1 -0
  6. package/android/src/main/java/com/apollohg/editor/ImageResizeOverlayView.kt +101 -33
  7. package/android/src/main/java/com/apollohg/editor/RenderMediaSpans.kt +15 -3
  8. package/android/src/main/java/com/apollohg/editor/RichTextEditorView.kt +14 -0
  9. package/android/src/main/java/com/apollohg/editor/viewer/AndroidProseLayoutEngine.kt +1 -1
  10. package/app.plugin.js +42 -39
  11. package/dist/AtomHost.js +18 -11
  12. package/dist/EditorAddon.js +4 -2
  13. package/dist/EditorAddonNormalization.js +17 -9
  14. package/dist/EditorMentionThemeNormalization.js +6 -3
  15. package/dist/EditorMentionThemeValidation.js +28 -11
  16. package/dist/EditorStyleSheetNormalization.js +85 -38
  17. package/dist/EditorStyleSheetTypes.d.ts +1 -1
  18. package/dist/EditorTheme.d.ts +4 -0
  19. package/dist/EditorTheme.js +5 -3
  20. package/dist/EditorToolbarComponent.d.ts +1 -1
  21. package/dist/EditorToolbarComponent.js +1 -1
  22. package/dist/EditorToolbarRegistry.js +5 -5
  23. package/dist/EditorToolbarTypes.d.ts +12 -12
  24. package/dist/EditorToolbarVisuals.js +1 -1
  25. package/dist/ExternalTextComposition.js +89 -43
  26. package/dist/ImageLoadingPolicy.d.ts +1 -1
  27. package/dist/NativeEditorBoundaryError.d.ts +7 -7
  28. package/dist/NativeEditorBoundaryError.js +9 -5
  29. package/dist/NativeEditorCollaborationTransport.d.ts +7 -7
  30. package/dist/NativeEditorCollaborationTransport.js +28 -15
  31. package/dist/NativeEditorCreateConfig.js +11 -6
  32. package/dist/NativeEditorCreateJson.js +51 -25
  33. package/dist/NativeEditorCreateValidation.js +11 -6
  34. package/dist/NativeEditorDocumentBridge.d.ts +1 -1
  35. package/dist/NativeEditorDocumentBridge.js +32 -18
  36. package/dist/NativeEditorDocumentHandle.d.ts +4 -4
  37. package/dist/NativeEditorDocumentHandle.js +1 -1
  38. package/dist/NativeEditorLocalAwareness.js +25 -13
  39. package/dist/NativeEditorNativeModule.d.ts +8 -1
  40. package/dist/NativeEditorNativeModule.js +7 -5
  41. package/dist/NativeEditorRenderNormalization.js +66 -25
  42. package/dist/NativeEditorResultNormalization.js +53 -29
  43. package/dist/NativeEditorTypes.d.ts +10 -10
  44. package/dist/NativeEditorV2Decimal.js +6 -3
  45. package/dist/NativeProseViewer.js +11 -3
  46. package/dist/ResourceLimits.d.ts +2 -2
  47. package/dist/ResourceLimits.js +7 -2
  48. package/dist/RichTextEditor.js +1 -1
  49. package/dist/RichTextEditorNativeTypes.d.ts +1 -1
  50. package/dist/RichTextEditorNativeView.d.ts +1 -3
  51. package/dist/RichTextEditorSerialization.js +24 -14
  52. package/dist/RichTextEditorTypes.d.ts +1 -1
  53. package/dist/YjsCollaboration.d.ts +7 -7
  54. package/dist/YjsCollaboration.js +42 -26
  55. package/dist/addons.d.ts +4 -4
  56. package/dist/addons.js +3 -3
  57. package/dist/atomInstances.js +6 -3
  58. package/dist/atomUpdates.js +7 -4
  59. package/dist/atoms.js +20 -12
  60. package/dist/attributeValidation.js +55 -24
  61. package/dist/contentExpression.js +80 -42
  62. package/dist/listMarkers.d.ts +1 -1
  63. package/dist/listMarkers.js +1 -1
  64. package/dist/schemaDefinition.d.ts +1 -1
  65. package/dist/schemaDefinition.js +23 -14
  66. package/dist/schemaDocument.js +1 -1
  67. package/dist/schemaDocumentConstruction.js +25 -14
  68. package/dist/schemaNormalization.js +51 -29
  69. package/dist/schemaPresets.d.ts +1 -1
  70. package/dist/schemaPresets.js +9 -4
  71. package/dist/schemaResolution.js +46 -25
  72. package/dist/specs/PreparedProseViewerNativeComponent.d.ts +4 -0
  73. package/dist/useEditorToolbarInteractions.d.ts +2 -2
  74. package/dist/useEditorToolbarInteractions.js +45 -23
  75. package/dist/useEditorToolbarItems.d.ts +1 -1
  76. package/dist/useEditorToolbarItems.js +4 -3
  77. package/dist/useEditorToolbarPresentation.d.ts +3 -3
  78. package/dist/useEditorToolbarPresentation.js +4 -4
  79. package/dist/useEditorToolbarState.d.ts +1 -1
  80. package/dist/useEditorToolbarState.js +1 -1
  81. package/dist/useFocusPreservingFrames.js +11 -8
  82. package/dist/useNativeEditor.d.ts +1 -1
  83. package/dist/useNativeEditor.js +21 -11
  84. package/dist/useRichTextEditorCommands.d.ts +2 -2
  85. package/dist/useRichTextEditorCommands.js +59 -29
  86. package/dist/useRichTextEditorEvents.d.ts +3 -3
  87. package/dist/useRichTextEditorEvents.js +75 -32
  88. package/dist/useRichTextEditorMentions.d.ts +4 -4
  89. package/dist/useRichTextEditorMentions.js +48 -29
  90. package/dist/useRichTextEditorPresentation.d.ts +4 -4
  91. package/dist/useRichTextEditorPresentation.js +25 -23
  92. package/dist/useRichTextEditorState.d.ts +3 -3
  93. package/dist/useRichTextEditorState.js +20 -15
  94. package/dist/useRichTextEditorUpdates.d.ts +1 -1
  95. package/dist/useRichTextEditorUpdates.js +99 -41
  96. package/dist/useViewerAtoms.js +63 -36
  97. package/ios/EditorCore.xcframework/ios-arm64/libeditor_core.a +0 -0
  98. package/ios/EditorCore.xcframework/ios-arm64_x86_64-simulator/libeditor_core.a +0 -0
  99. package/ios/EditorInteractionOverlays.swift +114 -122
  100. package/ios/EditorLayoutManager.swift +13 -3
  101. package/ios/EditorStyleSheet.swift +12 -1
  102. package/ios/EditorTextView+Images.swift +32 -10
  103. package/ios/EditorTextView.swift +1 -1
  104. package/ios/EditorV2Adapter+RenderValidation.swift +2 -2
  105. package/ios/NativeToolbar+ButtonStyle.swift +17 -5
  106. package/ios/NativeToolbar+Diagnostics.swift +15 -0
  107. package/ios/RenderBridge+Atoms.swift +0 -1
  108. package/ios/RenderBridge+Attachments.swift +0 -29
  109. package/ios/RichTextEditorView.swift +4 -12
  110. package/ios/Viewer/CoreTextProseLayoutEngine+AttributedText.swift +3 -2
  111. package/package.json +11 -3
  112. package/react-native.config.js +1 -1
  113. package/rust/android/arm64-v8a/libeditor_core.so +0 -0
  114. package/rust/android/armeabi-v7a/libeditor_core.so +0 -0
  115. package/rust/android/x86/libeditor_core.so +0 -0
  116. package/rust/android/x86_64/libeditor_core.so +0 -0
  117. package/src/AtomHost.tsx +58 -28
  118. package/src/EditorAddon.ts +18 -8
  119. package/src/EditorAddonNormalization.ts +40 -11
  120. package/src/EditorMentionThemeNormalization.ts +15 -4
  121. package/src/EditorMentionThemeValidation.ts +51 -14
  122. package/src/EditorStyleSheet.ts +1 -0
  123. package/src/EditorStyleSheetNormalization.ts +195 -64
  124. package/src/EditorStyleSheetTypes.ts +1 -1
  125. package/src/EditorTheme.ts +13 -5
  126. package/src/EditorToolbarComponent.tsx +2 -1
  127. package/src/EditorToolbarRegistry.tsx +23 -13
  128. package/src/EditorToolbarTypes.tsx +12 -12
  129. package/src/EditorToolbarVisuals.tsx +6 -3
  130. package/src/EditorUpdateRevision.ts +1 -0
  131. package/src/ExternalTextComposition.ts +259 -49
  132. package/src/ImageLoadingPolicy.ts +3 -1
  133. package/src/NativeEditorBoundaryError.ts +38 -11
  134. package/src/NativeEditorCollaborationTransport.ts +108 -27
  135. package/src/NativeEditorCreateConfig.ts +92 -19
  136. package/src/NativeEditorCreateJson.ts +163 -26
  137. package/src/NativeEditorCreateValidation.ts +33 -12
  138. package/src/NativeEditorDocumentBridge.ts +111 -19
  139. package/src/NativeEditorDocumentHandle.ts +9 -4
  140. package/src/NativeEditorLocalAwareness.ts +70 -15
  141. package/src/NativeEditorNativeModule.ts +13 -9
  142. package/src/NativeEditorRenderNormalization.ts +128 -29
  143. package/src/NativeEditorResultNormalization.ts +143 -32
  144. package/src/NativeEditorTypes.ts +12 -11
  145. package/src/NativeEditorV2Decimal.ts +12 -3
  146. package/src/NativeProseViewer.tsx +46 -16
  147. package/src/ResourceLimits.ts +15 -8
  148. package/src/RichTextEditor.tsx +3 -1
  149. package/src/RichTextEditorNativeTypes.tsx +1 -1
  150. package/src/RichTextEditorNativeView.tsx +2 -8
  151. package/src/RichTextEditorSerialization.tsx +70 -24
  152. package/src/RichTextEditorTypes.tsx +1 -1
  153. package/src/YjsCollaboration.ts +143 -47
  154. package/src/addons.ts +12 -8
  155. package/src/atomInstances.ts +25 -5
  156. package/src/atomUpdates.ts +23 -6
  157. package/src/atoms.ts +85 -18
  158. package/src/attributeValidation.ts +97 -33
  159. package/src/contentExpression.ts +218 -63
  160. package/src/listMarkers.ts +1 -1
  161. package/src/schemaDefinition.ts +82 -20
  162. package/src/schemaDocument.ts +15 -1
  163. package/src/schemaDocumentConstruction.ts +80 -16
  164. package/src/schemaNormalization.ts +155 -41
  165. package/src/schemaPresets.ts +37 -31
  166. package/src/schemaResolution.ts +126 -27
  167. package/src/specs/PreparedProseViewerNativeComponent.ts +4 -2
  168. package/src/useEditorToolbarInteractions.tsx +85 -36
  169. package/src/useEditorToolbarItems.tsx +50 -22
  170. package/src/useEditorToolbarPresentation.tsx +81 -58
  171. package/src/useEditorToolbarState.tsx +8 -6
  172. package/src/useFocusPreservingFrames.ts +43 -15
  173. package/src/useNativeEditor.ts +111 -51
  174. package/src/useRichTextEditorCommands.tsx +127 -54
  175. package/src/useRichTextEditorEvents.tsx +144 -42
  176. package/src/useRichTextEditorMentions.tsx +118 -37
  177. package/src/useRichTextEditorPresentation.tsx +128 -114
  178. package/src/useRichTextEditorState.tsx +76 -40
  179. package/src/useRichTextEditorUpdates.tsx +207 -56
  180. package/src/useViewerAtoms.tsx +162 -66
@@ -7,41 +7,51 @@ function jsonType(value) {
7
7
  return Array.isArray(value) ? 'array' : value === null ? 'null' : typeof value;
8
8
  }
9
9
  function validateJson(value, ancestors = new Set()) {
10
- if (value === null || typeof value === 'string' || typeof value === 'boolean')
10
+ if (value === null || typeof value === 'string' || typeof value === 'boolean') {
11
11
  return;
12
- if (typeof value === 'number' && Number.isFinite(value))
12
+ }
13
+ if (typeof value === 'number' && Number.isFinite(value)) {
13
14
  return;
14
- if (typeof value !== 'object' || ancestors.has(value) || ancestors.size > 128)
15
+ }
16
+ if (typeof value !== 'object' || ancestors.has(value) || ancestors.size > 128) {
15
17
  throw new Error('Attribute values must be finite, acyclic JSON.');
18
+ }
16
19
  if (!Array.isArray(value) &&
17
20
  Object.getPrototypeOf(value) !== Object.prototype &&
18
- Object.getPrototypeOf(value) !== null)
21
+ Object.getPrototypeOf(value) !== null) {
19
22
  throw new Error('Attribute values must be plain JSON objects.');
23
+ }
20
24
  ancestors.add(value);
21
25
  const entries = Array.isArray(value) ? value : Object.values(value);
22
- for (let index = 0; index < entries.length; index += 1)
26
+ for (let index = 0; index < entries.length; index += 1) {
23
27
  validateJson(entries[index], ancestors);
28
+ }
24
29
  ancestors.delete(value);
25
30
  }
26
31
  function equal(left, right) {
27
- if (left === right)
32
+ if (left === right) {
28
33
  return true;
29
- if (left == null || right == null || typeof left !== 'object' || typeof right !== 'object')
34
+ }
35
+ if (left == null || right == null || typeof left !== 'object' || typeof right !== 'object') {
30
36
  return false;
31
- if (Array.isArray(left) !== Array.isArray(right))
37
+ }
38
+ if (Array.isArray(left) !== Array.isArray(right)) {
32
39
  return false;
40
+ }
33
41
  const a = Object.keys(left), b = Object.keys(right);
34
42
  return (a.length === b.length &&
35
- a.every((key) => Object.prototype.hasOwnProperty.call(right, key) &&
43
+ a.every(key => Object.prototype.hasOwnProperty.call(right, key) &&
36
44
  equal(left[key], right[key])));
37
45
  }
38
46
  function validateAttribute(value, spec, name) {
39
47
  validateJson(value);
40
48
  const type = jsonType(value);
41
- if ((spec.type != null && type !== spec.type) || (type === 'number' && !Number.isFinite(value)))
49
+ if ((spec.type != null && type !== spec.type) || (type === 'number' && !Number.isFinite(value))) {
42
50
  throw new Error(`invalid attribute '${name}': expected ${spec.type ?? 'finite number'}`);
43
- if (spec.enum != null && !spec.enum.some((entry) => equal(entry, value)))
51
+ }
52
+ if (spec.enum != null && !spec.enum.some(entry => equal(entry, value))) {
44
53
  throw new Error(`invalid attribute '${name}': outside enum`);
54
+ }
45
55
  const size = typeof value === 'number'
46
56
  ? value
47
57
  : typeof value === 'string'
@@ -50,48 +60,69 @@ function validateAttribute(value, spec, name) {
50
60
  ? value.length
51
61
  : undefined;
52
62
  if ((spec.min != null && (size == null || size < spec.min)) ||
53
- (spec.max != null && (size == null || size > spec.max)))
63
+ (spec.max != null && (size == null || size > spec.max))) {
54
64
  throw new Error(`invalid attribute '${name}': outside bounds`);
65
+ }
55
66
  }
56
67
  function validateAttributeSpec(spec, name) {
57
- if (spec == null || typeof spec !== 'object' || Array.isArray(spec))
68
+ if (spec == null || typeof spec !== 'object' || Array.isArray(spec)) {
58
69
  throw new Error(`invalid attribute '${name}' declaration`);
59
- if (Object.keys(spec).some((key) => !['default', 'type', 'enum', 'min', 'max'].includes(key)))
70
+ }
71
+ if (Object.keys(spec).some(key => !['default',
72
+ 'type',
73
+ 'enum',
74
+ 'min',
75
+ 'max'].includes(key))) {
60
76
  throw new Error(`invalid attribute '${name}' declaration field`);
77
+ }
61
78
  if (spec.type !== undefined &&
62
- !['string', 'number', 'boolean', 'object', 'array'].includes(spec.type))
79
+ !['string',
80
+ 'number',
81
+ 'boolean',
82
+ 'object',
83
+ 'array'].includes(spec.type)) {
63
84
  throw new Error(`invalid attribute '${name}' type`);
85
+ }
64
86
  if (spec.min !== undefined || spec.max !== undefined) {
65
87
  if (!['number', 'string', 'array'].includes(spec.type ?? '') ||
66
88
  (spec.min !== undefined && !Number.isFinite(spec.min)) ||
67
89
  (spec.max !== undefined && !Number.isFinite(spec.max)) ||
68
- (spec.min !== undefined && spec.max !== undefined && spec.min > spec.max))
90
+ (spec.min !== undefined && spec.max !== undefined && spec.min > spec.max)) {
69
91
  throw new Error(`invalid attribute '${name}' bounds`);
92
+ }
70
93
  if (spec.type !== 'number' &&
71
- [spec.min, spec.max].some((bound) => bound !== undefined && (!Number.isInteger(bound) || bound < 0)))
94
+ [spec.min, spec.max].some(bound => bound !== undefined && (!Number.isInteger(bound) || bound < 0))) {
72
95
  throw new Error(`invalid attribute '${name}' length bounds`);
96
+ }
73
97
  }
74
98
  if (spec.enum !== undefined) {
75
- if (!Array.isArray(spec.enum) || spec.enum.length === 0)
99
+ if (!Array.isArray(spec.enum) || spec.enum.length === 0) {
76
100
  throw new Error(`invalid attribute '${name}' enum`);
77
- if (new Set(spec.enum.map(jsonType)).size !== 1)
101
+ }
102
+ if (new Set(spec.enum.map(jsonType)).size !== 1) {
78
103
  throw new Error(`invalid attribute '${name}': enum values must share one JSON type`);
79
- for (const entry of spec.enum)
104
+ }
105
+ for (const entry of spec.enum) {
80
106
  validateAttribute(entry, { ...spec, enum: undefined }, name);
107
+ }
81
108
  }
82
- if (spec.default !== undefined)
109
+ if (spec.default !== undefined) {
83
110
  validateAttribute(spec.default, spec, name);
111
+ }
84
112
  }
85
113
  function validateAttributes(attrs, specs) {
86
- for (const name of Object.keys(attrs))
87
- if (!Object.prototype.hasOwnProperty.call(specs, name))
114
+ for (const name of Object.keys(attrs)) {
115
+ if (!Object.prototype.hasOwnProperty.call(specs, name)) {
88
116
  throw new Error(`undeclared attribute '${name}'`);
117
+ }
118
+ }
89
119
  for (const [name, spec] of Object.entries(specs)) {
90
120
  const value = Object.prototype.hasOwnProperty.call(attrs, name)
91
121
  ? attrs[name]
92
122
  : spec.default;
93
- if (value === undefined)
123
+ if (value === undefined) {
94
124
  throw new Error(`required attribute '${name}' missing`);
125
+ }
95
126
  validateAttribute(value, spec, name);
96
127
  }
97
128
  }
@@ -13,11 +13,14 @@ function collectExpressionSymbols(expression, symbols) {
13
13
  symbols.add(expression.symbol);
14
14
  }
15
15
  else if (expression.kind !== 'empty') {
16
- if (expression.kind === 'repeat')
16
+ if (expression.kind === 'repeat') {
17
17
  collectExpressionSymbols(expression.expression, symbols);
18
- else
19
- for (const nested of expression.expressions)
18
+ }
19
+ else {
20
+ for (const nested of expression.expressions) {
20
21
  collectExpressionSymbols(nested, symbols);
22
+ }
23
+ }
21
24
  }
22
25
  }
23
26
  /** Return every referenced node/group symbol, or null for an invalid expression. */
@@ -41,23 +44,26 @@ class ContentExpressionParser {
41
44
  this.depth = 0;
42
45
  }
43
46
  parse() {
44
- if (this.source.trim() === '')
47
+ if (this.source.trim() === '') {
45
48
  return { kind: 'empty' };
49
+ }
46
50
  const expression = this.parseAlternation();
47
51
  this.skipWhitespace();
48
- if (!this.atEnd())
52
+ if (!this.atEnd()) {
49
53
  throw new Error(`unexpected '${this.peek()}'`);
54
+ }
50
55
  return expression;
51
56
  }
52
57
  parseAlternation() {
53
58
  const expressions = [this.parseSequence()];
54
59
  while (true) {
55
60
  this.skipWhitespace();
56
- if (!this.consume('|'))
61
+ if (!this.consume('|')) {
57
62
  break;
63
+ }
58
64
  this.skipWhitespace();
59
65
  if (this.atEnd() || this.peek() === ')' || this.peek() === '|') {
60
- throw new Error("missing expression after '|'");
66
+ throw new Error('missing expression after \'|\'');
61
67
  }
62
68
  expressions.push(this.parseSequence());
63
69
  }
@@ -67,26 +73,32 @@ class ContentExpressionParser {
67
73
  const expressions = [];
68
74
  while (true) {
69
75
  this.skipWhitespace();
70
- if (this.atEnd() || this.peek() === ')' || this.peek() === '|')
76
+ if (this.atEnd() || this.peek() === ')' || this.peek() === '|') {
71
77
  break;
78
+ }
72
79
  expressions.push(this.parseRepeated());
73
80
  }
74
- if (expressions.length === 0)
81
+ if (expressions.length === 0) {
75
82
  throw new Error('expected expression');
83
+ }
76
84
  return expressions.length === 1 ? expressions[0] : { kind: 'sequence', expressions };
77
85
  }
78
86
  parseRepeated() {
79
87
  const atom = this.parseAtom();
80
88
  this.skipWhitespace();
81
89
  let expression = atom;
82
- if (this.consume('?'))
90
+ if (this.consume('?')) {
83
91
  expression = { kind: 'repeat', expression: atom, min: 0, max: 1 };
84
- else if (this.consume('*'))
92
+ }
93
+ else if (this.consume('*')) {
85
94
  expression = { kind: 'repeat', expression: atom, min: 0, max: null };
86
- else if (this.consume('+'))
95
+ }
96
+ else if (this.consume('+')) {
87
97
  expression = { kind: 'repeat', expression: atom, min: 1, max: null };
88
- else if (this.consume('{'))
98
+ }
99
+ else if (this.consume('{')) {
89
100
  expression = this.parseRange(atom);
101
+ }
90
102
  this.skipWhitespace();
91
103
  if (['?', '*', '+', '{'].includes(this.peek() ?? '')) {
92
104
  throw new Error('multiple quantifiers');
@@ -96,17 +108,20 @@ class ContentExpressionParser {
96
108
  parseAtom() {
97
109
  this.skipWhitespace();
98
110
  if (this.consume('(')) {
99
- if (this.depth >= exports.CONTENT_EXPRESSION_MAX_DEPTH)
111
+ if (this.depth >= exports.CONTENT_EXPRESSION_MAX_DEPTH) {
100
112
  throw new Error('expression nesting too deep');
113
+ }
101
114
  this.depth += 1;
102
115
  try {
103
116
  this.skipWhitespace();
104
- if (this.peek() === ')')
117
+ if (this.peek() === ')') {
105
118
  throw new Error('empty group');
119
+ }
106
120
  const expression = this.parseAlternation();
107
121
  this.skipWhitespace();
108
- if (!this.consume(')'))
109
- throw new Error("missing ')'");
122
+ if (!this.consume(')')) {
123
+ throw new Error('missing \')\'');
124
+ }
110
125
  return expression;
111
126
  }
112
127
  finally {
@@ -114,55 +129,68 @@ class ContentExpressionParser {
114
129
  }
115
130
  }
116
131
  const start = this.position;
117
- while (this.peek() != null && /[A-Za-z0-9_-]/.test(this.peek()))
132
+ while (this.peek() != null && /[A-Za-z0-9_-]/.test(this.peek())) {
118
133
  this.position += 1;
119
- if (start === this.position)
134
+ }
135
+ if (start === this.position) {
120
136
  throw new Error('expected node or group name');
137
+ }
121
138
  return { kind: 'symbol', symbol: this.source.slice(start, this.position) };
122
139
  }
123
140
  parseRange(expression) {
124
141
  const min = this.parseNumber();
125
142
  let max;
126
- if (this.consume('}'))
143
+ if (this.consume('}')) {
127
144
  max = min;
145
+ }
128
146
  else {
129
- if (!this.consume(','))
130
- throw new Error("expected ',' or '}'");
131
- if (this.consume('}'))
147
+ if (!this.consume(',')) {
148
+ throw new Error('expected \',\' or \'}\'');
149
+ }
150
+ if (this.consume('}')) {
132
151
  max = null;
152
+ }
133
153
  else {
134
154
  max = this.parseNumber();
135
- if (!this.consume('}'))
136
- throw new Error("expected '}'");
155
+ if (!this.consume('}')) {
156
+ throw new Error('expected \'}\'');
157
+ }
137
158
  }
138
159
  }
139
- if (max != null && max < min)
160
+ if (max != null && max < min) {
140
161
  throw new Error('range maximum is smaller than minimum');
141
- if ((max ?? min) > MAX_REPETITION_BOUND)
162
+ }
163
+ if ((max ?? min) > MAX_REPETITION_BOUND) {
142
164
  throw new Error('repetition bound too large');
165
+ }
143
166
  return { kind: 'repeat', expression, min, max };
144
167
  }
145
168
  parseNumber() {
146
169
  const start = this.position;
147
- while (this.peek() != null && /[0-9]/.test(this.peek()))
170
+ while (this.peek() != null && /[0-9]/.test(this.peek())) {
148
171
  this.position += 1;
149
- if (start === this.position)
172
+ }
173
+ if (start === this.position) {
150
174
  throw new Error('expected number');
175
+ }
151
176
  const value = Number(this.source.slice(start, this.position));
152
- if (!Number.isSafeInteger(value) || value > 4294967295)
177
+ if (!Number.isSafeInteger(value) || value > 4294967295) {
153
178
  throw new Error('invalid count');
179
+ }
154
180
  return value;
155
181
  }
156
182
  skipWhitespace() {
157
- while (this.peek() != null && /\s/.test(this.peek()))
183
+ while (this.peek() != null && /\s/.test(this.peek())) {
158
184
  this.position += 1;
185
+ }
159
186
  }
160
187
  peek() {
161
188
  return this.source[this.position];
162
189
  }
163
190
  consume(character) {
164
- if (this.peek() !== character)
191
+ if (this.peek() !== character) {
165
192
  return false;
193
+ }
166
194
  this.position += 1;
167
195
  return true;
168
196
  }
@@ -175,8 +203,9 @@ class ContentExpressionCompiler {
175
203
  this.states = [];
176
204
  }
177
205
  compile(expression, depth = 0) {
178
- if (depth > exports.CONTENT_EXPRESSION_MAX_DEPTH)
206
+ if (depth > exports.CONTENT_EXPRESSION_MAX_DEPTH) {
179
207
  throw new Error('expression nesting too deep');
208
+ }
180
209
  if (expression.kind === 'empty') {
181
210
  const start = this.state();
182
211
  const end = this.state();
@@ -238,8 +267,9 @@ class ContentExpressionCompiler {
238
267
  return [start, end];
239
268
  }
240
269
  state() {
241
- if (this.states.length >= MAX_AUTOMATON_STATES)
270
+ if (this.states.length >= MAX_AUTOMATON_STATES) {
242
271
  throw new Error('too many automaton states');
272
+ }
243
273
  this.states.push({ epsilon: [], transitions: [] });
244
274
  return this.states.length - 1;
245
275
  }
@@ -249,8 +279,9 @@ function epsilonClosure(states, initial) {
249
279
  const pending = [...initial];
250
280
  while (pending.length > 0) {
251
281
  const state = pending.pop();
252
- if (result.has(state))
282
+ if (result.has(state)) {
253
283
  continue;
284
+ }
254
285
  result.add(state);
255
286
  pending.push(...states[state].epsilon);
256
287
  }
@@ -266,8 +297,9 @@ function acceptingContentSymbols(content, existingChildTypes = [], symbolMatches
266
297
  const next = new Set();
267
298
  for (const state of current) {
268
299
  for (const transition of compiler.states[state].transitions) {
269
- if (symbolMatches(childType, transition.symbol))
300
+ if (symbolMatches(childType, transition.symbol)) {
270
301
  next.add(transition.target);
302
+ }
271
303
  }
272
304
  }
273
305
  current = epsilonClosure(compiler.states, next);
@@ -295,30 +327,36 @@ function minimalContentMatch(content, choose, consumeWork = () => true) {
295
327
  const closure = new Map();
296
328
  const pending = [...current.entries()];
297
329
  while (pending.length > 0) {
298
- if (!consumeWork())
330
+ if (!consumeWork()) {
299
331
  return undefined;
332
+ }
300
333
  const [state, path] = pending.pop();
301
- if (closure.has(state))
334
+ if (closure.has(state)) {
302
335
  continue;
336
+ }
303
337
  closure.set(state, path);
304
- for (const target of compiler.states[state].epsilon)
338
+ for (const target of compiler.states[state].epsilon) {
305
339
  pending.push([target, path]);
340
+ }
306
341
  }
307
342
  const accepted = closure.get(accept);
308
343
  if (closure.has(accept)) {
309
344
  const result = [];
310
- for (let path = accepted; path; path = path.previous)
345
+ for (let path = accepted; path; path = path.previous) {
311
346
  result.push(path.value);
347
+ }
312
348
  return result.reverse();
313
349
  }
314
350
  const next = new Map();
315
351
  for (const [state, path] of closure) {
316
- if (visited.has(state))
352
+ if (visited.has(state)) {
317
353
  continue;
354
+ }
318
355
  visited.add(state);
319
356
  for (const transition of compiler.states[state].transitions) {
320
- if (!consumeWork())
357
+ if (!consumeWork()) {
321
358
  return undefined;
359
+ }
322
360
  const value = choose(transition.symbol);
323
361
  if (value !== undefined && !next.has(transition.target)) {
324
362
  next.set(transition.target, { value, previous: path });
@@ -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 pinned by marker_strings_are_the_cross_layer_contract
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
@@ -7,7 +7,7 @@ exports.orderedListMarker = orderedListMarker;
7
7
  *
8
8
  * CROSS-LAYER CONTRACT: these values must match the Rust core
9
9
  * (rust/editor-core/src/render/mod.rs: task_list_marker_string /
10
- * list_marker_string pinned by marker_strings_are_the_cross_layer_contract
10
+ * list_marker_string : pinned by marker_strings_are_the_cross_layer_contract
11
11
  * in render_test.rs), Android (LayoutConstants.TASK_LIST_MARKER_* /
12
12
  * UNORDERED_LIST_BULLET), and iOS (RenderBridge.listMarkerString). The
13
13
  * marker's scalar length feeds position mapping; a mismatch corrupts
@@ -63,7 +63,7 @@ export interface NodeSpec {
63
63
  * `insert_content_json`) admits attrs on this node that are not declared
64
64
  * in `attrs`, instead of filtering them out. Default `false`. Intended
65
65
  * for node types with an intentional pass-through-metadata contract
66
- * (e.g. the mention node see `mentionNodeSpec()` in addons.ts).
66
+ * (e.g. the mention node : see `mentionNodeSpec()` in addons.ts).
67
67
  */
68
68
  allowUndeclaredAttrs?: boolean;
69
69
  /** Public JSON representation when it differs from the native node name. */
@@ -27,35 +27,42 @@ function outputTag(spec) {
27
27
  }
28
28
  function appendGroup(group, name) {
29
29
  const groups = group?.split(/\s+/).filter(Boolean) ?? [];
30
- if (!groups.includes(name))
30
+ if (!groups.includes(name)) {
31
31
  groups.push(name);
32
+ }
32
33
  return groups.join(' ');
33
34
  }
34
35
  function schemaNodeRole(name, node) {
35
- if (node.role != null)
36
+ if (node.role != null) {
36
37
  return node.role === 'heading' ? 'textBlock' : node.role;
37
- if (name === 'doc')
38
+ }
39
+ if (name === 'doc') {
38
40
  return 'doc';
39
- if (name === 'text')
41
+ }
42
+ if (name === 'text') {
40
43
  return 'text';
44
+ }
41
45
  if (node.content === 'inline*' && node.group?.split(/\s+/).includes('block')) {
42
46
  return 'textBlock';
43
47
  }
44
- if (node.group?.split(/\s+/).includes('inline'))
48
+ if (node.group?.split(/\s+/).includes('inline')) {
45
49
  return 'inline';
50
+ }
46
51
  return 'block';
47
52
  }
48
53
  function caseAttributeValue(key, attribute, tag, parseDOM, defaultValue) {
49
- const rule = parseDOM?.find((candidate) => candidate.tag === tag &&
54
+ const rule = parseDOM?.find(candidate => candidate.tag === tag &&
50
55
  candidate.attrs != null &&
51
56
  String(candidate.attrs[attribute]) === key);
52
57
  if (rule?.attrs && Object.prototype.hasOwnProperty.call(rule.attrs, attribute)) {
53
58
  return rule.attrs[attribute];
54
59
  }
55
- if (typeof defaultValue === 'number')
60
+ if (typeof defaultValue === 'number') {
56
61
  return Number(key);
57
- if (typeof defaultValue === 'boolean')
62
+ }
63
+ if (typeof defaultValue === 'boolean') {
58
64
  return key === 'true';
65
+ }
59
66
  return key;
60
67
  }
61
68
  function validateAttributeDOMRules(name, switched, parseDOM, defaultValue) {
@@ -66,7 +73,7 @@ function validateAttributeDOMRules(name, switched, parseDOM, defaultValue) {
66
73
  ? typeof defaultValue
67
74
  : undefined;
68
75
  if (discriminatorType == null && parseDOM != null) {
69
- const parsedTypes = parseDOM.map((rule) => {
76
+ const parsedTypes = parseDOM.map(rule => {
70
77
  const value = rule.attrs?.[switched.switchOn];
71
78
  return typeof value === 'string' ||
72
79
  typeof value === 'number' ||
@@ -75,7 +82,7 @@ function validateAttributeDOMRules(name, switched, parseDOM, defaultValue) {
75
82
  : undefined;
76
83
  });
77
84
  const firstType = parsedTypes[0];
78
- if (firstType != null && parsedTypes.every((type) => type === firstType)) {
85
+ if (firstType != null && parsedTypes.every(type => type === firstType)) {
79
86
  discriminatorType = firstType;
80
87
  }
81
88
  }
@@ -94,7 +101,7 @@ function validateAttributeDOMRules(name, switched, parseDOM, defaultValue) {
94
101
  }
95
102
  return;
96
103
  }
97
- const matchesCase = ([caseKey, output]) => parseDOM.filter((rule) => rule.tag === outputTag(output) &&
104
+ const matchesCase = ([caseKey, output]) => parseDOM.filter(rule => rule.tag === outputTag(output) &&
98
105
  rule.attrs != null &&
99
106
  Object.prototype.hasOwnProperty.call(rule.attrs, switched.switchOn) &&
100
107
  String(rule.attrs[switched.switchOn]) === caseKey).length === 1;
@@ -102,7 +109,7 @@ function validateAttributeDOMRules(name, switched, parseDOM, defaultValue) {
102
109
  throw new Error(`node '${name}' DOM parse rules must map one-to-one with '${switched.switchOn}' output cases`);
103
110
  }
104
111
  if (discriminatorType != null &&
105
- parseDOM.some((rule) => rule.attrs != null && typeof rule.attrs[switched.switchOn] !== discriminatorType)) {
112
+ parseDOM.some(rule => rule.attrs != null && typeof rule.attrs[switched.switchOn] !== discriminatorType)) {
106
113
  throw new Error(`node '${name}' DOM discriminator '${switched.switchOn}' must use ${discriminatorType} values`);
107
114
  }
108
115
  }
@@ -153,8 +160,9 @@ function defineSchema(spec) {
153
160
  const { attrs: _attrs, ...variantCommon } = common;
154
161
  for (const [caseKey, output] of Object.entries(switched.cases)) {
155
162
  const tag = outputTag(output);
156
- if (names.has(tag))
163
+ if (names.has(tag)) {
157
164
  throw new Error(`schema produces duplicate native node '${tag}'`);
165
+ }
158
166
  names.add(tag);
159
167
  const { [switched.switchOn]: _discriminator, ...variantAttrs } = node.attrs ?? {};
160
168
  nodes.push({
@@ -173,8 +181,9 @@ function defineSchema(spec) {
173
181
  }
174
182
  continue;
175
183
  }
176
- if (names.has(name))
184
+ if (names.has(name)) {
177
185
  throw new Error(`schema produces duplicate native node '${name}'`);
186
+ }
178
187
  names.add(name);
179
188
  const tag = staticDOMTag('node', name, node.parseDOM, node.toDOM);
180
189
  nodes.push({
@@ -43,7 +43,7 @@ function defaultEmptyDocument(schema = schemaPresets_1.defaultSchema, limits) {
43
43
  function resolveDocumentDescriptor(schema, limits) {
44
44
  const resolvedLimits = (0, schemaResolution_1.resolveDescriptorLimits)(limits);
45
45
  const resolvedSchema = (0, schemaResolution_1.resolveDocumentSchema)(schema, resolvedLimits);
46
- const documentNode = resolvedSchema.nodes.find((node) => node.role === 'doc');
46
+ const documentNode = resolvedSchema.nodes.find(node => node.role === 'doc');
47
47
  if (!documentNode) {
48
48
  throw new NativeEditorBoundaryError_1.NativeEditorBoundaryError('SCHEMA_INVALID', 'schema has no document-role node');
49
49
  }