ngwr 10.2.1 → 11.0.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 +39 -19
- package/anchor/styles/_index.scss +4 -4
- package/back-top/styles/_index.scss +6 -1
- package/blur-text/styles/_index.scss +13 -0
- package/button/styles/_index.scss +11 -6
- package/carousel/styles/_index.scss +13 -2
- package/cascader/styles/_index.scss +2 -2
- package/circular-text/styles/_index.scss +2 -0
- package/collapse/styles/_index.scss +1 -1
- package/color-picker/styles/_index.scss +6 -1
- package/compare/styles/_index.scss +1 -2
- package/context-menu/styles/_index.scss +6 -1
- package/descriptions/styles/_index.scss +2 -2
- package/dialog/styles/_index.scss +7 -0
- package/drawer/styles/_index.scss +20 -1
- package/dropdown/styles/_index.scss +19 -5
- package/empty/styles/_index.scss +10 -0
- package/fesm2022/ngwr-action-sheet.mjs +13 -3
- package/fesm2022/ngwr-action-sheet.mjs.map +1 -1
- package/fesm2022/ngwr-affix.mjs +40 -13
- package/fesm2022/ngwr-affix.mjs.map +1 -1
- package/fesm2022/ngwr-anchor.mjs +18 -6
- package/fesm2022/ngwr-anchor.mjs.map +1 -1
- package/fesm2022/ngwr-aurora.mjs +2 -2
- package/fesm2022/ngwr-aurora.mjs.map +1 -1
- package/fesm2022/ngwr-avatar.mjs +31 -7
- package/fesm2022/ngwr-avatar.mjs.map +1 -1
- package/fesm2022/ngwr-back-top.mjs +6 -2
- package/fesm2022/ngwr-back-top.mjs.map +1 -1
- package/fesm2022/ngwr-badge.mjs +1 -1
- package/fesm2022/ngwr-badge.mjs.map +1 -1
- package/fesm2022/ngwr-bar-chart.mjs +30 -9
- package/fesm2022/ngwr-bar-chart.mjs.map +1 -1
- package/fesm2022/ngwr-blur-text.mjs +2 -2
- package/fesm2022/ngwr-blur-text.mjs.map +1 -1
- package/fesm2022/ngwr-border-glow.mjs +2 -2
- package/fesm2022/ngwr-border-glow.mjs.map +1 -1
- package/fesm2022/ngwr-breadcrumbs.mjs +2 -2
- package/fesm2022/ngwr-breadcrumbs.mjs.map +1 -1
- package/fesm2022/ngwr-burger.mjs +9 -4
- package/fesm2022/ngwr-burger.mjs.map +1 -1
- package/fesm2022/ngwr-button-testing.mjs +96 -0
- package/fesm2022/ngwr-button-testing.mjs.map +1 -0
- package/fesm2022/ngwr-button.mjs +31 -14
- package/fesm2022/ngwr-button.mjs.map +1 -1
- package/fesm2022/ngwr-calendar-heatmap.mjs +40 -8
- package/fesm2022/ngwr-calendar-heatmap.mjs.map +1 -1
- package/fesm2022/ngwr-calendar.mjs +20 -1
- package/fesm2022/ngwr-calendar.mjs.map +1 -1
- package/fesm2022/ngwr-card.mjs +2 -2
- package/fesm2022/ngwr-card.mjs.map +1 -1
- package/fesm2022/ngwr-carousel-testing.mjs +377 -0
- package/fesm2022/ngwr-carousel-testing.mjs.map +1 -0
- package/fesm2022/ngwr-carousel.mjs +67 -13
- package/fesm2022/ngwr-carousel.mjs.map +1 -1
- package/fesm2022/ngwr-cascader-testing.mjs +534 -0
- package/fesm2022/ngwr-cascader-testing.mjs.map +1 -0
- package/fesm2022/ngwr-cascader.mjs +2 -2
- package/fesm2022/ngwr-cascader.mjs.map +1 -1
- package/fesm2022/ngwr-checkbox-testing.mjs +90 -0
- package/fesm2022/ngwr-checkbox-testing.mjs.map +1 -0
- package/fesm2022/ngwr-checkbox.mjs +9 -3
- package/fesm2022/ngwr-checkbox.mjs.map +1 -1
- package/fesm2022/ngwr-circular-text.mjs +2 -2
- package/fesm2022/ngwr-circular-text.mjs.map +1 -1
- package/fesm2022/ngwr-click-spark.mjs +2 -2
- package/fesm2022/ngwr-click-spark.mjs.map +1 -1
- package/fesm2022/ngwr-collapse-testing.mjs +368 -0
- package/fesm2022/ngwr-collapse-testing.mjs.map +1 -0
- package/fesm2022/ngwr-color-picker.mjs +134 -14
- package/fesm2022/ngwr-color-picker.mjs.map +1 -1
- package/fesm2022/ngwr-command-palette-testing.mjs +589 -0
- package/fesm2022/ngwr-command-palette-testing.mjs.map +1 -0
- package/fesm2022/ngwr-command-palette.mjs +58 -8
- package/fesm2022/ngwr-command-palette.mjs.map +1 -1
- package/fesm2022/ngwr-compare.mjs +103 -13
- package/fesm2022/ngwr-compare.mjs.map +1 -1
- package/fesm2022/ngwr-config.mjs +106 -0
- package/fesm2022/ngwr-config.mjs.map +1 -0
- package/fesm2022/ngwr-context-menu-testing.mjs +631 -0
- package/fesm2022/ngwr-context-menu-testing.mjs.map +1 -0
- package/fesm2022/ngwr-context-menu.mjs +94 -8
- package/fesm2022/ngwr-context-menu.mjs.map +1 -1
- package/fesm2022/ngwr-cookie.mjs +5 -1
- package/fesm2022/ngwr-cookie.mjs.map +1 -1
- package/fesm2022/ngwr-counter.mjs +11 -3
- package/fesm2022/ngwr-counter.mjs.map +1 -1
- package/fesm2022/ngwr-date-adapter-luxon.mjs +52 -4
- package/fesm2022/ngwr-date-adapter-luxon.mjs.map +1 -1
- package/fesm2022/ngwr-date-adapter.mjs +54 -8
- package/fesm2022/ngwr-date-adapter.mjs.map +1 -1
- package/fesm2022/ngwr-date-picker-testing.mjs +766 -0
- package/fesm2022/ngwr-date-picker-testing.mjs.map +1 -0
- package/fesm2022/ngwr-date-picker.mjs +73 -3
- package/fesm2022/ngwr-date-picker.mjs.map +1 -1
- package/fesm2022/ngwr-decrypt-text.mjs +27 -9
- package/fesm2022/ngwr-decrypt-text.mjs.map +1 -1
- package/fesm2022/ngwr-dialog-testing.mjs +89 -0
- package/fesm2022/ngwr-dialog-testing.mjs.map +1 -0
- package/fesm2022/ngwr-directives.mjs +36 -12
- package/fesm2022/ngwr-directives.mjs.map +1 -1
- package/fesm2022/ngwr-donut-chart.mjs +22 -5
- package/fesm2022/ngwr-donut-chart.mjs.map +1 -1
- package/fesm2022/ngwr-drag-drop.mjs +2 -2
- package/fesm2022/ngwr-drag-drop.mjs.map +1 -1
- package/fesm2022/ngwr-drawer-testing.mjs +250 -0
- package/fesm2022/ngwr-drawer-testing.mjs.map +1 -0
- package/fesm2022/ngwr-dropdown-testing.mjs +291 -0
- package/fesm2022/ngwr-dropdown-testing.mjs.map +1 -0
- package/fesm2022/ngwr-dropdown.mjs +10 -2
- package/fesm2022/ngwr-dropdown.mjs.map +1 -1
- package/fesm2022/ngwr-empty.mjs +24 -7
- package/fesm2022/ngwr-empty.mjs.map +1 -1
- package/fesm2022/ngwr-event-calendar.mjs +57 -10
- package/fesm2022/ngwr-event-calendar.mjs.map +1 -1
- package/fesm2022/ngwr-falling-text.mjs +2 -2
- package/fesm2022/ngwr-falling-text.mjs.map +1 -1
- package/fesm2022/ngwr-file-upload-testing.mjs +332 -0
- package/fesm2022/ngwr-file-upload-testing.mjs.map +1 -0
- package/fesm2022/ngwr-form-testing.mjs +451 -0
- package/fesm2022/ngwr-form-testing.mjs.map +1 -0
- package/fesm2022/ngwr-form.mjs +19 -3
- package/fesm2022/ngwr-form.mjs.map +1 -1
- package/fesm2022/ngwr-fuzzy-text.mjs +9 -2
- package/fesm2022/ngwr-fuzzy-text.mjs.map +1 -1
- package/fesm2022/ngwr-gauge.mjs +19 -5
- package/fesm2022/ngwr-gauge.mjs.map +1 -1
- package/fesm2022/ngwr-glitch-text.mjs +2 -2
- package/fesm2022/ngwr-glitch-text.mjs.map +1 -1
- package/fesm2022/ngwr-gradient-text.mjs +2 -2
- package/fesm2022/ngwr-gradient-text.mjs.map +1 -1
- package/fesm2022/ngwr-i18n-en.mjs +50 -0
- package/fesm2022/ngwr-i18n-en.mjs.map +1 -1
- package/fesm2022/ngwr-i18n-ru.mjs +48 -0
- package/fesm2022/ngwr-i18n-ru.mjs.map +1 -1
- package/fesm2022/ngwr-image-cropper.mjs +23 -0
- package/fesm2022/ngwr-image-cropper.mjs.map +1 -1
- package/fesm2022/ngwr-input-number-testing.mjs +306 -0
- package/fesm2022/ngwr-input-number-testing.mjs.map +1 -0
- package/fesm2022/ngwr-input-number.mjs +35 -3
- package/fesm2022/ngwr-input-number.mjs.map +1 -1
- package/fesm2022/ngwr-input-otp-testing.mjs +419 -0
- package/fesm2022/ngwr-input-otp-testing.mjs.map +1 -0
- package/fesm2022/ngwr-input-otp.mjs +36 -5
- package/fesm2022/ngwr-input-otp.mjs.map +1 -1
- package/fesm2022/ngwr-input-testing.mjs +102 -0
- package/fesm2022/ngwr-input-testing.mjs.map +1 -0
- package/fesm2022/ngwr-input.mjs +47 -10
- package/fesm2022/ngwr-input.mjs.map +1 -1
- package/fesm2022/ngwr-knob.mjs +44 -8
- package/fesm2022/ngwr-knob.mjs.map +1 -1
- package/fesm2022/ngwr-layout.mjs +21 -5
- package/fesm2022/ngwr-layout.mjs.map +1 -1
- package/fesm2022/ngwr-lightbox.mjs +33 -6
- package/fesm2022/ngwr-lightbox.mjs.map +1 -1
- package/fesm2022/ngwr-line-chart.mjs +17 -4
- package/fesm2022/ngwr-line-chart.mjs.map +1 -1
- package/fesm2022/ngwr-list.mjs +2 -2
- package/fesm2022/ngwr-list.mjs.map +1 -1
- package/fesm2022/ngwr-loading-bar.mjs +2 -2
- package/fesm2022/ngwr-loading-bar.mjs.map +1 -1
- package/fesm2022/ngwr-markdown-testing.mjs +516 -0
- package/fesm2022/ngwr-markdown-testing.mjs.map +1 -0
- package/fesm2022/ngwr-markdown.mjs +1492 -0
- package/fesm2022/ngwr-markdown.mjs.map +1 -0
- package/fesm2022/ngwr-marquee.mjs +17 -6
- package/fesm2022/ngwr-marquee.mjs.map +1 -1
- package/fesm2022/ngwr-mention-testing.mjs +513 -0
- package/fesm2022/ngwr-mention-testing.mjs.map +1 -0
- package/fesm2022/ngwr-mention.mjs +10 -1
- package/fesm2022/ngwr-mention.mjs.map +1 -1
- package/fesm2022/ngwr-meta.mjs +22 -7
- package/fesm2022/ngwr-meta.mjs.map +1 -1
- package/fesm2022/ngwr-meter-group.mjs +19 -5
- package/fesm2022/ngwr-meter-group.mjs.map +1 -1
- package/fesm2022/ngwr-overlay.mjs +41 -1
- package/fesm2022/ngwr-overlay.mjs.map +1 -1
- package/fesm2022/ngwr-pagination-testing.mjs +389 -0
- package/fesm2022/ngwr-pagination-testing.mjs.map +1 -0
- package/fesm2022/ngwr-pagination.mjs +14 -2
- package/fesm2022/ngwr-pagination.mjs.map +1 -1
- package/fesm2022/ngwr-popconfirm-testing.mjs +309 -0
- package/fesm2022/ngwr-popconfirm-testing.mjs.map +1 -0
- package/fesm2022/ngwr-popconfirm.mjs +95 -17
- package/fesm2022/ngwr-popconfirm.mjs.map +1 -1
- package/fesm2022/ngwr-popover-testing.mjs +316 -0
- package/fesm2022/ngwr-popover-testing.mjs.map +1 -0
- package/fesm2022/ngwr-popover.mjs +21 -3
- package/fesm2022/ngwr-popover.mjs.map +1 -1
- package/fesm2022/ngwr-pull-to-refresh.mjs +17 -2
- package/fesm2022/ngwr-pull-to-refresh.mjs.map +1 -1
- package/fesm2022/ngwr-qr.mjs +13 -3
- package/fesm2022/ngwr-qr.mjs.map +1 -1
- package/fesm2022/ngwr-radio-testing.mjs +392 -0
- package/fesm2022/ngwr-radio-testing.mjs.map +1 -0
- package/fesm2022/ngwr-radio.mjs +10 -3
- package/fesm2022/ngwr-radio.mjs.map +1 -1
- package/fesm2022/ngwr-rating-testing.mjs +384 -0
- package/fesm2022/ngwr-rating-testing.mjs.map +1 -0
- package/fesm2022/ngwr-rating.mjs +37 -2
- package/fesm2022/ngwr-rating.mjs.map +1 -1
- package/fesm2022/ngwr-segmented-testing.mjs +512 -0
- package/fesm2022/ngwr-segmented-testing.mjs.map +1 -0
- package/fesm2022/ngwr-select-testing.mjs +268 -0
- package/fesm2022/ngwr-select-testing.mjs.map +1 -0
- package/fesm2022/ngwr-select.mjs +87 -16
- package/fesm2022/ngwr-select.mjs.map +1 -1
- package/fesm2022/ngwr-shiny-text.mjs +2 -2
- package/fesm2022/ngwr-shiny-text.mjs.map +1 -1
- package/fesm2022/ngwr-sidebar.mjs +65 -12
- package/fesm2022/ngwr-sidebar.mjs.map +1 -1
- package/fesm2022/ngwr-slider-testing.mjs +478 -0
- package/fesm2022/ngwr-slider-testing.mjs.map +1 -0
- package/fesm2022/ngwr-slider.mjs +57 -13
- package/fesm2022/ngwr-slider.mjs.map +1 -1
- package/fesm2022/ngwr-sparkline.mjs +26 -6
- package/fesm2022/ngwr-sparkline.mjs.map +1 -1
- package/fesm2022/ngwr-speed-dial.mjs +37 -4
- package/fesm2022/ngwr-speed-dial.mjs.map +1 -1
- package/fesm2022/ngwr-spinner.mjs +12 -3
- package/fesm2022/ngwr-spinner.mjs.map +1 -1
- package/fesm2022/ngwr-splash-cursor.mjs +2 -2
- package/fesm2022/ngwr-splash-cursor.mjs.map +1 -1
- package/fesm2022/ngwr-split-text.mjs +2 -2
- package/fesm2022/ngwr-split-text.mjs.map +1 -1
- package/fesm2022/ngwr-splitter.mjs +70 -9
- package/fesm2022/ngwr-splitter.mjs.map +1 -1
- package/fesm2022/ngwr-spotlight-card.mjs +2 -2
- package/fesm2022/ngwr-spotlight-card.mjs.map +1 -1
- package/fesm2022/ngwr-star-border.mjs +2 -2
- package/fesm2022/ngwr-star-border.mjs.map +1 -1
- package/fesm2022/ngwr-statistic.mjs +24 -7
- package/fesm2022/ngwr-statistic.mjs.map +1 -1
- package/fesm2022/ngwr-stepper-testing.mjs +477 -0
- package/fesm2022/ngwr-stepper-testing.mjs.map +1 -0
- package/fesm2022/ngwr-switch-testing.mjs +77 -0
- package/fesm2022/ngwr-switch-testing.mjs.map +1 -0
- package/fesm2022/ngwr-switch.mjs +9 -3
- package/fesm2022/ngwr-switch.mjs.map +1 -1
- package/fesm2022/ngwr-table-testing.mjs +580 -0
- package/fesm2022/ngwr-table-testing.mjs.map +1 -0
- package/fesm2022/ngwr-table.mjs +87 -14
- package/fesm2022/ngwr-table.mjs.map +1 -1
- package/fesm2022/ngwr-tabs-testing.mjs +617 -0
- package/fesm2022/ngwr-tabs-testing.mjs.map +1 -0
- package/fesm2022/ngwr-tabs.mjs +38 -6
- package/fesm2022/ngwr-tabs.mjs.map +1 -1
- package/fesm2022/ngwr-textarea-testing.mjs +238 -0
- package/fesm2022/ngwr-textarea-testing.mjs.map +1 -0
- package/fesm2022/ngwr-textarea.mjs +32 -4
- package/fesm2022/ngwr-textarea.mjs.map +1 -1
- package/fesm2022/ngwr-tilt-card.mjs +2 -2
- package/fesm2022/ngwr-tilt-card.mjs.map +1 -1
- package/fesm2022/ngwr-toast-testing.mjs +101 -0
- package/fesm2022/ngwr-toast-testing.mjs.map +1 -0
- package/fesm2022/ngwr-toast.mjs +2 -2
- package/fesm2022/ngwr-toast.mjs.map +1 -1
- package/fesm2022/ngwr-tour.mjs +61 -9
- package/fesm2022/ngwr-tour.mjs.map +1 -1
- package/fesm2022/ngwr-transfer-testing.mjs +538 -0
- package/fesm2022/ngwr-transfer-testing.mjs.map +1 -0
- package/fesm2022/ngwr-transfer.mjs +45 -14
- package/fesm2022/ngwr-transfer.mjs.map +1 -1
- package/fesm2022/ngwr-tree-testing.mjs +734 -0
- package/fesm2022/ngwr-tree-testing.mjs.map +1 -0
- package/fesm2022/ngwr-tree.mjs +73 -7
- package/fesm2022/ngwr-tree.mjs.map +1 -1
- package/fesm2022/ngwr-typewriter.mjs +5 -3
- package/fesm2022/ngwr-typewriter.mjs.map +1 -1
- package/fesm2022/ngwr-version.mjs +1 -1
- package/fesm2022/ngwr-version.mjs.map +1 -1
- package/fesm2022/ngwr-virtual-scroll.mjs +31 -5
- package/fesm2022/ngwr-virtual-scroll.mjs.map +1 -1
- package/fesm2022/ngwr-waves.mjs +3 -3
- package/fesm2022/ngwr-waves.mjs.map +1 -1
- package/fesm2022/ngwr-window.mjs +8 -0
- package/fesm2022/ngwr-window.mjs.map +1 -1
- package/gauge/styles/_index.scss +1 -1
- package/glitch-text/styles/_index.scss +4 -0
- package/i18n/en.json +48 -0
- package/i18n/ru.json +48 -0
- package/image-cropper/styles/_index.scss +13 -1
- package/input/styles/_index.scss +2 -2
- package/input-number/styles/_index.scss +7 -2
- package/knob/styles/_index.scss +8 -1
- package/layout/styles/_index.scss +3 -3
- package/lightbox/styles/_index.scss +10 -2
- package/line-chart/styles/_index.scss +6 -0
- package/llms-full.txt +151 -4
- package/llms.txt +57 -8
- package/loading-bar/styles/_index.scss +1 -2
- package/markdown/styles/_index.scss +296 -0
- package/marquee/styles/_index.scss +12 -0
- package/mcp/api.js +512 -0
- package/mcp/catalog.js +157 -0
- package/mcp/server.js +273 -0
- package/mcp/tools.js +366 -0
- package/meter-group/styles/_index.scss +1 -1
- package/package.json +186 -35
- package/pagination/styles/_index.scss +6 -6
- package/popover/styles/_index.scss +37 -5
- package/rating/styles/_index.scss +10 -0
- package/schematics/use/symbol-map.json +2 -0
- package/segmented/styles/_index.scss +7 -0
- package/select/styles/_index.scss +29 -9
- package/sidebar/styles/_index.scss +30 -5
- package/slider/styles/_index.scss +15 -0
- package/speed-dial/styles/_index.scss +20 -0
- package/split-text/styles/_index.scss +13 -0
- package/star-border/styles/_index.scss +2 -0
- package/stepper/styles/_index.scss +1 -1
- package/styles/_grid.scss +4 -4
- package/styles.scss +1 -0
- package/switch/styles/_index.scss +5 -3
- package/table/styles/_index.scss +22 -11
- package/tabs/styles/_index.scss +11 -1
- package/textarea/styles/_index.scss +5 -0
- package/theme/styles/_colors.scss +29 -13
- package/theme/styles/_dark.scss +11 -3
- package/theme/styles/_mixins.scss +3 -0
- package/timeline/styles/_index.scss +2 -2
- package/toast/styles/_index.scss +17 -8
- package/toolbar/styles/_index.scss +3 -3
- package/tour/styles/_index.scss +7 -1
- package/tree/styles/_index.scss +5 -3
- package/types/ngwr-action-sheet.d.ts +9 -1
- package/types/ngwr-affix.d.ts +7 -1
- package/types/ngwr-anchor.d.ts +8 -1
- package/types/ngwr-avatar.d.ts +13 -3
- package/types/ngwr-bar-chart.d.ts +16 -0
- package/types/ngwr-burger.d.ts +6 -2
- package/types/ngwr-button-testing.d.ts +85 -0
- package/types/ngwr-button.d.ts +26 -10
- package/types/ngwr-calendar-heatmap.d.ts +16 -2
- package/types/ngwr-calendar.d.ts +10 -0
- package/types/ngwr-carousel-testing.d.ts +257 -0
- package/types/ngwr-carousel.d.ts +20 -4
- package/types/ngwr-cascader-testing.d.ts +392 -0
- package/types/ngwr-checkbox-testing.d.ts +77 -0
- package/types/ngwr-checkbox.d.ts +7 -2
- package/types/ngwr-collapse-testing.d.ts +290 -0
- package/types/ngwr-color-picker.d.ts +20 -11
- package/types/ngwr-command-palette-testing.d.ts +437 -0
- package/types/ngwr-command-palette.d.ts +25 -2
- package/types/ngwr-compare.d.ts +50 -2
- package/types/ngwr-config.d.ts +176 -0
- package/types/ngwr-context-menu-testing.d.ts +401 -0
- package/types/ngwr-context-menu.d.ts +65 -17
- package/types/ngwr-counter.d.ts +6 -1
- package/types/ngwr-date-adapter-luxon.d.ts +26 -0
- package/types/ngwr-date-picker-testing.d.ts +518 -0
- package/types/ngwr-date-picker.d.ts +4 -0
- package/types/ngwr-dialog-testing.d.ts +79 -0
- package/types/ngwr-directives.d.ts +10 -1
- package/types/ngwr-donut-chart.d.ts +8 -1
- package/types/ngwr-drawer-testing.d.ts +196 -0
- package/types/ngwr-dropdown-testing.d.ts +202 -0
- package/types/ngwr-dropdown.d.ts +7 -1
- package/types/ngwr-empty.d.ts +19 -4
- package/types/ngwr-event-calendar.d.ts +26 -1
- package/types/ngwr-file-upload-testing.d.ts +194 -0
- package/types/ngwr-form-testing.d.ts +379 -0
- package/types/ngwr-form.d.ts +17 -0
- package/types/ngwr-gauge.d.ts +13 -1
- package/types/ngwr-image-cropper.d.ts +10 -0
- package/types/ngwr-input-number-testing.d.ts +226 -0
- package/types/ngwr-input-number.d.ts +29 -1
- package/types/ngwr-input-otp-testing.d.ts +299 -0
- package/types/ngwr-input-otp.d.ts +23 -2
- package/types/ngwr-input-testing.d.ts +84 -0
- package/types/ngwr-input.d.ts +20 -6
- package/types/ngwr-knob.d.ts +18 -0
- package/types/ngwr-layout.d.ts +1 -0
- package/types/ngwr-lightbox.d.ts +17 -3
- package/types/ngwr-line-chart.d.ts +9 -2
- package/types/ngwr-markdown-testing.d.ts +462 -0
- package/types/ngwr-markdown.d.ts +534 -0
- package/types/ngwr-marquee.d.ts +12 -2
- package/types/ngwr-mention-testing.d.ts +359 -0
- package/types/ngwr-meta.d.ts +4 -2
- package/types/ngwr-meter-group.d.ts +11 -1
- package/types/ngwr-overlay.d.ts +33 -2
- package/types/ngwr-pagination-testing.d.ts +291 -0
- package/types/ngwr-pagination.d.ts +1 -0
- package/types/ngwr-popconfirm-testing.d.ts +235 -0
- package/types/ngwr-popconfirm.d.ts +31 -21
- package/types/ngwr-popover-testing.d.ts +221 -0
- package/types/ngwr-popover.d.ts +9 -0
- package/types/ngwr-pull-to-refresh.d.ts +7 -0
- package/types/ngwr-qr.d.ts +9 -1
- package/types/ngwr-radio-testing.d.ts +296 -0
- package/types/ngwr-radio.d.ts +8 -2
- package/types/ngwr-rating-testing.d.ts +291 -0
- package/types/ngwr-rating.d.ts +23 -0
- package/types/ngwr-segmented-testing.d.ts +401 -0
- package/types/ngwr-select-testing.d.ts +175 -0
- package/types/ngwr-select.d.ts +45 -4
- package/types/ngwr-sidebar.d.ts +17 -2
- package/types/ngwr-slider-testing.d.ts +329 -0
- package/types/ngwr-slider.d.ts +35 -1
- package/types/ngwr-sparkline.d.ts +12 -2
- package/types/ngwr-speed-dial.d.ts +17 -18
- package/types/ngwr-spinner.d.ts +8 -1
- package/types/ngwr-splitter.d.ts +24 -1
- package/types/ngwr-statistic.d.ts +12 -2
- package/types/ngwr-stepper-testing.d.ts +346 -0
- package/types/ngwr-switch-testing.d.ts +66 -0
- package/types/ngwr-switch.d.ts +7 -2
- package/types/ngwr-table-testing.d.ts +423 -0
- package/types/ngwr-table.d.ts +42 -0
- package/types/ngwr-tabs-testing.d.ts +470 -0
- package/types/ngwr-tabs.d.ts +9 -0
- package/types/ngwr-textarea-testing.d.ts +184 -0
- package/types/ngwr-textarea.d.ts +7 -2
- package/types/ngwr-toast-testing.d.ts +80 -0
- package/types/ngwr-tour.d.ts +27 -0
- package/types/ngwr-transfer-testing.d.ts +444 -0
- package/types/ngwr-transfer.d.ts +16 -1
- package/types/ngwr-tree-testing.d.ts +501 -0
- package/types/ngwr-tree.d.ts +33 -0
- package/types/ngwr-version.d.ts +1 -1
- package/types/ngwr-virtual-scroll.d.ts +13 -1
- package/typewriter/styles/_index.scss +1 -1
- package/typography/styles/_index.scss +1 -1
- package/window/styles/_index.scss +32 -9
package/mcp/server.js
ADDED
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* @license
|
|
4
|
+
*
|
|
5
|
+
* Use of this source code is governed by an MIT-style license that can be
|
|
6
|
+
* found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE
|
|
7
|
+
*/
|
|
8
|
+
import { Catalog } from './catalog.js';
|
|
9
|
+
import { TOOLS, callTool, validateArguments } from './tools.js';
|
|
10
|
+
/**
|
|
11
|
+
* The ngwr MCP server — stdio, JSON-RPC 2.0, no dependencies.
|
|
12
|
+
*
|
|
13
|
+
* **Hand-rolled rather than built on the MCP SDK, and that is a deliberate
|
|
14
|
+
* trade.** This ships inside `ngwr`, whose only runtime dependency is `tslib`;
|
|
15
|
+
* an SDK would put a dependency tree behind every `npm i ngwr` for a feature most
|
|
16
|
+
* consumers never run. The protocol surface a tools-only server needs is a
|
|
17
|
+
* handful of methods and a framing rule.
|
|
18
|
+
*
|
|
19
|
+
* What that trade costs is that the error paths are the author's problem, and the
|
|
20
|
+
* first draft got several of them wrong in the same way: it answered the WRONG
|
|
21
|
+
* ID, or nothing at all. A client that never receives a response for an id does
|
|
22
|
+
* not fail — it waits, which is worse. Every branch here now ends in exactly one
|
|
23
|
+
* reply per request, and none for a notification.
|
|
24
|
+
*
|
|
25
|
+
* Run it with `npx ngwr-mcp`, or point a client at
|
|
26
|
+
* `node ./node_modules/ngwr/mcp/server.js`.
|
|
27
|
+
*
|
|
28
|
+
* @see https://modelcontextprotocol.io
|
|
29
|
+
*/
|
|
30
|
+
/** Versions this server knows how to speak. The newest is what it offers. */
|
|
31
|
+
const PROTOCOL_VERSIONS = ['2025-06-18', '2025-03-26', '2024-11-05'];
|
|
32
|
+
/**
|
|
33
|
+
* How much unterminated input to hold before giving up on the line.
|
|
34
|
+
*
|
|
35
|
+
* No MCP limit exists to violate, but an unbounded buffer means a client that
|
|
36
|
+
* never sends a newline grows this process until the machine complains. 32 MB is
|
|
37
|
+
* far past any real message — the largest this server can be asked for is a few
|
|
38
|
+
* hundred kilobytes.
|
|
39
|
+
*/
|
|
40
|
+
const MAX_LINE_BYTES = 32 * 1024 * 1024;
|
|
41
|
+
/**
|
|
42
|
+
* How many requests one batch may carry.
|
|
43
|
+
*
|
|
44
|
+
* Measured, not guessed: 58,000 entirely valid `get_ngwr_api` calls in one 6.8 MB
|
|
45
|
+
* batch made the single `JSON.stringify` of the reply array throw
|
|
46
|
+
* `RangeError: Invalid string length`, which killed the process with ZERO bytes
|
|
47
|
+
* written and none of the 58,000 ids answered — the exact failure this file's
|
|
48
|
+
* docblock says was eliminated. 30,000 entries already peaked at 3.3 GB of
|
|
49
|
+
* resident memory. No real client batches more than a handful.
|
|
50
|
+
*/
|
|
51
|
+
const MAX_BATCH = 256;
|
|
52
|
+
const PARSE_ERROR = -32700;
|
|
53
|
+
const INVALID_REQUEST = -32600;
|
|
54
|
+
const METHOD_NOT_FOUND = -32601;
|
|
55
|
+
const INVALID_PARAMS = -32602;
|
|
56
|
+
const INTERNAL_ERROR = -32603;
|
|
57
|
+
const catalog = new Catalog();
|
|
58
|
+
/**
|
|
59
|
+
* Stdout carries the protocol and nothing else.
|
|
60
|
+
*
|
|
61
|
+
* A stray `console.log` anywhere in this process corrupts the stream and the
|
|
62
|
+
* client drops the connection — which is why diagnostics go to stderr, and why
|
|
63
|
+
* the catalog is read lazily rather than announced at start-up.
|
|
64
|
+
*/
|
|
65
|
+
function write(message) {
|
|
66
|
+
let line;
|
|
67
|
+
try {
|
|
68
|
+
line = JSON.stringify(message);
|
|
69
|
+
}
|
|
70
|
+
catch (error) {
|
|
71
|
+
// Serialising the reply is the last thing that can fail, and failing here
|
|
72
|
+
// used to take the process down before a single byte was written. An error
|
|
73
|
+
// the client can correlate is worth more than a crash.
|
|
74
|
+
line = JSON.stringify(err(null, INTERNAL_ERROR, `Reply could not be serialised: ${String(error)}`));
|
|
75
|
+
}
|
|
76
|
+
process.stdout.write(`${line}\n`);
|
|
77
|
+
}
|
|
78
|
+
function ok(id, result) {
|
|
79
|
+
return { jsonrpc: '2.0', id, result };
|
|
80
|
+
}
|
|
81
|
+
function err(id, code, message) {
|
|
82
|
+
return { jsonrpc: '2.0', id, error: { code, message } };
|
|
83
|
+
}
|
|
84
|
+
/** JSON-RPC allows a String, a Number or Null. Anything else is not an id. */
|
|
85
|
+
function idOf(value) {
|
|
86
|
+
if (typeof value === 'string' || typeof value === 'number' || value === null)
|
|
87
|
+
return value;
|
|
88
|
+
return undefined;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* One request to one response, or `null` for a notification.
|
|
92
|
+
*
|
|
93
|
+
* A notification is a request with NO `id` member — not one whose id is null,
|
|
94
|
+
* which §4 says must still be answered.
|
|
95
|
+
*/
|
|
96
|
+
function respond(message) {
|
|
97
|
+
if (typeof message !== 'object' || message === null || Array.isArray(message)) {
|
|
98
|
+
return err(null, INVALID_REQUEST, 'A request must be a JSON object.');
|
|
99
|
+
}
|
|
100
|
+
const request = message;
|
|
101
|
+
const notification = !('id' in request);
|
|
102
|
+
const id = notification ? null : idOf(request.id);
|
|
103
|
+
if (!notification && id === undefined) {
|
|
104
|
+
return err(null, INVALID_REQUEST, 'A request id must be a string, a number or null.');
|
|
105
|
+
}
|
|
106
|
+
const reply = (response) => (notification ? null : response);
|
|
107
|
+
if (request.jsonrpc !== '2.0') {
|
|
108
|
+
return reply(err(id ?? null, INVALID_REQUEST, 'Only JSON-RPC 2.0 is supported.'));
|
|
109
|
+
}
|
|
110
|
+
if (typeof request.method !== 'string') {
|
|
111
|
+
return reply(err(id ?? null, INVALID_REQUEST, 'A request needs a method name.'));
|
|
112
|
+
}
|
|
113
|
+
// `null` params reads as "none given". Lenient on purpose: clients send it for
|
|
114
|
+
// a method that takes nothing, and the version that let it through to a
|
|
115
|
+
// destructure threw — which the framing layer then reported as a PARSE error
|
|
116
|
+
// against a null id, so the real request was never answered at all.
|
|
117
|
+
const raw = request.params;
|
|
118
|
+
if (raw !== undefined && raw !== null && (typeof raw !== 'object' || Array.isArray(raw))) {
|
|
119
|
+
return reply(err(id ?? null, INVALID_PARAMS, 'Params must be an object.'));
|
|
120
|
+
}
|
|
121
|
+
const params = (raw ?? {});
|
|
122
|
+
try {
|
|
123
|
+
const response = handle(id ?? null, request.method, params);
|
|
124
|
+
return reply(response);
|
|
125
|
+
}
|
|
126
|
+
catch (error) {
|
|
127
|
+
// A handler that throws is an internal error against the REAL id. Blaming
|
|
128
|
+
// the parser, as the first version did, tells the client its message was
|
|
129
|
+
// malformed and leaves the id it is waiting on unanswered for ever.
|
|
130
|
+
return reply(err(id ?? null, INTERNAL_ERROR, error instanceof Error ? error.message : String(error)));
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
function handle(id, method, params) {
|
|
134
|
+
switch (method) {
|
|
135
|
+
case 'initialize': {
|
|
136
|
+
const asked = typeof params.protocolVersion === 'string' ? params.protocolVersion : '';
|
|
137
|
+
return ok(id, {
|
|
138
|
+
// Echo the client's version when it is one we speak, so an older client
|
|
139
|
+
// is not told to upgrade for a server that would have worked.
|
|
140
|
+
protocolVersion: PROTOCOL_VERSIONS.includes(asked)
|
|
141
|
+
? asked
|
|
142
|
+
: PROTOCOL_VERSIONS[0],
|
|
143
|
+
capabilities: { tools: {} },
|
|
144
|
+
serverInfo: { name: 'ngwr', title: 'ngwr component catalog', version: catalog.version() },
|
|
145
|
+
instructions: 'Angular component library. Use search_ngwr first when you do not know an entry point name, ' +
|
|
146
|
+
'then get_ngwr_api for exact signatures and get_ngwr_setup for the commands to wire it in.',
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
case 'ping':
|
|
150
|
+
return ok(id, {});
|
|
151
|
+
case 'tools/list':
|
|
152
|
+
return ok(id, { tools: TOOLS });
|
|
153
|
+
case 'tools/call': {
|
|
154
|
+
const name = params.name;
|
|
155
|
+
if (typeof name !== 'string')
|
|
156
|
+
return err(id, INVALID_PARAMS, 'tools/call needs a tool name.');
|
|
157
|
+
const tool = TOOLS.find(candidate => candidate.name === name);
|
|
158
|
+
// An unknown tool is a protocol error, not an answer. Returned as a
|
|
159
|
+
// successful call it reads to an agent like the reply to its question.
|
|
160
|
+
if (!tool) {
|
|
161
|
+
return err(id, INVALID_PARAMS, `Unknown tool: ${name}. Available: ${TOOLS.map(t => t.name).join(', ')}.`);
|
|
162
|
+
}
|
|
163
|
+
const args = (params.arguments ?? {});
|
|
164
|
+
if (typeof args !== 'object' || args === null || Array.isArray(args)) {
|
|
165
|
+
return err(id, INVALID_PARAMS, `${name}: arguments must be an object.`);
|
|
166
|
+
}
|
|
167
|
+
// The schema is published at `tools/list`; honouring it is what stops a
|
|
168
|
+
// wrong argument type reaching the tool and coming back as a raw V8
|
|
169
|
+
// TypeError in the agent's face.
|
|
170
|
+
const complaint = validateArguments(tool, args);
|
|
171
|
+
if (complaint)
|
|
172
|
+
return err(id, INVALID_PARAMS, `${name}: ${complaint}`);
|
|
173
|
+
try {
|
|
174
|
+
return ok(id, { content: [{ type: 'text', text: callTool(catalog, name, args) }] });
|
|
175
|
+
}
|
|
176
|
+
catch (error) {
|
|
177
|
+
// A tool that throws is a failed CALL, not a failed request: reporting it
|
|
178
|
+
// this way leaves the conversation intact and tells the agent what went
|
|
179
|
+
// wrong, where a JSON-RPC error just looks like a broken server.
|
|
180
|
+
return ok(id, {
|
|
181
|
+
content: [
|
|
182
|
+
{ type: 'text', text: `${name} failed: ${error instanceof Error ? error.message : String(error)}` },
|
|
183
|
+
],
|
|
184
|
+
isError: true,
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
default:
|
|
189
|
+
return err(id, METHOD_NOT_FOUND, `Unknown method: ${method}`);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
/** One line in, at most one message out. Batches answer as a batch. */
|
|
193
|
+
function dispatch(line) {
|
|
194
|
+
let message;
|
|
195
|
+
try {
|
|
196
|
+
message = JSON.parse(line);
|
|
197
|
+
}
|
|
198
|
+
catch {
|
|
199
|
+
write(err(null, PARSE_ERROR, 'Parse error'));
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
// Batching is part of the two older protocol revisions this server offers, and
|
|
203
|
+
// silence is not a legal answer to any of them: the first version destructured
|
|
204
|
+
// the array, found no method, and dropped every id in it.
|
|
205
|
+
if (Array.isArray(message)) {
|
|
206
|
+
if (message.length === 0) {
|
|
207
|
+
write(err(null, INVALID_REQUEST, 'A batch must not be empty.'));
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
if (message.length > MAX_BATCH) {
|
|
211
|
+
write(err(null, INVALID_REQUEST, `A batch may carry at most ${MAX_BATCH} requests.`));
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
const responses = message.map(respond).filter((response) => response !== null);
|
|
215
|
+
if (responses.length > 0)
|
|
216
|
+
write(responses);
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
const response = respond(message);
|
|
220
|
+
if (response)
|
|
221
|
+
write(response);
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* Newline-delimited JSON on stdin.
|
|
225
|
+
*
|
|
226
|
+
* Buffered across chunks: a message longer than one read arrives in pieces, and a
|
|
227
|
+
* parser that assumed one chunk per message would work in testing and drop every
|
|
228
|
+
* large `tools/call` in the field.
|
|
229
|
+
*/
|
|
230
|
+
let buffer = '';
|
|
231
|
+
process.stdin.setEncoding('utf8');
|
|
232
|
+
process.stdin.on('data', (chunk) => {
|
|
233
|
+
buffer += chunk;
|
|
234
|
+
// `Buffer.byteLength`, not `.length`: the latter counts UTF-16 units, so
|
|
235
|
+
// 93 MB of three-byte characters passed a 32 MB cap untouched.
|
|
236
|
+
if (Buffer.byteLength(buffer, 'utf8') > MAX_LINE_BYTES) {
|
|
237
|
+
// Discard only the oversize LINE and resynchronise on the next one. Clearing
|
|
238
|
+
// the whole buffer threw away a complete, valid request that had already
|
|
239
|
+
// arrived behind it — answered with nothing, which is the one outcome this
|
|
240
|
+
// file is written to avoid.
|
|
241
|
+
const newline = buffer.indexOf('\n');
|
|
242
|
+
buffer = newline === -1 ? '' : buffer.slice(newline + 1);
|
|
243
|
+
write(err(null, INVALID_REQUEST, 'Message exceeded the maximum size and was discarded.'));
|
|
244
|
+
}
|
|
245
|
+
let newline = buffer.indexOf('\n');
|
|
246
|
+
while (newline !== -1) {
|
|
247
|
+
const line = buffer.slice(0, newline).trim();
|
|
248
|
+
buffer = buffer.slice(newline + 1);
|
|
249
|
+
newline = buffer.indexOf('\n');
|
|
250
|
+
if (line)
|
|
251
|
+
dispatch(line);
|
|
252
|
+
}
|
|
253
|
+
});
|
|
254
|
+
process.stdin.on('end', () => {
|
|
255
|
+
// A client that closes without a trailing newline still asked something. The
|
|
256
|
+
// version that exited here dropped it and reported success.
|
|
257
|
+
const last = buffer.trim();
|
|
258
|
+
buffer = '';
|
|
259
|
+
if (last)
|
|
260
|
+
dispatch(last);
|
|
261
|
+
// NOT `process.exit()`: writes to a pipe are asynchronous above the kernel
|
|
262
|
+
// buffer, and exiting discards whatever is still queued. A 1000-symbol
|
|
263
|
+
// `get_ngwr_setup` came back cut at exactly 65 536 bytes — mid-string, with a
|
|
264
|
+
// zero exit code. Setting the code and letting the loop drain sends all of it.
|
|
265
|
+
process.exitCode = 0;
|
|
266
|
+
});
|
|
267
|
+
// A client that dies without closing stdin leaves this writing into a broken
|
|
268
|
+
// pipe. Exiting quietly is the correct end of a session, not a crash with a
|
|
269
|
+
// stack trace.
|
|
270
|
+
process.stdout.on('error', error => {
|
|
271
|
+
if (error.code === 'EPIPE')
|
|
272
|
+
process.exit(0);
|
|
273
|
+
});
|
package/mcp/tools.js
ADDED
|
@@ -0,0 +1,366 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
*
|
|
4
|
+
* Use of this source code is governed by an MIT-style license that can be
|
|
5
|
+
* found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE
|
|
6
|
+
*/
|
|
7
|
+
import { declaredClasses, extractClass } from './api.js';
|
|
8
|
+
const DOCS = 'https://ngwr.dev';
|
|
9
|
+
/**
|
|
10
|
+
* The four tools, and why there are only four.
|
|
11
|
+
*
|
|
12
|
+
* Each one answers a question an agent actually has when it is holding this
|
|
13
|
+
* library for the first time: what is there, how do I use this one, what does it
|
|
14
|
+
* take, and what do I have to install. Anything else it can already do — the
|
|
15
|
+
* docs are prerendered HTML with a markdown twin at every URL, and the types are
|
|
16
|
+
* in the tarball. A tool per docs page would be a worse version of `fetch`.
|
|
17
|
+
*/
|
|
18
|
+
const TOOLS = [
|
|
19
|
+
{
|
|
20
|
+
name: 'search_ngwr',
|
|
21
|
+
description: 'Search the ngwr catalog by what you need ("date range picker", "wr-select", "virtual scroll"). ' +
|
|
22
|
+
'Returns matching entry points with their import line, selector and one-line description. ' +
|
|
23
|
+
'Start here when you do not already know the entry point name.',
|
|
24
|
+
inputSchema: {
|
|
25
|
+
type: 'object',
|
|
26
|
+
properties: {
|
|
27
|
+
query: { type: 'string', description: 'What you are looking for.' },
|
|
28
|
+
limit: { type: 'number', description: 'Maximum results. Defaults to 10.' },
|
|
29
|
+
},
|
|
30
|
+
required: ['query'],
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
name: 'get_ngwr_component',
|
|
35
|
+
description: 'Everything about one entry point: description, selector, exports, import line, SCSS import, ' +
|
|
36
|
+
'documentation URL and the markdown twin of its docs page. Accepts an entry point ' +
|
|
37
|
+
'("ngwr/select", "select"), a symbol ("WrSelect") or a selector ("wr-select").',
|
|
38
|
+
inputSchema: {
|
|
39
|
+
type: 'object',
|
|
40
|
+
properties: { name: { type: 'string', description: 'Entry point, symbol or selector.' } },
|
|
41
|
+
required: ['name'],
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
name: 'get_ngwr_api',
|
|
46
|
+
description: 'The public inputs, models, outputs and methods of one ngwr class, read out of the ' +
|
|
47
|
+
'declarations shipped in this package — so it is the published signature, not a copy of it. ' +
|
|
48
|
+
'Use instead of reading the .d.ts, which can be 60 KB for one component.',
|
|
49
|
+
inputSchema: {
|
|
50
|
+
type: 'object',
|
|
51
|
+
properties: {
|
|
52
|
+
symbol: { type: 'string', description: 'Class name, e.g. WrSelect.' },
|
|
53
|
+
kind: {
|
|
54
|
+
type: 'string',
|
|
55
|
+
enum: ['all', 'input', 'model', 'output', 'method', 'property'],
|
|
56
|
+
description: 'Narrow the surface. Defaults to all.',
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
required: ['symbol'],
|
|
60
|
+
},
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
name: 'get_ngwr_setup',
|
|
64
|
+
description: 'The exact commands and providers needed to use one or more ngwr symbols in an app: ' +
|
|
65
|
+
'install, the `ng g ngwr:use` invocation that wires the import, the SCSS to load, and any ' +
|
|
66
|
+
'provider the symbol depends on. Returns commands to run; it never runs them.',
|
|
67
|
+
inputSchema: {
|
|
68
|
+
type: 'object',
|
|
69
|
+
properties: {
|
|
70
|
+
symbols: {
|
|
71
|
+
type: 'array',
|
|
72
|
+
items: { type: 'string' },
|
|
73
|
+
description: 'Symbols you intend to use, e.g. ["WrSelect", "WrDialog"].',
|
|
74
|
+
},
|
|
75
|
+
},
|
|
76
|
+
required: ['symbols'],
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
];
|
|
80
|
+
/**
|
|
81
|
+
* Providers a symbol cannot work without.
|
|
82
|
+
*
|
|
83
|
+
* Hard-coded, and the list is short on purpose: these are the four cases where
|
|
84
|
+
* the component compiles, renders nothing useful, and gives no error that names
|
|
85
|
+
* the cause. Everything else is discoverable from the docs page.
|
|
86
|
+
*/
|
|
87
|
+
const REQUIRED_PROVIDERS = [
|
|
88
|
+
{
|
|
89
|
+
test: /^Wr(Dialog|Drawer|Toast|Popover|Popconfirm|ContextMenu|Select|Dropdown|CommandPalette|Cascader|Mention|DatePicker|Tour|Lightbox)/,
|
|
90
|
+
provider: "provideWrOverlay() // from 'ngwr/overlay'",
|
|
91
|
+
why: 'overlays render into an ngwr-owned container; without it they never appear',
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
test: /^WrIcon/,
|
|
95
|
+
provider: "provideWrIcons(lucideIcons({ … })) // from 'ngwr/icon' + 'ngwr/icon/adapters/lucide'",
|
|
96
|
+
why: 'icons resolve by name from a registry you populate',
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
test: /^WrDatePicker|^WrCalendar|^WrEventCalendar/,
|
|
100
|
+
provider: "provideWrDateAdapter(wrDateFnsAdapter) // from 'ngwr/date-adapter-fns'",
|
|
101
|
+
why: 'every date mode goes through an adapter; there is no built-in default',
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
test: /^WrT$|^WrI18n/,
|
|
105
|
+
provider: "provideWrI18n() + provideWrI18nStaticLoader({ en: wrEn }) // from 'ngwr/i18n'",
|
|
106
|
+
why: 'the pipe and directive read from a catalog you provide',
|
|
107
|
+
},
|
|
108
|
+
];
|
|
109
|
+
/**
|
|
110
|
+
* The published schema, actually enforced.
|
|
111
|
+
*
|
|
112
|
+
* A server that advertises `required: ["query"]` at `tools/list` and then accepts
|
|
113
|
+
* a call without it is lying in a way an agent cannot detect. Worse, three of the
|
|
114
|
+
* six wrong-argument shapes reached the tool body and came back as a raw V8
|
|
115
|
+
* `TypeError` — `symbols.map is not a function` — presented as the answer.
|
|
116
|
+
*
|
|
117
|
+
* Deliberately small: presence, and the handful of types these schemas use. This
|
|
118
|
+
* is not a JSON Schema implementation and should not grow into one.
|
|
119
|
+
*/
|
|
120
|
+
function validateArguments(tool, args) {
|
|
121
|
+
const schema = tool.inputSchema;
|
|
122
|
+
for (const name of schema.required ?? []) {
|
|
123
|
+
if (args[name] === undefined || args[name] === null)
|
|
124
|
+
return `\`${name}\` is required.`;
|
|
125
|
+
}
|
|
126
|
+
for (const [name, expected] of Object.entries(schema.properties ?? {})) {
|
|
127
|
+
const value = args[name];
|
|
128
|
+
if (value === undefined || value === null)
|
|
129
|
+
continue;
|
|
130
|
+
if (expected.type === 'array') {
|
|
131
|
+
if (!Array.isArray(value))
|
|
132
|
+
return `\`${name}\` must be an array.`;
|
|
133
|
+
const wanted = expected.items?.type ?? 'string';
|
|
134
|
+
const items = value;
|
|
135
|
+
if (items.some(item => typeof item !== wanted)) {
|
|
136
|
+
return `every item in \`${name}\` must be a ${wanted}.`;
|
|
137
|
+
}
|
|
138
|
+
continue;
|
|
139
|
+
}
|
|
140
|
+
if (expected.type && typeof value !== expected.type)
|
|
141
|
+
return `\`${name}\` must be a ${expected.type}.`;
|
|
142
|
+
// `enum` was published and unchecked, which failed in the worst possible
|
|
143
|
+
// shape: `kind: "Input"` answered successfully with ZERO members, and an
|
|
144
|
+
// agent has no way to tell that from a component with no inputs.
|
|
145
|
+
// `typeof` rather than `String(value)`: every `enum` property here is also
|
|
146
|
+
// `type: 'string'`, and stringifying an object would compare `[object Object]`.
|
|
147
|
+
if (expected.enum && (typeof value !== 'string' || !expected.enum.includes(value))) {
|
|
148
|
+
return `\`${name}\` must be one of ${expected.enum.join(', ')}.`;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
return null;
|
|
152
|
+
}
|
|
153
|
+
function isText(value) {
|
|
154
|
+
return typeof value === 'string';
|
|
155
|
+
}
|
|
156
|
+
/** An argument as a string, or empty — never `[object Object]`. */
|
|
157
|
+
function text(value) {
|
|
158
|
+
return isText(value) ? value : '';
|
|
159
|
+
}
|
|
160
|
+
/** Runs a tool and returns the text an agent will read. */
|
|
161
|
+
function callTool(catalog, name, args) {
|
|
162
|
+
switch (name) {
|
|
163
|
+
// Bracket access and `text()`, because `args` genuinely IS an untyped bag off
|
|
164
|
+
// the wire. The server checks it against the tool's published schema first;
|
|
165
|
+
// this layer still refuses to stringify an object into `[object Object]`.
|
|
166
|
+
case 'search_ngwr':
|
|
167
|
+
return search(catalog, text(args['query']), Number(args['limit'] ?? 10));
|
|
168
|
+
case 'get_ngwr_component':
|
|
169
|
+
return component(catalog, text(args['name']));
|
|
170
|
+
case 'get_ngwr_api':
|
|
171
|
+
return api(catalog, text(args['symbol']), text(args['kind']) || 'all');
|
|
172
|
+
case 'get_ngwr_setup':
|
|
173
|
+
return setup(catalog, Array.isArray(args['symbols']) ? args['symbols'].filter(isText) : []);
|
|
174
|
+
default:
|
|
175
|
+
return `Unknown tool: ${name}. Available: ${TOOLS.map(tool => tool.name).join(', ')}.`;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Ranked search over the catalog.
|
|
180
|
+
*
|
|
181
|
+
* Scored rather than filtered, because the useful query is "date range picker"
|
|
182
|
+
* and the useful answer is `ngwr/date-picker` first. Name and selector matches
|
|
183
|
+
* outrank a description match, since a description mentions neighbours —
|
|
184
|
+
* `wr-drawer` names the bottom sheet, `wr-select` names the tag mode — and a
|
|
185
|
+
* substring hit there is weaker evidence than the name itself.
|
|
186
|
+
*/
|
|
187
|
+
function search(catalog, query, limit) {
|
|
188
|
+
const terms = query.toLowerCase().split(/\s+/).filter(Boolean);
|
|
189
|
+
if (terms.length === 0)
|
|
190
|
+
return 'Give me something to search for.';
|
|
191
|
+
const scored = catalog
|
|
192
|
+
.all()
|
|
193
|
+
.map(entry => ({ entry, score: score(entry, terms) }))
|
|
194
|
+
.filter(hit => hit.score > 0)
|
|
195
|
+
.sort((a, b) => b.score - a.score || a.entry.path.localeCompare(b.entry.path))
|
|
196
|
+
.slice(0, Math.max(1, Math.min(limit || 10, 40)));
|
|
197
|
+
if (scored.length === 0) {
|
|
198
|
+
return `Nothing in the ngwr catalog matches "${query}". The full list is ${DOCS}/llms.txt.`;
|
|
199
|
+
}
|
|
200
|
+
return scored
|
|
201
|
+
.map(({ entry }) => [
|
|
202
|
+
`## ${entry.path}`,
|
|
203
|
+
entry.selectors.length > 0 ? `selector: ${entry.selectors.join(', ')}` : null,
|
|
204
|
+
`import: ${entry.import}`,
|
|
205
|
+
entry.description,
|
|
206
|
+
]
|
|
207
|
+
.filter(Boolean)
|
|
208
|
+
.join('\n'))
|
|
209
|
+
.join('\n\n');
|
|
210
|
+
}
|
|
211
|
+
function score(entry, terms) {
|
|
212
|
+
const name = entry.name.toLowerCase();
|
|
213
|
+
const selectors = entry.selectors.join(' ').toLowerCase();
|
|
214
|
+
const exports = entry.exports.join(' ').toLowerCase();
|
|
215
|
+
const description = entry.description.toLowerCase();
|
|
216
|
+
let total = 0;
|
|
217
|
+
for (const term of terms) {
|
|
218
|
+
if (name === term)
|
|
219
|
+
total += 100;
|
|
220
|
+
else if (name.includes(term))
|
|
221
|
+
total += 40;
|
|
222
|
+
if (selectors.includes(term))
|
|
223
|
+
total += 30;
|
|
224
|
+
if (exports.includes(term))
|
|
225
|
+
total += 20;
|
|
226
|
+
if (description.includes(term))
|
|
227
|
+
total += 5;
|
|
228
|
+
}
|
|
229
|
+
return total;
|
|
230
|
+
}
|
|
231
|
+
function component(catalog, name) {
|
|
232
|
+
const entry = catalog.find(name);
|
|
233
|
+
if (!entry)
|
|
234
|
+
return notFound(catalog, name);
|
|
235
|
+
const declarations = catalog.types(entry.path);
|
|
236
|
+
const classes = declarations ? declaredClasses(declarations).filter(symbol => entry.exports.includes(symbol)) : [];
|
|
237
|
+
const url = docsUrl(declarations, classes);
|
|
238
|
+
return [
|
|
239
|
+
`# ${entry.path}`,
|
|
240
|
+
'',
|
|
241
|
+
// An entry point with no description bullet answered with three blank lines.
|
|
242
|
+
...(entry.description ? [entry.description, ''] : []),
|
|
243
|
+
entry.selectors.length > 0 ? `- selector: ${entry.selectors.join(', ')}` : null,
|
|
244
|
+
`- import: ${entry.import}`,
|
|
245
|
+
// Only when there is one to load: 58 entry points ship no stylesheet.
|
|
246
|
+
catalog.hasStyles(entry.path) ? `- styles: @use '${entry.path}';` : null,
|
|
247
|
+
`- exports: ${entry.exports.join(', ')}`,
|
|
248
|
+
classes.length > 0 ? `- classes with an API: ${classes.join(', ')} (use get_ngwr_api)` : null,
|
|
249
|
+
// From the class's own `@see`, never guessed. Half the catalog — directives,
|
|
250
|
+
// services, pipes, utils, every `*/testing` harness — has no page under
|
|
251
|
+
// `/reference/components/`, and a link that 404s is worse than none.
|
|
252
|
+
url ? `- docs: ${url}` : null,
|
|
253
|
+
url ? `- docs as markdown: ${url}.md` : null,
|
|
254
|
+
]
|
|
255
|
+
.filter(line => line !== null)
|
|
256
|
+
.join('\n');
|
|
257
|
+
}
|
|
258
|
+
/** The documented URL of the first class that declares one. */
|
|
259
|
+
function docsUrl(declarations, classes) {
|
|
260
|
+
if (!declarations)
|
|
261
|
+
return null;
|
|
262
|
+
for (const symbol of classes) {
|
|
263
|
+
const found = extractClass(declarations, symbol);
|
|
264
|
+
if (found?.docs?.startsWith('http'))
|
|
265
|
+
return found.docs.split(/\s/)[0];
|
|
266
|
+
}
|
|
267
|
+
return null;
|
|
268
|
+
}
|
|
269
|
+
function api(catalog, symbol, kind) {
|
|
270
|
+
const entry = catalog.find(symbol);
|
|
271
|
+
if (!entry)
|
|
272
|
+
return notFound(catalog, symbol);
|
|
273
|
+
const declarations = catalog.types(entry.path);
|
|
274
|
+
if (!declarations)
|
|
275
|
+
return `${entry.path} ships no declarations, so there is no API to read.`;
|
|
276
|
+
const found = extractClass(declarations, symbol);
|
|
277
|
+
if (!found) {
|
|
278
|
+
return `${symbol} is not a class in ${entry.path}. It exports: ${entry.exports.join(', ')}.`;
|
|
279
|
+
}
|
|
280
|
+
const wanted = kind === 'all' ? null : kind;
|
|
281
|
+
const members = found.members.filter(member => (wanted ? member.kind === wanted : member.kind !== 'property'));
|
|
282
|
+
return [
|
|
283
|
+
`# ${found.name} — ${entry.path}`,
|
|
284
|
+
'',
|
|
285
|
+
found.description,
|
|
286
|
+
'',
|
|
287
|
+
...group(members, 'input'),
|
|
288
|
+
...group(members, 'model'),
|
|
289
|
+
...group(members, 'output'),
|
|
290
|
+
...group(members, 'method'),
|
|
291
|
+
...group(members, 'property'),
|
|
292
|
+
found.example ? `## Example\n${found.example}` : null,
|
|
293
|
+
found.docs ? `Docs: ${found.docs}` : null,
|
|
294
|
+
]
|
|
295
|
+
.filter(line => line !== null)
|
|
296
|
+
.join('\n');
|
|
297
|
+
}
|
|
298
|
+
function group(members, kind) {
|
|
299
|
+
const matching = members.filter(member => member.kind === kind);
|
|
300
|
+
if (matching.length === 0)
|
|
301
|
+
return [];
|
|
302
|
+
return [
|
|
303
|
+
`## ${kind === 'property' ? 'properties' : `${kind}s`}`,
|
|
304
|
+
...matching.map(member => {
|
|
305
|
+
const bits = [`- \`${member.name}\`: ${member.type}`];
|
|
306
|
+
if (member.alias)
|
|
307
|
+
bits.push(`(bound as \`${member.alias}\`)`);
|
|
308
|
+
if (member.required)
|
|
309
|
+
bits.push('(required)');
|
|
310
|
+
if (member.default)
|
|
311
|
+
bits.push(`default ${member.default}`);
|
|
312
|
+
if (member.description)
|
|
313
|
+
bits.push(`— ${member.description.replace(/\s+/g, ' ')}`);
|
|
314
|
+
return bits.join(' ');
|
|
315
|
+
}),
|
|
316
|
+
'',
|
|
317
|
+
];
|
|
318
|
+
}
|
|
319
|
+
function setup(catalog, symbols) {
|
|
320
|
+
if (symbols.length === 0)
|
|
321
|
+
return 'Name at least one symbol, e.g. ["WrSelect"].';
|
|
322
|
+
const found = symbols.map(symbol => ({ symbol, entry: catalog.find(symbol) }));
|
|
323
|
+
const missing = found.filter(hit => !hit.entry).map(hit => hit.symbol);
|
|
324
|
+
const resolved = found.filter((hit) => hit.entry !== null);
|
|
325
|
+
const providers = REQUIRED_PROVIDERS.filter(required => resolved.some(hit => required.test.test(hit.symbol)));
|
|
326
|
+
return [
|
|
327
|
+
'# Setting these up',
|
|
328
|
+
'',
|
|
329
|
+
'## 1. Install',
|
|
330
|
+
'ng add ngwr',
|
|
331
|
+
'(prompts for styles, date adapter, density and theme, and prints a bootstrap snippet)',
|
|
332
|
+
'',
|
|
333
|
+
'## 2. Wire each symbol into the component that uses it',
|
|
334
|
+
...resolved.map(hit => `ng g ngwr:use ${hit.symbol} --path src/app/some.component.ts # ${hit.entry.path}`),
|
|
335
|
+
'',
|
|
336
|
+
'`--path` is a NAMED option, not positional — passing it bare fails with `Unknown argument`.',
|
|
337
|
+
'',
|
|
338
|
+
'## 3. Styles',
|
|
339
|
+
"@use 'ngwr'; // everything, or per component:",
|
|
340
|
+
// Only the entry points that ship one. `component()` was fixed for this and
|
|
341
|
+
// `setup()` was missed — which is worse here, because this tool's entire
|
|
342
|
+
// output is commands to run, and `@use 'ngwr/table/testing'` fails the build.
|
|
343
|
+
...resolved.filter(hit => catalog.hasStyles(hit.entry.path)).map(hit => `@use '${hit.entry.path}';`),
|
|
344
|
+
'',
|
|
345
|
+
...(providers.length > 0
|
|
346
|
+
? [
|
|
347
|
+
'## 4. Providers these need',
|
|
348
|
+
...providers.map(required => `${required.provider}\n why: ${required.why}`),
|
|
349
|
+
'',
|
|
350
|
+
]
|
|
351
|
+
: []),
|
|
352
|
+
...(missing.length > 0 ? [`Not in the catalog: ${missing.join(', ')}. Try search_ngwr.`] : []),
|
|
353
|
+
].join('\n');
|
|
354
|
+
}
|
|
355
|
+
function notFound(catalog, name) {
|
|
356
|
+
const near = catalog
|
|
357
|
+
.all()
|
|
358
|
+
.filter(entry => entry.name.includes(name.toLowerCase().replace(/^ngwr\//, '')))
|
|
359
|
+
.slice(0, 5)
|
|
360
|
+
.map(entry => entry.path);
|
|
361
|
+
return [
|
|
362
|
+
`No ngwr entry point matches "${name}".`,
|
|
363
|
+
near.length > 0 ? `Close: ${near.join(', ')}.` : 'Use search_ngwr to find one.',
|
|
364
|
+
].join(' ');
|
|
365
|
+
}
|
|
366
|
+
export { TOOLS, callTool, validateArguments };
|