@ng-prism/core 22.6.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.
Files changed (377) hide show
  1. package/README.md +11 -9
  2. package/dist/app/canvas/canvas-bg.styles.d.ts +1 -1
  3. package/dist/app/canvas/canvas-bg.styles.d.ts.map +1 -1
  4. package/dist/app/canvas/canvas-bg.styles.js +1 -1
  5. package/dist/app/canvas/canvas-overlay-tokens.d.ts +12 -0
  6. package/dist/app/canvas/canvas-overlay-tokens.d.ts.map +1 -0
  7. package/dist/app/canvas/canvas-overlay-tokens.js +52 -0
  8. package/dist/app/canvas/prism-canvas-bg-pill.component.js +2 -2
  9. package/dist/app/canvas/prism-canvas-pin-row.component.js +2 -2
  10. package/dist/app/canvas/prism-canvas-rulers.component.d.ts +2 -0
  11. package/dist/app/canvas/prism-canvas-rulers.component.d.ts.map +1 -1
  12. package/dist/app/canvas/prism-canvas-rulers.component.js +17 -12
  13. package/dist/app/canvas/prism-canvas-toolbar.component.d.ts +3 -2
  14. package/dist/app/canvas/prism-canvas-toolbar.component.d.ts.map +1 -1
  15. package/dist/app/canvas/prism-canvas-toolbar.component.js +89 -97
  16. package/dist/app/canvas/prism-template-popover.component.d.ts.map +1 -1
  17. package/dist/app/canvas/prism-template-popover.component.js +16 -7
  18. package/dist/app/component-head/head-metrics.d.ts +35 -19
  19. package/dist/app/component-head/head-metrics.d.ts.map +1 -1
  20. package/dist/app/component-head/head-metrics.js +57 -27
  21. package/dist/app/component-head/pipe-facts.d.ts +9 -0
  22. package/dist/app/component-head/pipe-facts.d.ts.map +1 -0
  23. package/dist/app/component-head/pipe-facts.js +15 -0
  24. package/dist/app/component-head/prism-component-head.component.d.ts +19 -22
  25. package/dist/app/component-head/prism-component-head.component.d.ts.map +1 -1
  26. package/dist/app/component-head/prism-component-head.component.js +80 -96
  27. package/dist/app/component-head/prism-head-gauge.component.d.ts +8 -12
  28. package/dist/app/component-head/prism-head-gauge.component.d.ts.map +1 -1
  29. package/dist/app/component-head/prism-head-gauge.component.js +51 -67
  30. package/dist/app/component-head/prism-head-info.component.d.ts +13 -2
  31. package/dist/app/component-head/prism-head-info.component.d.ts.map +1 -1
  32. package/dist/app/component-head/prism-head-info.component.js +57 -16
  33. package/dist/app/component-head/prism-stat.component.d.ts +4 -5
  34. package/dist/app/component-head/prism-stat.component.d.ts.map +1 -1
  35. package/dist/app/component-head/prism-stat.component.js +16 -12
  36. package/dist/app/component-head/service-facts.d.ts +8 -0
  37. package/dist/app/component-head/service-facts.d.ts.map +1 -0
  38. package/dist/app/component-head/service-facts.js +11 -0
  39. package/dist/app/controls/boolean-control.component.js +2 -2
  40. package/dist/app/controls/json-control.component.js +2 -2
  41. package/dist/app/controls/union-control.component.js +4 -3
  42. package/dist/app/header/header-brand.d.ts +25 -0
  43. package/dist/app/header/header-brand.d.ts.map +1 -0
  44. package/dist/app/header/header-brand.js +10 -0
  45. package/dist/app/header/prism-header.component.d.ts +2 -2
  46. package/dist/app/header/prism-header.component.d.ts.map +1 -1
  47. package/dist/app/header/prism-header.component.js +73 -57
  48. package/dist/app/icons/icon-registry.d.ts.map +1 -1
  49. package/dist/app/icons/icon-registry.js +4 -1
  50. package/dist/app/index.d.ts +12 -0
  51. package/dist/app/index.d.ts.map +1 -1
  52. package/dist/app/index.js +12 -1
  53. package/dist/app/layout-menu/prism-layout-menu.component.d.ts +3 -0
  54. package/dist/app/layout-menu/prism-layout-menu.component.d.ts.map +1 -1
  55. package/dist/app/layout-menu/prism-layout-menu.component.js +72 -58
  56. package/dist/app/overview/open-in-playground.d.ts +8 -0
  57. package/dist/app/overview/open-in-playground.d.ts.map +1 -1
  58. package/dist/app/overview/open-in-playground.js +13 -0
  59. package/dist/app/overview/overview-matrix.d.ts +10 -4
  60. package/dist/app/overview/overview-matrix.d.ts.map +1 -1
  61. package/dist/app/overview/overview-matrix.js +3 -3
  62. package/dist/app/overview/prism-overview-cell.component.d.ts +6 -2
  63. package/dist/app/overview/prism-overview-cell.component.d.ts.map +1 -1
  64. package/dist/app/overview/prism-overview-cell.component.js +35 -24
  65. package/dist/app/overview/prism-overview-matrix.component.js +46 -55
  66. package/dist/app/page-renderer/prism-page-renderer.component.js +2 -2
  67. package/dist/app/panels/a11y/a11y-header-badge.component.d.ts +1 -4
  68. package/dist/app/panels/a11y/a11y-header-badge.component.d.ts.map +1 -1
  69. package/dist/app/panels/a11y/a11y-header-badge.component.js +8 -19
  70. package/dist/app/panels/a11y/a11y-keyboard-overlay.component.js +2 -2
  71. package/dist/app/panels/a11y/a11y-overlay-host.component.d.ts +1 -0
  72. package/dist/app/panels/a11y/a11y-overlay-host.component.d.ts.map +1 -1
  73. package/dist/app/panels/a11y/a11y-overlay-host.component.js +4 -3
  74. package/dist/app/panels/a11y/a11y-panel.component.d.ts +4 -1
  75. package/dist/app/panels/a11y/a11y-panel.component.d.ts.map +1 -1
  76. package/dist/app/panels/a11y/a11y-panel.component.js +32 -54
  77. package/dist/app/panels/a11y/a11y-score.component.d.ts +8 -3
  78. package/dist/app/panels/a11y/a11y-score.component.d.ts.map +1 -1
  79. package/dist/app/panels/a11y/a11y-score.component.js +19 -35
  80. package/dist/app/panels/a11y/a11y-sr-overlay.component.js +2 -2
  81. package/dist/app/panels/a11y/a11y-sr.component.js +2 -2
  82. package/dist/app/panels/a11y/a11y-summary.d.ts.map +1 -1
  83. package/dist/app/panels/a11y/a11y-summary.js +8 -1
  84. package/dist/app/panels/a11y/a11y-tree.component.js +2 -2
  85. package/dist/app/panels/a11y/a11y-violations.component.d.ts +23 -2
  86. package/dist/app/panels/a11y/a11y-violations.component.d.ts.map +1 -1
  87. package/dist/app/panels/a11y/a11y-violations.component.js +104 -89
  88. package/dist/app/panels/a11y/severity.d.ts +9 -0
  89. package/dist/app/panels/a11y/severity.d.ts.map +1 -0
  90. package/dist/app/panels/a11y/severity.js +12 -0
  91. package/dist/app/panels/controls/non-editable-input-types.d.ts +9 -1
  92. package/dist/app/panels/controls/non-editable-input-types.d.ts.map +1 -1
  93. package/dist/app/panels/controls/non-editable-input-types.js +18 -0
  94. package/dist/app/panels/controls/prism-controls-panel.component.d.ts +2 -1
  95. package/dist/app/panels/controls/prism-controls-panel.component.d.ts.map +1 -1
  96. package/dist/app/panels/controls/prism-controls-panel.component.js +77 -59
  97. package/dist/app/panels/events/prism-events-panel.component.d.ts +2 -0
  98. package/dist/app/panels/events/prism-events-panel.component.d.ts.map +1 -1
  99. package/dist/app/panels/events/prism-events-panel.component.js +20 -7
  100. package/dist/app/panels/events/prism-json-node.utils.d.ts +6 -0
  101. package/dist/app/panels/events/prism-json-node.utils.d.ts.map +1 -1
  102. package/dist/app/panels/events/prism-json-node.utils.js +8 -0
  103. package/dist/app/panels/panel-host/addon-panels.d.ts +11 -0
  104. package/dist/app/panels/panel-host/addon-panels.d.ts.map +1 -0
  105. package/dist/app/panels/panel-host/addon-panels.js +12 -0
  106. package/dist/app/panels/panel-host/panel-badge.d.ts +22 -0
  107. package/dist/app/panels/panel-host/panel-badge.d.ts.map +1 -1
  108. package/dist/app/panels/panel-host/panel-badge.js +56 -11
  109. package/dist/app/panels/panel-host/prism-panel-host.component.d.ts +4 -1
  110. package/dist/app/panels/panel-host/prism-panel-host.component.d.ts.map +1 -1
  111. package/dist/app/panels/panel-host/prism-panel-host.component.js +36 -70
  112. package/dist/app/renderer/composition.d.ts +20 -0
  113. package/dist/app/renderer/composition.d.ts.map +1 -0
  114. package/dist/app/renderer/composition.js +26 -0
  115. package/dist/app/renderer/input-bindings.d.ts +13 -1
  116. package/dist/app/renderer/input-bindings.d.ts.map +1 -1
  117. package/dist/app/renderer/input-bindings.js +22 -1
  118. package/dist/app/renderer/prism-renderer.component.d.ts +8 -1
  119. package/dist/app/renderer/prism-renderer.component.d.ts.map +1 -1
  120. package/dist/app/renderer/prism-renderer.component.js +40 -28
  121. package/dist/app/renderer/snippet-generator.d.ts +14 -2
  122. package/dist/app/renderer/snippet-generator.d.ts.map +1 -1
  123. package/dist/app/renderer/snippet-generator.js +137 -82
  124. package/dist/app/services/navigation-item.d.ts +10 -0
  125. package/dist/app/services/navigation-item.d.ts.map +1 -0
  126. package/dist/app/services/navigation-item.js +20 -0
  127. package/dist/app/services/navigation-item.types.d.ts +8 -0
  128. package/dist/app/services/navigation-item.types.d.ts.map +1 -1
  129. package/dist/app/services/prism-layout.service.d.ts +12 -0
  130. package/dist/app/services/prism-layout.service.d.ts.map +1 -1
  131. package/dist/app/services/prism-layout.service.js +17 -7
  132. package/dist/app/services/prism-manifest.service.d.ts +4 -0
  133. package/dist/app/services/prism-manifest.service.d.ts.map +1 -1
  134. package/dist/app/services/prism-manifest.service.js +4 -0
  135. package/dist/app/services/prism-navigation.service.d.ts +12 -0
  136. package/dist/app/services/prism-navigation.service.d.ts.map +1 -1
  137. package/dist/app/services/prism-navigation.service.js +85 -19
  138. package/dist/app/services/prism-panel.service.d.ts +7 -3
  139. package/dist/app/services/prism-panel.service.d.ts.map +1 -1
  140. package/dist/app/services/prism-panel.service.js +13 -4
  141. package/dist/app/services/prism-renderer.service.d.ts +6 -0
  142. package/dist/app/services/prism-renderer.service.d.ts.map +1 -1
  143. package/dist/app/services/prism-renderer.service.js +40 -6
  144. package/dist/app/services/prism-search.service.d.ts +4 -0
  145. package/dist/app/services/prism-search.service.d.ts.map +1 -1
  146. package/dist/app/services/prism-search.service.js +29 -6
  147. package/dist/app/services/prism-theme.service.d.ts +11 -3
  148. package/dist/app/services/prism-theme.service.d.ts.map +1 -1
  149. package/dist/app/services/prism-theme.service.js +27 -19
  150. package/dist/app/services/prism-url-state.service.d.ts.map +1 -1
  151. package/dist/app/services/prism-url-state.service.js +42 -4
  152. package/dist/app/shared/badge.types.d.ts +7 -0
  153. package/dist/app/shared/badge.types.d.ts.map +1 -0
  154. package/dist/app/shared/badge.types.js +9 -0
  155. package/dist/app/shared/brand-mark.d.ts +35 -0
  156. package/dist/app/shared/brand-mark.d.ts.map +1 -0
  157. package/dist/app/shared/brand-mark.js +52 -0
  158. package/dist/app/shared/metric-bar.d.ts +6 -0
  159. package/dist/app/shared/metric-bar.d.ts.map +1 -0
  160. package/dist/app/shared/metric-bar.js +7 -0
  161. package/dist/app/shared/prism-badge.component.d.ts +21 -0
  162. package/dist/app/shared/prism-badge.component.d.ts.map +1 -0
  163. package/dist/app/shared/prism-badge.component.js +68 -0
  164. package/dist/app/shared/prism-button.component.d.ts +12 -0
  165. package/dist/app/shared/prism-button.component.d.ts.map +1 -0
  166. package/dist/app/shared/prism-button.component.js +28 -0
  167. package/dist/app/shared/prism-icon-button.component.d.ts +17 -0
  168. package/dist/app/shared/prism-icon-button.component.d.ts.map +1 -0
  169. package/dist/app/shared/prism-icon-button.component.js +37 -0
  170. package/dist/app/shared/prism-list-row.component.d.ts +17 -0
  171. package/dist/app/shared/prism-list-row.component.d.ts.map +1 -0
  172. package/dist/app/shared/prism-list-row.component.js +57 -0
  173. package/dist/app/shared/prism-logo.component.d.ts +24 -0
  174. package/dist/app/shared/prism-logo.component.d.ts.map +1 -0
  175. package/dist/app/shared/prism-logo.component.js +77 -0
  176. package/dist/app/shared/prism-metric-badge.component.d.ts +9 -4
  177. package/dist/app/shared/prism-metric-badge.component.d.ts.map +1 -1
  178. package/dist/app/shared/prism-metric-badge.component.js +33 -12
  179. package/dist/app/shared/prism-metric-card.component.d.ts +30 -0
  180. package/dist/app/shared/prism-metric-card.component.d.ts.map +1 -0
  181. package/dist/app/shared/prism-metric-card.component.js +111 -0
  182. package/dist/app/shared/prism-panel-toolbar.component.d.ts +13 -0
  183. package/dist/app/shared/prism-panel-toolbar.component.d.ts.map +1 -0
  184. package/dist/app/shared/prism-panel-toolbar.component.js +28 -0
  185. package/dist/app/shared/prism-segmented.component.d.ts +25 -0
  186. package/dist/app/shared/prism-segmented.component.d.ts.map +1 -0
  187. package/dist/app/shared/prism-segmented.component.js +77 -0
  188. package/dist/app/shared/prism-tabs.component.d.ts +44 -0
  189. package/dist/app/shared/prism-tabs.component.d.ts.map +1 -0
  190. package/dist/app/shared/prism-tabs.component.js +134 -0
  191. package/dist/app/shared/roving-focus.d.ts +13 -0
  192. package/dist/app/shared/roving-focus.d.ts.map +1 -0
  193. package/dist/app/shared/roving-focus.js +34 -0
  194. package/dist/app/shell/prism-shell.component.d.ts +13 -0
  195. package/dist/app/shell/prism-shell.component.d.ts.map +1 -1
  196. package/dist/app/shell/prism-shell.component.js +57 -28
  197. package/dist/app/shell/should-select-first.d.ts +17 -0
  198. package/dist/app/shell/should-select-first.d.ts.map +1 -0
  199. package/dist/app/shell/should-select-first.js +13 -0
  200. package/dist/app/sidebar/navigation-decorations.d.ts +23 -1
  201. package/dist/app/sidebar/navigation-decorations.d.ts.map +1 -1
  202. package/dist/app/sidebar/navigation-decorations.js +33 -2
  203. package/dist/app/sidebar/prism-sidebar.component.d.ts +5 -15
  204. package/dist/app/sidebar/prism-sidebar.component.d.ts.map +1 -1
  205. package/dist/app/sidebar/prism-sidebar.component.js +89 -77
  206. package/dist/app/theme/deprecated-tokens.d.ts +15 -0
  207. package/dist/app/theme/deprecated-tokens.d.ts.map +1 -0
  208. package/dist/app/theme/deprecated-tokens.js +22 -0
  209. package/dist/app/theme/favicon.d.ts +3 -0
  210. package/dist/app/theme/favicon.d.ts.map +1 -0
  211. package/dist/app/theme/favicon.js +3 -0
  212. package/dist/app/theme/prism-default-theme.d.ts.map +1 -1
  213. package/dist/app/theme/prism-default-theme.js +116 -61
  214. package/dist/app/theme/resolve-theme-tokens.d.ts +29 -0
  215. package/dist/app/theme/resolve-theme-tokens.d.ts.map +1 -0
  216. package/dist/app/theme/resolve-theme-tokens.js +43 -0
  217. package/dist/app/variant-ribbon/prism-variant-ribbon.component.d.ts +4 -7
  218. package/dist/app/variant-ribbon/prism-variant-ribbon.component.d.ts.map +1 -1
  219. package/dist/app/variant-ribbon/prism-variant-ribbon.component.js +31 -69
  220. package/dist/app/view-tab-bar/next-view-id.d.ts +7 -1
  221. package/dist/app/view-tab-bar/next-view-id.d.ts.map +1 -1
  222. package/dist/app/view-tab-bar/next-view-id.js +9 -1
  223. package/dist/app/view-tab-bar/panel-inputs.d.ts +28 -0
  224. package/dist/app/view-tab-bar/panel-inputs.d.ts.map +1 -0
  225. package/dist/app/view-tab-bar/panel-inputs.js +41 -0
  226. package/dist/app/view-tab-bar/prism-view-panel-host.component.d.ts +2 -3
  227. package/dist/app/view-tab-bar/prism-view-panel-host.component.d.ts.map +1 -1
  228. package/dist/app/view-tab-bar/prism-view-panel-host.component.js +9 -9
  229. package/dist/app/view-tab-bar/prism-view-tab-bar.component.d.ts +6 -0
  230. package/dist/app/view-tab-bar/prism-view-tab-bar.component.d.ts.map +1 -1
  231. package/dist/app/view-tab-bar/prism-view-tab-bar.component.js +22 -29
  232. package/dist/builder/config-loader/deprecated-options.d.ts +4 -2
  233. package/dist/builder/config-loader/deprecated-options.d.ts.map +1 -1
  234. package/dist/builder/config-loader/deprecated-options.js +13 -2
  235. package/dist/builder/manifest/composition-wrapper.generator.d.ts +14 -0
  236. package/dist/builder/manifest/composition-wrapper.generator.d.ts.map +1 -0
  237. package/dist/builder/manifest/composition-wrapper.generator.js +66 -0
  238. package/dist/builder/manifest/host-parser.d.ts +2 -0
  239. package/dist/builder/manifest/host-parser.d.ts.map +1 -1
  240. package/dist/builder/manifest/host-parser.js +9 -4
  241. package/dist/builder/manifest/manifest-imports.d.ts +34 -0
  242. package/dist/builder/manifest/manifest-imports.d.ts.map +1 -0
  243. package/dist/builder/manifest/manifest-imports.js +91 -0
  244. package/dist/builder/manifest/runtime-manifest.generator.d.ts +13 -0
  245. package/dist/builder/manifest/runtime-manifest.generator.d.ts.map +1 -1
  246. package/dist/builder/manifest/runtime-manifest.generator.js +135 -64
  247. package/dist/builder/manifest/selector-element.d.ts +16 -0
  248. package/dist/builder/manifest/selector-element.d.ts.map +1 -0
  249. package/dist/builder/manifest/selector-element.js +46 -0
  250. package/dist/builder/manifest/template-literal.d.ts +3 -0
  251. package/dist/builder/manifest/template-literal.d.ts.map +1 -0
  252. package/dist/builder/manifest/template-literal.js +4 -0
  253. package/dist/builder/plugin-runner/plugin-runner.d.ts.map +1 -1
  254. package/dist/builder/plugin-runner/plugin-runner.js +29 -26
  255. package/dist/builder/scanner/api/angular-decorators.d.ts +84 -0
  256. package/dist/builder/scanner/api/angular-decorators.d.ts.map +1 -0
  257. package/dist/builder/scanner/api/angular-decorators.js +157 -0
  258. package/dist/builder/scanner/api/component-api.extractor.d.ts +13 -0
  259. package/dist/builder/scanner/api/component-api.extractor.d.ts.map +1 -0
  260. package/dist/builder/scanner/api/component-api.extractor.js +104 -0
  261. package/dist/builder/scanner/api/doc-tags.d.ts +13 -0
  262. package/dist/builder/scanner/api/doc-tags.d.ts.map +1 -0
  263. package/dist/builder/scanner/api/doc-tags.js +101 -0
  264. package/dist/builder/scanner/api/export-index.d.ts +18 -0
  265. package/dist/builder/scanner/api/export-index.d.ts.map +1 -0
  266. package/dist/builder/scanner/api/export-index.js +22 -0
  267. package/dist/builder/scanner/api/member.extractor.d.ts +90 -0
  268. package/dist/builder/scanner/api/member.extractor.d.ts.map +1 -0
  269. package/dist/builder/scanner/api/member.extractor.js +270 -0
  270. package/dist/builder/scanner/api/pipe-api.extractor.d.ts +12 -0
  271. package/dist/builder/scanner/api/pipe-api.extractor.d.ts.map +1 -0
  272. package/dist/builder/scanner/api/pipe-api.extractor.js +52 -0
  273. package/dist/builder/scanner/api/service-api.extractor.d.ts +14 -0
  274. package/dist/builder/scanner/api/service-api.extractor.d.ts.map +1 -0
  275. package/dist/builder/scanner/api/service-api.extractor.js +119 -0
  276. package/dist/builder/scanner/api/setup.reader.d.ts +26 -0
  277. package/dist/builder/scanner/api/setup.reader.d.ts.map +1 -0
  278. package/dist/builder/scanner/api/setup.reader.js +89 -0
  279. package/dist/builder/scanner/api/type-collector.d.ts +24 -0
  280. package/dist/builder/scanner/api/type-collector.d.ts.map +1 -0
  281. package/dist/builder/scanner/api/type-collector.js +211 -0
  282. package/dist/builder/scanner/ast-utils.d.ts +8 -0
  283. package/dist/builder/scanner/ast-utils.d.ts.map +1 -1
  284. package/dist/builder/scanner/ast-utils.js +37 -1
  285. package/dist/builder/scanner/class-hierarchy.d.ts +5 -3
  286. package/dist/builder/scanner/class-hierarchy.d.ts.map +1 -1
  287. package/dist/builder/scanner/class-hierarchy.js +12 -6
  288. package/dist/builder/scanner/component.scanner.d.ts +60 -6
  289. package/dist/builder/scanner/component.scanner.d.ts.map +1 -1
  290. package/dist/builder/scanner/component.scanner.js +209 -57
  291. package/dist/builder/scanner/composition/compose-template.d.ts +36 -0
  292. package/dist/builder/scanner/composition/compose-template.d.ts.map +1 -0
  293. package/dist/builder/scanner/composition/compose-template.js +187 -0
  294. package/dist/builder/scanner/composition/declarables.d.ts +54 -0
  295. package/dist/builder/scanner/composition/declarables.d.ts.map +1 -0
  296. package/dist/builder/scanner/composition/declarables.js +182 -0
  297. package/dist/builder/scanner/composition/match-declarables.d.ts +43 -0
  298. package/dist/builder/scanner/composition/match-declarables.d.ts.map +1 -0
  299. package/dist/builder/scanner/composition/match-declarables.js +131 -0
  300. package/dist/builder/scanner/composition/read-composition.d.ts +77 -0
  301. package/dist/builder/scanner/composition/read-composition.d.ts.map +1 -0
  302. package/dist/builder/scanner/composition/read-composition.js +302 -0
  303. package/dist/builder/scanner/composition/template-elements.d.ts +12 -0
  304. package/dist/builder/scanner/composition/template-elements.d.ts.map +1 -0
  305. package/dist/builder/scanner/composition/template-elements.js +41 -0
  306. package/dist/builder/scanner/index.d.ts +4 -0
  307. package/dist/builder/scanner/index.d.ts.map +1 -1
  308. package/dist/builder/scanner/index.js +2 -0
  309. package/dist/builder/scanner/input.extractor.d.ts +31 -2
  310. package/dist/builder/scanner/input.extractor.d.ts.map +1 -1
  311. package/dist/builder/scanner/input.extractor.js +52 -15
  312. package/dist/builder/scanner/pipe.scanner.d.ts +29 -0
  313. package/dist/builder/scanner/pipe.scanner.d.ts.map +1 -0
  314. package/dist/builder/scanner/pipe.scanner.js +65 -0
  315. package/dist/builder/scanner/scanner.d.ts +25 -1
  316. package/dist/builder/scanner/scanner.d.ts.map +1 -1
  317. package/dist/builder/scanner/scanner.js +60 -26
  318. package/dist/builder/scanner/service/angular-decorators.d.ts +80 -0
  319. package/dist/builder/scanner/service/angular-decorators.d.ts.map +1 -0
  320. package/dist/builder/scanner/service/angular-decorators.js +154 -0
  321. package/dist/builder/scanner/service/doc-tags.d.ts +13 -0
  322. package/dist/builder/scanner/service/doc-tags.d.ts.map +1 -0
  323. package/dist/builder/scanner/service/doc-tags.js +97 -0
  324. package/dist/builder/scanner/service/export-index.d.ts +18 -0
  325. package/dist/builder/scanner/service/export-index.d.ts.map +1 -0
  326. package/dist/builder/scanner/service/export-index.js +22 -0
  327. package/dist/builder/scanner/service/member.extractor.d.ts +65 -0
  328. package/dist/builder/scanner/service/member.extractor.d.ts.map +1 -0
  329. package/dist/builder/scanner/service/member.extractor.js +216 -0
  330. package/dist/builder/scanner/service/pipe-api.extractor.d.ts +12 -0
  331. package/dist/builder/scanner/service/pipe-api.extractor.d.ts.map +1 -0
  332. package/dist/builder/scanner/service/pipe-api.extractor.js +72 -0
  333. package/dist/builder/scanner/service/service-api.extractor.d.ts +14 -0
  334. package/dist/builder/scanner/service/service-api.extractor.d.ts.map +1 -0
  335. package/dist/builder/scanner/service/service-api.extractor.js +119 -0
  336. package/dist/builder/scanner/service/setup.reader.d.ts +26 -0
  337. package/dist/builder/scanner/service/setup.reader.d.ts.map +1 -0
  338. package/dist/builder/scanner/service/setup.reader.js +89 -0
  339. package/dist/builder/scanner/service/type-collector.d.ts +23 -0
  340. package/dist/builder/scanner/service/type-collector.d.ts.map +1 -0
  341. package/dist/builder/scanner/service/type-collector.js +210 -0
  342. package/dist/builder/scanner/service.scanner.d.ts +26 -0
  343. package/dist/builder/scanner/service.scanner.d.ts.map +1 -0
  344. package/dist/builder/scanner/service.scanner.js +61 -0
  345. package/dist/builder/scanner/showcase-diagnostics.d.ts +60 -1
  346. package/dist/builder/scanner/showcase-diagnostics.d.ts.map +1 -1
  347. package/dist/builder/scanner/showcase-diagnostics.js +114 -1
  348. package/dist/builder/shared/prism-pipeline.d.ts +6 -0
  349. package/dist/builder/shared/prism-pipeline.d.ts.map +1 -1
  350. package/dist/builder/shared/prism-pipeline.js +43 -5
  351. package/dist/decorator/index.d.ts +1 -1
  352. package/dist/decorator/index.d.ts.map +1 -1
  353. package/dist/decorator/showcase.types.d.ts +79 -9
  354. package/dist/decorator/showcase.types.d.ts.map +1 -1
  355. package/dist/plugin/index.d.ts +6 -1
  356. package/dist/plugin/index.d.ts.map +1 -1
  357. package/dist/plugin/index.js +4 -0
  358. package/dist/plugin/pipe.types.d.ts +36 -0
  359. package/dist/plugin/pipe.types.d.ts.map +1 -0
  360. package/dist/plugin/pipe.types.js +1 -0
  361. package/dist/plugin/plugin.types.d.ts +140 -3
  362. package/dist/plugin/plugin.types.d.ts.map +1 -1
  363. package/dist/plugin/service.types.d.ts +124 -0
  364. package/dist/plugin/service.types.d.ts.map +1 -0
  365. package/dist/plugin/service.types.js +1 -0
  366. package/dist/plugin/status.d.ts +27 -0
  367. package/dist/plugin/status.d.ts.map +1 -0
  368. package/dist/plugin/status.js +26 -0
  369. package/dist/shared/composition.d.ts +30 -0
  370. package/dist/shared/composition.d.ts.map +1 -0
  371. package/dist/shared/composition.js +29 -0
  372. package/dist/shared/pseudo-state.type.d.ts +2 -1
  373. package/dist/shared/pseudo-state.type.d.ts.map +1 -1
  374. package/dist/shared/void-elements.d.ts +3 -0
  375. package/dist/shared/void-elements.d.ts.map +1 -0
  376. package/dist/shared/void-elements.js +2 -0
  377. package/package.json +1 -1
@@ -1,11 +1,16 @@
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 { evaluateExpression, evaluateStatic, findDecorator, getDecoratorArgument, UNEVALUABLE } from './ast-utils.js';
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
12
  import { describeValue, readPseudoStates } from './pseudo-states.js';
8
- import { describeDeprecatedProviders, describeUnevaluable, describeUnreadableBase } from './showcase-diagnostics.js';
13
+ import { describeDeprecatedProviders, describeLegacyPipeComponent, describeLegacyServiceComponent, describeSetupOnComponent, describeSetupOnLegacyComponent, describeShowcaseIssue, describeUnevaluable, describeUnreadableApi, describeUnreadableBase } from './showcase-diagnostics.js';
9
14
  import { readShowcaseStates } from './showcase-states.js';
10
15
  const COMPONENT_STATUSES = ['stable', 'beta', 'wip', 'deprecated'];
11
16
  function isComponentStatus(value) {
@@ -39,47 +44,96 @@ function isCanvasBg(value) {
39
44
  function isCanvasLayout(value) {
40
45
  return typeof value === 'string' && CANVAS_LAYOUTS.includes(value);
41
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
+ }
65
+ /**
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
+ }
42
87
  /**
43
- * Scan exported symbols for Angular components annotated with @Showcase.
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.
44
92
  *
45
93
  * Every @Showcase value the scan has to drop is printed and collected in
46
- * `diagnostics`, once: sharing the array across entry points keeps a
47
- * component exported from several of them from repeating its warnings.
48
- * `notices` does the same for warnings about what a component inherits,
49
- * which are not diagnostics.
94
+ * `diagnostics`, once. `notices` does the same for warnings about what a
95
+ * component inherits, which are not diagnostics.
50
96
  */
51
- export function scanComponents(exports, checker, diagnostics = [], notices = new Set()) {
97
+ export function scanComponents(showcased, checker, options = {}) {
98
+ const { diagnostics = [], notices = new Set(), exportIndex = new Map(), api: readApi = true, composition: compositionContext } = options;
52
99
  const components = [];
53
- const report = (message) => {
54
- if (diagnostics.includes(message))
55
- return;
56
- diagnostics.push(message);
57
- console.warn(`⚠ ng-prism: ${message}`);
58
- };
59
- const notify = (message) => {
60
- if (notices.has(message))
61
- return;
62
- notices.add(message);
63
- console.warn(`⚠ ng-prism: ${message}`);
64
- };
65
- for (const sym of exports) {
66
- const resolved = sym.flags & ts.SymbolFlags.Alias ? checker.getAliasedSymbol(sym) : sym;
67
- const classDecl = resolved.declarations?.find(ts.isClassDeclaration);
68
- if (!classDecl)
69
- continue;
70
- // Perf: cheap pre-filter that skips the full decorator walk for files that don't
71
- // mention Showcase at all. False positives (string-literal containing "@Showcase")
72
- // just lose the optimization for that file; correctness is unaffected.
73
- if (!classDecl.getSourceFile().text.includes('@Showcase'))
74
- continue;
75
- const showcaseDecorator = findDecorator(classDecl, 'Showcase');
76
- 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')
77
103
  continue;
78
104
  const className = classDecl.name?.text ?? 'Anonymous';
79
- const showcaseConfig = extractShowcaseConfig(showcaseDecorator, className, report, checker);
80
- if (!showcaseConfig)
105
+ const read = readShowcaseConfig(showcaseDecorator, className, report, checker);
106
+ if (!read || !showcaseArg)
81
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));
82
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
+ }
83
137
  const hierarchy = getClassHierarchy(classDecl, checker);
84
138
  const inputs = extractInputs(classDecl, checker, hierarchy);
85
139
  const outputs = extractOutputs(classDecl, checker, hierarchy);
@@ -94,6 +148,28 @@ export function scanComponents(exports, checker, diagnostics = [], notices = new
94
148
  for (const base of hierarchy.unreadable) {
95
149
  notify(describeUnreadableBase(className, base));
96
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 });
97
173
  components.push({
98
174
  className,
99
175
  filePath,
@@ -104,11 +180,38 @@ export function scanComponents(exports, checker, diagnostics = [], notices = new
104
180
  // Plugins look a base class up by name, so an anonymous one is of no use to them.
105
181
  baseClasses: hierarchy.classes
106
182
  .slice(1)
107
- .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 })
108
186
  });
109
187
  }
110
188
  return components;
111
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
+ }
112
215
  function hasDecoratorInputs(classDecl) {
113
216
  for (const member of classDecl.members) {
114
217
  if (!ts.isPropertyDeclaration(member))
@@ -118,7 +221,16 @@ function hasDecoratorInputs(classDecl) {
118
221
  }
119
222
  return false;
120
223
  }
121
- function extractShowcaseConfig(decorator, className, report, checker) {
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) {
122
234
  const arg = getDecoratorArgument(decorator);
123
235
  if (!arg)
124
236
  return undefined;
@@ -126,15 +238,24 @@ function extractShowcaseConfig(decorator, className, report, checker) {
126
238
  let providers;
127
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.
128
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() };
129
243
  const raw = evaluateStatic(arg, {
130
244
  checker,
131
245
  report: (issue) => {
246
+ if (issue.path[0] === 'setup')
247
+ return;
132
248
  if (issue.path[0] === 'providers') {
133
249
  providers ??= issue.node;
134
250
  return;
135
251
  }
136
252
  if (issue.path[0] === 'states' && issue.path.length === 2 && typeof issue.path[1] === 'number')
137
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);
138
259
  report(describeUnevaluable(className, arg, issue));
139
260
  }
140
261
  });
@@ -151,6 +272,7 @@ function extractShowcaseConfig(decorator, className, report, checker) {
151
272
  const config = {
152
273
  title: obj['title']
153
274
  };
275
+ const sources = { variants: [], imports: [] };
154
276
  if (obj['description'])
155
277
  config.description = obj['description'];
156
278
  if (obj['category'])
@@ -170,8 +292,15 @@ function extractShowcaseConfig(decorator, className, report, checker) {
170
292
  config.tags = obj['tags'];
171
293
  if (obj['meta'])
172
294
  config.meta = obj['meta'];
173
- if (obj['host'] !== undefined)
174
- config.host = obj['host'];
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
+ }
175
304
  if (obj['renderPage'])
176
305
  config.renderPage = obj['renderPage'];
177
306
  if (obj['states'] !== undefined) {
@@ -209,9 +338,17 @@ function extractShowcaseConfig(decorator, className, report, checker) {
209
338
  report(`${className} declares invalid canvasLayout "${String(obj['canvasLayout'])}", ` + `expected one of: ${CANVAS_LAYOUTS.join(', ')}. Skipping.`);
210
339
  }
211
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
+ }
212
348
  if (Array.isArray(obj['variants'])) {
213
- config.variants = obj['variants'].map((variant) => {
349
+ config.variants = obj['variants'].map((variant, index) => {
214
350
  const cleaned = { ...variant };
351
+ const reportVariant = (field, text) => report(describeShowcaseIssue(className, arg, ['variants', sourceIndex(index, unevaluableElements.variants), field], text));
215
352
  if (isCanvasBg(variant['bg'])) {
216
353
  warnDeprecatedBg(variant['bg'], `${className} variant "${String(variant['name'])}"`);
217
354
  }
@@ -237,10 +374,42 @@ function extractShowcaseConfig(decorator, className, report, checker) {
237
374
  report(`${className} variant "${String(variant['name'])}" declares invalid states ${describeValue(variant['states'])}, expected false. Skipping.`);
238
375
  delete cleaned['states'];
239
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
+ }
240
389
  return cleaned;
241
390
  });
391
+ sources.variants = (config.variants ?? []).map((_, index) => sourceIndex(index, unevaluableElements.variants));
242
392
  }
243
- return config;
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 [];
404
+ }
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
+ });
244
413
  }
245
414
  function extractComponentMeta(classDecl, checker) {
246
415
  const componentDecorator = findDecorator(classDecl, 'Component');
@@ -256,20 +425,3 @@ function extractComponentMeta(classDecl, checker) {
256
425
  isDirective
257
426
  };
258
427
  }
259
- /**
260
- * One field of `@Component`/`@Directive` metadata, read from its own
261
- * property where the literal has one, so that `imports`, `providers` and the
262
- * rest are not resolved only to be thrown away. A spread or a shorthand could
263
- * supply the field from elsewhere, so then the whole argument is evaluated.
264
- */
265
- function readDecoratorField(arg, key, checker) {
266
- if (ts.isObjectLiteralExpression(arg) && !arg.properties.some(ts.isSpreadAssignment)) {
267
- const prop = arg.properties.find((p) => p.name !== undefined && (ts.isIdentifier(p.name) || ts.isStringLiteral(p.name)) && p.name.text === key);
268
- if (!prop)
269
- return undefined;
270
- if (ts.isPropertyAssignment(prop))
271
- return evaluateExpression(prop.initializer, checker);
272
- }
273
- const raw = evaluateExpression(arg, checker);
274
- return typeof raw === 'object' && raw !== null ? raw[key] : undefined;
275
- }
@@ -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
+ }
@@ -0,0 +1,54 @@
1
+ import ts from 'typescript';
2
+ import type { ShowcaseImport } from '../../../decorator/showcase.types.js';
3
+ /** A component, directive or pipe that a template can use, and the module specifier a consumer imports it from. */
4
+ export interface Declarable {
5
+ /** The name it is exported under. */
6
+ name: string;
7
+ from: string;
8
+ kind: 'component' | 'directive' | 'pipe';
9
+ /** Of a component or directive, as written in its metadata: a list of selectors is one string. */
10
+ selector?: string;
11
+ /** Of a pipe: the name a template calls it by. */
12
+ pipeName?: string;
13
+ /** `false` for a class an NgModule declares, which only that module can bring into a template. */
14
+ standalone: boolean;
15
+ }
16
+ /** What {@link readDeclarable} finds in a class: a {@link Declarable} before it is given a name and a module. */
17
+ export type DeclarableShape = Pick<Declarable, 'kind' | 'selector' | 'pipeName' | 'standalone'>;
18
+ /**
19
+ * Index every component, directive and pipe the library's entry points export
20
+ * by its selector or name, with or without `@Showcase`, so that a template can
21
+ * be matched against them. A class from a dependency that an entry point
22
+ * re-exports is read from its `.d.ts`. A class without a selector (or a pipe
23
+ * without a name) cannot be used in a template and is left out, as is
24
+ * everything that is not a component, directive or pipe.
25
+ *
26
+ * A class exported more than once keeps its first entry, as in
27
+ * `buildExportIndex`: callers put the secondary entry points before the
28
+ * primary one.
29
+ */
30
+ export declare function buildDeclarableIndex(entries: ReadonlyArray<{
31
+ exports: ts.Symbol[];
32
+ importPath: string;
33
+ }>, checker: ts.TypeChecker): Declarable[];
34
+ /**
35
+ * Look up each `{ name, from }` of a showcase's `imports` without a program: the module is resolved the way a bundler
36
+ * does it, with the `paths` and the other options given, and the class is read from the file it lands in, following
37
+ * `export … from` up to five modules on. An entry that cannot be found, is not exported, or is not a component,
38
+ * directive or pipe (an NgModule or a service, say) comes back unresolved. A selector that only a checker could
39
+ * evaluate is not read.
40
+ */
41
+ export declare function resolveShowcaseImports(imports: readonly ShowcaseImport[], containingFile: string, compilerOptions: ts.CompilerOptions): {
42
+ resolved: Declarable[];
43
+ unresolved: ShowcaseImport[];
44
+ };
45
+ /**
46
+ * What a class declares for templates: from `@Component`, `@Directive` or `@Pipe` in source, from the `ɵcmp`, `ɵdir`
47
+ * or `ɵpipe` that the compiler left in a `.d.ts`. `undefined` for a class that is neither, or has no selector or name.
48
+ * The `checker` evaluates a selector given as a constant; without one only a literal is read.
49
+ *
50
+ * A class is standalone unless it says otherwise, as in Angular since 19: with `standalone: false` in its decorator,
51
+ * or `false` as the `IsStandalone` type argument in a `.d.ts`.
52
+ */
53
+ export declare function readDeclarable(classDecl: ts.ClassDeclaration, checker?: ts.TypeChecker): DeclarableShape | undefined;
54
+ //# sourceMappingURL=declarables.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"declarables.d.ts","sourceRoot":"","sources":["../../../../src/builder/scanner/composition/declarables.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,YAAY,CAAC;AAC5B,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sCAAsC,CAAC;AAI3E,mHAAmH;AACnH,MAAM,WAAW,UAAU;IACvB,qCAAqC;IACrC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,WAAW,GAAG,WAAW,GAAG,MAAM,CAAC;IACzC,kGAAkG;IAClG,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,kDAAkD;IAClD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,kGAAkG;IAClG,UAAU,EAAE,OAAO,CAAC;CACvB;AAED,iHAAiH;AACjH,MAAM,MAAM,eAAe,GAAG,IAAI,CAAC,UAAU,EAAE,MAAM,GAAG,UAAU,GAAG,UAAU,GAAG,YAAY,CAAC,CAAC;AAgChG;;;;;;;;;;;GAWG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,aAAa,CAAC;IAAE,OAAO,EAAE,EAAE,CAAC,MAAM,EAAE,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,CAAC,EAAE,OAAO,EAAE,EAAE,CAAC,WAAW,GAAG,UAAU,EAAE,CAoBhJ;AAED;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CAClC,OAAO,EAAE,SAAS,cAAc,EAAE,EAClC,cAAc,EAAE,MAAM,EACtB,eAAe,EAAE,EAAE,CAAC,eAAe,GACpC;IAAE,QAAQ,EAAE,UAAU,EAAE,CAAC;IAAC,UAAU,EAAE,cAAc,EAAE,CAAA;CAAE,CAgB1D;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,SAAS,EAAE,EAAE,CAAC,gBAAgB,EAAE,OAAO,CAAC,EAAE,EAAE,CAAC,WAAW,GAAG,eAAe,GAAG,SAAS,CA4BpH"}