@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.
- package/dist/Visuals/lyne.css +117 -6
- package/dist/Visuals/osu.css +36 -5
- package/dist/index.js +9664 -3282
- package/dist/index.mjs +9535 -3283
- package/dist/types/Analysis/Contracts/AnalysisReport.d.ts +22 -0
- package/dist/types/Analysis/Contracts/Contribution.d.ts +68 -0
- package/dist/types/Analysis/Contracts/Pass.d.ts +59 -0
- package/dist/types/Analysis/Contracts/PipelineContext.d.ts +34 -0
- package/dist/types/Analysis/Passes/Analysis/ColorUsageAnalyzer.d.ts +56 -0
- package/dist/types/Analysis/Passes/Analysis/GradientAnalyzer.d.ts +111 -0
- package/dist/types/Analysis/Passes/Analysis/MergeableColorAnalyzer.d.ts +26 -0
- package/dist/types/Analysis/Passes/Analysis/RainbowAnalyzer.d.ts +47 -0
- package/dist/types/Analysis/Passes/Analysis/SymbolAnalyzer.d.ts +89 -0
- package/dist/types/Analysis/Passes/Analysis/WaveAnalyzer.d.ts +44 -0
- package/dist/types/Analysis/Passes/Analysis/__tests__/GradientAnalyzer.test.d.ts +4 -0
- package/dist/types/Analysis/Passes/Analysis/__tests__/MergeableColorAnalyzer.test.d.ts +4 -0
- package/dist/types/Analysis/Passes/Analysis/__tests__/RainbowAnalyzer.test.d.ts +4 -0
- package/dist/types/Analysis/Passes/Analysis/__tests__/WaveAnalyzer.test.d.ts +4 -0
- package/dist/types/Analysis/Passes/Decision/DefaultDecision.d.ts +30 -0
- package/dist/types/Analysis/Passes/Decision/PaletteRemapDecision.d.ts +169 -0
- package/dist/types/Analysis/Passes/Decision/__tests__/DefaultDecision.test.d.ts +4 -0
- package/dist/types/Analysis/Passes/Transform/CollapseGradientTransform.d.ts +37 -0
- package/dist/types/Analysis/Passes/Transform/MergeColorsTransform.d.ts +28 -0
- package/dist/types/Analysis/Passes/Transform/RainbowCollapseTransform.d.ts +19 -0
- package/dist/types/Analysis/Passes/Transform/WaveCollapseTransform.d.ts +20 -0
- package/dist/types/Analysis/Passes/Utility/CharacterCountAnalyzer.d.ts +19 -0
- package/dist/types/Analysis/Pipeline/Pipeline.d.ts +69 -0
- package/dist/types/Analysis/Pipeline/PipelineBuilder.d.ts +31 -0
- package/dist/types/Analysis/Pipeline/PipelineStage.d.ts +17 -0
- package/dist/types/Analysis/Utils/color-utils.d.ts +60 -0
- package/dist/types/Analysis/__tests__/Integration.test.d.ts +8 -0
- package/dist/types/Analysis/__tests__/PaletteRemap.test.d.ts +14 -0
- package/dist/types/Analysis/__tests__/Pipeline.test.d.ts +10 -0
- package/dist/types/Analysis/__tests__/RoundTrip.test.d.ts +30 -0
- package/dist/types/Analysis/__tests__/SymbolAnalyzer.test.d.ts +11 -0
- package/dist/types/Analysis/index.d.ts +40 -0
- package/dist/types/BBCode/BBCodeDocumentModel.d.ts +92 -0
- package/dist/types/BBCode/BBCodeToGreenNode.d.ts +111 -0
- package/dist/types/BBCode/Parser.d.ts +78 -0
- package/dist/types/BBCode/index.d.ts +4 -0
- package/dist/types/Collab/positions.d.ts +55 -0
- package/dist/types/Commands/Command.d.ts +37 -0
- package/dist/types/Commands/CommandRegistry.d.ts +48 -0
- package/dist/types/Commands/DeleteNode.d.ts +7 -0
- package/dist/types/Commands/InsertText.d.ts +8 -0
- package/dist/types/Commands/SplitMerge.d.ts +9 -0
- package/dist/types/Commands/WrapInTag.d.ts +8 -0
- package/dist/types/Commands/index.d.ts +6 -0
- package/dist/types/Diff/TreeDiffer.d.ts +52 -0
- package/dist/types/Diff/__tests__/TreeDiffer.test.d.ts +1 -0
- package/dist/types/Diff/index.d.ts +2 -0
- package/dist/types/Edits/EditPlan.d.ts +144 -0
- package/dist/types/Edits/Optimizer.d.ts +78 -0
- package/dist/types/Edits/Rules/Rule.d.ts +91 -0
- package/dist/types/Edits/Rules/dropEmptyTags.d.ts +40 -0
- package/dist/types/Edits/Rules/dropRedundantNesting.d.ts +59 -0
- package/dist/types/Edits/Rules/index.d.ts +9 -0
- package/dist/types/Edits/Rules/mergeAdjacent.d.ts +93 -0
- package/dist/types/Edits/Rules/reorderWrappers.d.ts +42 -0
- package/dist/types/Edits/Rules/shortenHex.d.ts +30 -0
- package/dist/types/Edits/Rules/tagValue.d.ts +56 -0
- package/dist/types/Edits/Rules/unwrapInvisibleColor.d.ts +47 -0
- package/dist/types/Edits/applyEdits.d.ts +36 -0
- package/dist/types/Edits/index.d.ts +6 -0
- package/dist/types/Events/EventBus.d.ts +103 -0
- package/dist/types/Events/index.d.ts +2 -0
- package/dist/types/Formatter/Formatter.d.ts +32 -0
- package/dist/types/Formatter/index.d.ts +2 -0
- package/dist/types/HTML/HTMLDocumentModel.d.ts +13 -0
- package/dist/types/HTML/HTMLToGreenNode.d.ts +4 -0
- package/dist/types/Incremental/BracketIndex.d.ts +101 -0
- package/dist/types/Incremental/ChangeTracker.d.ts +69 -0
- package/dist/types/Incremental/IncrementalParser.d.ts +246 -0
- package/dist/types/Incremental/__tests__/BracketIndex.test.d.ts +1 -0
- package/dist/types/Incremental/__tests__/IncrementalParser.test.d.ts +1 -0
- package/dist/types/Incremental/index.d.ts +4 -0
- package/dist/types/Lexer/BBCodeLexer.d.ts +74 -0
- package/dist/types/Lexer/Lexer.d.ts +54 -0
- package/dist/types/Lexer/index.d.ts +4 -0
- package/dist/types/Linter/Linter.d.ts +58 -0
- package/dist/types/Linter/index.d.ts +2 -0
- package/dist/types/Markdown/MarkdownAST.d.ts +122 -0
- package/dist/types/Markdown/MarkdownDocumentModel.d.ts +15 -0
- package/dist/types/Markdown/MarkdownLexer.d.ts +155 -0
- package/dist/types/Markdown/MarkdownParser.d.ts +42 -0
- package/dist/types/Markdown/MarkdownToGreenNode.d.ts +6 -0
- package/dist/types/MilHibri/MilHibriDocumentModel.d.ts +21 -0
- package/dist/types/Model/DocumentModel.d.ts +318 -0
- package/dist/types/Model/NodeFactory.d.ts +29 -0
- package/dist/types/Model/TagRegistry.d.ts +165 -0
- package/dist/types/Model/index.d.ts +5 -0
- package/dist/types/Plugins/PluginAPI.d.ts +44 -0
- package/dist/types/Plugins/PluginRegistry.d.ts +81 -0
- package/dist/types/Plugins/index.d.ts +3 -0
- package/dist/types/Queries/QueryEngine.d.ts +32 -0
- package/dist/types/Queries/index.d.ts +1 -0
- package/dist/types/Reconciler/SurgicalReconciler.d.ts +23 -0
- package/dist/types/RenderPipeline/RenderPipeline.d.ts +46 -0
- package/dist/types/RenderPipeline/RenderTree.d.ts +55 -0
- package/dist/types/RenderPipeline/index.d.ts +4 -0
- package/dist/types/Repair/NestingRepair.d.ts +48 -0
- package/dist/types/Repair/index.d.ts +1 -0
- package/dist/types/Semantic/SemanticAnalyzer.d.ts +321 -0
- package/dist/types/Semantic/index.d.ts +2 -0
- package/dist/types/Symbols/SymbolTable.d.ts +47 -0
- package/dist/types/Symbols/index.d.ts +1 -0
- package/dist/types/Syntax/GreenNode.d.ts +154 -0
- package/dist/types/Syntax/GreenNodePool.d.ts +134 -0
- package/dist/types/Syntax/NodeMatcher.d.ts +75 -0
- package/dist/types/Syntax/RedNode.d.ts +280 -0
- package/dist/types/Syntax/RedNodeStore.d.ts +116 -0
- package/dist/types/Syntax/TreeBuilder.d.ts +54 -0
- package/dist/types/Syntax/__tests__/GreenNode.test.d.ts +1 -0
- package/dist/types/Syntax/__tests__/RedNode.test.d.ts +1 -0
- package/dist/types/Syntax/__tests__/RedNodeStore.test.d.ts +1 -0
- package/dist/types/Syntax/greenEdit.d.ts +64 -0
- package/dist/types/Syntax/hash.d.ts +17 -0
- package/dist/types/Syntax/index.d.ts +8 -0
- package/dist/types/Syntax/nodeAttr.d.ts +63 -0
- package/dist/types/Syntax/partition.d.ts +67 -0
- package/dist/types/Syntax/preserveNodeIds.d.ts +47 -0
- package/dist/types/Tokens/TokenResolver.d.ts +25 -0
- package/dist/types/Tokens/index.d.ts +1 -0
- package/dist/types/Transactions/Transaction.d.ts +36 -0
- package/dist/types/Transactions/UndoManager.d.ts +63 -0
- package/dist/types/Transactions/index.d.ts +3 -0
- package/dist/types/Transformers/ASTOptimizer.d.ts +34 -0
- package/dist/types/Transformers/GradientTransformer.d.ts +18 -0
- package/dist/types/Transformers/GrowTransformer.d.ts +16 -0
- package/dist/types/Transformers/RainbowTransformer.d.ts +17 -0
- package/dist/types/Transformers/SineWaveTransformer.d.ts +17 -0
- package/dist/types/Transformers/Transformer.d.ts +17 -0
- package/dist/types/Types/core.d.ts +104 -0
- package/dist/types/Types/diagnostics.d.ts +85 -0
- package/dist/types/Types/index.d.ts +11 -0
- package/dist/types/Types/operations.d.ts +109 -0
- package/dist/types/Types/queries.d.ts +67 -0
- package/dist/types/Types/symbols.d.ts +42 -0
- package/dist/types/Types/tokens.d.ts +75 -0
- package/dist/types/Utils/BBCodeGenerator.d.ts +21 -0
- package/dist/types/Utils/ColorMath.d.ts +92 -0
- package/dist/types/Utils/EffectMath.d.ts +643 -0
- package/dist/types/Utils/TagVocabulary.d.ts +104 -0
- package/dist/types/Utils/TagVocabulary.test.d.ts +1 -0
- package/dist/types/Utils/color.d.ts +29 -0
- package/dist/types/Utils/dom-to-svg.d.ts +28 -0
- package/dist/types/Utils/dom-to-svg.test.d.ts +1 -0
- package/dist/types/Utils/treeTransformers.d.ts +160 -0
- package/dist/types/Visitors/BBBlocksExporter.d.ts +27 -0
- package/dist/types/Visitors/BBCodeExporter.d.ts +90 -0
- package/dist/types/Visitors/BlockPatcher.d.ts +91 -0
- package/dist/types/Visitors/DOMMorpher.d.ts +13 -0
- package/dist/types/Visitors/HTMLRenderer.d.ts +380 -0
- package/dist/types/Visitors/JSONExporter.d.ts +42 -0
- package/dist/types/Visitors/MarkdownExporter.d.ts +28 -0
- package/dist/types/Visitors/SVGRenderer.d.ts +16 -0
- package/dist/types/Visitors/TiptapExporter.d.ts +40 -0
- package/dist/types/Visitors/Visitor.d.ts +35 -0
- package/dist/types/Visitors/index.d.ts +9 -0
- package/dist/types/Visuals/BoxDrawer.d.ts +49 -0
- package/dist/types/Visuals/index.d.ts +38 -0
- package/dist/types/index.d.ts +154 -0
- package/package.json +14 -10
- package/src/Analysis/Passes/Analysis/ColorUsageAnalyzer.ts +103 -0
- package/src/Analysis/Passes/Analysis/GradientAnalyzer.ts +294 -20
- package/src/Analysis/Passes/Analysis/SymbolAnalyzer.ts +257 -0
- package/src/Analysis/Passes/Decision/PaletteRemapDecision.ts +425 -0
- package/src/Analysis/Pipeline/Pipeline.ts +15 -2
- package/src/Analysis/index.ts +8 -2
- package/src/BBCode/BBCodeDocumentModel.ts +3 -0
- package/src/BBCode/BBCodeToGreenNode.ts +18 -12
- package/src/BBCode/Parser.ts +38 -1
- package/src/Edits/EditPlan.ts +290 -0
- package/src/Edits/Optimizer.ts +185 -0
- package/src/Edits/Rules/Rule.ts +145 -0
- package/src/Edits/Rules/dropEmptyTags.ts +110 -0
- package/src/Edits/Rules/dropRedundantNesting.ts +120 -0
- package/src/Edits/Rules/index.ts +28 -0
- package/src/Edits/Rules/mergeAdjacent.ts +224 -0
- package/src/Edits/Rules/reorderWrappers.ts +154 -0
- package/src/Edits/Rules/shortenHex.ts +79 -0
- package/src/Edits/Rules/tagValue.ts +105 -0
- package/src/Edits/Rules/unwrapInvisibleColor.ts +93 -0
- package/src/Edits/applyEdits.ts +54 -0
- package/src/Edits/index.ts +22 -0
- package/src/Events/EventBus.ts +18 -0
- package/src/HTML/HTMLToGreenNode.ts +185 -37
- package/src/Incremental/BracketIndex.ts +249 -0
- package/src/Incremental/IncrementalParser.ts +464 -41
- package/src/Lexer/BBCodeLexer.ts +25 -3
- package/src/Lexer/index.ts +1 -1
- package/src/Markdown/MarkdownAST.ts +65 -2
- package/src/Markdown/MarkdownLexer.ts +69 -14
- package/src/Markdown/MarkdownParser.ts +749 -62
- package/src/Markdown/MarkdownToGreenNode.ts +148 -27
- package/src/MilHibri/MilHibriDocumentModel.ts +56 -0
- package/src/Model/DocumentModel.ts +138 -5
- package/src/Model/TagRegistry.ts +129 -134
- package/src/Reconciler/SurgicalReconciler.ts +460 -0
- package/src/Repair/NestingRepair.ts +116 -0
- package/src/Repair/index.ts +1 -0
- package/src/Semantic/SemanticAnalyzer.ts +1802 -65
- package/src/Syntax/GreenNodePool.ts +12 -12
- package/src/Syntax/RedNode.ts +17 -3
- package/src/Syntax/RedNodeStore.ts +9 -1
- package/src/Syntax/nodeAttr.ts +172 -0
- package/src/Tokens/TokenResolver.ts +55 -0
- package/src/Tokens/index.ts +1 -0
- package/src/Types/core.ts +15 -0
- package/src/Utils/ColorMath.ts +276 -55
- package/src/Utils/EffectMath.ts +2462 -0
- package/src/Utils/TagVocabulary.ts +141 -0
- package/src/Utils/dom-to-svg.ts +28 -12
- package/src/Visitors/BBBlocksExporter.ts +15 -1
- package/src/Visitors/BBCodeExporter.ts +319 -32
- package/src/Visitors/BlockPatcher.ts +87 -11
- package/src/Visitors/DOMMorpher.ts +15 -5
- package/src/Visitors/HTMLRenderer.ts +374 -151
- package/src/Visitors/MarkdownExporter.ts +98 -41
- package/src/Visitors/TiptapExporter.ts +1 -0
- package/src/Visuals/index.ts +7 -4
- package/src/Visuals/lyne.css +117 -6
- package/src/Visuals/osu.css +36 -5
- package/src/index.ts +172 -5
- package/dist/index.d.mts +0 -4612
- package/dist/index.d.ts +0 -4612
- package/src/Analysis/Passes/Analysis/__tests__/GradientAnalyzer.test.ts +0 -135
- package/src/Analysis/Passes/Analysis/__tests__/MergeableColorAnalyzer.test.ts +0 -84
- package/src/Analysis/Passes/Analysis/__tests__/RainbowAnalyzer.test.ts +0 -99
- package/src/Analysis/Passes/Analysis/__tests__/WaveAnalyzer.test.ts +0 -119
- package/src/Analysis/Passes/Decision/__tests__/DefaultDecision.test.ts +0 -179
- package/src/Analysis/__tests__/Integration.test.ts +0 -162
- package/src/Analysis/__tests__/Pipeline.test.ts +0 -133
- package/src/Diff/__tests__/TreeDiffer.test.ts +0 -65
- package/src/Incremental/__tests__/IncrementalParser.test.ts +0 -164
- package/src/Syntax/__tests__/GreenNode.test.ts +0 -33
- package/src/Syntax/__tests__/RedNode.test.ts +0 -81
- package/src/Syntax/__tests__/RedNodeStore.test.ts +0 -104
- package/src/Tests/ASTOptimizerIdempotence.test.ts +0 -77
- package/src/Tests/BlockPatcher.test.ts +0 -437
- package/src/Tests/BlockPatcherWindowed.test.ts +0 -364
- package/src/Tests/BoxDrawer.test.ts +0 -217
- package/src/Tests/BoxRichTitle.test.ts +0 -105
- package/src/Tests/Chars500kBenchmark.test.ts +0 -151
- package/src/Tests/Chars500kEdits.test.ts +0 -321
- package/src/Tests/CollabPositions.test.ts +0 -146
- package/src/Tests/CompilerPathProfiling.test.ts +0 -186
- package/src/Tests/DOMMorpher.test.ts +0 -142
- package/src/Tests/DomPatchPerf.test.ts +0 -60
- package/src/Tests/EffectSegments.snapshot.json +0 -616
- package/src/Tests/EffectSegments.test.ts +0 -68
- package/src/Tests/FindNodeAtOffset.test.ts +0 -65
- package/src/Tests/Fuzzer.test.ts +0 -166
- package/src/Tests/GreenNodePool.test.ts +0 -153
- package/src/Tests/Lexer.test.ts +0 -238
- package/src/Tests/LyneMode.test.ts +0 -291
- package/src/Tests/ModelCoherence.test.ts +0 -180
- package/src/Tests/Partition.test.ts +0 -238
- package/src/Tests/PluginTags.test.ts +0 -150
- package/src/Tests/ProblematicSection.test.ts +0 -46
- package/src/Tests/ProblematicSectionHTML.test.ts +0 -58
- package/src/Tests/RedReuse.test.ts +0 -134
- package/src/Tests/ReproDelete20k.test.ts +0 -62
- package/src/Tests/SemanticValidators.test.ts +0 -136
- package/src/Tests/StableNodeIds.test.ts +0 -210
- package/src/Tests/StudioColorBloat.test.ts +0 -25
- package/src/Tests/StudioDebugText.test.ts +0 -27
- package/src/Tests/StudioTrailingChar.test.ts +0 -25
- package/src/Tests/StudioValidText.test.ts +0 -25
- package/src/Tests/UrlImgBug.test.ts +0 -23
- package/src/Tests/VisualBuilderFidelity.test.ts +0 -105
- package/src/Tests/referenceDocument.ts +0 -119
- 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,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
|
+
}
|