@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
|
@@ -252,18 +252,18 @@ export class GreenNodePool {
|
|
|
252
252
|
}
|
|
253
253
|
}
|
|
254
254
|
|
|
255
|
-
/**
|
|
255
|
+
/**
|
|
256
|
+
* Convenience helper for interning green leaves, over the shared singleton.
|
|
257
|
+
*
|
|
258
|
+
* The internal-node twin of this helper used to sit alongside it and was
|
|
259
|
+
* removed: nothing imported it, and it could not have worked if anything had.
|
|
260
|
+
* `GreenNodePool.instance` is built with the default `'leaves'` mode, and
|
|
261
|
+
* `internNode` returns a fresh `GreenNode` unconditionally in that mode — so
|
|
262
|
+
* the one thing the helper existed for, structural sharing of internal nodes,
|
|
263
|
+
* was unreachable through the only pool it could reach. Interning internal
|
|
264
|
+
* nodes is done by passing a `GreenNodePool.create('full')` to the parser,
|
|
265
|
+
* which is what `BBCodeDocumentModel` does per document.
|
|
266
|
+
*/
|
|
256
267
|
export function internGreenLeaf(kind: string, text: string, width = text.length): GreenNode {
|
|
257
268
|
return GreenNodePool.instance.internLeaf(kind, text, width)
|
|
258
269
|
}
|
|
259
|
-
|
|
260
|
-
/** Convenience helper for interning green nodes */
|
|
261
|
-
export function internGreenNode(
|
|
262
|
-
kind: string,
|
|
263
|
-
text: string,
|
|
264
|
-
children: GreenNode[],
|
|
265
|
-
leadingWidth = 0,
|
|
266
|
-
trailingWidth = 0,
|
|
267
|
-
): GreenNode {
|
|
268
|
-
return GreenNodePool.instance.internNode(kind, text, children, leadingWidth, trailingWidth)
|
|
269
|
-
}
|
package/src/Syntax/RedNode.ts
CHANGED
|
@@ -175,6 +175,22 @@ export class RedNode {
|
|
|
175
175
|
}
|
|
176
176
|
node._range.start += delta
|
|
177
177
|
node._range.end += delta
|
|
178
|
+
RedNode.shiftDescendants(node, delta)
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Push `delta` into every red node that lives under `node` — its title nodes
|
|
183
|
+
* as well as its children.
|
|
184
|
+
*
|
|
185
|
+
* The title subtree of a rich `[box=[b]heading[/b]]` is stored in
|
|
186
|
+
* `metadata.titleNodes`, never appended to `children`, so a loop over
|
|
187
|
+
* `children` alone leaves it at pre-edit offsets. That is not cosmetic:
|
|
188
|
+
* `findNodeAtOffset` consults `metadata.titleNodes` BEFORE `children`, so a
|
|
189
|
+
* stale title range mis-resolves caret, hover and selection inside the
|
|
190
|
+
* heading. Both shift paths — the recursive one and `materialize`'s ancestor
|
|
191
|
+
* loop — route through here so they cannot drift apart again.
|
|
192
|
+
*/
|
|
193
|
+
private static shiftDescendants(node: RedNode, delta: number): void {
|
|
178
194
|
const titleNodes = node.metadata?.titleNodes as RedNode[] | undefined
|
|
179
195
|
if (titleNodes) {
|
|
180
196
|
for (let i = 0; i < titleNodes.length; i++) {
|
|
@@ -223,9 +239,7 @@ export class RedNode {
|
|
|
223
239
|
ancestor._lazyShift = 0
|
|
224
240
|
ancestor._range.start += delta
|
|
225
241
|
ancestor._range.end += delta
|
|
226
|
-
|
|
227
|
-
RedNode.applyShift(ancestor.children[c], delta)
|
|
228
|
-
}
|
|
242
|
+
RedNode.shiftDescendants(ancestor, delta)
|
|
229
243
|
}
|
|
230
244
|
}
|
|
231
245
|
|
|
@@ -145,9 +145,17 @@ export class RedNodeStore {
|
|
|
145
145
|
|
|
146
146
|
/**
|
|
147
147
|
* Check if a GreenNode already has a canonical RedNode.
|
|
148
|
+
*
|
|
149
|
+
* Mirrors `getOrCreate`'s discriminator, including the identity check. A
|
|
150
|
+
* present hash entry only proves *some* structure registered under this
|
|
151
|
+
* 32-bit hash; if it is a different green, `getOrCreate` counts a collision
|
|
152
|
+
* and builds an unregistered node, so answering `true` here would be the
|
|
153
|
+
* opposite of the truth for any caller deciding whether canonicalization has
|
|
154
|
+
* already happened.
|
|
148
155
|
*/
|
|
149
156
|
has(green: GreenNode): boolean {
|
|
150
|
-
|
|
157
|
+
const existing = this.canonicals.get(green._hash.toString())
|
|
158
|
+
return existing !== undefined && existing.green === green
|
|
151
159
|
}
|
|
152
160
|
|
|
153
161
|
/**
|
|
@@ -0,0 +1,172 @@
|
|
|
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
|
+
|
|
18
|
+
import type { RedNode } from './RedNode'
|
|
19
|
+
import type { TokenResolverFn } from '../Tokens'
|
|
20
|
+
|
|
21
|
+
/** #rgb / #rgba / #rrggbb / #rrggbbaa, una palabra clave CSS, o rgb()/hsl(). */
|
|
22
|
+
const CSS_COLOR_RE =
|
|
23
|
+
/^(?:#(?:[0-9a-f]{3}|[0-9a-f]{4}|[0-9a-f]{6}|[0-9a-f]{8})|[a-z]{3,20}|(?:rgb|hsl)a?\([0-9a-z.,%\s/+-]{1,64}\))$/i
|
|
24
|
+
|
|
25
|
+
/** Número desnudo — se interpola como porcentaje. */
|
|
26
|
+
const CSS_SIZE_RE = /^\d{1,4}(?:\.\d{1,2})?$/
|
|
27
|
+
|
|
28
|
+
/** Lista de familias. Las comillas se rechazan; sin comillas es CSS válido. */
|
|
29
|
+
const CSS_FONT_RE = /^[A-Za-z0-9 ,_-]{1,120}$/
|
|
30
|
+
|
|
31
|
+
const BARE_HEX_RE = /^[0-9a-f]{3,8}$/i
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* El valor del atributo de un nodo.
|
|
35
|
+
*
|
|
36
|
+
* Los atributos BBCode vienen como `=VALOR` (`=#61afef`, `="Autor"`,
|
|
37
|
+
* `=https://osu.ppy.sh`): se quita el `=` y las comillas envolventes. Una
|
|
38
|
+
* etiqueta sin atributo —el contenido de un `[img]`, por ejemplo— devuelve su
|
|
39
|
+
* texto tal cual.
|
|
40
|
+
*
|
|
41
|
+
* Con `key`, gana lo que haya en `metadata`: es lo que escribe el Inspector al
|
|
42
|
+
* editar una propiedad, y tiene que pesar más que el texto original del
|
|
43
|
+
* documento, que todavía no se ha reescrito.
|
|
44
|
+
*/
|
|
45
|
+
export function nodeAttrValue(node: RedNode, key?: string): string {
|
|
46
|
+
if (key) {
|
|
47
|
+
const meta = node.metadata?.[key]
|
|
48
|
+
if (typeof meta === 'string' && meta) return meta
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const text = node.text || ''
|
|
52
|
+
if (!text) return ''
|
|
53
|
+
|
|
54
|
+
const eqIdx = text.indexOf('=')
|
|
55
|
+
if (eqIdx < 0) return text
|
|
56
|
+
|
|
57
|
+
let value = text.slice(eqIdx + 1)
|
|
58
|
+
if (
|
|
59
|
+
(value.startsWith('"') && value.endsWith('"')) ||
|
|
60
|
+
(value.startsWith("'") && value.endsWith("'"))
|
|
61
|
+
) {
|
|
62
|
+
value = value.slice(1, -1)
|
|
63
|
+
}
|
|
64
|
+
return value
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Un color que se puede meter en un `style`, o `null`.
|
|
69
|
+
*
|
|
70
|
+
* Devolver `null` en vez de el valor crudo no es remilgo: `[color=red;"
|
|
71
|
+
* onmouseover="alert(1)]` cierra el atributo e inyecta un manejador de eventos.
|
|
72
|
+
* Escapar solo neutralizaría la inyección, pero dejaría CSS roto, así que se
|
|
73
|
+
* valida la FORMA y se descarta lo que no sea un valor que quisiéramos admitir.
|
|
74
|
+
*
|
|
75
|
+
* Un hex sin `#` se completa: `[color=ff0000]` es como lo escribe medio mundo.
|
|
76
|
+
*/
|
|
77
|
+
export function sanitizeColor(raw: string, resolver?: TokenResolverFn): string | null {
|
|
78
|
+
// Atajo para `#RRGGBB`, que es la forma que produce el propio motor y con
|
|
79
|
+
// la que llega la inmensa mayoría de las llamadas. Un degradado sin
|
|
80
|
+
// fusionar emite UN SEGMENTO POR CARÁCTER y cada uno pasaba por `trim`,
|
|
81
|
+
// dos expresiones regulares y el `startsWith` de los tokens. La comprobación
|
|
82
|
+
// por códigos de carácter acepta exactamente el mismo conjunto que
|
|
83
|
+
// `CSS_COLOR_RE` para siete caracteres, así que la garantía no cambia:
|
|
84
|
+
// sigue siendo imposible que salga de aquí algo que no sea un color.
|
|
85
|
+
if (raw.length === 7 && raw.charCodeAt(0) === 35 /* # */ && isPlainHex6(raw)) return raw
|
|
86
|
+
|
|
87
|
+
let v = raw.trim()
|
|
88
|
+
if (!v) return null
|
|
89
|
+
if (v.startsWith('$') && resolver) {
|
|
90
|
+
const resolved = resolver(v.slice(1)) ?? resolver(v)
|
|
91
|
+
if (resolved !== undefined) {
|
|
92
|
+
v = resolved.trim()
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
if (BARE_HEX_RE.test(v) && (v.length === 3 || v.length === 4 || v.length === 6 || v.length === 8)) {
|
|
96
|
+
v = '#' + v
|
|
97
|
+
}
|
|
98
|
+
return CSS_COLOR_RE.test(v) ? v : null
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/** `true` si `s[1..7]` son seis dígitos hexadecimales. Sin asignar nada. */
|
|
102
|
+
function isPlainHex6(s: string): boolean {
|
|
103
|
+
for (let i = 1; i < 7; i++) {
|
|
104
|
+
const c = s.charCodeAt(i)
|
|
105
|
+
const isDigit = c >= 0x30 && c <= 0x39
|
|
106
|
+
const isLower = c >= 0x61 && c <= 0x66
|
|
107
|
+
const isUpper = c >= 0x41 && c <= 0x46
|
|
108
|
+
if (!isDigit && !isLower && !isUpper) return false
|
|
109
|
+
}
|
|
110
|
+
return true
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/** El tamaño de `[size=…]` como número, o `null`. Se interpola en `%`. */
|
|
114
|
+
export function sanitizeFontSize(raw: string, resolver?: TokenResolverFn): string | null {
|
|
115
|
+
let v = raw.trim()
|
|
116
|
+
if (v.startsWith('$') && resolver) {
|
|
117
|
+
const resolved = resolver(v.slice(1)) ?? resolver(v)
|
|
118
|
+
if (resolved !== undefined) {
|
|
119
|
+
v = resolved.trim()
|
|
120
|
+
if (v.endsWith('%')) {
|
|
121
|
+
v = v.slice(0, -1).trim()
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
return CSS_SIZE_RE.test(v) ? v : null
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/** La familia de `[font=…]`, o `null`. */
|
|
129
|
+
export function sanitizeFontFamily(raw: string, resolver?: TokenResolverFn): string | null {
|
|
130
|
+
let v = raw.trim()
|
|
131
|
+
if (v.startsWith('$') && resolver) {
|
|
132
|
+
const resolved = resolver(v.slice(1)) ?? resolver(v)
|
|
133
|
+
if (resolved !== undefined) {
|
|
134
|
+
v = resolved.trim()
|
|
135
|
+
if (
|
|
136
|
+
(v.startsWith('"') && v.endsWith('"')) ||
|
|
137
|
+
(v.startsWith("'") && v.endsWith("'"))
|
|
138
|
+
) {
|
|
139
|
+
v = v.slice(1, -1).trim()
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
return CSS_FONT_RE.test(v) ? v : null
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/** Lo que puede significar el atributo de un `[img=…]`. */
|
|
147
|
+
export interface ImgAttr {
|
|
148
|
+
w?: number
|
|
149
|
+
h?: number
|
|
150
|
+
round?: boolean
|
|
151
|
+
shadow?: boolean
|
|
152
|
+
float?: boolean
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* El modificador de una imagen: `[img=200x100]`, `[img=round]`, `[img=shadow]`,
|
|
157
|
+
* `[img=float]`.
|
|
158
|
+
*
|
|
159
|
+
* Vive aquí y no en el renderizador porque es interpretación del ATRIBUTO, no
|
|
160
|
+
* de cómo se pinta: quien quiera respetar un `round` necesita este mismo
|
|
161
|
+
* significado, y hasta ahora el lienzo simplemente lo ignoraba.
|
|
162
|
+
*/
|
|
163
|
+
export function parseImgAttr(v: string | null): ImgAttr {
|
|
164
|
+
if (!v) return {}
|
|
165
|
+
const t = v.trim().toLowerCase()
|
|
166
|
+
if (t === 'round') return { round: true }
|
|
167
|
+
if (t === 'shadow') return { shadow: true }
|
|
168
|
+
if (t === 'float') return { float: true }
|
|
169
|
+
const m = /^(\d{1,4})x(\d{1,4})$/i.exec(t)
|
|
170
|
+
if (m) return { w: Math.min(2000, parseInt(m[1], 10)), h: Math.min(2000, parseInt(m[2], 10)) }
|
|
171
|
+
return {}
|
|
172
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
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
|
+
|
|
8
|
+
export interface DocumentTokens {
|
|
9
|
+
palette?: Record<string, string>
|
|
10
|
+
variables?: Record<string, string>
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export type TokenResolverFn = (name: string) => string | undefined
|
|
14
|
+
export type TokenSource = DocumentTokens | TokenResolverFn
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Normalizes a TokenSource into a TokenResolverFn.
|
|
18
|
+
*
|
|
19
|
+
* For DocumentTokens, checks palette[name] ?? variables[name], handling both
|
|
20
|
+
* with and without leading `$`.
|
|
21
|
+
* If source is already a function, passes it through.
|
|
22
|
+
*/
|
|
23
|
+
export function toTokenResolver(source?: TokenSource): TokenResolverFn | undefined {
|
|
24
|
+
if (!source) return undefined
|
|
25
|
+
if (typeof source === 'function') return source
|
|
26
|
+
|
|
27
|
+
return (name: string): string | undefined => {
|
|
28
|
+
const bare = name.startsWith('$') ? name.slice(1) : name
|
|
29
|
+
const dollar = '$' + bare
|
|
30
|
+
const palette = source.palette
|
|
31
|
+
const variables = source.variables
|
|
32
|
+
|
|
33
|
+
return (
|
|
34
|
+
palette?.[name] ??
|
|
35
|
+
palette?.[bare] ??
|
|
36
|
+
palette?.[dollar] ??
|
|
37
|
+
variables?.[name] ??
|
|
38
|
+
variables?.[bare] ??
|
|
39
|
+
variables?.[dollar]
|
|
40
|
+
)
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Resolves a token value if val starts with `$`.
|
|
46
|
+
* Strips `$` and looks up in resolver. If found, returns resolved value; otherwise returns val.
|
|
47
|
+
*/
|
|
48
|
+
export function resolveTokenValue(val: string, resolver?: TokenResolverFn): string {
|
|
49
|
+
if (!resolver || !val.startsWith('$')) {
|
|
50
|
+
return val
|
|
51
|
+
}
|
|
52
|
+
const tokenName = val.slice(1)
|
|
53
|
+
const resolved = resolver(tokenName) ?? resolver(val)
|
|
54
|
+
return resolved !== undefined ? resolved : val
|
|
55
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './TokenResolver'
|
package/src/Types/core.ts
CHANGED
|
@@ -92,8 +92,23 @@ export type NodeKind =
|
|
|
92
92
|
| 'grow'
|
|
93
93
|
| 'sinewave'
|
|
94
94
|
| 'rainbow'
|
|
95
|
+
| 'paint'
|
|
95
96
|
| 'spacing'
|
|
96
97
|
| 'empty_line'
|
|
98
|
+
/**
|
|
99
|
+
* Una etiqueta de cierre que no cerró nada y que no debe verse.
|
|
100
|
+
*
|
|
101
|
+
* Nace cuando un cierre llega tarde: su etiqueta ya se cerró sola porque un
|
|
102
|
+
* cierre anterior pasó por encima de ella (ver `Parser.ts`, modo legacy).
|
|
103
|
+
* osu! tira esos cierres, así que el renderer los omite.
|
|
104
|
+
*
|
|
105
|
+
* Existe como nodo, y no como texto, por dos razones. Conserva su rango, que
|
|
106
|
+
* es lo que necesita el parser incremental para saber a qué nodo pertenece
|
|
107
|
+
* cada carácter. Y el exportador puede saltárselo: escrito como texto volvía
|
|
108
|
+
* a salir por el otro lado convertido en etiqueta viva, y el documento no
|
|
109
|
+
* era estable al reexportarlo.
|
|
110
|
+
*/
|
|
111
|
+
| 'discarded_tag'
|
|
97
112
|
| 'group'
|
|
98
113
|
| 'wnotice'
|
|
99
114
|
| 'align'
|