@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,23 @@
1
+ import { RedNode } from '../Syntax/RedNode';
2
+ import { BBCodeExporter } from '../Visitors/BBCodeExporter';
3
+ import { HTMLRenderer } from '../Visitors/HTMLRenderer';
4
+ export interface SurgicalEdit {
5
+ start: number;
6
+ end: number;
7
+ text: string;
8
+ }
9
+ export interface ReconcileResult {
10
+ edits: SurgicalEdit[];
11
+ hasChanges: boolean;
12
+ resultingSource: string;
13
+ }
14
+ /**
15
+ * Computes the minimal single-range text edit (common prefix + suffix diff)
16
+ * between two strings, ensuring Monaco only replaces the exact changed characters.
17
+ */
18
+ export declare function computeTextDelta(original: string, updated: string): SurgicalEdit[];
19
+ /**
20
+ * Reconciles the visual DOM of a contenteditable container against the original BBCode document AST.
21
+ * Produces minimal, non-destructive surgical edits preserving untouched BBCode blocks and structure.
22
+ */
23
+ export declare function reconcileVisualDOMToBBCode(originalSource: string, originalAST: RedNode | null, editorContainer: HTMLElement, exporter?: BBCodeExporter, renderer?: HTMLRenderer): ReconcileResult;
@@ -0,0 +1,46 @@
1
+ /**
2
+ * DocumentEngine — RenderPipeline
3
+ *
4
+ * The Render Pipeline transforms a DocumentModel into renderable output.
5
+ * It sits between the model and the view layer.
6
+ *
7
+ * The pipeline is:
8
+ * DocumentModel → RenderTree → HTML/SVG/Canvas/React
9
+ *
10
+ * Plugins can intercept at any stage:
11
+ * - Add/transform render nodes
12
+ * - Provide custom renderers for custom tags
13
+ * - Post-process the output
14
+ */
15
+ import { RedNode } from '../Syntax/RedNode';
16
+ import { type RenderNode, type RenderVariant } from './RenderTree';
17
+ import type { TagRegistry } from '../Model/TagRegistry';
18
+ export type RenderPhase = 'build' | 'transform' | 'serialize';
19
+ export interface RenderHook {
20
+ phase: RenderPhase;
21
+ hook: (node: RenderNode, context: RenderContext) => RenderNode | null;
22
+ }
23
+ export interface RenderContext {
24
+ variant: RenderVariant;
25
+ registry: TagRegistry;
26
+ source: string;
27
+ }
28
+ export declare class RenderPipeline {
29
+ private hooks;
30
+ /**
31
+ * Register a render hook.
32
+ */
33
+ register(hook: RenderHook): void;
34
+ /**
35
+ * Unregister a render hook.
36
+ */
37
+ unregister(hook: RenderHook): void;
38
+ /**
39
+ * Render a RedNode tree to a string.
40
+ */
41
+ render(root: RedNode, variant: RenderVariant | undefined, registry: TagRegistry, source?: string): string;
42
+ /**
43
+ * Build a RenderNode tree from a RedNode tree.
44
+ */
45
+ private buildRenderTree;
46
+ }
@@ -0,0 +1,55 @@
1
+ /**
2
+ * DocumentEngine — RenderTree
3
+ *
4
+ * An intermediate representation between DocumentModel and final output.
5
+ * The RenderTree is what the RenderPipeline processes.
6
+ *
7
+ * This abstraction allows:
8
+ * - Same DocumentModel → multiple render outputs (HTML, Canvas, SVG, PDF)
9
+ * - Plugin renderers that intercept/modify render nodes
10
+ * - Smooth visual transitions between document states
11
+ * - Partial rendering for performance
12
+ */
13
+ import type { NodeKind } from '../Types/core';
14
+ export type RenderVariant = 'html' | 'canvas' | 'svg' | 'pdf' | 'react' | 'text';
15
+ export interface RenderNode {
16
+ /** Semantic kind */
17
+ kind: NodeKind | string;
18
+ /** Text content */
19
+ text: string;
20
+ /** Child render nodes */
21
+ children: RenderNode[];
22
+ /** Props/attributes for the renderer */
23
+ props: Record<string, unknown>;
24
+ /** Which render variant this node targets */
25
+ variant?: RenderVariant;
26
+ /** CSS class names */
27
+ className?: string;
28
+ /** Inline styles */
29
+ style?: Record<string, string | number>;
30
+ /** Events/handlers (for interactive renders) */
31
+ events?: Record<string, string>;
32
+ /** Metadata for renderers */
33
+ metadata?: Record<string, unknown>;
34
+ }
35
+ export declare class RenderTree {
36
+ /**
37
+ * Create a render tree from a document node.
38
+ */
39
+ static fromNode(kind: NodeKind | string, text?: string, children?: RenderNode[], props?: Record<string, unknown>): RenderNode;
40
+ /**
41
+ * Create a text render node.
42
+ */
43
+ static text(content: string): RenderNode;
44
+ /**
45
+ * Create a container render node.
46
+ */
47
+ static container(kind: NodeKind | string, children: RenderNode[], props?: Record<string, unknown>): RenderNode;
48
+ /**
49
+ * Serialize a render tree to HTML.
50
+ */
51
+ static toHTML(node: RenderNode): string;
52
+ private static kindToTag;
53
+ private static propsToHtml;
54
+ private static escapeHtml;
55
+ }
@@ -0,0 +1,4 @@
1
+ export { RenderPipeline } from './RenderPipeline';
2
+ export type { RenderPhase, RenderHook, RenderContext } from './RenderPipeline';
3
+ export { RenderTree } from './RenderTree';
4
+ export type { RenderNode, RenderVariant } from './RenderTree';
@@ -0,0 +1,48 @@
1
+ import { RedNode } from '../Syntax/RedNode';
2
+ import type { SurgicalEdit } from '../Reconciler/SurgicalReconciler';
3
+ /** A closing tag the source never opened, kept by the parser as literal text. */
4
+ export interface OrphanCloser {
5
+ /** The tag name as written, lowercased. */
6
+ tag: string;
7
+ /** Where the `[/tag]` sits in the source. */
8
+ range: {
9
+ start: number;
10
+ end: number;
11
+ };
12
+ }
13
+ /** An opening tag the parser had to close on the author's behalf. */
14
+ export interface UnclosedOpener {
15
+ tag: string;
16
+ /** Where its `[/tag]` belongs. */
17
+ at: number;
18
+ }
19
+ export interface NestingRepair {
20
+ /** Deletions for the orphans and insertions for the missing closers. */
21
+ edits: SurgicalEdit[];
22
+ orphans: OrphanCloser[];
23
+ unclosed: UnclosedOpener[];
24
+ /** The repaired source, for callers that want it whole. */
25
+ source: string;
26
+ hasChanges: boolean;
27
+ }
28
+ /**
29
+ * Repairs BBCode nesting without touching a byte the author wrote elsewhere.
30
+ *
31
+ * Two kinds of damage, two kinds of edit:
32
+ *
33
+ * - a closing tag with no opener is deleted, because that is what osu! does
34
+ * with it — Quasar renders it as literal text, which is the one place the
35
+ * two disagree (see `Tests/OsuNestingFidelity.test.ts`);
36
+ * - an opener the parser had to close silently gets its `[/tag]` written in,
37
+ * at the offset the parser already chose.
38
+ *
39
+ * Crossed tags need no rule of their own. `[a][b]x[/a][/b]` already parses to
40
+ * the same tree as `[a][b]x[/b][/a]`; removing the leftover `[/b]` is all the
41
+ * repair it takes.
42
+ *
43
+ * Deliberately *not* an export of the tree. Round-tripping through
44
+ * `BBCodeExporter` also yields balanced BBCode, but it rewrites the whole
45
+ * document — re-spelling attributes, collapsing spacing — and none of that is
46
+ * a change the author asked for. Edits keep the blast radius at the damage.
47
+ */
48
+ export declare function repairNesting(source: string, root: RedNode | null): NestingRepair;
@@ -0,0 +1 @@
1
+ export { repairNesting, type NestingRepair, type OrphanCloser, type UnclosedOpener } from './NestingRepair';
@@ -0,0 +1,321 @@
1
+ /**
2
+ * DocumentEngine — SemanticAnalyzer
3
+ *
4
+ * Walks the Red Tree and produces diagnostics by applying
5
+ * semantic rules to the syntax tree.
6
+ *
7
+ * This is where language-specific validation happens.
8
+ * The analyzer is extensible via registered validators.
9
+ *
10
+ * Inspired by Roslyn's Semantic Model and LSP diagnostics.
11
+ */
12
+ import { RedNode } from '../Syntax/RedNode';
13
+ import { type BBCodeDialect } from '../BBCode/BBCodeToGreenNode';
14
+ import type { Diagnostic, DiagnosticSeverity, DiagnosticCollection } from '../Types/diagnostics';
15
+ import { type CollapsibleGradient } from '../Analysis/Passes/Analysis/GradientAnalyzer';
16
+ import type { SourceSpan } from '../Incremental/IncrementalParser';
17
+ import { type TokenResolverFn, type TokenSource } from '../Tokens';
18
+ export interface Validator {
19
+ /** Unique code for this validator (e.g. 'invalid-color') */
20
+ code: string;
21
+ /** Severity of issues found by this validator */
22
+ severity: DiagnosticSeverity;
23
+ /**
24
+ * Node kinds this validator can ever fire on. Omit to run on every node.
25
+ *
26
+ * Three of the five built-ins open with nothing but a kind test, so on a
27
+ * document of 1736 nodes they were called 1736 times each to answer a
28
+ * question the dispatcher can answer once. Declaring the kinds turns the
29
+ * call into a lookup that never happens.
30
+ */
31
+ kinds?: readonly string[];
32
+ /**
33
+ * What a verdict on one node depends on. Default `'node'`.
34
+ *
35
+ * `'node'`: the node itself, its ancestors, its own source span, and the
36
+ * document-scope maps on the context (`crossings`, `unknownTags`,
37
+ * `orphanClosers`, `collapsibleGradients`) — everything the incremental
38
+ * analysis knows how to keep current. Every built-in is `'node'`-scoped.
39
+ *
40
+ * `'document'`: anything else — counting headings, comparing a node with
41
+ * an unrelated one, reading `allNodes`. A verdict like that can change for
42
+ * a node the edit never touched, which the window pass cannot see, so
43
+ * registering one turns every analysis into a full pass until it is
44
+ * unregistered. Reading `allNodes` from a `'node'`-scoped validator is
45
+ * treated the same way, at runtime.
46
+ */
47
+ scope?: 'node' | 'document';
48
+ /** Validate a node. Return diagnostics or null */
49
+ validate(node: RedNode, context: AnalyzerContext): Diagnostic | Diagnostic[] | null;
50
+ }
51
+ export interface AnalyzerContext {
52
+ /**
53
+ * Every node in the tree, by id, for cross-reference validation.
54
+ *
55
+ * A getter, and deliberately: building this Map cost a second full walk of
56
+ * the tree plus 1736 `Map.set` calls — 23% of `analyze()` — and **no
57
+ * validator has ever read it**. It was built so that the caller could look up
58
+ * by id the node to attach each diagnostic to, which is the node the
59
+ * validator was looking at when it produced it. Validators that genuinely
60
+ * need cross-references still get it; everyone else stops paying for it.
61
+ */
62
+ readonly allNodes: Map<string, RedNode>;
63
+ /**
64
+ * Openers whose `[/tag]` does exist but arrived too late, keyed by the
65
+ * opener's node id.
66
+ *
67
+ * A getter for the same reason `allNodes` is one, and asked for even more
68
+ * rarely: the only way to reach it is through a node that is already known
69
+ * to be unclosed, which on a healthy document never happens. Both validators
70
+ * that read it test `isUnclosedTag` first, so a document with no auto-closed
71
+ * tag never pays for the walk.
72
+ */
73
+ readonly crossings: ReadonlyMap<string, CrossedTags>;
74
+ /**
75
+ * Unknown tags that were written as a PAIR, keyed by the opener's node id.
76
+ *
77
+ * Same lazy contract as `crossings`, and reached through an even tighter
78
+ * gate: only a text leaf whose first and last characters are brackets can
79
+ * be in it, which is three integer compares per text node.
80
+ */
81
+ readonly unknownTags: ReadonlyMap<string, UnknownTag>;
82
+ /**
83
+ * Closing tags no opener claims, node id → tag name.
84
+ *
85
+ * Same walk as `unknownTags`, cached together, because the two answers are
86
+ * two halves of one pairing: what is left over after every unknown opener
87
+ * has taken its closer is a `[/tag]` that closes nothing.
88
+ */
89
+ readonly orphanClosers: ReadonlyMap<string, string>;
90
+ /** Sequences of [color] tags that form a gradient, keyed by the first node's id */
91
+ readonly collapsibleGradients: ReadonlyMap<string, CollapsibleGradient>;
92
+ /** Previously collected diagnostics */
93
+ diagnostics: DiagnosticCollection;
94
+ /** Source text for position lookups */
95
+ source: string;
96
+ }
97
+ /**
98
+ * How much of the tree a pass looked at.
99
+ *
100
+ * `'full'` — every node was validated afresh. `'window'` — only the nodes an
101
+ * edit could have changed were: the ones inside the reparse window, the
102
+ * ancestors on the path down to it, and any node elsewhere whose
103
+ * document-scope facts (a pairing, a crossing, a colour run) the edit
104
+ * altered. The diagnostics are complete and identical either way; the scope
105
+ * says how they were obtained.
106
+ */
107
+ export type AnalyzeScope = 'full' | 'window';
108
+ export interface AnalyzeResult {
109
+ diagnostics: DiagnosticCollection;
110
+ /** Time taken in ms */
111
+ duration: number;
112
+ /** Number of nodes analyzed */
113
+ nodesAnalyzed: number;
114
+ /** See {@link AnalyzeScope}. */
115
+ scope: AnalyzeScope;
116
+ /** The span re-validated by a `'window'` pass; `null` for a full one. */
117
+ window: SourceSpan | null;
118
+ }
119
+ /**
120
+ * What `analyze()` actually returns: an {@link AnalyzeResult} plus the node
121
+ * index it had to build anyway for cross-reference lookups.
122
+ *
123
+ * Kept as a separate type, and deliberately NOT part of `AnalyzeResult`,
124
+ * because the index holds a strong reference to every node in the tree. A
125
+ * caller that stores an `AnalyzeResult` long-term (as `DocumentModel` does)
126
+ * must not pin an entire stale tree; one that needs the index gets it here and
127
+ * owns that decision explicitly.
128
+ */
129
+ export interface IndexedAnalyzeResult extends AnalyzeResult {
130
+ allNodes: Map<string, RedNode>;
131
+ }
132
+ /**
133
+ * Whether the parser had to close this tag itself because the author never did.
134
+ *
135
+ * Exact, not heuristic. A tag the author closed ends exactly at its own
136
+ * `[/tag]`, because that is where the parser sets the node's end. A tag closed
137
+ * *for* the author ends wherever the parser gave up — at the end of the
138
+ * document, or at the mismatched `[/other]` that forced the issue — and the
139
+ * text up to that point does not end in its closing form.
140
+ *
141
+ * That single rule covers both shapes: `[b]x` (never closed) and `[b][i]x[/b]`
142
+ * (where `[i]` is auto-closed by the legacy nesting rules).
143
+ */
144
+ export declare function isUnclosedTag(node: RedNode, source: string): boolean;
145
+ /**
146
+ * An opener the parser closed on the author's behalf, together with the
147
+ * `[/tag]` the author *did* write — just too late for it to count.
148
+ */
149
+ export interface CrossedTags {
150
+ /** The tag name as written, lowercased. */
151
+ tag: string;
152
+ /** Where its closing tag belongs: the offset the parser already closed it at. */
153
+ at: number;
154
+ /** Where the ignored `[/tag]` sits in the source. */
155
+ closer: {
156
+ start: number;
157
+ end: number;
158
+ };
159
+ }
160
+ /**
161
+ * The tag name as the author actually spelled it, read back from the source.
162
+ *
163
+ * The tree cannot answer this. Several spellings collapse onto one `NodeKind`
164
+ * — `[strike]` and `[s]` both become `strikethrough` — and a node's `text`
165
+ * holds its attributes, not its name. A node's range does start at the opening
166
+ * bracket, so the name is the identifier immediately after it.
167
+ *
168
+ * Returns null for nodes that do not correspond to a written tag.
169
+ */
170
+ export declare function openingTagName(node: RedNode, source: string): string | null;
171
+ /**
172
+ * The span of the *name* inside this node's closing tag, or null if the author
173
+ * never wrote one.
174
+ *
175
+ * A rename has to touch both ends: rewriting only the opening `[strike]` to
176
+ * `[s]` leaves an orphan `[/strike]` that osu! renders as literal text — worse
177
+ * than the deprecation it was fixing. The name sits between `[/` and `]`, so it
178
+ * ends one character before the node and runs back its own length.
179
+ */
180
+ export declare function closingTagNameRange(node: RedNode, source: string, name: string): {
181
+ start: number;
182
+ end: number;
183
+ } | null;
184
+ /**
185
+ * An unknown tag the author wrote as a pair: `[bold]x[/bold]`.
186
+ *
187
+ * The pairing is the whole signal. An unknown tag becomes literal text on
188
+ * purpose — `[Gateron]` in prose has to stay visible, and a real corpus of 53
189
+ * userpages carries `[gb]`, `[insane]`, `[rm120]` and a dozen more of those —
190
+ * so a bare `[name]` is not evidence of anything. A `[name]` with a matching
191
+ * `[/name]` is: nobody closes a bracketed aside. That same corpus contains
192
+ * exactly ZERO of them, which is the false-positive budget this rule spends.
193
+ */
194
+ export interface UnknownTag {
195
+ /** The name as written, lowercased. */
196
+ tag: string;
197
+ /** The `[tag]` the parser refused, kept as literal text. */
198
+ opener: {
199
+ start: number;
200
+ end: number;
201
+ };
202
+ /** Its `[/tag]` — what makes this a misspelling rather than prose. */
203
+ closer: {
204
+ start: number;
205
+ end: number;
206
+ };
207
+ }
208
+ export interface SemanticAnalyzerOptions {
209
+ dialect?: BBCodeDialect;
210
+ tokens?: TokenSource;
211
+ }
212
+ export declare class SemanticAnalyzer {
213
+ private validators;
214
+ /**
215
+ * The same validators, arranged for the walk instead of for lookup.
216
+ *
217
+ * `_always` run on every node; `_byKind` are the ones that declared their
218
+ * kinds. Iterating the Map itself allocated an iterator and a destructuring
219
+ * pair per node — 9% of `analyze()` spent on bookkeeping, not on validating.
220
+ *
221
+ * Rebuilt on register/unregister, which happen once at construction and
222
+ * essentially never afterwards.
223
+ */
224
+ private _always;
225
+ private _byKind;
226
+ /** Set by register/unregister; cleared by the next `rebuildDispatch`. */
227
+ private _dispatchDirty;
228
+ /**
229
+ * The dialect this analyzer validates against.
230
+ *
231
+ * Only the suggestion for an unknown tag reads it — detection never needs a
232
+ * name list, because the parser already refused the tag. `DocumentModel`
233
+ * builds the analyzer before a subclass knows its dialect, so this is set
234
+ * afterwards rather than taken by the constructor.
235
+ */
236
+ dialect: BBCodeDialect;
237
+ private _tokens?;
238
+ private _tokenResolver?;
239
+ private _validatorsVersion;
240
+ private _tokensVersion;
241
+ private _snapshot;
242
+ get tokens(): TokenSource | undefined;
243
+ set tokens(val: TokenSource | undefined);
244
+ get tokenResolver(): TokenResolverFn | undefined;
245
+ setTokens(tokens?: TokenSource): void;
246
+ constructor(options?: SemanticAnalyzerOptions | BBCodeDialect);
247
+ /**
248
+ * Register a validator.
249
+ */
250
+ register(validator: Validator): void;
251
+ /**
252
+ * Remove a validator.
253
+ */
254
+ unregister(code: string): void;
255
+ /** Whether any registered validator declared `'document'` scope. */
256
+ private hasDocumentScopedValidator;
257
+ /**
258
+ * Rebuild the kind buckets, unless they are already current.
259
+ *
260
+ * `register` used to rebuild them itself, so constructing an analyzer —
261
+ * which registers thirteen built-ins — rebuilt the whole table thirteen
262
+ * times and threw away the first twelve. A plugin registering a batch paid
263
+ * the same way. Registration now only marks the table stale and `analyze`
264
+ * rebuilds it at most once, whatever the batch size.
265
+ */
266
+ private rebuildDispatch;
267
+ /**
268
+ * Analyze a Red Tree and produce diagnostics — every node, from scratch.
269
+ *
270
+ * Also the base a later {@link analyzeWindow} builds on: the pass remembers
271
+ * which nodes carry diagnostics and which ones feed the document-scope
272
+ * maps, so the next edit can re-validate its window alone.
273
+ */
274
+ analyze(root: RedNode, source: string, tokensOrOptions?: TokenSource | {
275
+ tokens?: TokenSource;
276
+ }): IndexedAnalyzeResult;
277
+ /**
278
+ * Re-validate only what an edit could have changed, on top of the previous
279
+ * pass over this analyzer.
280
+ *
281
+ * `root` must be the tree the previous pass's root turned into through
282
+ * incremental reparses WITH red-subtree reuse — that is what makes every
283
+ * node outside `window` (the union of those reparses' windows, carried
284
+ * into `root`'s coordinates) the same object over the same text. The
285
+ * `DocumentModel` tracks exactly that and calls this only when it holds;
286
+ * anyone else should prefer `DocumentModel.analyzeIncremental`.
287
+ *
288
+ * Returns `null` when no window pass can be trusted: there is no previous
289
+ * pass, the validators or the tokens changed since it, or a validator with
290
+ * document scope is registered (see `Validator.scope`). The caller runs a
291
+ * full `analyze` then. The result's diagnostics are complete — the whole
292
+ * document's, identical to what a full pass would produce — and come out
293
+ * in document order like a full pass's do.
294
+ *
295
+ * What happens, in order:
296
+ * 1. descend the window (see `descendWindow`), collecting its candidates;
297
+ * 2. keep every previous candidate outside it that is still in the tree,
298
+ * at its current offsets; derive the maps from kept plus fresh;
299
+ * 3. diff the maps against the previous ones for nodes outside the
300
+ * window, and mark the nodes whose entry changed for re-validation;
301
+ * 4. move the kept diagnostics of displaced nodes by their displacement;
302
+ * 5. validate the window nodes and the marked ones;
303
+ * 6. assemble the collection from every diagnostic-bearing node.
304
+ */
305
+ analyzeWindow(root: RedNode, source: string, window: SourceSpan): IndexedAnalyzeResult | null;
306
+ /**
307
+ * The context validators see. The maps are ready-made; `allNodes` is
308
+ * built on demand and, being the one cross-document index a validator can
309
+ * reach without declaring itself, its use is recorded (see
310
+ * `Validator.scope`).
311
+ */
312
+ private makeContext;
313
+ /** Run every applicable validator over `nodes`, in order. */
314
+ private validateNodes;
315
+ private registerBuiltinValidators;
316
+ /**
317
+ * Create a validator for a specific tag/kind.
318
+ * Convenience method for plugin authors.
319
+ */
320
+ createValidator(code: string, severity: DiagnosticSeverity, predicate: (node: RedNode, ctx: AnalyzerContext) => string | null): Validator;
321
+ }
@@ -0,0 +1,2 @@
1
+ export { SemanticAnalyzer } from './SemanticAnalyzer';
2
+ export type { Validator, AnalyzerContext, AnalyzeResult } from './SemanticAnalyzer';
@@ -0,0 +1,47 @@
1
+ /**
2
+ * DocumentEngine — SymbolTable
3
+ *
4
+ * Tracks symbols (definitions and references) in the document.
5
+ * Enables IDE features like:
6
+ * - Go to definition
7
+ * - Find all references
8
+ * - Rename symbol
9
+ * - Document outline
10
+ *
11
+ * In BBCode, symbols include:
12
+ * - [id=hero] → Definition
13
+ * - [goto=hero] → Reference
14
+ * - Named anchors and targets
15
+ */
16
+ import { RedNode } from '../Syntax/RedNode';
17
+ import type { SymbolInfo, SymbolSearchResult } from '../Types/symbols';
18
+ export declare class SymbolTable {
19
+ private symbols;
20
+ private nodeToSymbolId;
21
+ /**
22
+ * Build the symbol table from a RedNode tree.
23
+ */
24
+ build(root: RedNode): void;
25
+ /**
26
+ * Get a symbol by name.
27
+ */
28
+ get(name: string): SymbolInfo | undefined;
29
+ /**
30
+ * Get the symbol associated with a node.
31
+ */
32
+ getSymbolForNode(nodeId: string): SymbolInfo | undefined;
33
+ /**
34
+ * Search for symbols by name.
35
+ */
36
+ search(query: string, maxResults?: number): SymbolSearchResult[];
37
+ /**
38
+ * Get all symbols.
39
+ */
40
+ getAll(): SymbolInfo[];
41
+ /**
42
+ * Clear all symbols.
43
+ */
44
+ clear(): void;
45
+ private addSymbol;
46
+ private createSymbolId;
47
+ }
@@ -0,0 +1 @@
1
+ export { SymbolTable } from './SymbolTable';