@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
|
@@ -18,16 +18,13 @@ export function markdownAstToGreenTree(root: MarkdownNode): GreenNode {
|
|
|
18
18
|
for (const child of node.children) children.push(convert(child));
|
|
19
19
|
break;
|
|
20
20
|
case 'paragraph':
|
|
21
|
-
kind = '
|
|
22
|
-
// Actually DocumentEngine uses 'text' or 'group'
|
|
23
|
-
kind = 'document'; // Let's use group or document as container
|
|
21
|
+
kind = 'paragraph';
|
|
24
22
|
for (const child of node.children) children.push(convert(child));
|
|
25
23
|
break;
|
|
26
24
|
case 'heading':
|
|
27
25
|
kind = 'heading';
|
|
28
|
-
// Faking the '#' text length for the heading level offset
|
|
29
26
|
currentOffset += node.level;
|
|
30
|
-
text = `=${node.level}`;
|
|
27
|
+
text = `=${node.level}`;
|
|
31
28
|
for (const child of node.children) children.push(convert(child));
|
|
32
29
|
break;
|
|
33
30
|
case 'strong':
|
|
@@ -38,6 +35,58 @@ export function markdownAstToGreenTree(root: MarkdownNode): GreenNode {
|
|
|
38
35
|
kind = 'italic';
|
|
39
36
|
for (const child of node.children) children.push(convert(child));
|
|
40
37
|
break;
|
|
38
|
+
case 'strikethrough':
|
|
39
|
+
kind = 'strikethrough';
|
|
40
|
+
for (const child of node.children) children.push(convert(child));
|
|
41
|
+
break;
|
|
42
|
+
case 'underline':
|
|
43
|
+
kind = 'underline';
|
|
44
|
+
for (const child of node.children) children.push(convert(child));
|
|
45
|
+
break;
|
|
46
|
+
case 'color':
|
|
47
|
+
kind = 'color';
|
|
48
|
+
text = `=${node.color}`;
|
|
49
|
+
for (const child of node.children) children.push(convert(child));
|
|
50
|
+
break;
|
|
51
|
+
case 'font_size':
|
|
52
|
+
kind = 'font_size';
|
|
53
|
+
text = `=${node.size}`;
|
|
54
|
+
for (const child of node.children) children.push(convert(child));
|
|
55
|
+
break;
|
|
56
|
+
case 'font':
|
|
57
|
+
kind = 'font';
|
|
58
|
+
text = `=${node.font}`;
|
|
59
|
+
for (const child of node.children) children.push(convert(child));
|
|
60
|
+
break;
|
|
61
|
+
case 'center':
|
|
62
|
+
kind = 'center';
|
|
63
|
+
for (const child of node.children) children.push(convert(child));
|
|
64
|
+
break;
|
|
65
|
+
case 'right':
|
|
66
|
+
kind = 'right';
|
|
67
|
+
for (const child of node.children) children.push(convert(child));
|
|
68
|
+
break;
|
|
69
|
+
case 'left':
|
|
70
|
+
kind = 'left';
|
|
71
|
+
for (const child of node.children) children.push(convert(child));
|
|
72
|
+
break;
|
|
73
|
+
case 'align':
|
|
74
|
+
kind = 'align';
|
|
75
|
+
for (const child of node.children) children.push(convert(child));
|
|
76
|
+
break;
|
|
77
|
+
case 'box':
|
|
78
|
+
kind = 'box';
|
|
79
|
+
text = node.title ? `=${node.title}` : '';
|
|
80
|
+
for (const child of node.children) children.push(convert(child));
|
|
81
|
+
break;
|
|
82
|
+
case 'spoilerbox':
|
|
83
|
+
kind = 'spoilerbox';
|
|
84
|
+
text = node.title ? `=${node.title}` : '';
|
|
85
|
+
for (const child of node.children) children.push(convert(child));
|
|
86
|
+
break;
|
|
87
|
+
case 'separator':
|
|
88
|
+
kind = 'separator';
|
|
89
|
+
break;
|
|
41
90
|
case 'text':
|
|
42
91
|
kind = 'text';
|
|
43
92
|
text = node.value;
|
|
@@ -48,11 +97,6 @@ export function markdownAstToGreenTree(root: MarkdownNode): GreenNode {
|
|
|
48
97
|
text = `=${node.url}`;
|
|
49
98
|
for (const child of node.children) children.push(convert(child));
|
|
50
99
|
break;
|
|
51
|
-
case 'image':
|
|
52
|
-
kind = 'image';
|
|
53
|
-
text = node.url;
|
|
54
|
-
currentOffset += text.length;
|
|
55
|
-
break;
|
|
56
100
|
case 'code_block':
|
|
57
101
|
kind = 'code';
|
|
58
102
|
children.push(greenLeaf('text', node.value));
|
|
@@ -60,6 +104,7 @@ export function markdownAstToGreenTree(root: MarkdownNode): GreenNode {
|
|
|
60
104
|
break;
|
|
61
105
|
case 'list':
|
|
62
106
|
kind = 'list';
|
|
107
|
+
text = node.ordered ? '=1' : '';
|
|
63
108
|
for (const child of node.children) children.push(convert(child));
|
|
64
109
|
break;
|
|
65
110
|
case 'list_item':
|
|
@@ -72,10 +117,17 @@ export function markdownAstToGreenTree(root: MarkdownNode): GreenNode {
|
|
|
72
117
|
break;
|
|
73
118
|
case 'notice':
|
|
74
119
|
kind = 'notice';
|
|
120
|
+
text = node.color ? `=${node.color}` : '';
|
|
121
|
+
for (const child of node.children) children.push(convert(child));
|
|
122
|
+
break;
|
|
123
|
+
case 'wnotice':
|
|
124
|
+
kind = 'wnotice';
|
|
125
|
+
text = node.color ? `=${node.color}` : '';
|
|
75
126
|
for (const child of node.children) children.push(convert(child));
|
|
76
127
|
break;
|
|
77
128
|
case 'blockquote':
|
|
78
129
|
kind = 'quote';
|
|
130
|
+
text = node.source ? `=${node.source}` : '';
|
|
79
131
|
for (const child of node.children) children.push(convert(child));
|
|
80
132
|
break;
|
|
81
133
|
case 'spacing':
|
|
@@ -88,24 +140,23 @@ export function markdownAstToGreenTree(root: MarkdownNode): GreenNode {
|
|
|
88
140
|
text = '\n\n';
|
|
89
141
|
currentOffset += 2;
|
|
90
142
|
break;
|
|
91
|
-
// `image` and `code_inline` used to land in `default`, which discarded
|
|
92
|
-
// them as empty text nodes — Markdown images never survived conversion.
|
|
93
143
|
case 'image':
|
|
94
144
|
kind = 'image';
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
currentOffset += node.alt.length;
|
|
99
|
-
}
|
|
145
|
+
// In osu! BBCode, image content is the URL between [img] and [/img]
|
|
146
|
+
children.push(greenLeaf('text', node.url));
|
|
147
|
+
currentOffset += node.url.length;
|
|
100
148
|
break;
|
|
101
149
|
case 'code_inline':
|
|
102
150
|
kind = 'inline_code';
|
|
103
151
|
children.push(greenLeaf('text', node.value));
|
|
104
152
|
currentOffset += node.value.length;
|
|
105
153
|
break;
|
|
154
|
+
case 'bbcode_tag':
|
|
155
|
+
kind = node.tagName as NodeKind;
|
|
156
|
+
text = node.attrValue ? `=${node.attrValue}` : '';
|
|
157
|
+
for (const child of node.children) children.push(convert(child));
|
|
158
|
+
break;
|
|
106
159
|
default: {
|
|
107
|
-
// Exhaustiveness guard: adding a MarkdownNode variant without a case
|
|
108
|
-
// here is now a compile error rather than a silently dropped node.
|
|
109
160
|
const unhandled: never = node;
|
|
110
161
|
void unhandled;
|
|
111
162
|
kind = 'text';
|
|
@@ -113,25 +164,95 @@ export function markdownAstToGreenTree(root: MarkdownNode): GreenNode {
|
|
|
113
164
|
}
|
|
114
165
|
}
|
|
115
166
|
|
|
116
|
-
|
|
117
|
-
// Map text container to group for proper DocumentEngine representation if not text
|
|
118
|
-
const actualKind = kind === 'document' && node.type === 'paragraph' ? 'group' : kind;
|
|
119
|
-
return greenNode(actualKind as string, text, children);
|
|
167
|
+
return greenNode(kind as string, text, children);
|
|
120
168
|
}
|
|
121
169
|
|
|
122
170
|
return convert(root);
|
|
123
171
|
}
|
|
124
172
|
|
|
173
|
+
const EFFECT_TAGS = new Set(['glow', 'neon', 'outline', 'shimmer', 'ghost', 'rainbow', 'fire', 'ice', 'emboss', 'engrave']);
|
|
174
|
+
const ANIM_TAGS = new Set(['typewriter', 'wave', 'sparkle', 'glitch', 'levitate', 'pulse', 'bounce', 'shake', 'fade-in', 'fade-out']);
|
|
175
|
+
const CONTAINER_TAGS = new Set(['card', 'glass', 'neon-box', 'neonbox', 'square', 'circle', 'stack', 'flex', 'grid', 'middle']);
|
|
176
|
+
|
|
125
177
|
export function greenToRedNode(green: GreenNode, parent?: RedNode | null): RedNode {
|
|
126
|
-
// Simple metadata extraction based on heading text
|
|
127
178
|
let metadata: Record<string, unknown> = {};
|
|
128
|
-
|
|
129
|
-
|
|
179
|
+
let kind = (green.kind as NodeKind) || 'text';
|
|
180
|
+
|
|
181
|
+
const attrValue = green.text.startsWith('=') ? green.text.slice(1) : undefined;
|
|
182
|
+
|
|
183
|
+
if (EFFECT_TAGS.has(green.kind)) {
|
|
184
|
+
kind = 'effect';
|
|
185
|
+
metadata.effectType = green.kind;
|
|
186
|
+
if (attrValue) metadata.color = attrValue;
|
|
187
|
+
} else if (ANIM_TAGS.has(green.kind)) {
|
|
188
|
+
kind = 'anim';
|
|
189
|
+
metadata.animType = green.kind;
|
|
190
|
+
if (attrValue) metadata.animParam = attrValue;
|
|
191
|
+
} else if (CONTAINER_TAGS.has(green.kind)) {
|
|
192
|
+
kind = 'container';
|
|
193
|
+
metadata.containerType = green.kind;
|
|
194
|
+
if (attrValue) metadata.color = attrValue;
|
|
195
|
+
} else if (green.kind === 'row') {
|
|
196
|
+
kind = 'table_row';
|
|
197
|
+
} else if (green.kind === 'col') {
|
|
198
|
+
kind = 'table_col';
|
|
199
|
+
if (attrValue) metadata.variant = attrValue;
|
|
200
|
+
} else if (green.kind === 'th') {
|
|
201
|
+
kind = 'table_th';
|
|
202
|
+
if (attrValue) metadata.variant = attrValue;
|
|
203
|
+
} else if (green.kind === 'tables') {
|
|
204
|
+
kind = 'tables';
|
|
205
|
+
if (attrValue) metadata.variant = attrValue;
|
|
206
|
+
} else if (green.kind === 'columns') {
|
|
207
|
+
kind = 'columns';
|
|
208
|
+
if (attrValue) metadata.columns = parseInt(attrValue) || 2;
|
|
209
|
+
} else if (green.kind === 'scroll') {
|
|
210
|
+
kind = 'scroll';
|
|
211
|
+
if (attrValue) metadata.height = attrValue;
|
|
212
|
+
} else if (green.kind === 'separator') {
|
|
213
|
+
kind = 'separator';
|
|
214
|
+
if (attrValue) metadata.variant = attrValue;
|
|
215
|
+
} else if (green.kind === 'heading' && attrValue) {
|
|
216
|
+
metadata.level = parseInt(attrValue) || 1;
|
|
217
|
+
} else if (green.kind === 'color' && attrValue) {
|
|
218
|
+
metadata.color = attrValue;
|
|
219
|
+
} else if (green.kind === 'font_size' && attrValue) {
|
|
220
|
+
metadata.size = attrValue;
|
|
221
|
+
} else if (green.kind === 'font' && attrValue) {
|
|
222
|
+
metadata.font = attrValue;
|
|
223
|
+
} else if (green.kind === 'url' && attrValue) {
|
|
224
|
+
metadata.href = attrValue;
|
|
225
|
+
} else if (green.kind === 'list' && attrValue === '1') {
|
|
226
|
+
metadata.ordered = true;
|
|
227
|
+
} else if ((green.kind === 'box' || green.kind === 'boxw' || green.kind === 'spoilerbox') && attrValue) {
|
|
228
|
+
metadata.title = attrValue;
|
|
229
|
+
metadata.rawTitle = attrValue;
|
|
230
|
+
} else if ((green.kind === 'notice' || green.kind === 'wnotice') && attrValue) {
|
|
231
|
+
metadata.color = attrValue;
|
|
232
|
+
} else if (green.kind === 'quote' && attrValue) {
|
|
233
|
+
metadata.source = attrValue;
|
|
234
|
+
} else if (green.kind === 'abbr' && attrValue) {
|
|
235
|
+
metadata.title = attrValue;
|
|
236
|
+
} else if (green.kind === 'tooltip' && attrValue) {
|
|
237
|
+
metadata.tip = attrValue;
|
|
238
|
+
} else if (green.kind === 'style' || green.kind === 'style_tag') {
|
|
239
|
+
kind = 'style_tag';
|
|
240
|
+
if (attrValue) metadata.style = attrValue;
|
|
241
|
+
} else if (green.kind === 'image') {
|
|
242
|
+
if (green.children.length > 0) {
|
|
243
|
+
const first = green.children[0] as GreenNode;
|
|
244
|
+
if (first.kind === 'text') {
|
|
245
|
+
metadata.src = first.text;
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
} else if (attrValue) {
|
|
249
|
+
metadata.value = attrValue;
|
|
250
|
+
metadata.raw = attrValue;
|
|
130
251
|
}
|
|
131
252
|
|
|
132
253
|
const red = new RedNode(green, {
|
|
133
254
|
parent: parent ?? null,
|
|
134
|
-
kind
|
|
255
|
+
kind,
|
|
135
256
|
metadata
|
|
136
257
|
});
|
|
137
258
|
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { DocumentModel, type DocumentModelOptions } from '../Model/DocumentModel';
|
|
2
|
+
import { GreenNode, greenLeaf } from '../Syntax/GreenNode';
|
|
3
|
+
import { RedNode } from '../Syntax/RedNode';
|
|
4
|
+
import { scanMarkdown } from '../Markdown/MarkdownLexer';
|
|
5
|
+
import { parseMarkdown } from '../Markdown/MarkdownParser';
|
|
6
|
+
import { markdownAstToGreenTree, greenToRedNode } from '../Markdown/MarkdownToGreenNode';
|
|
7
|
+
|
|
8
|
+
export interface MilHibriDocumentModelOptions extends DocumentModelOptions {
|
|
9
|
+
source?: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* DocumentEngine — MilHibriDocumentModel
|
|
14
|
+
*
|
|
15
|
+
* First-class DocumentModel for the MilHibri language:
|
|
16
|
+
* Unifies 100% of osu! BBCode and 100% of Markdown + Modern Industry Extensions
|
|
17
|
+
* into a single unified, collision-free AST.
|
|
18
|
+
*/
|
|
19
|
+
export class MilHibriDocumentModel extends DocumentModel {
|
|
20
|
+
constructor(options: MilHibriDocumentModelOptions = {}) {
|
|
21
|
+
super({ source: '', language: 'milhibri' });
|
|
22
|
+
if (options.source) {
|
|
23
|
+
this.rebuild(options.source);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
static fromSource(source: string): MilHibriDocumentModel {
|
|
28
|
+
return new MilHibriDocumentModel({ source });
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
protected parseToGreen(source: string): GreenNode {
|
|
32
|
+
try {
|
|
33
|
+
const tokens = scanMarkdown(source);
|
|
34
|
+
const ast = parseMarkdown(tokens);
|
|
35
|
+
return markdownAstToGreenTree(ast);
|
|
36
|
+
} catch (error) {
|
|
37
|
+
console.warn('[MilHibriDocumentModel] Parse error:', error);
|
|
38
|
+
return greenLeaf('text', source);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
protected buildRedFromGreen(green: GreenNode): RedNode {
|
|
43
|
+
return greenToRedNode(green);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
applyTextUpdate(newSource: string): void {
|
|
47
|
+
if (this.source === newSource) return;
|
|
48
|
+
this.rebuild(newSource);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
applyChange(change: any): void {
|
|
52
|
+
const before = this.source.slice(0, change.start);
|
|
53
|
+
const after = this.source.slice(change.end);
|
|
54
|
+
this.rebuild(before + change.text + after);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
@@ -27,6 +27,7 @@ import {
|
|
|
27
27
|
IncrementalParser,
|
|
28
28
|
type ReparseParseOptions,
|
|
29
29
|
type FallbackReason,
|
|
30
|
+
type SourceSpan,
|
|
30
31
|
} from '../Incremental/IncrementalParser'
|
|
31
32
|
import { ChangeTracker } from '../Incremental/ChangeTracker'
|
|
32
33
|
import type { TextChange, TextChangeRange } from '../Incremental/ChangeTracker'
|
|
@@ -84,6 +85,34 @@ export interface DocumentModelOptions {
|
|
|
84
85
|
reuseRed?: boolean
|
|
85
86
|
}
|
|
86
87
|
|
|
88
|
+
/**
|
|
89
|
+
* A span of the OLD text, in the coordinates of the text `change` produced.
|
|
90
|
+
*
|
|
91
|
+
* An endpoint before the change does not move and one after it moves by the
|
|
92
|
+
* change's delta; one INSIDE it has no image, so it is pushed outwards — the
|
|
93
|
+
* start down to where the change begins, the end up to where the replacement
|
|
94
|
+
* ends. The span this belongs to is a re-validation window, and a window that
|
|
95
|
+
* covers slightly more than it must costs nodes, never correctness.
|
|
96
|
+
*/
|
|
97
|
+
function shiftSpan(span: SourceSpan | null, change: TextChange): SourceSpan | null {
|
|
98
|
+
if (span === null) return null
|
|
99
|
+
const delta = change.text.length - (change.end - change.start)
|
|
100
|
+
const newEnd = change.start + change.text.length
|
|
101
|
+
const start = span.start <= change.start
|
|
102
|
+
? span.start
|
|
103
|
+
: span.start >= change.end ? span.start + delta : change.start
|
|
104
|
+
const end = span.end <= change.start
|
|
105
|
+
? span.end
|
|
106
|
+
: span.end >= change.end ? span.end + delta : newEnd
|
|
107
|
+
return { start, end }
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/** The smallest span containing both. */
|
|
111
|
+
function unionSpans(a: SourceSpan | null, b: SourceSpan): SourceSpan {
|
|
112
|
+
if (a === null) return b
|
|
113
|
+
return { start: Math.min(a.start, b.start), end: Math.max(a.end, b.end) }
|
|
114
|
+
}
|
|
115
|
+
|
|
87
116
|
export class DocumentModel {
|
|
88
117
|
// ── Core State ──
|
|
89
118
|
private _source: string
|
|
@@ -123,6 +152,32 @@ export class DocumentModel {
|
|
|
123
152
|
/** Why the last reparse fell back to a full rebuild, if it did. */
|
|
124
153
|
lastReparseFallbackReason: FallbackReason | null = null
|
|
125
154
|
lastReparseTimings: { findAffected: number; safeBoundary: number; parse: number; buildRed: number; mutate: number; other: number } | null = null
|
|
155
|
+
/**
|
|
156
|
+
* The span of the current source the last reparse actually re-parsed, in
|
|
157
|
+
* CURRENT coordinates — `null` after a full rebuild, where the answer is
|
|
158
|
+
* "all of it". See {@link ReparseResult.window}.
|
|
159
|
+
*/
|
|
160
|
+
lastReparseWindow: SourceSpan | null = null
|
|
161
|
+
|
|
162
|
+
// ── Incremental analysis bookkeeping ──
|
|
163
|
+
//
|
|
164
|
+
// `analyzeWindow` re-validates the nodes an edit could have changed and
|
|
165
|
+
// keeps every other node's verdict. What makes that sound is a promise only
|
|
166
|
+
// the model can make: that this tree grew out of the analysed one through
|
|
167
|
+
// incremental reparses WITH red-subtree reuse, so every node outside the
|
|
168
|
+
// windows is the same object over the same text. These two fields are that
|
|
169
|
+
// promise, tracked edit by edit.
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* The union of every reparse window since the last analysis, in CURRENT
|
|
173
|
+
* coordinates — `null` when nothing is pending. A bounding span rather than
|
|
174
|
+
* a list: over-covering only means re-validating a few more nodes, and the
|
|
175
|
+
* arithmetic to keep several spans current across later edits costs more
|
|
176
|
+
* than the nodes do.
|
|
177
|
+
*/
|
|
178
|
+
private _analysisWindow: SourceSpan | null = null
|
|
179
|
+
/** Set by anything a window pass cannot be built on: a rebuild, a reparse that fell back. */
|
|
180
|
+
private _analysisWindowBroken = true
|
|
126
181
|
|
|
127
182
|
constructor(options: DocumentModelOptions = {}) {
|
|
128
183
|
this._options = {
|
|
@@ -181,6 +236,12 @@ export class DocumentModel {
|
|
|
181
236
|
return this._diagnostics
|
|
182
237
|
}
|
|
183
238
|
|
|
239
|
+
/**
|
|
240
|
+
* What the last analysis cost and how it was obtained — its `scope` says
|
|
241
|
+
* whether it walked the document or only the edit's window, and `window`
|
|
242
|
+
* carries that span when it did. The diagnostics themselves are on
|
|
243
|
+
* {@link diagnostics}, and are the whole document's on either route.
|
|
244
|
+
*/
|
|
184
245
|
get lastAnalyze(): AnalyzeResult | null {
|
|
185
246
|
return this._lastAnalyzeResult
|
|
186
247
|
}
|
|
@@ -215,6 +276,12 @@ export class DocumentModel {
|
|
|
215
276
|
// incrementally, so the range is cleared and the preview falls back to its
|
|
216
277
|
// full reconcile (which is what it must do for undo/redo/load anyway).
|
|
217
278
|
this._lastChangeRange = null
|
|
279
|
+
this.lastReparseWindow = null
|
|
280
|
+
// A rebuild replaces every node in the tree, so nothing a previous
|
|
281
|
+
// analysis knew about any of them survives. Set BEFORE `analyze()` below,
|
|
282
|
+
// which reads it.
|
|
283
|
+
this._analysisWindow = null
|
|
284
|
+
this._analysisWindowBroken = true
|
|
218
285
|
this._attachChangeRange(this._redRoot)
|
|
219
286
|
// Unchanged nodes keep the identity they had before the rebuild, so the
|
|
220
287
|
// HTML of untouched subtrees stays byte-identical between renders and the
|
|
@@ -296,8 +363,22 @@ export class DocumentModel {
|
|
|
296
363
|
}
|
|
297
364
|
|
|
298
365
|
/**
|
|
299
|
-
* Apply
|
|
300
|
-
*
|
|
366
|
+
* Apply one exact source change — THE edit path, and the one an editor
|
|
367
|
+
* should use.
|
|
368
|
+
*
|
|
369
|
+
* An editor already knows what the user did: Monaco's
|
|
370
|
+
* `onDidChangeModelContent` hands over `rangeOffset`, `rangeLength` and
|
|
371
|
+
* `text`, which is exactly a {@link TextChange}. Handing that over instead
|
|
372
|
+
* of the new document text skips the only part of the pipeline that is
|
|
373
|
+
* unavoidably proportional to the whole document — the prefix/suffix diff
|
|
374
|
+
* in {@link applyTextUpdate} — and the difference is not marginal. Typing
|
|
375
|
+
* 120 characters into the middle of the 500 KB fixture, per keystroke:
|
|
376
|
+
*
|
|
377
|
+
* applyTextUpdate p50 7.35 ms p95 28.79 ms
|
|
378
|
+
* applyChange p50 1.85 ms p95 8.18 ms
|
|
379
|
+
*
|
|
380
|
+
* Everything downstream is already windowed, so what is left after the diff
|
|
381
|
+
* goes is work proportional to the edit.
|
|
301
382
|
*
|
|
302
383
|
* `origin` tags where the change came from — `'local'` (default) for the
|
|
303
384
|
* user's own editing, anything else for programmatic or synced sources
|
|
@@ -357,6 +438,7 @@ export class DocumentModel {
|
|
|
357
438
|
this.lastReparsePath = result.path
|
|
358
439
|
this.lastReparseFallbackReason = result.reason ?? null
|
|
359
440
|
this.lastReparseTimings = result.timings
|
|
441
|
+
this.lastReparseWindow = result.window
|
|
360
442
|
this._greenRoot = result.green
|
|
361
443
|
this._redRoot = result.red
|
|
362
444
|
// Identity across the edit, by whichever mechanism applies.
|
|
@@ -377,6 +459,20 @@ export class DocumentModel {
|
|
|
377
459
|
if (oldRoot && reuse.adopted === 0) {
|
|
378
460
|
preserveNodeIds(oldRoot, this._redRoot)
|
|
379
461
|
}
|
|
462
|
+
// Carry the analysis window across this edit, or give up on it. Both
|
|
463
|
+
// conditions matter: without a reparse window every node is new, and
|
|
464
|
+
// without adopted subtrees `preserveNodeIds` has just moved ids
|
|
465
|
+
// between different nodes, which is exactly what an id-keyed snapshot
|
|
466
|
+
// of the previous analysis cannot survive.
|
|
467
|
+
if (result.window === null || reuse.adopted === 0) {
|
|
468
|
+
this._analysisWindow = null
|
|
469
|
+
this._analysisWindowBroken = true
|
|
470
|
+
} else if (!this._analysisWindowBroken) {
|
|
471
|
+
this._analysisWindow = unionSpans(
|
|
472
|
+
shiftSpan(this._analysisWindow, change),
|
|
473
|
+
result.window,
|
|
474
|
+
)
|
|
475
|
+
}
|
|
380
476
|
this._version++
|
|
381
477
|
// The incremental path resolved: the range stays attached to the new
|
|
382
478
|
// root so the preview can find the edited region.
|
|
@@ -384,6 +480,8 @@ export class DocumentModel {
|
|
|
384
480
|
} catch {
|
|
385
481
|
this.lastReparsePath = 'full_rebuild'
|
|
386
482
|
this.lastReparseTimings = null
|
|
483
|
+
this.lastReparseWindow = null
|
|
484
|
+
// `rebuild` clears the analysis window itself.
|
|
387
485
|
this.rebuild(this._source)
|
|
388
486
|
return
|
|
389
487
|
}
|
|
@@ -427,6 +525,10 @@ export class DocumentModel {
|
|
|
427
525
|
version: this._version,
|
|
428
526
|
source: this._source,
|
|
429
527
|
diagnostics: this._diagnostics,
|
|
528
|
+
// How they were arrived at, not what they are: `diagnostics` is the
|
|
529
|
+
// whole document's on both routes. See `DocumentEvent.analysisScope`.
|
|
530
|
+
analysisScope: this._lastAnalyzeResult?.scope,
|
|
531
|
+
analysisWindow: this._lastAnalyzeResult?.window ?? null,
|
|
430
532
|
timestamp: Date.now()
|
|
431
533
|
}
|
|
432
534
|
this.defineLazyNodeMatch(diagnosticsEvent, oldRoot, this._redRoot)
|
|
@@ -456,8 +558,14 @@ export class DocumentModel {
|
|
|
456
558
|
}
|
|
457
559
|
|
|
458
560
|
/**
|
|
459
|
-
*
|
|
460
|
-
*
|
|
561
|
+
* Recover the edit from the new document text, then apply it.
|
|
562
|
+
*
|
|
563
|
+
* The FALLBACK, for a caller that only has the text: a textarea's `value`,
|
|
564
|
+
* a CRDT that hands over a materialised document, a paste normaliser. It is
|
|
565
|
+
* a shared-prefix/shared-suffix diff, so it costs one pass over the
|
|
566
|
+
* unchanged part of the document before any of the incremental machinery
|
|
567
|
+
* gets to run — which is precisely the term {@link applyChange} does not
|
|
568
|
+
* pay. Anything that knows the edit should say so and use that instead.
|
|
461
569
|
*/
|
|
462
570
|
applyTextUpdate(newSource: string, origin: string = 'local'): void {
|
|
463
571
|
if (this._source === newSource) return
|
|
@@ -568,12 +676,35 @@ export class DocumentModel {
|
|
|
568
676
|
|
|
569
677
|
/**
|
|
570
678
|
* Run semantic analysis on the current tree.
|
|
679
|
+
*
|
|
680
|
+
* Incremental when it can be: if every edit since the last analysis was an
|
|
681
|
+
* incremental reparse that adopted subtrees, only the nodes inside those
|
|
682
|
+
* reparse windows — plus the ones whose document-wide facts the edits moved
|
|
683
|
+
* — are re-validated, and every other node keeps the verdict it already
|
|
684
|
+
* had. The DIAGNOSTICS ARE THE SAME EITHER WAY; the difference is how long
|
|
685
|
+
* it took to arrive at them, and {@link AnalyzeResult.scope} says which
|
|
686
|
+
* route was taken. The differential in `Chars500kAnalysis.test.ts` compares
|
|
687
|
+
* the two, edit by edit, on the real fixture.
|
|
688
|
+
*
|
|
689
|
+
* Falls back to the full pass whenever the window pass declines — no
|
|
690
|
+
* previous pass to build on, the validator set or the token source changed
|
|
691
|
+
* under it, or a validator whose verdicts are not a function of one node
|
|
692
|
+
* (see `Validator.scope`).
|
|
571
693
|
*/
|
|
572
694
|
analyze(): AnalyzeResult {
|
|
573
695
|
if (!this._redRoot) {
|
|
574
696
|
throw new Error('Cannot analyze: no document loaded')
|
|
575
697
|
}
|
|
576
|
-
const
|
|
698
|
+
const window = this._analysisWindowBroken ? null : this._analysisWindow
|
|
699
|
+
const result =
|
|
700
|
+
(window !== null
|
|
701
|
+
? this.semanticAnalyzer.analyzeWindow(this._redRoot, this._source, window)
|
|
702
|
+
: null)
|
|
703
|
+
?? this.semanticAnalyzer.analyze(this._redRoot, this._source)
|
|
704
|
+
// Whatever route it took, the tree is now fully analysed and the next
|
|
705
|
+
// edit starts a fresh window on top of this pass.
|
|
706
|
+
this._analysisWindow = null
|
|
707
|
+
this._analysisWindowBroken = false
|
|
577
708
|
this._diagnostics = result.diagnostics
|
|
578
709
|
|
|
579
710
|
// Keep the id index out of the retained result: holding it would pin every
|
|
@@ -584,6 +715,8 @@ export class DocumentModel {
|
|
|
584
715
|
diagnostics: result.diagnostics,
|
|
585
716
|
duration: result.duration,
|
|
586
717
|
nodesAnalyzed: result.nodesAnalyzed,
|
|
718
|
+
scope: result.scope,
|
|
719
|
+
window: result.window,
|
|
587
720
|
}
|
|
588
721
|
|
|
589
722
|
// Attaching diagnostics to nodes used to happen here, and needed an id→node
|