@ng-prism/core 22.5.0 → 22.7.0-beta.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/README.md +13 -9
- package/dist/app/canvas/canvas-bg.styles.d.ts +1 -1
- package/dist/app/canvas/canvas-bg.styles.d.ts.map +1 -1
- package/dist/app/canvas/canvas-bg.styles.js +1 -1
- package/dist/app/canvas/canvas-overlay-tokens.d.ts +12 -0
- package/dist/app/canvas/canvas-overlay-tokens.d.ts.map +1 -0
- package/dist/app/canvas/canvas-overlay-tokens.js +52 -0
- package/dist/app/canvas/prism-canvas-bg-pill.component.js +2 -2
- package/dist/app/canvas/prism-canvas-pin-row.component.js +2 -2
- package/dist/app/canvas/prism-canvas-rulers.component.d.ts +2 -0
- package/dist/app/canvas/prism-canvas-rulers.component.d.ts.map +1 -1
- package/dist/app/canvas/prism-canvas-rulers.component.js +17 -12
- package/dist/app/canvas/prism-canvas-toolbar.component.d.ts +25 -3
- package/dist/app/canvas/prism-canvas-toolbar.component.d.ts.map +1 -1
- package/dist/app/canvas/prism-canvas-toolbar.component.js +154 -89
- package/dist/app/canvas/prism-template-popover.component.d.ts.map +1 -1
- package/dist/app/canvas/prism-template-popover.component.js +16 -7
- package/dist/app/canvas/state-chips.d.ts +50 -0
- package/dist/app/canvas/state-chips.d.ts.map +1 -0
- package/dist/app/canvas/state-chips.js +40 -0
- package/dist/app/component-head/head-metrics.d.ts +35 -19
- package/dist/app/component-head/head-metrics.d.ts.map +1 -1
- package/dist/app/component-head/head-metrics.js +57 -27
- package/dist/app/component-head/pipe-facts.d.ts +9 -0
- package/dist/app/component-head/pipe-facts.d.ts.map +1 -0
- package/dist/app/component-head/pipe-facts.js +15 -0
- package/dist/app/component-head/prism-component-head.component.d.ts +20 -22
- package/dist/app/component-head/prism-component-head.component.d.ts.map +1 -1
- package/dist/app/component-head/prism-component-head.component.js +85 -96
- package/dist/app/component-head/prism-head-gauge.component.d.ts +8 -12
- package/dist/app/component-head/prism-head-gauge.component.d.ts.map +1 -1
- package/dist/app/component-head/prism-head-gauge.component.js +51 -67
- package/dist/app/component-head/prism-head-info.component.d.ts +14 -2
- package/dist/app/component-head/prism-head-info.component.d.ts.map +1 -1
- package/dist/app/component-head/prism-head-info.component.js +84 -20
- package/dist/app/component-head/prism-stat.component.d.ts +4 -5
- package/dist/app/component-head/prism-stat.component.d.ts.map +1 -1
- package/dist/app/component-head/prism-stat.component.js +16 -12
- package/dist/app/component-head/service-facts.d.ts +8 -0
- package/dist/app/component-head/service-facts.d.ts.map +1 -0
- package/dist/app/component-head/service-facts.js +11 -0
- package/dist/app/controls/boolean-control.component.js +2 -2
- package/dist/app/controls/json-control.component.js +2 -2
- package/dist/app/controls/union-control.component.js +4 -3
- package/dist/app/directives/resize-value.d.ts +1 -1
- package/dist/app/directives/resize-value.js +1 -1
- package/dist/app/discovery-manifest.d.ts +2 -2
- package/dist/app/discovery-manifest.d.ts.map +1 -1
- package/dist/app/discovery-manifest.js +15 -3
- package/dist/app/header/header-brand.d.ts +25 -0
- package/dist/app/header/header-brand.d.ts.map +1 -0
- package/dist/app/header/header-brand.js +10 -0
- package/dist/app/header/prism-header.component.d.ts +2 -2
- package/dist/app/header/prism-header.component.d.ts.map +1 -1
- package/dist/app/header/prism-header.component.js +73 -57
- package/dist/app/icons/icon-registry.d.ts.map +1 -1
- package/dist/app/icons/icon-registry.js +4 -1
- package/dist/app/index.d.ts +12 -0
- package/dist/app/index.d.ts.map +1 -1
- package/dist/app/index.js +12 -1
- package/dist/app/layout-menu/prism-layout-menu.component.d.ts +3 -0
- package/dist/app/layout-menu/prism-layout-menu.component.d.ts.map +1 -1
- package/dist/app/layout-menu/prism-layout-menu.component.js +72 -58
- package/dist/app/overview/open-in-playground.d.ts +19 -0
- package/dist/app/overview/open-in-playground.d.ts.map +1 -0
- package/dist/app/overview/open-in-playground.js +25 -0
- package/dist/app/overview/overview-matrix.d.ts +85 -0
- package/dist/app/overview/overview-matrix.d.ts.map +1 -0
- package/dist/app/overview/overview-matrix.js +98 -0
- package/dist/app/overview/overview-visibility.d.ts +10 -2
- package/dist/app/overview/overview-visibility.d.ts.map +1 -1
- package/dist/app/overview/overview-visibility.js +14 -3
- package/dist/app/overview/prism-overview-cell.component.d.ts +27 -2
- package/dist/app/overview/prism-overview-cell.component.d.ts.map +1 -1
- package/dist/app/overview/prism-overview-cell.component.js +145 -28
- package/dist/app/overview/prism-overview-matrix.component.d.ts +29 -0
- package/dist/app/overview/prism-overview-matrix.component.d.ts.map +1 -0
- package/dist/app/overview/prism-overview-matrix.component.js +155 -0
- package/dist/app/overview/prism-overview.component.d.ts +4 -0
- package/dist/app/overview/prism-overview.component.d.ts.map +1 -1
- package/dist/app/overview/prism-overview.component.js +37 -14
- package/dist/app/page-renderer/prism-page-renderer.component.js +2 -2
- package/dist/app/panels/a11y/a11y-core.plugin.d.ts.map +1 -1
- package/dist/app/panels/a11y/a11y-core.plugin.js +0 -1
- package/dist/app/panels/a11y/a11y-header-badge.component.d.ts +1 -4
- package/dist/app/panels/a11y/a11y-header-badge.component.d.ts.map +1 -1
- package/dist/app/panels/a11y/a11y-header-badge.component.js +8 -19
- package/dist/app/panels/a11y/a11y-keyboard-overlay.component.js +2 -2
- package/dist/app/panels/a11y/a11y-overlay-host.component.d.ts +1 -0
- package/dist/app/panels/a11y/a11y-overlay-host.component.d.ts.map +1 -1
- package/dist/app/panels/a11y/a11y-overlay-host.component.js +4 -3
- package/dist/app/panels/a11y/a11y-panel.component.d.ts +4 -1
- package/dist/app/panels/a11y/a11y-panel.component.d.ts.map +1 -1
- package/dist/app/panels/a11y/a11y-panel.component.js +32 -54
- package/dist/app/panels/a11y/a11y-score.component.d.ts +8 -3
- package/dist/app/panels/a11y/a11y-score.component.d.ts.map +1 -1
- package/dist/app/panels/a11y/a11y-score.component.js +19 -35
- package/dist/app/panels/a11y/a11y-sr-overlay.component.js +2 -2
- package/dist/app/panels/a11y/a11y-sr.component.js +2 -2
- package/dist/app/panels/a11y/a11y-summary.d.ts.map +1 -1
- package/dist/app/panels/a11y/a11y-summary.js +8 -1
- package/dist/app/panels/a11y/a11y-tree.component.js +2 -2
- package/dist/app/panels/a11y/a11y-violations.component.d.ts +23 -2
- package/dist/app/panels/a11y/a11y-violations.component.d.ts.map +1 -1
- package/dist/app/panels/a11y/a11y-violations.component.js +104 -89
- package/dist/app/panels/a11y/severity.d.ts +9 -0
- package/dist/app/panels/a11y/severity.d.ts.map +1 -0
- package/dist/app/panels/a11y/severity.js +12 -0
- package/dist/app/panels/controls/controls-plugin.d.ts.map +1 -1
- package/dist/app/panels/controls/controls-plugin.js +1 -2
- package/dist/app/panels/controls/non-editable-input-types.d.ts +9 -1
- package/dist/app/panels/controls/non-editable-input-types.d.ts.map +1 -1
- package/dist/app/panels/controls/non-editable-input-types.js +18 -0
- package/dist/app/panels/controls/prism-controls-panel.component.d.ts +2 -1
- package/dist/app/panels/controls/prism-controls-panel.component.d.ts.map +1 -1
- package/dist/app/panels/controls/prism-controls-panel.component.js +77 -59
- package/dist/app/panels/events/events-plugin.d.ts.map +1 -1
- package/dist/app/panels/events/events-plugin.js +1 -2
- package/dist/app/panels/events/prism-events-panel.component.d.ts +2 -0
- package/dist/app/panels/events/prism-events-panel.component.d.ts.map +1 -1
- package/dist/app/panels/events/prism-events-panel.component.js +20 -7
- package/dist/app/panels/events/prism-json-node.utils.d.ts +6 -0
- package/dist/app/panels/events/prism-json-node.utils.d.ts.map +1 -1
- package/dist/app/panels/events/prism-json-node.utils.js +8 -0
- package/dist/app/panels/panel-host/addon-panels.d.ts +11 -0
- package/dist/app/panels/panel-host/addon-panels.d.ts.map +1 -0
- package/dist/app/panels/panel-host/addon-panels.js +12 -0
- package/dist/app/panels/panel-host/panel-badge.d.ts +22 -0
- package/dist/app/panels/panel-host/panel-badge.d.ts.map +1 -1
- package/dist/app/panels/panel-host/panel-badge.js +56 -11
- package/dist/app/panels/panel-host/prism-panel-host.component.d.ts +4 -1
- package/dist/app/panels/panel-host/prism-panel-host.component.d.ts.map +1 -1
- package/dist/app/panels/panel-host/prism-panel-host.component.js +36 -70
- package/dist/app/pseudo/pseudo-state-marker.d.ts +32 -10
- package/dist/app/pseudo/pseudo-state-marker.d.ts.map +1 -1
- package/dist/app/pseudo/pseudo-state-marker.js +83 -67
- package/dist/app/pseudo/pseudo-targets.d.ts +11 -0
- package/dist/app/pseudo/pseudo-targets.d.ts.map +1 -0
- package/dist/app/pseudo/pseudo-targets.js +46 -0
- package/dist/app/pseudo/state-fit.d.ts +28 -0
- package/dist/app/pseudo/state-fit.d.ts.map +1 -0
- package/dist/app/pseudo/state-fit.js +97 -0
- package/dist/app/renderer/composition.d.ts +20 -0
- package/dist/app/renderer/composition.d.ts.map +1 -0
- package/dist/app/renderer/composition.js +26 -0
- package/dist/app/renderer/input-bindings.d.ts +28 -0
- package/dist/app/renderer/input-bindings.d.ts.map +1 -0
- package/dist/app/renderer/input-bindings.js +42 -0
- package/dist/app/renderer/known-inputs.d.ts +8 -1
- package/dist/app/renderer/known-inputs.d.ts.map +1 -1
- package/dist/app/renderer/known-inputs.js +13 -5
- package/dist/app/renderer/prism-renderer.component.d.ts +18 -4
- package/dist/app/renderer/prism-renderer.component.d.ts.map +1 -1
- package/dist/app/renderer/prism-renderer.component.js +78 -44
- package/dist/app/renderer/projectable-content.d.ts +8 -1
- package/dist/app/renderer/projectable-content.d.ts.map +1 -1
- package/dist/app/renderer/projectable-content.js +40 -29
- package/dist/app/renderer/rendered-key.d.ts +20 -6
- package/dist/app/renderer/rendered-key.d.ts.map +1 -1
- package/dist/app/renderer/rendered-key.js +25 -8
- package/dist/app/renderer/snippet-generator.d.ts +14 -2
- package/dist/app/renderer/snippet-generator.d.ts.map +1 -1
- package/dist/app/renderer/snippet-generator.js +138 -81
- package/dist/app/services/navigation-item.d.ts +10 -0
- package/dist/app/services/navigation-item.d.ts.map +1 -0
- package/dist/app/services/navigation-item.js +20 -0
- package/dist/app/services/navigation-item.types.d.ts +8 -0
- package/dist/app/services/navigation-item.types.d.ts.map +1 -1
- package/dist/app/services/prism-layout.service.d.ts +12 -0
- package/dist/app/services/prism-layout.service.d.ts.map +1 -1
- package/dist/app/services/prism-layout.service.js +17 -7
- package/dist/app/services/prism-manifest.service.d.ts +4 -0
- package/dist/app/services/prism-manifest.service.d.ts.map +1 -1
- package/dist/app/services/prism-manifest.service.js +4 -0
- package/dist/app/services/prism-navigation.service.d.ts +12 -0
- package/dist/app/services/prism-navigation.service.d.ts.map +1 -1
- package/dist/app/services/prism-navigation.service.js +85 -19
- package/dist/app/services/prism-panel.service.d.ts +7 -3
- package/dist/app/services/prism-panel.service.d.ts.map +1 -1
- package/dist/app/services/prism-panel.service.js +13 -4
- package/dist/app/services/prism-pseudo-state.service.d.ts +59 -14
- package/dist/app/services/prism-pseudo-state.service.d.ts.map +1 -1
- package/dist/app/services/prism-pseudo-state.service.js +86 -29
- package/dist/app/services/prism-renderer.service.d.ts +23 -0
- package/dist/app/services/prism-renderer.service.d.ts.map +1 -1
- package/dist/app/services/prism-renderer.service.js +77 -8
- package/dist/app/services/prism-search.service.d.ts +4 -0
- package/dist/app/services/prism-search.service.d.ts.map +1 -1
- package/dist/app/services/prism-search.service.js +29 -6
- package/dist/app/services/prism-theme.service.d.ts +11 -3
- package/dist/app/services/prism-theme.service.d.ts.map +1 -1
- package/dist/app/services/prism-theme.service.js +27 -19
- package/dist/app/services/prism-url-state.service.d.ts.map +1 -1
- package/dist/app/services/prism-url-state.service.js +81 -12
- package/dist/app/shared/badge.types.d.ts +7 -0
- package/dist/app/shared/badge.types.d.ts.map +1 -0
- package/dist/app/shared/badge.types.js +9 -0
- package/dist/app/shared/brand-mark.d.ts +35 -0
- package/dist/app/shared/brand-mark.d.ts.map +1 -0
- package/dist/app/shared/brand-mark.js +52 -0
- package/dist/app/shared/metric-bar.d.ts +6 -0
- package/dist/app/shared/metric-bar.d.ts.map +1 -0
- package/dist/app/shared/metric-bar.js +7 -0
- package/dist/app/shared/prism-badge.component.d.ts +21 -0
- package/dist/app/shared/prism-badge.component.d.ts.map +1 -0
- package/dist/app/shared/prism-badge.component.js +68 -0
- package/dist/app/shared/prism-button.component.d.ts +12 -0
- package/dist/app/shared/prism-button.component.d.ts.map +1 -0
- package/dist/app/shared/prism-button.component.js +28 -0
- package/dist/app/shared/prism-icon-button.component.d.ts +17 -0
- package/dist/app/shared/prism-icon-button.component.d.ts.map +1 -0
- package/dist/app/shared/prism-icon-button.component.js +37 -0
- package/dist/app/shared/prism-list-row.component.d.ts +17 -0
- package/dist/app/shared/prism-list-row.component.d.ts.map +1 -0
- package/dist/app/shared/prism-list-row.component.js +57 -0
- package/dist/app/shared/prism-logo.component.d.ts +24 -0
- package/dist/app/shared/prism-logo.component.d.ts.map +1 -0
- package/dist/app/shared/prism-logo.component.js +77 -0
- package/dist/app/shared/prism-metric-badge.component.d.ts +9 -4
- package/dist/app/shared/prism-metric-badge.component.d.ts.map +1 -1
- package/dist/app/shared/prism-metric-badge.component.js +33 -12
- package/dist/app/shared/prism-metric-card.component.d.ts +30 -0
- package/dist/app/shared/prism-metric-card.component.d.ts.map +1 -0
- package/dist/app/shared/prism-metric-card.component.js +111 -0
- package/dist/app/shared/prism-panel-toolbar.component.d.ts +13 -0
- package/dist/app/shared/prism-panel-toolbar.component.d.ts.map +1 -0
- package/dist/app/shared/prism-panel-toolbar.component.js +28 -0
- package/dist/app/shared/prism-segmented.component.d.ts +25 -0
- package/dist/app/shared/prism-segmented.component.d.ts.map +1 -0
- package/dist/app/shared/prism-segmented.component.js +77 -0
- package/dist/app/shared/prism-tabs.component.d.ts +44 -0
- package/dist/app/shared/prism-tabs.component.d.ts.map +1 -0
- package/dist/app/shared/prism-tabs.component.js +134 -0
- package/dist/app/shared/roving-focus.d.ts +13 -0
- package/dist/app/shared/roving-focus.d.ts.map +1 -0
- package/dist/app/shared/roving-focus.js +34 -0
- package/dist/app/shell/prism-shell.component.d.ts +13 -0
- package/dist/app/shell/prism-shell.component.d.ts.map +1 -1
- package/dist/app/shell/prism-shell.component.js +57 -28
- package/dist/app/shell/should-select-first.d.ts +17 -0
- package/dist/app/shell/should-select-first.d.ts.map +1 -0
- package/dist/app/shell/should-select-first.js +13 -0
- package/dist/app/sidebar/navigation-decorations.d.ts +23 -1
- package/dist/app/sidebar/navigation-decorations.d.ts.map +1 -1
- package/dist/app/sidebar/navigation-decorations.js +33 -2
- package/dist/app/sidebar/prism-sidebar.component.d.ts +5 -15
- package/dist/app/sidebar/prism-sidebar.component.d.ts.map +1 -1
- package/dist/app/sidebar/prism-sidebar.component.js +89 -77
- package/dist/app/theme/deprecated-tokens.d.ts +15 -0
- package/dist/app/theme/deprecated-tokens.d.ts.map +1 -0
- package/dist/app/theme/deprecated-tokens.js +22 -0
- package/dist/app/theme/favicon.d.ts +3 -0
- package/dist/app/theme/favicon.d.ts.map +1 -0
- package/dist/app/theme/favicon.js +3 -0
- package/dist/app/theme/prism-default-theme.d.ts.map +1 -1
- package/dist/app/theme/prism-default-theme.js +122 -66
- package/dist/app/theme/resolve-theme-tokens.d.ts +29 -0
- package/dist/app/theme/resolve-theme-tokens.d.ts.map +1 -0
- package/dist/app/theme/resolve-theme-tokens.js +43 -0
- package/dist/app/variant-ribbon/prism-variant-ribbon.component.d.ts +4 -7
- package/dist/app/variant-ribbon/prism-variant-ribbon.component.d.ts.map +1 -1
- package/dist/app/variant-ribbon/prism-variant-ribbon.component.js +31 -69
- package/dist/app/view-tab-bar/next-view-id.d.ts +7 -1
- package/dist/app/view-tab-bar/next-view-id.d.ts.map +1 -1
- package/dist/app/view-tab-bar/next-view-id.js +9 -1
- package/dist/app/view-tab-bar/panel-inputs.d.ts +28 -0
- package/dist/app/view-tab-bar/panel-inputs.d.ts.map +1 -0
- package/dist/app/view-tab-bar/panel-inputs.js +41 -0
- package/dist/app/view-tab-bar/prism-view-panel-host.component.d.ts +2 -3
- package/dist/app/view-tab-bar/prism-view-panel-host.component.d.ts.map +1 -1
- package/dist/app/view-tab-bar/prism-view-panel-host.component.js +9 -9
- package/dist/app/view-tab-bar/prism-view-tab-bar.component.d.ts +6 -0
- package/dist/app/view-tab-bar/prism-view-tab-bar.component.d.ts.map +1 -1
- package/dist/app/view-tab-bar/prism-view-tab-bar.component.js +22 -29
- package/dist/builder/config-loader/deprecated-options.d.ts +9 -0
- package/dist/builder/config-loader/deprecated-options.d.ts.map +1 -0
- package/dist/builder/config-loader/deprecated-options.js +34 -0
- package/dist/builder/manifest/composition-wrapper.generator.d.ts +14 -0
- package/dist/builder/manifest/composition-wrapper.generator.d.ts.map +1 -0
- package/dist/builder/manifest/composition-wrapper.generator.js +66 -0
- package/dist/builder/manifest/host-parser.d.ts +2 -0
- package/dist/builder/manifest/host-parser.d.ts.map +1 -1
- package/dist/builder/manifest/host-parser.js +9 -4
- package/dist/builder/manifest/manifest-imports.d.ts +34 -0
- package/dist/builder/manifest/manifest-imports.d.ts.map +1 -0
- package/dist/builder/manifest/manifest-imports.js +91 -0
- package/dist/builder/manifest/runtime-manifest.generator.d.ts +13 -0
- package/dist/builder/manifest/runtime-manifest.generator.d.ts.map +1 -1
- package/dist/builder/manifest/runtime-manifest.generator.js +137 -65
- package/dist/builder/manifest/selector-element.d.ts +16 -0
- package/dist/builder/manifest/selector-element.d.ts.map +1 -0
- package/dist/builder/manifest/selector-element.js +46 -0
- package/dist/builder/manifest/template-literal.d.ts +3 -0
- package/dist/builder/manifest/template-literal.d.ts.map +1 -0
- package/dist/builder/manifest/template-literal.js +4 -0
- package/dist/builder/plugin-runner/plugin-runner.d.ts.map +1 -1
- package/dist/builder/plugin-runner/plugin-runner.js +29 -26
- package/dist/builder/scanner/api/angular-decorators.d.ts +84 -0
- package/dist/builder/scanner/api/angular-decorators.d.ts.map +1 -0
- package/dist/builder/scanner/api/angular-decorators.js +157 -0
- package/dist/builder/scanner/api/component-api.extractor.d.ts +13 -0
- package/dist/builder/scanner/api/component-api.extractor.d.ts.map +1 -0
- package/dist/builder/scanner/api/component-api.extractor.js +104 -0
- package/dist/builder/scanner/api/doc-tags.d.ts +13 -0
- package/dist/builder/scanner/api/doc-tags.d.ts.map +1 -0
- package/dist/builder/scanner/api/doc-tags.js +101 -0
- package/dist/builder/scanner/api/export-index.d.ts +18 -0
- package/dist/builder/scanner/api/export-index.d.ts.map +1 -0
- package/dist/builder/scanner/api/export-index.js +22 -0
- package/dist/builder/scanner/api/member.extractor.d.ts +90 -0
- package/dist/builder/scanner/api/member.extractor.d.ts.map +1 -0
- package/dist/builder/scanner/api/member.extractor.js +270 -0
- package/dist/builder/scanner/api/pipe-api.extractor.d.ts +12 -0
- package/dist/builder/scanner/api/pipe-api.extractor.d.ts.map +1 -0
- package/dist/builder/scanner/api/pipe-api.extractor.js +52 -0
- package/dist/builder/scanner/api/service-api.extractor.d.ts +14 -0
- package/dist/builder/scanner/api/service-api.extractor.d.ts.map +1 -0
- package/dist/builder/scanner/api/service-api.extractor.js +119 -0
- package/dist/builder/scanner/api/setup.reader.d.ts +26 -0
- package/dist/builder/scanner/api/setup.reader.d.ts.map +1 -0
- package/dist/builder/scanner/api/setup.reader.js +89 -0
- package/dist/builder/scanner/api/type-collector.d.ts +24 -0
- package/dist/builder/scanner/api/type-collector.d.ts.map +1 -0
- package/dist/builder/scanner/api/type-collector.js +211 -0
- package/dist/builder/scanner/ast-utils.d.ts +8 -0
- package/dist/builder/scanner/ast-utils.d.ts.map +1 -1
- package/dist/builder/scanner/ast-utils.js +37 -1
- package/dist/builder/scanner/class-hierarchy.d.ts +5 -3
- package/dist/builder/scanner/class-hierarchy.d.ts.map +1 -1
- package/dist/builder/scanner/class-hierarchy.js +12 -6
- package/dist/builder/scanner/component.scanner.d.ts +60 -6
- package/dist/builder/scanner/component.scanner.d.ts.map +1 -1
- package/dist/builder/scanner/component.scanner.js +229 -58
- package/dist/builder/scanner/composition/compose-template.d.ts +36 -0
- package/dist/builder/scanner/composition/compose-template.d.ts.map +1 -0
- package/dist/builder/scanner/composition/compose-template.js +187 -0
- package/dist/builder/scanner/composition/declarables.d.ts +54 -0
- package/dist/builder/scanner/composition/declarables.d.ts.map +1 -0
- package/dist/builder/scanner/composition/declarables.js +182 -0
- package/dist/builder/scanner/composition/match-declarables.d.ts +43 -0
- package/dist/builder/scanner/composition/match-declarables.d.ts.map +1 -0
- package/dist/builder/scanner/composition/match-declarables.js +131 -0
- package/dist/builder/scanner/composition/read-composition.d.ts +77 -0
- package/dist/builder/scanner/composition/read-composition.d.ts.map +1 -0
- package/dist/builder/scanner/composition/read-composition.js +302 -0
- package/dist/builder/scanner/composition/template-elements.d.ts +12 -0
- package/dist/builder/scanner/composition/template-elements.d.ts.map +1 -0
- package/dist/builder/scanner/composition/template-elements.js +41 -0
- package/dist/builder/scanner/entry-point-discovery.d.ts +5 -0
- package/dist/builder/scanner/entry-point-discovery.d.ts.map +1 -1
- package/dist/builder/scanner/entry-point-discovery.js +14 -0
- package/dist/builder/scanner/entry-point.scanner.d.ts +3 -1
- package/dist/builder/scanner/entry-point.scanner.d.ts.map +1 -1
- package/dist/builder/scanner/entry-point.scanner.js +7 -6
- package/dist/builder/scanner/index.d.ts +4 -0
- package/dist/builder/scanner/index.d.ts.map +1 -1
- package/dist/builder/scanner/index.js +2 -0
- package/dist/builder/scanner/input.extractor.d.ts +31 -2
- package/dist/builder/scanner/input.extractor.d.ts.map +1 -1
- package/dist/builder/scanner/input.extractor.js +73 -17
- package/dist/builder/scanner/pipe.scanner.d.ts +29 -0
- package/dist/builder/scanner/pipe.scanner.d.ts.map +1 -0
- package/dist/builder/scanner/pipe.scanner.js +65 -0
- package/dist/builder/scanner/pseudo-states.d.ts +1 -0
- package/dist/builder/scanner/pseudo-states.d.ts.map +1 -1
- package/dist/builder/scanner/pseudo-states.js +1 -1
- package/dist/builder/scanner/scanner.d.ts +27 -3
- package/dist/builder/scanner/scanner.d.ts.map +1 -1
- package/dist/builder/scanner/scanner.js +68 -24
- package/dist/builder/scanner/service/angular-decorators.d.ts +80 -0
- package/dist/builder/scanner/service/angular-decorators.d.ts.map +1 -0
- package/dist/builder/scanner/service/angular-decorators.js +154 -0
- package/dist/builder/scanner/service/doc-tags.d.ts +13 -0
- package/dist/builder/scanner/service/doc-tags.d.ts.map +1 -0
- package/dist/builder/scanner/service/doc-tags.js +97 -0
- package/dist/builder/scanner/service/export-index.d.ts +18 -0
- package/dist/builder/scanner/service/export-index.d.ts.map +1 -0
- package/dist/builder/scanner/service/export-index.js +22 -0
- package/dist/builder/scanner/service/member.extractor.d.ts +65 -0
- package/dist/builder/scanner/service/member.extractor.d.ts.map +1 -0
- package/dist/builder/scanner/service/member.extractor.js +216 -0
- package/dist/builder/scanner/service/pipe-api.extractor.d.ts +12 -0
- package/dist/builder/scanner/service/pipe-api.extractor.d.ts.map +1 -0
- package/dist/builder/scanner/service/pipe-api.extractor.js +72 -0
- package/dist/builder/scanner/service/service-api.extractor.d.ts +14 -0
- package/dist/builder/scanner/service/service-api.extractor.d.ts.map +1 -0
- package/dist/builder/scanner/service/service-api.extractor.js +119 -0
- package/dist/builder/scanner/service/setup.reader.d.ts +26 -0
- package/dist/builder/scanner/service/setup.reader.d.ts.map +1 -0
- package/dist/builder/scanner/service/setup.reader.js +89 -0
- package/dist/builder/scanner/service/type-collector.d.ts +23 -0
- package/dist/builder/scanner/service/type-collector.d.ts.map +1 -0
- package/dist/builder/scanner/service/type-collector.js +210 -0
- package/dist/builder/scanner/service.scanner.d.ts +26 -0
- package/dist/builder/scanner/service.scanner.d.ts.map +1 -0
- package/dist/builder/scanner/service.scanner.js +61 -0
- package/dist/builder/scanner/showcase-diagnostics.d.ts +60 -1
- package/dist/builder/scanner/showcase-diagnostics.d.ts.map +1 -1
- package/dist/builder/scanner/showcase-diagnostics.js +123 -10
- package/dist/builder/scanner/showcase-states.d.ts +17 -0
- package/dist/builder/scanner/showcase-states.d.ts.map +1 -0
- package/dist/builder/scanner/showcase-states.js +58 -0
- package/dist/builder/scanner/source-file-cache.d.ts +26 -0
- package/dist/builder/scanner/source-file-cache.d.ts.map +1 -0
- package/dist/builder/scanner/source-file-cache.js +60 -0
- package/dist/builder/shared/prism-pipeline.d.ts +6 -0
- package/dist/builder/shared/prism-pipeline.d.ts.map +1 -1
- package/dist/builder/shared/prism-pipeline.js +71 -18
- package/dist/decorator/index.d.ts +1 -1
- package/dist/decorator/index.d.ts.map +1 -1
- package/dist/decorator/showcase.types.d.ts +102 -9
- package/dist/decorator/showcase.types.d.ts.map +1 -1
- package/dist/plugin/index.d.ts +6 -1
- package/dist/plugin/index.d.ts.map +1 -1
- package/dist/plugin/index.js +4 -0
- package/dist/plugin/pipe.types.d.ts +36 -0
- package/dist/plugin/pipe.types.d.ts.map +1 -0
- package/dist/plugin/pipe.types.js +1 -0
- package/dist/plugin/plugin.types.d.ts +184 -8
- package/dist/plugin/plugin.types.d.ts.map +1 -1
- package/dist/plugin/service.types.d.ts +124 -0
- package/dist/plugin/service.types.d.ts.map +1 -0
- package/dist/plugin/service.types.js +1 -0
- package/dist/plugin/status.d.ts +27 -0
- package/dist/plugin/status.d.ts.map +1 -0
- package/dist/plugin/status.js +26 -0
- package/dist/shared/composition.d.ts +30 -0
- package/dist/shared/composition.d.ts.map +1 -0
- package/dist/shared/composition.js +29 -0
- package/dist/shared/pseudo-state.type.d.ts +2 -1
- package/dist/shared/pseudo-state.type.d.ts.map +1 -1
- package/dist/shared/void-elements.d.ts +3 -0
- package/dist/shared/void-elements.d.ts.map +1 -0
- package/dist/shared/void-elements.js +2 -0
- package/package.json +1 -1
- package/src/builder/build/schema.json +6 -6
- package/src/builder/serve/schema.json +6 -6
|
@@ -1,11 +1,17 @@
|
|
|
1
1
|
import ts from 'typescript';
|
|
2
2
|
import { CANVAS_BGS } from '../../shared/canvas-bg.type.js';
|
|
3
3
|
import { CANVAS_LAYOUTS } from '../../shared/canvas-layout.type.js';
|
|
4
|
-
import {
|
|
4
|
+
import { isImportableName } from '../manifest/manifest-imports.js';
|
|
5
|
+
import { classifyShowcaseClass } from './api/angular-decorators.js';
|
|
6
|
+
import { extractComponentApi } from './api/component-api.extractor.js';
|
|
7
|
+
import { findSetupProperty } from './api/setup.reader.js';
|
|
8
|
+
import { evaluateStatic, findDecorator, getDecoratorArgument, readDecoratorField, UNEVALUABLE } from './ast-utils.js';
|
|
5
9
|
import { getClassHierarchy } from './class-hierarchy.js';
|
|
10
|
+
import { readComposition } from './composition/read-composition.js';
|
|
6
11
|
import { extractInputs, extractOutputs } from './input.extractor.js';
|
|
7
|
-
import { readPseudoStates } from './pseudo-states.js';
|
|
8
|
-
import { describeDeprecatedProviders, describeUnevaluable, describeUnreadableBase } from './showcase-diagnostics.js';
|
|
12
|
+
import { describeValue, readPseudoStates } from './pseudo-states.js';
|
|
13
|
+
import { describeDeprecatedProviders, describeLegacyPipeComponent, describeLegacyServiceComponent, describeSetupOnComponent, describeSetupOnLegacyComponent, describeShowcaseIssue, describeUnevaluable, describeUnreadableApi, describeUnreadableBase } from './showcase-diagnostics.js';
|
|
14
|
+
import { readShowcaseStates } from './showcase-states.js';
|
|
9
15
|
const COMPONENT_STATUSES = ['stable', 'beta', 'wip', 'deprecated'];
|
|
10
16
|
function isComponentStatus(value) {
|
|
11
17
|
return typeof value === 'string' && COMPONENT_STATUSES.includes(value);
|
|
@@ -38,47 +44,96 @@ function isCanvasBg(value) {
|
|
|
38
44
|
function isCanvasLayout(value) {
|
|
39
45
|
return typeof value === 'string' && CANVAS_LAYOUTS.includes(value);
|
|
40
46
|
}
|
|
47
|
+
function isShowcaseImport(value) {
|
|
48
|
+
const { name, from } = typeof value === 'object' && value !== null ? value : {};
|
|
49
|
+
return typeof name === 'string' && name !== '' && typeof from === 'string' && from !== '';
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* What is wrong with an import the generated manifest would write as `import { name } from 'from'`, `undefined` when
|
|
53
|
+
* nothing is: anything but an identifier there, `default` or a module path, is a syntax error in the whole manifest.
|
|
54
|
+
*/
|
|
55
|
+
function importProblem(entry) {
|
|
56
|
+
return isImportableName(entry.name) ? undefined : `expected the name a class is exported under, got ${JSON.stringify(entry.name)}; it was dropped`;
|
|
57
|
+
}
|
|
58
|
+
function isHostTemplate(value) {
|
|
59
|
+
return typeof value === 'object' && value !== null && typeof value['template'] === 'string';
|
|
60
|
+
}
|
|
61
|
+
/** The position an element has in the source, given the positions before it that the evaluator dropped: the evaluated list is shorter by those. */
|
|
62
|
+
function sourceIndex(index, dropped) {
|
|
63
|
+
return [...dropped].sort((a, b) => a - b).reduce((position, gap) => (gap <= position ? position + 1 : position), index);
|
|
64
|
+
}
|
|
41
65
|
/**
|
|
42
|
-
*
|
|
66
|
+
* The two ways a scan warns, each printing a message once however often it is
|
|
67
|
+
* raised: `report` for a dropped value, which is also collected in
|
|
68
|
+
* `diagnostics` and fails the build under `strictShowcase`, and `notify` for
|
|
69
|
+
* anything else worth saying.
|
|
70
|
+
*/
|
|
71
|
+
export function createReporters(diagnostics, notices) {
|
|
72
|
+
return {
|
|
73
|
+
report: (message) => {
|
|
74
|
+
if (diagnostics.includes(message))
|
|
75
|
+
return;
|
|
76
|
+
diagnostics.push(message);
|
|
77
|
+
console.warn(`⚠ ng-prism: ${message}`);
|
|
78
|
+
},
|
|
79
|
+
notify: (message) => {
|
|
80
|
+
if (notices.has(message))
|
|
81
|
+
return;
|
|
82
|
+
notices.add(message);
|
|
83
|
+
console.warn(`⚠ ng-prism: ${message}`);
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Read the Angular components among the showcased classes of an entry point.
|
|
89
|
+
* A class with `@Injectable` or `@Service` is a service and one with `@Pipe` a
|
|
90
|
+
* pipe, each left to its own scan, unless it declares fields only a component
|
|
91
|
+
* can use.
|
|
43
92
|
*
|
|
44
93
|
* Every @Showcase value the scan has to drop is printed and collected in
|
|
45
|
-
* `diagnostics`, once
|
|
46
|
-
* component
|
|
47
|
-
* `notices` does the same for warnings about what a component inherits,
|
|
48
|
-
* which are not diagnostics.
|
|
94
|
+
* `diagnostics`, once. `notices` does the same for warnings about what a
|
|
95
|
+
* component inherits, which are not diagnostics.
|
|
49
96
|
*/
|
|
50
|
-
export function scanComponents(
|
|
97
|
+
export function scanComponents(showcased, checker, options = {}) {
|
|
98
|
+
const { diagnostics = [], notices = new Set(), exportIndex = new Map(), api: readApi = true, composition: compositionContext } = options;
|
|
51
99
|
const components = [];
|
|
52
|
-
const report = (
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
diagnostics.push(message);
|
|
56
|
-
console.warn(`⚠ ng-prism: ${message}`);
|
|
57
|
-
};
|
|
58
|
-
const notify = (message) => {
|
|
59
|
-
if (notices.has(message))
|
|
60
|
-
return;
|
|
61
|
-
notices.add(message);
|
|
62
|
-
console.warn(`⚠ ng-prism: ${message}`);
|
|
63
|
-
};
|
|
64
|
-
for (const sym of exports) {
|
|
65
|
-
const resolved = sym.flags & ts.SymbolFlags.Alias ? checker.getAliasedSymbol(sym) : sym;
|
|
66
|
-
const classDecl = resolved.declarations?.find(ts.isClassDeclaration);
|
|
67
|
-
if (!classDecl)
|
|
68
|
-
continue;
|
|
69
|
-
// Perf: cheap pre-filter that skips the full decorator walk for files that don't
|
|
70
|
-
// mention Showcase at all. False positives (string-literal containing "@Showcase")
|
|
71
|
-
// just lose the optimization for that file; correctness is unaffected.
|
|
72
|
-
if (!classDecl.getSourceFile().text.includes('@Showcase'))
|
|
73
|
-
continue;
|
|
74
|
-
const showcaseDecorator = findDecorator(classDecl, 'Showcase');
|
|
75
|
-
if (!showcaseDecorator)
|
|
100
|
+
const { report, notify } = createReporters(diagnostics, notices);
|
|
101
|
+
for (const { classDecl, decorator: showcaseDecorator, argument: showcaseArg, kind: classKind } of showcased) {
|
|
102
|
+
if (classKind.kind === 'service' || classKind.kind === 'pipe')
|
|
76
103
|
continue;
|
|
77
104
|
const className = classDecl.name?.text ?? 'Anonymous';
|
|
78
|
-
const
|
|
79
|
-
if (!
|
|
105
|
+
const read = readShowcaseConfig(showcaseDecorator, className, report, checker);
|
|
106
|
+
if (!read || !showcaseArg)
|
|
80
107
|
continue;
|
|
108
|
+
const { config: showcaseConfig, sources } = read;
|
|
109
|
+
// Not a diagnostic: the component still works, and strictShowcase must not fail the build over a notice about 23.0.0.
|
|
110
|
+
if (classKind.kind === 'legacy-component') {
|
|
111
|
+
notify(classKind.source === 'pipe'
|
|
112
|
+
? describeLegacyPipeComponent(className, classKind.fields, classKind.standalone !== false)
|
|
113
|
+
: describeLegacyServiceComponent(className, classKind.fields));
|
|
114
|
+
}
|
|
115
|
+
const setup = findSetupProperty(showcaseArg);
|
|
116
|
+
if (setup)
|
|
117
|
+
report(classKind.kind === 'legacy-component' ? describeSetupOnLegacyComponent(className, setup, classKind.fields) : describeSetupOnComponent(className, setup));
|
|
81
118
|
const componentMeta = extractComponentMeta(classDecl, checker);
|
|
119
|
+
// A string or an object host puts a directive on an element. A component has ignored it so far and keeps doing so, so that what a library renders stays as it is.
|
|
120
|
+
// Not a diagnostic: nothing is lost, and strictShowcase must not start failing a build over it.
|
|
121
|
+
if (!componentMeta.isDirective && showcaseConfig.host !== undefined && !isHostTemplate(showcaseConfig.host)) {
|
|
122
|
+
notify(describeShowcaseIssue(className, showcaseArg, ['host'], 'a string or object host has no effect on a component; use host: { template } to render it inside other markup. It was dropped.'));
|
|
123
|
+
delete showcaseConfig.host;
|
|
124
|
+
}
|
|
125
|
+
const host = showcaseConfig.host;
|
|
126
|
+
// The manifest imports the class of a directive's object host, as an import of the showcase.
|
|
127
|
+
if (componentMeta.isDirective && typeof host === 'object' && host !== null && !isHostTemplate(host) && host.import !== undefined) {
|
|
128
|
+
const hostImport = host.import;
|
|
129
|
+
const problem = isShowcaseImport(hostImport)
|
|
130
|
+
? importProblem(hostImport)
|
|
131
|
+
: `expected { name, from } with a non-empty string each, got ${describeValue(hostImport)}; it was dropped`;
|
|
132
|
+
if (problem) {
|
|
133
|
+
report(describeShowcaseIssue(className, showcaseArg, ['host', 'import'], problem));
|
|
134
|
+
delete host.import;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
82
137
|
const hierarchy = getClassHierarchy(classDecl, checker);
|
|
83
138
|
const inputs = extractInputs(classDecl, checker, hierarchy);
|
|
84
139
|
const outputs = extractOutputs(classDecl, checker, hierarchy);
|
|
@@ -93,6 +148,28 @@ export function scanComponents(exports, checker, diagnostics = [], notices = new
|
|
|
93
148
|
for (const base of hierarchy.unreadable) {
|
|
94
149
|
notify(describeUnreadableBase(className, base));
|
|
95
150
|
}
|
|
151
|
+
// The API only feeds the API page, which has a fallback for a component without one: a class the extractor
|
|
152
|
+
// cannot read must not take the scan down. A notice, not a diagnostic, so strictShowcase does not fail over it.
|
|
153
|
+
let api;
|
|
154
|
+
try {
|
|
155
|
+
if (readApi)
|
|
156
|
+
api = extractComponentApi(classDecl, inputs, outputs, hierarchy, checker, exportIndex);
|
|
157
|
+
}
|
|
158
|
+
catch (error) {
|
|
159
|
+
notify(describeUnreadableApi(className, error, 'component'));
|
|
160
|
+
}
|
|
161
|
+
const composition = compositionContext &&
|
|
162
|
+
readComposition({
|
|
163
|
+
className,
|
|
164
|
+
filePath,
|
|
165
|
+
selector: componentMeta.selector,
|
|
166
|
+
isDirective: componentMeta.isDirective,
|
|
167
|
+
standalone: componentMeta.standalone,
|
|
168
|
+
inputs,
|
|
169
|
+
config: showcaseConfig,
|
|
170
|
+
configNode: showcaseArg,
|
|
171
|
+
sources
|
|
172
|
+
}, compositionContext, { report, notify });
|
|
96
173
|
components.push({
|
|
97
174
|
className,
|
|
98
175
|
filePath,
|
|
@@ -103,11 +180,38 @@ export function scanComponents(exports, checker, diagnostics = [], notices = new
|
|
|
103
180
|
// Plugins look a base class up by name, so an anonymous one is of no use to them.
|
|
104
181
|
baseClasses: hierarchy.classes
|
|
105
182
|
.slice(1)
|
|
106
|
-
.flatMap(({ classDecl: base }) => (base.name ? [{ className: base.name.text, filePath: base.getSourceFile().fileName }] : []))
|
|
183
|
+
.flatMap(({ classDecl: base }) => (base.name ? [{ className: base.name.text, filePath: base.getSourceFile().fileName }] : [])),
|
|
184
|
+
api,
|
|
185
|
+
...(composition && { composition })
|
|
107
186
|
});
|
|
108
187
|
}
|
|
109
188
|
return components;
|
|
110
189
|
}
|
|
190
|
+
/**
|
|
191
|
+
* The classes with `@Showcase` among the exports of an entry point, each
|
|
192
|
+
* classified once: the component, the service and the pipe scan each keep
|
|
193
|
+
* the classes of their own kind.
|
|
194
|
+
*/
|
|
195
|
+
export function findShowcasedClasses(exports, checker) {
|
|
196
|
+
return exports.flatMap((sym) => {
|
|
197
|
+
const showcased = findShowcasedClass(sym, checker);
|
|
198
|
+
return showcased ? [{ ...showcased, kind: classifyShowcaseClass(showcased.classDecl, showcased.argument, checker) }] : [];
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
/** The class an export resolves to, when it carries `@Showcase`. */
|
|
202
|
+
function findShowcasedClass(sym, checker) {
|
|
203
|
+
const symbol = sym.flags & ts.SymbolFlags.Alias ? checker.getAliasedSymbol(sym) : sym;
|
|
204
|
+
const classDecl = symbol.declarations?.find(ts.isClassDeclaration);
|
|
205
|
+
if (!classDecl)
|
|
206
|
+
return undefined;
|
|
207
|
+
// Perf: cheap pre-filter that skips the full decorator walk for files that don't
|
|
208
|
+
// mention Showcase at all. False positives (string-literal containing "@Showcase")
|
|
209
|
+
// just lose the optimization for that file; correctness is unaffected.
|
|
210
|
+
if (!classDecl.getSourceFile().text.includes('@Showcase'))
|
|
211
|
+
return undefined;
|
|
212
|
+
const decorator = findDecorator(classDecl, 'Showcase');
|
|
213
|
+
return decorator && { symbol, classDecl, decorator, argument: getDecoratorArgument(decorator) };
|
|
214
|
+
}
|
|
111
215
|
function hasDecoratorInputs(classDecl) {
|
|
112
216
|
for (const member of classDecl.members) {
|
|
113
217
|
if (!ts.isPropertyDeclaration(member))
|
|
@@ -117,19 +221,41 @@ function hasDecoratorInputs(classDecl) {
|
|
|
117
221
|
}
|
|
118
222
|
return false;
|
|
119
223
|
}
|
|
120
|
-
|
|
224
|
+
/**
|
|
225
|
+
* `setup` is read for services and pipes only, so a component's is never
|
|
226
|
+
* part of the config: the issue the evaluator raises for its function is
|
|
227
|
+
* swallowed here, and {@link scanComponents} says what is wrong with it instead.
|
|
228
|
+
*/
|
|
229
|
+
export function extractShowcaseConfig(decorator, className, report, checker) {
|
|
230
|
+
return readShowcaseConfig(decorator, className, report, checker)?.config;
|
|
231
|
+
}
|
|
232
|
+
/** {@link extractShowcaseConfig}, and where the entries it kept are written. */
|
|
233
|
+
function readShowcaseConfig(decorator, className, report, checker) {
|
|
121
234
|
const arg = getDecoratorArgument(decorator);
|
|
122
235
|
if (!arg)
|
|
123
236
|
return undefined;
|
|
124
237
|
// Reported once for the whole field below, wherever it came from: the literal, a spread or a constant.
|
|
125
238
|
let providers;
|
|
239
|
+
// A state the evaluator dropped whole leaves no element behind, so its position is noted to keep the later states where the source has them.
|
|
240
|
+
const unevaluableStates = new Set();
|
|
241
|
+
// The same for the elements of `imports` and `variants`, which are not put back but named by the position the source gives them.
|
|
242
|
+
const unevaluableElements = { imports: new Set(), variants: new Set() };
|
|
126
243
|
const raw = evaluateStatic(arg, {
|
|
127
244
|
checker,
|
|
128
245
|
report: (issue) => {
|
|
246
|
+
if (issue.path[0] === 'setup')
|
|
247
|
+
return;
|
|
129
248
|
if (issue.path[0] === 'providers') {
|
|
130
249
|
providers ??= issue.node;
|
|
131
250
|
return;
|
|
132
251
|
}
|
|
252
|
+
if (issue.path[0] === 'states' && issue.path.length === 2 && typeof issue.path[1] === 'number')
|
|
253
|
+
unevaluableStates.add(issue.path[1]);
|
|
254
|
+
const [field, index] = issue.path;
|
|
255
|
+
// A spread that fails inside an element leaves the element behind, and one in the list leaves no telling how many.
|
|
256
|
+
const isElement = issue.path.length === 2 && !ts.isSpreadAssignment(issue.node) && !ts.isSpreadElement(issue.node);
|
|
257
|
+
if (isElement && (field === 'imports' || field === 'variants') && typeof index === 'number')
|
|
258
|
+
unevaluableElements[field].add(index);
|
|
133
259
|
report(describeUnevaluable(className, arg, issue));
|
|
134
260
|
}
|
|
135
261
|
});
|
|
@@ -146,6 +272,7 @@ function extractShowcaseConfig(decorator, className, report, checker) {
|
|
|
146
272
|
const config = {
|
|
147
273
|
title: obj['title']
|
|
148
274
|
};
|
|
275
|
+
const sources = { variants: [], imports: [] };
|
|
149
276
|
if (obj['description'])
|
|
150
277
|
config.description = obj['description'];
|
|
151
278
|
if (obj['category'])
|
|
@@ -165,10 +292,27 @@ function extractShowcaseConfig(decorator, className, report, checker) {
|
|
|
165
292
|
config.tags = obj['tags'];
|
|
166
293
|
if (obj['meta'])
|
|
167
294
|
config.meta = obj['meta'];
|
|
168
|
-
if (obj['host'] !== undefined)
|
|
169
|
-
|
|
295
|
+
if (obj['host'] !== undefined) {
|
|
296
|
+
// An object with a `template` is meant as a host template, so one that is no string is not a host of another kind.
|
|
297
|
+
if (typeof obj['host'] === 'object' && obj['host'] !== null && 'template' in obj['host'] && !isHostTemplate(obj['host'])) {
|
|
298
|
+
report(describeShowcaseIssue(className, arg, ['host'], `expected { template: string }, got ${describeValue(obj['host'])}; it was dropped`));
|
|
299
|
+
}
|
|
300
|
+
else {
|
|
301
|
+
config.host = obj['host'];
|
|
302
|
+
}
|
|
303
|
+
}
|
|
170
304
|
if (obj['renderPage'])
|
|
171
305
|
config.renderPage = obj['renderPage'];
|
|
306
|
+
if (obj['states'] !== undefined) {
|
|
307
|
+
if (config.renderPage) {
|
|
308
|
+
report(`${className} declares states together with renderPage; a component page has no Overview to show them in. Skipping states.`);
|
|
309
|
+
}
|
|
310
|
+
else {
|
|
311
|
+
const states = readShowcaseStates(obj['states'], className, report, unevaluableStates);
|
|
312
|
+
if (states)
|
|
313
|
+
config.states = states;
|
|
314
|
+
}
|
|
315
|
+
}
|
|
172
316
|
if (obj['status'] !== undefined) {
|
|
173
317
|
if (isComponentStatus(obj['status'])) {
|
|
174
318
|
config.status = obj['status'];
|
|
@@ -194,9 +338,17 @@ function extractShowcaseConfig(decorator, className, report, checker) {
|
|
|
194
338
|
report(`${className} declares invalid canvasLayout "${String(obj['canvasLayout'])}", ` + `expected one of: ${CANVAS_LAYOUTS.join(', ')}. Skipping.`);
|
|
195
339
|
}
|
|
196
340
|
}
|
|
341
|
+
if (obj['imports'] !== undefined) {
|
|
342
|
+
const imports = readShowcaseImports(obj['imports'], className, arg, report, unevaluableElements.imports);
|
|
343
|
+
if (imports.length > 0) {
|
|
344
|
+
config.imports = imports.map(({ entry }) => entry);
|
|
345
|
+
sources.imports = imports.map(({ source }) => source);
|
|
346
|
+
}
|
|
347
|
+
}
|
|
197
348
|
if (Array.isArray(obj['variants'])) {
|
|
198
|
-
config.variants = obj['variants'].map((variant) => {
|
|
349
|
+
config.variants = obj['variants'].map((variant, index) => {
|
|
199
350
|
const cleaned = { ...variant };
|
|
351
|
+
const reportVariant = (field, text) => report(describeShowcaseIssue(className, arg, ['variants', sourceIndex(index, unevaluableElements.variants), field], text));
|
|
200
352
|
if (isCanvasBg(variant['bg'])) {
|
|
201
353
|
warnDeprecatedBg(variant['bg'], `${className} variant "${String(variant['name'])}"`);
|
|
202
354
|
}
|
|
@@ -218,10 +370,46 @@ function extractShowcaseConfig(decorator, className, report, checker) {
|
|
|
218
370
|
else
|
|
219
371
|
delete cleaned['pseudo'];
|
|
220
372
|
}
|
|
373
|
+
if (variant['states'] !== undefined && variant['states'] !== false) {
|
|
374
|
+
report(`${className} variant "${String(variant['name'])}" declares invalid states ${describeValue(variant['states'])}, expected false. Skipping.`);
|
|
375
|
+
delete cleaned['states'];
|
|
376
|
+
}
|
|
377
|
+
if (variant['template'] !== undefined && typeof variant['template'] !== 'string') {
|
|
378
|
+
reportVariant('template', `expected a string, got ${describeValue(variant['template'])}; it was dropped`);
|
|
379
|
+
delete cleaned['template'];
|
|
380
|
+
}
|
|
381
|
+
if (cleaned['template'] !== undefined && variant['content'] !== undefined) {
|
|
382
|
+
reportVariant('content', 'set together with template; template wins and content was dropped');
|
|
383
|
+
delete cleaned['content'];
|
|
384
|
+
}
|
|
385
|
+
if (variant['host'] !== undefined && !isHostTemplate(variant['host'])) {
|
|
386
|
+
reportVariant('host', `expected { template: string }, got ${describeValue(variant['host'])}; it was dropped`);
|
|
387
|
+
delete cleaned['host'];
|
|
388
|
+
}
|
|
221
389
|
return cleaned;
|
|
222
390
|
});
|
|
391
|
+
sources.variants = (config.variants ?? []).map((_, index) => sourceIndex(index, unevaluableElements.variants));
|
|
392
|
+
}
|
|
393
|
+
return { config, sources };
|
|
394
|
+
}
|
|
395
|
+
/**
|
|
396
|
+
* `ShowcaseConfig.imports` as the scanner evaluated it, with every entry that is not a `{ name, from }` pair of
|
|
397
|
+
* non-empty strings reported and dropped. `unevaluable` holds the source positions the evaluator dropped, which keep
|
|
398
|
+
* the later entries named by the position they have in the source; `source` is that position for each kept entry.
|
|
399
|
+
*/
|
|
400
|
+
function readShowcaseImports(value, className, config, report, unevaluable) {
|
|
401
|
+
if (!Array.isArray(value)) {
|
|
402
|
+
report(describeShowcaseIssue(className, config, ['imports'], `expected a list of { name, from }, got ${describeValue(value)}; it was dropped`));
|
|
403
|
+
return [];
|
|
223
404
|
}
|
|
224
|
-
return
|
|
405
|
+
return value.flatMap((entry, index) => {
|
|
406
|
+
const source = sourceIndex(index, unevaluable);
|
|
407
|
+
const text = isShowcaseImport(entry) ? importProblem(entry) : `expected { name, from } with a non-empty string each, got ${describeValue(entry)}; it was dropped`;
|
|
408
|
+
if (!text)
|
|
409
|
+
return [{ entry: { name: entry.name, from: entry.from }, source }];
|
|
410
|
+
report(describeShowcaseIssue(className, config, ['imports', source], text));
|
|
411
|
+
return [];
|
|
412
|
+
});
|
|
225
413
|
}
|
|
226
414
|
function extractComponentMeta(classDecl, checker) {
|
|
227
415
|
const componentDecorator = findDecorator(classDecl, 'Component');
|
|
@@ -237,20 +425,3 @@ function extractComponentMeta(classDecl, checker) {
|
|
|
237
425
|
isDirective
|
|
238
426
|
};
|
|
239
427
|
}
|
|
240
|
-
/**
|
|
241
|
-
* One field of `@Component`/`@Directive` metadata, read from its own
|
|
242
|
-
* property where the literal has one, so that `imports`, `providers` and the
|
|
243
|
-
* rest are not resolved only to be thrown away. A spread or a shorthand could
|
|
244
|
-
* supply the field from elsewhere, so then the whole argument is evaluated.
|
|
245
|
-
*/
|
|
246
|
-
function readDecoratorField(arg, key, checker) {
|
|
247
|
-
if (ts.isObjectLiteralExpression(arg) && !arg.properties.some(ts.isSpreadAssignment)) {
|
|
248
|
-
const prop = arg.properties.find((p) => p.name !== undefined && (ts.isIdentifier(p.name) || ts.isStringLiteral(p.name)) && p.name.text === key);
|
|
249
|
-
if (!prop)
|
|
250
|
-
return undefined;
|
|
251
|
-
if (ts.isPropertyAssignment(prop))
|
|
252
|
-
return evaluateExpression(prop.initializer, checker);
|
|
253
|
-
}
|
|
254
|
-
const raw = evaluateExpression(arg, checker);
|
|
255
|
-
return typeof raw === 'object' && raw !== null ? raw[key] : undefined;
|
|
256
|
-
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { type TmplAstNode } from '@angular/compiler';
|
|
2
|
+
export interface ComposeInput {
|
|
3
|
+
selector: string;
|
|
4
|
+
isDirective: boolean;
|
|
5
|
+
/** Public input name (alias ?? name) → member name. */
|
|
6
|
+
inputNames: ReadonlyMap<string, string>;
|
|
7
|
+
hostTemplate?: string;
|
|
8
|
+
/** Inner markup of the subject: the variant's template, or a directive's text content already escaped. */
|
|
9
|
+
content?: string;
|
|
10
|
+
}
|
|
11
|
+
export type ComposeResult = {
|
|
12
|
+
ok: true;
|
|
13
|
+
template: string;
|
|
14
|
+
ownedInputs: string[];
|
|
15
|
+
nodes: TmplAstNode[];
|
|
16
|
+
} | {
|
|
17
|
+
ok: false;
|
|
18
|
+
at: 'host' | 'template';
|
|
19
|
+
problem: string;
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* The template of a composition: the subject in its host template, or written from its selector without one, with
|
|
23
|
+
* `content` as what it holds. {@link COMPOSITION_SUBJECT_SLOT} marks the end of the subject's start tag, right after
|
|
24
|
+
* its last attribute or its tag name; whoever replaces it brings the leading space.
|
|
25
|
+
*
|
|
26
|
+
* In a host template the subject is the element marked with `prism-subject`, else the one element its selector
|
|
27
|
+
* matches. A directive whose selector does not match the marked element gets the attributes that make it match.
|
|
28
|
+
* The marker is removed, and `content` replaces what the subject holds in the host template. `ownedInputs` are the
|
|
29
|
+
* member names of the inputs the host template sets on the subject.
|
|
30
|
+
*
|
|
31
|
+
* What fails is reported against the field it comes from: `host` for the host template and finding the subject in
|
|
32
|
+
* it, `template` for the content and, when there is content, for what Angular's parser rejects in the composed
|
|
33
|
+
* template. Both are parsed as the generated wrapper holds them, inside a `@case`, where an element left open fails.
|
|
34
|
+
*/
|
|
35
|
+
export declare function composeTemplate(input: ComposeInput): ComposeResult;
|
|
36
|
+
//# sourceMappingURL=compose-template.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compose-template.d.ts","sourceRoot":"","sources":["../../../../src/builder/scanner/composition/compose-template.ts"],"names":[],"mappings":"AAAA,OAAO,EAKH,KAAK,WAAW,EAInB,MAAM,mBAAmB,CAAC;AAM3B,MAAM,WAAW,YAAY;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,OAAO,CAAC;IACrB,uDAAuD;IACvD,UAAU,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACxC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,0GAA0G;IAC1G,OAAO,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,MAAM,aAAa,GAAG;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,EAAE,CAAC;IAAC,KAAK,EAAE,WAAW,EAAE,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,EAAE,EAAE,MAAM,GAAG,UAAU,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAUlK;;;;;;;;;;;;;GAaG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,YAAY,GAAG,aAAa,CAYlE"}
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
import { CssSelector, parseTemplate, SelectorMatcher, TmplAstElement, TmplAstRecursiveVisitor, TmplAstTemplate, tmplAstVisitAll } from '@angular/compiler';
|
|
2
|
+
import { COMPOSITION_SUBJECT_SLOT, SUBJECT_MARKER_ATTR } from '../../../shared/composition.js';
|
|
3
|
+
import { VOID_ELEMENTS } from '../../../shared/void-elements.js';
|
|
4
|
+
import { selectorElement } from '../../manifest/selector-element.js';
|
|
5
|
+
import { elementSelector, isInputBinding, localName } from './template-elements.js';
|
|
6
|
+
/** The URL the parser files the composition under. A problem carries only Angular's `msg`, so it shows nowhere. */
|
|
7
|
+
const TEMPLATE_URL = 'prism-composition.html';
|
|
8
|
+
/**
|
|
9
|
+
* The template of a composition: the subject in its host template, or written from its selector without one, with
|
|
10
|
+
* `content` as what it holds. {@link COMPOSITION_SUBJECT_SLOT} marks the end of the subject's start tag, right after
|
|
11
|
+
* its last attribute or its tag name; whoever replaces it brings the leading space.
|
|
12
|
+
*
|
|
13
|
+
* In a host template the subject is the element marked with `prism-subject`, else the one element its selector
|
|
14
|
+
* matches. A directive whose selector does not match the marked element gets the attributes that make it match.
|
|
15
|
+
* The marker is removed, and `content` replaces what the subject holds in the host template. `ownedInputs` are the
|
|
16
|
+
* member names of the inputs the host template sets on the subject.
|
|
17
|
+
*
|
|
18
|
+
* What fails is reported against the field it comes from: `host` for the host template and finding the subject in
|
|
19
|
+
* it, `template` for the content and, when there is content, for what Angular's parser rejects in the composed
|
|
20
|
+
* template. Both are parsed as the generated wrapper holds them, inside a `@case`, where an element left open fails.
|
|
21
|
+
*/
|
|
22
|
+
export function composeTemplate(input) {
|
|
23
|
+
const composed = input.hostTemplate === undefined ? composeWithoutHost(input) : composeInHost(input, input.hostTemplate);
|
|
24
|
+
if (!composed.ok)
|
|
25
|
+
return composed;
|
|
26
|
+
const template = composed.template.replace(COMPOSITION_SUBJECT_SLOT, '');
|
|
27
|
+
const parsed = parseTemplate(template, TEMPLATE_URL);
|
|
28
|
+
const problem = parsed.errors?.[0]?.msg ?? problemInCase(template);
|
|
29
|
+
// Without content the host template alone was parsed, so a remaining error is still its own.
|
|
30
|
+
if (problem)
|
|
31
|
+
return fail(input.content === undefined ? 'host' : 'template', problem);
|
|
32
|
+
return { ...composed, nodes: parsed.nodes };
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* What Angular rejects in `template` inside the `@case` of the generated wrapper, beyond what it rejects at the top
|
|
36
|
+
* level: there it closes an element left open at the end of the template, in a block it fails on the block's `}`.
|
|
37
|
+
*/
|
|
38
|
+
function problemInCase(template) {
|
|
39
|
+
const error = parseTemplate(`@switch (0) {\n@case (0) {\n${template}\n}\n}`, TEMPLATE_URL).errors?.[0];
|
|
40
|
+
if (!error)
|
|
41
|
+
return undefined;
|
|
42
|
+
// The message is about the `}` ng-prism wrote, and names the element only in passing.
|
|
43
|
+
const unclosed = /Did you forget to close the (<[^>]+>) element\?/.exec(error.msg);
|
|
44
|
+
return unclosed ? `${unclosed[1]} is not closed` : `${error.msg}, in the @case that the generated wrapper puts the template in; an unclosed {{ or block can cause it`;
|
|
45
|
+
}
|
|
46
|
+
function composeWithoutHost({ selector, content }) {
|
|
47
|
+
const element = selectorElement(selector);
|
|
48
|
+
if (!element)
|
|
49
|
+
return fail('template', `the selector "${selector}" names no element to render the subject on`);
|
|
50
|
+
const { tag, attributes } = element;
|
|
51
|
+
const opening = `<${tag}${attributes ? ` ${attributes}` : ''}${COMPOSITION_SUBJECT_SLOT}`;
|
|
52
|
+
if (VOID_ELEMENTS.has(tag.toLowerCase())) {
|
|
53
|
+
return content ? voidContent(tag) : { ok: true, template: `${opening} />`, ownedInputs: [] };
|
|
54
|
+
}
|
|
55
|
+
return { ok: true, template: `${opening}>${content ?? ''}</${tag}>`, ownedInputs: [] };
|
|
56
|
+
}
|
|
57
|
+
function composeInHost(input, hostTemplate) {
|
|
58
|
+
const parsed = parseTemplate(hostTemplate, TEMPLATE_URL, { preserveWhitespaces: true });
|
|
59
|
+
const problem = parsed.errors?.[0]?.msg ?? problemInCase(hostTemplate);
|
|
60
|
+
if (problem)
|
|
61
|
+
return fail('host', problem);
|
|
62
|
+
const subject = findSubject(parsed.nodes, input.selector);
|
|
63
|
+
if ('problem' in subject)
|
|
64
|
+
return subject;
|
|
65
|
+
const { element, matched } = subject;
|
|
66
|
+
const tag = writtenTag(element, hostTemplate);
|
|
67
|
+
let added = '';
|
|
68
|
+
if (!matched) {
|
|
69
|
+
if (!input.isDirective)
|
|
70
|
+
return fail('host', `prism-subject marks <${tag}>, which the selector "${input.selector}" does not match`);
|
|
71
|
+
const fitting = selectorElement(input.selector, tag);
|
|
72
|
+
if (!fitting?.attributes)
|
|
73
|
+
return fail('host', `prism-subject marks <${tag}>, but no part of the selector "${input.selector}" fits a <${tag}>`);
|
|
74
|
+
added = ` ${fitting.attributes}`;
|
|
75
|
+
}
|
|
76
|
+
const isVoid = VOID_ELEMENTS.has(tag.toLowerCase());
|
|
77
|
+
if (isVoid && input.content)
|
|
78
|
+
return voidContent(tag);
|
|
79
|
+
const edits = [];
|
|
80
|
+
const startTagEnd = element.startSourceSpan.end.offset;
|
|
81
|
+
const slotAt = slotOffset(hostTemplate, startTagEnd);
|
|
82
|
+
const slot = { from: slotAt, to: slotAt, text: `${added}${COMPOSITION_SUBJECT_SLOT}` };
|
|
83
|
+
const marker = element.attributes.find((attribute) => attribute.name === SUBJECT_MARKER_ATTR);
|
|
84
|
+
if (marker) {
|
|
85
|
+
edits.push({ from: skipWhitespaceBack(hostTemplate, marker.sourceSpan.start.offset), to: marker.sourceSpan.end.offset, text: '' });
|
|
86
|
+
}
|
|
87
|
+
if (!isVoid && input.content !== undefined) {
|
|
88
|
+
if (!element.isSelfClosing) {
|
|
89
|
+
const childrenEnd = element.endSourceSpan?.start.offset ?? endOffset(element);
|
|
90
|
+
edits.push({ from: startTagEnd, to: childrenEnd, text: input.content });
|
|
91
|
+
}
|
|
92
|
+
else if (input.content) {
|
|
93
|
+
slot.to = startTagEnd;
|
|
94
|
+
slot.text += `>${input.content}</${tag}>`;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
edits.push(slot);
|
|
98
|
+
return { ok: true, template: applyEdits(hostTemplate, edits), ownedInputs: ownedInputs(element, input) };
|
|
99
|
+
}
|
|
100
|
+
/** The subject of a host template, and whether its selector matches it, which only a marked element may fail. */
|
|
101
|
+
function findSubject(nodes, selector) {
|
|
102
|
+
const elements = collectElements(nodes);
|
|
103
|
+
const marked = elements.filter((element) => element.attributes.some((attribute) => attribute.name === SUBJECT_MARKER_ATTR));
|
|
104
|
+
if (marked.length > 1)
|
|
105
|
+
return fail('host', `prism-subject marks ${marked.length} elements of the host template; mark one`);
|
|
106
|
+
const matcher = new SelectorMatcher();
|
|
107
|
+
matcher.addSelectables(CssSelector.parse(selector));
|
|
108
|
+
const matches = (element) => matcher.match(elementSelector(element), null);
|
|
109
|
+
if (marked.length === 1)
|
|
110
|
+
return { element: marked[0], matched: matches(marked[0]) };
|
|
111
|
+
const matching = elements.filter(matches);
|
|
112
|
+
if (matching.length === 0)
|
|
113
|
+
return fail('host', `the selector "${selector}" matches no element of the host template`);
|
|
114
|
+
if (matching.length > 1)
|
|
115
|
+
return fail('host', `the selector "${selector}" matches ${matching.length} elements of the host template; mark one with prism-subject`);
|
|
116
|
+
return { element: matching[0], matched: true };
|
|
117
|
+
}
|
|
118
|
+
class ElementCollector extends TmplAstRecursiveVisitor {
|
|
119
|
+
elements = [];
|
|
120
|
+
visitElement(element) {
|
|
121
|
+
this.elements.push(element);
|
|
122
|
+
super.visitElement(element);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
/** Every element of a template, also those in control flow blocks and in `<ng-template>`, in document order. */
|
|
126
|
+
function collectElements(nodes) {
|
|
127
|
+
const collector = new ElementCollector();
|
|
128
|
+
tmplAstVisitAll(collector, nodes);
|
|
129
|
+
return collector.elements;
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* The member names of the inputs that the host template sets on the subject, statically or by a property binding.
|
|
133
|
+
* An attribute without a value that the selector names is there to match it (`<button libTooltip>`), so ng-prism
|
|
134
|
+
* still binds the input of that name.
|
|
135
|
+
*/
|
|
136
|
+
function ownedInputs(element, { selector, inputNames }) {
|
|
137
|
+
const selectorAttributes = new Set(CssSelector.parse(selector).flatMap((part) => part.attrs.filter((_, i) => i % 2 === 0)));
|
|
138
|
+
const written = new Set();
|
|
139
|
+
for (const attribute of element.attributes) {
|
|
140
|
+
if (attribute.value !== '' || !selectorAttributes.has(attribute.name))
|
|
141
|
+
written.add(attribute.name);
|
|
142
|
+
}
|
|
143
|
+
for (const bound of element.inputs) {
|
|
144
|
+
if (isInputBinding(bound.type))
|
|
145
|
+
written.add(bound.name);
|
|
146
|
+
}
|
|
147
|
+
return [...inputNames].filter(([publicName]) => written.has(publicName)).map(([, member]) => member);
|
|
148
|
+
}
|
|
149
|
+
/** The tag name as the host template writes it, which is what an end tag and a message repeat. */
|
|
150
|
+
function writtenTag(element, source) {
|
|
151
|
+
const start = element.startSourceSpan.start.offset;
|
|
152
|
+
return /^<([^\s/>]+)/.exec(source.slice(start, element.startSourceSpan.end.offset))?.[1] ?? localName(element.name);
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Where a node ends in the source. The span of an element or `<ng-template>` whose end tag the parser implies (`<li>`
|
|
156
|
+
* before the next `<li>`, anything open at the end of the template) covers only its start tag, so it ends with its
|
|
157
|
+
* last descendant.
|
|
158
|
+
*/
|
|
159
|
+
function endOffset(node) {
|
|
160
|
+
const end = node.sourceSpan.end.offset;
|
|
161
|
+
if (!(node instanceof TmplAstElement || node instanceof TmplAstTemplate) || node.endSourceSpan)
|
|
162
|
+
return end;
|
|
163
|
+
const last = node.children.at(-1);
|
|
164
|
+
return last ? Math.max(end, endOffset(last)) : end;
|
|
165
|
+
}
|
|
166
|
+
/** Where the slot goes in a start tag ending at `startTagEnd`: before its `>` or `/>` and the whitespace in front of it. */
|
|
167
|
+
function slotOffset(source, startTagEnd) {
|
|
168
|
+
let offset = startTagEnd - 1;
|
|
169
|
+
if (source[offset - 1] === '/')
|
|
170
|
+
offset--;
|
|
171
|
+
return skipWhitespaceBack(source, offset);
|
|
172
|
+
}
|
|
173
|
+
function skipWhitespaceBack(source, offset) {
|
|
174
|
+
while (offset > 0 && /\s/.test(source[offset - 1]))
|
|
175
|
+
offset--;
|
|
176
|
+
return offset;
|
|
177
|
+
}
|
|
178
|
+
/** Applies edits that do not overlap, from the last to the first, so that the offsets of the others stay valid. */
|
|
179
|
+
function applyEdits(source, edits) {
|
|
180
|
+
return [...edits].sort((a, b) => b.from - a.from).reduce((text, edit) => text.slice(0, edit.from) + edit.text + text.slice(edit.to), source);
|
|
181
|
+
}
|
|
182
|
+
function voidContent(tag) {
|
|
183
|
+
return fail('template', `<${tag}> is a void element and takes no content`);
|
|
184
|
+
}
|
|
185
|
+
function fail(at, problem) {
|
|
186
|
+
return { ok: false, at, problem };
|
|
187
|
+
}
|