@saolabs/client 1.0.0 → 1.0.2
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/README.md +52 -195
- package/dist/index.d.ts +20 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +14 -3
- package/dist/index.js.map +1 -1
- package/dist/plugins.d.ts +2 -2
- package/dist/plugins.js +2 -2
- package/dist/src/core/app/Application.d.ts +17 -15
- package/dist/src/core/app/Application.d.ts.map +1 -1
- package/dist/src/core/app/Application.js +41 -18
- package/dist/src/core/app/Application.js.map +1 -1
- package/dist/src/core/bootstrap/app.d.ts +1 -1
- package/dist/src/core/bootstrap/app.d.ts.map +1 -1
- package/dist/src/core/bootstrap/app.js +74 -4
- package/dist/src/core/bootstrap/app.js.map +1 -1
- package/dist/src/core/bootstrap/bundle.d.ts +41 -0
- package/dist/src/core/bootstrap/bundle.d.ts.map +1 -0
- package/dist/src/core/bootstrap/bundle.js +98 -0
- package/dist/src/core/bootstrap/bundle.js.map +1 -0
- package/dist/src/core/bootstrap/providers/ApiServiceProvider.d.ts +1 -1
- package/dist/src/core/bootstrap/providers/ApiServiceProvider.d.ts.map +1 -1
- package/dist/src/core/bootstrap/providers/ApiServiceProvider.js +3 -3
- package/dist/src/core/bootstrap/providers/ApiServiceProvider.js.map +1 -1
- package/dist/src/core/bootstrap/providers/CoreServiceProvider.d.ts +1 -1
- package/dist/src/core/bootstrap/providers/CoreServiceProvider.d.ts.map +1 -1
- package/dist/src/core/bootstrap/providers/CoreServiceProvider.js +11 -8
- package/dist/src/core/bootstrap/providers/CoreServiceProvider.js.map +1 -1
- package/dist/src/core/bootstrap/providers/HelperServiceProvider.d.ts +3 -1
- package/dist/src/core/bootstrap/providers/HelperServiceProvider.d.ts.map +1 -1
- package/dist/src/core/bootstrap/providers/HelperServiceProvider.js +8 -3
- package/dist/src/core/bootstrap/providers/HelperServiceProvider.js.map +1 -1
- package/dist/src/core/bootstrap/providers/RouteServiceProvider.d.ts +2 -1
- package/dist/src/core/bootstrap/providers/RouteServiceProvider.d.ts.map +1 -1
- package/dist/src/core/bootstrap/providers/RouteServiceProvider.js +14 -4
- package/dist/src/core/bootstrap/providers/RouteServiceProvider.js.map +1 -1
- package/dist/src/core/bootstrap/providers/ServiceProvider.d.ts +4 -4
- package/dist/src/core/bootstrap/providers/ServiceProvider.d.ts.map +1 -1
- package/dist/src/core/bootstrap/providers/ServiceProvider.js +5 -5
- package/dist/src/core/bootstrap/providers/ServiceProvider.js.map +1 -1
- package/dist/src/core/bootstrap/providers/ViewServiceProvider.d.ts +1 -1
- package/dist/src/core/bootstrap/providers/ViewServiceProvider.d.ts.map +1 -1
- package/dist/src/core/bootstrap/providers/ViewServiceProvider.js +3 -3
- package/dist/src/core/bootstrap/providers/ViewServiceProvider.js.map +1 -1
- package/dist/src/core/bootstrap/providers/default-providers.d.ts +1 -1
- package/dist/src/core/bootstrap/providers/default-providers.d.ts.map +1 -1
- package/dist/src/core/bootstrap/providers/default-providers.js +44 -11
- package/dist/src/core/bootstrap/providers/default-providers.js.map +1 -1
- package/dist/src/core/bootstrap/providers/index.d.ts +9 -9
- package/dist/src/core/bootstrap/providers/index.d.ts.map +1 -1
- package/dist/src/core/bootstrap/providers/index.js +8 -8
- package/dist/src/core/bootstrap/providers/index.js.map +1 -1
- package/dist/src/core/bootstrap/providers/provider-order.d.ts +1 -1
- package/dist/src/core/bootstrap/providers/provider-order.d.ts.map +1 -1
- package/dist/src/core/bootstrap/ssr.d.ts +47 -0
- package/dist/src/core/bootstrap/ssr.d.ts.map +1 -0
- package/dist/src/core/bootstrap/ssr.js +125 -0
- package/dist/src/core/bootstrap/ssr.js.map +1 -0
- package/dist/src/core/cache/ViewCache.d.ts +1 -1
- package/dist/src/core/cache/ViewCache.d.ts.map +1 -1
- package/dist/src/core/cache/index.d.ts +1 -1
- package/dist/src/core/cache/index.d.ts.map +1 -1
- package/dist/src/core/cache/index.js +1 -1
- package/dist/src/core/cache/index.js.map +1 -1
- package/dist/src/core/contracts/ApplicationInterface.d.ts +13 -11
- package/dist/src/core/contracts/ApplicationInterface.d.ts.map +1 -1
- package/dist/src/core/contracts/BlockInterface.d.ts +10 -10
- package/dist/src/core/contracts/BlockInterface.d.ts.map +1 -1
- package/dist/src/core/contracts/BundleInterface.d.ts +38 -0
- package/dist/src/core/contracts/BundleInterface.d.ts.map +1 -0
- package/dist/src/core/contracts/BundleInterface.js +2 -0
- package/dist/src/core/contracts/BundleInterface.js.map +1 -0
- package/dist/src/core/contracts/ComponentInterface.d.ts +7 -6
- package/dist/src/core/contracts/ComponentInterface.d.ts.map +1 -1
- package/dist/src/core/contracts/ElementInterface.d.ts +91 -27
- package/dist/src/core/contracts/ElementInterface.d.ts.map +1 -1
- package/dist/src/core/contracts/HeadServiceInterface.d.ts +37 -0
- package/dist/src/core/contracts/HeadServiceInterface.d.ts.map +1 -0
- package/dist/src/core/contracts/HeadServiceInterface.js +3 -0
- package/dist/src/core/contracts/HeadServiceInterface.js.map +1 -0
- package/dist/src/core/contracts/HelperInterface.d.ts +9 -1
- package/dist/src/core/contracts/HelperInterface.d.ts.map +1 -1
- package/dist/src/core/contracts/HttpServiceInterface.d.ts +3 -0
- package/dist/src/core/contracts/HttpServiceInterface.d.ts.map +1 -1
- package/dist/src/core/contracts/MarkerInterface.d.ts +29 -44
- package/dist/src/core/contracts/MarkerInterface.d.ts.map +1 -1
- package/dist/src/core/contracts/ReactiveInterface.d.ts +9 -9
- package/dist/src/core/contracts/ReactiveInterface.d.ts.map +1 -1
- package/dist/src/core/contracts/RouterInterface.d.ts +5 -2
- package/dist/src/core/contracts/RouterInterface.d.ts.map +1 -1
- package/dist/src/core/contracts/SectionInterface.d.ts +48 -0
- package/dist/src/core/contracts/SectionInterface.d.ts.map +1 -0
- package/dist/src/core/contracts/SectionInterface.js +2 -0
- package/dist/src/core/contracts/SectionInterface.js.map +1 -0
- package/dist/src/core/contracts/ServiceProviderInterface.d.ts +3 -3
- package/dist/src/core/contracts/ServiceProviderInterface.d.ts.map +1 -1
- package/dist/src/core/contracts/ViewControllerInterface.d.ts +116 -15
- package/dist/src/core/contracts/ViewControllerInterface.d.ts.map +1 -1
- package/dist/src/core/contracts/ViewInterface.d.ts +31 -5
- package/dist/src/core/contracts/ViewInterface.d.ts.map +1 -1
- package/dist/src/core/contracts/ViewManagerInterface.d.ts +47 -5
- package/dist/src/core/contracts/ViewManagerInterface.d.ts.map +1 -1
- package/dist/src/core/contracts/ViewStateInterface.d.ts +39 -2
- package/dist/src/core/contracts/ViewStateInterface.d.ts.map +1 -1
- package/dist/src/core/contracts/common.d.ts +3 -3
- package/dist/src/core/contracts/common.js +3 -3
- package/dist/src/core/contracts/utils.d.ts +19 -19
- package/dist/src/core/contracts/utils.d.ts.map +1 -1
- package/dist/src/core/contracts/views.d.ts +1 -22
- package/dist/src/core/contracts/views.d.ts.map +1 -1
- package/dist/src/core/devtools/hook.d.ts +66 -0
- package/dist/src/core/devtools/hook.d.ts.map +1 -0
- package/dist/src/core/devtools/hook.js +114 -0
- package/dist/src/core/devtools/hook.js.map +1 -0
- package/dist/src/core/devtools/index.d.ts +34 -0
- package/dist/src/core/devtools/index.d.ts.map +1 -0
- package/dist/src/core/devtools/index.js +33 -0
- package/dist/src/core/devtools/index.js.map +1 -0
- package/dist/src/core/devtools/inspector.d.ts +31 -0
- package/dist/src/core/devtools/inspector.d.ts.map +1 -0
- package/dist/src/core/devtools/inspector.js +249 -0
- package/dist/src/core/devtools/inspector.js.map +1 -0
- package/dist/src/core/elements/Block.d.ts +9 -7
- package/dist/src/core/elements/Block.d.ts.map +1 -1
- package/dist/src/core/elements/Block.js +33 -9
- package/dist/src/core/elements/Block.js.map +1 -1
- package/dist/src/core/elements/BlockOutlet.d.ts +19 -8
- package/dist/src/core/elements/BlockOutlet.d.ts.map +1 -1
- package/dist/src/core/elements/BlockOutlet.js +57 -13
- package/dist/src/core/elements/BlockOutlet.js.map +1 -1
- package/dist/src/core/elements/Component.d.ts +83 -11
- package/dist/src/core/elements/Component.d.ts.map +1 -1
- package/dist/src/core/elements/Component.js +334 -13
- package/dist/src/core/elements/Component.js.map +1 -1
- package/dist/src/core/elements/ForeachSlotCache.d.ts +95 -0
- package/dist/src/core/elements/ForeachSlotCache.d.ts.map +1 -0
- package/dist/src/core/elements/ForeachSlotCache.js +149 -0
- package/dist/src/core/elements/ForeachSlotCache.js.map +1 -0
- package/dist/src/core/elements/Fragment.d.ts +19 -13
- package/dist/src/core/elements/Fragment.d.ts.map +1 -1
- package/dist/src/core/elements/Fragment.js +43 -20
- package/dist/src/core/elements/Fragment.js.map +1 -1
- package/dist/src/core/elements/Html.d.ts +89 -12
- package/dist/src/core/elements/Html.d.ts.map +1 -1
- package/dist/src/core/elements/Html.js +707 -106
- package/dist/src/core/elements/Html.js.map +1 -1
- package/dist/src/core/elements/Output.d.ts +34 -10
- package/dist/src/core/elements/Output.d.ts.map +1 -1
- package/dist/src/core/elements/Output.js +141 -26
- package/dist/src/core/elements/Output.js.map +1 -1
- package/dist/src/core/elements/Reactive.d.ts +85 -14
- package/dist/src/core/elements/Reactive.d.ts.map +1 -1
- package/dist/src/core/elements/Reactive.js +315 -41
- package/dist/src/core/elements/Reactive.js.map +1 -1
- package/dist/src/core/elements/TextElement.d.ts +11 -7
- package/dist/src/core/elements/TextElement.d.ts.map +1 -1
- package/dist/src/core/elements/TextElement.js +18 -11
- package/dist/src/core/elements/TextElement.js.map +1 -1
- package/dist/src/core/elements/Wrapper.d.ts +24 -13
- package/dist/src/core/elements/Wrapper.d.ts.map +1 -1
- package/dist/src/core/elements/Wrapper.js +65 -8
- package/dist/src/core/elements/Wrapper.js.map +1 -1
- package/dist/src/core/elements/Yield.d.ts +10 -9
- package/dist/src/core/elements/Yield.d.ts.map +1 -1
- package/dist/src/core/elements/Yield.js +31 -19
- package/dist/src/core/elements/Yield.js.map +1 -1
- package/dist/src/core/elements/helpers.d.ts +7 -7
- package/dist/src/core/elements/helpers.d.ts.map +1 -1
- package/dist/src/core/elements/helpers.js +4 -4
- package/dist/src/core/elements/index.d.ts +12 -11
- package/dist/src/core/elements/index.d.ts.map +1 -1
- package/dist/src/core/elements/index.js +12 -11
- package/dist/src/core/elements/index.js.map +1 -1
- package/dist/src/core/elements/reconcileChildren.d.ts +7 -0
- package/dist/src/core/elements/reconcileChildren.d.ts.map +1 -0
- package/dist/src/core/elements/reconcileChildren.js +74 -0
- package/dist/src/core/elements/reconcileChildren.js.map +1 -0
- package/dist/src/core/hellpers/utils.d.ts +2 -2
- package/dist/src/core/hellpers/utils.js +4 -4
- package/dist/src/core/helpers/ApiClient.d.ts +58 -0
- package/dist/src/core/helpers/ApiClient.d.ts.map +1 -0
- package/dist/src/core/helpers/ApiClient.js +131 -0
- package/dist/src/core/helpers/ApiClient.js.map +1 -0
- package/dist/src/core/helpers/app.d.ts +3 -0
- package/dist/src/core/helpers/app.d.ts.map +1 -0
- package/dist/src/core/helpers/app.js +63 -0
- package/dist/src/core/helpers/app.js.map +1 -0
- package/dist/src/core/helpers/transition.d.ts +34 -0
- package/dist/src/core/helpers/transition.d.ts.map +1 -0
- package/dist/src/core/helpers/transition.js +118 -0
- package/dist/src/core/helpers/transition.js.map +1 -0
- package/dist/src/core/helpers/utils.d.ts +26 -0
- package/dist/src/core/helpers/utils.d.ts.map +1 -0
- package/dist/src/core/helpers/utils.js +96 -0
- package/dist/src/core/helpers/utils.js.map +1 -0
- package/dist/src/core/helpers/view.d.ts +39 -0
- package/dist/src/core/helpers/view.d.ts.map +1 -0
- package/dist/src/core/helpers/view.js +286 -0
- package/dist/src/core/helpers/view.js.map +1 -0
- package/dist/src/core/routers/Router.d.ts +108 -7
- package/dist/src/core/routers/Router.d.ts.map +1 -1
- package/dist/src/core/routers/Router.js +444 -68
- package/dist/src/core/routers/Router.js.map +1 -1
- package/dist/src/core/routers/index.d.ts +2 -2
- package/dist/src/core/routers/index.d.ts.map +1 -1
- package/dist/src/core/routers/index.js +1 -1
- package/dist/src/core/routers/index.js.map +1 -1
- package/dist/src/core/services/AssetManager.d.ts +112 -0
- package/dist/src/core/services/AssetManager.d.ts.map +1 -0
- package/dist/src/core/services/AssetManager.js +361 -0
- package/dist/src/core/services/AssetManager.js.map +1 -0
- package/dist/src/core/services/BlockManager.d.ts +73 -2
- package/dist/src/core/services/BlockManager.d.ts.map +1 -1
- package/dist/src/core/services/BlockManager.js +270 -48
- package/dist/src/core/services/BlockManager.js.map +1 -1
- package/dist/src/core/services/DomService.js +3 -3
- package/dist/src/core/services/DomService.js.map +1 -1
- package/dist/src/core/services/HeadService.d.ts +24 -0
- package/dist/src/core/services/HeadService.d.ts.map +1 -0
- package/dist/src/core/services/HeadService.js +120 -0
- package/dist/src/core/services/HeadService.js.map +1 -0
- package/dist/src/core/services/HelperService.d.ts +14 -3
- package/dist/src/core/services/HelperService.d.ts.map +1 -1
- package/dist/src/core/services/HelperService.js +32 -2
- package/dist/src/core/services/HelperService.js.map +1 -1
- package/dist/src/core/services/HttpService.d.ts +8 -0
- package/dist/src/core/services/HttpService.d.ts.map +1 -1
- package/dist/src/core/services/HttpService.js +121 -47
- package/dist/src/core/services/HttpService.js.map +1 -1
- package/dist/src/core/services/MarkerRegistry.d.ts +51 -8
- package/dist/src/core/services/MarkerRegistry.d.ts.map +1 -1
- package/dist/src/core/services/MarkerRegistry.js +135 -14
- package/dist/src/core/services/MarkerRegistry.js.map +1 -1
- package/dist/src/core/services/PageCache.d.ts +101 -0
- package/dist/src/core/services/PageCache.d.ts.map +1 -0
- package/dist/src/core/services/PageCache.js +184 -0
- package/dist/src/core/services/PageCache.js.map +1 -0
- package/dist/src/core/services/SectionManager.d.ts +100 -0
- package/dist/src/core/services/SectionManager.d.ts.map +1 -0
- package/dist/src/core/services/SectionManager.js +408 -0
- package/dist/src/core/services/SectionManager.js.map +1 -0
- package/dist/src/core/services/StorageService.js +1 -1
- package/dist/src/core/services/TranslationService.d.ts +21 -0
- package/dist/src/core/services/TranslationService.d.ts.map +1 -0
- package/dist/src/core/services/TranslationService.js +95 -0
- package/dist/src/core/services/TranslationService.js.map +1 -0
- package/dist/src/core/services/index.d.ts +11 -8
- package/dist/src/core/services/index.d.ts.map +1 -1
- package/dist/src/core/services/index.js +11 -8
- package/dist/src/core/services/index.js.map +1 -1
- package/dist/src/core/types/utils.d.ts +8 -8
- package/dist/src/core/types/utils.d.ts.map +1 -1
- package/dist/src/core/view/LoopContext.d.ts +21 -1
- package/dist/src/core/view/LoopContext.d.ts.map +1 -1
- package/dist/src/core/view/LoopContext.js +36 -0
- package/dist/src/core/view/LoopContext.js.map +1 -1
- package/dist/src/core/view/ResourceScope.d.ts +38 -0
- package/dist/src/core/view/ResourceScope.d.ts.map +1 -0
- package/dist/src/core/view/ResourceScope.js +167 -0
- package/dist/src/core/view/ResourceScope.js.map +1 -0
- package/dist/src/core/view/Section.d.ts +17 -32
- package/dist/src/core/view/Section.d.ts.map +1 -1
- package/dist/src/core/view/Section.js +14 -55
- package/dist/src/core/view/Section.js.map +1 -1
- package/dist/src/core/view/View.d.ts +43 -7
- package/dist/src/core/view/View.d.ts.map +1 -1
- package/dist/src/core/view/View.js +22 -4
- package/dist/src/core/view/View.js.map +1 -1
- package/dist/src/core/view/ViewController.d.ts +313 -40
- package/dist/src/core/view/ViewController.d.ts.map +1 -1
- package/dist/src/core/view/ViewController.js +1002 -147
- package/dist/src/core/view/ViewController.js.map +1 -1
- package/dist/src/core/view/ViewManager.d.ts +318 -27
- package/dist/src/core/view/ViewManager.d.ts.map +1 -1
- package/dist/src/core/view/ViewManager.js +1199 -258
- package/dist/src/core/view/ViewManager.js.map +1 -1
- package/dist/src/core/view/ViewState.d.ts +185 -6
- package/dist/src/core/view/ViewState.d.ts.map +1 -1
- package/dist/src/core/view/ViewState.js +851 -123
- package/dist/src/core/view/ViewState.js.map +1 -1
- package/dist/src/core/view/index.d.ts +5 -5
- package/dist/src/core/view/index.d.ts.map +1 -1
- package/dist/src/core/view/index.js +5 -5
- package/dist/src/core/view/index.js.map +1 -1
- package/dist/src/testing/index.d.ts +69 -0
- package/dist/src/testing/index.d.ts.map +1 -0
- package/dist/src/testing/index.js +140 -0
- package/dist/src/testing/index.js.map +1 -0
- package/index.ts +29 -5
- package/package.json +30 -21
- package/plugins.ts +2 -2
- package/src/core/app/Application.ts +58 -31
- package/src/core/bootstrap/app.ts +80 -6
- package/src/core/bootstrap/bundle.ts +101 -0
- package/src/core/bootstrap/providers/ApiServiceProvider.ts +4 -4
- package/src/core/bootstrap/providers/CoreServiceProvider.ts +14 -8
- package/src/core/bootstrap/providers/HelperServiceProvider.ts +8 -3
- package/src/core/bootstrap/providers/RouteServiceProvider.ts +15 -4
- package/src/core/bootstrap/providers/ServiceProvider.ts +8 -8
- package/src/core/bootstrap/providers/ViewServiceProvider.ts +3 -3
- package/src/core/bootstrap/providers/default-providers.ts +51 -16
- package/src/core/bootstrap/providers/index.ts +9 -9
- package/src/core/bootstrap/providers/provider-order.test.ts +16 -27
- package/src/core/bootstrap/providers/provider-order.ts +1 -1
- package/src/core/bootstrap/ssr.ts +136 -0
- package/src/core/cache/ViewCache.ts +1 -1
- package/src/core/cache/index.ts +1 -1
- package/src/core/contracts/ApplicationInterface.ts +13 -11
- package/src/core/contracts/BlockInterface.ts +18 -18
- package/src/core/contracts/BundleInterface.ts +40 -0
- package/src/core/contracts/ComponentInterface.ts +7 -6
- package/src/core/contracts/ElementInterface.ts +95 -27
- package/src/core/contracts/HeadServiceInterface.ts +41 -0
- package/src/core/contracts/HelperInterface.ts +9 -1
- package/src/core/contracts/HttpServiceInterface.ts +3 -0
- package/src/core/contracts/MarkerInterface.ts +22 -49
- package/src/core/contracts/ReactiveInterface.ts +9 -9
- package/src/core/contracts/RouterInterface.ts +5 -2
- package/src/core/contracts/SectionInterface.ts +49 -0
- package/src/core/contracts/ServiceProviderInterface.ts +3 -3
- package/src/core/contracts/ViewControllerInterface.ts +124 -16
- package/src/core/contracts/ViewInterface.ts +34 -5
- package/src/core/contracts/ViewManagerInterface.ts +40 -5
- package/src/core/contracts/ViewStateInterface.ts +39 -2
- package/src/core/contracts/common.ts +3 -3
- package/src/core/contracts/utils.ts +19 -19
- package/src/core/contracts/views.ts +2 -22
- package/src/core/devtools/hook.ts +142 -0
- package/src/core/devtools/index.ts +38 -0
- package/src/core/devtools/inspector.ts +270 -0
- package/src/core/elements/Block.ts +43 -21
- package/src/core/elements/BlockOutlet.ts +61 -21
- package/src/core/elements/Component.ts +352 -18
- package/src/core/elements/ElementManager.ts +9 -9
- package/src/core/elements/ForeachSlotCache.ts +170 -0
- package/src/core/elements/Fragment.ts +50 -32
- package/src/core/elements/Html.ts +696 -117
- package/src/core/elements/Output.ts +147 -30
- package/src/core/elements/Reactive.ts +329 -52
- package/src/core/elements/TextElement.ts +25 -16
- package/src/core/elements/Wrapper.ts +84 -18
- package/src/core/elements/Yield.ts +35 -24
- package/src/core/elements/helpers.ts +12 -12
- package/src/core/elements/index.ts +25 -24
- package/src/core/elements/reconcileChildren.ts +70 -0
- package/src/core/{hellpers → helpers}/ApiClient.ts +8 -1
- package/src/core/{hellpers → helpers}/app.ts +13 -2
- package/src/core/helpers/transition.ts +127 -0
- package/src/core/{hellpers → helpers}/utils.ts +4 -4
- package/src/core/helpers/view.ts +283 -0
- package/src/core/routers/Router.ts +458 -64
- package/src/core/routers/index.ts +2 -2
- package/src/core/services/AssetManager.ts +387 -0
- package/src/core/services/BlockManager.ts +272 -50
- package/src/core/services/DomService.ts +3 -3
- package/src/core/services/HeadService.ts +124 -0
- package/src/core/services/HelperService.ts +34 -4
- package/src/core/services/HttpService.ts +116 -55
- package/src/core/services/MarkerRegistry.ts +142 -16
- package/src/core/services/PageCache.ts +239 -0
- package/src/core/services/SectionManager.ts +387 -0
- package/src/core/services/StorageService.ts +1 -1
- package/src/core/services/TranslationService.ts +91 -0
- package/src/core/services/index.ts +11 -8
- package/src/core/types/utils.ts +8 -8
- package/src/core/view/LoopContext.ts +38 -1
- package/src/core/view/ResourceScope.ts +174 -0
- package/src/core/view/Section.ts +21 -68
- package/src/core/view/View.ts +57 -8
- package/src/core/view/ViewController.ts +1070 -186
- package/src/core/view/ViewManager.ts +1346 -272
- package/src/core/view/ViewState.ts +834 -116
- package/src/core/view/index.ts +5 -5
- package/src/testing/index.ts +184 -0
- package/dist/src/core/services/MarkerService.d.ts +0 -299
- package/dist/src/core/services/MarkerService.d.ts.map +0 -1
- package/dist/src/core/services/MarkerService.js +0 -723
- package/dist/src/core/services/MarkerService.js.map +0 -1
- package/src/core/services/MarkerService.ts +0 -923
|
@@ -20,6 +20,10 @@
|
|
|
20
20
|
export interface HttpRequestConfig extends RequestInit {
|
|
21
21
|
headers?: Record<string, string>;
|
|
22
22
|
timeout?: number;
|
|
23
|
+
/** Default: cancel only an identical method + final URL. */
|
|
24
|
+
dedupe?: 'cancel-previous' | 'parallel';
|
|
25
|
+
/** Explicit logical identity, e.g. latest search across different queries. */
|
|
26
|
+
requestKey?: string;
|
|
23
27
|
[key: string]: any;
|
|
24
28
|
}
|
|
25
29
|
|
|
@@ -57,7 +61,8 @@ export class HttpService {
|
|
|
57
61
|
private timeout: number = 10000;
|
|
58
62
|
private defaultHeaders: Record<string, string> = {};
|
|
59
63
|
private interceptors: HttpInterceptor[] = [];
|
|
60
|
-
private pending = new Map<string, AbortController
|
|
64
|
+
private pending = new Map<string, Set<AbortController>>();
|
|
65
|
+
private activeRequests = new Set<AbortController>();
|
|
61
66
|
|
|
62
67
|
// ─── Config ─────────────────────────────────────────────────
|
|
63
68
|
|
|
@@ -103,58 +108,84 @@ export class HttpService {
|
|
|
103
108
|
data: any = null,
|
|
104
109
|
options: HttpRequestConfig = {},
|
|
105
110
|
): Promise<HttpResponse<T>> {
|
|
106
|
-
// Build full URL
|
|
107
|
-
let fullUrl = url.startsWith('http') ? url : `${this.baseUrl}${url}`;
|
|
108
|
-
|
|
109
|
-
// Cancel duplicate in-flight request
|
|
110
|
-
const requestKey = `${method.toUpperCase()}:${fullUrl}`;
|
|
111
|
-
this.pending.get(requestKey)?.abort();
|
|
112
|
-
|
|
113
111
|
const controller = new AbortController();
|
|
114
|
-
this.
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
112
|
+
this.activeRequests.add(controller);
|
|
113
|
+
const detach: (() => void)[] = [];
|
|
114
|
+
const linked = new Set<AbortSignal>();
|
|
115
|
+
const linkSignal = (signal?: AbortSignal | null) => {
|
|
116
|
+
if (!signal || signal === controller.signal || linked.has(signal)) return;
|
|
117
|
+
linked.add(signal);
|
|
118
|
+
const abort = () => controller.abort(signal.reason);
|
|
119
|
+
if (signal.aborted) abort();
|
|
120
|
+
else {
|
|
121
|
+
signal.addEventListener('abort', abort, { once: true });
|
|
122
|
+
detach.push(() => signal.removeEventListener('abort', abort));
|
|
123
|
+
}
|
|
122
124
|
};
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
(
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
125
|
+
linkSignal(options.signal);
|
|
126
|
+
let requestKey: string | undefined;
|
|
127
|
+
const timeoutId = setTimeout(() => controller.abort(), options.timeout ?? this.timeout);
|
|
128
|
+
try {
|
|
129
|
+
let config: HttpRequestConfig = {
|
|
130
|
+
...options,
|
|
131
|
+
method: (options.method ?? method).toUpperCase(),
|
|
132
|
+
headers: { ...this.defaultHeaders, ...options.headers },
|
|
133
|
+
signal: controller.signal,
|
|
134
|
+
};
|
|
135
|
+
if (typeof window !== 'undefined') {
|
|
136
|
+
const revision = (window as any).APP_CONFIGS?.view?.revision;
|
|
137
|
+
const headers = config.headers as Record<string, string>;
|
|
138
|
+
if (typeof revision === 'string' && !headers['X-Saola-View-Revision']) {
|
|
139
|
+
headers['X-Saola-View-Revision'] = revision;
|
|
140
|
+
headers['X-Sao-Response'] ??= 'json';
|
|
141
|
+
}
|
|
140
142
|
}
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
urlObj.searchParams.append(key, String(value));
|
|
143
|
+
controller.signal.throwIfAborted();
|
|
144
|
+
for (const i of this.interceptors) {
|
|
145
|
+
if (i.request) config = await i.request(config);
|
|
146
|
+
linkSignal(config.signal);
|
|
147
|
+
config.signal = controller.signal;
|
|
148
|
+
controller.signal.throwIfAborted();
|
|
148
149
|
}
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
150
|
+
config.method = (config.method ?? method).toUpperCase();
|
|
151
|
+
if (data !== null && ['POST', 'PUT', 'PATCH'].includes(config.method)) {
|
|
152
|
+
const ct = config.headers?.['Content-Type'];
|
|
153
|
+
if (data instanceof FormData) {
|
|
154
|
+
config.body = data;
|
|
155
|
+
if (config.headers) delete config.headers['Content-Type'];
|
|
156
|
+
} else if (ct === 'application/json' || !ct) {
|
|
157
|
+
config.headers ??= {};
|
|
158
|
+
config.headers['Content-Type'] = 'application/json';
|
|
159
|
+
config.body = JSON.stringify(data);
|
|
160
|
+
} else config.body = data;
|
|
161
|
+
}
|
|
162
|
+
const urlObj = this.resolveUrl(url);
|
|
163
|
+
if (data && config.method === 'GET' && typeof data === 'object') {
|
|
164
|
+
for (const [key, value] of Object.entries(data)) urlObj.searchParams.append(key, String(value));
|
|
165
|
+
}
|
|
166
|
+
const fullUrl = urlObj.toString();
|
|
167
|
+
requestKey = `${config.method}:${config.requestKey ?? fullUrl}`;
|
|
168
|
+
let group = this.pending.get(requestKey);
|
|
169
|
+
if (config.dedupe !== 'parallel') {
|
|
170
|
+
for (const previous of group ?? []) previous.abort();
|
|
171
|
+
}
|
|
172
|
+
if (!group) this.pending.set(requestKey, group = new Set());
|
|
173
|
+
group.add(controller);
|
|
154
174
|
const raw = await fetch(fullUrl, config);
|
|
155
|
-
clearTimeout(timeoutId);
|
|
156
|
-
|
|
157
175
|
const responseData = await raw.json().catch(() => ({}));
|
|
176
|
+
controller.signal.throwIfAborted();
|
|
177
|
+
|
|
178
|
+
const viewContext = responseData?.viewContext;
|
|
179
|
+
const currentContext = typeof window !== 'undefined'
|
|
180
|
+
? (window as any).APP_CONFIGS?.view?.systemData?.__context__
|
|
181
|
+
: null;
|
|
182
|
+
if (viewContext?.changed === true
|
|
183
|
+
&& (!currentContext || viewContext.context === currentContext)
|
|
184
|
+
&& typeof window !== 'undefined') {
|
|
185
|
+
window.dispatchEvent(new CustomEvent('saola:view-context', {
|
|
186
|
+
detail: viewContext,
|
|
187
|
+
}));
|
|
188
|
+
}
|
|
158
189
|
|
|
159
190
|
let response: HttpResponse<T> = {
|
|
160
191
|
status: raw.ok,
|
|
@@ -168,25 +199,43 @@ export class HttpService {
|
|
|
168
199
|
if (i.response) response = await i.response(response);
|
|
169
200
|
}
|
|
170
201
|
|
|
171
|
-
|
|
202
|
+
controller.signal.throwIfAborted();
|
|
172
203
|
|
|
173
204
|
if (!raw.ok) {
|
|
174
|
-
|
|
205
|
+
// Ưu tiên message của server (Laravel 422 trả "The email field is
|
|
206
|
+
// required."): caller nào cũng in `err.message`, mà "HTTP 422
|
|
207
|
+
// Unprocessable Content" thì người dùng không biết sai ở đâu.
|
|
208
|
+
// Body đầy đủ (kèm `errors` từng field) vẫn nằm ở `err.response`.
|
|
209
|
+
const serverMessage = typeof (responseData as any)?.message === 'string'
|
|
210
|
+
? (responseData as any).message.trim()
|
|
211
|
+
: '';
|
|
212
|
+
const message = serverMessage !== ''
|
|
213
|
+
? serverMessage
|
|
214
|
+
: `HTTP ${raw.status} ${raw.statusText}`;
|
|
215
|
+
throw Object.assign(new Error(message), { response });
|
|
175
216
|
}
|
|
176
217
|
|
|
177
218
|
return response;
|
|
178
219
|
} catch (err) {
|
|
179
|
-
this.pending.delete(requestKey);
|
|
180
220
|
|
|
181
221
|
let error = err as Error;
|
|
182
222
|
for (const i of this.interceptors) {
|
|
183
223
|
if (i.error) error = await i.error(error);
|
|
184
224
|
}
|
|
185
225
|
|
|
186
|
-
if (error.name === 'AbortError') {
|
|
187
|
-
throw new Error('Request cancelled');
|
|
226
|
+
if (controller.signal.aborted || error.name === 'AbortError') {
|
|
227
|
+
throw Object.assign(new Error('Request cancelled'), { name: 'AbortError', cause: error });
|
|
188
228
|
}
|
|
189
229
|
throw error;
|
|
230
|
+
} finally {
|
|
231
|
+
clearTimeout(timeoutId);
|
|
232
|
+
for (const off of detach) off();
|
|
233
|
+
this.activeRequests.delete(controller);
|
|
234
|
+
if (requestKey !== undefined) {
|
|
235
|
+
const group = this.pending.get(requestKey);
|
|
236
|
+
group?.delete(controller);
|
|
237
|
+
if (group?.size === 0) this.pending.delete(requestKey);
|
|
238
|
+
}
|
|
190
239
|
}
|
|
191
240
|
}
|
|
192
241
|
|
|
@@ -216,17 +265,29 @@ export class HttpService {
|
|
|
216
265
|
|
|
217
266
|
/** Cancel all pending requests */
|
|
218
267
|
cancelAll(): void {
|
|
219
|
-
this.
|
|
268
|
+
for (const controller of this.activeRequests) controller.abort();
|
|
220
269
|
this.pending.clear();
|
|
221
270
|
}
|
|
222
271
|
|
|
223
272
|
/** Cancel a specific pending request */
|
|
224
273
|
cancel(url: string, method: string = 'GET'): void {
|
|
225
|
-
|
|
226
|
-
|
|
274
|
+
this.cancelKey(this.resolveUrl(url).toString(), method);
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
/** Cancel a logical requestKey (all parallel requests in the group). */
|
|
278
|
+
cancelKey(identity: string, method: string = 'GET'): void {
|
|
279
|
+
const key = `${method.toUpperCase()}:${identity}`;
|
|
280
|
+
for (const controller of this.pending.get(key) ?? []) controller.abort();
|
|
227
281
|
this.pending.delete(key);
|
|
228
282
|
}
|
|
229
283
|
|
|
284
|
+
private resolveUrl(url: string): URL {
|
|
285
|
+
const full = /^(https?:)?\/\//i.test(url) ? url : `${this.baseUrl}${url}`;
|
|
286
|
+
const resolved = new URL(full, typeof window !== 'undefined' ? window.location.origin : 'http://localhost');
|
|
287
|
+
resolved.hash = ''; // fragments are never sent to the server
|
|
288
|
+
return resolved;
|
|
289
|
+
}
|
|
290
|
+
|
|
230
291
|
/** Destroy — cancel all + clear interceptors */
|
|
231
292
|
destroy(): void {
|
|
232
293
|
this.cancelAll();
|
|
@@ -18,12 +18,16 @@
|
|
|
18
18
|
* - DevTools (future) — to inspect/debug the element tree via markers
|
|
19
19
|
*/
|
|
20
20
|
|
|
21
|
-
import { MarkerRegistryRecord } from "../contracts/MarkerInterface";
|
|
21
|
+
import { MarkerRegistryInterface, MarkerRegistryRecord } from "../contracts/MarkerInterface.js";
|
|
22
22
|
|
|
23
23
|
|
|
24
|
-
export class MarkerRegistryService {
|
|
24
|
+
export class MarkerRegistryService implements MarkerRegistryInterface {
|
|
25
25
|
static class: string = 'MarkerRegistryService';
|
|
26
|
-
/**
|
|
26
|
+
/**
|
|
27
|
+
* Tag name → short abbreviation (for compact DOM comments).
|
|
28
|
+
* PHẢI khớp 1-1 với server core/ViewStorageManager::$markerTagShortcut —
|
|
29
|
+
* lệch shortcut nào thì marker loại đó không claim được khi hydrate.
|
|
30
|
+
*/
|
|
27
31
|
private shortcuts: Record<string, string> = {
|
|
28
32
|
view: 'v',
|
|
29
33
|
component: 'c',
|
|
@@ -34,9 +38,12 @@ export class MarkerRegistryService {
|
|
|
34
38
|
section: 's',
|
|
35
39
|
fragment: 'frg',
|
|
36
40
|
blockoutlet: 'bo',
|
|
41
|
+
output: 'o',
|
|
37
42
|
for: 'fo',
|
|
38
43
|
forin: 'fi',
|
|
39
44
|
foreach: 'fe',
|
|
45
|
+
forelse: 'fls',
|
|
46
|
+
each: 'ea',
|
|
40
47
|
while: 'wh',
|
|
41
48
|
if: 'if',
|
|
42
49
|
switch: 'sw',
|
|
@@ -60,6 +67,17 @@ export class MarkerRegistryService {
|
|
|
60
67
|
/** Delimiter between tag shortcut and ID in keys */
|
|
61
68
|
private delimiter: string = ':';
|
|
62
69
|
|
|
70
|
+
/**
|
|
71
|
+
* Saola marker prefix — format chuẩn (RUNTIME_CONTRACT.md §5.1):
|
|
72
|
+
* open: <!--s:{type}:{id}-s-->
|
|
73
|
+
* close: <!--s:{type}:{id}-e-->
|
|
74
|
+
* Phải khớp server (core ViewStorageManager) để hydration claim đúng.
|
|
75
|
+
*/
|
|
76
|
+
private prefix: string = 's';
|
|
77
|
+
/** Hậu tố đánh dấu open/close marker */
|
|
78
|
+
private openSuffix: string = '-s';
|
|
79
|
+
private closeSuffix: string = '-e';
|
|
80
|
+
|
|
63
81
|
/** Auto-increment counter for generating unique IDs */
|
|
64
82
|
private counter: number = 0;
|
|
65
83
|
|
|
@@ -165,6 +183,7 @@ export class MarkerRegistryService {
|
|
|
165
183
|
clear(): void {
|
|
166
184
|
this.records.clear();
|
|
167
185
|
this.counter = 0;
|
|
186
|
+
this.index = null;
|
|
168
187
|
}
|
|
169
188
|
|
|
170
189
|
/** Total number of registered markers */
|
|
@@ -172,41 +191,148 @@ export class MarkerRegistryService {
|
|
|
172
191
|
return this.records.size;
|
|
173
192
|
}
|
|
174
193
|
|
|
194
|
+
// ─── Marker Index (O(1) claim khi hydrate) ──────────────────
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Index text-comment → Comment node, dựng 1 lần cho mỗi lượt hydrate.
|
|
198
|
+
*
|
|
199
|
+
* Trước đây mỗi element (Reactive/Output/Component/Wrapper/BlockOutlet/Block)
|
|
200
|
+
* tự tạo TreeWalker quét toàn bộ comment trong parent để tìm đúng 2 chuỗi →
|
|
201
|
+
* O(số element × số comment). Với 400 row × 5 cột (~4000 marker) đo được
|
|
202
|
+
* ~210ms chỉ để claim. Index 1 lượt rồi Map.get đưa về O(N) tổng, ~1.5ms.
|
|
203
|
+
*
|
|
204
|
+
* null = chưa dựng (lazy — CSR không bao giờ chạm tới).
|
|
205
|
+
*/
|
|
206
|
+
private index: Map<string, Comment> | null = null;
|
|
207
|
+
|
|
208
|
+
/** Đã dựng lại index vì miss trong lượt microtask hiện tại chưa? */
|
|
209
|
+
private rebuiltOnMiss: boolean = false;
|
|
210
|
+
|
|
211
|
+
/** Bỏ index — gọi khi có HTML server MỚI vào DOM (đầu mỗi lượt hydrate). */
|
|
212
|
+
invalidateIndex(): void {
|
|
213
|
+
this.index = null;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
private buildIndex(): Map<string, Comment> {
|
|
217
|
+
const idx = new Map<string, Comment>();
|
|
218
|
+
const root = document.body ?? document.documentElement;
|
|
219
|
+
if (root) {
|
|
220
|
+
const head = this.prefix + this.delimiter; // "s:"
|
|
221
|
+
const walker = document.createTreeWalker(root, NodeFilter.SHOW_COMMENT);
|
|
222
|
+
let node: Comment | null;
|
|
223
|
+
while ((node = walker.nextNode() as Comment | null)) {
|
|
224
|
+
const value = (node.nodeValue ?? '').trim();
|
|
225
|
+
// Giữ node ĐẦU TIÊN theo document order — đúng thứ tự mà
|
|
226
|
+
// TreeWalker scan cũ trả về.
|
|
227
|
+
if (value.startsWith(head) && !idx.has(value)) idx.set(value, node);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
this.index = idx;
|
|
231
|
+
return idx;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* Claim cặp marker SSR `<!--s:{tag}:{id}-s-->` … `<!--s:{tag}:{id}-e-->`.
|
|
236
|
+
*
|
|
237
|
+
* @param scope Nếu truyền, cặp tìm được PHẢI nằm trong scope — không thì
|
|
238
|
+
* rơi về scan tuyến tính trong scope (giữ nguyên ngữ nghĩa cũ).
|
|
239
|
+
* @returns null khi server không render vùng này (partial hydration).
|
|
240
|
+
*/
|
|
241
|
+
claim(tag: string, id: string, scope?: Element | null): { open: Comment; close: Comment } | null {
|
|
242
|
+
const openText = this.openComment(tag, id);
|
|
243
|
+
const closeText = this.closeComment(tag, id);
|
|
244
|
+
|
|
245
|
+
let idx = this.index ?? this.buildIndex();
|
|
246
|
+
let open = idx.get(openText);
|
|
247
|
+
let close = idx.get(closeText);
|
|
248
|
+
|
|
249
|
+
// Miss có HAI nguyên nhân: (a) server không render vùng này — partial
|
|
250
|
+
// hydration, hợp lệ; (b) index cũ vì HTML server mới vào DOM sau lần
|
|
251
|
+
// dựng. Không phân biệt được trong O(1), nên dựng lại TỐI ĐA MỘT LẦN
|
|
252
|
+
// mỗi lượt microtask: burst hydrate đồng bộ chỉ tốn thêm 1 lượt quét,
|
|
253
|
+
// còn 499 miss thật sau đó vẫn O(1) (không quay lại O(N²)).
|
|
254
|
+
// Node rời DOM cũng là dấu hiệu index cũ → xử lý cùng nhánh.
|
|
255
|
+
const stale = (open && !open.isConnected) || (close && !close.isConnected);
|
|
256
|
+
if (stale || ((!open || !close) && !this.rebuiltOnMiss)) {
|
|
257
|
+
this.rebuiltOnMiss = true;
|
|
258
|
+
queueMicrotask(() => { this.rebuiltOnMiss = false; });
|
|
259
|
+
idx = this.buildIndex();
|
|
260
|
+
open = idx.get(openText);
|
|
261
|
+
close = idx.get(closeText);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
if (!open || !close || !open.isConnected || !close.isConnected) return null;
|
|
265
|
+
|
|
266
|
+
if (scope && !(scope.contains(open) && scope.contains(close))) {
|
|
267
|
+
return this.scanForPair(scope, openText, closeText);
|
|
268
|
+
}
|
|
269
|
+
return { open, close };
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
/** Fallback hiếm: quét tuyến tính trong scope (ngữ nghĩa scan cũ). */
|
|
273
|
+
private scanForPair(scope: Node, openText: string, closeText: string): { open: Comment; close: Comment } | null {
|
|
274
|
+
const walker = document.createTreeWalker(scope, NodeFilter.SHOW_COMMENT);
|
|
275
|
+
let openNode: Comment | null = null;
|
|
276
|
+
let node: Comment | null;
|
|
277
|
+
while ((node = walker.nextNode() as Comment | null)) {
|
|
278
|
+
const value = (node.nodeValue ?? '').trim();
|
|
279
|
+
if (!openNode && value === openText) { openNode = node; continue; }
|
|
280
|
+
if (openNode && value === closeText) return { open: openNode, close: node };
|
|
281
|
+
}
|
|
282
|
+
return null;
|
|
283
|
+
}
|
|
284
|
+
|
|
175
285
|
// ─── Comment Node Helpers ───────────────────────────────────
|
|
176
286
|
|
|
177
287
|
/**
|
|
178
288
|
* Create a comment string for a marker (open).
|
|
179
|
-
*
|
|
289
|
+
* Format chuẩn: 's:r:abc123-s' cho <!--s:r:abc123-s-->
|
|
180
290
|
*/
|
|
181
291
|
openComment(tag: string, id?: string): string {
|
|
182
|
-
|
|
292
|
+
const body = id ? `${this.shortcut(tag)}${this.delimiter}${id}` : this.shortcut(tag);
|
|
293
|
+
return `${this.prefix}${this.delimiter}${body}${this.openSuffix}`;
|
|
183
294
|
}
|
|
184
295
|
|
|
185
296
|
/**
|
|
186
297
|
* Create a comment string for a closing marker.
|
|
187
|
-
*
|
|
298
|
+
* Format chuẩn: 's:r:abc123-e' cho <!--s:r:abc123-e-->
|
|
188
299
|
*/
|
|
189
300
|
closeComment(tag: string, id?: string): string {
|
|
190
|
-
|
|
301
|
+
const body = id ? `${this.shortcut(tag)}${this.delimiter}${id}` : this.shortcut(tag);
|
|
302
|
+
return `${this.prefix}${this.delimiter}${body}${this.closeSuffix}`;
|
|
191
303
|
}
|
|
192
304
|
|
|
193
305
|
/**
|
|
194
|
-
* Parse a comment node's text to extract tag and id.
|
|
195
|
-
* '
|
|
196
|
-
* '
|
|
306
|
+
* Parse a comment node's text to extract tag and id (format chuẩn §5.1).
|
|
307
|
+
* 's:r:abc123-s' → { tag: 'reactive', id: 'abc123', isClose: false }
|
|
308
|
+
* 's:r:abc123-e' → { tag: 'reactive', id: 'abc123', isClose: true }
|
|
197
309
|
*/
|
|
198
310
|
parseComment(text: string): { tag: string; id: string; isClose: boolean } | null {
|
|
199
311
|
const trimmed = text.trim();
|
|
200
312
|
if (!trimmed) return null;
|
|
201
313
|
|
|
202
|
-
const
|
|
203
|
-
|
|
204
|
-
|
|
314
|
+
const head = this.prefix + this.delimiter; // "s:"
|
|
315
|
+
if (!trimmed.startsWith(head)) return null;
|
|
316
|
+
|
|
317
|
+
let body = trimmed.slice(head.length); // "r:abc123-s"
|
|
318
|
+
let isClose: boolean;
|
|
319
|
+
if (body.endsWith(this.openSuffix)) {
|
|
320
|
+
isClose = false;
|
|
321
|
+
body = body.slice(0, -this.openSuffix.length);
|
|
322
|
+
} else if (body.endsWith(this.closeSuffix)) {
|
|
323
|
+
isClose = true;
|
|
324
|
+
body = body.slice(0, -this.closeSuffix.length);
|
|
325
|
+
} else {
|
|
326
|
+
return null;
|
|
327
|
+
}
|
|
205
328
|
|
|
206
|
-
|
|
329
|
+
const delimIdx = body.indexOf(this.delimiter);
|
|
330
|
+
if (delimIdx === -1) {
|
|
331
|
+
return { tag: this.fullTag(body), id: '', isClose };
|
|
332
|
+
}
|
|
207
333
|
|
|
208
|
-
const shortTag =
|
|
209
|
-
const id =
|
|
334
|
+
const shortTag = body.slice(0, delimIdx);
|
|
335
|
+
const id = body.slice(delimIdx + 1);
|
|
210
336
|
|
|
211
337
|
return {
|
|
212
338
|
tag: this.fullTag(shortTag),
|