@bendyline/squisq 2.1.0 → 2.2.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/LICENSE +21 -0
- package/NOTICE.md +24 -0
- package/dist/{ContentContainer-BXUlIf18.d.ts → ContentContainer-B2w9sUoL.d.ts} +15 -0
- package/dist/{Doc-DynJleo-.d.ts → Doc-BubIpWsp.d.ts} +1 -1
- package/dist/{ImageEditDoc-Ca4Tr9uN.d.ts → ImageEditDoc-CGxk5CHc.d.ts} +1 -1
- package/dist/{annotationCoercion-Dr_DY9Hx.d.ts → annotationCoercion-PtRQhk5V.d.ts} +1 -1
- package/dist/chunk-2L55443L.js +0 -0
- package/dist/{chunk-VWCJ2WXC.js → chunk-2ZWIXGAC.js} +0 -1
- package/dist/{chunk-VYFRI7R6.js → chunk-32R2RZAO.js} +72 -3
- package/dist/chunk-3IGPAPQ7.js +645 -0
- package/dist/{chunk-QE7TWGVT.js → chunk-4VOD55SX.js} +0 -1
- package/dist/{chunk-3E5F2XMR.js → chunk-67L6WRJN.js} +0 -1
- package/dist/{chunk-5DKBFXPY.js → chunk-6ECMNUIP.js} +26 -18
- package/dist/{chunk-JI77MGAK.js → chunk-7ARJZYQY.js} +159 -120
- package/dist/{chunk-DBS6RIFL.js → chunk-7N4G32LG.js} +0 -1
- package/dist/{chunk-JOQYPRDZ.js → chunk-7YEZFHLS.js} +10 -8
- package/dist/{chunk-2UQOHYE2.js → chunk-7ZAAICW4.js} +0 -1
- package/dist/{chunk-66QO7XFB.js → chunk-ACZOVWX3.js} +117 -7
- package/dist/{chunk-5J4HKRJF.js → chunk-BAOV476U.js} +0 -1
- package/dist/chunk-BCCXTMN5.js +699 -0
- package/dist/{chunk-JHZWYRSW.js → chunk-C33GTPUZ.js} +11 -4
- package/dist/{chunk-QUUPYOSP.js → chunk-CB45YGAM.js} +2 -3
- package/dist/{chunk-XNLB57UD.js → chunk-DYPMOPIW.js} +18 -2
- package/dist/{chunk-VR7UPJ7C.js → chunk-FCG3BIZN.js} +12 -1
- package/dist/{chunk-5UYI3RJB.js → chunk-FDYDYL77.js} +54 -40
- package/dist/{chunk-OTKVFVL6.js → chunk-I2O6W7DX.js} +116 -44
- package/dist/{chunk-Q7LROV2H.js → chunk-NKNMGIIN.js} +0 -1
- package/dist/chunk-OPO5K4DZ.js +241 -0
- package/dist/{chunk-TUWMK62B.js → chunk-PUS54YU6.js} +45 -2
- package/dist/chunk-QKPXHDLR.js +0 -0
- package/dist/{chunk-GZY66SDN.js → chunk-R3KTTOMS.js} +0 -1
- package/dist/{chunk-ILWDXLUK.js → chunk-RS5AP3J4.js} +49 -10
- package/dist/chunk-WV5ARNDA.js +0 -0
- package/dist/{chunk-4X3JQXNM.js → chunk-XOFT65EX.js} +1 -2
- package/dist/{chunk-FVTQSNR7.js → chunk-XRW6P7IF.js} +13 -5
- package/dist/chunk-XWNNA3KE.js +0 -0
- package/dist/chunk-YZNGMV3G.js +0 -0
- package/dist/{chunk-R2YZTCLO.js → chunk-ZQKZSJAX.js} +1 -2
- package/dist/doc/index.d.ts +27 -12
- package/dist/doc/index.js +16 -17
- package/dist/generate/index.d.ts +2 -2
- package/dist/generate/index.js +2 -3
- package/dist/icons/index.js +3 -4
- package/dist/icons/inlineIconMarker.js +1 -2
- package/dist/imageEdit/index.d.ts +48 -17
- package/dist/imageEdit/index.js +3 -4
- package/dist/index.d.ts +11 -11
- package/dist/index.js +60 -33
- package/dist/jsonForm/index.d.ts +10 -3
- package/dist/jsonForm/index.js +8 -7
- package/dist/markdown/index.d.ts +75 -11
- package/dist/markdown/index.js +32 -7
- package/dist/{materializePageSection-DDzubQXo.d.ts → materializePageSection-wSLA2A1g.d.ts} +2 -2
- package/dist/narration/index.d.ts +16 -3
- package/dist/narration/index.js +13 -14
- package/dist/random/index.d.ts +11 -2
- package/dist/random/index.js +2 -3
- package/dist/recommend/index.d.ts +1 -1
- package/dist/recommend/index.js +3 -4
- package/dist/schemas/index.d.ts +5 -5
- package/dist/schemas/index.js +5 -6
- package/dist/spatial/index.d.ts +2 -1
- package/dist/spatial/index.js +1 -2
- package/dist/storage/index.d.ts +4 -2
- package/dist/storage/index.js +1 -2
- package/dist/{themeLibrary-B72m0W1y.d.ts → themeLibrary-DU9mUmVl.d.ts} +1 -1
- package/dist/timing/index.js +3 -4
- package/dist/transform/index.d.ts +3 -3
- package/dist/transform/index.js +6 -7
- package/dist/{types-C4kiRn_k.d.ts → types-8QjefM9J.d.ts} +38 -2
- package/dist/{types-BwMPl2CB.d.ts → types-CUNc9biN.d.ts} +24 -1
- package/dist/versions/index.d.ts +14 -11
- package/dist/versions/index.js +2 -3
- package/package.json +4 -2
- package/dist/chunk-2UQOHYE2.js.map +0 -1
- package/dist/chunk-3E5F2XMR.js.map +0 -1
- package/dist/chunk-4X3JQXNM.js.map +0 -1
- package/dist/chunk-5DKBFXPY.js.map +0 -1
- package/dist/chunk-5J4HKRJF.js.map +0 -1
- package/dist/chunk-5UYI3RJB.js.map +0 -1
- package/dist/chunk-66QO7XFB.js.map +0 -1
- package/dist/chunk-AMIR72JP.js +0 -380
- package/dist/chunk-AMIR72JP.js.map +0 -1
- package/dist/chunk-DBS6RIFL.js.map +0 -1
- package/dist/chunk-DNJKBAI7.js +0 -1
- package/dist/chunk-DNJKBAI7.js.map +0 -1
- package/dist/chunk-ET53IIEP.js +0 -1
- package/dist/chunk-ET53IIEP.js.map +0 -1
- package/dist/chunk-FVTQSNR7.js.map +0 -1
- package/dist/chunk-GZY66SDN.js.map +0 -1
- package/dist/chunk-ILWDXLUK.js.map +0 -1
- package/dist/chunk-JHZWYRSW.js.map +0 -1
- package/dist/chunk-JI77MGAK.js.map +0 -1
- package/dist/chunk-JOQYPRDZ.js.map +0 -1
- package/dist/chunk-OTKVFVL6.js.map +0 -1
- package/dist/chunk-PGGGKYWG.js +0 -1
- package/dist/chunk-PGGGKYWG.js.map +0 -1
- package/dist/chunk-Q7LROV2H.js.map +0 -1
- package/dist/chunk-QE7TWGVT.js.map +0 -1
- package/dist/chunk-QUUPYOSP.js.map +0 -1
- package/dist/chunk-R2GC6RLD.js +0 -344
- package/dist/chunk-R2GC6RLD.js.map +0 -1
- package/dist/chunk-R2YZTCLO.js.map +0 -1
- package/dist/chunk-S7A5D7ZJ.js +0 -174
- package/dist/chunk-S7A5D7ZJ.js.map +0 -1
- package/dist/chunk-TUWMK62B.js.map +0 -1
- package/dist/chunk-V543AI2F.js +0 -1
- package/dist/chunk-V543AI2F.js.map +0 -1
- package/dist/chunk-VR7UPJ7C.js.map +0 -1
- package/dist/chunk-VWCJ2WXC.js.map +0 -1
- package/dist/chunk-VYFRI7R6.js.map +0 -1
- package/dist/chunk-XNLB57UD.js.map +0 -1
- package/dist/chunk-ZLQKNOZQ.js +0 -1
- package/dist/chunk-ZLQKNOZQ.js.map +0 -1
- package/dist/doc/index.js.map +0 -1
- package/dist/generate/index.js.map +0 -1
- package/dist/icons/index.js.map +0 -1
- package/dist/icons/inlineIconMarker.js.map +0 -1
- package/dist/imageEdit/index.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/jsonForm/index.js.map +0 -1
- package/dist/markdown/index.js.map +0 -1
- package/dist/narration/index.js.map +0 -1
- package/dist/random/index.js.map +0 -1
- package/dist/recommend/index.js.map +0 -1
- package/dist/schemas/index.js.map +0 -1
- package/dist/spatial/index.js.map +0 -1
- package/dist/storage/index.js.map +0 -1
- package/dist/timing/index.js.map +0 -1
- package/dist/transform/index.js.map +0 -1
- package/dist/versions/index.js.map +0 -1
- package/src/__tests__/animationUtils.test.ts +0 -117
- package/src/__tests__/annotationCoercion.test.ts +0 -243
- package/src/__tests__/applyNarrationTiming.test.ts +0 -190
- package/src/__tests__/applyRenderStyle.test.ts +0 -146
- package/src/__tests__/asciiDiagramBattle.test.ts +0 -246
- package/src/__tests__/asciiDiagramDetect.test.ts +0 -162
- package/src/__tests__/asciiDiagramMapping.test.ts +0 -38
- package/src/__tests__/asciiDiagramParse.test.ts +0 -233
- package/src/__tests__/asciiDiagramPipeline.test.ts +0 -273
- package/src/__tests__/asciiDiagramRender.test.ts +0 -162
- package/src/__tests__/asciiDiagramRepair.test.ts +0 -84
- package/src/__tests__/asciiTimelineDetect.test.ts +0 -157
- package/src/__tests__/asciiTimelineParse.test.ts +0 -205
- package/src/__tests__/asciiTimelinePipeline.test.ts +0 -349
- package/src/__tests__/asciiTimelineRender.test.ts +0 -376
- package/src/__tests__/atmosphereLayers.test.ts +0 -108
- package/src/__tests__/attrTokens.test.ts +0 -167
- package/src/__tests__/colorUtils.test.ts +0 -112
- package/src/__tests__/contentContainer.test.ts +0 -325
- package/src/__tests__/contentExtractor.test.ts +0 -243
- package/src/__tests__/coverBlock.test.ts +0 -310
- package/src/__tests__/customTemplateSample.test.ts +0 -144
- package/src/__tests__/customTemplatesFrontmatter.test.ts +0 -221
- package/src/__tests__/customThemesFrontmatter.test.ts +0 -146
- package/src/__tests__/dataTable.test.ts +0 -145
- package/src/__tests__/diagramBlock.test.ts +0 -122
- package/src/__tests__/diagramLayout.test.ts +0 -134
- package/src/__tests__/diagramText.test.ts +0 -26
- package/src/__tests__/docToMarkdownMedia.test.ts +0 -83
- package/src/__tests__/drawing.test.ts +0 -109
- package/src/__tests__/drawingBlock.test.ts +0 -124
- package/src/__tests__/drawingLayout.test.ts +0 -171
- package/src/__tests__/fixtures/asciiDiagramBattle.ts +0 -512
- package/src/__tests__/fixtures/asciiDiagrams.ts +0 -287
- package/src/__tests__/fixtures/asciiTimelines.ts +0 -35
- package/src/__tests__/fixtures/treeviewFixtures.ts +0 -243
- package/src/__tests__/geohash.test.ts +0 -110
- package/src/__tests__/getLayers.test.ts +0 -243
- package/src/__tests__/getLayersFallback.test.ts +0 -103
- package/src/__tests__/haversine.test.ts +0 -63
- package/src/__tests__/iconResolve.test.ts +0 -122
- package/src/__tests__/imageEditExportSvg.test.ts +0 -70
- package/src/__tests__/imageEditState.test.ts +0 -74
- package/src/__tests__/imageEditVersions.test.ts +0 -243
- package/src/__tests__/inferDocumentTitle.test.ts +0 -50
- package/src/__tests__/inlineIconMarker.test.ts +0 -36
- package/src/__tests__/inputDescriptors.test.ts +0 -162
- package/src/__tests__/jsonForm.chooseControl.test.ts +0 -86
- package/src/__tests__/jsonForm.evaluateWhen.test.ts +0 -59
- package/src/__tests__/jsonForm.inferSchema.test.ts +0 -25
- package/src/__tests__/jsonForm.pointer.test.ts +0 -149
- package/src/__tests__/jsonForm.tokens.test.ts +0 -84
- package/src/__tests__/layoutBlock.test.ts +0 -83
- package/src/__tests__/layoutLayout.test.ts +0 -169
- package/src/__tests__/localForageAdapter.test.ts +0 -155
- package/src/__tests__/majorApiTypes.test.ts +0 -18
- package/src/__tests__/markdown.test.ts +0 -1009
- package/src/__tests__/markdownIcons.test.ts +0 -104
- package/src/__tests__/markdownSanitize.test.ts +0 -81
- package/src/__tests__/markdownToDoc.test.ts +0 -957
- package/src/__tests__/matchFontFamily.test.ts +0 -114
- package/src/__tests__/materializeBlockLayers.test.ts +0 -167
- package/src/__tests__/materializePageSections.test.ts +0 -404
- package/src/__tests__/materializeTestUtils.ts +0 -17
- package/src/__tests__/mediaAnnotations.test.ts +0 -91
- package/src/__tests__/mediaSchedule.test.ts +0 -118
- package/src/__tests__/narrationAlign.test.ts +0 -150
- package/src/__tests__/narrationFeatures.test.ts +0 -71
- package/src/__tests__/narrationNuclei.test.ts +0 -45
- package/src/__tests__/narrationPacing.test.ts +0 -189
- package/src/__tests__/narrationScript.test.ts +0 -149
- package/src/__tests__/narrationSessionRepro.test.ts +0 -62
- package/src/__tests__/narrationSidecar.test.ts +0 -88
- package/src/__tests__/narrationSyllables.test.ts +0 -65
- package/src/__tests__/narrationTestSignals.ts +0 -167
- package/src/__tests__/narrationVad.test.ts +0 -66
- package/src/__tests__/pageStyle.test.ts +0 -258
- package/src/__tests__/pandocAttrParse.test.ts +0 -187
- package/src/__tests__/recommendTemplates.test.ts +0 -183
- package/src/__tests__/resolveDocTheme.test.ts +0 -69
- package/src/__tests__/rootExports.test.ts +0 -61
- package/src/__tests__/scopedContentContainer.test.ts +0 -109
- package/src/__tests__/seededRandom.test.ts +0 -142
- package/src/__tests__/shapeGeometry.test.ts +0 -138
- package/src/__tests__/shapeVocabulary.test.ts +0 -133
- package/src/__tests__/storage.test.ts +0 -60
- package/src/__tests__/structuredData.test.ts +0 -249
- package/src/__tests__/surface.test.ts +0 -68
- package/src/__tests__/templateAnnotationParse.test.ts +0 -173
- package/src/__tests__/templateInputs.test.ts +0 -69
- package/src/__tests__/templateMetadata.test.ts +0 -32
- package/src/__tests__/templates.test.ts +0 -710
- package/src/__tests__/themeCompile.test.ts +0 -225
- package/src/__tests__/themeValidator.test.ts +0 -131
- package/src/__tests__/timing.test.ts +0 -167
- package/src/__tests__/transformProvenance.test.ts +0 -160
- package/src/__tests__/transformV2.test.ts +0 -163
- package/src/__tests__/transitionNormalize.test.ts +0 -61
- package/src/__tests__/treeviewBattle.test.ts +0 -76
- package/src/__tests__/treeviewDetect.test.ts +0 -168
- package/src/__tests__/treeviewParse.test.ts +0 -118
- package/src/__tests__/treeviewPipeline.test.ts +0 -183
- package/src/__tests__/treeviewRender.test.ts +0 -91
- package/src/__tests__/validateDoc.test.ts +0 -260
- package/src/__tests__/versions.test.ts +0 -459
- package/src/doc/annotationBlocks.ts +0 -117
- package/src/doc/applyNarrationTiming.ts +0 -244
- package/src/doc/asciiDiagram/chars.ts +0 -210
- package/src/doc/asciiDiagram/detect.ts +0 -175
- package/src/doc/asciiDiagram/index.ts +0 -38
- package/src/doc/asciiDiagram/mapping.ts +0 -225
- package/src/doc/asciiDiagram/parse.ts +0 -1095
- package/src/doc/asciiDiagram/render.ts +0 -963
- package/src/doc/asciiDiagram/repair.ts +0 -400
- package/src/doc/asciiDiagram/types.ts +0 -65
- package/src/doc/asciiTimeline/detect.ts +0 -138
- package/src/doc/asciiTimeline/index.ts +0 -26
- package/src/doc/asciiTimeline/mapping.ts +0 -43
- package/src/doc/asciiTimeline/parse.ts +0 -870
- package/src/doc/asciiTimeline/render.ts +0 -427
- package/src/doc/asciiTimeline/types.ts +0 -73
- package/src/doc/asciiTimeline/wrappedFlow.ts +0 -427
- package/src/doc/audioMapping.ts +0 -442
- package/src/doc/customTemplatesFrontmatter.ts +0 -273
- package/src/doc/customThemesFrontmatter.ts +0 -95
- package/src/doc/docToMarkdown.ts +0 -284
- package/src/doc/index.ts +0 -161
- package/src/doc/markdownToDoc.ts +0 -1054
- package/src/doc/materializeBlockLayers.ts +0 -465
- package/src/doc/mediaAnnotations.ts +0 -120
- package/src/doc/page/PageSection.ts +0 -174
- package/src/doc/page/materializePageSection.ts +0 -616
- package/src/doc/page/resolvePageBlock.ts +0 -108
- package/src/doc/page/sectionExtractors.ts +0 -466
- package/src/doc/pageCss.ts +0 -628
- package/src/doc/resolveDocTheme.ts +0 -56
- package/src/doc/standaloneAnnotation.ts +0 -58
- package/src/doc/structuredData.ts +0 -301
- package/src/doc/templateInputs.ts +0 -424
- package/src/doc/templates/__tests__/customTemplate.test.ts +0 -170
- package/src/doc/templates/__tests__/customTemplateRegistry.test.ts +0 -124
- package/src/doc/templates/__tests__/listBlock.test.ts +0 -64
- package/src/doc/templates/accentImage.ts +0 -362
- package/src/doc/templates/captionUtils.ts +0 -56
- package/src/doc/templates/comparisonBar.ts +0 -173
- package/src/doc/templates/coverBlock.ts +0 -255
- package/src/doc/templates/customTemplate.ts +0 -51
- package/src/doc/templates/dataTable.ts +0 -102
- package/src/doc/templates/dateEvent.ts +0 -147
- package/src/doc/templates/definitionCard.ts +0 -140
- package/src/doc/templates/diagramBlock.ts +0 -403
- package/src/doc/templates/diagramLayout.ts +0 -159
- package/src/doc/templates/drawingBlock.ts +0 -325
- package/src/doc/templates/drawingLayout.ts +0 -539
- package/src/doc/templates/factCard.ts +0 -146
- package/src/doc/templates/fallbackBlock.ts +0 -123
- package/src/doc/templates/featureBlock.ts +0 -209
- package/src/doc/templates/fullBleedQuote.ts +0 -83
- package/src/doc/templates/imageWithCaption.ts +0 -186
- package/src/doc/templates/index.ts +0 -642
- package/src/doc/templates/inputDescriptors.ts +0 -451
- package/src/doc/templates/layoutBlock.ts +0 -43
- package/src/doc/templates/layoutLayout.ts +0 -243
- package/src/doc/templates/listBlock.ts +0 -207
- package/src/doc/templates/mapBlock.ts +0 -138
- package/src/doc/templates/metadata.ts +0 -130
- package/src/doc/templates/persistentLayers.ts +0 -526
- package/src/doc/templates/photoGrid.ts +0 -190
- package/src/doc/templates/pullQuote.ts +0 -141
- package/src/doc/templates/quoteBlock.ts +0 -141
- package/src/doc/templates/registry.ts +0 -88
- package/src/doc/templates/sectionHeader.ts +0 -120
- package/src/doc/templates/statHighlight.ts +0 -146
- package/src/doc/templates/templateNames.ts +0 -22
- package/src/doc/templates/timelineBlock.ts +0 -613
- package/src/doc/templates/titleBlock.ts +0 -150
- package/src/doc/templates/tokens/__tests__/resolveTokens.test.ts +0 -487
- package/src/doc/templates/tokens/resolveTokens.ts +0 -453
- package/src/doc/templates/treeBlock.ts +0 -131
- package/src/doc/templates/twoColumn.ts +0 -263
- package/src/doc/templates/videoPullQuote.ts +0 -142
- package/src/doc/templates/videoWithCaption.ts +0 -135
- package/src/doc/treeview/chars.ts +0 -72
- package/src/doc/treeview/detect.ts +0 -145
- package/src/doc/treeview/index.ts +0 -30
- package/src/doc/treeview/mapping.ts +0 -95
- package/src/doc/treeview/parse.ts +0 -201
- package/src/doc/treeview/render.ts +0 -41
- package/src/doc/treeview/types.ts +0 -43
- package/src/doc/utils/animationUtils.ts +0 -399
- package/src/doc/utils/applyRenderStyle.ts +0 -106
- package/src/doc/utils/diagramText.ts +0 -78
- package/src/doc/utils/imageTreatment.ts +0 -70
- package/src/doc/utils/nearest.ts +0 -59
- package/src/doc/utils/shapeGeometry.ts +0 -614
- package/src/doc/utils/themeUtils.ts +0 -243
- package/src/doc/validate.ts +0 -575
- package/src/generate/contentExtractor.ts +0 -921
- package/src/generate/index.ts +0 -18
- package/src/generate/templateMapper.ts +0 -177
- package/src/icons/iconData.ts +0 -31
- package/src/icons/index.ts +0 -26
- package/src/icons/inlineIconMarker.ts +0 -73
- package/src/icons/resolve.ts +0 -139
- package/src/imageEdit/ImageEditVersionManager.ts +0 -73
- package/src/imageEdit/export.ts +0 -410
- package/src/imageEdit/index.ts +0 -72
- package/src/imageEdit/persistence.ts +0 -113
- package/src/imageEdit/state.ts +0 -112
- package/src/imageEdit/versionPaths.ts +0 -44
- package/src/imageEdit/versions.ts +0 -152
- package/src/index.ts +0 -15
- package/src/internal/immutable.ts +0 -58
- package/src/jsonForm/chooseControl.ts +0 -88
- package/src/jsonForm/evaluateWhen.ts +0 -59
- package/src/jsonForm/index.ts +0 -32
- package/src/jsonForm/inferSchema.ts +0 -25
- package/src/jsonForm/pointer.ts +0 -154
- package/src/jsonForm/tokens.ts +0 -78
- package/src/jsonForm/types.ts +0 -167
- package/src/markdown/annotationCoercion.ts +0 -295
- package/src/markdown/attrTokens.ts +0 -243
- package/src/markdown/convert.ts +0 -1353
- package/src/markdown/htmlParse.ts +0 -212
- package/src/markdown/index.ts +0 -152
- package/src/markdown/parse.ts +0 -103
- package/src/markdown/sanitize.ts +0 -318
- package/src/markdown/stringify.ts +0 -207
- package/src/markdown/types.ts +0 -710
- package/src/markdown/utils.ts +0 -459
- package/src/narration/align.ts +0 -514
- package/src/narration/features.ts +0 -231
- package/src/narration/index.ts +0 -86
- package/src/narration/nuclei.ts +0 -118
- package/src/narration/pacing.ts +0 -211
- package/src/narration/script.ts +0 -239
- package/src/narration/session.ts +0 -100
- package/src/narration/sidecar.ts +0 -187
- package/src/narration/syllables.ts +0 -85
- package/src/narration/trace.ts +0 -50
- package/src/narration/types.ts +0 -299
- package/src/narration/vad.ts +0 -131
- package/src/ngeohash.d.ts +0 -11
- package/src/random/SeededRandom.ts +0 -127
- package/src/random/index.ts +0 -1
- package/src/recommend/index.ts +0 -16
- package/src/recommend/numberHighlight.ts +0 -25
- package/src/recommend/templates.ts +0 -393
- package/src/schemas/BlockTemplates.ts +0 -1046
- package/src/schemas/CustomTemplates.ts +0 -126
- package/src/schemas/Doc.ts +0 -1073
- package/src/schemas/ImageEditDoc.ts +0 -102
- package/src/schemas/LayoutStrategy.ts +0 -178
- package/src/schemas/Media.ts +0 -179
- package/src/schemas/MediaProvider.ts +0 -70
- package/src/schemas/PageStyle.ts +0 -213
- package/src/schemas/Theme.ts +0 -413
- package/src/schemas/Transitions.ts +0 -224
- package/src/schemas/Types.ts +0 -15
- package/src/schemas/Viewport.ts +0 -91
- package/src/schemas/colorUtils.ts +0 -219
- package/src/schemas/fontStacks.ts +0 -339
- package/src/schemas/index.ts +0 -31
- package/src/schemas/pageStyleDefaults.ts +0 -204
- package/src/schemas/themeCompile.ts +0 -244
- package/src/schemas/themeConstants.ts +0 -2
- package/src/schemas/themeLibrary.ts +0 -60
- package/src/schemas/themeValidator.ts +0 -609
- package/src/schemas/themes/bold.json +0 -77
- package/src/schemas/themes/cinematic.json +0 -143
- package/src/schemas/themes/documentary.json +0 -125
- package/src/schemas/themes/gezellig.json +0 -123
- package/src/schemas/themes/index.ts +0 -53
- package/src/schemas/themes/magazine.json +0 -126
- package/src/schemas/themes/minimalist.json +0 -74
- package/src/schemas/themes/morning-light.json +0 -117
- package/src/schemas/themes/standard-dark.json +0 -109
- package/src/schemas/themes/standard.json +0 -98
- package/src/schemas/themes/tech-dark.json +0 -143
- package/src/schemas/themes/warm-earth.json +0 -74
- package/src/spatial/Geohash.ts +0 -196
- package/src/spatial/Haversine.ts +0 -59
- package/src/spatial/index.ts +0 -2
- package/src/storage/ContentContainer.ts +0 -220
- package/src/storage/LocalForageAdapter.ts +0 -103
- package/src/storage/LocalStorageAdapter.ts +0 -57
- package/src/storage/MediaProviderFromContainer.ts +0 -92
- package/src/storage/MemoryStorageAdapter.ts +0 -37
- package/src/storage/ScopedContentContainer.ts +0 -143
- package/src/storage/Storage.ts +0 -28
- package/src/storage/index.ts +0 -9
- package/src/timing/index.ts +0 -17
- package/src/timing/narrationTiming.ts +0 -220
- package/src/timing/readingTime.ts +0 -94
- package/src/transform/applyTransform.ts +0 -122
- package/src/transform/blockAnalyzer.ts +0 -181
- package/src/transform/index.ts +0 -23
- package/src/transform/registry.ts +0 -217
- package/src/transform/styles/dataDriven.ts +0 -18
- package/src/transform/styles/documentary.ts +0 -18
- package/src/transform/styles/index.ts +0 -5
- package/src/transform/styles/magazine.ts +0 -19
- package/src/transform/styles/minimal.ts +0 -18
- package/src/transform/styles/narrative.ts +0 -19
- package/src/transform/templateSelector.ts +0 -389
- package/src/transform/timingAllocator.ts +0 -257
- package/src/transform/types.ts +0 -158
- package/src/versions/DocumentVersionManager.ts +0 -70
- package/src/versions/gitignore.ts +0 -34
- package/src/versions/index.ts +0 -56
- package/src/versions/operations.ts +0 -144
- package/src/versions/paths.ts +0 -51
- package/src/versions/snapshotStore.ts +0 -202
- package/src/versions/timestamp.ts +0 -48
- package/src/versions/types.ts +0 -93
|
@@ -0,0 +1,645 @@
|
|
|
1
|
+
import {
|
|
2
|
+
assertMarkdownDocumentWithinLimits,
|
|
3
|
+
toMdast
|
|
4
|
+
} from "./chunk-ACZOVWX3.js";
|
|
5
|
+
import {
|
|
6
|
+
formatFrontmatterYaml
|
|
7
|
+
} from "./chunk-BCCXTMN5.js";
|
|
8
|
+
|
|
9
|
+
// src/markdown/stringify.ts
|
|
10
|
+
import { unified } from "unified";
|
|
11
|
+
import remarkStringify from "remark-stringify";
|
|
12
|
+
import remarkGfm from "remark-gfm";
|
|
13
|
+
import remarkMath from "remark-math";
|
|
14
|
+
import remarkDirective from "remark-directive";
|
|
15
|
+
var defaultProcessor;
|
|
16
|
+
var DQ_RUN = `"(?:[^"\\\\]|\\\\.)*"`;
|
|
17
|
+
var SQ_RUN = `'(?:[^'\\\\]|\\\\.)*'`;
|
|
18
|
+
var ESCAPED_TEMPLATE_SPAN_RE = new RegExp(
|
|
19
|
+
`\\{\\\\\\[((?:${DQ_RUN}|${SQ_RUN}|\\\\.|[^\\]\\\\])*)\\]\\}`,
|
|
20
|
+
"g"
|
|
21
|
+
);
|
|
22
|
+
var HEADING_LINE_RE = /^#{1,6} .*$/gm;
|
|
23
|
+
var TRAILING_ESCAPED_PANDOC_SPAN_RE = new RegExp(
|
|
24
|
+
`\\{(?!\\\\?\\[)((?:${DQ_RUN}|${SQ_RUN}|\\\\.|[^}\\\\])*)\\}(?=\\s*(?:\\{\\[.*)?$)`
|
|
25
|
+
);
|
|
26
|
+
var UNESCAPE_PUNCT_RE = /\\([\\[\]:#.,+=/?;@%$(){}'"-])/g;
|
|
27
|
+
function unescapeMarkdownPunct(text) {
|
|
28
|
+
return text.replace(UNESCAPE_PUNCT_RE, "$1");
|
|
29
|
+
}
|
|
30
|
+
var PREFERRED_MASK_SENTINEL = "\0";
|
|
31
|
+
function pickMaskSentinel(text) {
|
|
32
|
+
const present = new Set(text);
|
|
33
|
+
if (!present.has(PREFERRED_MASK_SENTINEL)) return PREFERRED_MASK_SENTINEL;
|
|
34
|
+
for (let cp = 57344; cp <= 63743; cp++) {
|
|
35
|
+
const ch = String.fromCodePoint(cp);
|
|
36
|
+
if (!present.has(ch)) return ch;
|
|
37
|
+
}
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
var FENCE_OPEN_RE = /^([ \t]*)(`{3,}|~{3,})(.*)$/;
|
|
41
|
+
function findFencedRanges(text) {
|
|
42
|
+
const ranges = [];
|
|
43
|
+
let offset = 0;
|
|
44
|
+
let open = null;
|
|
45
|
+
for (const line of text.split("\n")) {
|
|
46
|
+
const lineEnd = offset + line.length;
|
|
47
|
+
if (open) {
|
|
48
|
+
const close = /^([ \t]*)(`{3,}|~{3,})[ \t]*$/.exec(line);
|
|
49
|
+
if (close && close[2][0] === open.marker && close[2].length >= open.length && close[1].length <= open.indent + 3) {
|
|
50
|
+
ranges.push([open.start, lineEnd]);
|
|
51
|
+
open = null;
|
|
52
|
+
}
|
|
53
|
+
} else {
|
|
54
|
+
const match = FENCE_OPEN_RE.exec(line);
|
|
55
|
+
if (match && !(match[2][0] === "`" && match[3].includes("`"))) {
|
|
56
|
+
open = {
|
|
57
|
+
marker: match[2][0],
|
|
58
|
+
length: match[2].length,
|
|
59
|
+
indent: match[1].length,
|
|
60
|
+
start: offset
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
offset = lineEnd + 1;
|
|
65
|
+
}
|
|
66
|
+
if (open) ranges.push([open.start, text.length]);
|
|
67
|
+
return ranges;
|
|
68
|
+
}
|
|
69
|
+
function isEscapedAt(text, i) {
|
|
70
|
+
let slashes = 0;
|
|
71
|
+
for (let k = i - 1; k >= 0 && text[k] === "\\"; k--) slashes++;
|
|
72
|
+
return slashes % 2 === 1;
|
|
73
|
+
}
|
|
74
|
+
function findInlineCodeRanges(text, from, to) {
|
|
75
|
+
const ranges = [];
|
|
76
|
+
let i = from;
|
|
77
|
+
while (i < to) {
|
|
78
|
+
if (text[i] !== "`" || isEscapedAt(text, i)) {
|
|
79
|
+
i++;
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
let openEnd = i;
|
|
83
|
+
while (openEnd < to && text[openEnd] === "`") openEnd++;
|
|
84
|
+
const runLength = openEnd - i;
|
|
85
|
+
let j = openEnd;
|
|
86
|
+
let closed = -1;
|
|
87
|
+
while (j < to) {
|
|
88
|
+
if (text[j] !== "`") {
|
|
89
|
+
j++;
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
let runEnd = j;
|
|
93
|
+
while (runEnd < to && text[runEnd] === "`") runEnd++;
|
|
94
|
+
if (runEnd - j === runLength) {
|
|
95
|
+
closed = runEnd;
|
|
96
|
+
break;
|
|
97
|
+
}
|
|
98
|
+
j = runEnd;
|
|
99
|
+
}
|
|
100
|
+
if (closed === -1) {
|
|
101
|
+
i = openEnd;
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
104
|
+
ranges.push([i, closed]);
|
|
105
|
+
i = closed;
|
|
106
|
+
}
|
|
107
|
+
return ranges;
|
|
108
|
+
}
|
|
109
|
+
function transformOutsideCode(text, transform) {
|
|
110
|
+
const fenced = findFencedRanges(text);
|
|
111
|
+
const ranges = [];
|
|
112
|
+
let cursor = 0;
|
|
113
|
+
for (const [start, end] of fenced) {
|
|
114
|
+
ranges.push(...findInlineCodeRanges(text, cursor, start));
|
|
115
|
+
ranges.push([start, end]);
|
|
116
|
+
cursor = end;
|
|
117
|
+
}
|
|
118
|
+
ranges.push(...findInlineCodeRanges(text, cursor, text.length));
|
|
119
|
+
if (ranges.length === 0) return transform(text);
|
|
120
|
+
const sentinel = pickMaskSentinel(text);
|
|
121
|
+
if (sentinel === null) return text;
|
|
122
|
+
const protectedText = [];
|
|
123
|
+
let masked = "";
|
|
124
|
+
let last = 0;
|
|
125
|
+
for (const [start, end] of ranges) {
|
|
126
|
+
masked += text.slice(last, start);
|
|
127
|
+
masked += `${sentinel}${protectedText.length}${sentinel}`;
|
|
128
|
+
protectedText.push(text.slice(start, end));
|
|
129
|
+
last = end;
|
|
130
|
+
}
|
|
131
|
+
masked += text.slice(last);
|
|
132
|
+
return transform(masked).replace(
|
|
133
|
+
new RegExp(`${sentinel}(\\d+)${sentinel}`, "g"),
|
|
134
|
+
(_m, index) => protectedText[Number(index)]
|
|
135
|
+
);
|
|
136
|
+
}
|
|
137
|
+
function stringifyMarkdown(doc, options) {
|
|
138
|
+
options?.signal?.throwIfAborted();
|
|
139
|
+
assertMarkdownDocumentWithinLimits(doc, options?.limits, options?.signal);
|
|
140
|
+
const mdastTree = toMdast(doc);
|
|
141
|
+
const useDefaults = !options || options.gfm !== false && options.math !== false && options.directive !== false && !options.bullet && !options.bulletOrdered && !options.emphasis && !options.strong && !options.rule && !options.fence && options.setext == null;
|
|
142
|
+
let processor;
|
|
143
|
+
if (useDefaults) {
|
|
144
|
+
if (!defaultProcessor) {
|
|
145
|
+
defaultProcessor = unified().use(remarkGfm).use(remarkMath).use(remarkDirective).use(remarkStringify, {
|
|
146
|
+
bullet: "-",
|
|
147
|
+
bulletOrdered: ".",
|
|
148
|
+
emphasis: "*",
|
|
149
|
+
strong: "*",
|
|
150
|
+
rule: "-",
|
|
151
|
+
fence: "`",
|
|
152
|
+
setext: false
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
processor = defaultProcessor;
|
|
156
|
+
} else {
|
|
157
|
+
processor = unified();
|
|
158
|
+
if (options?.gfm !== false) {
|
|
159
|
+
processor = processor.use(remarkGfm);
|
|
160
|
+
}
|
|
161
|
+
if (options?.math !== false) {
|
|
162
|
+
processor = processor.use(remarkMath);
|
|
163
|
+
}
|
|
164
|
+
if (options?.directive !== false) {
|
|
165
|
+
processor = processor.use(remarkDirective);
|
|
166
|
+
}
|
|
167
|
+
processor = processor.use(remarkStringify, {
|
|
168
|
+
bullet: options?.bullet ?? "-",
|
|
169
|
+
bulletOrdered: options?.bulletOrdered ?? ".",
|
|
170
|
+
emphasis: options?.emphasis ?? "*",
|
|
171
|
+
strong: options?.strong ?? "*",
|
|
172
|
+
rule: options?.rule ?? "-",
|
|
173
|
+
fence: options?.fence ?? "`",
|
|
174
|
+
setext: options?.setext ?? false
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
const result = processor.stringify(mdastTree);
|
|
178
|
+
const cleaned = transformOutsideCode(result, (text) => {
|
|
179
|
+
let out = text.replace(
|
|
180
|
+
ESCAPED_TEMPLATE_SPAN_RE,
|
|
181
|
+
(_m, inner) => `{[${unescapeMarkdownPunct(inner)}]}`
|
|
182
|
+
);
|
|
183
|
+
out = out.replace(
|
|
184
|
+
HEADING_LINE_RE,
|
|
185
|
+
(line) => line.replace(
|
|
186
|
+
TRAILING_ESCAPED_PANDOC_SPAN_RE,
|
|
187
|
+
(_m, inner) => `{${unescapeMarkdownPunct(inner)}}`
|
|
188
|
+
)
|
|
189
|
+
);
|
|
190
|
+
return out.replace(/\{(?!\\?\[)[^}]*\}/g, (match) => match.replace(/\\:/g, ":"));
|
|
191
|
+
});
|
|
192
|
+
if (doc.frontmatter && Object.keys(doc.frontmatter).length > 0) {
|
|
193
|
+
const yaml = formatFrontmatterYaml(doc.frontmatter);
|
|
194
|
+
if (yaml) return `---
|
|
195
|
+
${yaml}
|
|
196
|
+
---
|
|
197
|
+
|
|
198
|
+
${cleaned}`;
|
|
199
|
+
}
|
|
200
|
+
return cleaned;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// src/markdown/sanitize.ts
|
|
204
|
+
var SAFE_LINK_SCHEMES = /* @__PURE__ */ new Set(["http", "https", "mailto", "tel"]);
|
|
205
|
+
var SAFE_MEDIA_SCHEMES = /* @__PURE__ */ new Set(["http", "https", "blob"]);
|
|
206
|
+
var NEVER_ALLOWED_SCHEMES = /* @__PURE__ */ new Set(["javascript", "vbscript", "data"]);
|
|
207
|
+
var SAFE_DATA_MEDIA_RE = /^data:(?:image\/(?!svg\+xml)[a-z0-9.+-]+|audio\/[a-z0-9.+-]+|video\/[a-z0-9.+-]+);/i;
|
|
208
|
+
var SAFE_TAGS = /* @__PURE__ */ new Set([
|
|
209
|
+
"a",
|
|
210
|
+
"abbr",
|
|
211
|
+
"b",
|
|
212
|
+
"blockquote",
|
|
213
|
+
"br",
|
|
214
|
+
"caption",
|
|
215
|
+
"cite",
|
|
216
|
+
"code",
|
|
217
|
+
"col",
|
|
218
|
+
"colgroup",
|
|
219
|
+
"data",
|
|
220
|
+
"dd",
|
|
221
|
+
"del",
|
|
222
|
+
"details",
|
|
223
|
+
"dfn",
|
|
224
|
+
"div",
|
|
225
|
+
"dl",
|
|
226
|
+
"dt",
|
|
227
|
+
"em",
|
|
228
|
+
"figcaption",
|
|
229
|
+
"figure",
|
|
230
|
+
"h1",
|
|
231
|
+
"h2",
|
|
232
|
+
"h3",
|
|
233
|
+
"h4",
|
|
234
|
+
"h5",
|
|
235
|
+
"h6",
|
|
236
|
+
"hr",
|
|
237
|
+
"i",
|
|
238
|
+
"img",
|
|
239
|
+
"kbd",
|
|
240
|
+
"li",
|
|
241
|
+
"mark",
|
|
242
|
+
"ol",
|
|
243
|
+
"p",
|
|
244
|
+
"pre",
|
|
245
|
+
"q",
|
|
246
|
+
"s",
|
|
247
|
+
"samp",
|
|
248
|
+
"small",
|
|
249
|
+
"source",
|
|
250
|
+
"span",
|
|
251
|
+
"strong",
|
|
252
|
+
"sub",
|
|
253
|
+
"summary",
|
|
254
|
+
"sup",
|
|
255
|
+
"table",
|
|
256
|
+
"tbody",
|
|
257
|
+
"td",
|
|
258
|
+
"tfoot",
|
|
259
|
+
"th",
|
|
260
|
+
"thead",
|
|
261
|
+
"time",
|
|
262
|
+
"tr",
|
|
263
|
+
"track",
|
|
264
|
+
"u",
|
|
265
|
+
"ul",
|
|
266
|
+
"var",
|
|
267
|
+
"video",
|
|
268
|
+
"audio"
|
|
269
|
+
]);
|
|
270
|
+
var DROP_WITH_CONTENT_TAGS = /* @__PURE__ */ new Set([
|
|
271
|
+
"base",
|
|
272
|
+
"button",
|
|
273
|
+
"embed",
|
|
274
|
+
"form",
|
|
275
|
+
"iframe",
|
|
276
|
+
"input",
|
|
277
|
+
"link",
|
|
278
|
+
"meta",
|
|
279
|
+
"object",
|
|
280
|
+
"option",
|
|
281
|
+
"script",
|
|
282
|
+
"select",
|
|
283
|
+
"style",
|
|
284
|
+
"svg",
|
|
285
|
+
"template",
|
|
286
|
+
"textarea"
|
|
287
|
+
]);
|
|
288
|
+
var GLOBAL_ATTRS = /* @__PURE__ */ new Set(["class", "id", "title", "role"]);
|
|
289
|
+
var TAG_ATTRS = {
|
|
290
|
+
a: /* @__PURE__ */ new Set(["href", "target", "rel"]),
|
|
291
|
+
audio: /* @__PURE__ */ new Set(["src", "controls", "preload", "muted", "loop"]),
|
|
292
|
+
col: /* @__PURE__ */ new Set(["span", "width"]),
|
|
293
|
+
colgroup: /* @__PURE__ */ new Set(["span"]),
|
|
294
|
+
data: /* @__PURE__ */ new Set(["value"]),
|
|
295
|
+
img: /* @__PURE__ */ new Set(["src", "alt", "width", "height", "loading", "decoding"]),
|
|
296
|
+
li: /* @__PURE__ */ new Set(["value"]),
|
|
297
|
+
ol: /* @__PURE__ */ new Set(["start", "type"]),
|
|
298
|
+
q: /* @__PURE__ */ new Set(["cite"]),
|
|
299
|
+
source: /* @__PURE__ */ new Set(["src", "type", "media"]),
|
|
300
|
+
td: /* @__PURE__ */ new Set(["colspan", "rowspan", "align"]),
|
|
301
|
+
th: /* @__PURE__ */ new Set(["colspan", "rowspan", "align", "scope"]),
|
|
302
|
+
time: /* @__PURE__ */ new Set(["datetime"]),
|
|
303
|
+
track: /* @__PURE__ */ new Set(["src", "kind", "label", "srclang", "default"]),
|
|
304
|
+
video: /* @__PURE__ */ new Set([
|
|
305
|
+
"src",
|
|
306
|
+
"poster",
|
|
307
|
+
"width",
|
|
308
|
+
"height",
|
|
309
|
+
"controls",
|
|
310
|
+
"preload",
|
|
311
|
+
"muted",
|
|
312
|
+
"loop",
|
|
313
|
+
"playsinline"
|
|
314
|
+
])
|
|
315
|
+
};
|
|
316
|
+
var SAFE_ATTR_NAME_RE = /^[a-z][a-z0-9:_.-]*$/;
|
|
317
|
+
var SAFE_OL_TYPES = /* @__PURE__ */ new Set(["1", "a", "A", "i", "I"]);
|
|
318
|
+
var SAFE_PRELOAD_VALUES = /* @__PURE__ */ new Set(["none", "metadata", "auto"]);
|
|
319
|
+
var SAFE_TRACK_KINDS = /* @__PURE__ */ new Set(["subtitles", "captions", "descriptions", "chapters", "metadata"]);
|
|
320
|
+
function sanitizeUrl(url, kind = "link", options) {
|
|
321
|
+
if (typeof url !== "string") return null;
|
|
322
|
+
const trimmed = url.trim();
|
|
323
|
+
if (!trimmed) return null;
|
|
324
|
+
const compact = stripUrlSchemeNoise(trimmed);
|
|
325
|
+
const colon = compact.indexOf(":");
|
|
326
|
+
const firstPathChar = firstIndexOfAny(compact, ["/", "?", "#"]);
|
|
327
|
+
const hasScheme = colon >= 0 && (firstPathChar < 0 || colon < firstPathChar);
|
|
328
|
+
if (!hasScheme) return trimmed;
|
|
329
|
+
const scheme = compact.slice(0, colon).toLowerCase();
|
|
330
|
+
if (kind === "media") {
|
|
331
|
+
if (scheme === "data") return SAFE_DATA_MEDIA_RE.test(compact) ? trimmed : null;
|
|
332
|
+
return SAFE_MEDIA_SCHEMES.has(scheme) ? trimmed : null;
|
|
333
|
+
}
|
|
334
|
+
if (SAFE_LINK_SCHEMES.has(scheme)) return trimmed;
|
|
335
|
+
if (options?.extraLinkSchemes?.includes(scheme) && !NEVER_ALLOWED_SCHEMES.has(scheme)) {
|
|
336
|
+
return trimmed;
|
|
337
|
+
}
|
|
338
|
+
return null;
|
|
339
|
+
}
|
|
340
|
+
function sanitizeHtmlNodes(nodes) {
|
|
341
|
+
const out = [];
|
|
342
|
+
for (const node of nodes) {
|
|
343
|
+
out.push(...sanitizeHtmlNode(node));
|
|
344
|
+
}
|
|
345
|
+
return out;
|
|
346
|
+
}
|
|
347
|
+
function sanitizeHtmlNode(node) {
|
|
348
|
+
switch (node.type) {
|
|
349
|
+
case "htmlText":
|
|
350
|
+
return [node];
|
|
351
|
+
case "htmlComment":
|
|
352
|
+
return [];
|
|
353
|
+
case "htmlElement":
|
|
354
|
+
return sanitizeHtmlElement(node);
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
function sanitizeHtmlElement(node) {
|
|
358
|
+
const tag = node.tagName.toLowerCase();
|
|
359
|
+
if (DROP_WITH_CONTENT_TAGS.has(tag)) return [];
|
|
360
|
+
const children = sanitizeHtmlNodes(node.children);
|
|
361
|
+
if (!SAFE_TAGS.has(tag)) return children;
|
|
362
|
+
return [
|
|
363
|
+
{
|
|
364
|
+
type: "htmlElement",
|
|
365
|
+
tagName: tag,
|
|
366
|
+
attributes: sanitizeAttrs(tag, node.attributes),
|
|
367
|
+
children,
|
|
368
|
+
selfClosing: node.selfClosing
|
|
369
|
+
}
|
|
370
|
+
];
|
|
371
|
+
}
|
|
372
|
+
function sanitizeAttrs(tag, attrs) {
|
|
373
|
+
const out = {};
|
|
374
|
+
for (const [rawName, rawValue] of Object.entries(attrs)) {
|
|
375
|
+
const name = rawName.toLowerCase();
|
|
376
|
+
if (!isAllowedAttr(tag, name)) continue;
|
|
377
|
+
const value = String(rawValue);
|
|
378
|
+
const safeValue = sanitizeAttrValue(tag, name, value);
|
|
379
|
+
if (safeValue === null) continue;
|
|
380
|
+
out[name] = safeValue;
|
|
381
|
+
}
|
|
382
|
+
if (tag === "a" && out.target === "_blank") {
|
|
383
|
+
out.rel = ensureRelTokens(out.rel, ["noopener", "noreferrer"]);
|
|
384
|
+
}
|
|
385
|
+
return out;
|
|
386
|
+
}
|
|
387
|
+
function isAllowedAttr(tag, name) {
|
|
388
|
+
if (!SAFE_ATTR_NAME_RE.test(name)) return false;
|
|
389
|
+
if (name.startsWith("on")) return false;
|
|
390
|
+
if (name.startsWith("aria-") || name.startsWith("data-")) return true;
|
|
391
|
+
if (GLOBAL_ATTRS.has(name)) return true;
|
|
392
|
+
return TAG_ATTRS[tag]?.has(name) ?? false;
|
|
393
|
+
}
|
|
394
|
+
function sanitizeAttrValue(tag, name, value) {
|
|
395
|
+
if (name === "href") return sanitizeUrl(value, "link");
|
|
396
|
+
if (name === "src" || name === "poster") return sanitizeUrl(value, "media");
|
|
397
|
+
if ((name === "width" || name === "height" || name === "span" || name === "colspan" || name === "rowspan" || name === "value") && !isNonNegativeInteger(value)) {
|
|
398
|
+
return null;
|
|
399
|
+
}
|
|
400
|
+
if (name === "start" && !isInteger(value)) return null;
|
|
401
|
+
if (name === "type" && tag === "ol" && !SAFE_OL_TYPES.has(value)) return null;
|
|
402
|
+
if (name === "preload" && !SAFE_PRELOAD_VALUES.has(value)) return null;
|
|
403
|
+
if (name === "kind" && tag === "track" && !SAFE_TRACK_KINDS.has(value)) return null;
|
|
404
|
+
if (name === "align" && value !== "left" && value !== "right" && value !== "center") return null;
|
|
405
|
+
if (name === "target")
|
|
406
|
+
return value === "_blank" || value === "_self" || value === "_parent" || value === "_top" ? value : null;
|
|
407
|
+
if (name === "rel") return sanitizeRel(value);
|
|
408
|
+
return value;
|
|
409
|
+
}
|
|
410
|
+
function sanitizeRel(value) {
|
|
411
|
+
return relTokens(value).join(" ");
|
|
412
|
+
}
|
|
413
|
+
function ensureRelTokens(value, required) {
|
|
414
|
+
const tokens = new Set(value ? relTokens(value) : []);
|
|
415
|
+
for (const token of required) tokens.add(token);
|
|
416
|
+
return Array.from(tokens).join(" ");
|
|
417
|
+
}
|
|
418
|
+
function relTokens(value) {
|
|
419
|
+
const tokens = value.split(/\s+/).map((token) => token.trim().toLowerCase()).filter(Boolean).filter((token) => /^[a-z0-9_-]+$/.test(token));
|
|
420
|
+
return Array.from(new Set(tokens));
|
|
421
|
+
}
|
|
422
|
+
function isInteger(value) {
|
|
423
|
+
return /^-?\d+$/.test(value.trim());
|
|
424
|
+
}
|
|
425
|
+
function isNonNegativeInteger(value) {
|
|
426
|
+
return /^\d+$/.test(value.trim());
|
|
427
|
+
}
|
|
428
|
+
function firstIndexOfAny(value, needles) {
|
|
429
|
+
let result = -1;
|
|
430
|
+
for (const needle of needles) {
|
|
431
|
+
const index = value.indexOf(needle);
|
|
432
|
+
if (index >= 0 && (result < 0 || index < result)) result = index;
|
|
433
|
+
}
|
|
434
|
+
return result;
|
|
435
|
+
}
|
|
436
|
+
function stripUrlSchemeNoise(value) {
|
|
437
|
+
let out = "";
|
|
438
|
+
for (const char of value) {
|
|
439
|
+
const code = char.charCodeAt(0);
|
|
440
|
+
if (code <= 32 || code === 127 || char.trim() === "") continue;
|
|
441
|
+
out += char;
|
|
442
|
+
}
|
|
443
|
+
return out;
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
// src/markdown/resourcePolicy.ts
|
|
447
|
+
var DEFAULT_RESOURCE_MAX_BYTES = 64 * 1024 * 1024;
|
|
448
|
+
var DEFAULT_RESOURCE_TIMEOUT_MS = 15e3;
|
|
449
|
+
var DEFAULT_INTERACTIVE_RESOURCE_POLICY = Object.freeze({
|
|
450
|
+
allowRemote: true,
|
|
451
|
+
allowRelative: true,
|
|
452
|
+
allowBlob: true,
|
|
453
|
+
allowData: true,
|
|
454
|
+
allowedHosts: Object.freeze([]),
|
|
455
|
+
maxBytes: DEFAULT_RESOURCE_MAX_BYTES,
|
|
456
|
+
timeoutMs: DEFAULT_RESOURCE_TIMEOUT_MS
|
|
457
|
+
});
|
|
458
|
+
var LOCAL_ONLY_RESOURCE_POLICY = Object.freeze({
|
|
459
|
+
allowRemote: false,
|
|
460
|
+
allowRelative: true,
|
|
461
|
+
allowBlob: true,
|
|
462
|
+
allowData: true,
|
|
463
|
+
allowedHosts: Object.freeze([]),
|
|
464
|
+
maxBytes: DEFAULT_RESOURCE_MAX_BYTES,
|
|
465
|
+
timeoutMs: DEFAULT_RESOURCE_TIMEOUT_MS
|
|
466
|
+
});
|
|
467
|
+
var ResourcePolicyError = class extends Error {
|
|
468
|
+
constructor(code, message) {
|
|
469
|
+
super(message);
|
|
470
|
+
this.name = "ResourcePolicyError";
|
|
471
|
+
this.code = code;
|
|
472
|
+
}
|
|
473
|
+
};
|
|
474
|
+
function isResourceUrlAllowed(input, policy = DEFAULT_INTERACTIVE_RESOURCE_POLICY) {
|
|
475
|
+
if (typeof input !== "string") return false;
|
|
476
|
+
const value = input.trim();
|
|
477
|
+
if (!value || hasUrlControlCharacters(value)) return false;
|
|
478
|
+
const resolved = resolvePolicy(policy);
|
|
479
|
+
if (value.startsWith("\\\\")) return false;
|
|
480
|
+
if (value.startsWith("//")) {
|
|
481
|
+
if (!resolved.allowRemote) return false;
|
|
482
|
+
return hostAllowed(parseUrl(`https:${value}`), resolved.allowedHosts);
|
|
483
|
+
}
|
|
484
|
+
const schemeMatch = /^([a-z][a-z0-9+.-]*):/i.exec(value);
|
|
485
|
+
if (!schemeMatch) return resolved.allowRelative;
|
|
486
|
+
const scheme = schemeMatch[1].toLowerCase();
|
|
487
|
+
if (scheme === "blob") return resolved.allowBlob;
|
|
488
|
+
if (scheme === "data") return resolved.allowData && isSafeMediaDataUrl(value);
|
|
489
|
+
if (scheme !== "http" && scheme !== "https") return false;
|
|
490
|
+
if (!resolved.allowRemote) return false;
|
|
491
|
+
return hostAllowed(parseUrl(value), resolved.allowedHosts);
|
|
492
|
+
}
|
|
493
|
+
async function fetchResourceBytes(input, options = {}) {
|
|
494
|
+
const policy = resolvePolicy(options.policy);
|
|
495
|
+
if (!isResourceUrlAllowed(input, policy)) {
|
|
496
|
+
throw new ResourcePolicyError(
|
|
497
|
+
"RESOURCE_BLOCKED",
|
|
498
|
+
`Resource URL is blocked by policy: ${input}`
|
|
499
|
+
);
|
|
500
|
+
}
|
|
501
|
+
const fetchImpl = options.fetch ?? globalThis.fetch;
|
|
502
|
+
if (typeof fetchImpl !== "function") {
|
|
503
|
+
throw new Error("fetchResourceBytes requires a fetch implementation");
|
|
504
|
+
}
|
|
505
|
+
const controller = new AbortController();
|
|
506
|
+
let timedOut = false;
|
|
507
|
+
const onAbort = () => controller.abort(options.signal?.reason);
|
|
508
|
+
if (options.signal?.aborted) onAbort();
|
|
509
|
+
else options.signal?.addEventListener("abort", onAbort, { once: true });
|
|
510
|
+
const timeout = setTimeout(() => {
|
|
511
|
+
timedOut = true;
|
|
512
|
+
controller.abort();
|
|
513
|
+
}, policy.timeoutMs);
|
|
514
|
+
try {
|
|
515
|
+
const response = await fetchImpl(input, {
|
|
516
|
+
signal: controller.signal,
|
|
517
|
+
credentials: "omit",
|
|
518
|
+
redirect: "follow",
|
|
519
|
+
referrerPolicy: "no-referrer"
|
|
520
|
+
});
|
|
521
|
+
if (!response.ok) throw new Error(`Resource request failed with HTTP ${response.status}`);
|
|
522
|
+
const finalUrl = response.url || input;
|
|
523
|
+
if (!isResourceUrlAllowed(finalUrl, policy)) {
|
|
524
|
+
throw new ResourcePolicyError(
|
|
525
|
+
"RESOURCE_BLOCKED",
|
|
526
|
+
`Resource redirect destination is blocked by policy: ${finalUrl}`
|
|
527
|
+
);
|
|
528
|
+
}
|
|
529
|
+
const contentType = response.headers?.get?.("content-type")?.split(";", 1)[0].trim() ?? "";
|
|
530
|
+
if (contentType && options.contentTypePrefixes?.length && !options.contentTypePrefixes.some((prefix) => contentType.toLowerCase().startsWith(prefix))) {
|
|
531
|
+
throw new ResourcePolicyError(
|
|
532
|
+
"RESOURCE_BLOCKED",
|
|
533
|
+
`Resource Content-Type is not allowed: ${contentType || "(missing)"}`
|
|
534
|
+
);
|
|
535
|
+
}
|
|
536
|
+
const declaredLength = Number(response.headers?.get?.("content-length"));
|
|
537
|
+
if (Number.isFinite(declaredLength) && declaredLength > policy.maxBytes) {
|
|
538
|
+
throw tooLarge(policy.maxBytes);
|
|
539
|
+
}
|
|
540
|
+
const bytes = await readResponseBounded(response, policy.maxBytes, controller.signal);
|
|
541
|
+
return { bytes, contentType, finalUrl };
|
|
542
|
+
} catch (error) {
|
|
543
|
+
if (timedOut) {
|
|
544
|
+
throw new ResourcePolicyError(
|
|
545
|
+
"RESOURCE_TIMEOUT",
|
|
546
|
+
`Resource request exceeded ${policy.timeoutMs} ms`
|
|
547
|
+
);
|
|
548
|
+
}
|
|
549
|
+
throw error;
|
|
550
|
+
} finally {
|
|
551
|
+
clearTimeout(timeout);
|
|
552
|
+
options.signal?.removeEventListener("abort", onAbort);
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
function resolvePolicy(policy) {
|
|
556
|
+
return {
|
|
557
|
+
...DEFAULT_INTERACTIVE_RESOURCE_POLICY,
|
|
558
|
+
...policy,
|
|
559
|
+
allowedHosts: policy?.allowedHosts ?? DEFAULT_INTERACTIVE_RESOURCE_POLICY.allowedHosts
|
|
560
|
+
};
|
|
561
|
+
}
|
|
562
|
+
function parseUrl(value) {
|
|
563
|
+
try {
|
|
564
|
+
return new URL(value);
|
|
565
|
+
} catch {
|
|
566
|
+
return null;
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
function hostAllowed(url, allowedHosts) {
|
|
570
|
+
if (!url || url.username || url.password) return false;
|
|
571
|
+
if (allowedHosts.length === 0) return true;
|
|
572
|
+
const host = url.hostname.toLowerCase().replace(/\.$/, "");
|
|
573
|
+
return allowedHosts.some((entry) => {
|
|
574
|
+
const allowed = entry.trim().toLowerCase().replace(/\.$/, "");
|
|
575
|
+
if (allowed.startsWith("*.")) {
|
|
576
|
+
const suffix = allowed.slice(2);
|
|
577
|
+
return host !== suffix && host.endsWith(`.${suffix}`);
|
|
578
|
+
}
|
|
579
|
+
return host === allowed;
|
|
580
|
+
});
|
|
581
|
+
}
|
|
582
|
+
function isSafeMediaDataUrl(value) {
|
|
583
|
+
return /^data:(?:image\/(?!svg\+xml)[a-z0-9.+-]+|audio\/[a-z0-9.+-]+|video\/[a-z0-9.+-]+);/i.test(
|
|
584
|
+
value
|
|
585
|
+
);
|
|
586
|
+
}
|
|
587
|
+
function hasUrlControlCharacters(value) {
|
|
588
|
+
for (const char of value) {
|
|
589
|
+
const code = char.charCodeAt(0);
|
|
590
|
+
if (code < 32 || code === 127) return true;
|
|
591
|
+
}
|
|
592
|
+
return false;
|
|
593
|
+
}
|
|
594
|
+
async function readResponseBounded(response, maxBytes, signal) {
|
|
595
|
+
if (!response.body) {
|
|
596
|
+
const buffer = response.arrayBuffer ? await response.arrayBuffer() : await (await response.blob()).arrayBuffer();
|
|
597
|
+
const bytes = new Uint8Array(buffer);
|
|
598
|
+
if (bytes.byteLength > maxBytes) throw tooLarge(maxBytes);
|
|
599
|
+
return bytes;
|
|
600
|
+
}
|
|
601
|
+
const reader = response.body.getReader();
|
|
602
|
+
const chunks = [];
|
|
603
|
+
let total = 0;
|
|
604
|
+
try {
|
|
605
|
+
while (true) {
|
|
606
|
+
signal.throwIfAborted();
|
|
607
|
+
const { done, value } = await reader.read();
|
|
608
|
+
if (done) break;
|
|
609
|
+
total += value.byteLength;
|
|
610
|
+
if (total > maxBytes) {
|
|
611
|
+
await reader.cancel();
|
|
612
|
+
throw tooLarge(maxBytes);
|
|
613
|
+
}
|
|
614
|
+
chunks.push(value);
|
|
615
|
+
}
|
|
616
|
+
} finally {
|
|
617
|
+
reader.releaseLock();
|
|
618
|
+
}
|
|
619
|
+
const out = new Uint8Array(total);
|
|
620
|
+
let offset = 0;
|
|
621
|
+
for (const chunk of chunks) {
|
|
622
|
+
out.set(chunk, offset);
|
|
623
|
+
offset += chunk.byteLength;
|
|
624
|
+
}
|
|
625
|
+
return out;
|
|
626
|
+
}
|
|
627
|
+
function tooLarge(maxBytes) {
|
|
628
|
+
return new ResourcePolicyError(
|
|
629
|
+
"RESOURCE_TOO_LARGE",
|
|
630
|
+
`Resource exceeds the ${maxBytes}-byte policy limit`
|
|
631
|
+
);
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
export {
|
|
635
|
+
stringifyMarkdown,
|
|
636
|
+
sanitizeUrl,
|
|
637
|
+
sanitizeHtmlNodes,
|
|
638
|
+
DEFAULT_RESOURCE_MAX_BYTES,
|
|
639
|
+
DEFAULT_RESOURCE_TIMEOUT_MS,
|
|
640
|
+
DEFAULT_INTERACTIVE_RESOURCE_POLICY,
|
|
641
|
+
LOCAL_ONLY_RESOURCE_POLICY,
|
|
642
|
+
ResourcePolicyError,
|
|
643
|
+
isResourceUrlAllowed,
|
|
644
|
+
fetchResourceBytes
|
|
645
|
+
};
|