@exponential-at/ui 0.0.0-stage → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -0
- package/NOTICE +54 -0
- package/README.md +360 -2
- package/catalog/a11y.json +668 -0
- package/catalog/basic-map.json +104 -0
- package/catalog/code.json +58 -0
- package/catalog/core.catalog.json +4752 -0
- package/catalog/core.schema.json +22667 -0
- package/catalog/host.json +64 -0
- package/catalog/layout.json +20 -0
- package/catalog/limits.json +9 -0
- package/catalog/locale.json +48 -0
- package/catalog/macros.json +3417 -0
- package/catalog/recipes.json +61 -0
- package/catalog/strings.json +72 -0
- package/catalog/style.json +128 -0
- package/catalog/theme.schema.json +42543 -0
- package/catalog/tokens.json +47 -0
- package/conformance/README.md +217 -0
- package/conformance/baseline.ts +101 -0
- package/conformance/browser-page.ts +146 -0
- package/conformance/browser-suites.ts +683 -0
- package/conformance/compare.ts +201 -0
- package/conformance/dom.ts +96 -0
- package/conformance/dump.ts +163 -0
- package/conformance/fonts.json +154 -0
- package/conformance/manifest.json +224 -0
- package/conformance/parity-compare.ts +191 -0
- package/conformance/parity-report.schema.json +73 -0
- package/conformance/parity.ts +412 -0
- package/conformance/pixel.ts +177 -0
- package/conformance/primitives-page.ts +49 -0
- package/conformance/report.schema.json +66 -0
- package/conformance/run.ts +118 -0
- package/dist/chunks/index-98npjvsd.js +3940 -0
- package/dist/chunks/index-98npjvsd.js.map +27 -0
- package/dist/chunks/index-gwkt14w3.js +7314 -0
- package/dist/chunks/index-gwkt14w3.js.map +10 -0
- package/dist/chunks/index-njt7yzzm.js +134 -0
- package/dist/chunks/index-njt7yzzm.js.map +9 -0
- package/dist/chunks/index-we7va6v6.js +7984 -0
- package/dist/chunks/index-we7va6v6.js.map +15 -0
- package/dist/chunks/index-xrm6f7wc.js +2563 -0
- package/dist/chunks/index-xrm6f7wc.js.map +10 -0
- package/dist/conformance.js +182749 -0
- package/dist/conformance.js.map +10 -0
- package/dist/entries/prompt.js +251 -0
- package/dist/entries/prompt.js.map +11 -0
- package/dist/entries/schema.js +1725 -0
- package/dist/entries/schema.js.map +11 -0
- package/dist/host/index.js +122 -0
- package/dist/host/index.js.map +9 -0
- package/dist/index.js +3213 -0
- package/dist/index.js.map +27 -0
- package/dist/types/src/a11y.d.ts +21 -0
- package/dist/types/src/animation.d.ts +76 -0
- package/dist/types/src/basic-map.d.ts +38 -0
- package/dist/types/src/builder.d.ts +50 -0
- package/dist/types/src/catalog.d.ts +54 -0
- package/dist/types/src/catalog.described.d.ts +33 -0
- package/dist/types/src/catalog.generated.d.ts +829 -0
- package/dist/types/src/chart.d.ts +46 -0
- package/dist/types/src/code.d.ts +44 -0
- package/dist/types/src/color.d.ts +20 -0
- package/dist/types/src/conformance.d.ts +39 -0
- package/dist/types/src/connector/app.d.ts +14 -0
- package/dist/types/src/connector/connector.d.ts +77 -0
- package/dist/types/src/connector/index.d.ts +4 -0
- package/dist/types/src/css.d.ts +29 -0
- package/dist/types/src/define.d.ts +66 -0
- package/dist/types/src/direction.d.ts +16 -0
- package/dist/types/src/dynamic.d.ts +159 -0
- package/dist/types/src/entries/prompt.d.ts +11 -0
- package/dist/types/src/entries/schema.d.ts +8 -0
- package/dist/types/src/expr.d.ts +71 -0
- package/dist/types/src/extension.d.ts +4 -0
- package/dist/types/src/format.d.ts +112 -0
- package/dist/types/src/geometry.d.ts +40 -0
- package/dist/types/src/host/contract.d.ts +188 -0
- package/dist/types/src/host/decoders.d.ts +61 -0
- package/dist/types/src/host/index.d.ts +11 -0
- package/dist/types/src/host/package.d.ts +58 -0
- package/dist/types/src/host/policy.d.ts +105 -0
- package/dist/types/src/host/router.d.ts +34 -0
- package/dist/types/src/host/runtime.d.ts +205 -0
- package/dist/types/src/host/sources.d.ts +15 -0
- package/dist/types/src/host/transports.d.ts +109 -0
- package/dist/types/src/index.d.ts +63 -0
- package/dist/types/src/layout.d.ts +20 -0
- package/dist/types/src/limits.d.ts +21 -0
- package/dist/types/src/list.d.ts +133 -0
- package/dist/types/src/locale.d.ts +22 -0
- package/dist/types/src/macros.d.ts +29 -0
- package/dist/types/src/overlay.d.ts +27 -0
- package/dist/types/src/prompt.d.ts +44 -0
- package/dist/types/src/recipes.d.ts +17 -0
- package/dist/types/src/reducer.d.ts +41 -0
- package/dist/types/src/resizable.d.ts +38 -0
- package/dist/types/src/schema.d.ts +7 -0
- package/dist/types/src/strings.d.ts +13 -0
- package/dist/types/src/style.d.ts +201 -0
- package/dist/types/src/test-preload.d.ts +1 -0
- package/dist/types/src/text-shimmer.d.ts +24 -0
- package/dist/types/src/theme-types.d.ts +162 -0
- package/dist/types/src/theme.d.ts +73 -0
- package/dist/types/src/themes.d.ts +22 -0
- package/dist/types/src/tree-guides.d.ts +17 -0
- package/dist/types/src/types.d.ts +314 -0
- package/dist/types/src/validate.d.ts +31 -0
- package/dist/types/src/web/base-css.d.ts +1 -0
- package/dist/types/src/web/box-css.d.ts +55 -0
- package/dist/types/src/web/coerce.d.ts +32 -0
- package/dist/types/src/web/data.d.ts +105 -0
- package/dist/types/src/web/dates.d.ts +12 -0
- package/dist/types/src/web/form.d.ts +44 -0
- package/dist/types/src/web/host-types.d.ts +119 -0
- package/dist/types/src/web/index.d.ts +28 -0
- package/dist/types/src/web/inputs.d.ts +55 -0
- package/dist/types/src/web/list.d.ts +13 -0
- package/dist/types/src/web/listbox.d.ts +14 -0
- package/dist/types/src/web/markdown.d.ts +96 -0
- package/dist/types/src/web/media.d.ts +62 -0
- package/dist/types/src/web/parts.d.ts +4 -0
- package/dist/types/src/web/primitives/alert-dialog.d.ts +10 -0
- package/dist/types/src/web/primitives/alert.d.ts +9 -0
- package/dist/types/src/web/primitives/avatar-color.d.ts +2 -0
- package/dist/types/src/web/primitives/avatar.d.ts +13 -0
- package/dist/types/src/web/primitives/badge.d.ts +10 -0
- package/dist/types/src/web/primitives/breadcrumb.d.ts +10 -0
- package/dist/types/src/web/primitives/button.d.ts +6 -0
- package/dist/types/src/web/primitives/calendar.d.ts +43 -0
- package/dist/types/src/web/primitives/card.d.ts +9 -0
- package/dist/types/src/web/primitives/checkbox.d.ts +5 -0
- package/dist/types/src/web/primitives/choice-tiles.d.ts +32 -0
- package/dist/types/src/web/primitives/cn.d.ts +3 -0
- package/dist/types/src/web/primitives/code-block.d.ts +24 -0
- package/dist/types/src/web/primitives/command.d.ts +134 -0
- package/dist/types/src/web/primitives/context-ring.d.ts +24 -0
- package/dist/types/src/web/primitives/dialog-arms.d.ts +6 -0
- package/dist/types/src/web/primitives/dialog.d.ts +24 -0
- package/dist/types/src/web/primitives/disclosure-header.d.ts +5 -0
- package/dist/types/src/web/primitives/dock.d.ts +42 -0
- package/dist/types/src/web/primitives/dropdown-menu.d.ts +14 -0
- package/dist/types/src/web/primitives/empty-state.d.ts +15 -0
- package/dist/types/src/web/primitives/glass-card.d.ts +4 -0
- package/dist/types/src/web/primitives/hover-card.d.ts +7 -0
- package/dist/types/src/web/primitives/icon-disc.d.ts +12 -0
- package/dist/types/src/web/primitives/index.d.ts +48 -0
- package/dist/types/src/web/primitives/input.d.ts +5 -0
- package/dist/types/src/web/primitives/kbd.d.ts +4 -0
- package/dist/types/src/web/primitives/label.d.ts +3 -0
- package/dist/types/src/web/primitives/menu-surface.d.ts +17 -0
- package/dist/types/src/web/primitives/meter.d.ts +21 -0
- package/dist/types/src/web/primitives/popover.d.ts +3 -0
- package/dist/types/src/web/primitives/progress-ring.d.ts +5 -0
- package/dist/types/src/web/primitives/progress.d.ts +8 -0
- package/dist/types/src/web/primitives/scroll-area.d.ts +49 -0
- package/dist/types/src/web/primitives/segmented-control.d.ts +5 -0
- package/dist/types/src/web/primitives/select.d.ts +47 -0
- package/dist/types/src/web/primitives/separator.d.ts +3 -0
- package/dist/types/src/web/primitives/sheet-chrome.d.ts +4 -0
- package/dist/types/src/web/primitives/sheet.d.ts +20 -0
- package/dist/types/src/web/primitives/skeleton.d.ts +3 -0
- package/dist/types/src/web/primitives/spinner.d.ts +3 -0
- package/dist/types/src/web/primitives/switch.d.ts +4 -0
- package/dist/types/src/web/primitives/table.d.ts +11 -0
- package/dist/types/src/web/primitives/tabs.d.ts +13 -0
- package/dist/types/src/web/primitives/textarea.d.ts +3 -0
- package/dist/types/src/web/primitives/toast.d.ts +163 -0
- package/dist/types/src/web/primitives/tooltip.d.ts +3 -0
- package/dist/types/src/web/primitives/truncate.d.ts +7 -0
- package/dist/types/src/web/primitives/typeahead-portal.d.ts +12 -0
- package/dist/types/src/web/share.d.ts +6 -0
- package/dist/types/src/web/table.d.ts +20 -0
- package/dist/types/src/web/theme-css.d.ts +69 -0
- package/dist/types/src/web/urls.d.ts +21 -0
- package/dist/web/index.js +2303 -0
- package/dist/web/index.js.map +26 -0
- package/dist/web/primitives/index.js +1450 -0
- package/dist/web/primitives/index.js.map +57 -0
- package/docs/components.generated.json +6238 -0
- package/docs/round-1-contract.md +679 -0
- package/docs/round-2-contract.md +476 -0
- package/docs/round-3-contract.md +174 -0
- package/docs/themes.generated.json +3503 -0
- package/fixtures/animations.json +2890 -0
- package/fixtures/bench-list.json +58 -0
- package/fixtures/bind-time.json +30664 -0
- package/fixtures/catalog-basic-map.json +1692 -0
- package/fixtures/catalog-components.json +9323 -0
- package/fixtures/catalog-extension.json +620 -0
- package/fixtures/catalog-macros.json +36370 -0
- package/fixtures/code-tokens.json +1993 -0
- package/fixtures/conformance-baseline.json +55544 -0
- package/fixtures/conformance-cases.json +49 -0
- package/fixtures/conformance-known.json +2123 -0
- package/fixtures/control-geometry.json +4200 -0
- package/fixtures/dashboard.data.json +74 -0
- package/fixtures/dashboard.json +752 -0
- package/fixtures/demo-surface.json +47 -0
- package/fixtures/format.json +870 -0
- package/fixtures/host-policy.json +1067 -0
- package/fixtures/host-router.json +1152 -0
- package/fixtures/host-transport.json +590 -0
- package/fixtures/interactions-round1.json +773 -0
- package/fixtures/kitchen-sink.expanded.json +10844 -0
- package/fixtures/kitchen-sink.json +3049 -0
- package/fixtures/layout-geometry-round1.json +7278 -0
- package/fixtures/layout-geometry.json +2072 -0
- package/fixtures/overlay-geometry.json +272 -0
- package/fixtures/primitive-specimens.json +58 -0
- package/fixtures/prompt-budget.json +33 -0
- package/fixtures/resizable.json +714 -0
- package/fixtures/round4-contract.json +2985 -0
- package/fixtures/specimens.json +9832 -0
- package/fixtures/style-conditions.json +336 -0
- package/fixtures/template-items.json +2215 -0
- package/fixtures/text-direction.json +309 -0
- package/fixtures/text-shimmer.json +96 -0
- package/fixtures/theme-extends.json +573 -0
- package/fixtures/theme-invalid.json +1296 -0
- package/fixtures/theme-recipes.json +58600 -0
- package/fixtures/theme-resolved.json +23949 -0
- package/fixtures/toast-stack.json +215 -0
- package/fixtures/tree-guides.json +224 -0
- package/fixtures/virtual-list.json +733 -0
- package/generated/ExponentialUICatalog.generated.kt +67 -0
- package/generated/ExponentialUICatalog.generated.swift +67 -0
- package/generated/ExponentialUIThemes.generated.kt +23 -0
- package/generated/ExponentialUIThemes.generated.swift +23 -0
- package/generated/catalog.descriptions.generated.rs +6 -0
- package/generated/catalog.generated.rs +80 -0
- package/generated/catalog.themes.generated.rs +34 -0
- package/generated/core.descriptions.json +2505 -0
- package/generated/core.runtime.json +3609 -0
- package/package.json +87 -4
- package/themes/exponential.recipes.json +49 -0
- package/themes/exponential.theme.json +755 -0
- package/themes/neutral.theme.json +5676 -0
- package/themes/orange.theme.json +43 -0
- package/themes/playful.theme.json +219 -0
- package/vendor/a2ui/LICENSE.txt +203 -0
- package/vendor/a2ui/README.md +27 -0
- package/vendor/a2ui/v0_9/basic_catalog.json +1387 -0
- package/vendor/a2ui/v0_9/basic_catalog_rules.txt +5 -0
- package/vendor/a2ui/v0_9/client_capabilities.json +97 -0
- package/vendor/a2ui/v0_9/client_to_server.json +104 -0
- package/vendor/a2ui/v0_9/common_types.json +315 -0
- package/vendor/a2ui/v0_9/server_to_client.json +132 -0
- package/vendor/json-render/LICENSE.txt +201 -0
- package/vendor/json-render/README.md +13 -0
|
@@ -0,0 +1,3940 @@
|
|
|
1
|
+
import {
|
|
2
|
+
basic_map_default,
|
|
3
|
+
coreCatalog2,
|
|
4
|
+
CORE_CATALOG_ID2,
|
|
5
|
+
CORE_LITE_CATALOG_ID2,
|
|
6
|
+
A2UI_BASIC_CATALOG_ID2,
|
|
7
|
+
A2UI_VERSION2,
|
|
8
|
+
UNKNOWN_COMPONENT2,
|
|
9
|
+
TOKEN_GROUPS2,
|
|
10
|
+
parseTokenRef2,
|
|
11
|
+
isKnownToken2,
|
|
12
|
+
sharedCatalogView2
|
|
13
|
+
} from "./index-gwkt14w3.js";
|
|
14
|
+
import {
|
|
15
|
+
validateStyle2,
|
|
16
|
+
tryLoadTheme2,
|
|
17
|
+
BUILTIN_THEMES2,
|
|
18
|
+
BUILTIN_THEME_IDS2,
|
|
19
|
+
builtinTheme2,
|
|
20
|
+
MESSAGE_KINDS2,
|
|
21
|
+
DEFAULT_URL_SCHEMES2,
|
|
22
|
+
DEFAULT_MEDIA_SCHEMES2,
|
|
23
|
+
MEDIA_LIMITS2,
|
|
24
|
+
RENDER_FAILED2,
|
|
25
|
+
MCP_MIME_TYPES2,
|
|
26
|
+
MCP_ACTION_TOOL2,
|
|
27
|
+
SSE_EVENTS2,
|
|
28
|
+
errorMessage2,
|
|
29
|
+
actionMessage2
|
|
30
|
+
} from "./index-we7va6v6.js";
|
|
31
|
+
|
|
32
|
+
// packages/exponential-ui/src/catalog.generated.ts
|
|
33
|
+
var CATALOG_ID2 = "https://ui.exponential.at/catalogs/core/v1";
|
|
34
|
+
var LITE_CATALOG_ID2 = "https://ui.exponential.at/catalogs/core-lite/v1";
|
|
35
|
+
var BASIC_CATALOG_ID2 = "https://a2ui.org/specification/v0_9/basic_catalog.json";
|
|
36
|
+
var BASIC_VERSION2 = "v0.9";
|
|
37
|
+
var CATALOG_VERSION2 = "1";
|
|
38
|
+
var UNKNOWN_COMPONENT_NAME2 = "Unknown";
|
|
39
|
+
var COMPONENT_NAMES2 = ["Box", "Stack", "Grid", "Card", "Separator", "List", "Resizable", "ScrollArea", "Sidebar", "SplitView", "AppBar", "Page", "Toolbar", "Section", "Group", "Text", "Heading", "Markdown", "CodeBlock", "Kbd", "Label", "Image", "Icon", "Video", "AudioPlayer", "Avatar", "Carousel", "Tabs", "Segmented", "Accordion", "Collapsible", "Trace", "TraceItem", "Pagination", "Breadcrumb", "Stepper", "Dialog", "Drawer", "DockCard", "AlertDialog", "Popover", "Tooltip", "Menu", "Toast", "Badge", "Alert", "Chip", "EmptyState", "Progress", "Meter", "Ring", "Spinner", "Skeleton", "Table", "Chart", "Sparkline", "StatTile", "Button", "Link", "Toggle", "Form", "FieldGroup", "FormActions", "Input", "Textarea", "NumberField", "Checkbox", "Radio", "ChoiceTiles", "Switch", "Slider", "Rating", "Select", "SearchList", "ChipInput", "DatePicker", "DateRangePicker", "TimePicker", "FileUpload", "Composer", "Row", "TreeGuides", "Unknown"];
|
|
40
|
+
var NATIVE_COMPONENTS2 = ["Box", "List", "Resizable", "Text", "Markdown", "CodeBlock", "Image", "Icon", "Video", "AudioPlayer", "Avatar", "Carousel", "Tabs", "Segmented", "Accordion", "Dialog", "Drawer", "Popover", "Tooltip", "Menu", "Toast", "Ring", "Spinner", "Skeleton", "Table", "Chart", "Button", "Link", "Toggle", "Form", "Input", "Textarea", "NumberField", "Checkbox", "Radio", "ChoiceTiles", "Switch", "Slider", "Select", "SearchList", "ChipInput", "DatePicker", "DateRangePicker", "TimePicker", "FileUpload", "Composer", "TreeGuides", "Unknown"];
|
|
41
|
+
var MACRO_COMPONENTS2 = ["Stack", "Grid", "Card", "Separator", "ScrollArea", "Sidebar", "SplitView", "AppBar", "Page", "Toolbar", "Section", "Group", "Heading", "Kbd", "Label", "Collapsible", "Trace", "TraceItem", "Pagination", "Breadcrumb", "Stepper", "DockCard", "AlertDialog", "Badge", "Alert", "Chip", "EmptyState", "Progress", "Meter", "Sparkline", "StatTile", "FieldGroup", "FormActions", "Rating", "Row"];
|
|
42
|
+
var LITE_COMPONENTS2 = ["Box", "Stack", "Grid", "Card", "Separator", "List", "Resizable", "ScrollArea", "Sidebar", "SplitView", "AppBar", "Page", "Toolbar", "Section", "Group", "Text", "Heading", "Markdown", "CodeBlock", "Kbd", "Label", "Icon", "Avatar", "Tabs", "Segmented", "Collapsible", "Trace", "TraceItem", "Breadcrumb", "Stepper", "Badge", "Alert", "Chip", "EmptyState", "Progress", "Meter", "Ring", "Skeleton", "StatTile", "Button", "Link", "Form", "FieldGroup", "FormActions", "Input", "Textarea", "NumberField", "Checkbox", "Switch", "Rating", "Select", "SearchList", "ChipInput", "DatePicker", "DateRangePicker", "TimePicker", "FileUpload", "Composer", "Row"];
|
|
43
|
+
var COMPONENT_GROUPS2 = { Box: "layout", Stack: "layout", Grid: "layout", Card: "layout", Separator: "layout", List: "layout", Resizable: "layout", ScrollArea: "layout", Sidebar: "layout", SplitView: "layout", AppBar: "layout", Page: "layout", Toolbar: "layout", Section: "list", Group: "list", Text: "text", Heading: "text", Markdown: "text", CodeBlock: "text", Kbd: "text", Label: "text", Image: "media", Icon: "media", Video: "media", AudioPlayer: "media", Avatar: "media", Carousel: "media", Tabs: "navigation", Segmented: "navigation", Accordion: "navigation", Collapsible: "navigation", Trace: "list", TraceItem: "list", Pagination: "navigation", Breadcrumb: "navigation", Stepper: "navigation", Dialog: "overlay", Drawer: "overlay", DockCard: "overlay", AlertDialog: "overlay", Popover: "overlay", Tooltip: "overlay", Menu: "overlay", Toast: "overlay", Badge: "feedback", Alert: "feedback", Chip: "feedback", EmptyState: "feedback", Progress: "feedback", Meter: "feedback", Ring: "feedback", Spinner: "feedback", Skeleton: "feedback", Table: "data", Chart: "data", Sparkline: "data", StatTile: "data", Button: "action", Link: "action", Toggle: "action", Form: "input", FieldGroup: "input", FormActions: "input", Input: "input", Textarea: "input", NumberField: "input", Checkbox: "input", Radio: "input", ChoiceTiles: "input", Switch: "input", Slider: "input", Rating: "input", Select: "input", SearchList: "input", ChipInput: "input", DatePicker: "input", DateRangePicker: "input", TimePicker: "input", FileUpload: "input", Composer: "input", Row: "list", TreeGuides: "list", Unknown: "feedback" };
|
|
44
|
+
var SPECIMEN_IDS2 = { Box: "exponential-ui-box", Stack: "exponential-ui-stack", Grid: "exponential-ui-grid", Card: "exponential-ui-card", Separator: "exponential-ui-separator", List: "exponential-ui-list", Resizable: "exponential-ui-resizable", ScrollArea: "exponential-ui-scroll-area", Sidebar: "exponential-ui-sidebar", SplitView: "exponential-ui-split-view", AppBar: "exponential-ui-app-bar", Page: "exponential-ui-page", Toolbar: "exponential-ui-toolbar", Section: "exponential-ui-section", Group: "exponential-ui-group", Text: "exponential-ui-text", Heading: "exponential-ui-heading", Markdown: "exponential-ui-markdown", CodeBlock: "exponential-ui-code-block", Kbd: "exponential-ui-kbd", Label: "exponential-ui-label", Image: "exponential-ui-image", Icon: "exponential-ui-icon", Video: "exponential-ui-video", AudioPlayer: "exponential-ui-audio-player", Avatar: "exponential-ui-avatar", Carousel: "exponential-ui-carousel", Tabs: "exponential-ui-tabs", Segmented: "exponential-ui-segmented", Accordion: "exponential-ui-accordion", Collapsible: "exponential-ui-collapsible", Trace: "exponential-ui-trace", TraceItem: "exponential-ui-trace-item", Pagination: "exponential-ui-pagination", Breadcrumb: "exponential-ui-breadcrumb", Stepper: "exponential-ui-stepper", Dialog: "exponential-ui-dialog", Drawer: "exponential-ui-drawer", DockCard: "exponential-ui-dock-card", AlertDialog: "exponential-ui-alert-dialog", Popover: "exponential-ui-popover", Tooltip: "exponential-ui-tooltip", Menu: "exponential-ui-menu", Toast: "exponential-ui-toast", Badge: "exponential-ui-badge", Alert: "exponential-ui-alert", Chip: "exponential-ui-chip", EmptyState: "exponential-ui-empty-state", Progress: "exponential-ui-progress", Meter: "exponential-ui-meter", Ring: "exponential-ui-ring", Spinner: "exponential-ui-spinner", Skeleton: "exponential-ui-skeleton", Table: "exponential-ui-table", Chart: "exponential-ui-chart", Sparkline: "exponential-ui-sparkline", StatTile: "exponential-ui-stat-tile", Button: "exponential-ui-button", Link: "exponential-ui-link", Toggle: "exponential-ui-toggle", Form: "exponential-ui-form", FieldGroup: "exponential-ui-field-group", FormActions: "exponential-ui-form-actions", Input: "exponential-ui-input", Textarea: "exponential-ui-textarea", NumberField: "exponential-ui-number-field", Checkbox: "exponential-ui-checkbox", Radio: "exponential-ui-radio", ChoiceTiles: "exponential-ui-choice-tiles", Switch: "exponential-ui-switch", Slider: "exponential-ui-slider", Rating: "exponential-ui-rating", Select: "exponential-ui-select", SearchList: "exponential-ui-search-list", ChipInput: "exponential-ui-chip-input", DatePicker: "exponential-ui-date-picker", DateRangePicker: "exponential-ui-date-range-picker", TimePicker: "exponential-ui-time-picker", FileUpload: "exponential-ui-file-upload", Composer: "exponential-ui-composer", Row: "exponential-ui-row", TreeGuides: "exponential-ui-tree-guides", Unknown: "exponential-ui-unknown" };
|
|
45
|
+
var ENUMS2 = {
|
|
46
|
+
variant: ["default", "secondary", "outline", "ghost", "destructive", "link"],
|
|
47
|
+
size: ["sm", "default", "lg", "icon"],
|
|
48
|
+
tone: ["neutral", "primary", "success", "warning", "danger", "info"],
|
|
49
|
+
gap: ["none", "xs", "sm", "md", "lg", "xl"],
|
|
50
|
+
align: ["start", "center", "end", "stretch"],
|
|
51
|
+
justify: ["start", "center", "end", "between", "around", "evenly"],
|
|
52
|
+
textVariant: ["body", "caption", "muted", "lead", "code", "label", "title"],
|
|
53
|
+
headingLevel: ["h1", "h2", "h3", "h4"],
|
|
54
|
+
imageFit: ["contain", "cover", "fill", "none", "scaleDown"],
|
|
55
|
+
orientation: ["horizontal", "vertical"],
|
|
56
|
+
side: ["top", "right", "bottom", "left"],
|
|
57
|
+
inputType: ["text", "email", "password", "number", "search", "url", "tel"],
|
|
58
|
+
validateOn: ["change", "blur", "submit"],
|
|
59
|
+
alertType: ["info", "success", "warning", "error"],
|
|
60
|
+
controlSize: ["sm", "default", "lg"],
|
|
61
|
+
spinnerSize: ["xs", "sm", "default", "lg"],
|
|
62
|
+
tabClosable: ["none", "hover", "always"],
|
|
63
|
+
groupType: ["single", "multiple"],
|
|
64
|
+
rowChevron: ["none", "right", "selector"],
|
|
65
|
+
rowSurface: ["flat", "card"],
|
|
66
|
+
chipShape: ["pill", "rect"],
|
|
67
|
+
density: ["default", "compact"],
|
|
68
|
+
listDirection: ["vertical", "horizontal"],
|
|
69
|
+
chartKind: ["bar", "stackedBar", "line", "area", "pie", "donut", "sparkline"],
|
|
70
|
+
segmentedVariant: ["segmented", "toggles", "outline", "bar"],
|
|
71
|
+
liveTone: ["live", "attention", "done", "unread", "idle", "muted"],
|
|
72
|
+
menuItemKind: ["item", "checkbox", "separator", "label", "submenu"],
|
|
73
|
+
openOn: ["press", "hover"],
|
|
74
|
+
menuOpenOn: ["press", "contextmenu"],
|
|
75
|
+
live: ["off", "polite", "assertive"],
|
|
76
|
+
selectable: ["none", "single", "multiple"],
|
|
77
|
+
cellType: ["text", "number", "date", "boolean", "badge", "slot", "currency", "percent", "relativeTime"],
|
|
78
|
+
sortDirection: ["asc", "desc"],
|
|
79
|
+
imageLoading: ["lazy", "eager"],
|
|
80
|
+
scrollDirection: ["vertical", "horizontal", "both"],
|
|
81
|
+
collapseBelow: ["never", "sm", "md", "lg", "xl"],
|
|
82
|
+
codeLanguage: ["plain", "json", "js", "ts", "tsx", "rust", "swift", "kotlin", "python", "bash", "html", "css", "sql", "yaml", "markdown", "ansi"],
|
|
83
|
+
codeToken: ["plain", "keyword", "string", "number", "comment", "punctuation", "operator", "type", "function", "property", "tag", "attribute", "success", "warning", "error"],
|
|
84
|
+
codeBlockVariant: ["default", "destructive"],
|
|
85
|
+
codeBlockSize: ["default", "sm"],
|
|
86
|
+
traceStatus: ["running", "error", "pending"],
|
|
87
|
+
traceSize: ["default", "sm"]
|
|
88
|
+
};
|
|
89
|
+
var TOKEN_NAMES2 = {
|
|
90
|
+
color: ["background", "foreground", "card", "cardForeground", "popover", "popoverForeground", "primary", "primaryForeground", "secondary", "secondaryForeground", "muted", "mutedForeground", "accent", "accentForeground", "destructive", "destructiveForeground", "success", "successForeground", "warning", "warningForeground", "info", "infoForeground", "border", "input", "ring", "chart1", "chart2", "chart3", "chart4", "chart5", "chart6", "chart7", "chart8"],
|
|
91
|
+
spacing: ["none", "xxs", "xs", "sm", "md", "lg", "xl", "xl2", "xl3"],
|
|
92
|
+
radius: ["none", "sm", "md", "lg", "xl", "xl2", "xl3", "full"],
|
|
93
|
+
"type.size": ["xs", "sm", "base", "lg", "xl", "xl2", "xl3"],
|
|
94
|
+
"type.lineHeight": ["xs", "sm", "base", "lg", "xl", "xl2", "xl3"],
|
|
95
|
+
"type.weight": ["regular", "medium", "semibold", "bold"],
|
|
96
|
+
"type.family": ["sans", "mono"],
|
|
97
|
+
control: ["buttonSm", "buttonMd", "buttonLg", "buttonIcon", "input", "textarea", "row", "rowCompact", "pill", "badge", "chip", "toggle", "switch", "checkbox", "slider", "progress", "meter", "avatarSm", "avatarMd", "avatarLg", "iconSm", "iconMd", "iconLg", "hairline", "appBar", "tabBar", "toast"],
|
|
98
|
+
shadow: ["none", "sm", "md", "lg", "xl"],
|
|
99
|
+
opacity: ["primary", "secondary", "tertiary", "quaternary", "disabled"],
|
|
100
|
+
border: ["none", "hairline", "thick"],
|
|
101
|
+
motion: ["fast", "standard", "slow"],
|
|
102
|
+
breakpoint: ["sm", "md", "lg", "xl"],
|
|
103
|
+
ease: ["standard", "decelerate", "accelerate"],
|
|
104
|
+
density: ["compact", "comfortable"],
|
|
105
|
+
blur: ["sm", "md", "lg", "xl"],
|
|
106
|
+
scale: ["press", "popoverFrom"]
|
|
107
|
+
};
|
|
108
|
+
var STYLE_KEY_NAMES2 = ["display", "flexDirection", "flexWrap", "justifyContent", "alignItems", "alignContent", "alignSelf", "justifySelf", "flexGrow", "flexShrink", "flexBasis", "gap", "rowGap", "columnGap", "direction", "overflow", "overflowX", "overflowY", "width", "height", "minWidth", "minHeight", "maxWidth", "maxHeight", "aspectRatio", "position", "top", "right", "bottom", "left", "inset", "insetInlineStart", "insetInlineEnd", "insetBlockStart", "insetBlockEnd", "padding", "paddingTop", "paddingRight", "paddingBottom", "paddingLeft", "paddingHorizontal", "paddingVertical", "paddingInlineStart", "paddingInlineEnd", "margin", "marginTop", "marginRight", "marginBottom", "marginLeft", "marginHorizontal", "marginVertical", "marginInlineStart", "marginInlineEnd", "gridTemplateColumns", "gridTemplateRows", "gridTemplateAreas", "gridArea", "gridColumn", "gridRow", "backgroundColor", "backgroundGradient", "color", "borderWidth", "borderTopWidth", "borderRightWidth", "borderBottomWidth", "borderLeftWidth", "borderColor", "borderStyle", "borderRadius", "borderTopLeftRadius", "borderTopRightRadius", "borderBottomRightRadius", "borderBottomLeftRadius", "opacity", "boxShadow", "fontSize", "fontWeight", "lineHeight", "letterSpacing", "textAlign", "textDecoration", "textTransform", "fontStyle", "fontFamily", "transition", "transitionEasing", "transform", "visibility", "pointerEvents", "userSelect", "cursor", "backdropBlur", "animation", "animationDuration"];
|
|
109
|
+
var STYLE_STATE_NAMES2 = [":hover", ":focus-visible", ":pressed"];
|
|
110
|
+
var ICON_NAMES2 = ["a-large-small", "action-chat", "action-create", "action-default", "action-repository", "action-run", "action-suggestion", "activity", "anchor", "app-editor-chat", "archive", "arrow-down", "arrow-down-left", "arrow-left", "arrow-left-right", "arrow-right", "arrow-up-right", "at-sign", "atom", "auth-passkey", "award", "ban", "bell", "bell-off", "bold", "book-open", "bookmark", "bot", "boxes", "braces", "brain", "briefcase", "brush-cleaning", "bug", "building", "building-2", "calculator", "calendar", "calendar-days", "camera", "car", "chart-line", "check", "chevron-down", "chevron-left", "chevron-right", "chevron-up", "chevrons-up-down", "circle", "circle-arrow-up", "circle-check", "circle-dashed", "circle-dot", "circle-minus", "circle-question-mark", "circle-slash", "circle-stop", "circle-user", "circle-x", "clipboard-list", "clock", "cloud", "code", "coding-assistant", "coding-command", "coding-compact", "coding-diff", "coding-ended", "coding-in-review", "coding-needs-input", "coding-plan", "coding-running", "coding-stop", "coding-subagent", "coding-tool", "coffee", "compass", "computer", "copy", "corner-down-right", "cpu", "credit-card", "crown", "database", "download", "droplet", "dumbbell", "editor-bold", "editor-clear-formatting", "editor-code", "editor-emoji", "editor-heading-1", "editor-heading-2", "editor-heading-3", "editor-image", "editor-issue-ref", "editor-italic", "editor-link", "editor-list", "editor-list-ordered", "editor-list-todo", "editor-mention", "editor-quote", "editor-strikethrough", "editor-text", "editor-text-format", "editor-unlink", "ellipsis", "ellipsis-vertical", "event-assignee-changed", "event-board-moved", "event-estimate-changed", "event-label-added", "event-label-removed", "event-priority-changed", "event-relation-added", "event-relation-removed", "event-status-changed", "event-title-changed", "external-link", "eye", "eye-off", "fast-forward", "file", "file-diff", "file-pen-line", "file-text", "fingerprint", "flag", "flame", "flask-conical", "fold-vertical", "folder", "folder-kanban", "folder-open", "gamepad-2", "gauge", "gem", "gift", "git-branch", "git-merge", "git-pull-request", "github", "globe", "graduation-cap", "guide-changes", "hammer", "hard-drive", "hash", "heading-1", "heading-2", "heading-3", "headphones", "heart", "heart-off", "history", "hourglass", "house", "image", "images", "inbox", "info", "italic", "key", "landmark", "laptop", "layers", "layers-2", "layout-grid", "leaf", "lightbulb", "link", "link-2", "list", "list-checks", "list-end", "list-ordered", "list-todo", "list-tree", "loader-circle", "lock", "lock-open", "log-in", "log-out", "mail", "map", "map-pin", "maximize-2", "media-fast-forward", "media-rewind", "media-skip-next", "media-skip-previous", "media-volume-down", "media-volume-mute", "media-volume-off", "media-volume-up", "megaphone", "menu", "message-circle", "message-square", "message-square-plus", "message-square-reply", "mic", "microscope", "minimize-2", "minus", "monitor", "monitor-off", "moon", "mountain", "move", "music", "nav-account", "nav-actions", "nav-admin", "nav-apps", "nav-boards", "nav-changelog", "nav-computer", "nav-create-issue", "nav-devices", "nav-drafts", "nav-files", "nav-getting-started", "nav-inbox", "nav-issues", "nav-my-issues", "nav-notifications", "nav-rail-collapse", "nav-rail-expand", "nav-report-bug", "nav-search", "nav-settings", "nav-sign-out", "nav-source-control", "nav-team-switcher", "nav-terminal", "nav-threads", "newspaper", "notification-agent-message", "notification-issue-assigned", "notification-issue-comment", "notification-issue-created", "notification-issue-mention", "notification-issue-status-changed", "notification-mark-read", "notification-mute", "notification-pr-merged", "notification-pr-opened", "notification-reporter-reply", "notification-session-blocked", "os-apple", "os-linux", "os-windows", "package", "paintbrush", "palette", "panel-left-close", "panel-left-open", "paperclip", "pause", "pen-tool", "pencil", "phone", "pin", "pin-off", "plane", "play", "plug", "plus", "pr-batch", "pr-closed", "pr-draft", "pr-merged", "pr-open", "pr-stack", "printer", "priority-high", "priority-low", "priority-medium", "priority-none", "priority-urgent", "progress-1-4", "progress-1-5", "progress-2-4", "progress-2-5", "progress-3-4", "progress-3-5", "progress-4-5", "puzzle", "quote", "refresh-cw", "relation-blocked-by", "relation-blocks", "relation-duplicate", "relation-parent", "relation-related", "relation-section", "relation-sub-issue", "remove-formatting", "repeat", "rewind", "rocket", "rotate-ccw", "run-pause", "run-resume", "sc-push", "scale", "search", "search-x", "send", "server", "session-shell", "session-tree", "settings", "settings-about", "settings-account", "settings-agents", "settings-api", "settings-billing", "settings-boards", "settings-general", "settings-import", "settings-issues", "settings-labels", "settings-licenses", "settings-local-repos", "settings-mcp", "settings-members", "settings-notifications", "settings-rate", "settings-repositories", "settings-servers", "settings-sessions", "settings-statuses", "settings-storage", "settings-sync", "settings-tools", "settings-widget", "share-2", "shield", "shield-check", "shield-question-mark", "shopping-bag", "shopping-cart", "signal-high", "signal-low", "signal-medium", "skip-back", "skip-forward", "sliders-horizontal", "smartphone", "smile", "sparkles", "square-kanban", "square-pen", "square-slash", "square-terminal", "star", "star-half", "star-off", "status-backlog", "status-cancelled", "status-done", "status-duplicate", "status-in-progress", "status-in-review", "status-todo", "stethoscope", "store", "strikethrough", "sun", "support-open", "support-resolved", "tag", "target", "terminal", "tool-script", "trace-background", "trace-chevron", "trace-completed", "trace-edit", "trace-failed", "trace-fetch", "trace-read", "trace-reasoning", "trace-search", "trace-subagent", "trace-task-done", "trace-task-pending", "trace-task-running", "trace-terminal", "trace-todo", "trace-tool", "trash-2", "tree-pine", "triangle-alert", "trigger-event", "trigger-schedule", "trophy", "truck", "type", "ui-add", "ui-agent-source", "ui-archive", "ui-arrow-down", "ui-arrow-right", "ui-assignee", "ui-attach", "ui-avatar-placeholder", "ui-back", "ui-branch", "ui-check", "ui-checklist", "ui-chevron-down", "ui-chevron-left", "ui-chevron-right", "ui-chevron-up", "ui-clean", "ui-clear", "ui-clock", "ui-close", "ui-cloud", "ui-copy", "ui-delete", "ui-delete-account", "ui-device", "ui-device-default", "ui-device-offline", "ui-dock-side", "ui-docs", "ui-download", "ui-due-date", "ui-edit", "ui-empty-search", "ui-error", "ui-estimate", "ui-external-link", "ui-favorite-off", "ui-file", "ui-float", "ui-folder", "ui-folder-open", "ui-fullscreen", "ui-fullscreen-exit", "ui-github", "ui-help", "ui-hide", "ui-history", "ui-icon-placeholder", "ui-indeterminate", "ui-info", "ui-invite", "ui-issue", "ui-link", "ui-loading", "ui-mail", "ui-mcp", "ui-member", "ui-menu", "ui-minus", "ui-more", "ui-more-vertical", "ui-offline", "ui-organization", "ui-owner", "ui-permission", "ui-pin", "ui-print", "ui-private", "ui-properties", "ui-queued", "ui-redock", "ui-refresh", "ui-remove-member", "ui-repeat", "ui-repository", "ui-selected", "ui-selector", "ui-send", "ui-server", "ui-share", "ui-sign-in", "ui-sign-out", "ui-staging", "ui-star-half", "ui-star-off", "ui-stop", "ui-submit", "ui-subscribe", "ui-success", "ui-swap", "ui-team", "ui-unassigned", "ui-undo", "ui-undock", "ui-unlock", "ui-unpin", "ui-unselected", "ui-unsubscribe", "ui-update", "ui-usage", "ui-warning", "ui-watch", "ui-widget", "undo-2", "unlink", "upload", "user", "user-minus", "user-plus", "user-x", "users", "video", "volume-1", "volume-2", "volume-off", "volume-x", "wallet", "wifi-off", "work-faces", "work-results", "workflow", "wrench", "x", "zap"];
|
|
111
|
+
var FUNCTION_NAMES2 = ["required", "regex", "length", "numeric", "email", "formatString", "formatNumber", "formatCurrency", "formatDate", "pluralize", "openUrl", "and", "or", "not", "percent", "add", "sub", "eq", "lt", "clamp", "cond", "fallback", "concat", "coalesce", "text", "map", "len", "fill", "set", "formatPercent", "formatRelativeTime", "filter"];
|
|
112
|
+
var BASIC_COMPONENT_MAP2 = { Text: "Text", Image: "Image", Icon: "Icon", Video: "Video", AudioPlayer: "AudioPlayer", Row: "Stack", Column: "Stack", List: "List", Card: "Card", Tabs: "Tabs", Modal: "Dialog", Divider: "Separator", Button: "Button", TextField: "Input", CheckBox: "Checkbox", ChoicePicker: "Radio", Slider: "Slider", DateTimeInput: "DatePicker" };
|
|
113
|
+
var BASIC_ICON_MAP2 = { accountCircle: "ui-assignee", add: "ui-add", arrowBack: "ui-back", arrowForward: "ui-arrow-right", attachFile: "ui-attach", calendarToday: "calendar", call: "phone", camera: "camera", check: "ui-check", close: "ui-close", delete: "ui-delete", download: "ui-download", edit: "ui-edit", event: "ui-due-date", error: "ui-error", fastForward: "media-fast-forward", favorite: "heart", favoriteOff: "ui-favorite-off", folder: "ui-folder", help: "ui-help", home: "house", info: "ui-info", locationOn: "map-pin", lock: "ui-private", lockOpen: "ui-unlock", mail: "ui-mail", menu: "ui-menu", moreVert: "ui-more-vertical", moreHoriz: "ui-more", notificationsOff: "ui-unsubscribe", notifications: "ui-subscribe", pause: "run-pause", payment: "credit-card", person: "ui-avatar-placeholder", phone: "smartphone", photo: "image", play: "action-run", print: "ui-print", refresh: "ui-refresh", rewind: "media-rewind", search: "nav-search", send: "ui-send", settings: "nav-settings", share: "ui-share", shoppingCart: "shopping-cart", skipNext: "media-skip-next", skipPrevious: "media-skip-previous", star: "star", starHalf: "ui-star-half", starOff: "ui-star-off", stop: "ui-stop", upload: "sc-push", visibility: "ui-watch", visibilityOff: "ui-hide", volumeDown: "media-volume-down", volumeMute: "media-volume-mute", volumeOff: "media-volume-off", volumeUp: "media-volume-up", warning: "ui-warning" };
|
|
114
|
+
var BASIC_PLACEHOLDER_ICON2 = "ui-icon-placeholder";
|
|
115
|
+
// packages/exponential-ui/catalog/strings.json
|
|
116
|
+
var strings_default = {
|
|
117
|
+
$comment: "Round 1 (docs/round-1-contract.md §4): the built-in UI STRINGS every renderer shows — the copy no author writes (a Select's search placeholder, the calendar's month buttons, the copy button, the Pagination arrows' labels). Keys are the ids, values the English defaults. A renderer ships this table (generated into TS/Swift/Kotlin/Rust as STRING_IDS + STRING_DEFAULTS) and lets the HOST override any id per surface (`strings: {search: \"Suchen…\"}`); the catalog refers to an entry as `$string.<id>` in a prop default or a macro template (`$string.previous`), which the renderer resolves at bind time like a token. `{name}` placeholders are filled by the renderer (src/strings.ts formatString; a macro template uses `$fill` → the core `fill` function): a sentence is ONE id with placeholders, never concatenated fragments. Round 2 adds the names the renderers still hard-coded (`invalidValue` = a failed check without a message, `message` = the Composer field, `codeBlock` = an untitled CodeBlock, `dialog` = an untitled Dialog/Drawer, `table` = an uncaptioned Table, `carousel`/`slide` = the carousel's role descriptions, `resize` = a Resizable handle). EXP-1259 adds `closeTab` and `newTab` (the Tabs close glyph and + button). Append-only (round 1 dropped the unused fragment `of`).",
|
|
118
|
+
strings: {
|
|
119
|
+
back: "Back",
|
|
120
|
+
breadcrumb: "Breadcrumb",
|
|
121
|
+
browse: "Browse",
|
|
122
|
+
cancel: "Cancel",
|
|
123
|
+
carousel: "Carousel",
|
|
124
|
+
chartSummary: "Chart of {series}, values from {min} to {max}",
|
|
125
|
+
choose: "Choose",
|
|
126
|
+
clear: "Clear",
|
|
127
|
+
close: "Close",
|
|
128
|
+
closeTab: "Close {name}",
|
|
129
|
+
codeBlock: "Code",
|
|
130
|
+
collapse: "Collapse",
|
|
131
|
+
confirm: "Confirm",
|
|
132
|
+
copied: "Copied",
|
|
133
|
+
copy: "Copy",
|
|
134
|
+
decrement: "Decrease",
|
|
135
|
+
dialog: "Dialog",
|
|
136
|
+
dismiss: "Dismiss",
|
|
137
|
+
dropFiles: "Drop files here",
|
|
138
|
+
expand: "Expand",
|
|
139
|
+
fileTooLarge: "File too large",
|
|
140
|
+
fileTooLargeNamed: "{name}: File too large",
|
|
141
|
+
increment: "Increase",
|
|
142
|
+
invalidFields: "Check the highlighted fields",
|
|
143
|
+
invalidValue: "Invalid value",
|
|
144
|
+
loading: "Loading",
|
|
145
|
+
menu: "Menu",
|
|
146
|
+
message: "Message",
|
|
147
|
+
more: "More",
|
|
148
|
+
newTab: "New tab",
|
|
149
|
+
next: "Next",
|
|
150
|
+
nextMonth: "Next month",
|
|
151
|
+
noResults: "No results",
|
|
152
|
+
optional: "Optional",
|
|
153
|
+
pageOf: "Page {page} of {total}",
|
|
154
|
+
pagination: "Pagination",
|
|
155
|
+
previous: "Previous",
|
|
156
|
+
previousMonth: "Previous month",
|
|
157
|
+
ratingStar: "{value} of {max}",
|
|
158
|
+
ratingValue: "Rated {value} of {max}",
|
|
159
|
+
remove: "Remove",
|
|
160
|
+
removeItem: "Remove {name}",
|
|
161
|
+
required: "Required",
|
|
162
|
+
resize: "Resize",
|
|
163
|
+
search: "Search…",
|
|
164
|
+
selectAll: "Select all",
|
|
165
|
+
selectedCount: "{count} selected",
|
|
166
|
+
selectRow: "Select row",
|
|
167
|
+
send: "Send",
|
|
168
|
+
showLess: "Show less",
|
|
169
|
+
showMore: "Show more",
|
|
170
|
+
slide: "Slide",
|
|
171
|
+
sortAscending: "Sort ascending",
|
|
172
|
+
sortByAscending: "{name}: Sort ascending",
|
|
173
|
+
sortByDescending: "{name}: Sort descending",
|
|
174
|
+
sortDescending: "Sort descending",
|
|
175
|
+
sparklineSummary: "Trend from {first} to {last}, low {min}, high {max}",
|
|
176
|
+
stepCurrent: "Step {step} of {total}: {label}, current",
|
|
177
|
+
stepDone: "Step {step} of {total}: {label}, completed",
|
|
178
|
+
stepUpcoming: "Step {step} of {total}: {label}",
|
|
179
|
+
stop: "Stop",
|
|
180
|
+
submit: "Submit",
|
|
181
|
+
table: "Table",
|
|
182
|
+
today: "Today",
|
|
183
|
+
unknownComponent: "Unknown component",
|
|
184
|
+
unsupportedFile: "Unsupported file",
|
|
185
|
+
unsupportedFileNamed: "{name}: Unsupported file"
|
|
186
|
+
}
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
// packages/exponential-ui/src/strings.ts
|
|
190
|
+
var DEFAULT_STRINGS2 = strings_default.strings;
|
|
191
|
+
var STRING_IDS2 = Object.keys(DEFAULT_STRINGS2);
|
|
192
|
+
var REF = /^\$string\.([a-zA-Z][a-zA-Z0-9]*)$/;
|
|
193
|
+
var PLACEHOLDER = /\{([a-zA-Z][a-zA-Z0-9]*)\}/g;
|
|
194
|
+
function parseStringRef2(value) {
|
|
195
|
+
if (typeof value !== `string`)
|
|
196
|
+
return null;
|
|
197
|
+
const m = REF.exec(value);
|
|
198
|
+
return m ? m[1] : null;
|
|
199
|
+
}
|
|
200
|
+
function isStringRef2(value) {
|
|
201
|
+
const id = parseStringRef2(value);
|
|
202
|
+
return id !== null && id in DEFAULT_STRINGS2;
|
|
203
|
+
}
|
|
204
|
+
function stringTable2(overrides = {}) {
|
|
205
|
+
return { ...DEFAULT_STRINGS2, ...overrides };
|
|
206
|
+
}
|
|
207
|
+
function formatString2(template, params = {}) {
|
|
208
|
+
return template.replace(PLACEHOLDER, (whole, name) => (name in params) && params[name] !== undefined && params[name] !== null ? String(params[name]) : whole);
|
|
209
|
+
}
|
|
210
|
+
function resolveString2(value, table = DEFAULT_STRINGS2) {
|
|
211
|
+
const id = parseStringRef2(value);
|
|
212
|
+
if (id === null)
|
|
213
|
+
return value;
|
|
214
|
+
return table[id] ?? id;
|
|
215
|
+
}
|
|
216
|
+
// packages/exponential-ui/catalog/locale.json
|
|
217
|
+
var locale_default = {
|
|
218
|
+
$comment: "Round 1 (docs/round-1-contract.md §4): the LOCALE contract. A surface carries one BCP 47 `locale` (SurfaceSettings.locale, default `en-US`); it drives the basic catalog's formatNumber/formatCurrency/formatDate/pluralize, NumberField's display, the calendar's month and weekday names and the default week start, and the text direction. Platforms format with their own ICU (Intl, Foundation, java.text, icu4x); what must not differ is decided HERE so every renderer agrees: `weekStart` = CLDR supplemental weekData `firstDay` by REGION (0 = Sunday … 6 = Saturday; a region not listed = `default`); a locale without a region takes `likelyRegion[language]` (CLDR likelySubtags: every rtl language and the most spoken ~90; else `default`); `languageAliases` = deprecated codes normalised FIRST (Java/Android still emit `iw`, `ji`, `in`); `rtl` = the languages whose text direction is right-to-left (the surface root gets `direction: rtl` unless the author set one); `rtlMirroredIcons` = the DIRECTIONAL glyphs (icons.json names, semantic and Lucide) a painter MIRRORS under rtl: scaleX(-1) as the OUTERMOST transform of the glyph, after the node's own `transform` (CSS `transform: scaleX(-1) <own>`), so a back arrow, a prev/next or breadcrumb chevron and a submenu indicator point the reading direction; media transport glyphs and everything else are never mirrored. Round 2: formatting goes through a host-supplied Formatter (SurfaceSettings.locale + timeZone; TS = Intl, Rust = a Formatter trait with the `englishFallback` below, FFI = a foreign Formatter). src/locale.ts + src/format.ts are the reference; generated into every target as constants. Append-only.",
|
|
219
|
+
default: "en-US",
|
|
220
|
+
weekStart: {
|
|
221
|
+
default: 1,
|
|
222
|
+
regions: {
|
|
223
|
+
"0": ["AG", "AS", "BD", "BR", "BS", "BT", "BW", "BZ", "CA", "CN", "CO", "DM", "DO", "ET", "GT", "GU", "HK", "HN", "ID", "IL", "IN", "JM", "JP", "KE", "KH", "KR", "LA", "MH", "MM", "MO", "MT", "MX", "MZ", "NI", "NP", "PA", "PE", "PH", "PK", "PR", "PT", "PY", "SA", "SG", "SV", "TH", "TT", "TW", "UM", "US", "VE", "VI", "WS", "YE", "ZA", "ZW"],
|
|
224
|
+
"5": ["MV"],
|
|
225
|
+
"6": ["AE", "AF", "BH", "DJ", "DZ", "EG", "IQ", "IR", "JO", "KW", "LY", "OM", "QA", "SD", "SY"]
|
|
226
|
+
}
|
|
227
|
+
},
|
|
228
|
+
likelyRegion: {
|
|
229
|
+
af: "ZA",
|
|
230
|
+
am: "ET",
|
|
231
|
+
ar: "EG",
|
|
232
|
+
az: "AZ",
|
|
233
|
+
be: "BY",
|
|
234
|
+
bg: "BG",
|
|
235
|
+
bn: "BD",
|
|
236
|
+
bs: "BA",
|
|
237
|
+
ca: "ES",
|
|
238
|
+
ckb: "IQ",
|
|
239
|
+
cs: "CZ",
|
|
240
|
+
cy: "GB",
|
|
241
|
+
da: "DK",
|
|
242
|
+
de: "DE",
|
|
243
|
+
dv: "MV",
|
|
244
|
+
el: "GR",
|
|
245
|
+
en: "US",
|
|
246
|
+
es: "ES",
|
|
247
|
+
et: "EE",
|
|
248
|
+
eu: "ES",
|
|
249
|
+
fa: "IR",
|
|
250
|
+
fi: "FI",
|
|
251
|
+
fil: "PH",
|
|
252
|
+
fr: "FR",
|
|
253
|
+
ga: "IE",
|
|
254
|
+
gl: "ES",
|
|
255
|
+
gu: "IN",
|
|
256
|
+
ha: "NG",
|
|
257
|
+
he: "IL",
|
|
258
|
+
hi: "IN",
|
|
259
|
+
hr: "HR",
|
|
260
|
+
hu: "HU",
|
|
261
|
+
hy: "AM",
|
|
262
|
+
id: "ID",
|
|
263
|
+
ig: "NG",
|
|
264
|
+
is: "IS",
|
|
265
|
+
it: "IT",
|
|
266
|
+
ja: "JP",
|
|
267
|
+
jv: "ID",
|
|
268
|
+
ka: "GE",
|
|
269
|
+
kk: "KZ",
|
|
270
|
+
km: "KH",
|
|
271
|
+
kn: "IN",
|
|
272
|
+
ko: "KR",
|
|
273
|
+
ku: "TR",
|
|
274
|
+
ky: "KG",
|
|
275
|
+
lo: "LA",
|
|
276
|
+
lt: "LT",
|
|
277
|
+
lv: "LV",
|
|
278
|
+
mk: "MK",
|
|
279
|
+
ml: "IN",
|
|
280
|
+
mn: "MN",
|
|
281
|
+
mr: "IN",
|
|
282
|
+
ms: "MY",
|
|
283
|
+
mt: "MT",
|
|
284
|
+
my: "MM",
|
|
285
|
+
nb: "NO",
|
|
286
|
+
ne: "NP",
|
|
287
|
+
nl: "NL",
|
|
288
|
+
nn: "NO",
|
|
289
|
+
no: "NO",
|
|
290
|
+
or: "IN",
|
|
291
|
+
pa: "IN",
|
|
292
|
+
pl: "PL",
|
|
293
|
+
ps: "AF",
|
|
294
|
+
pt: "BR",
|
|
295
|
+
ro: "RO",
|
|
296
|
+
ru: "RU",
|
|
297
|
+
sd: "PK",
|
|
298
|
+
si: "LK",
|
|
299
|
+
sk: "SK",
|
|
300
|
+
sl: "SI",
|
|
301
|
+
so: "SO",
|
|
302
|
+
sq: "AL",
|
|
303
|
+
sr: "RS",
|
|
304
|
+
sv: "SE",
|
|
305
|
+
sw: "TZ",
|
|
306
|
+
ta: "IN",
|
|
307
|
+
te: "IN",
|
|
308
|
+
th: "TH",
|
|
309
|
+
tl: "PH",
|
|
310
|
+
tr: "TR",
|
|
311
|
+
ug: "CN",
|
|
312
|
+
uk: "UA",
|
|
313
|
+
ur: "PK",
|
|
314
|
+
uz: "UZ",
|
|
315
|
+
vi: "VN",
|
|
316
|
+
yi: "001",
|
|
317
|
+
yo: "NG",
|
|
318
|
+
zh: "CN",
|
|
319
|
+
zu: "ZA"
|
|
320
|
+
},
|
|
321
|
+
languageAliases: { in: "id", iw: "he", ji: "yi", jw: "jv", mo: "ro", tl: "fil" },
|
|
322
|
+
rtl: ["ar", "ckb", "dv", "fa", "he", "ps", "sd", "ug", "ur", "yi"],
|
|
323
|
+
rtlMirroredIcons: ["ui-back", "ui-chevron-left", "ui-chevron-right", "ui-arrow-right", "ui-send", "ui-undo", "ui-external-link", "arrow-left", "arrow-right", "chevron-left", "chevron-right", "send", "undo-2", "external-link"],
|
|
324
|
+
englishFallback: {
|
|
325
|
+
$comment: "Round 2 (docs/round-2-contract.md §3): the data of the ENGLISH fallback Formatter (src/format.ts englishFormatter; the Rust core's fallback reads the same): what a renderer without a platform ICU prints, equal to Intl en-US (ICU 74+) for every case of fixtures/format.json. `currencyPrefix` = the en-US prefix per ISO 4217 code (a code not listed prints `unknownCurrency`: `<CODE>` + U+00A0); `currencyDigits` = the minor digits where they are not 2; `relative` = the numeric:auto phrases of a unit at -1/0/+1 and the unit names (singular, plural); `datePatterns` = the TR35 pattern per `style`, `timePattern` = what `time: true` adds, joined by `dateTimeJoin[style]`. Instants show in the surface zone: the fallback takes the zone as a UTC offset per instant from the host (fixtures: `offsetMinutes`).",
|
|
326
|
+
months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
|
|
327
|
+
monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
|
|
328
|
+
weekdays: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"],
|
|
329
|
+
weekdaysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
|
|
330
|
+
dayPeriods: ["AM", "PM"],
|
|
331
|
+
currencyPrefix: {
|
|
332
|
+
USD: "$",
|
|
333
|
+
EUR: "€",
|
|
334
|
+
GBP: "£",
|
|
335
|
+
JPY: "¥",
|
|
336
|
+
CNY: "CN¥",
|
|
337
|
+
INR: "₹",
|
|
338
|
+
KRW: "₩",
|
|
339
|
+
CAD: "CA$",
|
|
340
|
+
AUD: "A$",
|
|
341
|
+
MXN: "MX$",
|
|
342
|
+
BRL: "R$",
|
|
343
|
+
ILS: "₪",
|
|
344
|
+
NZD: "NZ$",
|
|
345
|
+
HKD: "HK$",
|
|
346
|
+
TWD: "NT$",
|
|
347
|
+
VND: "₫",
|
|
348
|
+
PHP: "₱",
|
|
349
|
+
XAF: "FCFA ",
|
|
350
|
+
XOF: "F CFA "
|
|
351
|
+
},
|
|
352
|
+
currencyDigits: { JPY: 0, KRW: 0, VND: 0, CLP: 0, ISK: 0, UGX: 0, PYG: 0, XAF: 0, XOF: 0, BHD: 3, IQD: 3, JOD: 3, KWD: 3, OMR: 3, TND: 3 },
|
|
353
|
+
relative: {
|
|
354
|
+
units: { second: ["second", "seconds"], minute: ["minute", "minutes"], hour: ["hour", "hours"], day: ["day", "days"], week: ["week", "weeks"], month: ["month", "months"], year: ["year", "years"] },
|
|
355
|
+
auto: { second: { "0": "now" }, day: { "-1": "yesterday", "1": "tomorrow" }, week: { "-1": "last week", "1": "next week" }, month: { "-1": "last month", "1": "next month" }, year: { "-1": "last year", "1": "next year" } },
|
|
356
|
+
past: "{value} {unit} ago",
|
|
357
|
+
future: "in {value} {unit}"
|
|
358
|
+
},
|
|
359
|
+
unknownCurrency: "{code} ",
|
|
360
|
+
datePatterns: { short: "M/d/yy", medium: "MMM d, y", long: "MMMM d, y", full: "EEEE, MMMM d, y" },
|
|
361
|
+
timePattern: "h:mm a",
|
|
362
|
+
dateTimeJoin: { short: "{date}, {time}", medium: "{date}, {time}", long: "{date} at {time}", full: "{date} at {time}" }
|
|
363
|
+
}
|
|
364
|
+
};
|
|
365
|
+
|
|
366
|
+
// packages/exponential-ui/src/format.ts
|
|
367
|
+
var FALLBACK = locale_default.englishFallback;
|
|
368
|
+
var MS = { second: 1000, minute: 60000, hour: 3600000, day: 86400000 };
|
|
369
|
+
function displayString2(value) {
|
|
370
|
+
if (typeof value === `string`)
|
|
371
|
+
return value;
|
|
372
|
+
if (typeof value === `number`)
|
|
373
|
+
return Number.isFinite(value) ? String(value) : ``;
|
|
374
|
+
if (typeof value === `boolean`)
|
|
375
|
+
return String(value);
|
|
376
|
+
return ``;
|
|
377
|
+
}
|
|
378
|
+
function decimalOf(abs) {
|
|
379
|
+
const m = /^(\d+)(?:\.(\d+))?(?:e([+-]\d+))?$/.exec(String(abs));
|
|
380
|
+
if (!m)
|
|
381
|
+
return { int: `0`, frac: `` };
|
|
382
|
+
const digits = m[1] + (m[2] ?? ``);
|
|
383
|
+
let point = m[1].length + (m[3] ? Number(m[3]) : 0);
|
|
384
|
+
let all = digits;
|
|
385
|
+
if (point <= 0) {
|
|
386
|
+
all = `0`.repeat(1 - point) + all;
|
|
387
|
+
point = 1;
|
|
388
|
+
}
|
|
389
|
+
if (point > all.length)
|
|
390
|
+
all = all + `0`.repeat(point - all.length);
|
|
391
|
+
const int = all.slice(0, point).replace(/^0+(?=\d)/, ``);
|
|
392
|
+
return { int, frac: all.slice(point).replace(/0+$/, ``) };
|
|
393
|
+
}
|
|
394
|
+
function shift(d, places) {
|
|
395
|
+
const frac = d.frac + `0`.repeat(Math.max(0, places - d.frac.length));
|
|
396
|
+
const int = (d.int + frac.slice(0, places)).replace(/^0+(?=\d)/, ``);
|
|
397
|
+
return { int, frac: frac.slice(places).replace(/0+$/, ``) };
|
|
398
|
+
}
|
|
399
|
+
function round(d, min, max) {
|
|
400
|
+
let { int, frac } = d;
|
|
401
|
+
if (frac.length > max) {
|
|
402
|
+
const up = frac.charCodeAt(max) >= 53;
|
|
403
|
+
let kept = int + frac.slice(0, max);
|
|
404
|
+
if (up) {
|
|
405
|
+
const chars = kept.split(``);
|
|
406
|
+
let i = chars.length - 1;
|
|
407
|
+
for (;i >= 0; i--) {
|
|
408
|
+
if (chars[i] === `9`)
|
|
409
|
+
chars[i] = `0`;
|
|
410
|
+
else {
|
|
411
|
+
chars[i] = String(Number(chars[i]) + 1);
|
|
412
|
+
break;
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
kept = (i < 0 ? `1` : ``) + chars.join(``);
|
|
416
|
+
}
|
|
417
|
+
const intLen = kept.length - max;
|
|
418
|
+
int = kept.slice(0, intLen) || `0`;
|
|
419
|
+
frac = kept.slice(intLen).replace(/0+$/, ``);
|
|
420
|
+
}
|
|
421
|
+
if (frac.length < min)
|
|
422
|
+
frac = frac + `0`.repeat(min - frac.length);
|
|
423
|
+
return { int, frac };
|
|
424
|
+
}
|
|
425
|
+
function group(int, on) {
|
|
426
|
+
if (!on || int.length < 4)
|
|
427
|
+
return int;
|
|
428
|
+
let out = ``;
|
|
429
|
+
for (let i = 0;i < int.length; i++) {
|
|
430
|
+
if (i > 0 && (int.length - i) % 3 === 0)
|
|
431
|
+
out += `,`;
|
|
432
|
+
out += int[i];
|
|
433
|
+
}
|
|
434
|
+
return out;
|
|
435
|
+
}
|
|
436
|
+
function englishNumber(value, min, max, grouping) {
|
|
437
|
+
const neg = value < 0 || Object.is(value, -0);
|
|
438
|
+
if (Number.isNaN(value))
|
|
439
|
+
return { sign: ``, body: `NaN` };
|
|
440
|
+
if (!Number.isFinite(value))
|
|
441
|
+
return { sign: neg ? `-` : ``, body: `∞` };
|
|
442
|
+
const d = round(decimalOf(Math.abs(value)), min, max);
|
|
443
|
+
return { sign: neg ? `-` : ``, body: `${group(d.int, grouping)}${d.frac ? `.${d.frac}` : ``}` };
|
|
444
|
+
}
|
|
445
|
+
var fixedDigits = (decimals) => typeof decimals === `number` && Number.isFinite(decimals) ? Math.max(0, Math.min(20, Math.trunc(decimals))) : undefined;
|
|
446
|
+
function currencyDigits2(code) {
|
|
447
|
+
return FALLBACK.currencyDigits[code.toUpperCase()] ?? 2;
|
|
448
|
+
}
|
|
449
|
+
function parseDateValue2(value) {
|
|
450
|
+
if (typeof value === `number`)
|
|
451
|
+
return Number.isFinite(value) ? { ms: value, dateOnly: false } : null;
|
|
452
|
+
if (typeof value !== `string` || value.trim() === ``)
|
|
453
|
+
return null;
|
|
454
|
+
const day = /^(\d{4})-(\d{2})-(\d{2})$/.exec(value);
|
|
455
|
+
if (day) {
|
|
456
|
+
const ms = Date.UTC(Number(day[1]), Number(day[2]) - 1, Number(day[3]));
|
|
457
|
+
return Number.isFinite(ms) ? { ms, dateOnly: true } : null;
|
|
458
|
+
}
|
|
459
|
+
if (!/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}(:\d{2}(\.\d+)?)?(Z|[+-]\d{2}:\d{2})?$/.test(value))
|
|
460
|
+
return null;
|
|
461
|
+
const zoned = /(Z|[+-]\d{2}:\d{2})$/.test(value) ? value : `${value}Z`;
|
|
462
|
+
const ms = Date.parse(zoned);
|
|
463
|
+
return Number.isFinite(ms) ? { ms, dateOnly: false } : null;
|
|
464
|
+
}
|
|
465
|
+
function utcFields(ms) {
|
|
466
|
+
const d = new Date(ms);
|
|
467
|
+
return { year: d.getUTCFullYear(), month: d.getUTCMonth() + 1, day: d.getUTCDate(), weekday: d.getUTCDay(), hour: d.getUTCHours(), minute: d.getUTCMinutes(), second: d.getUTCSeconds() };
|
|
468
|
+
}
|
|
469
|
+
var pad = (n, width) => String(n).padStart(width, `0`);
|
|
470
|
+
function formatPattern2(pattern, f, names) {
|
|
471
|
+
let out = ``;
|
|
472
|
+
let i = 0;
|
|
473
|
+
while (i < pattern.length) {
|
|
474
|
+
const ch = pattern[i];
|
|
475
|
+
if (ch === `'`) {
|
|
476
|
+
if (pattern[i + 1] === `'`) {
|
|
477
|
+
out += `'`;
|
|
478
|
+
i += 2;
|
|
479
|
+
continue;
|
|
480
|
+
}
|
|
481
|
+
i++;
|
|
482
|
+
while (i < pattern.length) {
|
|
483
|
+
if (pattern[i] === `'`) {
|
|
484
|
+
if (pattern[i + 1] === `'`) {
|
|
485
|
+
out += `'`;
|
|
486
|
+
i += 2;
|
|
487
|
+
continue;
|
|
488
|
+
}
|
|
489
|
+
i++;
|
|
490
|
+
break;
|
|
491
|
+
}
|
|
492
|
+
out += pattern[i];
|
|
493
|
+
i++;
|
|
494
|
+
}
|
|
495
|
+
continue;
|
|
496
|
+
}
|
|
497
|
+
if (!/[A-Za-z]/.test(ch)) {
|
|
498
|
+
out += ch;
|
|
499
|
+
i++;
|
|
500
|
+
continue;
|
|
501
|
+
}
|
|
502
|
+
let n = 1;
|
|
503
|
+
while (pattern[i + n] === ch)
|
|
504
|
+
n++;
|
|
505
|
+
const run = pattern.slice(i, i + n);
|
|
506
|
+
i += n;
|
|
507
|
+
const h12 = f.hour % 12 === 0 ? 12 : f.hour % 12;
|
|
508
|
+
switch (ch) {
|
|
509
|
+
case `y`:
|
|
510
|
+
out += n === 2 ? pad(f.year % 100, 2) : pad(f.year, n);
|
|
511
|
+
break;
|
|
512
|
+
case `M`:
|
|
513
|
+
out += n >= 4 ? names.months[f.month - 1] : n === 3 ? names.monthsShort[f.month - 1] : pad(f.month, n);
|
|
514
|
+
break;
|
|
515
|
+
case `d`:
|
|
516
|
+
out += pad(f.day, n);
|
|
517
|
+
break;
|
|
518
|
+
case `E`:
|
|
519
|
+
out += n >= 4 ? names.weekdays[f.weekday] : names.weekdaysShort[f.weekday];
|
|
520
|
+
break;
|
|
521
|
+
case `h`:
|
|
522
|
+
out += pad(h12, n);
|
|
523
|
+
break;
|
|
524
|
+
case `H`:
|
|
525
|
+
out += pad(f.hour, n);
|
|
526
|
+
break;
|
|
527
|
+
case `m`:
|
|
528
|
+
out += pad(f.minute, n);
|
|
529
|
+
break;
|
|
530
|
+
case `s`:
|
|
531
|
+
out += pad(f.second, n);
|
|
532
|
+
break;
|
|
533
|
+
case `a`:
|
|
534
|
+
out += names.dayPeriods[f.hour < 12 ? 0 : 1];
|
|
535
|
+
break;
|
|
536
|
+
default:
|
|
537
|
+
out += run;
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
return out;
|
|
541
|
+
}
|
|
542
|
+
var ENGLISH_DATE_PATTERNS2 = FALLBACK.datePatterns;
|
|
543
|
+
var ENGLISH_TIME_PATTERN2 = FALLBACK.timePattern;
|
|
544
|
+
var ENGLISH_DATE_TIME_JOIN2 = FALLBACK.dateTimeJoin;
|
|
545
|
+
var fixedOffset2 = (minutes) => () => minutes;
|
|
546
|
+
function intlZoneOffset2(timeZone) {
|
|
547
|
+
const dtf = new Intl.DateTimeFormat(`en-US`, { timeZone, year: `numeric`, month: `numeric`, day: `numeric`, hour: `numeric`, minute: `numeric`, second: `numeric`, hourCycle: `h23` });
|
|
548
|
+
return (ms) => {
|
|
549
|
+
const at = Math.floor(ms / 1000) * 1000;
|
|
550
|
+
const p = Object.fromEntries(dtf.formatToParts(new Date(at)).map((x) => [x.type, x.value]));
|
|
551
|
+
const local = Date.UTC(Number(p.year), Number(p.month) - 1, Number(p.day), Number(p.hour) % 24, Number(p.minute), Number(p.second));
|
|
552
|
+
return Math.round((local - at) / 60000);
|
|
553
|
+
};
|
|
554
|
+
}
|
|
555
|
+
function relativeTimeUnit2(deltaMs) {
|
|
556
|
+
const abs = Math.abs(deltaMs);
|
|
557
|
+
const t = (unit) => Math.trunc(deltaMs / unit) || 0;
|
|
558
|
+
if (abs < MS.minute)
|
|
559
|
+
return { value: t(MS.second), unit: `second` };
|
|
560
|
+
if (abs < MS.hour)
|
|
561
|
+
return { value: t(MS.minute), unit: `minute` };
|
|
562
|
+
if (abs < MS.day)
|
|
563
|
+
return { value: t(MS.hour), unit: `hour` };
|
|
564
|
+
if (abs < 7 * MS.day)
|
|
565
|
+
return { value: t(MS.day), unit: `day` };
|
|
566
|
+
if (abs < 30 * MS.day)
|
|
567
|
+
return { value: t(7 * MS.day), unit: `week` };
|
|
568
|
+
if (abs < 365 * MS.day)
|
|
569
|
+
return { value: t(30 * MS.day), unit: `month` };
|
|
570
|
+
return { value: t(365 * MS.day), unit: `year` };
|
|
571
|
+
}
|
|
572
|
+
var ENGLISH_NAMES = FALLBACK;
|
|
573
|
+
function englishFormatter2(zone = fixedOffset2(0)) {
|
|
574
|
+
return {
|
|
575
|
+
locale: `en-US`,
|
|
576
|
+
number(value, options = {}) {
|
|
577
|
+
const fixed = fixedDigits(options.decimals);
|
|
578
|
+
const { sign, body } = englishNumber(value, fixed ?? 0, fixed ?? 3, options.grouping !== false);
|
|
579
|
+
return `${sign}${body}`;
|
|
580
|
+
},
|
|
581
|
+
currency(value, currency, options = {}) {
|
|
582
|
+
const code = currency.toUpperCase();
|
|
583
|
+
const digits = fixedDigits(options.decimals) ?? currencyDigits2(code);
|
|
584
|
+
const { sign, body } = englishNumber(value, digits, digits, options.grouping !== false);
|
|
585
|
+
const prefix = FALLBACK.currencyPrefix[code] ?? FALLBACK.unknownCurrency.replace(`{code}`, code);
|
|
586
|
+
return `${sign}${prefix}${body}`;
|
|
587
|
+
},
|
|
588
|
+
percent(value, options = {}) {
|
|
589
|
+
const digits = fixedDigits(options.decimals) ?? 0;
|
|
590
|
+
if (!Number.isFinite(value)) {
|
|
591
|
+
const { sign, body } = englishNumber(value, 0, 0, true);
|
|
592
|
+
return `${sign}${body}%`;
|
|
593
|
+
}
|
|
594
|
+
const neg = value < 0 || Object.is(value, -0);
|
|
595
|
+
const d = round(shift(decimalOf(Math.abs(value)), 2), digits, digits);
|
|
596
|
+
return `${neg ? `-` : ``}${group(d.int, true)}${d.frac ? `.${d.frac}` : ``}%`;
|
|
597
|
+
},
|
|
598
|
+
date(value, options = {}) {
|
|
599
|
+
const parsed = parseDateValue2(value);
|
|
600
|
+
if (!parsed)
|
|
601
|
+
return ``;
|
|
602
|
+
const f = utcFields(parsed.dateOnly ? parsed.ms : parsed.ms + zone(parsed.ms) * 60000);
|
|
603
|
+
if (options.format)
|
|
604
|
+
return formatPattern2(options.format, f, ENGLISH_NAMES);
|
|
605
|
+
const style = options.style ?? `medium`;
|
|
606
|
+
const date = formatPattern2(ENGLISH_DATE_PATTERNS2[style], f, ENGLISH_NAMES);
|
|
607
|
+
if (!options.time)
|
|
608
|
+
return date;
|
|
609
|
+
const time = formatPattern2(ENGLISH_TIME_PATTERN2, f, ENGLISH_NAMES);
|
|
610
|
+
return ENGLISH_DATE_TIME_JOIN2[style].replace(`{date}`, date).replace(`{time}`, time);
|
|
611
|
+
},
|
|
612
|
+
relativeTime(value, now) {
|
|
613
|
+
const parsed = parseDateValue2(value);
|
|
614
|
+
if (!parsed)
|
|
615
|
+
return ``;
|
|
616
|
+
const { value: n, unit } = relativeTimeUnit2(parsed.ms - now);
|
|
617
|
+
const auto = FALLBACK.relative.auto[unit]?.[String(n)];
|
|
618
|
+
if (auto)
|
|
619
|
+
return auto;
|
|
620
|
+
const [one, many] = FALLBACK.relative.units[unit];
|
|
621
|
+
const count = englishNumber(Math.abs(n), 0, 0, true).body;
|
|
622
|
+
const unitName = Math.abs(n) === 1 ? one : many;
|
|
623
|
+
const template = n < 0 ? FALLBACK.relative.past : FALLBACK.relative.future;
|
|
624
|
+
return template.replace(`{value}`, count).replace(`{unit}`, unitName);
|
|
625
|
+
},
|
|
626
|
+
plural(value) {
|
|
627
|
+
return Math.abs(value) === 1 ? `one` : `other`;
|
|
628
|
+
}
|
|
629
|
+
};
|
|
630
|
+
}
|
|
631
|
+
function intlFormatter2(locale, timeZone = `UTC`) {
|
|
632
|
+
const nf = (o) => new Intl.NumberFormat(locale, o);
|
|
633
|
+
let names = null;
|
|
634
|
+
const dateNames = () => {
|
|
635
|
+
if (names)
|
|
636
|
+
return names;
|
|
637
|
+
const at = (o, ms) => new Intl.DateTimeFormat(locale, { ...o, timeZone: `UTC` }).format(new Date(ms));
|
|
638
|
+
const months = Array.from({ length: 12 }, (_, i) => Date.UTC(2026, i, 1));
|
|
639
|
+
const days = Array.from({ length: 7 }, (_, i) => Date.UTC(2026, 0, 4 + i));
|
|
640
|
+
const period = (h) => new Intl.DateTimeFormat(locale, { hour: `numeric`, hour12: true, timeZone: `UTC` }).formatToParts(new Date(Date.UTC(2026, 0, 1, h))).find((p) => p.type === `dayPeriod`)?.value ?? (h < 12 ? `AM` : `PM`);
|
|
641
|
+
names = {
|
|
642
|
+
months: months.map((ms) => at({ month: `long` }, ms)),
|
|
643
|
+
monthsShort: months.map((ms) => at({ month: `short` }, ms)),
|
|
644
|
+
weekdays: days.map((ms) => at({ weekday: `long` }, ms)),
|
|
645
|
+
weekdaysShort: days.map((ms) => at({ weekday: `short` }, ms)),
|
|
646
|
+
dayPeriods: [period(9), period(15)]
|
|
647
|
+
};
|
|
648
|
+
return names;
|
|
649
|
+
};
|
|
650
|
+
const zonedFields = (ms) => {
|
|
651
|
+
const parts = new Intl.DateTimeFormat(`en-US`, { timeZone, year: `numeric`, month: `numeric`, day: `numeric`, hour: `numeric`, minute: `numeric`, second: `numeric`, weekday: `short`, hourCycle: `h23` }).formatToParts(new Date(ms));
|
|
652
|
+
const get = (t) => parts.find((p) => p.type === t)?.value ?? `0`;
|
|
653
|
+
return { year: Number(get(`year`)), month: Number(get(`month`)), day: Number(get(`day`)), weekday: [`Sun`, `Mon`, `Tue`, `Wed`, `Thu`, `Fri`, `Sat`].indexOf(get(`weekday`)), hour: Number(get(`hour`)) % 24, minute: Number(get(`minute`)), second: Number(get(`second`)) };
|
|
654
|
+
};
|
|
655
|
+
return {
|
|
656
|
+
locale,
|
|
657
|
+
number(value, options = {}) {
|
|
658
|
+
const fixed = fixedDigits(options.decimals);
|
|
659
|
+
return nf({ minimumFractionDigits: fixed ?? 0, maximumFractionDigits: fixed ?? 3, useGrouping: options.grouping !== false }).format(value);
|
|
660
|
+
},
|
|
661
|
+
currency(value, currency, options = {}) {
|
|
662
|
+
const fixed = fixedDigits(options.decimals);
|
|
663
|
+
return nf({ style: `currency`, currency, ...fixed !== undefined ? { minimumFractionDigits: fixed, maximumFractionDigits: fixed } : {}, useGrouping: options.grouping !== false }).format(value);
|
|
664
|
+
},
|
|
665
|
+
percent(value, options = {}) {
|
|
666
|
+
const fixed = fixedDigits(options.decimals) ?? 0;
|
|
667
|
+
return nf({ style: `percent`, minimumFractionDigits: fixed, maximumFractionDigits: fixed }).format(value);
|
|
668
|
+
},
|
|
669
|
+
date(value, options = {}) {
|
|
670
|
+
const parsed = parseDateValue2(value);
|
|
671
|
+
if (!parsed)
|
|
672
|
+
return ``;
|
|
673
|
+
const zone = parsed.dateOnly ? `UTC` : timeZone;
|
|
674
|
+
if (options.format)
|
|
675
|
+
return formatPattern2(options.format, parsed.dateOnly ? utcFields(parsed.ms) : zonedFields(parsed.ms), dateNames());
|
|
676
|
+
return new Intl.DateTimeFormat(locale, { dateStyle: options.style ?? `medium`, ...options.time ? { timeStyle: `short` } : {}, timeZone: zone }).format(new Date(parsed.ms));
|
|
677
|
+
},
|
|
678
|
+
relativeTime(value, now) {
|
|
679
|
+
const parsed = parseDateValue2(value);
|
|
680
|
+
if (!parsed)
|
|
681
|
+
return ``;
|
|
682
|
+
const { value: n, unit } = relativeTimeUnit2(parsed.ms - now);
|
|
683
|
+
return new Intl.RelativeTimeFormat(locale, { numeric: `auto` }).format(n, unit);
|
|
684
|
+
},
|
|
685
|
+
plural(value) {
|
|
686
|
+
return new Intl.PluralRules(locale).select(value);
|
|
687
|
+
}
|
|
688
|
+
};
|
|
689
|
+
}
|
|
690
|
+
var FORMAT_FUNCTION_NAMES2 = [`formatNumber`, `formatCurrency`, `formatPercent`, `formatDate`, `formatRelativeTime`, `pluralize`];
|
|
691
|
+
var NUMERIC = /^[ \t\n\r]*[+-]?(\d+\.?\d*|\.\d+)([eE][+-]?\d+)?[ \t\n\r]*$/;
|
|
692
|
+
var toNum = (v) => typeof v === `number` ? v : typeof v === `string` && NUMERIC.test(v) ? Number(v) : NaN;
|
|
693
|
+
var optNum = (v) => v === undefined || v === null ? undefined : toNum(v);
|
|
694
|
+
function formatFunctions2(formatter, now = () => Date.now()) {
|
|
695
|
+
const numberOr = (value, f) => {
|
|
696
|
+
const n = toNum(value);
|
|
697
|
+
return Number.isFinite(n) ? f(n) : ``;
|
|
698
|
+
};
|
|
699
|
+
return {
|
|
700
|
+
formatNumber: ({ value, decimals, grouping }) => numberOr(value, (n) => formatter.number(n, { decimals: optNum(decimals), grouping: grouping === undefined ? undefined : grouping !== false })),
|
|
701
|
+
formatCurrency: ({ value, currency, decimals, grouping }) => numberOr(value, (n) => typeof currency === `string` && /^[A-Za-z]{3}$/.test(currency) ? formatter.currency(n, currency, { decimals: optNum(decimals), grouping: grouping === undefined ? undefined : grouping !== false }) : ``),
|
|
702
|
+
formatPercent: ({ value, decimals }) => numberOr(value, (n) => formatter.percent(n, { decimals: optNum(decimals) })),
|
|
703
|
+
formatDate: ({ value, format, style, time }) => formatter.date(value, { ...typeof format === `string` && format ? { format } : {}, ...style === `short` || style === `medium` || style === `long` || style === `full` ? { style } : {}, ...time === true ? { time: true } : {} }),
|
|
704
|
+
formatRelativeTime: ({ value, now: at }) => formatter.relativeTime(value, typeof at === `number` ? at : parseDateValue2(at)?.ms ?? now()),
|
|
705
|
+
pluralize: (args) => {
|
|
706
|
+
const n = toNum(args.value);
|
|
707
|
+
if (!Number.isFinite(n))
|
|
708
|
+
return args.other;
|
|
709
|
+
if (n === 0 && args.zero !== undefined)
|
|
710
|
+
return args.zero;
|
|
711
|
+
const category = formatter.plural(n);
|
|
712
|
+
return args[category] ?? args.other;
|
|
713
|
+
}
|
|
714
|
+
};
|
|
715
|
+
}
|
|
716
|
+
var ENGLISH_FORMAT_FUNCTIONS2 = formatFunctions2(englishFormatter2());
|
|
717
|
+
|
|
718
|
+
// packages/exponential-ui/src/expr.ts
|
|
719
|
+
var WHOLE = /^\{([^{}]+)\}$/;
|
|
720
|
+
var EMBEDDED = /\{([^{}]+)\}/g;
|
|
721
|
+
var FUNCTION = /^(len|range)\((.+)\)$/;
|
|
722
|
+
function isBinding2(value) {
|
|
723
|
+
return typeof value === `object` && value !== null && !Array.isArray(value) && typeof value.path === `string` && Object.keys(value).length === 1;
|
|
724
|
+
}
|
|
725
|
+
function isCall2(value) {
|
|
726
|
+
return typeof value === `object` && value !== null && !Array.isArray(value) && typeof value.call === `string`;
|
|
727
|
+
}
|
|
728
|
+
function isDynamic2(value) {
|
|
729
|
+
return isBinding2(value) || isCall2(value);
|
|
730
|
+
}
|
|
731
|
+
function truthy2(value) {
|
|
732
|
+
return value !== undefined && value !== null && value !== false && value !== ``;
|
|
733
|
+
}
|
|
734
|
+
function call(name, args) {
|
|
735
|
+
const out = {};
|
|
736
|
+
for (const [k, v] of Object.entries(args))
|
|
737
|
+
if (v !== undefined)
|
|
738
|
+
out[k] = v;
|
|
739
|
+
return { call: name, args: out };
|
|
740
|
+
}
|
|
741
|
+
function parseLiteral(text) {
|
|
742
|
+
if (text === `true`)
|
|
743
|
+
return true;
|
|
744
|
+
if (text === `false`)
|
|
745
|
+
return false;
|
|
746
|
+
if (text === `null`)
|
|
747
|
+
return null;
|
|
748
|
+
if (/^-?\d+(\.\d+)?$/.test(text))
|
|
749
|
+
return Number(text);
|
|
750
|
+
return text;
|
|
751
|
+
}
|
|
752
|
+
function lookup(path, ctx) {
|
|
753
|
+
if (path === `id`)
|
|
754
|
+
return ctx.id;
|
|
755
|
+
const [head, ...rest] = path.split(`.`);
|
|
756
|
+
let cur;
|
|
757
|
+
if (head === `props`)
|
|
758
|
+
cur = ctx.props;
|
|
759
|
+
else if (head in ctx.vars)
|
|
760
|
+
cur = ctx.vars[head];
|
|
761
|
+
else
|
|
762
|
+
return;
|
|
763
|
+
for (const key of rest) {
|
|
764
|
+
if (cur === undefined || cur === null)
|
|
765
|
+
return;
|
|
766
|
+
cur = cur[key];
|
|
767
|
+
}
|
|
768
|
+
return cur;
|
|
769
|
+
}
|
|
770
|
+
function toNumber(value) {
|
|
771
|
+
return typeof value === `number` ? value : Number(value ?? 0) || 0;
|
|
772
|
+
}
|
|
773
|
+
function numericString(value) {
|
|
774
|
+
const text = value.trim();
|
|
775
|
+
if (text === ``)
|
|
776
|
+
return;
|
|
777
|
+
const n = Number(text);
|
|
778
|
+
return Number.isFinite(n) ? n : undefined;
|
|
779
|
+
}
|
|
780
|
+
function valuesEqual2(a, b) {
|
|
781
|
+
if (a === b)
|
|
782
|
+
return true;
|
|
783
|
+
if (typeof a === `number` && typeof b === `string`)
|
|
784
|
+
return numericString(b) === a;
|
|
785
|
+
if (typeof b === `number` && typeof a === `string`)
|
|
786
|
+
return numericString(a) === b;
|
|
787
|
+
return false;
|
|
788
|
+
}
|
|
789
|
+
function clampNumber2(value, min, max) {
|
|
790
|
+
let n = toNumber(value);
|
|
791
|
+
if (max !== undefined && max !== null)
|
|
792
|
+
n = Math.min(n, toNumber(max));
|
|
793
|
+
if (min !== undefined && min !== null)
|
|
794
|
+
n = Math.max(n, toNumber(min));
|
|
795
|
+
return n;
|
|
796
|
+
}
|
|
797
|
+
function fillTemplate2(template, params) {
|
|
798
|
+
const text = template === undefined || template === null ? `` : String(template);
|
|
799
|
+
return formatString2(text, typeof params === `object` && params !== null ? params : {});
|
|
800
|
+
}
|
|
801
|
+
var MAX_RANGE_ITEMS = 1e4;
|
|
802
|
+
function evalExpr2(expr, ctx) {
|
|
803
|
+
const text = expr.trim();
|
|
804
|
+
const fn = FUNCTION.exec(text);
|
|
805
|
+
if (fn) {
|
|
806
|
+
const inner = evalExpr2(fn[2], ctx);
|
|
807
|
+
if (fn[1] === `len`) {
|
|
808
|
+
if (isDynamic2(inner))
|
|
809
|
+
return call(`len`, { value: inner });
|
|
810
|
+
return Array.isArray(inner) ? inner.length : typeof inner === `string` ? inner.length : 0;
|
|
811
|
+
}
|
|
812
|
+
if (isDynamic2(inner))
|
|
813
|
+
return;
|
|
814
|
+
const n = Math.min(MAX_RANGE_ITEMS, Math.max(0, Math.floor(toNumber(inner))) || 0);
|
|
815
|
+
return Array.from({ length: n }, (_, i) => i);
|
|
816
|
+
}
|
|
817
|
+
const bar = text.indexOf(`|`);
|
|
818
|
+
if (bar >= 0) {
|
|
819
|
+
const value = evalExpr2(text.slice(0, bar), ctx);
|
|
820
|
+
const fallback = parseLiteral(text.slice(bar + 1));
|
|
821
|
+
if (value === undefined || value === null)
|
|
822
|
+
return fallback;
|
|
823
|
+
if (isDynamic2(value))
|
|
824
|
+
return call(`fallback`, { value, default: fallback });
|
|
825
|
+
return value;
|
|
826
|
+
}
|
|
827
|
+
if (text.startsWith(`!`)) {
|
|
828
|
+
const value = evalExpr2(text.slice(1), ctx);
|
|
829
|
+
if (isDynamic2(value))
|
|
830
|
+
return call(`not`, { value });
|
|
831
|
+
return !truthy2(value);
|
|
832
|
+
}
|
|
833
|
+
return lookup(text, ctx);
|
|
834
|
+
}
|
|
835
|
+
function passThrough(value) {
|
|
836
|
+
if (isCall2(value) && value.call === `fallback` && isDynamic2(value.args?.value))
|
|
837
|
+
return value.args?.value;
|
|
838
|
+
return value;
|
|
839
|
+
}
|
|
840
|
+
function evalOperand(value, ctx) {
|
|
841
|
+
if (typeof value === `string`) {
|
|
842
|
+
const whole = WHOLE.exec(value);
|
|
843
|
+
if (whole)
|
|
844
|
+
return evalExpr2(whole[1], ctx);
|
|
845
|
+
}
|
|
846
|
+
return evalValue2(value, ctx);
|
|
847
|
+
}
|
|
848
|
+
function evalConditionValue2(cond, ctx) {
|
|
849
|
+
const value = typeof cond === `string` ? evalExpr2(cond, ctx) : evalOperand(cond, ctx);
|
|
850
|
+
if (isDynamic2(value))
|
|
851
|
+
return value;
|
|
852
|
+
return truthy2(value);
|
|
853
|
+
}
|
|
854
|
+
function evalCondition2(cond, ctx) {
|
|
855
|
+
const value = evalConditionValue2(cond, ctx);
|
|
856
|
+
return value === true || isDynamic2(value);
|
|
857
|
+
}
|
|
858
|
+
function interpolate(value, ctx) {
|
|
859
|
+
const parts = [];
|
|
860
|
+
let dynamic = false;
|
|
861
|
+
let last = 0;
|
|
862
|
+
for (const match of value.matchAll(EMBEDDED)) {
|
|
863
|
+
const at = match.index ?? 0;
|
|
864
|
+
if (at > last)
|
|
865
|
+
parts.push(value.slice(last, at));
|
|
866
|
+
const v = evalExpr2(match[1], ctx);
|
|
867
|
+
if (isDynamic2(v))
|
|
868
|
+
dynamic = true;
|
|
869
|
+
parts.push(v);
|
|
870
|
+
last = at + match[0].length;
|
|
871
|
+
}
|
|
872
|
+
if (last < value.length)
|
|
873
|
+
parts.push(value.slice(last));
|
|
874
|
+
if (dynamic)
|
|
875
|
+
return call(`concat`, { values: parts.filter((p) => p !== undefined && p !== null && p !== ``) });
|
|
876
|
+
return parts.map((p) => p === undefined || p === null ? `` : String(p)).join(``);
|
|
877
|
+
}
|
|
878
|
+
function evalValue2(value, ctx) {
|
|
879
|
+
if (typeof value === `string`) {
|
|
880
|
+
const whole = WHOLE.exec(value);
|
|
881
|
+
if (whole)
|
|
882
|
+
return passThrough(evalExpr2(whole[1], ctx));
|
|
883
|
+
return interpolate(value, ctx);
|
|
884
|
+
}
|
|
885
|
+
if (Array.isArray(value)) {
|
|
886
|
+
return value.map((item) => evalValue2(item, ctx)).filter((item) => item !== undefined);
|
|
887
|
+
}
|
|
888
|
+
if (typeof value !== `object` || value === null)
|
|
889
|
+
return value;
|
|
890
|
+
const obj = value;
|
|
891
|
+
if (`$map` in obj) {
|
|
892
|
+
const spec = obj.$map;
|
|
893
|
+
const from = evalExpr2(spec.from, ctx);
|
|
894
|
+
if (isDynamic2(from)) {
|
|
895
|
+
const cases = {};
|
|
896
|
+
for (const [k, v] of Object.entries(spec.cases)) {
|
|
897
|
+
const evaluated = evalOperand(v, ctx);
|
|
898
|
+
if (evaluated !== undefined)
|
|
899
|
+
cases[k] = evaluated;
|
|
900
|
+
}
|
|
901
|
+
return call(`map`, { value: from, cases, default: evalOperand(spec.default, ctx) });
|
|
902
|
+
}
|
|
903
|
+
const key = from === undefined || from === null ? `` : String(from);
|
|
904
|
+
const hit = Object.prototype.hasOwnProperty.call(spec.cases, key) ? spec.cases[key] : spec.default;
|
|
905
|
+
return evalOperand(hit, ctx);
|
|
906
|
+
}
|
|
907
|
+
if (`$cond` in obj) {
|
|
908
|
+
const [cond, then, otherwise] = obj.$cond;
|
|
909
|
+
const decided = evalConditionValue2(cond, ctx);
|
|
910
|
+
if (isDynamic2(decided))
|
|
911
|
+
return call(`cond`, { if: decided, then: evalOperand(then, ctx), else: evalOperand(otherwise, ctx) });
|
|
912
|
+
return evalOperand(decided ? then : otherwise, ctx);
|
|
913
|
+
}
|
|
914
|
+
if (`$eq` in obj) {
|
|
915
|
+
const [a, b] = obj.$eq.map((x) => evalOperand(x, ctx));
|
|
916
|
+
if (isDynamic2(a) || isDynamic2(b))
|
|
917
|
+
return call(`eq`, { a, b });
|
|
918
|
+
return valuesEqual2(a, b);
|
|
919
|
+
}
|
|
920
|
+
if (`$lt` in obj) {
|
|
921
|
+
const [a, b] = obj.$lt.map((x) => evalOperand(x, ctx));
|
|
922
|
+
if (isDynamic2(a) || isDynamic2(b))
|
|
923
|
+
return call(`lt`, { a, b });
|
|
924
|
+
return toNumber(a) < toNumber(b);
|
|
925
|
+
}
|
|
926
|
+
if (`$add` in obj) {
|
|
927
|
+
const [a, b] = obj.$add.map((x) => evalOperand(x, ctx));
|
|
928
|
+
if (isDynamic2(a) || isDynamic2(b))
|
|
929
|
+
return call(`add`, { a, b });
|
|
930
|
+
return toNumber(a) + toNumber(b);
|
|
931
|
+
}
|
|
932
|
+
if (`$sub` in obj) {
|
|
933
|
+
const [a, b] = obj.$sub.map((x) => evalOperand(x, ctx));
|
|
934
|
+
if (isDynamic2(a) || isDynamic2(b))
|
|
935
|
+
return call(`sub`, { a, b });
|
|
936
|
+
return toNumber(a) - toNumber(b);
|
|
937
|
+
}
|
|
938
|
+
if (`$clamp` in obj) {
|
|
939
|
+
const [v, min, max] = obj.$clamp.map((x) => evalOperand(x, ctx));
|
|
940
|
+
if (isDynamic2(v) || isDynamic2(min) || isDynamic2(max))
|
|
941
|
+
return call(`clamp`, { value: v, min, max });
|
|
942
|
+
return clampNumber2(v, min, max);
|
|
943
|
+
}
|
|
944
|
+
if (`$fill` in obj) {
|
|
945
|
+
const [template, params] = obj.$fill;
|
|
946
|
+
const filled = {};
|
|
947
|
+
for (const [k, v] of Object.entries(params ?? {})) {
|
|
948
|
+
const evaluated = evalOperand(v, ctx);
|
|
949
|
+
if (evaluated !== undefined)
|
|
950
|
+
filled[k] = evaluated;
|
|
951
|
+
}
|
|
952
|
+
return call(`fill`, { template: evalOperand(template, ctx), params: filled });
|
|
953
|
+
}
|
|
954
|
+
if (`$percent` in obj) {
|
|
955
|
+
const [v, max] = obj.$percent.map((x) => evalOperand(x, ctx));
|
|
956
|
+
if (isDynamic2(v) || isDynamic2(max))
|
|
957
|
+
return call(`percent`, { value: v, max });
|
|
958
|
+
return percent2(v, max);
|
|
959
|
+
}
|
|
960
|
+
if (`$text` in obj) {
|
|
961
|
+
const spec = obj.$text;
|
|
962
|
+
const v = typeof spec === `string` ? evalExpr2(spec, ctx) : evalOperand(spec, ctx);
|
|
963
|
+
if (isDynamic2(v))
|
|
964
|
+
return call(`text`, { value: v });
|
|
965
|
+
return v === undefined || v === null ? undefined : String(v);
|
|
966
|
+
}
|
|
967
|
+
if (`$coalesce` in obj) {
|
|
968
|
+
const out = [];
|
|
969
|
+
for (const candidate of obj.$coalesce) {
|
|
970
|
+
const v = evalOperand(candidate, ctx);
|
|
971
|
+
if (v === undefined)
|
|
972
|
+
continue;
|
|
973
|
+
if (isDynamic2(v)) {
|
|
974
|
+
out.push(v);
|
|
975
|
+
continue;
|
|
976
|
+
}
|
|
977
|
+
if (!truthy2(v))
|
|
978
|
+
continue;
|
|
979
|
+
if (out.length === 0)
|
|
980
|
+
return v;
|
|
981
|
+
out.push(v);
|
|
982
|
+
break;
|
|
983
|
+
}
|
|
984
|
+
if (out.length === 0)
|
|
985
|
+
return;
|
|
986
|
+
if (out.length === 1)
|
|
987
|
+
return out[0];
|
|
988
|
+
return call(`coalesce`, { values: out });
|
|
989
|
+
}
|
|
990
|
+
if (`$not` in obj) {
|
|
991
|
+
const decided = evalConditionValue2(obj.$not, ctx);
|
|
992
|
+
if (isDynamic2(decided))
|
|
993
|
+
return call(`not`, { value: decided });
|
|
994
|
+
return !decided;
|
|
995
|
+
}
|
|
996
|
+
const out = {};
|
|
997
|
+
for (const [k, v] of Object.entries(obj)) {
|
|
998
|
+
const evaluated = evalValue2(v, ctx);
|
|
999
|
+
if (evaluated === undefined)
|
|
1000
|
+
continue;
|
|
1001
|
+
const key = k.includes(`{`) ? evalValue2(k, ctx) : k;
|
|
1002
|
+
out[typeof key === `string` ? key : k] = evaluated;
|
|
1003
|
+
}
|
|
1004
|
+
return out;
|
|
1005
|
+
}
|
|
1006
|
+
function percent2(value, max) {
|
|
1007
|
+
const m = toNumber(max);
|
|
1008
|
+
const pct = m > 0 ? toNumber(value) / m * 100 : 0;
|
|
1009
|
+
const clamped = Math.min(100, Math.max(0, pct));
|
|
1010
|
+
return `${Math.round(clamped * 100) / 100}%`;
|
|
1011
|
+
}
|
|
1012
|
+
function filterItems2(items, query, fields, where) {
|
|
1013
|
+
if (!Array.isArray(items))
|
|
1014
|
+
return [];
|
|
1015
|
+
const needle = typeof query === `string` ? query.trim().toLowerCase() : typeof query === `number` ? String(query) : ``;
|
|
1016
|
+
const keys = Array.isArray(fields) ? fields.filter((f) => typeof f === `string`) : null;
|
|
1017
|
+
const conditions = typeof where === `object` && where !== null && !Array.isArray(where) ? Object.entries(where).filter(([, v]) => v !== undefined && v !== null && v !== ``) : [];
|
|
1018
|
+
const searchable = (v) => typeof v === `string` ? v : typeof v === `number` ? String(v) : null;
|
|
1019
|
+
return items.filter((item) => {
|
|
1020
|
+
const record = typeof item === `object` && item !== null && !Array.isArray(item) ? item : null;
|
|
1021
|
+
for (const [field, want] of conditions)
|
|
1022
|
+
if (!valuesEqual2(record?.[field], want))
|
|
1023
|
+
return false;
|
|
1024
|
+
if (needle === ``)
|
|
1025
|
+
return true;
|
|
1026
|
+
const values = record ? (keys ?? Object.keys(record)).map((k) => record[k]) : [item];
|
|
1027
|
+
return values.some((v) => searchable(v)?.toLowerCase().includes(needle) ?? false);
|
|
1028
|
+
});
|
|
1029
|
+
}
|
|
1030
|
+
var CORE_FUNCTIONS2 = {
|
|
1031
|
+
percent: ({ value, max }) => percent2(value, max),
|
|
1032
|
+
add: ({ a, b }) => toNumber(a) + toNumber(b),
|
|
1033
|
+
sub: ({ a, b }) => toNumber(a) - toNumber(b),
|
|
1034
|
+
eq: ({ a, b }) => valuesEqual2(a, b),
|
|
1035
|
+
lt: ({ a, b }) => toNumber(a) < toNumber(b),
|
|
1036
|
+
clamp: ({ value, min, max }) => clampNumber2(value, min, max),
|
|
1037
|
+
cond: ({ if: test, then, else: otherwise }) => truthy2(test) ? then : otherwise,
|
|
1038
|
+
fallback: ({ value, default: fallback }) => value === undefined || value === null ? fallback : value,
|
|
1039
|
+
concat: ({ values }) => Array.isArray(values) ? values.map((v) => v === undefined || v === null ? `` : String(v)).join(``) : ``,
|
|
1040
|
+
coalesce: ({ values }) => Array.isArray(values) ? values.find(truthy2) : undefined,
|
|
1041
|
+
text: ({ value }) => value === undefined || value === null ? undefined : String(value),
|
|
1042
|
+
map: ({ value, cases, default: fallback }) => {
|
|
1043
|
+
const key = value === undefined || value === null ? `` : String(value);
|
|
1044
|
+
const table = cases ?? {};
|
|
1045
|
+
return Object.prototype.hasOwnProperty.call(table, key) ? table[key] : fallback;
|
|
1046
|
+
},
|
|
1047
|
+
len: ({ value }) => Array.isArray(value) ? value.length : typeof value === `string` ? value.length : 0,
|
|
1048
|
+
fill: ({ template, params }) => fillTemplate2(template, params),
|
|
1049
|
+
filter: ({ items, query, fields, where }) => filterItems2(items, query, fields, where),
|
|
1050
|
+
formatPercent: ENGLISH_FORMAT_FUNCTIONS2.formatPercent,
|
|
1051
|
+
formatRelativeTime: ENGLISH_FORMAT_FUNCTIONS2.formatRelativeTime
|
|
1052
|
+
};
|
|
1053
|
+
var CORE_FUNCTION_NAMES2 = Object.keys(CORE_FUNCTIONS2);
|
|
1054
|
+
// packages/exponential-ui/catalog/limits.json
|
|
1055
|
+
var limits_default = {
|
|
1056
|
+
$comment: "VAPP-103: the input LIMITS every core enforces (the TS reference, the Rust core and through it Swift, Compose and gpui). An agent's input past a limit is refused with an issue, never worked on. `maxComponents` = nodes the reducer places in one surface's tree, template nodes included (the rest is dropped: `surface: more than N components; the rest is dropped`); a renderer's build holds at most `maxComponents` nodes too: the reduced tree's (after expansion, children and slots) plus, per template ITEM, its template subtree's (nested items charged when they are instantiated); the first item that does not fit and every later one are not rendered, with ONE issue on the template component (the same message). `maxDepth` = nesting levels of the REDUCED tree, after macro expansion (the root and every lifted template = 1, children and slots one level down; a Card, Section or Group macro adds a level; a deeper node is the Unknown placeholder, its subtree dropped: `nesting deeper than N levels`); 48 keeps every tree a core emits (2 JSON levels per node) inside serde_json's default recursion limit of 128, so reduced trees, fixtures and the FFI's JSON round-trip; the Rust core's recursive passes switch to a heap-allocated stack segment when the host thread runs low, so an iOS secondary thread's 512 KB never decides (a 48-level surface lays out on a 128 KB thread, debug build). `maxMessageBytes` = one server message as UTF-8 JSON (host routers refuse it: INVALID_MESSAGE). `maxTemplateItems` = template items one surface instantiates (beyond it the items are not rendered: `template: more than N items; the rest is not rendered`). `maxPointerBytes` / `maxPointerSegments` = a data pointer's length and token count (a longer write is refused). Generated into every target; src/limits.ts reads it.",
|
|
1057
|
+
maxComponents: 20000,
|
|
1058
|
+
maxDepth: 48,
|
|
1059
|
+
maxMessageBytes: 4194304,
|
|
1060
|
+
maxTemplateItems: 1e4,
|
|
1061
|
+
maxPointerBytes: 1024,
|
|
1062
|
+
maxPointerSegments: 64
|
|
1063
|
+
};
|
|
1064
|
+
|
|
1065
|
+
// packages/exponential-ui/src/limits.ts
|
|
1066
|
+
var LIMITS2 = Object.fromEntries(Object.entries(limits_default).filter(([k]) => !k.startsWith(`$`)));
|
|
1067
|
+
var MAX_COMPONENTS2 = limits_default.maxComponents;
|
|
1068
|
+
var MAX_DEPTH2 = limits_default.maxDepth;
|
|
1069
|
+
var MAX_MESSAGE_BYTES2 = limits_default.maxMessageBytes;
|
|
1070
|
+
var MAX_TEMPLATE_ITEMS2 = limits_default.maxTemplateItems;
|
|
1071
|
+
var MAX_POINTER_BYTES2 = limits_default.maxPointerBytes;
|
|
1072
|
+
var MAX_POINTER_SEGMENTS2 = limits_default.maxPointerSegments;
|
|
1073
|
+
var LIMIT_ISSUES2 = {
|
|
1074
|
+
usedTwice: `id used twice; only its first place renders`,
|
|
1075
|
+
depth: `nesting deeper than ${MAX_DEPTH2} levels`,
|
|
1076
|
+
components: `surface: more than ${MAX_COMPONENTS2} components; the rest is dropped`,
|
|
1077
|
+
templateItems: `template: more than ${MAX_TEMPLATE_ITEMS2} items; the rest is not rendered`,
|
|
1078
|
+
messageBytes: `message larger than ${MAX_MESSAGE_BYTES2} bytes`
|
|
1079
|
+
};
|
|
1080
|
+
|
|
1081
|
+
// packages/exponential-ui/src/dynamic.ts
|
|
1082
|
+
var unescape = (token) => token.replace(/~1/g, `/`).replace(/~0/g, `~`);
|
|
1083
|
+
function own(table, key) {
|
|
1084
|
+
return table !== undefined && Object.prototype.hasOwnProperty.call(table, key) ? table[key] : undefined;
|
|
1085
|
+
}
|
|
1086
|
+
function absolutePath2(path, scope = {}) {
|
|
1087
|
+
if (path.startsWith(`/`))
|
|
1088
|
+
return path;
|
|
1089
|
+
const base = scope.base ?? ``;
|
|
1090
|
+
if (path === ``)
|
|
1091
|
+
return base;
|
|
1092
|
+
return `${base}/${path}`;
|
|
1093
|
+
}
|
|
1094
|
+
function hasItem2(scope) {
|
|
1095
|
+
return scope !== undefined && Object.prototype.hasOwnProperty.call(scope, `item`);
|
|
1096
|
+
}
|
|
1097
|
+
function readPath2(data, path, scope = {}) {
|
|
1098
|
+
if (!path.startsWith(`/`) && hasItem2(scope))
|
|
1099
|
+
return path === `` ? scope.item : readPointer2(scope.item, `/${path}`);
|
|
1100
|
+
return readPointer2(data, absolutePath2(path, scope));
|
|
1101
|
+
}
|
|
1102
|
+
function readPointer2(data, pointer) {
|
|
1103
|
+
if (pointer === `` || pointer === `/`)
|
|
1104
|
+
return data;
|
|
1105
|
+
let cur = data;
|
|
1106
|
+
for (const raw of (pointer.startsWith(`/`) ? pointer.slice(1) : pointer).split(`/`)) {
|
|
1107
|
+
if (cur === undefined || cur === null || typeof cur !== `object`)
|
|
1108
|
+
return;
|
|
1109
|
+
const token = unescape(raw);
|
|
1110
|
+
if (Array.isArray(cur))
|
|
1111
|
+
cur = /^[0-9]+$/.test(token) ? cur[Number(token)] : undefined;
|
|
1112
|
+
else
|
|
1113
|
+
cur = Object.prototype.hasOwnProperty.call(cur, token) ? cur[token] : undefined;
|
|
1114
|
+
}
|
|
1115
|
+
return cur;
|
|
1116
|
+
}
|
|
1117
|
+
var utf8Length = (text) => new TextEncoder().encode(text).length;
|
|
1118
|
+
function writeTokens2(pointer) {
|
|
1119
|
+
if (utf8Length(pointer) > MAX_POINTER_BYTES2)
|
|
1120
|
+
return POINTER_ISSUES2.bytes;
|
|
1121
|
+
if (pointer === `` || pointer === `/`)
|
|
1122
|
+
return [];
|
|
1123
|
+
const tokens = (pointer.startsWith(`/`) ? pointer.slice(1) : pointer).split(`/`);
|
|
1124
|
+
if (tokens.length > MAX_POINTER_SEGMENTS2)
|
|
1125
|
+
return POINTER_ISSUES2.segments;
|
|
1126
|
+
return tokens.map(unescape);
|
|
1127
|
+
}
|
|
1128
|
+
var POINTER_ISSUES2 = {
|
|
1129
|
+
bytes: `data: pointer longer than ${MAX_POINTER_BYTES2} bytes`,
|
|
1130
|
+
segments: `data: pointer has more than ${MAX_POINTER_SEGMENTS2} segments`,
|
|
1131
|
+
notIndex: (token) => `data: ${JSON.stringify(token)} is not an array index`,
|
|
1132
|
+
pastEnd: (token, length) => `data: index ${token} is past the end of the array (${length} items)`
|
|
1133
|
+
};
|
|
1134
|
+
function arrayIndex(token, length) {
|
|
1135
|
+
if (token === `-`)
|
|
1136
|
+
return length;
|
|
1137
|
+
if (!/^[0-9]+$/.test(token))
|
|
1138
|
+
return POINTER_ISSUES2.notIndex(token);
|
|
1139
|
+
const index = Number(token);
|
|
1140
|
+
return index <= length ? index : POINTER_ISSUES2.pastEnd(token, length);
|
|
1141
|
+
}
|
|
1142
|
+
function setOwn(target, key, value) {
|
|
1143
|
+
Object.defineProperty(target, key, { value, writable: true, enumerable: true, configurable: true });
|
|
1144
|
+
}
|
|
1145
|
+
function writePointer2(data, pointer, value) {
|
|
1146
|
+
const tokens = writeTokens2(pointer);
|
|
1147
|
+
if (typeof tokens === `string`)
|
|
1148
|
+
return { data, error: tokens };
|
|
1149
|
+
if (tokens.length === 0)
|
|
1150
|
+
return { data: value === undefined ? {} : value };
|
|
1151
|
+
const chain = [];
|
|
1152
|
+
const keys = [];
|
|
1153
|
+
let cur = data;
|
|
1154
|
+
for (let i = 0;i < tokens.length; i++) {
|
|
1155
|
+
const token = tokens[i];
|
|
1156
|
+
const last = i === tokens.length - 1;
|
|
1157
|
+
if (Array.isArray(cur)) {
|
|
1158
|
+
const index = arrayIndex(token, cur.length);
|
|
1159
|
+
if (typeof index === `string`)
|
|
1160
|
+
return { data, error: index };
|
|
1161
|
+
const next = [...cur];
|
|
1162
|
+
if (!last)
|
|
1163
|
+
cur = next[index];
|
|
1164
|
+
else if (value === undefined) {
|
|
1165
|
+
if (index < next.length)
|
|
1166
|
+
next.splice(index, 1);
|
|
1167
|
+
} else
|
|
1168
|
+
next[index] = value;
|
|
1169
|
+
chain.push(next);
|
|
1170
|
+
keys.push(index);
|
|
1171
|
+
} else {
|
|
1172
|
+
const next = {};
|
|
1173
|
+
if (cur !== null && typeof cur === `object`)
|
|
1174
|
+
for (const [k, v] of Object.entries(cur))
|
|
1175
|
+
setOwn(next, k, v);
|
|
1176
|
+
if (!last)
|
|
1177
|
+
cur = Object.prototype.hasOwnProperty.call(next, token) ? next[token] : undefined;
|
|
1178
|
+
else if (value === undefined)
|
|
1179
|
+
delete next[token];
|
|
1180
|
+
else
|
|
1181
|
+
setOwn(next, token, value);
|
|
1182
|
+
chain.push(next);
|
|
1183
|
+
keys.push(token);
|
|
1184
|
+
}
|
|
1185
|
+
}
|
|
1186
|
+
for (let i = chain.length - 2;i >= 0; i--) {
|
|
1187
|
+
const parent = chain[i];
|
|
1188
|
+
if (Array.isArray(parent))
|
|
1189
|
+
parent[keys[i]] = chain[i + 1];
|
|
1190
|
+
else
|
|
1191
|
+
setOwn(parent, keys[i], chain[i + 1]);
|
|
1192
|
+
}
|
|
1193
|
+
return { data: chain[0] };
|
|
1194
|
+
}
|
|
1195
|
+
var LOGIC_FUNCTIONS = {
|
|
1196
|
+
and: ({ values }) => Array.isArray(values) && values.every(truthy2),
|
|
1197
|
+
or: ({ values }) => Array.isArray(values) && values.some(truthy2),
|
|
1198
|
+
not: ({ value }) => !truthy2(value),
|
|
1199
|
+
required: ({ value }) => truthy2(value) && !(Array.isArray(value) && value.length === 0)
|
|
1200
|
+
};
|
|
1201
|
+
var BIND_FUNCTIONS2 = { ...LOGIC_FUNCTIONS, ...CORE_FUNCTIONS2, ...ENGLISH_FORMAT_FUNCTIONS2 };
|
|
1202
|
+
var BIND_FUNCTION_NAMES2 = Object.keys(BIND_FUNCTIONS2);
|
|
1203
|
+
var FORMAT_NAMES = new Set(FORMAT_FUNCTION_NAMES2);
|
|
1204
|
+
var FORMAT_TABLES = new WeakMap;
|
|
1205
|
+
function formatTable(options) {
|
|
1206
|
+
if (!options.formatter && !options.now)
|
|
1207
|
+
return;
|
|
1208
|
+
const formatter = options.formatter ?? (english ??= englishFormatter2());
|
|
1209
|
+
if (options.now)
|
|
1210
|
+
return formatFunctions2(formatter, options.now);
|
|
1211
|
+
let table = FORMAT_TABLES.get(formatter);
|
|
1212
|
+
if (!table)
|
|
1213
|
+
FORMAT_TABLES.set(formatter, table = formatFunctions2(formatter));
|
|
1214
|
+
return table;
|
|
1215
|
+
}
|
|
1216
|
+
var english;
|
|
1217
|
+
function resolveDynamic2(value, data, options = {}) {
|
|
1218
|
+
if (isBinding2(value))
|
|
1219
|
+
return readPath2(data, value.path, options.scope);
|
|
1220
|
+
if (isCall2(value)) {
|
|
1221
|
+
const args = {};
|
|
1222
|
+
for (const [k, v] of Object.entries(value.args ?? {}))
|
|
1223
|
+
args[k] = resolveDynamic2(v, data, options);
|
|
1224
|
+
const fn = own(options.functions, value.call) ?? (FORMAT_NAMES.has(value.call) ? own(formatTable(options), value.call) : undefined) ?? own(BIND_FUNCTIONS2, value.call);
|
|
1225
|
+
return fn ? fn(args) : undefined;
|
|
1226
|
+
}
|
|
1227
|
+
if (typeof value === `string`)
|
|
1228
|
+
return options.strings ? resolveString2(value, options.strings) : value;
|
|
1229
|
+
if (Array.isArray(value))
|
|
1230
|
+
return value.map((v) => resolveDynamic2(v, data, options));
|
|
1231
|
+
if (typeof value === `object` && value !== null) {
|
|
1232
|
+
const out = {};
|
|
1233
|
+
for (const [k, v] of Object.entries(value)) {
|
|
1234
|
+
const r = resolveDynamic2(v, data, options);
|
|
1235
|
+
if (r !== undefined)
|
|
1236
|
+
out[k] = r;
|
|
1237
|
+
}
|
|
1238
|
+
return out;
|
|
1239
|
+
}
|
|
1240
|
+
return value;
|
|
1241
|
+
}
|
|
1242
|
+
function isVisible2(visible, data, options = {}) {
|
|
1243
|
+
if (visible === undefined)
|
|
1244
|
+
return true;
|
|
1245
|
+
return truthy2(resolveDynamic2(visible, data, options));
|
|
1246
|
+
}
|
|
1247
|
+
function withOwnWrites2(data, props, own, scope = {}) {
|
|
1248
|
+
let out = data;
|
|
1249
|
+
for (const [key, value] of Object.entries(own ?? {})) {
|
|
1250
|
+
const bound = props[key];
|
|
1251
|
+
if (!isBinding2(bound))
|
|
1252
|
+
continue;
|
|
1253
|
+
if (!bound.path.startsWith(`/`) && hasItem2(scope))
|
|
1254
|
+
continue;
|
|
1255
|
+
out = writePointer2(out, absolutePath2(bound.path, scope), value).data;
|
|
1256
|
+
}
|
|
1257
|
+
return out;
|
|
1258
|
+
}
|
|
1259
|
+
var OVERLAY_COMPONENTS = [`Dialog`, `Drawer`, `AlertDialog`, `Popover`, `Tooltip`, `Menu`, `Toast`];
|
|
1260
|
+
var OVERLAYS = new Set(OVERLAY_COMPONENTS);
|
|
1261
|
+
function submitClosesOverlay2(root, formId) {
|
|
1262
|
+
const walk = (n, overlay) => {
|
|
1263
|
+
const here = OVERLAYS.has(n.component) && n.id !== formId ? n : overlay;
|
|
1264
|
+
if (n.id === formId && n.component === `Form`)
|
|
1265
|
+
return here;
|
|
1266
|
+
for (const slot of Object.values(n.slots ?? {})) {
|
|
1267
|
+
const hit = walk(slot, here);
|
|
1268
|
+
if (hit !== undefined)
|
|
1269
|
+
return hit;
|
|
1270
|
+
}
|
|
1271
|
+
for (const child of n.children) {
|
|
1272
|
+
const hit = walk(child, here);
|
|
1273
|
+
if (hit !== undefined)
|
|
1274
|
+
return hit;
|
|
1275
|
+
}
|
|
1276
|
+
return;
|
|
1277
|
+
};
|
|
1278
|
+
const nearest = walk(root, null);
|
|
1279
|
+
if (!nearest || nearest.component !== `Dialog` && nearest.component !== `Drawer` || nearest.props.dismissible === false)
|
|
1280
|
+
return null;
|
|
1281
|
+
return nearest.id;
|
|
1282
|
+
}
|
|
1283
|
+
function runAction2(action, data, options = {}) {
|
|
1284
|
+
const out = { data };
|
|
1285
|
+
const event = action.event ? { name: action.event.name, ...action.event.context ? { context: resolveDynamic2(action.event.context, data, options) } : {} } : undefined;
|
|
1286
|
+
const fn = action.functionCall;
|
|
1287
|
+
if (fn) {
|
|
1288
|
+
const args = resolveDynamic2(fn.args ?? {}, data, options);
|
|
1289
|
+
if (fn.call === `set`) {
|
|
1290
|
+
if (typeof args.path === `string` && (args.path.startsWith(`/`) || !hasItem2(options.scope))) {
|
|
1291
|
+
const pointer = absolutePath2(args.path, options.scope);
|
|
1292
|
+
const written = writePointer2(data, pointer, args.value === undefined ? null : args.value);
|
|
1293
|
+
const final = args.value === undefined && !written.error ? writePointer2(written.data, pointer, undefined) : written;
|
|
1294
|
+
out.data = final.data;
|
|
1295
|
+
if (final.error)
|
|
1296
|
+
out.error = final.error;
|
|
1297
|
+
}
|
|
1298
|
+
} else
|
|
1299
|
+
out.call = { call: fn.call, args };
|
|
1300
|
+
}
|
|
1301
|
+
if (event)
|
|
1302
|
+
out.event = event;
|
|
1303
|
+
return out;
|
|
1304
|
+
}
|
|
1305
|
+
function isDataSchema2(schema) {
|
|
1306
|
+
if (!schema)
|
|
1307
|
+
return false;
|
|
1308
|
+
if (schema.type === `object`)
|
|
1309
|
+
return schema.shape === undefined;
|
|
1310
|
+
if (schema.type === `array`)
|
|
1311
|
+
return schema.items !== undefined && isDataSchema2(schema.items);
|
|
1312
|
+
return false;
|
|
1313
|
+
}
|
|
1314
|
+
var isObj = (v) => typeof v === `object` && v !== null && !Array.isArray(v);
|
|
1315
|
+
function resolveProp2(value, schema, data, options = {}, defs = {}) {
|
|
1316
|
+
if (isDynamic2(value))
|
|
1317
|
+
return resolveDynamic2(value, data, options);
|
|
1318
|
+
if (isDataSchema2(schema))
|
|
1319
|
+
return value;
|
|
1320
|
+
if (schema?.type === `array` && schema.items && Array.isArray(value))
|
|
1321
|
+
return value.map((item) => resolveProp2(item, schema.items, data, options, defs));
|
|
1322
|
+
const shape = schema?.type === `object` && schema.shape ? defs[schema.shape] : undefined;
|
|
1323
|
+
if (shape && isObj(value)) {
|
|
1324
|
+
const out = {};
|
|
1325
|
+
for (const [k, v] of Object.entries(value)) {
|
|
1326
|
+
const r = resolveProp2(v, shape.properties[k], data, options, defs);
|
|
1327
|
+
if (r !== undefined)
|
|
1328
|
+
out[k] = r;
|
|
1329
|
+
}
|
|
1330
|
+
return out;
|
|
1331
|
+
}
|
|
1332
|
+
return resolveDynamic2(value, data, options);
|
|
1333
|
+
}
|
|
1334
|
+
function resolveNodeProps2(def, props, data, options = {}, defs = {}) {
|
|
1335
|
+
const out = {};
|
|
1336
|
+
for (const [k, v] of Object.entries(props)) {
|
|
1337
|
+
const r = resolveProp2(v, def?.props[k], data, options, defs);
|
|
1338
|
+
if (r !== undefined)
|
|
1339
|
+
out[k] = r;
|
|
1340
|
+
}
|
|
1341
|
+
return out;
|
|
1342
|
+
}
|
|
1343
|
+
function hasRowSlots2(def) {
|
|
1344
|
+
return def?.slotScope === `row`;
|
|
1345
|
+
}
|
|
1346
|
+
function rowScope2(rowsProp, rows, index, scope = {}) {
|
|
1347
|
+
if (isBinding2(rowsProp))
|
|
1348
|
+
return { base: `${absolutePath2(rowsProp.path, scope)}/${index}` };
|
|
1349
|
+
return { ...scope.base !== undefined ? { base: scope.base } : {}, item: rows[index] };
|
|
1350
|
+
}
|
|
1351
|
+
function bindRowSlot2(slot, rowsProp, rows, index, data, options = {}) {
|
|
1352
|
+
return bindTree2(slot, data, { ...options, scope: rowScope2(rowsProp, rows, index, options.scope) });
|
|
1353
|
+
}
|
|
1354
|
+
function sectionScope2(section, index, scope = {}) {
|
|
1355
|
+
return { ...scope.base !== undefined ? { base: scope.base } : {}, item: { value: section.value, count: section.count, index } };
|
|
1356
|
+
}
|
|
1357
|
+
function bindSectionHeader2(slot, section, index, data, options = {}) {
|
|
1358
|
+
return bindTree2(slot, data, { ...options, scope: sectionScope2(section, index, options.scope) });
|
|
1359
|
+
}
|
|
1360
|
+
var viewFor = (extensions) => sharedCatalogView2(extensions);
|
|
1361
|
+
function bindTree2(node, data, options = {}) {
|
|
1362
|
+
const view = viewFor(options.extensions);
|
|
1363
|
+
const walk = (n) => {
|
|
1364
|
+
if (!isVisible2(n.visible, data, options))
|
|
1365
|
+
return null;
|
|
1366
|
+
const def = view.components[n.component];
|
|
1367
|
+
const out = { id: n.id, component: n.component, props: resolveNodeProps2(def, n.props, data, options, view.defs), children: [] };
|
|
1368
|
+
if (n.style)
|
|
1369
|
+
out.style = resolveDynamic2(n.style, data, options);
|
|
1370
|
+
if (n.on)
|
|
1371
|
+
out.on = n.on;
|
|
1372
|
+
if (n.accessibility) {
|
|
1373
|
+
const a11y = resolveDynamic2(n.accessibility, data, options);
|
|
1374
|
+
if (Object.keys(a11y).length > 0)
|
|
1375
|
+
out.accessibility = a11y;
|
|
1376
|
+
}
|
|
1377
|
+
for (const child of n.children) {
|
|
1378
|
+
const bound = walk(child);
|
|
1379
|
+
if (bound)
|
|
1380
|
+
out.children.push(bound);
|
|
1381
|
+
}
|
|
1382
|
+
if (n.slots) {
|
|
1383
|
+
if (hasRowSlots2(def))
|
|
1384
|
+
out.slots = n.slots;
|
|
1385
|
+
else
|
|
1386
|
+
for (const [slot, child] of Object.entries(n.slots)) {
|
|
1387
|
+
const bound = walk(child);
|
|
1388
|
+
if (bound)
|
|
1389
|
+
(out.slots ??= {})[slot] = bound;
|
|
1390
|
+
}
|
|
1391
|
+
}
|
|
1392
|
+
if (n.template)
|
|
1393
|
+
out.template = n.template;
|
|
1394
|
+
if (n.recipe)
|
|
1395
|
+
out.recipe = { ...n.recipe, props: resolveDynamic2(n.recipe.props, data, options) };
|
|
1396
|
+
return out;
|
|
1397
|
+
};
|
|
1398
|
+
return walk(node);
|
|
1399
|
+
}
|
|
1400
|
+
|
|
1401
|
+
// packages/exponential-ui/src/tree-guides.ts
|
|
1402
|
+
function continuesAfter(depths, index, level) {
|
|
1403
|
+
for (let at = index + 1;at < depths.length; at += 1) {
|
|
1404
|
+
const depth = depths[at];
|
|
1405
|
+
if (depth <= level)
|
|
1406
|
+
return false;
|
|
1407
|
+
if (depth === level + 1)
|
|
1408
|
+
return true;
|
|
1409
|
+
}
|
|
1410
|
+
return false;
|
|
1411
|
+
}
|
|
1412
|
+
function treeGuides2(depths) {
|
|
1413
|
+
return depths.map((depth, index) => {
|
|
1414
|
+
if (depth <= 0)
|
|
1415
|
+
return { elbowAt: null, tee: false, passThrough: [] };
|
|
1416
|
+
const passThrough = [];
|
|
1417
|
+
for (let level = 0;level <= depth - 2; level += 1) {
|
|
1418
|
+
if (continuesAfter(depths, index, level))
|
|
1419
|
+
passThrough.push(level);
|
|
1420
|
+
}
|
|
1421
|
+
return { elbowAt: depth - 1, tee: continuesAfter(depths, index, depth - 1), passThrough };
|
|
1422
|
+
});
|
|
1423
|
+
}
|
|
1424
|
+
function isRowRoot2(node) {
|
|
1425
|
+
return node.recipe?.macro === `Row` && node.recipe.part === `root`;
|
|
1426
|
+
}
|
|
1427
|
+
function siblingDepth(node) {
|
|
1428
|
+
const depth = isRowRoot2(node) ? node.recipe?.props.depth : node.props.depth;
|
|
1429
|
+
return typeof depth === `number` && Number.isFinite(depth) && depth > 0 ? Math.floor(depth) : 0;
|
|
1430
|
+
}
|
|
1431
|
+
function hasDepth(node) {
|
|
1432
|
+
return !isRowRoot2(node) && node.component !== `TreeGuides` && typeof node.props.depth === `number`;
|
|
1433
|
+
}
|
|
1434
|
+
function guideProps(depth, g) {
|
|
1435
|
+
const props = { depth };
|
|
1436
|
+
if (g.elbowAt !== null)
|
|
1437
|
+
props.elbowAt = g.elbowAt;
|
|
1438
|
+
props.tee = g.tee;
|
|
1439
|
+
props.passThrough = g.passThrough;
|
|
1440
|
+
return props;
|
|
1441
|
+
}
|
|
1442
|
+
function fillSiblings(nodes) {
|
|
1443
|
+
const depths = nodes.map(siblingDepth);
|
|
1444
|
+
const guides = treeGuides2(depths);
|
|
1445
|
+
nodes.forEach((node, i) => {
|
|
1446
|
+
const g = guides[i];
|
|
1447
|
+
if (isRowRoot2(node)) {
|
|
1448
|
+
const part = guidesPart(node);
|
|
1449
|
+
if (part)
|
|
1450
|
+
part.props = guideProps(depths[i], g);
|
|
1451
|
+
} else if (hasDepth(node)) {
|
|
1452
|
+
const { depth: _d, ...guide } = guideProps(depths[i], g);
|
|
1453
|
+
node.props = { ...node.props, guide };
|
|
1454
|
+
}
|
|
1455
|
+
});
|
|
1456
|
+
}
|
|
1457
|
+
function guidesPart(row) {
|
|
1458
|
+
return row.children.find((c) => c.component === `TreeGuides` && c.recipe?.part === `guides`);
|
|
1459
|
+
}
|
|
1460
|
+
function applyTreeGuides2(root) {
|
|
1461
|
+
const visit = (node) => {
|
|
1462
|
+
fillSiblings(node.children);
|
|
1463
|
+
for (const slot of Object.values(node.slots ?? {})) {
|
|
1464
|
+
fillSiblings([slot]);
|
|
1465
|
+
visit(slot);
|
|
1466
|
+
}
|
|
1467
|
+
node.children.forEach(visit);
|
|
1468
|
+
};
|
|
1469
|
+
fillSiblings([root]);
|
|
1470
|
+
visit(root);
|
|
1471
|
+
return root;
|
|
1472
|
+
}
|
|
1473
|
+
|
|
1474
|
+
// packages/exponential-ui/src/macros.ts
|
|
1475
|
+
var MAX_DEPTH = 16;
|
|
1476
|
+
var BREAKPOINTS2 = TOKEN_GROUPS2.breakpoint;
|
|
1477
|
+
function clone(value) {
|
|
1478
|
+
return value === undefined ? value : JSON.parse(JSON.stringify(value));
|
|
1479
|
+
}
|
|
1480
|
+
var isObj2 = (v) => typeof v === `object` && v !== null && !Array.isArray(v);
|
|
1481
|
+
function isResponsiveValue2(value) {
|
|
1482
|
+
if (!isObj2(value) || !(`base` in value))
|
|
1483
|
+
return false;
|
|
1484
|
+
return Object.keys(value).every((k) => k === `base` || BREAKPOINTS2.includes(k));
|
|
1485
|
+
}
|
|
1486
|
+
function responsiveAt2(value, breakpoint) {
|
|
1487
|
+
let out = value.base;
|
|
1488
|
+
if (breakpoint === null)
|
|
1489
|
+
return out;
|
|
1490
|
+
for (const bp of BREAKPOINTS2) {
|
|
1491
|
+
if (bp in value)
|
|
1492
|
+
out = value[bp];
|
|
1493
|
+
if (bp === breakpoint)
|
|
1494
|
+
break;
|
|
1495
|
+
}
|
|
1496
|
+
return out;
|
|
1497
|
+
}
|
|
1498
|
+
function propsAt2(props, breakpoint) {
|
|
1499
|
+
const out = {};
|
|
1500
|
+
for (const [k, v] of Object.entries(props))
|
|
1501
|
+
out[k] = isResponsiveValue2(v) ? responsiveAt2(v, breakpoint) : v;
|
|
1502
|
+
return out;
|
|
1503
|
+
}
|
|
1504
|
+
function responsiveVariants(props) {
|
|
1505
|
+
const used = new Set;
|
|
1506
|
+
for (const v of Object.values(props))
|
|
1507
|
+
if (isResponsiveValue2(v)) {
|
|
1508
|
+
for (const k of Object.keys(v))
|
|
1509
|
+
if (k !== `base`)
|
|
1510
|
+
used.add(k);
|
|
1511
|
+
}
|
|
1512
|
+
return BREAKPOINTS2.filter((bp) => used.has(bp)).map((bp) => ({ breakpoint: bp, props: propsAt2(props, bp) }));
|
|
1513
|
+
}
|
|
1514
|
+
function mergeStyle(base, over) {
|
|
1515
|
+
if (!base && !over)
|
|
1516
|
+
return;
|
|
1517
|
+
const out = { ...base ?? {} };
|
|
1518
|
+
for (const [k, v] of Object.entries(over ?? {})) {
|
|
1519
|
+
const nested = typeof v === `object` && v !== null && !Array.isArray(v);
|
|
1520
|
+
out[k] = nested ? { ...out[k] ?? {}, ...v } : v;
|
|
1521
|
+
}
|
|
1522
|
+
return out;
|
|
1523
|
+
}
|
|
1524
|
+
function routedAction(action, context) {
|
|
1525
|
+
const out = clone(action);
|
|
1526
|
+
if (context && out.event) {
|
|
1527
|
+
out.event.context = { ...out.event.context ?? {}, ...context };
|
|
1528
|
+
}
|
|
1529
|
+
return out;
|
|
1530
|
+
}
|
|
1531
|
+
function recipeProps(exp, ctx, extra) {
|
|
1532
|
+
const props = {};
|
|
1533
|
+
const schema = exp.view.components[exp.macro]?.props ?? {};
|
|
1534
|
+
for (const name of exp.def.recipeProps) {
|
|
1535
|
+
const value = exp.baseProps[name] ?? schema[name]?.default;
|
|
1536
|
+
if (value !== undefined)
|
|
1537
|
+
props[name] = value;
|
|
1538
|
+
}
|
|
1539
|
+
if (extra) {
|
|
1540
|
+
const evaluated = evalValue2(extra, ctx);
|
|
1541
|
+
for (const [k, v] of Object.entries(evaluated))
|
|
1542
|
+
props[k] = v;
|
|
1543
|
+
}
|
|
1544
|
+
return props;
|
|
1545
|
+
}
|
|
1546
|
+
function andOf(conditions, op) {
|
|
1547
|
+
if (conditions.length === 1)
|
|
1548
|
+
return conditions[0];
|
|
1549
|
+
return { call: op, args: { values: conditions } };
|
|
1550
|
+
}
|
|
1551
|
+
function decideConditions(tpl, ctx) {
|
|
1552
|
+
const bound = [];
|
|
1553
|
+
if (tpl.$if !== undefined) {
|
|
1554
|
+
const conds = Array.isArray(tpl.$if) ? tpl.$if : [tpl.$if];
|
|
1555
|
+
for (const c of conds) {
|
|
1556
|
+
const r = evalConditionValue2(c, ctx);
|
|
1557
|
+
if (r === false)
|
|
1558
|
+
return false;
|
|
1559
|
+
if (r !== true)
|
|
1560
|
+
bound.push(r);
|
|
1561
|
+
}
|
|
1562
|
+
}
|
|
1563
|
+
if (tpl.$any !== undefined) {
|
|
1564
|
+
let decided = false;
|
|
1565
|
+
const any = [];
|
|
1566
|
+
for (const c of tpl.$any) {
|
|
1567
|
+
const r = evalConditionValue2(c, ctx);
|
|
1568
|
+
if (r === true) {
|
|
1569
|
+
decided = true;
|
|
1570
|
+
break;
|
|
1571
|
+
}
|
|
1572
|
+
if (r !== false)
|
|
1573
|
+
any.push(r);
|
|
1574
|
+
}
|
|
1575
|
+
if (!decided) {
|
|
1576
|
+
if (any.length === 0)
|
|
1577
|
+
return false;
|
|
1578
|
+
bound.push(andOf(any, `or`));
|
|
1579
|
+
}
|
|
1580
|
+
}
|
|
1581
|
+
return bound.length === 0 ? true : andOf(bound, `and`);
|
|
1582
|
+
}
|
|
1583
|
+
function expandTemplate(tpl, exp, ctx, parentId) {
|
|
1584
|
+
const decided = decideConditions(tpl, ctx);
|
|
1585
|
+
if (decided === false)
|
|
1586
|
+
return [];
|
|
1587
|
+
const visible = decided === true ? undefined : decided;
|
|
1588
|
+
if (tpl.$each !== undefined) {
|
|
1589
|
+
const items = evalValue2(`{${tpl.$each}}`, ctx);
|
|
1590
|
+
if (!Array.isArray(items))
|
|
1591
|
+
return [];
|
|
1592
|
+
const as = tpl.$as ?? `item`;
|
|
1593
|
+
return items.map((item, index) => buildNode(tpl, exp, { ...ctx, vars: { ...ctx.vars, [as]: item, index } }, `${parentId}.${tpl.part}.${index}`, visible));
|
|
1594
|
+
}
|
|
1595
|
+
const id = tpl.part === `root` ? exp.source.id : `${parentId}.${tpl.part}`;
|
|
1596
|
+
return [buildNode(tpl, exp, ctx, id, visible)];
|
|
1597
|
+
}
|
|
1598
|
+
var canon = (v) => JSON.stringify(v);
|
|
1599
|
+
function partStyle(tpl, exp, ctx) {
|
|
1600
|
+
if (!tpl.style)
|
|
1601
|
+
return;
|
|
1602
|
+
const style = evalValue2(tpl.style, ctx);
|
|
1603
|
+
let previous = style;
|
|
1604
|
+
for (const variant of exp.variants) {
|
|
1605
|
+
const at = evalValue2(tpl.style, { ...ctx, props: variant.props });
|
|
1606
|
+
const diff = {};
|
|
1607
|
+
for (const [k, v] of Object.entries(at))
|
|
1608
|
+
if (!k.startsWith(`@`) && !k.startsWith(`:`) && canon(previous[k]) !== canon(v))
|
|
1609
|
+
diff[k] = v;
|
|
1610
|
+
if (Object.keys(diff).length > 0) {
|
|
1611
|
+
const key = `@media (min-width: $breakpoint.${variant.breakpoint})`;
|
|
1612
|
+
style[key] = { ...style[key] ?? {}, ...diff };
|
|
1613
|
+
}
|
|
1614
|
+
previous = at;
|
|
1615
|
+
}
|
|
1616
|
+
return Object.keys(style).length > 0 ? style : undefined;
|
|
1617
|
+
}
|
|
1618
|
+
function buildNode(tpl, exp, ctx, id, visible) {
|
|
1619
|
+
const props = evalValue2(tpl.props ?? {}, ctx) ?? {};
|
|
1620
|
+
const style = partStyle(tpl, exp, ctx);
|
|
1621
|
+
const node = { id, component: tpl.component, props, children: [] };
|
|
1622
|
+
if (style)
|
|
1623
|
+
node.style = style;
|
|
1624
|
+
if (visible !== undefined)
|
|
1625
|
+
node.visible = visible;
|
|
1626
|
+
node.recipe = { macro: exp.macro, part: tpl.part, props: recipeProps(exp, ctx, tpl.$recipe) };
|
|
1627
|
+
if (tpl.$on) {
|
|
1628
|
+
const on = {};
|
|
1629
|
+
for (const [partEvent, macroEvent] of Object.entries(tpl.$on)) {
|
|
1630
|
+
const action = exp.source.on?.[macroEvent];
|
|
1631
|
+
if (!action)
|
|
1632
|
+
continue;
|
|
1633
|
+
exp.claimed.add(macroEvent);
|
|
1634
|
+
const context = tpl.$context ? evalValue2(tpl.$context, ctx) : undefined;
|
|
1635
|
+
on[partEvent] = routedAction(action, context);
|
|
1636
|
+
}
|
|
1637
|
+
if (Object.keys(on).length > 0)
|
|
1638
|
+
node.on = on;
|
|
1639
|
+
}
|
|
1640
|
+
if (tpl.$set) {
|
|
1641
|
+
for (const [partEvent, spec] of Object.entries(tpl.$set)) {
|
|
1642
|
+
const bound = exp.baseProps[spec.prop];
|
|
1643
|
+
if (!isBinding2(bound))
|
|
1644
|
+
continue;
|
|
1645
|
+
const on = node.on ??= {};
|
|
1646
|
+
if (on[partEvent]?.functionCall) {
|
|
1647
|
+
const macroEvent = tpl.$on?.[partEvent] ?? partEvent;
|
|
1648
|
+
const message = `on.${macroEvent}: a function action replaces the two-way set of props.${spec.prop}; write it in that function's handler or use an event`;
|
|
1649
|
+
if (!exp.issues?.some((i) => i.id === exp.source.id && i.message === message))
|
|
1650
|
+
exp.issues?.push({ id: exp.source.id, message });
|
|
1651
|
+
continue;
|
|
1652
|
+
}
|
|
1653
|
+
const value = evalValue2(spec.value, ctx);
|
|
1654
|
+
on[partEvent] = { ...on[partEvent] ?? {}, functionCall: { call: `set`, args: value === undefined ? { path: bound.path } : { path: bound.path, value } } };
|
|
1655
|
+
}
|
|
1656
|
+
}
|
|
1657
|
+
if (tpl.$a11y) {
|
|
1658
|
+
const a11y = evalValue2(tpl.$a11y, ctx);
|
|
1659
|
+
if (Object.keys(a11y).length > 0)
|
|
1660
|
+
node.accessibility = a11y;
|
|
1661
|
+
}
|
|
1662
|
+
if (tpl.slots) {
|
|
1663
|
+
for (const [slot, ref] of Object.entries(tpl.slots)) {
|
|
1664
|
+
if (typeof ref === `string`) {
|
|
1665
|
+
const name = ref.startsWith(`$slot:`) ? ref.slice(6) : null;
|
|
1666
|
+
const value = name ? exp.source.slots?.[name] : undefined;
|
|
1667
|
+
if (value)
|
|
1668
|
+
(node.slots ??= {})[slot] = value;
|
|
1669
|
+
continue;
|
|
1670
|
+
}
|
|
1671
|
+
const [built] = expandTemplate(ref, exp, ctx, id);
|
|
1672
|
+
if (built)
|
|
1673
|
+
(node.slots ??= {})[slot] = built;
|
|
1674
|
+
}
|
|
1675
|
+
}
|
|
1676
|
+
for (const child of tpl.children ?? []) {
|
|
1677
|
+
if (child === `$children`) {
|
|
1678
|
+
node.children.push(...exp.source.children);
|
|
1679
|
+
if (exp.source.template)
|
|
1680
|
+
node.template = exp.source.template;
|
|
1681
|
+
continue;
|
|
1682
|
+
}
|
|
1683
|
+
if (typeof child === `string`) {
|
|
1684
|
+
if (child.startsWith(`$slot:`)) {
|
|
1685
|
+
const value = exp.source.slots?.[child.slice(6)];
|
|
1686
|
+
if (value)
|
|
1687
|
+
node.children.push(value);
|
|
1688
|
+
}
|
|
1689
|
+
continue;
|
|
1690
|
+
}
|
|
1691
|
+
node.children.push(...expandTemplate(child, exp, ctx, id));
|
|
1692
|
+
}
|
|
1693
|
+
return node;
|
|
1694
|
+
}
|
|
1695
|
+
function expandMacro(node, macro, def, view, depth, issues) {
|
|
1696
|
+
if (depth > MAX_DEPTH)
|
|
1697
|
+
throw new Error(`macro ${macro}: expansion deeper than ${MAX_DEPTH}`);
|
|
1698
|
+
const baseProps = propsAt2(node.props, null);
|
|
1699
|
+
if (node.on?.press && baseProps.pressable === undefined && view.components[macro]?.props.pressable)
|
|
1700
|
+
baseProps.pressable = true;
|
|
1701
|
+
const exp = { view, macro, def, source: node, baseProps, variants: responsiveVariants(node.props), claimed: new Set, issues };
|
|
1702
|
+
const ctx = { id: node.id, props: baseProps, vars: {} };
|
|
1703
|
+
const [root] = expandTemplate(def.root, exp, ctx, node.id);
|
|
1704
|
+
root.style = mergeStyle(root.style, node.style);
|
|
1705
|
+
if (root.style && Object.keys(root.style).length === 0)
|
|
1706
|
+
delete root.style;
|
|
1707
|
+
if (node.visible !== undefined)
|
|
1708
|
+
root.visible = node.visible;
|
|
1709
|
+
if (node.accessibility)
|
|
1710
|
+
root.accessibility = { ...root.accessibility ?? {}, ...node.accessibility };
|
|
1711
|
+
const remaining = { ...root.on ?? {} };
|
|
1712
|
+
for (const [event, action] of Object.entries(node.on ?? {})) {
|
|
1713
|
+
if (!exp.claimed.has(event))
|
|
1714
|
+
remaining[event] = action;
|
|
1715
|
+
}
|
|
1716
|
+
if (Object.keys(remaining).length > 0)
|
|
1717
|
+
root.on = remaining;
|
|
1718
|
+
else
|
|
1719
|
+
delete root.on;
|
|
1720
|
+
return expandTree(root, view, depth + 1, issues);
|
|
1721
|
+
}
|
|
1722
|
+
function expandTree(node, view, depth, issues) {
|
|
1723
|
+
const out = { ...node, children: node.children.map((c) => expandTree(c, view, depth, issues)) };
|
|
1724
|
+
if (node.slots) {
|
|
1725
|
+
out.slots = {};
|
|
1726
|
+
for (const [slot, child] of Object.entries(node.slots))
|
|
1727
|
+
out.slots[slot] = expandTree(child, view, depth, issues);
|
|
1728
|
+
}
|
|
1729
|
+
const def = view.macros[out.component];
|
|
1730
|
+
if (def && view.components[out.component]?.kind === `macro`) {
|
|
1731
|
+
return expandMacro(out, out.component, def, view, depth, issues);
|
|
1732
|
+
}
|
|
1733
|
+
return out;
|
|
1734
|
+
}
|
|
1735
|
+
function expandMacros2(root, options = {}) {
|
|
1736
|
+
return applyTreeGuides2(expandTree(clone(root), sharedCatalogView2(options.extensions), 0, options.issues));
|
|
1737
|
+
}
|
|
1738
|
+
|
|
1739
|
+
// packages/exponential-ui/src/validate.ts
|
|
1740
|
+
var ICONS = new Set(ICON_NAMES2);
|
|
1741
|
+
var viewOf = (extensions) => sharedCatalogView2(extensions);
|
|
1742
|
+
var FUNCTIONS = new Set(FUNCTION_NAMES2);
|
|
1743
|
+
var ISO_DATE = /^\d{4}-\d{2}-\d{2}$/;
|
|
1744
|
+
function checkScalar(schema, value, path, view, issues) {
|
|
1745
|
+
switch (schema.type) {
|
|
1746
|
+
case `string`:
|
|
1747
|
+
case `markdown`:
|
|
1748
|
+
case `url`:
|
|
1749
|
+
if (typeof value !== `string`)
|
|
1750
|
+
issues.push({ path, message: `expected a string` });
|
|
1751
|
+
else if (parseStringRef2(value) !== null && !isStringRef2(value))
|
|
1752
|
+
issues.push({ path, message: `unknown built-in string ${value} (catalog/strings.json)` });
|
|
1753
|
+
return;
|
|
1754
|
+
case `date`:
|
|
1755
|
+
if (typeof value !== `string` || value !== `` && !ISO_DATE.test(value))
|
|
1756
|
+
issues.push({ path, message: `expected yyyy-mm-dd` });
|
|
1757
|
+
return;
|
|
1758
|
+
case `number`:
|
|
1759
|
+
if (typeof value !== `number` || !Number.isFinite(value))
|
|
1760
|
+
issues.push({ path, message: `expected a number` });
|
|
1761
|
+
else if (schema.minimum !== undefined && value < schema.minimum)
|
|
1762
|
+
issues.push({ path, message: `expected at least ${schema.minimum}` });
|
|
1763
|
+
else if (schema.maximum !== undefined && value > schema.maximum)
|
|
1764
|
+
issues.push({ path, message: `expected at most ${schema.maximum}` });
|
|
1765
|
+
return;
|
|
1766
|
+
case `boolean`:
|
|
1767
|
+
if (typeof value !== `boolean`)
|
|
1768
|
+
issues.push({ path, message: `expected a boolean` });
|
|
1769
|
+
return;
|
|
1770
|
+
case `enum`: {
|
|
1771
|
+
const values = schema.values ?? (schema.enum ? view.enums[schema.enum] : undefined);
|
|
1772
|
+
if (!values)
|
|
1773
|
+
issues.push({ path, message: `enum ${schema.enum} is not defined` });
|
|
1774
|
+
else if (!values.includes(value))
|
|
1775
|
+
issues.push({ path, message: `expected one of ${values.join(`|`)}` });
|
|
1776
|
+
return;
|
|
1777
|
+
}
|
|
1778
|
+
case `icon`:
|
|
1779
|
+
if (typeof value !== `string` || !ICONS.has(value))
|
|
1780
|
+
issues.push({ path, message: `not an icons.json name` });
|
|
1781
|
+
return;
|
|
1782
|
+
case `color`:
|
|
1783
|
+
if (isKnownToken2(value) && parseTokenRef2(value)?.group === `color`)
|
|
1784
|
+
return;
|
|
1785
|
+
issues.push({ path, message: `expected $color.<name>` });
|
|
1786
|
+
return;
|
|
1787
|
+
case `style`:
|
|
1788
|
+
for (const issue of validateStyle2(value, { path, root: false }))
|
|
1789
|
+
issues.push(issue);
|
|
1790
|
+
return;
|
|
1791
|
+
case `array`:
|
|
1792
|
+
if (!Array.isArray(value)) {
|
|
1793
|
+
issues.push({ path, message: `expected an array` });
|
|
1794
|
+
return;
|
|
1795
|
+
}
|
|
1796
|
+
if (schema.items)
|
|
1797
|
+
value.forEach((item, i) => checkValue(schema.items, item, `${path}[${i}]`, view, issues));
|
|
1798
|
+
return;
|
|
1799
|
+
case `object`: {
|
|
1800
|
+
if (typeof value !== `object` || value === null || Array.isArray(value)) {
|
|
1801
|
+
issues.push({ path, message: `expected an object` });
|
|
1802
|
+
return;
|
|
1803
|
+
}
|
|
1804
|
+
if (!schema.shape)
|
|
1805
|
+
return;
|
|
1806
|
+
const def = view.defs[schema.shape];
|
|
1807
|
+
if (!def) {
|
|
1808
|
+
issues.push({ path, message: `shape ${schema.shape} is not defined` });
|
|
1809
|
+
return;
|
|
1810
|
+
}
|
|
1811
|
+
checkProps(def.properties, value, path, view, issues);
|
|
1812
|
+
return;
|
|
1813
|
+
}
|
|
1814
|
+
}
|
|
1815
|
+
}
|
|
1816
|
+
function checkValue(schema, value, path, view, issues) {
|
|
1817
|
+
if (schema.bindable && isDynamic2(value))
|
|
1818
|
+
return;
|
|
1819
|
+
if (schema.responsive && isResponsiveValue2(value)) {
|
|
1820
|
+
for (const [bp, v] of Object.entries(value))
|
|
1821
|
+
checkScalar(schema, v, `${path}.${bp}`, view, issues);
|
|
1822
|
+
return;
|
|
1823
|
+
}
|
|
1824
|
+
if (schema.responsive && typeof value === `object` && value !== null && !Array.isArray(value) && !isDynamic2(value)) {
|
|
1825
|
+
issues.push({ path, message: `a responsive value needs base and only ${BREAKPOINTS2.join(`|`)} besides` });
|
|
1826
|
+
return;
|
|
1827
|
+
}
|
|
1828
|
+
checkScalar(schema, value, path, view, issues);
|
|
1829
|
+
}
|
|
1830
|
+
function checkProps(schemas, props, path, view, issues) {
|
|
1831
|
+
for (const [name, schema] of Object.entries(schemas)) {
|
|
1832
|
+
const value = props[name];
|
|
1833
|
+
if (value === undefined || value === null) {
|
|
1834
|
+
if (schema.required)
|
|
1835
|
+
issues.push({ path: `${path}.${name}`, message: `required` });
|
|
1836
|
+
continue;
|
|
1837
|
+
}
|
|
1838
|
+
checkValue(schema, value, `${path}.${name}`, view, issues);
|
|
1839
|
+
}
|
|
1840
|
+
for (const name of Object.keys(props)) {
|
|
1841
|
+
if (!(name in schemas))
|
|
1842
|
+
issues.push({ path: `${path}.${name}`, message: `unknown prop` });
|
|
1843
|
+
}
|
|
1844
|
+
}
|
|
1845
|
+
function isCallableName2(name) {
|
|
1846
|
+
return FUNCTIONS.has(name) || /^[A-Za-z_][\w-]*(\.[A-Za-z_][\w-]*)+$/.test(name);
|
|
1847
|
+
}
|
|
1848
|
+
function checkCall(value, path, issues) {
|
|
1849
|
+
if (!isCallableName2(value.call))
|
|
1850
|
+
issues.push({ path, message: `unknown function "${value.call}"; known: the catalog functions, or a namespaced host function (app.toast)` });
|
|
1851
|
+
}
|
|
1852
|
+
function checkCallsDeep(value, path, issues) {
|
|
1853
|
+
if (Array.isArray(value)) {
|
|
1854
|
+
value.forEach((v, i) => checkCallsDeep(v, `${path}[${i}]`, issues));
|
|
1855
|
+
return;
|
|
1856
|
+
}
|
|
1857
|
+
if (typeof value !== `object` || value === null)
|
|
1858
|
+
return;
|
|
1859
|
+
if (isCall2(value))
|
|
1860
|
+
checkCall(value, path, issues);
|
|
1861
|
+
for (const [k, v] of Object.entries(value))
|
|
1862
|
+
checkCallsDeep(v, `${path}.${k}`, issues);
|
|
1863
|
+
}
|
|
1864
|
+
function checkPropCalls(value, schema, path, view, issues) {
|
|
1865
|
+
if (isCall2(value)) {
|
|
1866
|
+
checkCall(value, path, issues);
|
|
1867
|
+
checkCallsDeep(value.args, `${path}.args`, issues);
|
|
1868
|
+
return;
|
|
1869
|
+
}
|
|
1870
|
+
if (!schema || isDataSchema2(schema))
|
|
1871
|
+
return;
|
|
1872
|
+
if (schema.type === `style`)
|
|
1873
|
+
return checkCallsDeep(value, path, issues);
|
|
1874
|
+
if (schema.type === `array` && schema.items && Array.isArray(value)) {
|
|
1875
|
+
value.forEach((item, i) => checkPropCalls(item, schema.items, `${path}[${i}]`, view, issues));
|
|
1876
|
+
return;
|
|
1877
|
+
}
|
|
1878
|
+
const shape = schema.type === `object` && schema.shape ? view.defs[schema.shape] : undefined;
|
|
1879
|
+
if (shape && typeof value === `object` && value !== null && !Array.isArray(value))
|
|
1880
|
+
for (const [k, v] of Object.entries(value))
|
|
1881
|
+
checkPropCalls(v, shape.properties[k], `${path}.${k}`, view, issues);
|
|
1882
|
+
}
|
|
1883
|
+
function checkActionCalls(action, path, issues) {
|
|
1884
|
+
if (typeof action !== `object` || action === null)
|
|
1885
|
+
return;
|
|
1886
|
+
const { functionCall, event } = action;
|
|
1887
|
+
if (isCall2(functionCall)) {
|
|
1888
|
+
checkCall(functionCall, `${path}.functionCall`, issues);
|
|
1889
|
+
checkCallsDeep(functionCall.args, `${path}.functionCall.args`, issues);
|
|
1890
|
+
}
|
|
1891
|
+
if (typeof event === `object` && event !== null)
|
|
1892
|
+
checkCallsDeep(event.context, `${path}.event.context`, issues);
|
|
1893
|
+
}
|
|
1894
|
+
function validateNode2(node, options = {}) {
|
|
1895
|
+
const issues = [];
|
|
1896
|
+
const view = viewOf(options.extensions);
|
|
1897
|
+
const def = view.components[node.component];
|
|
1898
|
+
if (node.style !== undefined)
|
|
1899
|
+
for (const issue of validateStyle2(node.style, { path: `style` }))
|
|
1900
|
+
issues.push(issue);
|
|
1901
|
+
for (const [k, v] of Object.entries(node.props))
|
|
1902
|
+
checkPropCalls(v, def?.props[k], `props.${k}`, view, issues);
|
|
1903
|
+
if (node.visible !== undefined)
|
|
1904
|
+
checkCallsDeep(node.visible, `visible`, issues);
|
|
1905
|
+
for (const [event, action] of Object.entries(node.on ?? {}))
|
|
1906
|
+
checkActionCalls(action, `on.${event}`, issues);
|
|
1907
|
+
if (node.component === `Table` && Array.isArray(node.props.columns)) {
|
|
1908
|
+
const slots = Object.keys(node.slots ?? {});
|
|
1909
|
+
node.props.columns.forEach((column, i) => {
|
|
1910
|
+
if (typeof column !== `object` || column === null || column.type !== `slot`)
|
|
1911
|
+
return;
|
|
1912
|
+
const slot = column.slot;
|
|
1913
|
+
if (typeof slot !== `string`)
|
|
1914
|
+
issues.push({ path: `props.columns[${i}].slot`, message: `a slot column names one of the Table's slots` });
|
|
1915
|
+
else if (!slots.includes(slot))
|
|
1916
|
+
issues.push({ path: `props.columns[${i}].slot`, message: `no slot "${slot}" on this Table; slots: ${slots.join(`|`) || `none`}` });
|
|
1917
|
+
});
|
|
1918
|
+
}
|
|
1919
|
+
return issues;
|
|
1920
|
+
}
|
|
1921
|
+
function validateProps2(def, props, options = {}) {
|
|
1922
|
+
const issues = [];
|
|
1923
|
+
checkProps(def.props, props, options.path ?? `props`, viewOf(options.extensions), issues);
|
|
1924
|
+
return issues;
|
|
1925
|
+
}
|
|
1926
|
+
|
|
1927
|
+
// packages/exponential-ui/src/basic-map.ts
|
|
1928
|
+
var basicMap2 = basic_map_default;
|
|
1929
|
+
function mapBasicIcon2(name) {
|
|
1930
|
+
if (typeof name !== `string`)
|
|
1931
|
+
return basicMap2.placeholderIcon;
|
|
1932
|
+
return (own2(basicMap2.icons, name) ? basicMap2.icons[name] : undefined) ?? basicMap2.placeholderIcon;
|
|
1933
|
+
}
|
|
1934
|
+
function isBinding(value) {
|
|
1935
|
+
return typeof value === `object` && value !== null && typeof value.path === `string`;
|
|
1936
|
+
}
|
|
1937
|
+
var transforms = {
|
|
1938
|
+
textVariant(out, flat) {
|
|
1939
|
+
const variant = flat.variant;
|
|
1940
|
+
if (variant === `h1` || variant === `h2` || variant === `h3` || variant === `h4`) {
|
|
1941
|
+
out.component = `Heading`;
|
|
1942
|
+
out.props = { text: out.props.text, level: variant };
|
|
1943
|
+
return;
|
|
1944
|
+
}
|
|
1945
|
+
out.props.variant = variant === `h5` ? `label` : variant === `caption` ? `caption` : `body`;
|
|
1946
|
+
},
|
|
1947
|
+
imageVariant(out, flat) {
|
|
1948
|
+
const variant = flat.variant ?? `mediumFeature`;
|
|
1949
|
+
if (variant === `avatar`) {
|
|
1950
|
+
out.component = `Avatar`;
|
|
1951
|
+
out.props = { src: out.props.src, name: flat.description ?? `` };
|
|
1952
|
+
return;
|
|
1953
|
+
}
|
|
1954
|
+
const style = variant === `icon` ? { width: 24, height: 24 } : variant === `smallFeature` ? { width: 120, height: 120 } : variant === `header` ? { width: `100%`, aspectRatio: 3 } : { width: `100%`, aspectRatio: 1.7777778 };
|
|
1955
|
+
out.style = { ...out.style ?? {}, ...style };
|
|
1956
|
+
},
|
|
1957
|
+
iconName(out, flat) {
|
|
1958
|
+
out.props.name = mapBasicIcon2(flat.name);
|
|
1959
|
+
},
|
|
1960
|
+
tabs(out, flat) {
|
|
1961
|
+
const tabs = Array.isArray(flat.tabs) ? flat.tabs : [];
|
|
1962
|
+
out.props.tabs = tabs.map((tab) => ({ label: tab.title, value: tab.child }));
|
|
1963
|
+
out.childrenIds = tabs.map((tab) => tab.child);
|
|
1964
|
+
if (tabs.length > 0)
|
|
1965
|
+
out.props.value = tabs[0].child;
|
|
1966
|
+
},
|
|
1967
|
+
modal(out, flat) {
|
|
1968
|
+
if (typeof flat.trigger === `string`)
|
|
1969
|
+
out.slots.trigger = flat.trigger;
|
|
1970
|
+
if (typeof flat.content === `string`)
|
|
1971
|
+
out.childrenIds = [flat.content];
|
|
1972
|
+
out.props.open = false;
|
|
1973
|
+
},
|
|
1974
|
+
buttonChild(out, flat, lookup) {
|
|
1975
|
+
const childId = typeof flat.child === `string` ? flat.child : undefined;
|
|
1976
|
+
const child = childId ? lookup(childId) : undefined;
|
|
1977
|
+
if (child?.component === `Text`)
|
|
1978
|
+
out.props.label = child.text;
|
|
1979
|
+
else if (child?.component === `Icon`)
|
|
1980
|
+
out.props.icon = mapBasicIcon2(child.name);
|
|
1981
|
+
else if (childId)
|
|
1982
|
+
out.childrenIds = [childId];
|
|
1983
|
+
if (out.props.icon !== undefined && out.props.label === undefined)
|
|
1984
|
+
out.props.size = `icon`;
|
|
1985
|
+
if (flat.action !== undefined)
|
|
1986
|
+
out.on = { press: flat.action };
|
|
1987
|
+
},
|
|
1988
|
+
textField(out, flat) {
|
|
1989
|
+
out.props.name = flat.id;
|
|
1990
|
+
const variant = flat.variant ?? `shortText`;
|
|
1991
|
+
if (variant === `longText`)
|
|
1992
|
+
out.component = `Textarea`;
|
|
1993
|
+
else
|
|
1994
|
+
out.props.type = variant === `number` ? `number` : variant === `obscured` ? `password` : `text`;
|
|
1995
|
+
if (typeof flat.validationRegexp === `string`) {
|
|
1996
|
+
const value = isBinding(flat.value) ? flat.value.path : flat.id;
|
|
1997
|
+
const checks = Array.isArray(out.props.checks) ? [...out.props.checks] : [];
|
|
1998
|
+
checks.push({
|
|
1999
|
+
condition: { call: `regex`, args: { value: { path: value }, pattern: flat.validationRegexp } },
|
|
2000
|
+
message: `Invalid value`
|
|
2001
|
+
});
|
|
2002
|
+
out.props.checks = checks;
|
|
2003
|
+
}
|
|
2004
|
+
},
|
|
2005
|
+
fieldName(out, flat) {
|
|
2006
|
+
out.props.name = flat.id;
|
|
2007
|
+
},
|
|
2008
|
+
choicePicker(out, flat) {
|
|
2009
|
+
out.props.name = flat.id;
|
|
2010
|
+
const multiple = flat.variant === `multipleSelection`;
|
|
2011
|
+
const value = flat.value;
|
|
2012
|
+
const joined = Array.isArray(value) ? multiple ? value.join(`,`) : value[0] ?? `` : value;
|
|
2013
|
+
if (joined !== undefined)
|
|
2014
|
+
out.props.value = joined;
|
|
2015
|
+
if (flat.filterable === true) {
|
|
2016
|
+
out.component = `Select`;
|
|
2017
|
+
out.props.searchable = true;
|
|
2018
|
+
out.props.multiple = multiple;
|
|
2019
|
+
} else if (flat.displayStyle === `chips`) {
|
|
2020
|
+
out.component = `Segmented`;
|
|
2021
|
+
out.props = { items: out.props.options, type: multiple ? `multiple` : `single`, variant: `outline`, value: out.props.value };
|
|
2022
|
+
} else if (multiple) {
|
|
2023
|
+
out.component = `Select`;
|
|
2024
|
+
out.props.multiple = true;
|
|
2025
|
+
}
|
|
2026
|
+
}
|
|
2027
|
+
};
|
|
2028
|
+
function own2(table, key) {
|
|
2029
|
+
return Object.prototype.hasOwnProperty.call(table, key);
|
|
2030
|
+
}
|
|
2031
|
+
function mapBasicComponent2(flat, lookup) {
|
|
2032
|
+
const rule = own2(basicMap2.components, flat.component) ? basicMap2.components[flat.component] : undefined;
|
|
2033
|
+
if (!rule)
|
|
2034
|
+
return null;
|
|
2035
|
+
const props = {};
|
|
2036
|
+
for (const [coreProp, spec] of Object.entries(rule.props)) {
|
|
2037
|
+
if (typeof spec === `string`) {
|
|
2038
|
+
if (flat[spec] !== undefined)
|
|
2039
|
+
props[coreProp] = flat[spec];
|
|
2040
|
+
continue;
|
|
2041
|
+
}
|
|
2042
|
+
if (`const` in spec) {
|
|
2043
|
+
props[coreProp] = spec.const;
|
|
2044
|
+
continue;
|
|
2045
|
+
}
|
|
2046
|
+
let value = spec.from !== undefined ? flat[spec.from] : undefined;
|
|
2047
|
+
if (spec.map && typeof value === `string` && own2(spec.map, value))
|
|
2048
|
+
value = spec.map[value];
|
|
2049
|
+
if (value === undefined && spec.default !== undefined)
|
|
2050
|
+
value = spec.default;
|
|
2051
|
+
if (value !== undefined)
|
|
2052
|
+
props[coreProp] = value;
|
|
2053
|
+
}
|
|
2054
|
+
const out = { component: rule.to, props, childrenIds: [], slots: {} };
|
|
2055
|
+
if (rule.children === `children`) {
|
|
2056
|
+
const children = flat.children;
|
|
2057
|
+
if (Array.isArray(children))
|
|
2058
|
+
out.childrenIds = children;
|
|
2059
|
+
else if (children && typeof children === `object`)
|
|
2060
|
+
out.template = { component: children.componentId, path: children.path, ...typeof children.key === `string` ? { key: children.key } : {} };
|
|
2061
|
+
} else if (rule.children === `child` && typeof flat.child === `string`) {
|
|
2062
|
+
out.childrenIds = [flat.child];
|
|
2063
|
+
}
|
|
2064
|
+
if (rule.transform) {
|
|
2065
|
+
const fn = transforms[rule.transform];
|
|
2066
|
+
if (!fn)
|
|
2067
|
+
throw new Error(`basic-map.json names an unimplemented transform: ${rule.transform}`);
|
|
2068
|
+
fn(out, flat, lookup);
|
|
2069
|
+
}
|
|
2070
|
+
return out;
|
|
2071
|
+
}
|
|
2072
|
+
var BASIC_TRANSFORM_NAMES2 = Object.keys(transforms);
|
|
2073
|
+
|
|
2074
|
+
// packages/exponential-ui/src/reducer.ts
|
|
2075
|
+
var RESERVED_KEYS2 = [`id`, `component`, `children`, `slots`, `on`, `style`, `visible`, `accessibility`, `template`];
|
|
2076
|
+
var RESERVED = new Set(RESERVED_KEYS2);
|
|
2077
|
+
function liftTemplates(root, issues, buildMissing) {
|
|
2078
|
+
const order = [];
|
|
2079
|
+
const want = new Set;
|
|
2080
|
+
const found = new Map;
|
|
2081
|
+
const missing = new Set;
|
|
2082
|
+
let rootNamed = false;
|
|
2083
|
+
const originals = new Map;
|
|
2084
|
+
const collect = (n) => {
|
|
2085
|
+
const id = n.template?.component;
|
|
2086
|
+
if (id === root.id)
|
|
2087
|
+
rootNamed = true;
|
|
2088
|
+
else if (id !== undefined && !want.has(id)) {
|
|
2089
|
+
want.add(id);
|
|
2090
|
+
order.push(id);
|
|
2091
|
+
}
|
|
2092
|
+
for (const slot of Object.values(n.slots ?? {}))
|
|
2093
|
+
collect(slot);
|
|
2094
|
+
n.children.forEach(collect);
|
|
2095
|
+
};
|
|
2096
|
+
const strip = (n) => {
|
|
2097
|
+
const lifts = n.children.some((c) => want.has(c.id)) || Object.values(n.slots ?? {}).some((c) => want.has(c.id));
|
|
2098
|
+
if (lifts && !originals.has(n))
|
|
2099
|
+
originals.set(n, { children: [...n.children], ...n.slots ? { slots: { ...n.slots } } : {} });
|
|
2100
|
+
n.children = n.children.filter((c) => {
|
|
2101
|
+
if (!want.has(c.id))
|
|
2102
|
+
return true;
|
|
2103
|
+
if (!found.has(c.id))
|
|
2104
|
+
found.set(c.id, c);
|
|
2105
|
+
return false;
|
|
2106
|
+
});
|
|
2107
|
+
if (n.slots) {
|
|
2108
|
+
for (const [name, slot] of Object.entries(n.slots)) {
|
|
2109
|
+
if (!want.has(slot.id))
|
|
2110
|
+
continue;
|
|
2111
|
+
if (!found.has(slot.id))
|
|
2112
|
+
found.set(slot.id, slot);
|
|
2113
|
+
delete n.slots[name];
|
|
2114
|
+
}
|
|
2115
|
+
if (Object.keys(n.slots).length === 0)
|
|
2116
|
+
delete n.slots;
|
|
2117
|
+
}
|
|
2118
|
+
for (const slot of Object.values(n.slots ?? {}))
|
|
2119
|
+
strip(slot);
|
|
2120
|
+
n.children.forEach(strip);
|
|
2121
|
+
};
|
|
2122
|
+
collect(root);
|
|
2123
|
+
for (let before = ``;before !== `${want.size}/${found.size}/${missing.size}`; ) {
|
|
2124
|
+
before = `${want.size}/${found.size}/${missing.size}`;
|
|
2125
|
+
strip(root);
|
|
2126
|
+
for (let n = -1;n !== found.size; ) {
|
|
2127
|
+
n = found.size;
|
|
2128
|
+
for (const node of [...found.values()])
|
|
2129
|
+
strip(node);
|
|
2130
|
+
}
|
|
2131
|
+
for (const id of order) {
|
|
2132
|
+
if (found.has(id) || missing.has(id))
|
|
2133
|
+
continue;
|
|
2134
|
+
const built = buildMissing?.(id);
|
|
2135
|
+
if (built)
|
|
2136
|
+
found.set(id, built);
|
|
2137
|
+
else {
|
|
2138
|
+
missing.add(id);
|
|
2139
|
+
issues.push({ id, message: `template: no component with this id` });
|
|
2140
|
+
}
|
|
2141
|
+
}
|
|
2142
|
+
for (const node of [...found.values()])
|
|
2143
|
+
collect(node);
|
|
2144
|
+
}
|
|
2145
|
+
if (rootNamed)
|
|
2146
|
+
issues.push({ id: root.id, message: `template: cycle through this id` });
|
|
2147
|
+
const lifted = new Set(found.keys());
|
|
2148
|
+
for (;; ) {
|
|
2149
|
+
for (const [node, orig] of originals) {
|
|
2150
|
+
node.children = orig.children.filter((c) => !lifted.has(c.id));
|
|
2151
|
+
if (orig.slots) {
|
|
2152
|
+
const kept = Object.entries(orig.slots).filter(([, c]) => !lifted.has(c.id));
|
|
2153
|
+
if (kept.length > 0)
|
|
2154
|
+
node.slots = Object.fromEntries(kept);
|
|
2155
|
+
else
|
|
2156
|
+
delete node.slots;
|
|
2157
|
+
}
|
|
2158
|
+
}
|
|
2159
|
+
const deps = new Map;
|
|
2160
|
+
for (const id of lifted) {
|
|
2161
|
+
const out = new Set;
|
|
2162
|
+
const walk = (n) => {
|
|
2163
|
+
const t = n.template?.component;
|
|
2164
|
+
if (t !== undefined && lifted.has(t))
|
|
2165
|
+
out.add(t);
|
|
2166
|
+
for (const slot of Object.values(n.slots ?? {}))
|
|
2167
|
+
walk(slot);
|
|
2168
|
+
n.children.forEach(walk);
|
|
2169
|
+
};
|
|
2170
|
+
walk(found.get(id));
|
|
2171
|
+
deps.set(id, out);
|
|
2172
|
+
}
|
|
2173
|
+
const reaches = (from, to) => {
|
|
2174
|
+
const seen = new Set;
|
|
2175
|
+
const stack = [...deps.get(from) ?? []];
|
|
2176
|
+
while (stack.length > 0) {
|
|
2177
|
+
const id = stack.pop();
|
|
2178
|
+
if (id === to)
|
|
2179
|
+
return true;
|
|
2180
|
+
if (seen.has(id))
|
|
2181
|
+
continue;
|
|
2182
|
+
seen.add(id);
|
|
2183
|
+
stack.push(...deps.get(id) ?? []);
|
|
2184
|
+
}
|
|
2185
|
+
return false;
|
|
2186
|
+
};
|
|
2187
|
+
const cyclic = order.filter((id) => lifted.has(id) && reaches(id, id));
|
|
2188
|
+
if (cyclic.length === 0)
|
|
2189
|
+
break;
|
|
2190
|
+
for (const id of cyclic) {
|
|
2191
|
+
lifted.delete(id);
|
|
2192
|
+
issues.push({ id, message: `template: cycle through this id` });
|
|
2193
|
+
}
|
|
2194
|
+
}
|
|
2195
|
+
const out = new Map;
|
|
2196
|
+
for (const id of order) {
|
|
2197
|
+
const node = found.get(id);
|
|
2198
|
+
if (node && lifted.has(id))
|
|
2199
|
+
out.set(id, node);
|
|
2200
|
+
}
|
|
2201
|
+
return out;
|
|
2202
|
+
}
|
|
2203
|
+
function finish(root, lifted, expand, extensions, catalogId, issues) {
|
|
2204
|
+
const budget = { left: MAX_COMPONENTS2, reported: issues.some((i) => i.message === LIMIT_ISSUES2.components) };
|
|
2205
|
+
root = capComponents(capDepth(expand ? expandMacros2(root, { extensions, issues }) : root, catalogId, issues), budget, issues);
|
|
2206
|
+
if (lifted.size === 0)
|
|
2207
|
+
return { root, issues };
|
|
2208
|
+
const templates = {};
|
|
2209
|
+
for (const [id, node] of lifted)
|
|
2210
|
+
templates[id] = capComponents(capDepth(expand ? expandMacros2(node, { extensions, issues }) : node, catalogId, issues), budget, issues);
|
|
2211
|
+
return { root, issues, templates };
|
|
2212
|
+
}
|
|
2213
|
+
function capComponents(root, budget, issues) {
|
|
2214
|
+
spend(budget, root.id, issues);
|
|
2215
|
+
const walk = (node) => {
|
|
2216
|
+
node.children = node.children.filter((child) => {
|
|
2217
|
+
if (!spend(budget, child.id, issues))
|
|
2218
|
+
return false;
|
|
2219
|
+
walk(child);
|
|
2220
|
+
return true;
|
|
2221
|
+
});
|
|
2222
|
+
if (node.slots)
|
|
2223
|
+
for (const [name, slot] of Object.entries(node.slots)) {
|
|
2224
|
+
if (!spend(budget, slot.id, issues))
|
|
2225
|
+
delete node.slots[name];
|
|
2226
|
+
else
|
|
2227
|
+
walk(slot);
|
|
2228
|
+
}
|
|
2229
|
+
};
|
|
2230
|
+
walk(root);
|
|
2231
|
+
return root;
|
|
2232
|
+
}
|
|
2233
|
+
function capDepth(root, catalogId, issues) {
|
|
2234
|
+
const reported = new Set(issues.filter((i) => i.message === LIMIT_ISSUES2.depth).map((i) => i.id));
|
|
2235
|
+
const stack = [{ node: root, depth: 1 }];
|
|
2236
|
+
while (stack.length) {
|
|
2237
|
+
const { node, depth } = stack.pop();
|
|
2238
|
+
const cap = (child) => {
|
|
2239
|
+
if (depth + 1 <= MAX_DEPTH2)
|
|
2240
|
+
return child;
|
|
2241
|
+
if (child.component === UNKNOWN_COMPONENT2 && child.children.length === 0 && child.slots === undefined)
|
|
2242
|
+
return child;
|
|
2243
|
+
if (!reported.has(child.id)) {
|
|
2244
|
+
reported.add(child.id);
|
|
2245
|
+
issues.push({ id: child.id, message: LIMIT_ISSUES2.depth });
|
|
2246
|
+
}
|
|
2247
|
+
return unknown(child.id, child.component, catalogId);
|
|
2248
|
+
};
|
|
2249
|
+
const next = [];
|
|
2250
|
+
node.children = node.children.map((child) => {
|
|
2251
|
+
const capped = cap(child);
|
|
2252
|
+
next.push(capped);
|
|
2253
|
+
return capped;
|
|
2254
|
+
});
|
|
2255
|
+
if (node.slots)
|
|
2256
|
+
for (const [name, slot] of Object.entries(node.slots)) {
|
|
2257
|
+
const capped = cap(slot);
|
|
2258
|
+
node.slots[name] = capped;
|
|
2259
|
+
next.push(capped);
|
|
2260
|
+
}
|
|
2261
|
+
if (depth + 1 > MAX_DEPTH2)
|
|
2262
|
+
continue;
|
|
2263
|
+
for (let i = next.length - 1;i >= 0; i--)
|
|
2264
|
+
stack.push({ node: next[i], depth: depth + 1 });
|
|
2265
|
+
}
|
|
2266
|
+
return root;
|
|
2267
|
+
}
|
|
2268
|
+
function unknown(id, component, catalogId) {
|
|
2269
|
+
return { id, component: UNKNOWN_COMPONENT2, props: { component, catalogId }, children: [] };
|
|
2270
|
+
}
|
|
2271
|
+
function ownProps(flat) {
|
|
2272
|
+
const props = {};
|
|
2273
|
+
for (const [key, value] of Object.entries(flat)) {
|
|
2274
|
+
if (!RESERVED.has(key) && value !== undefined)
|
|
2275
|
+
props[key] = value;
|
|
2276
|
+
}
|
|
2277
|
+
return props;
|
|
2278
|
+
}
|
|
2279
|
+
function knownCatalog(catalogId, extensions) {
|
|
2280
|
+
return catalogId === CORE_CATALOG_ID2 || catalogId === CORE_LITE_CATALOG_ID2 || catalogId === A2UI_BASIC_CATALOG_ID2 || extensions.some((ext) => ext.id === catalogId);
|
|
2281
|
+
}
|
|
2282
|
+
function validVisible2(value) {
|
|
2283
|
+
return typeof value === `boolean` || isDynamic2(value);
|
|
2284
|
+
}
|
|
2285
|
+
function childTemplate2(value) {
|
|
2286
|
+
const out = { component: value.componentId, path: value.path };
|
|
2287
|
+
if (typeof value.key === `string`)
|
|
2288
|
+
out.key = value.key;
|
|
2289
|
+
return out;
|
|
2290
|
+
}
|
|
2291
|
+
function reduceSurface2(components, options) {
|
|
2292
|
+
const extensions = options.extensions ?? [];
|
|
2293
|
+
const view = sharedCatalogView2(extensions);
|
|
2294
|
+
const issues = [];
|
|
2295
|
+
const byId = new Map;
|
|
2296
|
+
components.forEach((flat, i) => {
|
|
2297
|
+
if (!flat || typeof flat !== `object` || typeof flat.id !== `string` || typeof flat.component !== `string`) {
|
|
2298
|
+
issues.push({ id: options.rootId ?? `root`, message: `components[${i}] is not a component (an object with a string id and component)` });
|
|
2299
|
+
return;
|
|
2300
|
+
}
|
|
2301
|
+
if (byId.has(flat.id))
|
|
2302
|
+
issues.push({ id: flat.id, message: `duplicate id; the last definition wins` });
|
|
2303
|
+
byId.set(flat.id, flat);
|
|
2304
|
+
});
|
|
2305
|
+
const lookup = (id) => byId.get(id);
|
|
2306
|
+
const basic = options.catalogId === A2UI_BASIC_CATALOG_ID2;
|
|
2307
|
+
if (!knownCatalog(options.catalogId, extensions))
|
|
2308
|
+
issues.push({ id: options.rootId ?? `root`, message: `unsupported catalog ${options.catalogId}` });
|
|
2309
|
+
const visiting = new Set;
|
|
2310
|
+
const placed = new Set;
|
|
2311
|
+
const twiceReported = new Set;
|
|
2312
|
+
const budget = { left: MAX_COMPONENTS2, reported: false };
|
|
2313
|
+
const build = (id, depth) => {
|
|
2314
|
+
const flat = byId.get(id);
|
|
2315
|
+
if (flat) {
|
|
2316
|
+
if (visiting.has(id)) {
|
|
2317
|
+
if (!spend(budget, id, issues))
|
|
2318
|
+
return;
|
|
2319
|
+
issues.push({ id, message: `cycle through this id` });
|
|
2320
|
+
return unknown(id, flat.component, options.catalogId);
|
|
2321
|
+
}
|
|
2322
|
+
if (placed.has(id)) {
|
|
2323
|
+
if (!twiceReported.has(id)) {
|
|
2324
|
+
twiceReported.add(id);
|
|
2325
|
+
issues.push({ id, message: LIMIT_ISSUES2.usedTwice });
|
|
2326
|
+
}
|
|
2327
|
+
return;
|
|
2328
|
+
}
|
|
2329
|
+
}
|
|
2330
|
+
if (!spend(budget, id, issues))
|
|
2331
|
+
return;
|
|
2332
|
+
if (!flat) {
|
|
2333
|
+
issues.push({ id, message: `no component with this id` });
|
|
2334
|
+
return unknown(id, `#${id}`, options.catalogId);
|
|
2335
|
+
}
|
|
2336
|
+
placed.add(id);
|
|
2337
|
+
if (depth > MAX_DEPTH2) {
|
|
2338
|
+
issues.push({ id, message: LIMIT_ISSUES2.depth });
|
|
2339
|
+
return unknown(id, flat.component, options.catalogId);
|
|
2340
|
+
}
|
|
2341
|
+
const child = (childId) => build(childId, depth + 1);
|
|
2342
|
+
const children = (ids) => ids.map(child).filter((n) => n !== undefined);
|
|
2343
|
+
visiting.add(id);
|
|
2344
|
+
let node;
|
|
2345
|
+
if (basic) {
|
|
2346
|
+
const mapped = mapBasicComponent2(flat, lookup);
|
|
2347
|
+
if (!mapped) {
|
|
2348
|
+
issues.push({ id, message: `basic component ${flat.component} has no mapping` });
|
|
2349
|
+
node = unknown(id, flat.component, options.catalogId);
|
|
2350
|
+
} else {
|
|
2351
|
+
node = { id, component: mapped.component, props: mapped.props, children: children(mapped.childrenIds) };
|
|
2352
|
+
if (mapped.template)
|
|
2353
|
+
node.template = mapped.template;
|
|
2354
|
+
if (mapped.style)
|
|
2355
|
+
node.style = mapped.style;
|
|
2356
|
+
if (mapped.on)
|
|
2357
|
+
node.on = mapped.on;
|
|
2358
|
+
for (const [slot, childId] of Object.entries(mapped.slots)) {
|
|
2359
|
+
const built = child(childId);
|
|
2360
|
+
if (built)
|
|
2361
|
+
(node.slots ??= {})[slot] = built;
|
|
2362
|
+
}
|
|
2363
|
+
}
|
|
2364
|
+
} else {
|
|
2365
|
+
const def = view.components[flat.component];
|
|
2366
|
+
if (!def) {
|
|
2367
|
+
issues.push({ id, message: `unknown component ${flat.component}` });
|
|
2368
|
+
node = unknown(id, flat.component, options.catalogId);
|
|
2369
|
+
} else {
|
|
2370
|
+
node = { id, component: flat.component, props: ownProps(flat), children: [] };
|
|
2371
|
+
if (Array.isArray(flat.children))
|
|
2372
|
+
node.children = children(flat.children);
|
|
2373
|
+
else if (flat.children && typeof flat.children === `object`)
|
|
2374
|
+
node.template = childTemplate2(flat.children);
|
|
2375
|
+
if (flat.style)
|
|
2376
|
+
node.style = flat.style;
|
|
2377
|
+
if (flat.on)
|
|
2378
|
+
node.on = flat.on;
|
|
2379
|
+
for (const [slot, childId] of Object.entries(flat.slots ?? {})) {
|
|
2380
|
+
const built = child(childId);
|
|
2381
|
+
if (built)
|
|
2382
|
+
(node.slots ??= {})[slot] = built;
|
|
2383
|
+
}
|
|
2384
|
+
}
|
|
2385
|
+
}
|
|
2386
|
+
if (flat.visible !== undefined) {
|
|
2387
|
+
if (validVisible2(flat.visible))
|
|
2388
|
+
node.visible = flat.visible;
|
|
2389
|
+
else
|
|
2390
|
+
issues.push({ id, message: `visible: expected a boolean, a binding or a function call` });
|
|
2391
|
+
}
|
|
2392
|
+
if (flat.accessibility)
|
|
2393
|
+
node.accessibility = flat.accessibility;
|
|
2394
|
+
visiting.delete(id);
|
|
2395
|
+
if (options.validate !== false && node.component !== UNKNOWN_COMPONENT2) {
|
|
2396
|
+
const def = view.components[node.component];
|
|
2397
|
+
if (def) {
|
|
2398
|
+
for (const issue of validateProps2(def, node.props, { path: `props`, extensions }))
|
|
2399
|
+
issues.push({ id, message: `${issue.path}: ${issue.message}` });
|
|
2400
|
+
if (def.children === `none` && node.children.length > 0)
|
|
2401
|
+
issues.push({ id, message: `${node.component} takes no children` });
|
|
2402
|
+
for (const slot of Object.keys(node.slots ?? {}))
|
|
2403
|
+
if (!slotAllowed2(def.slots, slot))
|
|
2404
|
+
issues.push({ id, message: `slots.${slot}: ${node.component} has no such slot` });
|
|
2405
|
+
for (const issue of validateNode2(node, { extensions }))
|
|
2406
|
+
issues.push({ id, message: `${issue.path}: ${issue.message}` });
|
|
2407
|
+
}
|
|
2408
|
+
}
|
|
2409
|
+
return node;
|
|
2410
|
+
};
|
|
2411
|
+
const rootId = options.rootId ?? `root`;
|
|
2412
|
+
let root = build(rootId, 1) ?? unknown(rootId, `#${rootId}`, options.catalogId);
|
|
2413
|
+
const lifted = liftTemplates(root, issues, (id) => byId.has(id) && !placed.has(id) ? build(id, 1) : undefined);
|
|
2414
|
+
return finish(root, lifted, options.expand !== false, extensions, options.catalogId, issues);
|
|
2415
|
+
}
|
|
2416
|
+
function spend(budget, id, issues) {
|
|
2417
|
+
if (budget.left > 0) {
|
|
2418
|
+
budget.left -= 1;
|
|
2419
|
+
return true;
|
|
2420
|
+
}
|
|
2421
|
+
if (!budget.reported)
|
|
2422
|
+
issues.push({ id, message: LIMIT_ISSUES2.components });
|
|
2423
|
+
budget.reported = true;
|
|
2424
|
+
return false;
|
|
2425
|
+
}
|
|
2426
|
+
function slotAllowed2(slots, name) {
|
|
2427
|
+
return (slots ?? []).some((s) => s === `*` || s === name);
|
|
2428
|
+
}
|
|
2429
|
+
function reduceNested2(tree, options) {
|
|
2430
|
+
const extensions = options.extensions ?? [];
|
|
2431
|
+
const view = sharedCatalogView2(extensions);
|
|
2432
|
+
const issues = [];
|
|
2433
|
+
const budget = { left: MAX_COMPONENTS2, reported: false };
|
|
2434
|
+
const walk = (n, depth) => {
|
|
2435
|
+
if (!spend(budget, n.id, issues))
|
|
2436
|
+
return;
|
|
2437
|
+
if (depth > MAX_DEPTH2) {
|
|
2438
|
+
issues.push({ id: n.id, message: LIMIT_ISSUES2.depth });
|
|
2439
|
+
return unknown(n.id, n.component, options.catalogId);
|
|
2440
|
+
}
|
|
2441
|
+
const def = view.components[n.component];
|
|
2442
|
+
if (!def) {
|
|
2443
|
+
issues.push({ id: n.id, message: `unknown component ${n.component}` });
|
|
2444
|
+
return unknown(n.id, n.component, options.catalogId);
|
|
2445
|
+
}
|
|
2446
|
+
const children = (n.children ?? []).map((c) => walk(c, depth + 1)).filter((c) => c !== undefined);
|
|
2447
|
+
const node = { id: n.id, component: n.component, props: { ...n.props ?? {} }, children };
|
|
2448
|
+
if (n.style)
|
|
2449
|
+
node.style = n.style;
|
|
2450
|
+
if (n.visible !== undefined) {
|
|
2451
|
+
if (validVisible2(n.visible))
|
|
2452
|
+
node.visible = n.visible;
|
|
2453
|
+
else
|
|
2454
|
+
issues.push({ id: n.id, message: `visible: expected a boolean, a binding or a function call` });
|
|
2455
|
+
}
|
|
2456
|
+
if (n.on)
|
|
2457
|
+
node.on = n.on;
|
|
2458
|
+
if (n.accessibility)
|
|
2459
|
+
node.accessibility = n.accessibility;
|
|
2460
|
+
if (n.template)
|
|
2461
|
+
node.template = n.template;
|
|
2462
|
+
if (n.slots) {
|
|
2463
|
+
node.slots = {};
|
|
2464
|
+
for (const [slot, child] of Object.entries(n.slots)) {
|
|
2465
|
+
const built = walk(child, depth + 1);
|
|
2466
|
+
if (built)
|
|
2467
|
+
node.slots[slot] = built;
|
|
2468
|
+
}
|
|
2469
|
+
}
|
|
2470
|
+
if (options.validate !== false) {
|
|
2471
|
+
for (const issue of validateProps2(def, node.props, { path: `props`, extensions }))
|
|
2472
|
+
issues.push({ id: n.id, message: `${issue.path}: ${issue.message}` });
|
|
2473
|
+
if (def.children === `none` && node.children.length > 0)
|
|
2474
|
+
issues.push({ id: n.id, message: `${n.component} takes no children` });
|
|
2475
|
+
for (const slot of Object.keys(node.slots ?? {}))
|
|
2476
|
+
if (!slotAllowed2(def.slots, slot))
|
|
2477
|
+
issues.push({ id: n.id, message: `slots.${slot}: ${n.component} has no such slot` });
|
|
2478
|
+
for (const issue of validateNode2(node, { extensions }))
|
|
2479
|
+
issues.push({ id: n.id, message: `${issue.path}: ${issue.message}` });
|
|
2480
|
+
}
|
|
2481
|
+
return node;
|
|
2482
|
+
};
|
|
2483
|
+
let root = walk(tree, 1);
|
|
2484
|
+
const lifted = liftTemplates(root, issues);
|
|
2485
|
+
return finish(root, lifted, options.expand !== false, extensions, options.catalogId, issues);
|
|
2486
|
+
}
|
|
2487
|
+
function preorder2(root) {
|
|
2488
|
+
const out = [];
|
|
2489
|
+
const walk = (n) => {
|
|
2490
|
+
out.push(n.id);
|
|
2491
|
+
for (const slot of Object.values(n.slots ?? {}))
|
|
2492
|
+
walk(slot);
|
|
2493
|
+
n.children.forEach(walk);
|
|
2494
|
+
};
|
|
2495
|
+
walk(root);
|
|
2496
|
+
return out;
|
|
2497
|
+
}
|
|
2498
|
+
// packages/exponential-ui/src/host/policy.ts
|
|
2499
|
+
var BUILTIN_FUNCTIONS2 = coreCatalog2.functions.names;
|
|
2500
|
+
function matchesPattern2(pattern, name) {
|
|
2501
|
+
return pattern.endsWith(`*`) ? name.startsWith(pattern.slice(0, -1)) : pattern === name;
|
|
2502
|
+
}
|
|
2503
|
+
function decideFunction2(policy, name, registered) {
|
|
2504
|
+
if (BUILTIN_FUNCTIONS2.includes(name))
|
|
2505
|
+
return `allow`;
|
|
2506
|
+
if (!registered)
|
|
2507
|
+
return `not_found`;
|
|
2508
|
+
const p = policy ?? {};
|
|
2509
|
+
const any = (list) => (list ?? []).some((pattern) => matchesPattern2(pattern, name));
|
|
2510
|
+
if (any(p.deny))
|
|
2511
|
+
return `deny`;
|
|
2512
|
+
if (any(p.allow))
|
|
2513
|
+
return `allow`;
|
|
2514
|
+
if (any(p.ask))
|
|
2515
|
+
return `ask`;
|
|
2516
|
+
return p.default ?? `allow`;
|
|
2517
|
+
}
|
|
2518
|
+
function combineDecisions2(a, b) {
|
|
2519
|
+
const rank = { allow: 0, ask: 1, deny: 2, not_found: 3 };
|
|
2520
|
+
return rank[a] >= rank[b] ? a : b;
|
|
2521
|
+
}
|
|
2522
|
+
function packagePolicy2(functions) {
|
|
2523
|
+
return { allow: functions ?? [], default: `deny` };
|
|
2524
|
+
}
|
|
2525
|
+
function absolute(url, baseUrl) {
|
|
2526
|
+
try {
|
|
2527
|
+
return new URL(url);
|
|
2528
|
+
} catch {
|
|
2529
|
+
if (!baseUrl)
|
|
2530
|
+
return null;
|
|
2531
|
+
try {
|
|
2532
|
+
return new URL(url, baseUrl);
|
|
2533
|
+
} catch {
|
|
2534
|
+
return null;
|
|
2535
|
+
}
|
|
2536
|
+
}
|
|
2537
|
+
}
|
|
2538
|
+
function hostMatches(pattern, host) {
|
|
2539
|
+
const p = pattern.toLowerCase();
|
|
2540
|
+
return p.startsWith(`*.`) ? host.endsWith(p.slice(1)) && host.length > p.length - 1 : host === p;
|
|
2541
|
+
}
|
|
2542
|
+
function ipv4(host) {
|
|
2543
|
+
const m = /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/.exec(host);
|
|
2544
|
+
if (!m)
|
|
2545
|
+
return null;
|
|
2546
|
+
const parts = m.slice(1).map(Number);
|
|
2547
|
+
return parts.every((n) => n <= 255) ? parts : null;
|
|
2548
|
+
}
|
|
2549
|
+
function ipv6(host) {
|
|
2550
|
+
if (!host.startsWith(`[`) || !host.endsWith(`]`))
|
|
2551
|
+
return null;
|
|
2552
|
+
const text = host.slice(1, -1);
|
|
2553
|
+
const halves = text.split(`::`);
|
|
2554
|
+
if (halves.length > 2)
|
|
2555
|
+
return null;
|
|
2556
|
+
const pieces = (part) => {
|
|
2557
|
+
if (part === ``)
|
|
2558
|
+
return [];
|
|
2559
|
+
const out = [];
|
|
2560
|
+
for (const p of part.split(`:`)) {
|
|
2561
|
+
if (!/^[0-9a-f]{1,4}$/.test(p))
|
|
2562
|
+
return null;
|
|
2563
|
+
out.push(parseInt(p, 16));
|
|
2564
|
+
}
|
|
2565
|
+
return out;
|
|
2566
|
+
};
|
|
2567
|
+
const head = pieces(halves[0]);
|
|
2568
|
+
const tail = halves.length === 2 ? pieces(halves[1]) : [];
|
|
2569
|
+
if (!head || !tail)
|
|
2570
|
+
return null;
|
|
2571
|
+
if (halves.length === 1)
|
|
2572
|
+
return head.length === 8 ? head : null;
|
|
2573
|
+
if (head.length + tail.length > 7)
|
|
2574
|
+
return null;
|
|
2575
|
+
return [...head, ...new Array(8 - head.length - tail.length).fill(0), ...tail];
|
|
2576
|
+
}
|
|
2577
|
+
function privateV4([a, b]) {
|
|
2578
|
+
return a === 0 || a === 10 || a === 127 || a === 169 && b === 254 || a === 172 && b >= 16 && b <= 31 || a === 192 && b === 168;
|
|
2579
|
+
}
|
|
2580
|
+
function isPrivateHost2(hostname) {
|
|
2581
|
+
const host = hostname.toLowerCase().replace(/\.$/, ``);
|
|
2582
|
+
if (host === `localhost` || host.endsWith(`.localhost`) || host.endsWith(`.local`))
|
|
2583
|
+
return true;
|
|
2584
|
+
const v4 = ipv4(host);
|
|
2585
|
+
if (v4)
|
|
2586
|
+
return privateV4(v4);
|
|
2587
|
+
const v6 = ipv6(host);
|
|
2588
|
+
if (!v6)
|
|
2589
|
+
return false;
|
|
2590
|
+
if (v6.every((p) => p === 0))
|
|
2591
|
+
return true;
|
|
2592
|
+
if (v6.slice(0, 7).every((p) => p === 0) && v6[7] === 1)
|
|
2593
|
+
return true;
|
|
2594
|
+
if ((v6[0] & 65472) === 65152 || (v6[0] & 65024) === 64512)
|
|
2595
|
+
return true;
|
|
2596
|
+
if (v6.slice(0, 5).every((p) => p === 0) && v6[5] === 65535)
|
|
2597
|
+
return privateV4([v6[6] >> 8, v6[6] & 255, v6[7] >> 8, v6[7] & 255]);
|
|
2598
|
+
return false;
|
|
2599
|
+
}
|
|
2600
|
+
function privateAllowed(allow, host) {
|
|
2601
|
+
return (allow ?? []).some((p) => p === `*` || hostMatches(p, host));
|
|
2602
|
+
}
|
|
2603
|
+
function decideUrl2(policy, url) {
|
|
2604
|
+
const parsed = absolute(url.trim(), policy?.baseUrl);
|
|
2605
|
+
if (!parsed)
|
|
2606
|
+
return { allowed: false, reason: `invalid` };
|
|
2607
|
+
const scheme = parsed.protocol.replace(/:$/, ``).toLowerCase();
|
|
2608
|
+
const schemes = policy?.schemes ?? DEFAULT_URL_SCHEMES2;
|
|
2609
|
+
if (!schemes.includes(scheme))
|
|
2610
|
+
return { allowed: false, url: parsed.href, reason: `scheme` };
|
|
2611
|
+
if (scheme === `http` || scheme === `https`) {
|
|
2612
|
+
const host = parsed.hostname.toLowerCase();
|
|
2613
|
+
if (policy?.hosts && !policy.hosts.some((h) => hostMatches(h, host)))
|
|
2614
|
+
return { allowed: false, url: parsed.href, reason: `host` };
|
|
2615
|
+
if (isPrivateHost2(host) && !privateAllowed(policy?.allowPrivate, host))
|
|
2616
|
+
return { allowed: false, url: parsed.href, reason: `private` };
|
|
2617
|
+
}
|
|
2618
|
+
return { allowed: true, url: parsed.href };
|
|
2619
|
+
}
|
|
2620
|
+
function mediaRequest2(url, options = {}) {
|
|
2621
|
+
const d = decideUrl2({ baseUrl: options.baseUrl, schemes: options.schemes ?? DEFAULT_MEDIA_SCHEMES2, hosts: options.hosts, allowPrivate: options.allowPrivate }, url);
|
|
2622
|
+
if (!d.allowed || !d.url)
|
|
2623
|
+
return null;
|
|
2624
|
+
const href = d.url;
|
|
2625
|
+
const headers = {};
|
|
2626
|
+
for (const rule of options.rules ?? [])
|
|
2627
|
+
if (href.startsWith(rule.prefix))
|
|
2628
|
+
Object.assign(headers, rule.headers);
|
|
2629
|
+
return { url: href, headers: sortKeys2(headers) };
|
|
2630
|
+
}
|
|
2631
|
+
function safeHref2(policy, url) {
|
|
2632
|
+
if (typeof url !== `string` || !url)
|
|
2633
|
+
return;
|
|
2634
|
+
const d = decideUrl2(policy, url);
|
|
2635
|
+
return d.allowed ? d.url : undefined;
|
|
2636
|
+
}
|
|
2637
|
+
function sortKeys2(record) {
|
|
2638
|
+
return Object.fromEntries(Object.entries(record).sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0));
|
|
2639
|
+
}
|
|
2640
|
+
function imageDimensions2(bytes) {
|
|
2641
|
+
if (isSvg(bytes))
|
|
2642
|
+
return svgDimensions2(bytes);
|
|
2643
|
+
const n = bytes.length;
|
|
2644
|
+
const be16 = (i) => i + 2 <= n ? bytes[i] << 8 | bytes[i + 1] : null;
|
|
2645
|
+
const le16 = (i) => i + 2 <= n ? bytes[i] | bytes[i + 1] << 8 : null;
|
|
2646
|
+
const be32 = (i) => i + 4 <= n ? (bytes[i] << 24 | bytes[i + 1] << 16 | bytes[i + 2] << 8 | bytes[i + 3]) >>> 0 : null;
|
|
2647
|
+
const le32 = (i) => i + 4 <= n ? (bytes[i] | bytes[i + 1] << 8 | bytes[i + 2] << 16 | bytes[i + 3] << 24) >>> 0 : null;
|
|
2648
|
+
const le24 = (i) => i + 3 <= n ? bytes[i] | bytes[i + 1] << 8 | bytes[i + 2] << 16 : null;
|
|
2649
|
+
const starts = (sig, at = 0) => sig.every((b, i) => bytes[at + i] === b);
|
|
2650
|
+
const pair = (w, h) => w === null || h === null ? null : [w, h];
|
|
2651
|
+
if (starts([137, 80, 78, 71, 13, 10, 26, 10]))
|
|
2652
|
+
return pair(be32(16), be32(20));
|
|
2653
|
+
if (starts([71, 73, 70, 56]) && (bytes[4] === 55 || bytes[4] === 57) && bytes[5] === 97)
|
|
2654
|
+
return pair(le16(6), le16(8));
|
|
2655
|
+
if (starts([66, 77])) {
|
|
2656
|
+
const h = le32(22);
|
|
2657
|
+
return pair(le32(18), h === null ? null : Math.abs(h | 0));
|
|
2658
|
+
}
|
|
2659
|
+
if (n >= 30 && starts([82, 73, 70, 70]) && starts([87, 69, 66, 80], 8)) {
|
|
2660
|
+
const kind = String.fromCharCode(bytes[12], bytes[13], bytes[14], bytes[15]);
|
|
2661
|
+
if (kind === `VP8 `)
|
|
2662
|
+
return pair(le16(26) & 16383, le16(28) & 16383);
|
|
2663
|
+
if (kind === `VP8L`) {
|
|
2664
|
+
const b = le32(21);
|
|
2665
|
+
return b === null ? null : [(b & 16383) + 1, (b >>> 14 & 16383) + 1];
|
|
2666
|
+
}
|
|
2667
|
+
if (kind === `VP8X`) {
|
|
2668
|
+
const w = le24(24);
|
|
2669
|
+
const h = le24(27);
|
|
2670
|
+
return w === null || h === null ? null : [w + 1, h + 1];
|
|
2671
|
+
}
|
|
2672
|
+
return null;
|
|
2673
|
+
}
|
|
2674
|
+
if (starts([255, 216])) {
|
|
2675
|
+
let i = 2;
|
|
2676
|
+
while (i + 4 <= n) {
|
|
2677
|
+
if (bytes[i] !== 255) {
|
|
2678
|
+
i += 1;
|
|
2679
|
+
continue;
|
|
2680
|
+
}
|
|
2681
|
+
const marker = bytes[i + 1];
|
|
2682
|
+
if (marker === 255) {
|
|
2683
|
+
i += 1;
|
|
2684
|
+
continue;
|
|
2685
|
+
}
|
|
2686
|
+
if (marker === 216 || marker === 1 || marker >= 208 && marker <= 215) {
|
|
2687
|
+
i += 2;
|
|
2688
|
+
continue;
|
|
2689
|
+
}
|
|
2690
|
+
const len = be16(i + 2);
|
|
2691
|
+
if (len === null)
|
|
2692
|
+
return null;
|
|
2693
|
+
if (marker >= 192 && marker <= 207 && marker !== 196 && marker !== 200 && marker !== 204)
|
|
2694
|
+
return pair(be16(i + 7), be16(i + 5));
|
|
2695
|
+
i += 2 + len;
|
|
2696
|
+
}
|
|
2697
|
+
}
|
|
2698
|
+
return null;
|
|
2699
|
+
}
|
|
2700
|
+
function isSvg(bytes) {
|
|
2701
|
+
const head = bytes.subarray(0, 256);
|
|
2702
|
+
let i = 0;
|
|
2703
|
+
while (i < head.length && (head[i] === 32 || head[i] === 9 || head[i] === 10 || head[i] === 12 || head[i] === 13))
|
|
2704
|
+
i += 1;
|
|
2705
|
+
const text = String.fromCharCode(...head.subarray(i, i + 5)).toLowerCase();
|
|
2706
|
+
return text.startsWith(`<svg`) || text.startsWith(`<?xml`);
|
|
2707
|
+
}
|
|
2708
|
+
var SVG_UNITS = { "": 1, px: 1, pt: 4 / 3, pc: 16, in: 96, cm: 96 / 2.54, mm: 96 / 25.4, em: 16, ex: 8 };
|
|
2709
|
+
function svgLength(value) {
|
|
2710
|
+
const v = value.trim();
|
|
2711
|
+
const m = /^[0-9.+\-eE]*/.exec(v);
|
|
2712
|
+
let num = m[0];
|
|
2713
|
+
let unit = v.slice(num.length);
|
|
2714
|
+
if (/[eE]$/.test(num)) {
|
|
2715
|
+
num = num.slice(0, -1);
|
|
2716
|
+
unit = v.slice(num.length);
|
|
2717
|
+
}
|
|
2718
|
+
const scale = SVG_UNITS[unit.trim()];
|
|
2719
|
+
if (scale === undefined || !/^[+-]?(\d+\.?\d*|\.\d+)([eE][+-]?\d+)?$/.test(num))
|
|
2720
|
+
return null;
|
|
2721
|
+
const n = Number(num);
|
|
2722
|
+
return Number.isFinite(n) && n >= 0 ? n * scale : null;
|
|
2723
|
+
}
|
|
2724
|
+
function svgViewBox(value) {
|
|
2725
|
+
const parts = value.split(/[\s,]+/).filter((p) => p !== ``);
|
|
2726
|
+
if (parts.length !== 4 || parts.some((p) => !/^[+-]?(\d+\.?\d*|\.\d+)([eE][+-]?\d+)?$/.test(p)))
|
|
2727
|
+
return null;
|
|
2728
|
+
const w = Number(parts[2]);
|
|
2729
|
+
const h = Number(parts[3]);
|
|
2730
|
+
return w > 0 && h > 0 && Number.isFinite(w) && Number.isFinite(h) ? [w, h] : null;
|
|
2731
|
+
}
|
|
2732
|
+
function svgDimensions2(bytes) {
|
|
2733
|
+
let at = -1;
|
|
2734
|
+
for (let i = 0;i + 4 <= bytes.length; i++) {
|
|
2735
|
+
if (bytes[i] === 60 && bytes[i + 1] === 115 && bytes[i + 2] === 118 && bytes[i + 3] === 103) {
|
|
2736
|
+
at = i;
|
|
2737
|
+
break;
|
|
2738
|
+
}
|
|
2739
|
+
}
|
|
2740
|
+
if (at < 0)
|
|
2741
|
+
return null;
|
|
2742
|
+
let end = bytes.indexOf(62, at);
|
|
2743
|
+
if (end < 0)
|
|
2744
|
+
end = bytes.length;
|
|
2745
|
+
const tag = new TextDecoder().decode(bytes.subarray(at + 4, end));
|
|
2746
|
+
let width = null;
|
|
2747
|
+
let height = null;
|
|
2748
|
+
let viewBox = null;
|
|
2749
|
+
for (const m of tag.matchAll(/(?<=\s)([A-Za-z_:][A-Za-z0-9_:.\-]*)\s*=\s*("([^"]*)"?|'([^']*)'?)/g)) {
|
|
2750
|
+
const value = m[3] ?? m[4] ?? ``;
|
|
2751
|
+
if (m[1] === `width`)
|
|
2752
|
+
width = svgLength(value);
|
|
2753
|
+
else if (m[1] === `height`)
|
|
2754
|
+
height = svgLength(value);
|
|
2755
|
+
else if (m[1] === `viewBox`)
|
|
2756
|
+
viewBox = svgViewBox(value);
|
|
2757
|
+
}
|
|
2758
|
+
let w;
|
|
2759
|
+
let h;
|
|
2760
|
+
if (width !== null && height !== null)
|
|
2761
|
+
[w, h] = [width, height];
|
|
2762
|
+
else if (width !== null)
|
|
2763
|
+
[w, h] = [width, viewBox ? width * viewBox[1] / viewBox[0] : 100];
|
|
2764
|
+
else if (height !== null)
|
|
2765
|
+
[w, h] = [viewBox ? height * viewBox[0] / viewBox[1] : 100, height];
|
|
2766
|
+
else
|
|
2767
|
+
[w, h] = viewBox ?? [100, 100];
|
|
2768
|
+
const px = (v) => Number.isFinite(v) ? Math.min(Math.max(Math.ceil(v), 0), 4294967295) : 4294967295;
|
|
2769
|
+
return [px(w), px(h)];
|
|
2770
|
+
}
|
|
2771
|
+
function imageFrames2(bytes) {
|
|
2772
|
+
const n = bytes.length;
|
|
2773
|
+
const be32 = (i) => i + 4 <= n ? (bytes[i] << 24 | bytes[i + 1] << 16 | bytes[i + 2] << 8 | bytes[i + 3]) >>> 0 : null;
|
|
2774
|
+
const le32 = (i) => i + 4 <= n ? (bytes[i] | bytes[i + 1] << 8 | bytes[i + 2] << 16 | bytes[i + 3] << 24) >>> 0 : null;
|
|
2775
|
+
const tag = (i) => i + 4 <= n ? String.fromCharCode(bytes[i], bytes[i + 1], bytes[i + 2], bytes[i + 3]) : null;
|
|
2776
|
+
const starts = (sig) => sig.every((b, i) => bytes[i] === b);
|
|
2777
|
+
let frames = 1;
|
|
2778
|
+
if (starts([71, 73, 70, 56]) && (bytes[4] === 55 || bytes[4] === 57) && bytes[5] === 97) {
|
|
2779
|
+
const skipBlocks = (i) => {
|
|
2780
|
+
while (i < n) {
|
|
2781
|
+
const size = bytes[i];
|
|
2782
|
+
i += 1 + size;
|
|
2783
|
+
if (size === 0)
|
|
2784
|
+
break;
|
|
2785
|
+
}
|
|
2786
|
+
return i;
|
|
2787
|
+
};
|
|
2788
|
+
const table = (packed) => packed & 128 ? 3 << (packed & 7) + 1 : 0;
|
|
2789
|
+
let i = 13 + (n > 10 ? table(bytes[10]) : 0);
|
|
2790
|
+
frames = 0;
|
|
2791
|
+
for (;; ) {
|
|
2792
|
+
if (bytes[i] === 44) {
|
|
2793
|
+
frames += 1;
|
|
2794
|
+
if (i + 9 >= n)
|
|
2795
|
+
break;
|
|
2796
|
+
i = skipBlocks(i + 10 + table(bytes[i + 9]) + 1);
|
|
2797
|
+
} else if (bytes[i] === 33)
|
|
2798
|
+
i = skipBlocks(i + 2);
|
|
2799
|
+
else
|
|
2800
|
+
break;
|
|
2801
|
+
}
|
|
2802
|
+
} else if (starts([137, 80, 78, 71, 13, 10, 26, 10])) {
|
|
2803
|
+
let i = 8;
|
|
2804
|
+
for (;; ) {
|
|
2805
|
+
const len = be32(i);
|
|
2806
|
+
const kind = tag(i + 4);
|
|
2807
|
+
if (len === null || kind === null || kind === `IDAT`)
|
|
2808
|
+
break;
|
|
2809
|
+
if (kind === `acTL`) {
|
|
2810
|
+
frames = be32(i + 8) ?? 1;
|
|
2811
|
+
break;
|
|
2812
|
+
}
|
|
2813
|
+
i += 12 + len;
|
|
2814
|
+
}
|
|
2815
|
+
} else if (n >= 21 && tag(0) === `RIFF` && tag(8) === `WEBP` && tag(12) === `VP8X` && bytes[20] & 2) {
|
|
2816
|
+
let i = 12;
|
|
2817
|
+
frames = 0;
|
|
2818
|
+
for (;; ) {
|
|
2819
|
+
const kind = tag(i);
|
|
2820
|
+
const size = le32(i + 4);
|
|
2821
|
+
if (kind === null || size === null)
|
|
2822
|
+
break;
|
|
2823
|
+
if (kind === `ANMF`)
|
|
2824
|
+
frames += 1;
|
|
2825
|
+
i += 8 + size + (size & 1);
|
|
2826
|
+
}
|
|
2827
|
+
}
|
|
2828
|
+
return Math.max(frames, 1);
|
|
2829
|
+
}
|
|
2830
|
+
function mediaImageWithinLimits2(bytes, limits = MEDIA_LIMITS2) {
|
|
2831
|
+
const { maxBytes, maxPixels } = limits;
|
|
2832
|
+
if (bytes.length > maxBytes)
|
|
2833
|
+
return `media is over ${maxBytes} bytes`;
|
|
2834
|
+
const starts = (sig, at = 0) => sig.every((b, i) => bytes[at + i] === b);
|
|
2835
|
+
const raster = starts([137, 80, 78, 71, 13, 10, 26, 10]) || starts([71, 73, 70, 56]) && (bytes[4] === 55 || bytes[4] === 57) && bytes[5] === 97 || starts([66, 77]) || starts([255, 216]) || bytes.length >= 12 && starts([82, 73, 70, 70]) && starts([87, 69, 66, 80], 8);
|
|
2836
|
+
if (!raster && !isSvg(bytes))
|
|
2837
|
+
return null;
|
|
2838
|
+
const dims = imageDimensions2(bytes);
|
|
2839
|
+
if (!dims)
|
|
2840
|
+
return `media: image dimensions unreadable`;
|
|
2841
|
+
const [w, h] = dims;
|
|
2842
|
+
const frames = imageFrames2(bytes);
|
|
2843
|
+
if (frames <= 1)
|
|
2844
|
+
return w * h > maxPixels ? `media is ${w}×${h}, over ${maxPixels} pixels` : null;
|
|
2845
|
+
return w * h * frames > maxPixels ? `media is ${w}×${h} × ${frames} frames, over ${maxPixels} pixels` : null;
|
|
2846
|
+
}
|
|
2847
|
+
// packages/exponential-ui/src/host/sources.ts
|
|
2848
|
+
var SOURCE = /^([a-zA-Z][a-zA-Z0-9+.-]*):([^?]+)(?:\?(.*))?$/;
|
|
2849
|
+
function decode(part) {
|
|
2850
|
+
try {
|
|
2851
|
+
return decodeURIComponent(part.replace(/\+/g, ` `));
|
|
2852
|
+
} catch {
|
|
2853
|
+
return part;
|
|
2854
|
+
}
|
|
2855
|
+
}
|
|
2856
|
+
function parseSource2(uri) {
|
|
2857
|
+
const m = SOURCE.exec(uri.trim());
|
|
2858
|
+
if (!m)
|
|
2859
|
+
return null;
|
|
2860
|
+
const name = decode(m[2]);
|
|
2861
|
+
if (!name)
|
|
2862
|
+
return null;
|
|
2863
|
+
const params = {};
|
|
2864
|
+
for (const pair of (m[3] ?? ``).split(`&`)) {
|
|
2865
|
+
if (!pair)
|
|
2866
|
+
continue;
|
|
2867
|
+
const eq = pair.indexOf(`=`);
|
|
2868
|
+
const key = decode(eq < 0 ? pair : pair.slice(0, eq));
|
|
2869
|
+
if (!key)
|
|
2870
|
+
continue;
|
|
2871
|
+
params[key] = eq < 0 ? `` : decode(pair.slice(eq + 1));
|
|
2872
|
+
}
|
|
2873
|
+
return { uri, scheme: m[1].toLowerCase(), name, params: sortKeys2(params) };
|
|
2874
|
+
}
|
|
2875
|
+
// packages/exponential-ui/src/host/decoders.ts
|
|
2876
|
+
function parseLine(line, at, out) {
|
|
2877
|
+
const text = line.trim();
|
|
2878
|
+
if (!text)
|
|
2879
|
+
return;
|
|
2880
|
+
try {
|
|
2881
|
+
out.messages.push(JSON.parse(text));
|
|
2882
|
+
} catch {
|
|
2883
|
+
out.issues.push({ at, message: `line ${at} is not JSON` });
|
|
2884
|
+
}
|
|
2885
|
+
}
|
|
2886
|
+
function utf8Bytes(text) {
|
|
2887
|
+
let n = 0;
|
|
2888
|
+
for (let i = 0;i < text.length; i++) {
|
|
2889
|
+
const c = text.charCodeAt(i);
|
|
2890
|
+
n += c < 128 ? 1 : c < 2048 ? 2 : c >= 55296 && c <= 57343 ? 2 : 3;
|
|
2891
|
+
}
|
|
2892
|
+
return n;
|
|
2893
|
+
}
|
|
2894
|
+
|
|
2895
|
+
class Lines {
|
|
2896
|
+
parts = [];
|
|
2897
|
+
bytes = 0;
|
|
2898
|
+
skipping = false;
|
|
2899
|
+
push(chunk) {
|
|
2900
|
+
const out = [];
|
|
2901
|
+
let start = 0;
|
|
2902
|
+
if (this.skipping) {
|
|
2903
|
+
const i = chunk.indexOf(`
|
|
2904
|
+
`);
|
|
2905
|
+
if (i < 0)
|
|
2906
|
+
return out;
|
|
2907
|
+
this.skipping = false;
|
|
2908
|
+
start = i + 1;
|
|
2909
|
+
}
|
|
2910
|
+
let nl = chunk.indexOf(`
|
|
2911
|
+
`, start);
|
|
2912
|
+
while (nl >= 0) {
|
|
2913
|
+
const piece = chunk.slice(start, nl);
|
|
2914
|
+
const oversized = this.bytes + utf8Bytes(piece) > MAX_MESSAGE_BYTES2;
|
|
2915
|
+
out.push(oversized ? null : this.parts.length ? this.parts.join(``) + piece : piece);
|
|
2916
|
+
this.parts = [];
|
|
2917
|
+
this.bytes = 0;
|
|
2918
|
+
start = nl + 1;
|
|
2919
|
+
nl = chunk.indexOf(`
|
|
2920
|
+
`, start);
|
|
2921
|
+
}
|
|
2922
|
+
if (start < chunk.length) {
|
|
2923
|
+
const tail = chunk.slice(start);
|
|
2924
|
+
this.parts.push(tail);
|
|
2925
|
+
this.bytes += utf8Bytes(tail);
|
|
2926
|
+
}
|
|
2927
|
+
if (this.bytes > MAX_MESSAGE_BYTES2) {
|
|
2928
|
+
out.push(null);
|
|
2929
|
+
this.parts = [];
|
|
2930
|
+
this.bytes = 0;
|
|
2931
|
+
this.skipping = true;
|
|
2932
|
+
}
|
|
2933
|
+
return out;
|
|
2934
|
+
}
|
|
2935
|
+
end() {
|
|
2936
|
+
const skipping = this.skipping;
|
|
2937
|
+
const tail = this.parts.join(``);
|
|
2938
|
+
this.parts = [];
|
|
2939
|
+
this.bytes = 0;
|
|
2940
|
+
this.skipping = false;
|
|
2941
|
+
return skipping ? null : tail;
|
|
2942
|
+
}
|
|
2943
|
+
}
|
|
2944
|
+
var oversized = (at, what) => ({ at, message: `${what} ${at}: ${LIMIT_ISSUES2.messageBytes}` });
|
|
2945
|
+
|
|
2946
|
+
class JsonlDecoder2 {
|
|
2947
|
+
lines = new Lines;
|
|
2948
|
+
line = 0;
|
|
2949
|
+
push(chunk) {
|
|
2950
|
+
const out = { messages: [], issues: [] };
|
|
2951
|
+
for (const raw of this.lines.push(chunk)) {
|
|
2952
|
+
this.line += 1;
|
|
2953
|
+
if (raw === null)
|
|
2954
|
+
out.issues.push(oversized(this.line, `line`));
|
|
2955
|
+
else
|
|
2956
|
+
parseLine(raw, this.line, out);
|
|
2957
|
+
}
|
|
2958
|
+
return out;
|
|
2959
|
+
}
|
|
2960
|
+
end() {
|
|
2961
|
+
const out = { messages: [], issues: [] };
|
|
2962
|
+
const raw = this.lines.end();
|
|
2963
|
+
if (raw !== null && raw.trim()) {
|
|
2964
|
+
this.line += 1;
|
|
2965
|
+
parseLine(raw, this.line, out);
|
|
2966
|
+
}
|
|
2967
|
+
return out;
|
|
2968
|
+
}
|
|
2969
|
+
}
|
|
2970
|
+
function decodeJsonl2(text) {
|
|
2971
|
+
const trimmed = text.trim();
|
|
2972
|
+
if (trimmed.startsWith(`[`)) {
|
|
2973
|
+
try {
|
|
2974
|
+
const value = JSON.parse(trimmed);
|
|
2975
|
+
if (Array.isArray(value))
|
|
2976
|
+
return { messages: value, issues: [] };
|
|
2977
|
+
} catch {}
|
|
2978
|
+
}
|
|
2979
|
+
const d = new JsonlDecoder2;
|
|
2980
|
+
const a = d.push(text);
|
|
2981
|
+
const b = d.end();
|
|
2982
|
+
return { messages: [...a.messages, ...b.messages], issues: [...a.issues, ...b.issues] };
|
|
2983
|
+
}
|
|
2984
|
+
|
|
2985
|
+
class SseDecoder2 {
|
|
2986
|
+
retryMs;
|
|
2987
|
+
lines = new Lines;
|
|
2988
|
+
data = [];
|
|
2989
|
+
dataBytes = 0;
|
|
2990
|
+
oversized = false;
|
|
2991
|
+
event = ``;
|
|
2992
|
+
count = 0;
|
|
2993
|
+
push(chunk) {
|
|
2994
|
+
const out = { messages: [], issues: [] };
|
|
2995
|
+
for (const raw of this.lines.push(chunk)) {
|
|
2996
|
+
if (raw === null)
|
|
2997
|
+
this.dropData();
|
|
2998
|
+
else
|
|
2999
|
+
this.line(raw.endsWith(`\r`) ? raw.slice(0, -1) : raw, out);
|
|
3000
|
+
}
|
|
3001
|
+
return out;
|
|
3002
|
+
}
|
|
3003
|
+
end() {
|
|
3004
|
+
const out = { messages: [], issues: [] };
|
|
3005
|
+
const raw = this.lines.end();
|
|
3006
|
+
if (raw === null)
|
|
3007
|
+
this.dropData();
|
|
3008
|
+
else if (raw)
|
|
3009
|
+
this.line(raw, out);
|
|
3010
|
+
this.dispatch(out);
|
|
3011
|
+
return out;
|
|
3012
|
+
}
|
|
3013
|
+
dropData() {
|
|
3014
|
+
this.data = [];
|
|
3015
|
+
this.dataBytes = 0;
|
|
3016
|
+
this.oversized = true;
|
|
3017
|
+
}
|
|
3018
|
+
line(line, out) {
|
|
3019
|
+
if (line === ``)
|
|
3020
|
+
return this.dispatch(out);
|
|
3021
|
+
if (line.startsWith(`:`))
|
|
3022
|
+
return;
|
|
3023
|
+
const colon = line.indexOf(`:`);
|
|
3024
|
+
const field = colon < 0 ? line : line.slice(0, colon);
|
|
3025
|
+
let value = colon < 0 ? `` : line.slice(colon + 1);
|
|
3026
|
+
if (value.startsWith(` `))
|
|
3027
|
+
value = value.slice(1);
|
|
3028
|
+
if (field === `data`) {
|
|
3029
|
+
if (this.oversized)
|
|
3030
|
+
return;
|
|
3031
|
+
this.dataBytes += utf8Bytes(value) + 1;
|
|
3032
|
+
if (this.dataBytes > MAX_MESSAGE_BYTES2)
|
|
3033
|
+
return this.dropData();
|
|
3034
|
+
this.data.push(value);
|
|
3035
|
+
} else if (field === `event`)
|
|
3036
|
+
this.event = value;
|
|
3037
|
+
else if (field === `retry` && /^\d+$/.test(value))
|
|
3038
|
+
this.retryMs = Number(value);
|
|
3039
|
+
}
|
|
3040
|
+
dispatch(out) {
|
|
3041
|
+
this.dataBytes = 0;
|
|
3042
|
+
if (this.oversized) {
|
|
3043
|
+
this.oversized = false;
|
|
3044
|
+
this.count += 1;
|
|
3045
|
+
this.data = [];
|
|
3046
|
+
this.event = ``;
|
|
3047
|
+
out.issues.push(oversized(this.count, `event`));
|
|
3048
|
+
return;
|
|
3049
|
+
}
|
|
3050
|
+
if (!this.data.length) {
|
|
3051
|
+
this.event = ``;
|
|
3052
|
+
return;
|
|
3053
|
+
}
|
|
3054
|
+
this.count += 1;
|
|
3055
|
+
const name = this.event || `message`;
|
|
3056
|
+
const data = this.data.join(`
|
|
3057
|
+
`);
|
|
3058
|
+
this.data = [];
|
|
3059
|
+
this.event = ``;
|
|
3060
|
+
if (!SSE_EVENTS2.includes(name))
|
|
3061
|
+
return;
|
|
3062
|
+
const d = decodeJsonl2(data);
|
|
3063
|
+
out.messages.push(...d.messages);
|
|
3064
|
+
if (d.issues.length)
|
|
3065
|
+
out.issues.push({ at: this.count, message: `event ${this.count} is not JSON` });
|
|
3066
|
+
}
|
|
3067
|
+
}
|
|
3068
|
+
function messagesFromMcpResult2(result) {
|
|
3069
|
+
const out = { messages: [], issues: [] };
|
|
3070
|
+
if (!result || typeof result !== `object`)
|
|
3071
|
+
return out;
|
|
3072
|
+
const r = result;
|
|
3073
|
+
const structured = r.structuredContent?.a2ui;
|
|
3074
|
+
if (Array.isArray(structured))
|
|
3075
|
+
out.messages.push(...structured);
|
|
3076
|
+
if (Array.isArray(r.content)) {
|
|
3077
|
+
r.content.forEach((item, i) => {
|
|
3078
|
+
const resource = item?.resource;
|
|
3079
|
+
if (item?.type !== `resource` || !resource || !MCP_MIME_TYPES2.includes(resource.mimeType ?? ``))
|
|
3080
|
+
return;
|
|
3081
|
+
if (typeof resource.text !== `string`)
|
|
3082
|
+
return;
|
|
3083
|
+
const d = decodeJsonl2(resource.text);
|
|
3084
|
+
out.messages.push(...d.messages);
|
|
3085
|
+
for (const issue of d.issues)
|
|
3086
|
+
out.issues.push({ at: i + 1, message: `content[${i}]: ${issue.message}` });
|
|
3087
|
+
});
|
|
3088
|
+
}
|
|
3089
|
+
return out;
|
|
3090
|
+
}
|
|
3091
|
+
function mcpActionCall2(message, tool = MCP_ACTION_TOOL2) {
|
|
3092
|
+
return { method: `tools/call`, params: { name: tool, arguments: { message } } };
|
|
3093
|
+
}
|
|
3094
|
+
// packages/exponential-ui/src/host/package.ts
|
|
3095
|
+
function supportedCatalogIds2(extensionIds = []) {
|
|
3096
|
+
const out = [];
|
|
3097
|
+
for (const id of [CORE_CATALOG_ID2, CORE_LITE_CATALOG_ID2, A2UI_BASIC_CATALOG_ID2, ...extensionIds])
|
|
3098
|
+
if (!out.includes(id))
|
|
3099
|
+
out.push(id);
|
|
3100
|
+
return out;
|
|
3101
|
+
}
|
|
3102
|
+
function clientCapabilities2(extensionIds = []) {
|
|
3103
|
+
return { "v0.9": { supportedCatalogIds: supportedCatalogIds2(extensionIds) } };
|
|
3104
|
+
}
|
|
3105
|
+
var isObject = (v) => !!v && typeof v === `object` && !Array.isArray(v);
|
|
3106
|
+
var POINTER = /^(\/([^/~]|~[01])*)*$/;
|
|
3107
|
+
function validatePackage2(pkg, catalogIds = supportedCatalogIds2()) {
|
|
3108
|
+
const issues = [];
|
|
3109
|
+
if (!isObject(pkg))
|
|
3110
|
+
return [{ path: ``, message: `a package is an object` }];
|
|
3111
|
+
for (const key of [`id`, `name`, `version`, `catalogId`])
|
|
3112
|
+
if (typeof pkg[key] !== `string` || !pkg[key])
|
|
3113
|
+
issues.push({ path: `/${key}`, message: `${key} is a required string` });
|
|
3114
|
+
if (typeof pkg.catalogId === `string` && pkg.catalogId && !catalogIds.includes(pkg.catalogId))
|
|
3115
|
+
issues.push({ path: `/catalogId`, message: `unsupported catalog ${pkg.catalogId}` });
|
|
3116
|
+
if (!isObject(pkg.templates) || !Object.keys(pkg.templates).length)
|
|
3117
|
+
issues.push({ path: `/templates`, message: `templates is a non-empty object` });
|
|
3118
|
+
else
|
|
3119
|
+
for (const [id, template] of Object.entries(pkg.templates)) {
|
|
3120
|
+
const at = `/templates/${id}`;
|
|
3121
|
+
if (!isObject(template)) {
|
|
3122
|
+
issues.push({ path: at, message: `a template is an object` });
|
|
3123
|
+
continue;
|
|
3124
|
+
}
|
|
3125
|
+
const components = template.components;
|
|
3126
|
+
if (!Array.isArray(components) || !components.length)
|
|
3127
|
+
issues.push({ path: `${at}/components`, message: `components is a non-empty array` });
|
|
3128
|
+
else {
|
|
3129
|
+
const ids = new Set;
|
|
3130
|
+
components.forEach((c, i) => {
|
|
3131
|
+
if (!isObject(c) || typeof c.id !== `string` || typeof c.component !== `string`)
|
|
3132
|
+
issues.push({ path: `${at}/components/${i}`, message: `a component needs an id and a component` });
|
|
3133
|
+
else if (ids.has(c.id))
|
|
3134
|
+
issues.push({ path: `${at}/components/${i}/id`, message: `duplicate id ${c.id}` });
|
|
3135
|
+
else
|
|
3136
|
+
ids.add(c.id);
|
|
3137
|
+
});
|
|
3138
|
+
if (!ids.has(`root`))
|
|
3139
|
+
issues.push({ path: `${at}/components`, message: `no component has the id root` });
|
|
3140
|
+
}
|
|
3141
|
+
if (template.bindings !== undefined) {
|
|
3142
|
+
if (!Array.isArray(template.bindings))
|
|
3143
|
+
issues.push({ path: `${at}/bindings`, message: `bindings is an array` });
|
|
3144
|
+
else
|
|
3145
|
+
template.bindings.forEach((b, i) => {
|
|
3146
|
+
const bp = `${at}/bindings/${i}`;
|
|
3147
|
+
if (!isObject(b) || typeof b.path !== `string` || !POINTER.test(b.path))
|
|
3148
|
+
issues.push({ path: `${bp}/path`, message: `path is a JSON pointer` });
|
|
3149
|
+
if (!isObject(b) || typeof b.source !== `string` || !parseSource2(b.source))
|
|
3150
|
+
issues.push({ path: `${bp}/source`, message: `source is a scheme:name URI` });
|
|
3151
|
+
});
|
|
3152
|
+
}
|
|
3153
|
+
}
|
|
3154
|
+
if (pkg.functions !== undefined && (!Array.isArray(pkg.functions) || pkg.functions.some((f) => typeof f !== `string` || !f)))
|
|
3155
|
+
issues.push({ path: `/functions`, message: `functions is a list of names or prefix* patterns` });
|
|
3156
|
+
if (pkg.sources !== undefined && (!Array.isArray(pkg.sources) || pkg.sources.some((f) => typeof f !== `string` || !f)))
|
|
3157
|
+
issues.push({ path: `/sources`, message: `sources is a list of scheme:name sources or prefix* patterns` });
|
|
3158
|
+
else if (Array.isArray(pkg.sources) && isObject(pkg.templates))
|
|
3159
|
+
for (const [id, template] of Object.entries(pkg.templates)) {
|
|
3160
|
+
if (!isObject(template) || !Array.isArray(template.bindings))
|
|
3161
|
+
continue;
|
|
3162
|
+
template.bindings.forEach((b, i) => {
|
|
3163
|
+
if (isObject(b) && typeof b.source === `string` && parseSource2(b.source) && !sourceAllowed2(pkg.sources, b.source))
|
|
3164
|
+
issues.push({ path: `/templates/${id}/bindings/${i}/source`, message: `source ${b.source} is not in the package's sources` });
|
|
3165
|
+
});
|
|
3166
|
+
}
|
|
3167
|
+
return issues;
|
|
3168
|
+
}
|
|
3169
|
+
function sourceAllowed2(allowed, source) {
|
|
3170
|
+
if (allowed === undefined)
|
|
3171
|
+
return true;
|
|
3172
|
+
const parsed = parseSource2(source);
|
|
3173
|
+
if (!parsed)
|
|
3174
|
+
return false;
|
|
3175
|
+
const name = `${parsed.scheme}:${parsed.name}`;
|
|
3176
|
+
return allowed.some((p) => matchesPattern2(p, name) || matchesPattern2(p, source));
|
|
3177
|
+
}
|
|
3178
|
+
function templateMessages2(pkg, templateId, surfaceId, data) {
|
|
3179
|
+
const template = pkg.templates[templateId];
|
|
3180
|
+
if (!template)
|
|
3181
|
+
return null;
|
|
3182
|
+
const version = A2UI_VERSION2;
|
|
3183
|
+
const out = [
|
|
3184
|
+
{ version, createSurface: { surfaceId, catalogId: pkg.catalogId } },
|
|
3185
|
+
{ version, updateComponents: { surfaceId, components: template.components } }
|
|
3186
|
+
];
|
|
3187
|
+
const merged = mergeData2(template.data, data);
|
|
3188
|
+
if (merged !== undefined)
|
|
3189
|
+
out.push({ version, updateDataModel: { surfaceId, path: `/`, value: merged } });
|
|
3190
|
+
for (const b of template.bindings ?? [])
|
|
3191
|
+
out.push({ version, bindDataModel: { surfaceId, path: b.path, source: b.source } });
|
|
3192
|
+
return out;
|
|
3193
|
+
}
|
|
3194
|
+
function mergeData2(base, over) {
|
|
3195
|
+
if (over === undefined)
|
|
3196
|
+
return base;
|
|
3197
|
+
if (isObject(base) && isObject(over))
|
|
3198
|
+
return { ...base, ...over };
|
|
3199
|
+
return over;
|
|
3200
|
+
}
|
|
3201
|
+
// packages/exponential-ui/src/host/router.ts
|
|
3202
|
+
var isObject2 = (v) => !!v && typeof v === `object` && !Array.isArray(v);
|
|
3203
|
+
|
|
3204
|
+
class HostRouter2 {
|
|
3205
|
+
extensionIds;
|
|
3206
|
+
surfaces = new Map;
|
|
3207
|
+
packages = new Map;
|
|
3208
|
+
constructor(options = {}) {
|
|
3209
|
+
this.extensionIds = [...options.extensionIds ?? []];
|
|
3210
|
+
}
|
|
3211
|
+
get supportedCatalogIds() {
|
|
3212
|
+
return supportedCatalogIds2(this.extensionIds);
|
|
3213
|
+
}
|
|
3214
|
+
registerExtension(id) {
|
|
3215
|
+
if (!this.extensionIds.includes(id))
|
|
3216
|
+
this.extensionIds.push(id);
|
|
3217
|
+
}
|
|
3218
|
+
installPackage(pkg) {
|
|
3219
|
+
const issues = validatePackage2(pkg, this.supportedCatalogIds);
|
|
3220
|
+
if (!issues.length)
|
|
3221
|
+
this.packages.set(pkg.id, pkg);
|
|
3222
|
+
return issues;
|
|
3223
|
+
}
|
|
3224
|
+
package(id) {
|
|
3225
|
+
return this.packages.get(id);
|
|
3226
|
+
}
|
|
3227
|
+
surface(id) {
|
|
3228
|
+
return this.surfaces.get(id);
|
|
3229
|
+
}
|
|
3230
|
+
surfaceIds() {
|
|
3231
|
+
return [...this.surfaces.keys()];
|
|
3232
|
+
}
|
|
3233
|
+
route(message) {
|
|
3234
|
+
if (oversized2(message))
|
|
3235
|
+
return [this.invalid(isObject2(message) ? surfaceIdOf(message) : ``, LIMIT_ISSUES2.messageBytes)];
|
|
3236
|
+
if (!isObject2(message))
|
|
3237
|
+
return [this.invalid(``, `a message is a JSON object`)];
|
|
3238
|
+
if (message.version !== undefined && message.version !== A2UI_VERSION2)
|
|
3239
|
+
return [this.invalid(surfaceIdOf(message), `unsupported version ${String(message.version)}`)];
|
|
3240
|
+
const kinds = Object.keys(message).filter((k) => k !== `version`);
|
|
3241
|
+
if (kinds.length !== 1 || !MESSAGE_KINDS2.includes(kinds[0]))
|
|
3242
|
+
return [this.invalid(surfaceIdOf(message), `expected exactly one of ${MESSAGE_KINDS2.join(`, `)}`)];
|
|
3243
|
+
const kind = kinds[0];
|
|
3244
|
+
const body = message[kind];
|
|
3245
|
+
if (!isObject2(body) || typeof body.surfaceId !== `string` || !body.surfaceId)
|
|
3246
|
+
return [this.invalid(``, `${kind}.surfaceId is required`)];
|
|
3247
|
+
const surfaceId = body.surfaceId;
|
|
3248
|
+
switch (kind) {
|
|
3249
|
+
case `createSurface`: {
|
|
3250
|
+
if (typeof body.catalogId !== `string`)
|
|
3251
|
+
return [this.invalid(surfaceId, `createSurface.catalogId is required`)];
|
|
3252
|
+
if (!this.supportedCatalogIds.includes(body.catalogId))
|
|
3253
|
+
return [{ op: `send`, message: errorMessage2(`UNSUPPORTED_CATALOG`, surfaceId, `catalog ${body.catalogId} is not supported`) }];
|
|
3254
|
+
this.surfaces.set(surfaceId, { surfaceId, catalogId: body.catalogId });
|
|
3255
|
+
const op = { op: `create`, surfaceId, catalogId: body.catalogId };
|
|
3256
|
+
if (body.theme !== undefined)
|
|
3257
|
+
op.theme = body.theme;
|
|
3258
|
+
if (body.sendDataModel === true)
|
|
3259
|
+
op.sendDataModel = true;
|
|
3260
|
+
return [op];
|
|
3261
|
+
}
|
|
3262
|
+
case `updateComponents`: {
|
|
3263
|
+
if (!Array.isArray(body.components))
|
|
3264
|
+
return [this.invalid(surfaceId, `updateComponents.components is required`)];
|
|
3265
|
+
if (!this.surfaces.has(surfaceId))
|
|
3266
|
+
return [this.missing(surfaceId)];
|
|
3267
|
+
return [{ op: `components`, surfaceId, components: body.components }];
|
|
3268
|
+
}
|
|
3269
|
+
case `updateDataModel`: {
|
|
3270
|
+
if (!this.surfaces.has(surfaceId))
|
|
3271
|
+
return [this.missing(surfaceId)];
|
|
3272
|
+
if (body.path !== undefined && typeof body.path !== `string`)
|
|
3273
|
+
return [this.invalid(surfaceId, `updateDataModel.path is a string`)];
|
|
3274
|
+
const path = normalizePath2(body.path);
|
|
3275
|
+
return [`value` in body ? { op: `data`, surfaceId, path, value: body.value } : { op: `data`, surfaceId, path }];
|
|
3276
|
+
}
|
|
3277
|
+
case `deleteSurface`: {
|
|
3278
|
+
if (!this.surfaces.has(surfaceId))
|
|
3279
|
+
return [this.missing(surfaceId)];
|
|
3280
|
+
this.surfaces.delete(surfaceId);
|
|
3281
|
+
return [{ op: `delete`, surfaceId }];
|
|
3282
|
+
}
|
|
3283
|
+
case `bindDataModel`: {
|
|
3284
|
+
const info = this.surfaces.get(surfaceId);
|
|
3285
|
+
if (!info)
|
|
3286
|
+
return [this.missing(surfaceId)];
|
|
3287
|
+
if (typeof body.path !== `string` || typeof body.source !== `string` || !parseSource2(body.source))
|
|
3288
|
+
return [this.invalid(surfaceId, `bindDataModel needs a path and a scheme:name source`)];
|
|
3289
|
+
const pkg = info.packageId ? this.packages.get(info.packageId) : undefined;
|
|
3290
|
+
if (pkg && !sourceAllowed2(pkg.sources, body.source))
|
|
3291
|
+
return [{ op: `send`, message: errorMessage2(`SOURCE_DENIED`, surfaceId, `source ${body.source} is not in package ${pkg.id}'s sources`, normalizePath2(body.path) || `/`) }];
|
|
3292
|
+
return [{ op: `bind`, surfaceId, path: normalizePath2(body.path), source: body.source }];
|
|
3293
|
+
}
|
|
3294
|
+
case `applyTemplate`: {
|
|
3295
|
+
if (typeof body.templateId !== `string`)
|
|
3296
|
+
return [this.invalid(surfaceId, `applyTemplate.templateId is required`)];
|
|
3297
|
+
const pkg = this.findPackage(body.templateId, typeof body.packageId === `string` ? body.packageId : undefined);
|
|
3298
|
+
if (!pkg)
|
|
3299
|
+
return [{ op: `send`, message: errorMessage2(`TEMPLATE_NOT_FOUND`, surfaceId, `no installed package has the template ${body.templateId}`) }];
|
|
3300
|
+
const ops = [];
|
|
3301
|
+
for (const m of templateMessages2(pkg, body.templateId, surfaceId, body.data) ?? []) {
|
|
3302
|
+
ops.push(...this.route(m));
|
|
3303
|
+
const info = this.surfaces.get(surfaceId);
|
|
3304
|
+
if (info)
|
|
3305
|
+
info.packageId = pkg.id;
|
|
3306
|
+
}
|
|
3307
|
+
return ops;
|
|
3308
|
+
}
|
|
3309
|
+
}
|
|
3310
|
+
return [this.invalid(surfaceId, `unknown message`)];
|
|
3311
|
+
}
|
|
3312
|
+
findPackage(templateId, packageId) {
|
|
3313
|
+
if (packageId !== undefined) {
|
|
3314
|
+
const pkg = this.packages.get(packageId);
|
|
3315
|
+
return pkg && pkg.templates[templateId] ? pkg : undefined;
|
|
3316
|
+
}
|
|
3317
|
+
for (const pkg of this.packages.values())
|
|
3318
|
+
if (pkg.templates[templateId])
|
|
3319
|
+
return pkg;
|
|
3320
|
+
return;
|
|
3321
|
+
}
|
|
3322
|
+
invalid(surfaceId, message) {
|
|
3323
|
+
return { op: `send`, message: errorMessage2(`INVALID_MESSAGE`, surfaceId, message) };
|
|
3324
|
+
}
|
|
3325
|
+
missing(surfaceId) {
|
|
3326
|
+
return { op: `send`, message: errorMessage2(`SURFACE_NOT_FOUND`, surfaceId, `no surface ${surfaceId}; send createSurface first`) };
|
|
3327
|
+
}
|
|
3328
|
+
}
|
|
3329
|
+
function oversized2(message) {
|
|
3330
|
+
let text;
|
|
3331
|
+
try {
|
|
3332
|
+
text = JSON.stringify(message);
|
|
3333
|
+
} catch {
|
|
3334
|
+
return false;
|
|
3335
|
+
}
|
|
3336
|
+
if (text === undefined || text.length * 3 <= MAX_MESSAGE_BYTES2)
|
|
3337
|
+
return false;
|
|
3338
|
+
return text.length > MAX_MESSAGE_BYTES2 || new TextEncoder().encode(text).length > MAX_MESSAGE_BYTES2;
|
|
3339
|
+
}
|
|
3340
|
+
function surfaceIdOf(message) {
|
|
3341
|
+
for (const v of Object.values(message))
|
|
3342
|
+
if (isObject2(v) && typeof v.surfaceId === `string`)
|
|
3343
|
+
return v.surfaceId;
|
|
3344
|
+
return ``;
|
|
3345
|
+
}
|
|
3346
|
+
function normalizePath2(path) {
|
|
3347
|
+
return path === undefined || path === `/` ? `` : path;
|
|
3348
|
+
}
|
|
3349
|
+
// packages/exponential-ui/src/host/runtime.ts
|
|
3350
|
+
class PackageError2 extends Error {
|
|
3351
|
+
packageId;
|
|
3352
|
+
issues;
|
|
3353
|
+
constructor(packageId, issues) {
|
|
3354
|
+
super(`exponential-ui: package ${packageId} is unusable: ${issues.map((i) => `${i.path || `/`} ${i.message}`).join(`; `)}`);
|
|
3355
|
+
this.packageId = packageId;
|
|
3356
|
+
this.issues = issues;
|
|
3357
|
+
this.name = `PackageError`;
|
|
3358
|
+
}
|
|
3359
|
+
}
|
|
3360
|
+
var MAX_ISSUES = 100;
|
|
3361
|
+
function resolveSurfaceTheme2(input) {
|
|
3362
|
+
if (typeof input === `string`) {
|
|
3363
|
+
if (!BUILTIN_THEME_IDS2.includes(input))
|
|
3364
|
+
return { theme: null, issues: [`unknown built-in theme "${input}"; known: ${BUILTIN_THEME_IDS2.join(`|`)}`] };
|
|
3365
|
+
return { theme: builtinTheme2(input), issues: [] };
|
|
3366
|
+
}
|
|
3367
|
+
const { theme, issues } = tryLoadTheme2(input, { themes: BUILTIN_THEMES2 });
|
|
3368
|
+
return { theme, issues: issues.map((i) => i.path ? `${i.path}: ${i.message}` : i.message) };
|
|
3369
|
+
}
|
|
3370
|
+
|
|
3371
|
+
class SurfaceStore2 {
|
|
3372
|
+
extensions;
|
|
3373
|
+
surfaceId;
|
|
3374
|
+
catalogId;
|
|
3375
|
+
packageId;
|
|
3376
|
+
sendDataModel = false;
|
|
3377
|
+
list = [];
|
|
3378
|
+
shared = false;
|
|
3379
|
+
positions = new Map;
|
|
3380
|
+
data = {};
|
|
3381
|
+
theme;
|
|
3382
|
+
reduced = null;
|
|
3383
|
+
listeners = new Set;
|
|
3384
|
+
version = 0;
|
|
3385
|
+
constructor(surfaceId, catalogId, extensions) {
|
|
3386
|
+
this.extensions = extensions;
|
|
3387
|
+
this.surfaceId = surfaceId;
|
|
3388
|
+
this.catalogId = catalogId;
|
|
3389
|
+
}
|
|
3390
|
+
get components() {
|
|
3391
|
+
this.shared = true;
|
|
3392
|
+
return this.list;
|
|
3393
|
+
}
|
|
3394
|
+
component(id) {
|
|
3395
|
+
const at = this.positions.get(id);
|
|
3396
|
+
return at === undefined ? undefined : this.list[at];
|
|
3397
|
+
}
|
|
3398
|
+
get root() {
|
|
3399
|
+
return this.reduce().root;
|
|
3400
|
+
}
|
|
3401
|
+
get issues() {
|
|
3402
|
+
return this.reduce().issues;
|
|
3403
|
+
}
|
|
3404
|
+
get templates() {
|
|
3405
|
+
return this.reduce().templates;
|
|
3406
|
+
}
|
|
3407
|
+
reduce() {
|
|
3408
|
+
if (!this.reduced)
|
|
3409
|
+
this.reduced = this.list.length ? reduceSurface2(this.list, { catalogId: this.catalogId, extensions: this.extensions() }) : { root: null, issues: [] };
|
|
3410
|
+
return this.reduced;
|
|
3411
|
+
}
|
|
3412
|
+
setComponents(components) {
|
|
3413
|
+
if (this.shared) {
|
|
3414
|
+
this.list = this.list.slice();
|
|
3415
|
+
this.shared = false;
|
|
3416
|
+
}
|
|
3417
|
+
for (const c of components) {
|
|
3418
|
+
const at = this.positions.get(c.id);
|
|
3419
|
+
if (at === undefined) {
|
|
3420
|
+
this.positions.set(c.id, this.list.length);
|
|
3421
|
+
this.list.push(c);
|
|
3422
|
+
} else
|
|
3423
|
+
this.list[at] = c;
|
|
3424
|
+
}
|
|
3425
|
+
this.reduced = null;
|
|
3426
|
+
this.notify();
|
|
3427
|
+
}
|
|
3428
|
+
invalidate() {
|
|
3429
|
+
this.reduced = null;
|
|
3430
|
+
this.notify();
|
|
3431
|
+
}
|
|
3432
|
+
setData(pointer, value) {
|
|
3433
|
+
const written = writePointer2(this.data, pointer, value);
|
|
3434
|
+
if (written.error)
|
|
3435
|
+
return written.error;
|
|
3436
|
+
this.data = written.data;
|
|
3437
|
+
this.notify();
|
|
3438
|
+
return;
|
|
3439
|
+
}
|
|
3440
|
+
subscribe(listener) {
|
|
3441
|
+
this.listeners.add(listener);
|
|
3442
|
+
return () => this.listeners.delete(listener);
|
|
3443
|
+
}
|
|
3444
|
+
notify() {
|
|
3445
|
+
this.version += 1;
|
|
3446
|
+
for (const l of [...this.listeners])
|
|
3447
|
+
l();
|
|
3448
|
+
}
|
|
3449
|
+
}
|
|
3450
|
+
|
|
3451
|
+
class ExponentialHost2 {
|
|
3452
|
+
options;
|
|
3453
|
+
router;
|
|
3454
|
+
stores = new Map;
|
|
3455
|
+
subscriptions = new Map;
|
|
3456
|
+
paintErrors = new Map;
|
|
3457
|
+
listeners = new Set;
|
|
3458
|
+
functions;
|
|
3459
|
+
sources;
|
|
3460
|
+
extensions;
|
|
3461
|
+
status = `closed`;
|
|
3462
|
+
statusDetail;
|
|
3463
|
+
unsupportedCatalog;
|
|
3464
|
+
issues = [];
|
|
3465
|
+
constructor(options = {}) {
|
|
3466
|
+
this.options = options;
|
|
3467
|
+
this.extensions = [...options.extensions ?? []];
|
|
3468
|
+
this.router = new HostRouter2({ extensionIds: this.extensions.map((e) => e.id) });
|
|
3469
|
+
this.functions = { ...options.functions ?? {} };
|
|
3470
|
+
this.sources = { ...options.sources ?? {} };
|
|
3471
|
+
for (const pkg of options.packages ?? []) {
|
|
3472
|
+
const issues = this.installPackage(pkg);
|
|
3473
|
+
if (issues.length)
|
|
3474
|
+
throw new PackageError2(typeof pkg?.id === `string` && pkg.id ? pkg.id : `?`, issues);
|
|
3475
|
+
}
|
|
3476
|
+
}
|
|
3477
|
+
get hasTransport() {
|
|
3478
|
+
return this.options.transport !== undefined;
|
|
3479
|
+
}
|
|
3480
|
+
get supportedCatalogIds() {
|
|
3481
|
+
return this.router.supportedCatalogIds;
|
|
3482
|
+
}
|
|
3483
|
+
clientCapabilities() {
|
|
3484
|
+
return clientCapabilities2(this.extensions.map((e) => e.id));
|
|
3485
|
+
}
|
|
3486
|
+
get extensionDefs() {
|
|
3487
|
+
return this.extensions;
|
|
3488
|
+
}
|
|
3489
|
+
registerExtension(ext) {
|
|
3490
|
+
if (this.extensions.some((e) => e.id === ext.id))
|
|
3491
|
+
return;
|
|
3492
|
+
this.extensions.push(ext);
|
|
3493
|
+
this.router.registerExtension(ext.id);
|
|
3494
|
+
for (const store of this.stores.values())
|
|
3495
|
+
store.invalidate();
|
|
3496
|
+
}
|
|
3497
|
+
registerFunction(name, fn) {
|
|
3498
|
+
this.functions[name] = fn;
|
|
3499
|
+
}
|
|
3500
|
+
registerSource(scheme, resolver) {
|
|
3501
|
+
this.sources[scheme.toLowerCase()] = resolver;
|
|
3502
|
+
}
|
|
3503
|
+
installPackage(pkg) {
|
|
3504
|
+
const issues = this.router.installPackage(pkg);
|
|
3505
|
+
const packageId = typeof pkg?.id === `string` ? pkg.id : undefined;
|
|
3506
|
+
for (const i of issues)
|
|
3507
|
+
this.report({ code: `PACKAGE_INVALID`, message: i.message, path: i.path, ...packageId ? { packageId } : {} });
|
|
3508
|
+
return issues;
|
|
3509
|
+
}
|
|
3510
|
+
report(issue) {
|
|
3511
|
+
const next = [...this.issues, issue];
|
|
3512
|
+
this.issues = next.length > MAX_ISSUES ? next.slice(next.length - MAX_ISSUES) : next;
|
|
3513
|
+
this.options.onIssue?.(issue);
|
|
3514
|
+
this.notify();
|
|
3515
|
+
}
|
|
3516
|
+
surface(id) {
|
|
3517
|
+
return this.stores.get(id);
|
|
3518
|
+
}
|
|
3519
|
+
surfaceIds() {
|
|
3520
|
+
return [...this.stores.keys()];
|
|
3521
|
+
}
|
|
3522
|
+
subscribe(listener) {
|
|
3523
|
+
this.listeners.add(listener);
|
|
3524
|
+
return () => this.listeners.delete(listener);
|
|
3525
|
+
}
|
|
3526
|
+
notify() {
|
|
3527
|
+
for (const l of [...this.listeners])
|
|
3528
|
+
l();
|
|
3529
|
+
}
|
|
3530
|
+
connect() {
|
|
3531
|
+
const t = this.options.transport;
|
|
3532
|
+
if (!t)
|
|
3533
|
+
return;
|
|
3534
|
+
t.start((m) => this.receive(m), (status, detail) => {
|
|
3535
|
+
this.status = status;
|
|
3536
|
+
this.statusDetail = detail;
|
|
3537
|
+
this.notify();
|
|
3538
|
+
});
|
|
3539
|
+
}
|
|
3540
|
+
close() {
|
|
3541
|
+
this.options.transport?.close();
|
|
3542
|
+
for (const id of this.surfaceIds())
|
|
3543
|
+
this.perform({ op: `delete`, surfaceId: id });
|
|
3544
|
+
}
|
|
3545
|
+
receive(message) {
|
|
3546
|
+
const ops = this.router.route(message);
|
|
3547
|
+
for (const op of ops)
|
|
3548
|
+
this.perform(op);
|
|
3549
|
+
return ops;
|
|
3550
|
+
}
|
|
3551
|
+
send(message) {
|
|
3552
|
+
this.options.transport?.send(message);
|
|
3553
|
+
this.options.onSend?.(message);
|
|
3554
|
+
if (`error` in message) {
|
|
3555
|
+
const e = message.error;
|
|
3556
|
+
this.report({ code: e.code, message: e.message, ...e.surfaceId ? { surfaceId: e.surfaceId } : {}, ...e.path !== undefined ? { path: e.path } : {} });
|
|
3557
|
+
}
|
|
3558
|
+
}
|
|
3559
|
+
perform(op) {
|
|
3560
|
+
this.options.onOp?.(op);
|
|
3561
|
+
switch (op.op) {
|
|
3562
|
+
case `create`: {
|
|
3563
|
+
this.unbind(op.surfaceId);
|
|
3564
|
+
this.forgetPaintErrors(op.surfaceId);
|
|
3565
|
+
const store = new SurfaceStore2(op.surfaceId, op.catalogId, () => this.extensions);
|
|
3566
|
+
store.sendDataModel = op.sendDataModel === true;
|
|
3567
|
+
store.packageId = this.router.surface(op.surfaceId)?.packageId;
|
|
3568
|
+
if (op.theme !== undefined && op.theme !== null) {
|
|
3569
|
+
const { theme, issues } = resolveSurfaceTheme2(op.theme);
|
|
3570
|
+
if (theme)
|
|
3571
|
+
store.theme = theme;
|
|
3572
|
+
else
|
|
3573
|
+
this.send(errorMessage2(`VALIDATION_FAILED`, op.surfaceId, `createSurface.theme is unusable: ${issues.join(`; `)}`, `/createSurface/theme`));
|
|
3574
|
+
}
|
|
3575
|
+
this.stores.set(op.surfaceId, store);
|
|
3576
|
+
this.notify();
|
|
3577
|
+
return;
|
|
3578
|
+
}
|
|
3579
|
+
case `components`: {
|
|
3580
|
+
const failed = this.paintErrors.get(op.surfaceId);
|
|
3581
|
+
if (failed)
|
|
3582
|
+
for (const c of op.components)
|
|
3583
|
+
failed.delete(c.id);
|
|
3584
|
+
this.stores.get(op.surfaceId)?.setComponents(op.components);
|
|
3585
|
+
return;
|
|
3586
|
+
}
|
|
3587
|
+
case `data`: {
|
|
3588
|
+
const error = this.stores.get(op.surfaceId)?.setData(op.path, op.value);
|
|
3589
|
+
if (error)
|
|
3590
|
+
this.send(errorMessage2(`VALIDATION_FAILED`, op.surfaceId, error, op.path || `/`));
|
|
3591
|
+
return;
|
|
3592
|
+
}
|
|
3593
|
+
case `bind`: {
|
|
3594
|
+
const store = this.stores.get(op.surfaceId);
|
|
3595
|
+
const source = parseSource2(op.source);
|
|
3596
|
+
const resolver = source ? this.sources[source.scheme] : undefined;
|
|
3597
|
+
if (!store || !source)
|
|
3598
|
+
return;
|
|
3599
|
+
if (!resolver) {
|
|
3600
|
+
this.send(errorMessage2(`VALIDATION_FAILED`, op.surfaceId, `no resolver for the source scheme ${source.scheme}`, op.path || `/`));
|
|
3601
|
+
return;
|
|
3602
|
+
}
|
|
3603
|
+
const cancel = resolver(source, (value) => this.stores.get(op.surfaceId)?.setData(op.path, value));
|
|
3604
|
+
if (cancel)
|
|
3605
|
+
this.subscriptions.set(op.surfaceId, [...this.subscriptions.get(op.surfaceId) ?? [], cancel]);
|
|
3606
|
+
return;
|
|
3607
|
+
}
|
|
3608
|
+
case `delete`:
|
|
3609
|
+
this.unbind(op.surfaceId);
|
|
3610
|
+
this.forgetPaintErrors(op.surfaceId);
|
|
3611
|
+
this.stores.delete(op.surfaceId);
|
|
3612
|
+
this.notify();
|
|
3613
|
+
return;
|
|
3614
|
+
case `send`: {
|
|
3615
|
+
const err = `error` in op.message ? op.message.error : undefined;
|
|
3616
|
+
if (err?.code === `UNSUPPORTED_CATALOG`) {
|
|
3617
|
+
this.unsupportedCatalog = err.message.replace(/^catalog (\S+).*$/, `$1`);
|
|
3618
|
+
this.notify();
|
|
3619
|
+
}
|
|
3620
|
+
this.send(op.message);
|
|
3621
|
+
return;
|
|
3622
|
+
}
|
|
3623
|
+
}
|
|
3624
|
+
}
|
|
3625
|
+
unbind(surfaceId) {
|
|
3626
|
+
for (const cancel of this.subscriptions.get(surfaceId) ?? [])
|
|
3627
|
+
cancel();
|
|
3628
|
+
this.subscriptions.delete(surfaceId);
|
|
3629
|
+
}
|
|
3630
|
+
action(event) {
|
|
3631
|
+
const message = actionMessage2({
|
|
3632
|
+
name: event.name,
|
|
3633
|
+
surfaceId: event.surfaceId,
|
|
3634
|
+
sourceComponentId: event.componentId,
|
|
3635
|
+
timestamp: event.timestamp ?? new Date().toISOString(),
|
|
3636
|
+
context: event.context ?? {},
|
|
3637
|
+
payload: event.payload
|
|
3638
|
+
});
|
|
3639
|
+
this.send(message);
|
|
3640
|
+
return message;
|
|
3641
|
+
}
|
|
3642
|
+
decide(surfaceId, name) {
|
|
3643
|
+
const registered = Object.prototype.hasOwnProperty.call(this.functions, name);
|
|
3644
|
+
let decision = decideFunction2(this.options.policy?.functions, name, registered);
|
|
3645
|
+
const pkgId = this.stores.get(surfaceId)?.packageId;
|
|
3646
|
+
const pkg = pkgId ? this.router.package(pkgId) : undefined;
|
|
3647
|
+
if (pkg)
|
|
3648
|
+
decision = combineDecisions2(decision, decideFunction2(packagePolicy2(pkg.functions), name, registered));
|
|
3649
|
+
return decision;
|
|
3650
|
+
}
|
|
3651
|
+
async callFunction(call) {
|
|
3652
|
+
if (call.name === `openUrl`) {
|
|
3653
|
+
const url = typeof call.args.url === `string` ? call.args.url : ``;
|
|
3654
|
+
return { decision: this.openUrl(url) ? `allow` : `deny` };
|
|
3655
|
+
}
|
|
3656
|
+
let decision = this.decide(call.surfaceId, call.name);
|
|
3657
|
+
if (decision === `not_found`) {
|
|
3658
|
+
this.send(errorMessage2(`FUNCTION_NOT_FOUND`, call.surfaceId, `no function ${call.name}`));
|
|
3659
|
+
return { decision };
|
|
3660
|
+
}
|
|
3661
|
+
let consentError;
|
|
3662
|
+
if (decision === `ask`) {
|
|
3663
|
+
let ok = false;
|
|
3664
|
+
try {
|
|
3665
|
+
ok = await this.options.policy?.onFunctionCall?.(call) === true;
|
|
3666
|
+
} catch (e) {
|
|
3667
|
+
consentError = e instanceof Error ? e.message : String(e);
|
|
3668
|
+
}
|
|
3669
|
+
if (!ok)
|
|
3670
|
+
decision = `deny`;
|
|
3671
|
+
}
|
|
3672
|
+
if (decision === `deny`) {
|
|
3673
|
+
this.send(errorMessage2(`FUNCTION_DENIED`, call.surfaceId, consentError === undefined ? `${call.name} was not allowed` : `${call.name} was not allowed: the consent hook failed: ${consentError}`));
|
|
3674
|
+
return consentError === undefined ? { decision } : { decision, error: consentError };
|
|
3675
|
+
}
|
|
3676
|
+
const fn = Object.prototype.hasOwnProperty.call(this.functions, call.name) ? this.functions[call.name] : undefined;
|
|
3677
|
+
if (!fn)
|
|
3678
|
+
return { decision: `allow` };
|
|
3679
|
+
try {
|
|
3680
|
+
return { decision: `allow`, result: await fn(call.args, call) };
|
|
3681
|
+
} catch (e) {
|
|
3682
|
+
return { decision: `allow`, error: e instanceof Error ? e.message : String(e) };
|
|
3683
|
+
}
|
|
3684
|
+
}
|
|
3685
|
+
urlPolicy() {
|
|
3686
|
+
return { baseUrl: this.options.policy?.media?.baseUrl, ...this.options.policy?.urls };
|
|
3687
|
+
}
|
|
3688
|
+
openUrl(url) {
|
|
3689
|
+
const d = decideUrl2(this.urlPolicy(), url);
|
|
3690
|
+
if (!d.allowed || !d.url)
|
|
3691
|
+
return false;
|
|
3692
|
+
const open = this.options.policy?.openUrl ?? ((u) => globalThis.window?.open(u, `_blank`, `noopener`));
|
|
3693
|
+
open(d.url);
|
|
3694
|
+
return true;
|
|
3695
|
+
}
|
|
3696
|
+
paintError(error) {
|
|
3697
|
+
const store = this.stores.get(error.surfaceId);
|
|
3698
|
+
let owner = error.componentId;
|
|
3699
|
+
while (store && !store.component(owner) && owner.includes(`.`))
|
|
3700
|
+
owner = owner.slice(0, owner.lastIndexOf(`.`));
|
|
3701
|
+
const current = store?.component(owner);
|
|
3702
|
+
let failed = this.paintErrors.get(error.surfaceId);
|
|
3703
|
+
if (!failed)
|
|
3704
|
+
this.paintErrors.set(error.surfaceId, failed = new Map);
|
|
3705
|
+
let entry = failed.get(owner);
|
|
3706
|
+
if (!entry || entry.component !== current)
|
|
3707
|
+
failed.set(owner, entry = { component: current, ids: new Set });
|
|
3708
|
+
if (entry.ids.has(error.componentId))
|
|
3709
|
+
return;
|
|
3710
|
+
entry.ids.add(error.componentId);
|
|
3711
|
+
this.send(errorMessage2(RENDER_FAILED2, error.surfaceId, error.message, `/components/${error.componentId}`));
|
|
3712
|
+
}
|
|
3713
|
+
forgetPaintErrors(surfaceId) {
|
|
3714
|
+
this.paintErrors.delete(surfaceId);
|
|
3715
|
+
}
|
|
3716
|
+
mediaOptions() {
|
|
3717
|
+
return this.options.policy?.media;
|
|
3718
|
+
}
|
|
3719
|
+
mediaRequest(url) {
|
|
3720
|
+
return mediaRequest2(url, this.options.policy?.media);
|
|
3721
|
+
}
|
|
3722
|
+
}
|
|
3723
|
+
// packages/exponential-ui/src/host/transports.ts
|
|
3724
|
+
class MemoryTransport2 {
|
|
3725
|
+
sent = [];
|
|
3726
|
+
receiveFn;
|
|
3727
|
+
pending = [];
|
|
3728
|
+
onSend;
|
|
3729
|
+
start(receive, status) {
|
|
3730
|
+
this.receiveFn = receive;
|
|
3731
|
+
status(`open`);
|
|
3732
|
+
const queued = this.pending;
|
|
3733
|
+
this.pending = [];
|
|
3734
|
+
queued.forEach(receive);
|
|
3735
|
+
}
|
|
3736
|
+
feed(...messages) {
|
|
3737
|
+
if (!this.receiveFn)
|
|
3738
|
+
this.pending.push(...messages);
|
|
3739
|
+
else
|
|
3740
|
+
messages.forEach(this.receiveFn);
|
|
3741
|
+
}
|
|
3742
|
+
feedJsonl(text) {
|
|
3743
|
+
this.feed(...decodeJsonl2(text).messages);
|
|
3744
|
+
}
|
|
3745
|
+
send(message) {
|
|
3746
|
+
this.sent.push(message);
|
|
3747
|
+
this.onSend?.(message);
|
|
3748
|
+
}
|
|
3749
|
+
close() {
|
|
3750
|
+
this.receiveFn = undefined;
|
|
3751
|
+
}
|
|
3752
|
+
}
|
|
3753
|
+
|
|
3754
|
+
class StreamTransport {
|
|
3755
|
+
options;
|
|
3756
|
+
controller;
|
|
3757
|
+
generation = 0;
|
|
3758
|
+
constructor(options) {
|
|
3759
|
+
this.options = options;
|
|
3760
|
+
}
|
|
3761
|
+
start(receive, status) {
|
|
3762
|
+
this.controller?.abort();
|
|
3763
|
+
const gen = ++this.generation;
|
|
3764
|
+
this.run(gen, receive, status);
|
|
3765
|
+
}
|
|
3766
|
+
async run(gen, receive, status) {
|
|
3767
|
+
const f = this.options.fetch ?? fetch;
|
|
3768
|
+
const live = () => gen === this.generation;
|
|
3769
|
+
while (live()) {
|
|
3770
|
+
const controller = new AbortController;
|
|
3771
|
+
this.controller = controller;
|
|
3772
|
+
status(`connecting`);
|
|
3773
|
+
let wait = this.options.reconnectMs ?? 2000;
|
|
3774
|
+
try {
|
|
3775
|
+
const res = await f(this.options.url, { headers: { accept: this.accept(), ...this.options.headers }, signal: controller.signal });
|
|
3776
|
+
if (!live())
|
|
3777
|
+
return;
|
|
3778
|
+
if (!res.ok || !res.body)
|
|
3779
|
+
throw new Error(`HTTP ${res.status}`);
|
|
3780
|
+
status(`open`);
|
|
3781
|
+
const reader = res.body.getReader();
|
|
3782
|
+
const text = new TextDecoder;
|
|
3783
|
+
const dec = this.decoder();
|
|
3784
|
+
for (;; ) {
|
|
3785
|
+
const { done, value } = await reader.read();
|
|
3786
|
+
if (!live())
|
|
3787
|
+
return;
|
|
3788
|
+
if (done)
|
|
3789
|
+
break;
|
|
3790
|
+
dec.push(text.decode(value, { stream: true })).messages.forEach(receive);
|
|
3791
|
+
}
|
|
3792
|
+
dec.end().messages.forEach(receive);
|
|
3793
|
+
status(`closed`);
|
|
3794
|
+
const resumable = this.options.resumable === true || dec.retryMs !== undefined;
|
|
3795
|
+
if (!resumable) {
|
|
3796
|
+
if (live())
|
|
3797
|
+
this.generation += 1;
|
|
3798
|
+
return;
|
|
3799
|
+
}
|
|
3800
|
+
if (dec.retryMs !== undefined && this.options.reconnectMs === undefined)
|
|
3801
|
+
wait = dec.retryMs;
|
|
3802
|
+
} catch (e) {
|
|
3803
|
+
if (!live())
|
|
3804
|
+
return;
|
|
3805
|
+
status(`error`, e instanceof Error ? e.message : String(e));
|
|
3806
|
+
}
|
|
3807
|
+
if (!wait || !live())
|
|
3808
|
+
return;
|
|
3809
|
+
await new Promise((r) => setTimeout(r, wait));
|
|
3810
|
+
}
|
|
3811
|
+
}
|
|
3812
|
+
async send(message) {
|
|
3813
|
+
const f = this.options.fetch ?? fetch;
|
|
3814
|
+
await f(this.options.postUrl ?? this.options.url, { method: `POST`, headers: { "content-type": `application/json`, ...this.options.headers }, body: JSON.stringify(message) });
|
|
3815
|
+
}
|
|
3816
|
+
close() {
|
|
3817
|
+
this.generation += 1;
|
|
3818
|
+
this.controller?.abort();
|
|
3819
|
+
}
|
|
3820
|
+
}
|
|
3821
|
+
|
|
3822
|
+
class JsonlStreamTransport2 extends StreamTransport {
|
|
3823
|
+
decoder() {
|
|
3824
|
+
return new JsonlDecoder2;
|
|
3825
|
+
}
|
|
3826
|
+
accept() {
|
|
3827
|
+
return `application/jsonl, application/x-ndjson`;
|
|
3828
|
+
}
|
|
3829
|
+
}
|
|
3830
|
+
|
|
3831
|
+
class SseTransport2 extends StreamTransport {
|
|
3832
|
+
decoder() {
|
|
3833
|
+
return new SseDecoder2;
|
|
3834
|
+
}
|
|
3835
|
+
accept() {
|
|
3836
|
+
return `text/event-stream`;
|
|
3837
|
+
}
|
|
3838
|
+
}
|
|
3839
|
+
|
|
3840
|
+
class WebSocketTransport2 {
|
|
3841
|
+
options;
|
|
3842
|
+
socket;
|
|
3843
|
+
generation = 0;
|
|
3844
|
+
constructor(options) {
|
|
3845
|
+
this.options = options;
|
|
3846
|
+
}
|
|
3847
|
+
start(receive, status) {
|
|
3848
|
+
const gen = ++this.generation;
|
|
3849
|
+
const live = () => gen === this.generation;
|
|
3850
|
+
const WS = this.options.WebSocket ?? WebSocket;
|
|
3851
|
+
status(`connecting`);
|
|
3852
|
+
const socket = new WS(this.options.url, this.options.protocols);
|
|
3853
|
+
this.socket = socket;
|
|
3854
|
+
socket.onopen = () => live() && status(`open`);
|
|
3855
|
+
socket.onmessage = (ev) => {
|
|
3856
|
+
if (live() && typeof ev.data === `string`)
|
|
3857
|
+
decodeJsonl2(ev.data).messages.forEach(receive);
|
|
3858
|
+
};
|
|
3859
|
+
socket.onerror = () => live() && status(`error`, `websocket error`);
|
|
3860
|
+
socket.onclose = () => {
|
|
3861
|
+
if (!live())
|
|
3862
|
+
return;
|
|
3863
|
+
status(`closed`);
|
|
3864
|
+
const wait = this.options.reconnectMs ?? 2000;
|
|
3865
|
+
if (wait)
|
|
3866
|
+
setTimeout(() => live() && this.start(receive, status), wait);
|
|
3867
|
+
};
|
|
3868
|
+
}
|
|
3869
|
+
send(message) {
|
|
3870
|
+
if (this.socket?.readyState === 1)
|
|
3871
|
+
this.socket.send(JSON.stringify(message));
|
|
3872
|
+
}
|
|
3873
|
+
close() {
|
|
3874
|
+
this.generation += 1;
|
|
3875
|
+
this.socket?.close();
|
|
3876
|
+
}
|
|
3877
|
+
}
|
|
3878
|
+
|
|
3879
|
+
class McpTransport2 {
|
|
3880
|
+
options;
|
|
3881
|
+
id = 0;
|
|
3882
|
+
receiveFn;
|
|
3883
|
+
session;
|
|
3884
|
+
constructor(options) {
|
|
3885
|
+
this.options = options;
|
|
3886
|
+
}
|
|
3887
|
+
start(receive, status) {
|
|
3888
|
+
this.receiveFn = receive;
|
|
3889
|
+
status(`connecting`);
|
|
3890
|
+
(async () => {
|
|
3891
|
+
try {
|
|
3892
|
+
await this.rpc(`initialize`, { protocolVersion: `2025-06-18`, capabilities: {}, clientInfo: { name: `exponential-ui`, version: `0.1.0` } });
|
|
3893
|
+
const result = await this.rpc(`tools/call`, { name: this.options.tool, arguments: this.options.arguments ?? {} });
|
|
3894
|
+
status(`open`);
|
|
3895
|
+
messagesFromMcpResult2(result).messages.forEach(receive);
|
|
3896
|
+
} catch (e) {
|
|
3897
|
+
status(`error`, e instanceof Error ? e.message : String(e));
|
|
3898
|
+
}
|
|
3899
|
+
})();
|
|
3900
|
+
}
|
|
3901
|
+
async send(message) {
|
|
3902
|
+
const call = mcpActionCall2(message, this.options.actionTool);
|
|
3903
|
+
const result = await this.rpc(call.method, call.params);
|
|
3904
|
+
if (this.receiveFn)
|
|
3905
|
+
messagesFromMcpResult2(result).messages.forEach(this.receiveFn);
|
|
3906
|
+
}
|
|
3907
|
+
close() {
|
|
3908
|
+
this.receiveFn = undefined;
|
|
3909
|
+
}
|
|
3910
|
+
async rpc(method, params) {
|
|
3911
|
+
const f = this.options.fetch ?? fetch;
|
|
3912
|
+
const id = ++this.id;
|
|
3913
|
+
const res = await f(this.options.url, {
|
|
3914
|
+
method: `POST`,
|
|
3915
|
+
headers: { "content-type": `application/json`, accept: `application/json, text/event-stream`, ...this.session ? { "mcp-session-id": this.session } : {}, ...this.options.headers },
|
|
3916
|
+
body: JSON.stringify({ jsonrpc: `2.0`, id, method, params })
|
|
3917
|
+
});
|
|
3918
|
+
const session = res.headers.get(`mcp-session-id`);
|
|
3919
|
+
if (session)
|
|
3920
|
+
this.session = session;
|
|
3921
|
+
if (!res.ok)
|
|
3922
|
+
throw new Error(`MCP HTTP ${res.status}`);
|
|
3923
|
+
const type = res.headers.get(`content-type`) ?? ``;
|
|
3924
|
+
const body = await res.text();
|
|
3925
|
+
const replies = type.includes(`text/event-stream`) ? (() => {
|
|
3926
|
+
const d = new SseDecoder2;
|
|
3927
|
+
return [...d.push(body).messages, ...d.end().messages];
|
|
3928
|
+
})() : [JSON.parse(body)];
|
|
3929
|
+
const reply = replies.find((r) => r?.id === id);
|
|
3930
|
+
if (!reply)
|
|
3931
|
+
throw new Error(`MCP: no reply to ${method}`);
|
|
3932
|
+
if (reply.error)
|
|
3933
|
+
throw new Error(`MCP: ${reply.error.message ?? `error`}`);
|
|
3934
|
+
return reply.result;
|
|
3935
|
+
}
|
|
3936
|
+
}
|
|
3937
|
+
export { CATALOG_ID2, LITE_CATALOG_ID2, BASIC_CATALOG_ID2, BASIC_VERSION2, CATALOG_VERSION2, UNKNOWN_COMPONENT_NAME2, COMPONENT_NAMES2, NATIVE_COMPONENTS2, MACRO_COMPONENTS2, LITE_COMPONENTS2, COMPONENT_GROUPS2, SPECIMEN_IDS2, ENUMS2, TOKEN_NAMES2, STYLE_KEY_NAMES2, STYLE_STATE_NAMES2, ICON_NAMES2, FUNCTION_NAMES2, BASIC_COMPONENT_MAP2, BASIC_ICON_MAP2, BASIC_PLACEHOLDER_ICON2, DEFAULT_STRINGS2, STRING_IDS2, parseStringRef2, isStringRef2, stringTable2, formatString2, resolveString2, locale_default, displayString2, currencyDigits2, parseDateValue2, formatPattern2, ENGLISH_DATE_PATTERNS2, ENGLISH_TIME_PATTERN2, ENGLISH_DATE_TIME_JOIN2, fixedOffset2, intlZoneOffset2, relativeTimeUnit2, englishFormatter2, intlFormatter2, FORMAT_FUNCTION_NAMES2, formatFunctions2, ENGLISH_FORMAT_FUNCTIONS2, isBinding2, isCall2, isDynamic2, truthy2, valuesEqual2, clampNumber2, fillTemplate2, evalExpr2, evalConditionValue2, evalCondition2, evalValue2, percent2, filterItems2, CORE_FUNCTIONS2, CORE_FUNCTION_NAMES2, LIMITS2, MAX_COMPONENTS2, MAX_DEPTH2, MAX_MESSAGE_BYTES2, MAX_TEMPLATE_ITEMS2, MAX_POINTER_BYTES2, MAX_POINTER_SEGMENTS2, LIMIT_ISSUES2, absolutePath2, hasItem2, readPath2, readPointer2, writeTokens2, POINTER_ISSUES2, writePointer2, BIND_FUNCTIONS2, BIND_FUNCTION_NAMES2, resolveDynamic2, isVisible2, withOwnWrites2, submitClosesOverlay2, runAction2, isDataSchema2, resolveProp2, resolveNodeProps2, hasRowSlots2, rowScope2, bindRowSlot2, sectionScope2, bindSectionHeader2, bindTree2, treeGuides2, isRowRoot2, applyTreeGuides2, BREAKPOINTS2, isResponsiveValue2, responsiveAt2, propsAt2, expandMacros2, isCallableName2, validateNode2, validateProps2, basicMap2, mapBasicIcon2, mapBasicComponent2, BASIC_TRANSFORM_NAMES2, RESERVED_KEYS2, validVisible2, childTemplate2, reduceSurface2, slotAllowed2, reduceNested2, preorder2, BUILTIN_FUNCTIONS2, matchesPattern2, decideFunction2, combineDecisions2, packagePolicy2, isPrivateHost2, decideUrl2, mediaRequest2, safeHref2, sortKeys2, imageDimensions2, svgDimensions2, imageFrames2, mediaImageWithinLimits2, parseSource2, JsonlDecoder2, decodeJsonl2, SseDecoder2, messagesFromMcpResult2, mcpActionCall2, supportedCatalogIds2, clientCapabilities2, validatePackage2, sourceAllowed2, templateMessages2, mergeData2, HostRouter2, normalizePath2, PackageError2, resolveSurfaceTheme2, SurfaceStore2, ExponentialHost2, MemoryTransport2, JsonlStreamTransport2, SseTransport2, WebSocketTransport2, McpTransport2 };
|
|
3938
|
+
|
|
3939
|
+
//# debugId=10AAE9080E35A11264756E2164756E21
|
|
3940
|
+
//# sourceMappingURL=index-98npjvsd.js.map
|