@miliastry/quasar 1.0.6 → 1.1.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.
Files changed (273) hide show
  1. package/dist/Visuals/lyne.css +117 -6
  2. package/dist/Visuals/osu.css +36 -5
  3. package/dist/index.js +9664 -3282
  4. package/dist/index.mjs +9535 -3283
  5. package/dist/types/Analysis/Contracts/AnalysisReport.d.ts +22 -0
  6. package/dist/types/Analysis/Contracts/Contribution.d.ts +68 -0
  7. package/dist/types/Analysis/Contracts/Pass.d.ts +59 -0
  8. package/dist/types/Analysis/Contracts/PipelineContext.d.ts +34 -0
  9. package/dist/types/Analysis/Passes/Analysis/ColorUsageAnalyzer.d.ts +56 -0
  10. package/dist/types/Analysis/Passes/Analysis/GradientAnalyzer.d.ts +111 -0
  11. package/dist/types/Analysis/Passes/Analysis/MergeableColorAnalyzer.d.ts +26 -0
  12. package/dist/types/Analysis/Passes/Analysis/RainbowAnalyzer.d.ts +47 -0
  13. package/dist/types/Analysis/Passes/Analysis/SymbolAnalyzer.d.ts +89 -0
  14. package/dist/types/Analysis/Passes/Analysis/WaveAnalyzer.d.ts +44 -0
  15. package/dist/types/Analysis/Passes/Analysis/__tests__/GradientAnalyzer.test.d.ts +4 -0
  16. package/dist/types/Analysis/Passes/Analysis/__tests__/MergeableColorAnalyzer.test.d.ts +4 -0
  17. package/dist/types/Analysis/Passes/Analysis/__tests__/RainbowAnalyzer.test.d.ts +4 -0
  18. package/dist/types/Analysis/Passes/Analysis/__tests__/WaveAnalyzer.test.d.ts +4 -0
  19. package/dist/types/Analysis/Passes/Decision/DefaultDecision.d.ts +30 -0
  20. package/dist/types/Analysis/Passes/Decision/PaletteRemapDecision.d.ts +169 -0
  21. package/dist/types/Analysis/Passes/Decision/__tests__/DefaultDecision.test.d.ts +4 -0
  22. package/dist/types/Analysis/Passes/Transform/CollapseGradientTransform.d.ts +37 -0
  23. package/dist/types/Analysis/Passes/Transform/MergeColorsTransform.d.ts +28 -0
  24. package/dist/types/Analysis/Passes/Transform/RainbowCollapseTransform.d.ts +19 -0
  25. package/dist/types/Analysis/Passes/Transform/WaveCollapseTransform.d.ts +20 -0
  26. package/dist/types/Analysis/Passes/Utility/CharacterCountAnalyzer.d.ts +19 -0
  27. package/dist/types/Analysis/Pipeline/Pipeline.d.ts +69 -0
  28. package/dist/types/Analysis/Pipeline/PipelineBuilder.d.ts +31 -0
  29. package/dist/types/Analysis/Pipeline/PipelineStage.d.ts +17 -0
  30. package/dist/types/Analysis/Utils/color-utils.d.ts +60 -0
  31. package/dist/types/Analysis/__tests__/Integration.test.d.ts +8 -0
  32. package/dist/types/Analysis/__tests__/PaletteRemap.test.d.ts +14 -0
  33. package/dist/types/Analysis/__tests__/Pipeline.test.d.ts +10 -0
  34. package/dist/types/Analysis/__tests__/RoundTrip.test.d.ts +30 -0
  35. package/dist/types/Analysis/__tests__/SymbolAnalyzer.test.d.ts +11 -0
  36. package/dist/types/Analysis/index.d.ts +40 -0
  37. package/dist/types/BBCode/BBCodeDocumentModel.d.ts +92 -0
  38. package/dist/types/BBCode/BBCodeToGreenNode.d.ts +111 -0
  39. package/dist/types/BBCode/Parser.d.ts +78 -0
  40. package/dist/types/BBCode/index.d.ts +4 -0
  41. package/dist/types/Collab/positions.d.ts +55 -0
  42. package/dist/types/Commands/Command.d.ts +37 -0
  43. package/dist/types/Commands/CommandRegistry.d.ts +48 -0
  44. package/dist/types/Commands/DeleteNode.d.ts +7 -0
  45. package/dist/types/Commands/InsertText.d.ts +8 -0
  46. package/dist/types/Commands/SplitMerge.d.ts +9 -0
  47. package/dist/types/Commands/WrapInTag.d.ts +8 -0
  48. package/dist/types/Commands/index.d.ts +6 -0
  49. package/dist/types/Diff/TreeDiffer.d.ts +52 -0
  50. package/dist/types/Diff/__tests__/TreeDiffer.test.d.ts +1 -0
  51. package/dist/types/Diff/index.d.ts +2 -0
  52. package/dist/types/Edits/EditPlan.d.ts +144 -0
  53. package/dist/types/Edits/Optimizer.d.ts +78 -0
  54. package/dist/types/Edits/Rules/Rule.d.ts +91 -0
  55. package/dist/types/Edits/Rules/dropEmptyTags.d.ts +40 -0
  56. package/dist/types/Edits/Rules/dropRedundantNesting.d.ts +59 -0
  57. package/dist/types/Edits/Rules/index.d.ts +9 -0
  58. package/dist/types/Edits/Rules/mergeAdjacent.d.ts +93 -0
  59. package/dist/types/Edits/Rules/reorderWrappers.d.ts +42 -0
  60. package/dist/types/Edits/Rules/shortenHex.d.ts +30 -0
  61. package/dist/types/Edits/Rules/tagValue.d.ts +56 -0
  62. package/dist/types/Edits/Rules/unwrapInvisibleColor.d.ts +47 -0
  63. package/dist/types/Edits/applyEdits.d.ts +36 -0
  64. package/dist/types/Edits/index.d.ts +6 -0
  65. package/dist/types/Events/EventBus.d.ts +103 -0
  66. package/dist/types/Events/index.d.ts +2 -0
  67. package/dist/types/Formatter/Formatter.d.ts +32 -0
  68. package/dist/types/Formatter/index.d.ts +2 -0
  69. package/dist/types/HTML/HTMLDocumentModel.d.ts +13 -0
  70. package/dist/types/HTML/HTMLToGreenNode.d.ts +4 -0
  71. package/dist/types/Incremental/BracketIndex.d.ts +101 -0
  72. package/dist/types/Incremental/ChangeTracker.d.ts +69 -0
  73. package/dist/types/Incremental/IncrementalParser.d.ts +246 -0
  74. package/dist/types/Incremental/__tests__/BracketIndex.test.d.ts +1 -0
  75. package/dist/types/Incremental/__tests__/IncrementalParser.test.d.ts +1 -0
  76. package/dist/types/Incremental/index.d.ts +4 -0
  77. package/dist/types/Lexer/BBCodeLexer.d.ts +74 -0
  78. package/dist/types/Lexer/Lexer.d.ts +54 -0
  79. package/dist/types/Lexer/index.d.ts +4 -0
  80. package/dist/types/Linter/Linter.d.ts +58 -0
  81. package/dist/types/Linter/index.d.ts +2 -0
  82. package/dist/types/Markdown/MarkdownAST.d.ts +122 -0
  83. package/dist/types/Markdown/MarkdownDocumentModel.d.ts +15 -0
  84. package/dist/types/Markdown/MarkdownLexer.d.ts +155 -0
  85. package/dist/types/Markdown/MarkdownParser.d.ts +42 -0
  86. package/dist/types/Markdown/MarkdownToGreenNode.d.ts +6 -0
  87. package/dist/types/MilHibri/MilHibriDocumentModel.d.ts +21 -0
  88. package/dist/types/Model/DocumentModel.d.ts +318 -0
  89. package/dist/types/Model/NodeFactory.d.ts +29 -0
  90. package/dist/types/Model/TagRegistry.d.ts +165 -0
  91. package/dist/types/Model/index.d.ts +5 -0
  92. package/dist/types/Plugins/PluginAPI.d.ts +44 -0
  93. package/dist/types/Plugins/PluginRegistry.d.ts +81 -0
  94. package/dist/types/Plugins/index.d.ts +3 -0
  95. package/dist/types/Queries/QueryEngine.d.ts +32 -0
  96. package/dist/types/Queries/index.d.ts +1 -0
  97. package/dist/types/Reconciler/SurgicalReconciler.d.ts +23 -0
  98. package/dist/types/RenderPipeline/RenderPipeline.d.ts +46 -0
  99. package/dist/types/RenderPipeline/RenderTree.d.ts +55 -0
  100. package/dist/types/RenderPipeline/index.d.ts +4 -0
  101. package/dist/types/Repair/NestingRepair.d.ts +48 -0
  102. package/dist/types/Repair/index.d.ts +1 -0
  103. package/dist/types/Semantic/SemanticAnalyzer.d.ts +321 -0
  104. package/dist/types/Semantic/index.d.ts +2 -0
  105. package/dist/types/Symbols/SymbolTable.d.ts +47 -0
  106. package/dist/types/Symbols/index.d.ts +1 -0
  107. package/dist/types/Syntax/GreenNode.d.ts +154 -0
  108. package/dist/types/Syntax/GreenNodePool.d.ts +134 -0
  109. package/dist/types/Syntax/NodeMatcher.d.ts +75 -0
  110. package/dist/types/Syntax/RedNode.d.ts +280 -0
  111. package/dist/types/Syntax/RedNodeStore.d.ts +116 -0
  112. package/dist/types/Syntax/TreeBuilder.d.ts +54 -0
  113. package/dist/types/Syntax/__tests__/GreenNode.test.d.ts +1 -0
  114. package/dist/types/Syntax/__tests__/RedNode.test.d.ts +1 -0
  115. package/dist/types/Syntax/__tests__/RedNodeStore.test.d.ts +1 -0
  116. package/dist/types/Syntax/greenEdit.d.ts +64 -0
  117. package/dist/types/Syntax/hash.d.ts +17 -0
  118. package/dist/types/Syntax/index.d.ts +8 -0
  119. package/dist/types/Syntax/nodeAttr.d.ts +63 -0
  120. package/dist/types/Syntax/partition.d.ts +67 -0
  121. package/dist/types/Syntax/preserveNodeIds.d.ts +47 -0
  122. package/dist/types/Tokens/TokenResolver.d.ts +25 -0
  123. package/dist/types/Tokens/index.d.ts +1 -0
  124. package/dist/types/Transactions/Transaction.d.ts +36 -0
  125. package/dist/types/Transactions/UndoManager.d.ts +63 -0
  126. package/dist/types/Transactions/index.d.ts +3 -0
  127. package/dist/types/Transformers/ASTOptimizer.d.ts +34 -0
  128. package/dist/types/Transformers/GradientTransformer.d.ts +18 -0
  129. package/dist/types/Transformers/GrowTransformer.d.ts +16 -0
  130. package/dist/types/Transformers/RainbowTransformer.d.ts +17 -0
  131. package/dist/types/Transformers/SineWaveTransformer.d.ts +17 -0
  132. package/dist/types/Transformers/Transformer.d.ts +17 -0
  133. package/dist/types/Types/core.d.ts +104 -0
  134. package/dist/types/Types/diagnostics.d.ts +85 -0
  135. package/dist/types/Types/index.d.ts +11 -0
  136. package/dist/types/Types/operations.d.ts +109 -0
  137. package/dist/types/Types/queries.d.ts +67 -0
  138. package/dist/types/Types/symbols.d.ts +42 -0
  139. package/dist/types/Types/tokens.d.ts +75 -0
  140. package/dist/types/Utils/BBCodeGenerator.d.ts +21 -0
  141. package/dist/types/Utils/ColorMath.d.ts +92 -0
  142. package/dist/types/Utils/EffectMath.d.ts +643 -0
  143. package/dist/types/Utils/TagVocabulary.d.ts +104 -0
  144. package/dist/types/Utils/TagVocabulary.test.d.ts +1 -0
  145. package/dist/types/Utils/color.d.ts +29 -0
  146. package/dist/types/Utils/dom-to-svg.d.ts +28 -0
  147. package/dist/types/Utils/dom-to-svg.test.d.ts +1 -0
  148. package/dist/types/Utils/treeTransformers.d.ts +160 -0
  149. package/dist/types/Visitors/BBBlocksExporter.d.ts +27 -0
  150. package/dist/types/Visitors/BBCodeExporter.d.ts +90 -0
  151. package/dist/types/Visitors/BlockPatcher.d.ts +91 -0
  152. package/dist/types/Visitors/DOMMorpher.d.ts +13 -0
  153. package/dist/types/Visitors/HTMLRenderer.d.ts +380 -0
  154. package/dist/types/Visitors/JSONExporter.d.ts +42 -0
  155. package/dist/types/Visitors/MarkdownExporter.d.ts +28 -0
  156. package/dist/types/Visitors/SVGRenderer.d.ts +16 -0
  157. package/dist/types/Visitors/TiptapExporter.d.ts +40 -0
  158. package/dist/types/Visitors/Visitor.d.ts +35 -0
  159. package/dist/types/Visitors/index.d.ts +9 -0
  160. package/dist/types/Visuals/BoxDrawer.d.ts +49 -0
  161. package/dist/types/Visuals/index.d.ts +38 -0
  162. package/dist/types/index.d.ts +154 -0
  163. package/package.json +14 -10
  164. package/src/Analysis/Passes/Analysis/ColorUsageAnalyzer.ts +103 -0
  165. package/src/Analysis/Passes/Analysis/GradientAnalyzer.ts +294 -20
  166. package/src/Analysis/Passes/Analysis/SymbolAnalyzer.ts +257 -0
  167. package/src/Analysis/Passes/Decision/PaletteRemapDecision.ts +425 -0
  168. package/src/Analysis/Pipeline/Pipeline.ts +15 -2
  169. package/src/Analysis/index.ts +8 -2
  170. package/src/BBCode/BBCodeDocumentModel.ts +3 -0
  171. package/src/BBCode/BBCodeToGreenNode.ts +18 -12
  172. package/src/BBCode/Parser.ts +38 -1
  173. package/src/Edits/EditPlan.ts +290 -0
  174. package/src/Edits/Optimizer.ts +185 -0
  175. package/src/Edits/Rules/Rule.ts +145 -0
  176. package/src/Edits/Rules/dropEmptyTags.ts +110 -0
  177. package/src/Edits/Rules/dropRedundantNesting.ts +120 -0
  178. package/src/Edits/Rules/index.ts +28 -0
  179. package/src/Edits/Rules/mergeAdjacent.ts +224 -0
  180. package/src/Edits/Rules/reorderWrappers.ts +154 -0
  181. package/src/Edits/Rules/shortenHex.ts +79 -0
  182. package/src/Edits/Rules/tagValue.ts +105 -0
  183. package/src/Edits/Rules/unwrapInvisibleColor.ts +93 -0
  184. package/src/Edits/applyEdits.ts +54 -0
  185. package/src/Edits/index.ts +22 -0
  186. package/src/Events/EventBus.ts +18 -0
  187. package/src/HTML/HTMLToGreenNode.ts +185 -37
  188. package/src/Incremental/BracketIndex.ts +249 -0
  189. package/src/Incremental/IncrementalParser.ts +464 -41
  190. package/src/Lexer/BBCodeLexer.ts +25 -3
  191. package/src/Lexer/index.ts +1 -1
  192. package/src/Markdown/MarkdownAST.ts +65 -2
  193. package/src/Markdown/MarkdownLexer.ts +69 -14
  194. package/src/Markdown/MarkdownParser.ts +749 -62
  195. package/src/Markdown/MarkdownToGreenNode.ts +148 -27
  196. package/src/MilHibri/MilHibriDocumentModel.ts +56 -0
  197. package/src/Model/DocumentModel.ts +138 -5
  198. package/src/Model/TagRegistry.ts +129 -134
  199. package/src/Reconciler/SurgicalReconciler.ts +460 -0
  200. package/src/Repair/NestingRepair.ts +116 -0
  201. package/src/Repair/index.ts +1 -0
  202. package/src/Semantic/SemanticAnalyzer.ts +1802 -65
  203. package/src/Syntax/GreenNodePool.ts +12 -12
  204. package/src/Syntax/RedNode.ts +17 -3
  205. package/src/Syntax/RedNodeStore.ts +9 -1
  206. package/src/Syntax/nodeAttr.ts +172 -0
  207. package/src/Tokens/TokenResolver.ts +55 -0
  208. package/src/Tokens/index.ts +1 -0
  209. package/src/Types/core.ts +15 -0
  210. package/src/Utils/ColorMath.ts +276 -55
  211. package/src/Utils/EffectMath.ts +2462 -0
  212. package/src/Utils/TagVocabulary.ts +141 -0
  213. package/src/Utils/dom-to-svg.ts +28 -12
  214. package/src/Visitors/BBBlocksExporter.ts +15 -1
  215. package/src/Visitors/BBCodeExporter.ts +319 -32
  216. package/src/Visitors/BlockPatcher.ts +87 -11
  217. package/src/Visitors/DOMMorpher.ts +15 -5
  218. package/src/Visitors/HTMLRenderer.ts +374 -151
  219. package/src/Visitors/MarkdownExporter.ts +98 -41
  220. package/src/Visitors/TiptapExporter.ts +1 -0
  221. package/src/Visuals/index.ts +7 -4
  222. package/src/Visuals/lyne.css +117 -6
  223. package/src/Visuals/osu.css +36 -5
  224. package/src/index.ts +172 -5
  225. package/dist/index.d.mts +0 -4612
  226. package/dist/index.d.ts +0 -4612
  227. package/src/Analysis/Passes/Analysis/__tests__/GradientAnalyzer.test.ts +0 -135
  228. package/src/Analysis/Passes/Analysis/__tests__/MergeableColorAnalyzer.test.ts +0 -84
  229. package/src/Analysis/Passes/Analysis/__tests__/RainbowAnalyzer.test.ts +0 -99
  230. package/src/Analysis/Passes/Analysis/__tests__/WaveAnalyzer.test.ts +0 -119
  231. package/src/Analysis/Passes/Decision/__tests__/DefaultDecision.test.ts +0 -179
  232. package/src/Analysis/__tests__/Integration.test.ts +0 -162
  233. package/src/Analysis/__tests__/Pipeline.test.ts +0 -133
  234. package/src/Diff/__tests__/TreeDiffer.test.ts +0 -65
  235. package/src/Incremental/__tests__/IncrementalParser.test.ts +0 -164
  236. package/src/Syntax/__tests__/GreenNode.test.ts +0 -33
  237. package/src/Syntax/__tests__/RedNode.test.ts +0 -81
  238. package/src/Syntax/__tests__/RedNodeStore.test.ts +0 -104
  239. package/src/Tests/ASTOptimizerIdempotence.test.ts +0 -77
  240. package/src/Tests/BlockPatcher.test.ts +0 -437
  241. package/src/Tests/BlockPatcherWindowed.test.ts +0 -364
  242. package/src/Tests/BoxDrawer.test.ts +0 -217
  243. package/src/Tests/BoxRichTitle.test.ts +0 -105
  244. package/src/Tests/Chars500kBenchmark.test.ts +0 -151
  245. package/src/Tests/Chars500kEdits.test.ts +0 -321
  246. package/src/Tests/CollabPositions.test.ts +0 -146
  247. package/src/Tests/CompilerPathProfiling.test.ts +0 -186
  248. package/src/Tests/DOMMorpher.test.ts +0 -142
  249. package/src/Tests/DomPatchPerf.test.ts +0 -60
  250. package/src/Tests/EffectSegments.snapshot.json +0 -616
  251. package/src/Tests/EffectSegments.test.ts +0 -68
  252. package/src/Tests/FindNodeAtOffset.test.ts +0 -65
  253. package/src/Tests/Fuzzer.test.ts +0 -166
  254. package/src/Tests/GreenNodePool.test.ts +0 -153
  255. package/src/Tests/Lexer.test.ts +0 -238
  256. package/src/Tests/LyneMode.test.ts +0 -291
  257. package/src/Tests/ModelCoherence.test.ts +0 -180
  258. package/src/Tests/Partition.test.ts +0 -238
  259. package/src/Tests/PluginTags.test.ts +0 -150
  260. package/src/Tests/ProblematicSection.test.ts +0 -46
  261. package/src/Tests/ProblematicSectionHTML.test.ts +0 -58
  262. package/src/Tests/RedReuse.test.ts +0 -134
  263. package/src/Tests/ReproDelete20k.test.ts +0 -62
  264. package/src/Tests/SemanticValidators.test.ts +0 -136
  265. package/src/Tests/StableNodeIds.test.ts +0 -210
  266. package/src/Tests/StudioColorBloat.test.ts +0 -25
  267. package/src/Tests/StudioDebugText.test.ts +0 -27
  268. package/src/Tests/StudioTrailingChar.test.ts +0 -25
  269. package/src/Tests/StudioValidText.test.ts +0 -25
  270. package/src/Tests/UrlImgBug.test.ts +0 -23
  271. package/src/Tests/VisualBuilderFidelity.test.ts +0 -105
  272. package/src/Tests/referenceDocument.ts +0 -119
  273. package/src/Utils/dom-to-svg.test.ts +0 -86
@@ -0,0 +1,116 @@
1
+ /**
2
+ * DocumentEngine — RedNodeStore
3
+ *
4
+ * Canonical store for RedNodes. Ensures that structurally identical subtrees
5
+ * share the EXACT SAME RedNode instance in RAM.
6
+ *
7
+ * This is the RedNode-level complement to GreenNodePool (which handles
8
+ * structural sharing at the GreenNode level).
9
+ *
10
+ * Architecture:
11
+ * - Keyed by GreenNode._hash (deterministic structural hash)
12
+ * - Bottom-up: children are stored first, then parents reference them
13
+ * - Immutable structural data: once a RedNode is in the store, its `children`
14
+ * array and `green` reference never change
15
+ * - Mutable metadata: the store's RedNode has canonical metadata (derived from
16
+ * green.text). Position-specific metadata lives in PositionRef.localOverlay.
17
+ *
18
+ * Benefits:
19
+ * - Memory deduplication: 100 identical blocks = 1 RedNode + 99 lightweight refs
20
+ * - Render caching: BBCodeCanvas can memoize by canonicalId
21
+ * - Faster incremental parse: unchanged subtrees keep their RedNode identity
22
+ * - HTMLRenderer cache: same canonicalId = same HTML (cache hits)
23
+ */
24
+ import { GreenNode } from './GreenNode';
25
+ import { RedNode } from './RedNode';
26
+ import type { NodeKind, NodeMetadata } from '../Types/core';
27
+ /**
28
+ * Derives a node's canonical metadata from its GreenNode.
29
+ *
30
+ * Injected rather than hardcoded: metadata extraction is *language* semantics
31
+ * (what `=#ff0000,#00ff00` means for a `gradient`), and this module sits in the
32
+ * language-agnostic `Syntax` layer. The BBCode implementation lives in
33
+ * `BBCode/BBCodeToGreenNode.ts`; pass it via the constructor.
34
+ */
35
+ export type MetadataExtractor = (green: GreenNode) => NodeMetadata;
36
+ export declare class RedNodeStore {
37
+ private canonicals;
38
+ private _hits;
39
+ private _misses;
40
+ private _collisions;
41
+ private readonly extractMetadata;
42
+ /**
43
+ * @param extractMetadata How to derive canonical metadata from a green node.
44
+ * Defaults to producing none — the store stays language-agnostic unless a
45
+ * caller supplies the mapping.
46
+ */
47
+ constructor(extractMetadata?: MetadataExtractor);
48
+ /**
49
+ * Get or create a canonical RedNode for the given GreenNode.
50
+ *
51
+ * The store is keyed by `green._hash` — a 32-bit FNV structural hash — so a
52
+ * matching key is necessary but NOT sufficient proof of identity. The
53
+ * canonical pipeline (GreenNodePool interning) guarantees that structurally
54
+ * identical greens ARE the same object, which is what makes reference
55
+ * equality a sound discriminator:
56
+ *
57
+ * - same hash + same green reference → HIT, reuse the canonical
58
+ * - same hash + different green → COLLISION: a distinct subtree shares
59
+ * the 32-bit hash. It is never reused as the registered canonical and never
60
+ * overwrites it (that would corrupt every future hit for the registered
61
+ * node). The colliding subtree simply loses canonicalization — rebuilt on
62
+ * each call. Guarding correctness costs a rare dedup miss; the alternative
63
+ * costs a wrong AST.
64
+ * - no hash entry → MISS, create and register
65
+ *
66
+ * Invariant preserved: a hash collision can never make one structure be
67
+ * represented by another structure's RedNode.
68
+ *
69
+ * @param green The GreenNode to wrap
70
+ * @param metadata Optional metadata to set (overrides intrinsic metadata)
71
+ * @param kind Optional kind override
72
+ * @returns The canonical RedNode (shared if already exists)
73
+ */
74
+ getOrCreate(green: GreenNode, metadata?: NodeMetadata, kind?: NodeKind): RedNode;
75
+ /**
76
+ * Build a canonical RedNode for `green` WITHOUT registering it.
77
+ *
78
+ * Shared by the miss path (which registers the result) and the collision
79
+ * path (which must not). Both need the same bottom-up construction:
80
+ * children are canonicalized first, then the parent references them.
81
+ */
82
+ private buildCanonical;
83
+ /**
84
+ * Look up a canonical RedNode by its structural hash.
85
+ */
86
+ getByHash(hash: string): RedNode | undefined;
87
+ /**
88
+ * Check if a GreenNode already has a canonical RedNode.
89
+ *
90
+ * Mirrors `getOrCreate`'s discriminator, including the identity check. A
91
+ * present hash entry only proves *some* structure registered under this
92
+ * 32-bit hash; if it is a different green, `getOrCreate` counts a collision
93
+ * and builds an unregistered node, so answering `true` here would be the
94
+ * opposite of the truth for any caller deciding whether canonicalization has
95
+ * already happened.
96
+ */
97
+ has(green: GreenNode): boolean;
98
+ /**
99
+ * Get the number of unique canonical nodes.
100
+ */
101
+ get size(): number;
102
+ /**
103
+ * Get store statistics.
104
+ */
105
+ get stats(): {
106
+ size: number;
107
+ hits: number;
108
+ misses: number;
109
+ collisions: number;
110
+ deduplicationRatio: string;
111
+ };
112
+ /**
113
+ * Clear all canonical nodes.
114
+ */
115
+ clear(): void;
116
+ }
@@ -0,0 +1,54 @@
1
+ /**
2
+ * DocumentEngine — TreeBuilder
3
+ *
4
+ * Converts a TokenStream into a GreenNode tree.
5
+ * This is the bridge between the Lexer and the Syntax Tree.
6
+ *
7
+ * The TreeBuilder is language-agnostic — it uses registry-based
8
+ * node factories to build the appropriate tree structure.
9
+ */
10
+ import { GreenNode } from './GreenNode';
11
+ import { RedNode } from './RedNode';
12
+ import type { TokenStream, Token } from '../Types/tokens';
13
+ import type { NodeKind } from '../Types/core';
14
+ export interface BuildResult {
15
+ green: GreenNode;
16
+ red: RedNode;
17
+ tokens: Token[];
18
+ }
19
+ export interface NodeFactory {
20
+ /** Create a GreenNode from a token or sequence of tokens */
21
+ createGreen(tokens: Token[], stream: TokenStream): GreenNode | null;
22
+ /** Create a RedNode from a green node */
23
+ createRed(green: GreenNode, parent?: RedNode | null): RedNode;
24
+ }
25
+ export declare class TreeBuilder {
26
+ private factories;
27
+ private defaultKind;
28
+ constructor(defaultKind?: NodeKind);
29
+ /**
30
+ * Register a node factory for a specific token kind or tag name.
31
+ */
32
+ register(kind: string, factory: NodeFactory): void;
33
+ /**
34
+ * Build a tree from a token stream.
35
+ */
36
+ build(stream: TokenStream): BuildResult;
37
+ /**
38
+ * Build a green tree from a token array.
39
+ * Uses registered factories to determine node structure.
40
+ *
41
+ * By default, creates a flat document structure.
42
+ * Language-specific builders (like BBCodeParser) override this.
43
+ */
44
+ buildGreen(tokens: Token[]): GreenNode;
45
+ /**
46
+ * Build a red tree from a green tree.
47
+ */
48
+ buildRed(green: GreenNode, parent?: RedNode | null, kind?: NodeKind): RedNode;
49
+ /**
50
+ * Create a RedNode directly from children (for language-specific parsers).
51
+ */
52
+ createRedFromChildren(kind: NodeKind, text: string, children: RedNode[], parent?: RedNode | null): RedNode;
53
+ private tagToKind;
54
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,64 @@
1
+ /**
2
+ * DocumentEngine — Green tree editing primitives
3
+ *
4
+ * The green tree is immutable, so an edit is not a mutation: it is a new tree
5
+ * that shares everything the edit did not touch.
6
+ *
7
+ * ─── What used to be here ───────────────────────────────────────────────────
8
+ *
9
+ * `shiftGreen(node, delta)` — a deep copy of a subtree with every range moved.
10
+ * It existed because green nodes carried absolute positions, so inserting three
11
+ * characters near the top of a document meant rebuilding every node after the
12
+ * insertion point just to renumber it. On a 19.6 KB document that was 14% of
13
+ * the cost of an incremental reparse, spent entirely on producing structurally
14
+ * identical copies of nodes that had not changed.
15
+ *
16
+ * It is gone, and there is nothing to replace it with. Green nodes have widths,
17
+ * not positions (see `GreenNode.ts`), so text inserted before a subtree changes
18
+ * where it is — which is the red tree's business — and not what it is. A
19
+ * sibling after an edit is now shared by reference, exactly like a sibling
20
+ * before it always was.
21
+ */
22
+ import { GreenNode } from './GreenNode';
23
+ /** One step of the descent from the root to the node being replaced. */
24
+ export interface SpineStep {
25
+ /** The ancestor. */
26
+ node: GreenNode;
27
+ /** Index of the child that the descent continued into. */
28
+ index: number;
29
+ }
30
+ /**
31
+ * Rebuild the ancestor spine after replacing one node.
32
+ *
33
+ * `spine` runs root-first; `replacement` takes the place of
34
+ * `spine[spine.length - 1].node.children[spine[spine.length - 1].index]`.
35
+ *
36
+ * Only the spine itself is rebuilt — one new node per level of nesting, and
37
+ * every other subtree in the document is carried over by reference. The
38
+ * ancestors' widths follow from their new children automatically, so there is
39
+ * no delta to propagate and no way to get the arithmetic wrong.
40
+ */
41
+ export declare function spliceGreen(spine: readonly SpineStep[], replacement: GreenNode): GreenNode;
42
+ /**
43
+ * Replace a node's children while keeping the node itself — its kind, its
44
+ * attributes and, above all, its delimiters.
45
+ *
46
+ * The incremental parser re-parses a span strictly INSIDE a node, so that
47
+ * node's own `[centre]` and `[/centre]` never pass through the parser again and
48
+ * cannot be reinterpreted. `leadingWidth`/`trailingWidth` carry across
49
+ * untouched; the new width follows from the new children.
50
+ */
51
+ export declare function withChildren(node: GreenNode, children: GreenNode[]): GreenNode;
52
+ /**
53
+ * Replace the children `[from, to)` of `node` with `replacement`.
54
+ *
55
+ * The unit an edit actually touches is a RUN OF SIBLINGS, not a whole node.
56
+ * Re-parsing a container's entire contents because one character changed
57
+ * somewhere inside it meant that typing into a large `[notice]` re-lexed 66% of
58
+ * the document per keystroke; and an edit at document level had no enclosing
59
+ * container at all, so it fell back to a full rebuild — which is where the
60
+ * caret sits while you write the end of a post, the single most common case.
61
+ *
62
+ * Everything outside `[from, to)` is carried over by reference.
63
+ */
64
+ export declare function withChildrenSpliced(node: GreenNode, from: number, to: number, replacement: readonly GreenNode[]): GreenNode;
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Quasar — Structural Hashing Primitives (FNV-1a)
3
+ *
4
+ * Shared by GreenNode (`_hash`, for interning and structural sharing) and
5
+ * NodeMatcher (subtree fingerprints, for cross-version node matching).
6
+ *
7
+ * FNV-1a is chosen for the same reason Roslyn uses a cheap non-cryptographic
8
+ * hash: this runs once per node on every keystroke, so throughput matters far
9
+ * more than adversarial collision resistance. `Math.imul` keeps the multiply
10
+ * in 32-bit integer space instead of promoting to doubles.
11
+ */
12
+ export declare const FNV_OFFSET = 2166136261;
13
+ export declare const FNV_PRIME = 16777619;
14
+ /** Secondary basis, used to build a 64-bit key from two independent lanes. */
15
+ export declare const FNV_OFFSET_ALT = 668265263;
16
+ export declare function hashString(seed: number, str: string): number;
17
+ export declare function hashUint32(seed: number, value: number): number;
@@ -0,0 +1,8 @@
1
+ export { GreenNode, greenNode, greenLeaf } from './GreenNode';
2
+ export { RedNode } from './RedNode';
3
+ export { TreeBuilder } from './TreeBuilder';
4
+ export type { BuildResult, NodeFactory } from './TreeBuilder';
5
+ export { checkPartition, assertPartition } from './partition';
6
+ export type { PartitionViolation, PartitionViolationKind, CheckPartitionOptions, } from './partition';
7
+ export { NodeMatcher } from './NodeMatcher';
8
+ export type { MatchResult, MatchStatus, NodeMatch } from './NodeMatcher';
@@ -0,0 +1,63 @@
1
+ /**
2
+ * Cómo se lee el atributo de una etiqueta BBCode, y qué valores se aceptan.
3
+ *
4
+ * ── Por qué esto vive fuera del renderizador ───────────────────────────────
5
+ *
6
+ * Era privado de `HTMLRenderer`, así que cualquier otro consumidor que
7
+ * necesitara el mismo dato tenía que reinventarlo — y se reinventó mal. Los
8
+ * presets del lienzo de BBCodeCanvas leían `node.text` en crudo, con el `=`
9
+ * pegado delante: `[color=#ff0000]` acababa produciendo `color: "=#ff0000"`,
10
+ * que es CSS inválido, así que el color no se pintaba en absoluto. Lo mismo con
11
+ * `font_size` y `url`.
12
+ *
13
+ * No es un helper nuevo: es el mismo código, movido a donde los dos lo ven. Si
14
+ * el renderizador y el lienzo vuelven a divergir, al menos divergirán desde el
15
+ * mismo sitio.
16
+ */
17
+ import type { RedNode } from './RedNode';
18
+ import type { TokenResolverFn } from '../Tokens';
19
+ /**
20
+ * El valor del atributo de un nodo.
21
+ *
22
+ * Los atributos BBCode vienen como `=VALOR` (`=#61afef`, `="Autor"`,
23
+ * `=https://osu.ppy.sh`): se quita el `=` y las comillas envolventes. Una
24
+ * etiqueta sin atributo —el contenido de un `[img]`, por ejemplo— devuelve su
25
+ * texto tal cual.
26
+ *
27
+ * Con `key`, gana lo que haya en `metadata`: es lo que escribe el Inspector al
28
+ * editar una propiedad, y tiene que pesar más que el texto original del
29
+ * documento, que todavía no se ha reescrito.
30
+ */
31
+ export declare function nodeAttrValue(node: RedNode, key?: string): string;
32
+ /**
33
+ * Un color que se puede meter en un `style`, o `null`.
34
+ *
35
+ * Devolver `null` en vez de el valor crudo no es remilgo: `[color=red;"
36
+ * onmouseover="alert(1)]` cierra el atributo e inyecta un manejador de eventos.
37
+ * Escapar solo neutralizaría la inyección, pero dejaría CSS roto, así que se
38
+ * valida la FORMA y se descarta lo que no sea un valor que quisiéramos admitir.
39
+ *
40
+ * Un hex sin `#` se completa: `[color=ff0000]` es como lo escribe medio mundo.
41
+ */
42
+ export declare function sanitizeColor(raw: string, resolver?: TokenResolverFn): string | null;
43
+ /** El tamaño de `[size=…]` como número, o `null`. Se interpola en `%`. */
44
+ export declare function sanitizeFontSize(raw: string, resolver?: TokenResolverFn): string | null;
45
+ /** La familia de `[font=…]`, o `null`. */
46
+ export declare function sanitizeFontFamily(raw: string, resolver?: TokenResolverFn): string | null;
47
+ /** Lo que puede significar el atributo de un `[img=…]`. */
48
+ export interface ImgAttr {
49
+ w?: number;
50
+ h?: number;
51
+ round?: boolean;
52
+ shadow?: boolean;
53
+ float?: boolean;
54
+ }
55
+ /**
56
+ * El modificador de una imagen: `[img=200x100]`, `[img=round]`, `[img=shadow]`,
57
+ * `[img=float]`.
58
+ *
59
+ * Vive aquí y no en el renderizador porque es interpretación del ATRIBUTO, no
60
+ * de cómo se pinta: quien quiera respetar un `round` necesita este mismo
61
+ * significado, y hasta ahora el lienzo simplemente lo ignoraba.
62
+ */
63
+ export declare function parseImgAttr(v: string | null): ImgAttr;
@@ -0,0 +1,67 @@
1
+ /**
2
+ * DocumentEngine — Partition Invariant
3
+ *
4
+ * The green tree must PARTITION the source text: every character of the input
5
+ * is accounted for exactly once, and the tree can answer "which node owns
6
+ * offset N?" without ambiguity.
7
+ *
8
+ * Before the width model this was false in three ways, all measured:
9
+ *
10
+ * 1. Delimiters were not represented at all. `[b]hola[/b]` produced a `bold`
11
+ * spanning `[0..13]` whose only child spanned `[3..7]` — 6 characters
12
+ * inside the parent belonged to no node. 32.630 occurrences of
13
+ * `parent.start != firstChild.start` in a single real document.
14
+ * 2. Siblings could occupy the same range. `"hola\n\nmundo"` produced
15
+ * `spacing [4..6]` AND `empty_line [4..6]`, so offset 5 had two owners.
16
+ * 3. Orphaned closing tags were dropped silently, leaving holes in the root.
17
+ *
18
+ * ─── What this module still checks, and what it no longer needs to ──────────
19
+ *
20
+ * Most of the invariant is now STRUCTURAL. A green node has no position, and
21
+ * its width is computed by its own constructor as
22
+ * `leadingWidth + Σ child widths + trailingWidth`, so gaps, overlaps and
23
+ * mismatched delimiters are not states the type can be in. The checks for them
24
+ * were deleted along with the ability to fail them.
25
+ *
26
+ * Two things remain genuinely checkable, and they are the two that matter:
27
+ *
28
+ * - **Coverage.** The root's width must equal the source length. If the parser
29
+ * drops a token — which is exactly what the orphaned-closing-tag bug did —
30
+ * the tree is internally consistent but describes a shorter document.
31
+ * - **Leaf honesty.** A `text` token's width must equal the text it holds.
32
+ * Nothing derives this, so nothing enforces it.
33
+ */
34
+ import type { GreenNode } from './GreenNode';
35
+ export type PartitionViolationKind =
36
+ /** The root's width does not match the source length. */
37
+ 'root-coverage'
38
+ /** A leaf's width does not match the text it claims to hold. */
39
+ | 'leaf-width'
40
+ /** A node's width disagrees with its own children plus delimiters. */
41
+ | 'width-mismatch';
42
+ export interface PartitionViolation {
43
+ kind: PartitionViolationKind;
44
+ /** Structural path to the offending node, e.g. `document/paragraph[0]/bold[1]`. */
45
+ path: string;
46
+ nodeKind: string;
47
+ detail: string;
48
+ }
49
+ export interface CheckPartitionOptions {
50
+ /** Stop after this many violations. Default 200 — enough to diagnose, cheap to print. */
51
+ limit?: number;
52
+ /**
53
+ * Also require leaf widths to match `text.length`. Off by default: `text` on
54
+ * a leaf is overloaded (it holds tag attributes on element nodes and is empty
55
+ * on `spacing`/`empty_line`), so only `text`-kind leaves are checked even
56
+ * when this is on.
57
+ */
58
+ checkLeafWidths?: boolean;
59
+ }
60
+ /**
61
+ * Verify that `root` partitions `[0..sourceLength]`.
62
+ *
63
+ * Returns an empty array when the tree is well formed. Never throws.
64
+ */
65
+ export declare function checkPartition(root: GreenNode, sourceLength: number, options?: CheckPartitionOptions): PartitionViolation[];
66
+ /** Convenience for tests: throw a readable error if the invariant is broken. */
67
+ export declare function assertPartition(root: GreenNode, sourceLength: number): void;
@@ -0,0 +1,47 @@
1
+ /**
2
+ * DocumentEngine — preserveNodeIds
3
+ *
4
+ * Carry `RedNode.id` across a reparse, so a node that did not change keeps
5
+ * the identity it had in the previous tree.
6
+ *
7
+ * Why this exists: every element in the rendered HTML embeds `data-node-id`
8
+ * (the preview→Monaco click mapping reads it), and ids used to be regenerated
9
+ * on every parse. That made the HTML of *unchanged* subtrees differ between
10
+ * keystrokes, which defeated the DOMMorpher's `isEqualNode` fast path —
11
+ * measured on a one-character edit, only 2 of 5 top-level subtrees compared
12
+ * equal with ids embedded, versus 4 of 5 without them. Stable ids also make
13
+ * any future node-identity feature (selection preservation, collaboration)
14
+ * possible at all: two versions of a document can refer to the same node.
15
+ *
16
+ * The pairing strategy mirrors `NodeMatcher`'s Phase 0, which is validated at
17
+ * scale: walk both trees in lockstep, trim the common prefix and suffix of
18
+ * every child list, and only descend into the changed window when it is the
19
+ * single-child shape a keystroke produces. Three tiers of matching:
20
+ *
21
+ * 1. Reference-equal greens — the incremental splice shares untouched
22
+ * subtrees by reference, so this covers almost everything while typing.
23
+ * Identical by construction; adopt the whole subtree, no checks.
24
+ * 2. Hash-equal greens — the full-rebuild path reparses everything, so
25
+ * nothing is reference-equal but unchanged subtrees hash the same.
26
+ * Verified structurally before adopting (a 32-bit hash is not proof).
27
+ * 3. Same kind at the same position — the node itself changed (it is the
28
+ * one being typed into) but it is still "the same element", so it keeps
29
+ * its id and its children get the prefix/suffix treatment.
30
+ *
31
+ * Uniqueness is preserved by construction: the walk is strictly positional
32
+ * (old child i pairs with at most one new child), so an old id is adopted at
33
+ * most once, and ids never adopted stay as freshly generated — the global
34
+ * counter guarantees those cannot collide with anything older.
35
+ */
36
+ import type { RedNode } from './RedNode';
37
+ export interface PreserveIdsStats {
38
+ /** Nodes that kept their previous id */
39
+ adopted: number;
40
+ /** Nodes in the new tree that kept a fresh id */
41
+ fresh: number;
42
+ }
43
+ /**
44
+ * Copy ids from `oldRoot`'s tree onto the matching nodes of `newRoot`'s tree.
45
+ * Returns how many nodes were matched, for tests and diagnostics.
46
+ */
47
+ export declare function preserveNodeIds(oldRoot: RedNode, newRoot: RedNode): PreserveIdsStats;
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Quasar Document Engine — Design Tokens
3
+ *
4
+ * Provides token types and normalization utilities for design token resolution.
5
+ * Completely independent of @miliastry/core.
6
+ */
7
+ export interface DocumentTokens {
8
+ palette?: Record<string, string>;
9
+ variables?: Record<string, string>;
10
+ }
11
+ export type TokenResolverFn = (name: string) => string | undefined;
12
+ export type TokenSource = DocumentTokens | TokenResolverFn;
13
+ /**
14
+ * Normalizes a TokenSource into a TokenResolverFn.
15
+ *
16
+ * For DocumentTokens, checks palette[name] ?? variables[name], handling both
17
+ * with and without leading `$`.
18
+ * If source is already a function, passes it through.
19
+ */
20
+ export declare function toTokenResolver(source?: TokenSource): TokenResolverFn | undefined;
21
+ /**
22
+ * Resolves a token value if val starts with `$`.
23
+ * Strips `$` and looks up in resolver. If found, returns resolved value; otherwise returns val.
24
+ */
25
+ export declare function resolveTokenValue(val: string, resolver?: TokenResolverFn): string;
@@ -0,0 +1 @@
1
+ export * from './TokenResolver';
@@ -0,0 +1,36 @@
1
+ /**
2
+ * DocumentEngine — Transaction
3
+ *
4
+ * Groups operations into an atomic, undoable unit.
5
+ * Every modification to the document MUST go through a Transaction.
6
+ *
7
+ * Inspired by ProseMirror's Transaction system.
8
+ */
9
+ import { RedNode } from '../Syntax/RedNode';
10
+ import type { Operation } from '../Types/operations';
11
+ export declare class Transaction {
12
+ readonly operations: Operation[];
13
+ readonly id: string;
14
+ readonly timestamp: number;
15
+ private _applied;
16
+ constructor(operations: Operation[]);
17
+ /**
18
+ * Apply the transaction to a RedNode tree.
19
+ * Returns the updated tree or null if application failed.
20
+ */
21
+ apply(root: RedNode): RedNode | null;
22
+ /**
23
+ * Create the inverse transaction (for undo).
24
+ */
25
+ invert(root: RedNode): Transaction;
26
+ /**
27
+ * Get a human-readable label for this transaction.
28
+ */
29
+ getLabel(): string;
30
+ private applyOperation;
31
+ private applyInsert;
32
+ private applyDelete;
33
+ private applyReplace;
34
+ private applyMove;
35
+ private applySetText;
36
+ }
@@ -0,0 +1,63 @@
1
+ /**
2
+ * DocumentEngine — UndoManager
3
+ *
4
+ * Manages the undo/redo history stack.
5
+ *
6
+ * Entries are source-text snapshots, not stored tree mutations: the model
7
+ * rebuilds from text on undo/redo, so an entry stays replayable even after
8
+ * intervening rebuilds have replaced every node id it could have referenced.
9
+ * (The previous design stored `Transaction`s, whose `invert()` was only
10
+ * defined for one of the six operation kinds and whose one-shot `_applied`
11
+ * flag made redo a silent no-op.)
12
+ *
13
+ * Inspired by VSCode's undo stack.
14
+ */
15
+ export interface UndoEntry {
16
+ /** Source text before the change */
17
+ before: string;
18
+ /** Source text after the change */
19
+ after: string;
20
+ label: string;
21
+ timestamp: number;
22
+ }
23
+ export declare class UndoManager {
24
+ private undoStack;
25
+ private redoStack;
26
+ private maxSize;
27
+ constructor(maxSize?: number);
28
+ /**
29
+ * Push a change (as before/after source snapshots) onto the undo stack.
30
+ */
31
+ push(snapshot: {
32
+ before: string;
33
+ after: string;
34
+ }, label?: string): void;
35
+ /**
36
+ * Undo the last change.
37
+ */
38
+ undo(): UndoEntry | null;
39
+ /**
40
+ * Redo the last undone change.
41
+ */
42
+ redo(): UndoEntry | null;
43
+ /**
44
+ * Peek at the top of the undo stack without removing.
45
+ */
46
+ peekUndo(): UndoEntry | null;
47
+ /**
48
+ * Peek at the top of the redo stack without removing.
49
+ */
50
+ peekRedo(): UndoEntry | null;
51
+ /**
52
+ * Clear both stacks.
53
+ */
54
+ clear(): void;
55
+ /**
56
+ * Get the number of undoable actions.
57
+ */
58
+ get undoCount(): number;
59
+ /**
60
+ * Get the number of redoable actions.
61
+ */
62
+ get redoCount(): number;
63
+ }
@@ -0,0 +1,3 @@
1
+ export { Transaction } from './Transaction';
2
+ export { UndoManager } from './UndoManager';
3
+ export type { UndoEntry } from './UndoManager';
@@ -0,0 +1,34 @@
1
+ import { DocumentModel } from '../Model/DocumentModel';
2
+ import { Transformer, TransformResult } from './Transformer';
3
+ export declare class ASTOptimizer implements Transformer {
4
+ transform(document: DocumentModel): TransformResult;
5
+ private applyRules;
6
+ private static VOID_TAGS;
7
+ private static UNMERGEABLE;
8
+ private isEmptyNode;
9
+ /**
10
+ * Two `paragraph` siblings with *nothing* between them.
11
+ *
12
+ * `paragraph` is in {@link UNMERGEABLE} for good reason — paragraphs are block
13
+ * separators and collapsing them normally would change the document. But this
14
+ * particular shape is one the optimizer creates itself and the parser never
15
+ * does: paragraphs exist because a block element split the inline content, so
16
+ * when a rule deletes that block (an empty `[notice]`, say) the two halves are
17
+ * left as adjacent paragraphs that no longer have anything separating them.
18
+ *
19
+ * That was the whole non-idempotence bug. Exporting such a tree emits no
20
+ * separator, so re-parsing folds the two paragraphs back into one and a second
21
+ * optimizer pass finds more work to do. Merging here makes the tree agree with
22
+ * its own round-trip.
23
+ *
24
+ * Verified empirically before relying on it: across 202.764 nodes (both real
25
+ * fixtures plus 20.000 seeded random documents) the parser produced this shape
26
+ * **zero** times, so the rule can only ever fire on optimizer-made trees.
27
+ *
28
+ * `spaces` must be empty — paragraphs separated by real spacing or blank lines
29
+ * are a genuine authored break and must survive.
30
+ */
31
+ private isOrphanedParagraphPair;
32
+ private canMerge;
33
+ private getRank;
34
+ }
@@ -0,0 +1,18 @@
1
+ import { DocumentModel } from '../Model/DocumentModel';
2
+ import { Transformer, TransformResult } from './Transformer';
3
+ import { type Easing } from '../Utils/color';
4
+ export interface GradientOptions {
5
+ from: string;
6
+ to: string;
7
+ unit: 'char' | 'word';
8
+ easing: Easing;
9
+ selectionRange?: {
10
+ start: number;
11
+ end: number;
12
+ };
13
+ }
14
+ export declare class GradientTransformer implements Transformer {
15
+ private options;
16
+ constructor(options?: Partial<GradientOptions>);
17
+ transform(document: DocumentModel): TransformResult;
18
+ }
@@ -0,0 +1,16 @@
1
+ import { DocumentModel } from '../Model/DocumentModel';
2
+ import { Transformer, TransformResult } from './Transformer';
3
+ export interface GrowOptions {
4
+ minSize: number;
5
+ maxSize: number;
6
+ cycles: number;
7
+ selectionRange?: {
8
+ start: number;
9
+ end: number;
10
+ };
11
+ }
12
+ export declare class GrowTransformer implements Transformer {
13
+ private options;
14
+ constructor(options?: Partial<GrowOptions>);
15
+ transform(document: DocumentModel): TransformResult;
16
+ }