@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
|
@@ -1,243 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, beforeEach } from 'vitest';
|
|
2
|
-
import { MemoryContentContainer } from '../storage/ContentContainer';
|
|
3
|
-
import { scopeContainer } from '../storage/ScopedContentContainer';
|
|
4
|
-
import { createEmptyImageEditDoc, addLayer } from '../imageEdit/state';
|
|
5
|
-
import { writeImageEditDoc, readImageEditDoc } from '../imageEdit/persistence';
|
|
6
|
-
import {
|
|
7
|
-
saveImageEditVersion,
|
|
8
|
-
listImageEditVersions,
|
|
9
|
-
readImageEditVersion,
|
|
10
|
-
revertToImageEditVersion,
|
|
11
|
-
pruneImageEditVersions,
|
|
12
|
-
} from '../imageEdit/versions';
|
|
13
|
-
import { ImageEditVersionManager } from '../imageEdit/ImageEditVersionManager';
|
|
14
|
-
import type { ImageEditLayer } from '../schemas/ImageEditDoc';
|
|
15
|
-
|
|
16
|
-
const text = (id: string): ImageEditLayer => ({
|
|
17
|
-
id,
|
|
18
|
-
type: 'text',
|
|
19
|
-
position: { x: 0, y: 0 },
|
|
20
|
-
content: { text: id, style: { fontSize: 16, color: '#000' } },
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
describe('imageEdit/persistence', () => {
|
|
24
|
-
it('round-trips state.json', async () => {
|
|
25
|
-
const sidecar = scopeContainer(new MemoryContentContainer(), 'image_files');
|
|
26
|
-
const doc = addLayer(createEmptyImageEditDoc(640, 480), text('a'));
|
|
27
|
-
await writeImageEditDoc(sidecar, doc);
|
|
28
|
-
const read = await readImageEditDoc(sidecar);
|
|
29
|
-
expect(read?.canvas.width).toBe(640);
|
|
30
|
-
expect(read?.layers).toHaveLength(1);
|
|
31
|
-
expect(read?.layers[0]!.id).toBe('a');
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
it('returns null when state.json is missing', async () => {
|
|
35
|
-
const sidecar = scopeContainer(new MemoryContentContainer(), 'sc');
|
|
36
|
-
expect(await readImageEditDoc(sidecar)).toBeNull();
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
it('rejects unsupported schema version', async () => {
|
|
40
|
-
const sidecar = scopeContainer(new MemoryContentContainer(), 'sc');
|
|
41
|
-
await sidecar.writeFile(
|
|
42
|
-
'state.json',
|
|
43
|
-
new TextEncoder().encode(
|
|
44
|
-
JSON.stringify({ version: 2, canvas: { width: 1, height: 1 }, layers: [] }),
|
|
45
|
-
),
|
|
46
|
-
);
|
|
47
|
-
await expect(readImageEditDoc(sidecar)).rejects.toThrow(/unsupported schema version/);
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
async function writeRaw(sidecar: ReturnType<typeof scopeContainer>, payload: unknown) {
|
|
51
|
-
await sidecar.writeFile('state.json', new TextEncoder().encode(JSON.stringify(payload)));
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
it('rejects layer that is not an object', async () => {
|
|
55
|
-
const sidecar = scopeContainer(new MemoryContentContainer(), 'sc');
|
|
56
|
-
await writeRaw(sidecar, { version: 1, canvas: { width: 1, height: 1 }, layers: [null] });
|
|
57
|
-
await expect(readImageEditDoc(sidecar)).rejects.toThrow(/layers\[0\] must be an object/);
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
it('rejects layer with missing id', async () => {
|
|
61
|
-
const sidecar = scopeContainer(new MemoryContentContainer(), 'sc');
|
|
62
|
-
await writeRaw(sidecar, {
|
|
63
|
-
version: 1,
|
|
64
|
-
canvas: { width: 1, height: 1 },
|
|
65
|
-
layers: [{ type: 'text', position: { x: 0, y: 0 }, content: { text: 'hi', style: {} } }],
|
|
66
|
-
});
|
|
67
|
-
await expect(readImageEditDoc(sidecar)).rejects.toThrow(/must have a string id/);
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
it('rejects layer with invalid type', async () => {
|
|
71
|
-
const sidecar = scopeContainer(new MemoryContentContainer(), 'sc');
|
|
72
|
-
await writeRaw(sidecar, {
|
|
73
|
-
version: 1,
|
|
74
|
-
canvas: { width: 1, height: 1 },
|
|
75
|
-
layers: [{ id: 'x', type: 'video', position: { x: 0, y: 0 }, content: {} }],
|
|
76
|
-
});
|
|
77
|
-
await expect(readImageEditDoc(sidecar)).rejects.toThrow(
|
|
78
|
-
/type must be one of image\|text\|shape/,
|
|
79
|
-
);
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
it('rejects image layer with missing content.src', async () => {
|
|
83
|
-
const sidecar = scopeContainer(new MemoryContentContainer(), 'sc');
|
|
84
|
-
await writeRaw(sidecar, {
|
|
85
|
-
version: 1,
|
|
86
|
-
canvas: { width: 1, height: 1 },
|
|
87
|
-
layers: [{ id: 'x', type: 'image', position: { x: 0, y: 0 }, content: { alt: 'test' } }],
|
|
88
|
-
});
|
|
89
|
-
await expect(readImageEditDoc(sidecar)).rejects.toThrow(/content\.src must be a string/);
|
|
90
|
-
});
|
|
91
|
-
|
|
92
|
-
it('rejects text layer with missing content.text', async () => {
|
|
93
|
-
const sidecar = scopeContainer(new MemoryContentContainer(), 'sc');
|
|
94
|
-
await writeRaw(sidecar, {
|
|
95
|
-
version: 1,
|
|
96
|
-
canvas: { width: 1, height: 1 },
|
|
97
|
-
layers: [{ id: 'x', type: 'text', position: { x: 0, y: 0 }, content: { style: {} } }],
|
|
98
|
-
});
|
|
99
|
-
await expect(readImageEditDoc(sidecar)).rejects.toThrow(/content\.text must be a string/);
|
|
100
|
-
});
|
|
101
|
-
|
|
102
|
-
it('rejects shape layer with missing content.shape', async () => {
|
|
103
|
-
const sidecar = scopeContainer(new MemoryContentContainer(), 'sc');
|
|
104
|
-
await writeRaw(sidecar, {
|
|
105
|
-
version: 1,
|
|
106
|
-
canvas: { width: 1, height: 1 },
|
|
107
|
-
layers: [{ id: 'x', type: 'shape', position: { x: 0, y: 0 }, content: {} }],
|
|
108
|
-
});
|
|
109
|
-
await expect(readImageEditDoc(sidecar)).rejects.toThrow(/content\.shape must be a string/);
|
|
110
|
-
});
|
|
111
|
-
|
|
112
|
-
it('rejects layer with missing position', async () => {
|
|
113
|
-
const sidecar = scopeContainer(new MemoryContentContainer(), 'sc');
|
|
114
|
-
await writeRaw(sidecar, {
|
|
115
|
-
version: 1,
|
|
116
|
-
canvas: { width: 1, height: 1 },
|
|
117
|
-
layers: [{ id: 'x', type: 'shape', content: { shape: 'rect' } }],
|
|
118
|
-
});
|
|
119
|
-
await expect(readImageEditDoc(sidecar)).rejects.toThrow(/position must have/);
|
|
120
|
-
});
|
|
121
|
-
});
|
|
122
|
-
|
|
123
|
-
describe('imageEdit/versions', () => {
|
|
124
|
-
let parent: MemoryContentContainer;
|
|
125
|
-
let sidecar: ReturnType<typeof scopeContainer>;
|
|
126
|
-
|
|
127
|
-
beforeEach(() => {
|
|
128
|
-
parent = new MemoryContentContainer();
|
|
129
|
-
sidecar = scopeContainer(parent, 'image_files');
|
|
130
|
-
});
|
|
131
|
-
|
|
132
|
-
it('saves a snapshot when state.json exists', async () => {
|
|
133
|
-
const doc = addLayer(createEmptyImageEditDoc(100, 100), text('a'));
|
|
134
|
-
await writeImageEditDoc(sidecar, doc);
|
|
135
|
-
const result = await saveImageEditVersion(sidecar, { now: new Date('2026-04-01T10:00:00Z') });
|
|
136
|
-
expect(result.saved).toBe(true);
|
|
137
|
-
expect(result.version?.path).toMatch(/^\.versions\/state\.\d{8}T\d{6}Z\.json$/);
|
|
138
|
-
// snapshot is inside the sidecar, visible to the parent under the prefix
|
|
139
|
-
expect(await parent.exists(`image_files/${result.version!.path}`)).toBe(true);
|
|
140
|
-
const gitignore = await parent.readFile('image_files/.gitignore');
|
|
141
|
-
expect(gitignore && new TextDecoder().decode(gitignore)).toBe('.versions/\n');
|
|
142
|
-
});
|
|
143
|
-
|
|
144
|
-
it('returns no-state when sidecar is empty', async () => {
|
|
145
|
-
const result = await saveImageEditVersion(sidecar);
|
|
146
|
-
expect(result).toEqual({ saved: false, version: null, reason: 'no-state' });
|
|
147
|
-
});
|
|
148
|
-
|
|
149
|
-
it('skips saving when content is unchanged', async () => {
|
|
150
|
-
const doc = createEmptyImageEditDoc(100, 100, { now: new Date('2026-01-01') });
|
|
151
|
-
await writeImageEditDoc(sidecar, doc);
|
|
152
|
-
const first = await saveImageEditVersion(sidecar, {
|
|
153
|
-
doc,
|
|
154
|
-
now: new Date('2026-04-01T10:00:00Z'),
|
|
155
|
-
});
|
|
156
|
-
expect(first.saved).toBe(true);
|
|
157
|
-
const second = await saveImageEditVersion(sidecar, {
|
|
158
|
-
doc,
|
|
159
|
-
now: new Date('2026-04-01T10:01:00Z'),
|
|
160
|
-
});
|
|
161
|
-
expect(second).toEqual({ saved: false, version: null, reason: 'unchanged' });
|
|
162
|
-
});
|
|
163
|
-
|
|
164
|
-
it('appends a collision suffix when saves land in the same second', async () => {
|
|
165
|
-
const same = new Date('2026-04-01T10:00:00Z');
|
|
166
|
-
const docA = addLayer(createEmptyImageEditDoc(100, 100), text('a'));
|
|
167
|
-
const docB = addLayer(createEmptyImageEditDoc(100, 100), text('b'));
|
|
168
|
-
const r1 = await saveImageEditVersion(sidecar, { doc: docA, now: same });
|
|
169
|
-
const r2 = await saveImageEditVersion(sidecar, { doc: docB, now: same });
|
|
170
|
-
expect(r1.saved).toBe(true);
|
|
171
|
-
expect(r2.saved).toBe(true);
|
|
172
|
-
expect(r1.version!.path).not.toBe(r2.version!.path);
|
|
173
|
-
expect(r2.version!.path).toMatch(/-2\.json$/);
|
|
174
|
-
});
|
|
175
|
-
|
|
176
|
-
it('lists versions newest-first', async () => {
|
|
177
|
-
await saveImageEditVersion(sidecar, {
|
|
178
|
-
doc: addLayer(createEmptyImageEditDoc(100, 100), text('a')),
|
|
179
|
-
now: new Date('2026-01-01T00:00:00Z'),
|
|
180
|
-
});
|
|
181
|
-
await saveImageEditVersion(sidecar, {
|
|
182
|
-
doc: addLayer(createEmptyImageEditDoc(100, 100), text('b')),
|
|
183
|
-
now: new Date('2026-02-01T00:00:00Z'),
|
|
184
|
-
});
|
|
185
|
-
const versions = await listImageEditVersions(sidecar);
|
|
186
|
-
expect(versions).toHaveLength(2);
|
|
187
|
-
expect(versions[0]!.timestamp.getUTCFullYear()).toBe(2026);
|
|
188
|
-
expect(versions[0]!.timestamp.getUTCMonth()).toBe(1); // Feb
|
|
189
|
-
});
|
|
190
|
-
|
|
191
|
-
it('readImageEditVersion returns the parsed snapshot', async () => {
|
|
192
|
-
const doc = addLayer(createEmptyImageEditDoc(100, 100), text('a'));
|
|
193
|
-
const result = await saveImageEditVersion(sidecar, {
|
|
194
|
-
doc,
|
|
195
|
-
now: new Date('2026-03-01T00:00:00Z'),
|
|
196
|
-
});
|
|
197
|
-
const read = await readImageEditVersion(sidecar, result.version!);
|
|
198
|
-
expect(read?.layers[0]!.id).toBe('a');
|
|
199
|
-
});
|
|
200
|
-
|
|
201
|
-
it('revertToImageEditVersion restores state.json and snapshots current first', async () => {
|
|
202
|
-
const docA = addLayer(createEmptyImageEditDoc(100, 100), text('a'));
|
|
203
|
-
await writeImageEditDoc(sidecar, docA);
|
|
204
|
-
const v1 = await saveImageEditVersion(sidecar, {
|
|
205
|
-
doc: docA,
|
|
206
|
-
now: new Date('2026-01-01T00:00:00Z'),
|
|
207
|
-
});
|
|
208
|
-
|
|
209
|
-
const docB = addLayer(createEmptyImageEditDoc(100, 100), text('b'));
|
|
210
|
-
await writeImageEditDoc(sidecar, docB);
|
|
211
|
-
const result = await revertToImageEditVersion(sidecar, v1.version!);
|
|
212
|
-
|
|
213
|
-
expect(result.reverted).toBe(true);
|
|
214
|
-
expect(result.snapshotted).not.toBeNull();
|
|
215
|
-
const current = await readImageEditDoc(sidecar);
|
|
216
|
-
expect(current?.layers[0]!.id).toBe('a');
|
|
217
|
-
});
|
|
218
|
-
|
|
219
|
-
it('pruneImageEditVersions keep-last-n drops older snapshots', async () => {
|
|
220
|
-
for (let i = 0; i < 5; i++) {
|
|
221
|
-
await saveImageEditVersion(sidecar, {
|
|
222
|
-
doc: addLayer(createEmptyImageEditDoc(100, 100), text(`v${i}`)),
|
|
223
|
-
now: new Date(`2026-01-0${i + 1}T00:00:00Z`),
|
|
224
|
-
});
|
|
225
|
-
}
|
|
226
|
-
const deleted = await pruneImageEditVersions(sidecar, { type: 'keep-last-n', n: 2 });
|
|
227
|
-
expect(deleted).toHaveLength(3);
|
|
228
|
-
const remaining = await listImageEditVersions(sidecar);
|
|
229
|
-
expect(remaining).toHaveLength(2);
|
|
230
|
-
});
|
|
231
|
-
});
|
|
232
|
-
|
|
233
|
-
describe('ImageEditVersionManager', () => {
|
|
234
|
-
it('mirrors operations against the captured container', async () => {
|
|
235
|
-
const sidecar = scopeContainer(new MemoryContentContainer(), 'image_files');
|
|
236
|
-
const mgr = new ImageEditVersionManager(sidecar);
|
|
237
|
-
const doc = addLayer(createEmptyImageEditDoc(100, 100), text('a'));
|
|
238
|
-
await writeImageEditDoc(sidecar, doc);
|
|
239
|
-
const r = await mgr.saveVersion({ now: new Date('2026-04-01T00:00:00Z') });
|
|
240
|
-
expect(r.saved).toBe(true);
|
|
241
|
-
expect((await mgr.listVersions())[0]!.path).toBe(r.version!.path);
|
|
242
|
-
});
|
|
243
|
-
});
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from 'vitest';
|
|
2
|
-
import { parseMarkdown } from '../markdown/parse.js';
|
|
3
|
-
import { inferDocumentTitle } from '../markdown/utils.js';
|
|
4
|
-
|
|
5
|
-
describe('inferDocumentTitle', () => {
|
|
6
|
-
it('returns the frontmatter title when set', () => {
|
|
7
|
-
const doc = parseMarkdown('---\ntitle: My Doc\n---\n\n# Heading\n');
|
|
8
|
-
expect(inferDocumentTitle(doc)).toBe('My Doc');
|
|
9
|
-
});
|
|
10
|
-
|
|
11
|
-
it('trims surrounding whitespace from frontmatter title', () => {
|
|
12
|
-
const doc = parseMarkdown('---\ntitle: " Spaced "\n---\n\n# Heading\n');
|
|
13
|
-
expect(inferDocumentTitle(doc)).toBe('Spaced');
|
|
14
|
-
});
|
|
15
|
-
|
|
16
|
-
it('falls back to the first H1 when frontmatter title is absent', () => {
|
|
17
|
-
const doc = parseMarkdown('# Welcome\n\n## Details');
|
|
18
|
-
expect(inferDocumentTitle(doc)).toBe('Welcome');
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
it('falls back to the first H2 when no H1 is present', () => {
|
|
22
|
-
const doc = parseMarkdown('## Section\n\n### Detail');
|
|
23
|
-
expect(inferDocumentTitle(doc)).toBe('Section');
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
it('prefers the shallowest heading regardless of source order', () => {
|
|
27
|
-
const doc = parseMarkdown('## Earlier H2\n\n# Real Title\n\n### Nested');
|
|
28
|
-
expect(inferDocumentTitle(doc)).toBe('Real Title');
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
it('skips empty frontmatter title and falls back to headings', () => {
|
|
32
|
-
const doc = parseMarkdown('---\ntitle: ""\n---\n\n# Real\n');
|
|
33
|
-
expect(inferDocumentTitle(doc)).toBe('Real');
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
it('returns undefined when there is no frontmatter and no heading', () => {
|
|
37
|
-
const doc = parseMarkdown('Just a paragraph.\n\nAnother one.');
|
|
38
|
-
expect(inferDocumentTitle(doc)).toBeUndefined();
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
it('strips inline formatting from heading text', () => {
|
|
42
|
-
const doc = parseMarkdown('# **Bold** and *italic*');
|
|
43
|
-
expect(inferDocumentTitle(doc)).toBe('Bold and italic');
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
it('skips headings that contain only whitespace', () => {
|
|
47
|
-
const doc = parseMarkdown('# \n\n## Real Heading');
|
|
48
|
-
expect(inferDocumentTitle(doc)).toBe('Real Heading');
|
|
49
|
-
});
|
|
50
|
-
});
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from 'vitest';
|
|
2
|
-
import {
|
|
3
|
-
hasIconMarker,
|
|
4
|
-
iconClass,
|
|
5
|
-
iconMarker,
|
|
6
|
-
splitIconMarkers,
|
|
7
|
-
stripIconMarkers,
|
|
8
|
-
} from '../icons/inlineIconMarker';
|
|
9
|
-
|
|
10
|
-
describe('inline icon markers', () => {
|
|
11
|
-
it('encodes icons with a private-use sentinel', () => {
|
|
12
|
-
expect(iconMarker('solid', 'rocket')).toBe('\uE000solid:rocket\uE000');
|
|
13
|
-
});
|
|
14
|
-
|
|
15
|
-
it('detects and strips encoded markers from plain-text projections', () => {
|
|
16
|
-
const text = `Launch ${iconMarker('solid', 'rocket')} now`;
|
|
17
|
-
|
|
18
|
-
expect(hasIconMarker(text)).toBe(true);
|
|
19
|
-
expect(stripIconMarkers(text)).toBe('Launch now');
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
it('splits marker-bearing text into text and icon runs', () => {
|
|
23
|
-
const text = `A ${iconMarker('regular', 'star')} and ${iconMarker('brands', 'github')}`;
|
|
24
|
-
|
|
25
|
-
expect(splitIconMarkers(text)).toEqual([
|
|
26
|
-
{ type: 'text', text: 'A ' },
|
|
27
|
-
{ type: 'icon', family: 'regular', name: 'star' },
|
|
28
|
-
{ type: 'text', text: ' and ' },
|
|
29
|
-
{ type: 'icon', family: 'brands', name: 'github' },
|
|
30
|
-
]);
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
it('builds FontAwesome class names', () => {
|
|
34
|
-
expect(iconClass('solid', 'rocket')).toBe('fa-solid fa-rocket');
|
|
35
|
-
});
|
|
36
|
-
});
|
|
@@ -1,162 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from 'vitest';
|
|
2
|
-
import {
|
|
3
|
-
BASE_INPUT_DESCRIPTORS,
|
|
4
|
-
TEMPLATE_INPUT_DESCRIPTORS,
|
|
5
|
-
coerceTemplateParams,
|
|
6
|
-
lintTemplateParams,
|
|
7
|
-
} from '../doc/templates/inputDescriptors';
|
|
8
|
-
import { templateRegistry } from '../doc/templates/index';
|
|
9
|
-
|
|
10
|
-
describe('coerceTemplateParams', () => {
|
|
11
|
-
it('coerces number keys, leaving the raw string on failure', () => {
|
|
12
|
-
expect(coerceTemplateParams('map', { zoom: '9' }).input).toEqual({ zoom: 9 });
|
|
13
|
-
|
|
14
|
-
const bad = coerceTemplateParams('map', { zoom: 'abc' });
|
|
15
|
-
expect(bad.input).toEqual({ zoom: 'abc' });
|
|
16
|
-
expect(bad.warnings).toHaveLength(1);
|
|
17
|
-
expect(bad.warnings[0]).toContain('zoom');
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
it('coerces boolean keys (true/empty → true, false → false)', () => {
|
|
21
|
-
const { input } = coerceTemplateParams('imageWithCaption', { isTitle: 'true' });
|
|
22
|
-
expect(input.isTitle).toBe(true);
|
|
23
|
-
// A bare flag `{[… isTitle]}` parses to an empty value → true.
|
|
24
|
-
expect(coerceTemplateParams('imageWithCaption', { isTitle: '' }).input.isTitle).toBe(true);
|
|
25
|
-
expect(coerceTemplateParams('imageWithCaption', { isTitle: 'false' }).input.isTitle).toBe(
|
|
26
|
-
false,
|
|
27
|
-
);
|
|
28
|
-
|
|
29
|
-
const bad = coerceTemplateParams('imageWithCaption', { isTitle: 'maybe' });
|
|
30
|
-
expect(bad.input.isTitle).toBe('maybe');
|
|
31
|
-
expect(bad.warnings).toHaveLength(1);
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
it('coerces latLng into { lat, lng }, warning on malformed input', () => {
|
|
35
|
-
expect(coerceTemplateParams('map', { center: '47.6,-122.3' }).input).toEqual({
|
|
36
|
-
center: { lat: 47.6, lng: -122.3 },
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
const bad = coerceTemplateParams('map', { center: 'nope' });
|
|
40
|
-
expect(bad.input).toEqual({ center: 'nope' });
|
|
41
|
-
expect(bad.warnings[0]).toContain('center');
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
it('coerces labeledPair into { label, sublabel? }', () => {
|
|
45
|
-
expect(coerceTemplateParams('twoColumn', { left: 'Espresso|Bold' }).input).toEqual({
|
|
46
|
-
left: { label: 'Espresso', sublabel: 'Bold' },
|
|
47
|
-
});
|
|
48
|
-
// No separator → label only, no sublabel key.
|
|
49
|
-
expect(coerceTemplateParams('twoColumn', { right: 'Filter' }).input).toEqual({
|
|
50
|
-
right: { label: 'Filter' },
|
|
51
|
-
});
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
it('coerces stringList by splitting on commas and trimming', () => {
|
|
55
|
-
expect(coerceTemplateParams('photoGrid', { images: 'a.jpg, b.jpg ,c.jpg' }).input).toEqual({
|
|
56
|
-
images: ['a.jpg', 'b.jpg', 'c.jpg'],
|
|
57
|
-
});
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
it('passes unknown keys through unchanged as strings (never lossy)', () => {
|
|
61
|
-
const { input, warnings } = coerceTemplateParams('map', { wobble: 'yes', center: '1,2' });
|
|
62
|
-
expect(input.wobble).toBe('yes');
|
|
63
|
-
expect(input.center).toEqual({ lat: 1, lng: 2 });
|
|
64
|
-
expect(warnings).toEqual([]);
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
it('passes everything through for a template with no descriptors', () => {
|
|
68
|
-
expect(coerceTemplateParams('sectionHeader', { anything: '5' }).input).toEqual({
|
|
69
|
-
anything: '5',
|
|
70
|
-
});
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
it('resolves legacy template aliases before coercing', () => {
|
|
74
|
-
expect(coerceTemplateParams('mapBlock', { zoom: '7' }).input).toEqual({ zoom: 7 });
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
it('coerces shared base inputs (useTopLayer boolean)', () => {
|
|
78
|
-
expect(coerceTemplateParams('title', { useTopLayer: 'false' }).input.useTopLayer).toBe(false);
|
|
79
|
-
});
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
describe('lintTemplateParams', () => {
|
|
83
|
-
it('returns [] for a template without descriptors', () => {
|
|
84
|
-
expect(lintTemplateParams('sectionHeader', { foo: 'bar' })).toEqual([]);
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
it('flags an unknown input with a did-you-mean suggestion', () => {
|
|
88
|
-
const findings = lintTemplateParams('map', { centre: '1,2' });
|
|
89
|
-
const unknown = findings.find((f) => f.kind === 'unknown-input');
|
|
90
|
-
expect(unknown).toBeDefined();
|
|
91
|
-
expect(unknown!.key).toBe('centre');
|
|
92
|
-
expect(unknown!.suggestion).toBe('center');
|
|
93
|
-
expect(unknown!.message).toContain('Did you mean "center"?');
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
it('does not flag block-meta keys carried on the same annotation', () => {
|
|
97
|
-
const findings = lintTemplateParams('title', { duration: '8', transition: 'fade' });
|
|
98
|
-
expect(findings.filter((f) => f.kind === 'unknown-input')).toEqual([]);
|
|
99
|
-
});
|
|
100
|
-
|
|
101
|
-
it('flags a value outside a closed enum', () => {
|
|
102
|
-
const findings = lintTemplateParams('map', { center: '1,2', mapStyle: 'nope' });
|
|
103
|
-
const invalid = findings.find((f) => f.kind === 'invalid-input-value');
|
|
104
|
-
expect(invalid).toBeDefined();
|
|
105
|
-
expect(invalid!.key).toBe('mapStyle');
|
|
106
|
-
expect(invalid!.message).toContain('terrain');
|
|
107
|
-
});
|
|
108
|
-
|
|
109
|
-
it('flags a value that fails coercion (bad latLng)', () => {
|
|
110
|
-
const findings = lintTemplateParams('map', { center: 'garbage' });
|
|
111
|
-
expect(findings.some((f) => f.kind === 'invalid-input-value' && f.key === 'center')).toBe(true);
|
|
112
|
-
});
|
|
113
|
-
|
|
114
|
-
it('flags missing required inputs', () => {
|
|
115
|
-
const findings = lintTemplateParams('twoColumn', {});
|
|
116
|
-
const missing = findings
|
|
117
|
-
.filter((f) => f.kind === 'missing-input')
|
|
118
|
-
.map((f) => f.key)
|
|
119
|
-
.sort();
|
|
120
|
-
expect(missing).toEqual(['left', 'right']);
|
|
121
|
-
});
|
|
122
|
-
|
|
123
|
-
it('does not flag a required input that is present', () => {
|
|
124
|
-
const findings = lintTemplateParams('map', { center: '1,2' });
|
|
125
|
-
expect(findings.filter((f) => f.kind === 'missing-input')).toEqual([]);
|
|
126
|
-
});
|
|
127
|
-
|
|
128
|
-
it('accepts a valid enum value', () => {
|
|
129
|
-
const findings = lintTemplateParams('map', { center: '1,2', mapStyle: 'satellite' });
|
|
130
|
-
expect(findings).toEqual([]);
|
|
131
|
-
});
|
|
132
|
-
});
|
|
133
|
-
|
|
134
|
-
describe('descriptor registry shape', () => {
|
|
135
|
-
it('base descriptors are declared with unique keys', () => {
|
|
136
|
-
const keys = BASE_INPUT_DESCRIPTORS.map((d) => d.key);
|
|
137
|
-
expect(new Set(keys).size).toBe(keys.length);
|
|
138
|
-
});
|
|
139
|
-
|
|
140
|
-
it('has no orphan descriptors — every keyed template exists in the registry', () => {
|
|
141
|
-
for (const template of Object.keys(TEMPLATE_INPUT_DESCRIPTORS)) {
|
|
142
|
-
expect(templateRegistry, `orphan descriptor for "${template}"`).toHaveProperty(template);
|
|
143
|
-
}
|
|
144
|
-
});
|
|
145
|
-
|
|
146
|
-
it('every template descriptor has unique keys and a description', () => {
|
|
147
|
-
for (const [template, descriptors] of Object.entries(TEMPLATE_INPUT_DESCRIPTORS)) {
|
|
148
|
-
const keys = descriptors.map((d) => d.key);
|
|
149
|
-
expect(new Set(keys).size, `duplicate key in ${template}`).toBe(keys.length);
|
|
150
|
-
for (const d of descriptors) {
|
|
151
|
-
expect(d.description.length, `empty description for ${template}.${d.key}`).toBeGreaterThan(
|
|
152
|
-
0,
|
|
153
|
-
);
|
|
154
|
-
// values / valueHint are mutually exclusive.
|
|
155
|
-
expect(
|
|
156
|
-
!(d.values && d.valueHint),
|
|
157
|
-
`${template}.${d.key} has both values and valueHint`,
|
|
158
|
-
).toBe(true);
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
});
|
|
162
|
-
});
|
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from 'vitest';
|
|
2
|
-
import { chooseControl, primaryType, arrayItemKind } from '../jsonForm/index.js';
|
|
3
|
-
|
|
4
|
-
describe('chooseControl', () => {
|
|
5
|
-
it('honors explicit squisq.control', () => {
|
|
6
|
-
expect(chooseControl({ type: 'string', squisq: { control: 'radio' } })).toBe('radio');
|
|
7
|
-
});
|
|
8
|
-
|
|
9
|
-
it('maps format=color', () => {
|
|
10
|
-
expect(chooseControl({ type: 'string', format: 'color' })).toBe('color');
|
|
11
|
-
});
|
|
12
|
-
it('maps format=date / time / date-time / markdown / textarea', () => {
|
|
13
|
-
expect(chooseControl({ type: 'string', format: 'date' })).toBe('date');
|
|
14
|
-
expect(chooseControl({ type: 'string', format: 'time' })).toBe('time');
|
|
15
|
-
expect(chooseControl({ type: 'string', format: 'date-time' })).toBe('datetime');
|
|
16
|
-
expect(chooseControl({ type: 'string', format: 'markdown' })).toBe('richtext');
|
|
17
|
-
expect(chooseControl({ type: 'string', format: 'textarea' })).toBe('multiline');
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
it('uses segmented for short enums (≤4)', () => {
|
|
21
|
-
expect(chooseControl({ type: 'string', enum: ['a', 'b', 'c'] })).toBe('segmented');
|
|
22
|
-
expect(chooseControl({ type: 'string', enum: ['a', 'b', 'c', 'd'] })).toBe('segmented');
|
|
23
|
-
});
|
|
24
|
-
it('uses combobox for long enums (>4)', () => {
|
|
25
|
-
expect(chooseControl({ type: 'string', enum: ['a', 'b', 'c', 'd', 'e'] })).toBe('combobox');
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
it('arrays of objects → card-stack', () => {
|
|
29
|
-
expect(chooseControl({ type: 'array', items: { type: 'object', properties: {} } })).toBe(
|
|
30
|
-
'card-stack',
|
|
31
|
-
);
|
|
32
|
-
});
|
|
33
|
-
it('arrays of primitives → chip-bin', () => {
|
|
34
|
-
expect(chooseControl({ type: 'array', items: { type: 'string' } })).toBe('chip-bin');
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
it('booleans → toggle', () => {
|
|
38
|
-
expect(chooseControl({ type: 'boolean' })).toBe('toggle');
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
it('numbers with both min and max → slider', () => {
|
|
42
|
-
expect(chooseControl({ type: 'number', minimum: 0, maximum: 100 })).toBe('slider');
|
|
43
|
-
});
|
|
44
|
-
it('numbers without bounded range → stepper', () => {
|
|
45
|
-
expect(chooseControl({ type: 'number' })).toBe('stepper');
|
|
46
|
-
expect(chooseControl({ type: 'integer', minimum: 0 })).toBe('stepper');
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
it('strings with maxLength > 200 → multiline', () => {
|
|
50
|
-
expect(chooseControl({ type: 'string', maxLength: 500 })).toBe('multiline');
|
|
51
|
-
});
|
|
52
|
-
it('plain strings → text', () => {
|
|
53
|
-
expect(chooseControl({ type: 'string' })).toBe('text');
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
it('objects → group', () => {
|
|
57
|
-
expect(chooseControl({ type: 'object', properties: {} })).toBe('group');
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
it('oneOf / anyOf → tabs', () => {
|
|
61
|
-
expect(chooseControl({ oneOf: [{ type: 'string' }, { type: 'number' }] })).toBe('tabs');
|
|
62
|
-
expect(chooseControl({ anyOf: [{ type: 'string' }, { type: 'number' }] })).toBe('tabs');
|
|
63
|
-
});
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
describe('primaryType', () => {
|
|
67
|
-
it('returns the lone type', () => {
|
|
68
|
-
expect(primaryType({ type: 'string' })).toBe('string');
|
|
69
|
-
});
|
|
70
|
-
it('skips null in nullable shorthand', () => {
|
|
71
|
-
expect(primaryType({ type: ['string', 'null'] })).toBe('string');
|
|
72
|
-
expect(primaryType({ type: ['null', 'integer'] })).toBe('integer');
|
|
73
|
-
});
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
describe('arrayItemKind', () => {
|
|
77
|
-
it('detects object items', () => {
|
|
78
|
-
expect(arrayItemKind({ type: 'array', items: { type: 'object' } })).toBe('object');
|
|
79
|
-
});
|
|
80
|
-
it('detects primitive items', () => {
|
|
81
|
-
expect(arrayItemKind({ type: 'array', items: { type: 'string' } })).toBe('primitive');
|
|
82
|
-
});
|
|
83
|
-
it('treats missing items as primitive', () => {
|
|
84
|
-
expect(arrayItemKind({ type: 'array' })).toBe('primitive');
|
|
85
|
-
});
|
|
86
|
-
});
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from 'vitest';
|
|
2
|
-
import { evaluateWhen, resolveFlag } from '../jsonForm/index.js';
|
|
3
|
-
|
|
4
|
-
const data = {
|
|
5
|
-
user: { role: 'admin', name: 'Alex' },
|
|
6
|
-
count: 3,
|
|
7
|
-
active: true,
|
|
8
|
-
tags: ['a', 'b'],
|
|
9
|
-
};
|
|
10
|
-
|
|
11
|
-
describe('evaluateWhen', () => {
|
|
12
|
-
it('equals — primitives', () => {
|
|
13
|
-
expect(evaluateWhen({ field: 'user.role', equals: 'admin' }, data)).toBe(true);
|
|
14
|
-
expect(evaluateWhen({ field: 'user.role', equals: 'guest' }, data)).toBe(false);
|
|
15
|
-
});
|
|
16
|
-
|
|
17
|
-
it('equals — arrays via deep equality', () => {
|
|
18
|
-
expect(evaluateWhen({ field: 'tags', equals: ['a', 'b'] }, data)).toBe(true);
|
|
19
|
-
expect(evaluateWhen({ field: 'tags', equals: ['a'] }, data)).toBe(false);
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
it('oneOf', () => {
|
|
23
|
-
expect(evaluateWhen({ field: 'count', oneOf: [1, 2, 3] }, data)).toBe(true);
|
|
24
|
-
expect(evaluateWhen({ field: 'count', oneOf: [10, 20] }, data)).toBe(false);
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
it('matches regex', () => {
|
|
28
|
-
expect(evaluateWhen({ field: 'user.name', matches: '^Al' }, data)).toBe(true);
|
|
29
|
-
expect(evaluateWhen({ field: 'user.name', matches: '^Bo' }, data)).toBe(false);
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
it('matches: returns false for non-string targets', () => {
|
|
33
|
-
expect(evaluateWhen({ field: 'count', matches: '\\d' }, data)).toBe(false);
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
it('truthy', () => {
|
|
37
|
-
expect(evaluateWhen({ field: 'active', truthy: true }, data)).toBe(true);
|
|
38
|
-
expect(evaluateWhen({ field: 'active', truthy: false }, data)).toBe(false);
|
|
39
|
-
expect(evaluateWhen({ field: 'missing', truthy: false }, data)).toBe(true);
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
it('default behavior with no operator: field is defined', () => {
|
|
43
|
-
expect(evaluateWhen({ field: 'count' }, data)).toBe(true);
|
|
44
|
-
expect(evaluateWhen({ field: 'missing' }, data)).toBe(false);
|
|
45
|
-
});
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
describe('resolveFlag', () => {
|
|
49
|
-
it('passes through literal booleans', () => {
|
|
50
|
-
expect(resolveFlag(true, data)).toBe(true);
|
|
51
|
-
expect(resolveFlag(false, data)).toBe(false);
|
|
52
|
-
});
|
|
53
|
-
it('returns false for undefined', () => {
|
|
54
|
-
expect(resolveFlag(undefined, data)).toBe(false);
|
|
55
|
-
});
|
|
56
|
-
it('evaluates SquisqWhen', () => {
|
|
57
|
-
expect(resolveFlag({ field: 'user.role', equals: 'admin' }, data)).toBe(true);
|
|
58
|
-
});
|
|
59
|
-
});
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from 'vitest';
|
|
2
|
-
import { inferSchema } from '../jsonForm/index.js';
|
|
3
|
-
|
|
4
|
-
describe('inferSchema', () => {
|
|
5
|
-
it('infers an object schema from a sample', () => {
|
|
6
|
-
const schema = inferSchema({ name: 'Alex', age: 30, active: true });
|
|
7
|
-
expect(schema.type).toBe('object');
|
|
8
|
-
expect(schema.properties?.name?.type).toBe('string');
|
|
9
|
-
expect(schema.properties?.age?.type).toBe('integer');
|
|
10
|
-
expect(schema.properties?.active?.type).toBe('boolean');
|
|
11
|
-
});
|
|
12
|
-
|
|
13
|
-
it('infers array item types', () => {
|
|
14
|
-
const schema = inferSchema({ tags: ['a', 'b', 'c'] });
|
|
15
|
-
const items = schema.properties?.tags?.items;
|
|
16
|
-
const first = Array.isArray(items) ? items[0] : items;
|
|
17
|
-
expect(first?.type).toBe('string');
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
it('merges multiple samples', () => {
|
|
21
|
-
const schema = inferSchema({ name: 'Alex' }, { additionalSamples: [{ name: 'Bo', age: 5 }] });
|
|
22
|
-
expect(schema.properties?.name?.type).toBe('string');
|
|
23
|
-
expect(schema.properties?.age?.type).toBe('integer');
|
|
24
|
-
});
|
|
25
|
-
});
|