@ng-prism/core 21.10.2 → 21.11.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 (38) hide show
  1. package/dist/app/canvas/prism-canvas-bg-pill.component.d.ts.map +1 -1
  2. package/dist/app/canvas/prism-canvas-bg-pill.component.js +3 -3
  3. package/dist/app/canvas/prism-canvas-rulers.component.d.ts +1 -0
  4. package/dist/app/canvas/prism-canvas-rulers.component.d.ts.map +1 -1
  5. package/dist/app/canvas/prism-canvas-rulers.component.js +4 -1
  6. package/dist/app/component-head/prism-component-head.component.d.ts +8 -0
  7. package/dist/app/component-head/prism-component-head.component.d.ts.map +1 -1
  8. package/dist/app/component-head/prism-component-head.component.js +119 -49
  9. package/dist/app/icons/prism-icon.component.d.ts.map +1 -1
  10. package/dist/app/icons/prism-icon.component.js +2 -1
  11. package/dist/app/panels/controls/prism-controls-panel.component.d.ts.map +1 -1
  12. package/dist/app/panels/controls/prism-controls-panel.component.js +99 -60
  13. package/dist/app/renderer/prism-renderer.component.d.ts.map +1 -1
  14. package/dist/app/renderer/prism-renderer.component.js +10 -6
  15. package/dist/app/services/prism-renderer.service.d.ts +9 -0
  16. package/dist/app/services/prism-renderer.service.d.ts.map +1 -1
  17. package/dist/app/services/prism-renderer.service.js +81 -30
  18. package/dist/app/sidebar/prism-sidebar.component.d.ts +3 -0
  19. package/dist/app/sidebar/prism-sidebar.component.d.ts.map +1 -1
  20. package/dist/app/sidebar/prism-sidebar.component.js +38 -8
  21. package/dist/builder/scanner/component.scanner.d.ts.map +1 -1
  22. package/dist/builder/scanner/component.scanner.js +19 -0
  23. package/dist/builder/scanner/entry-point.scanner.d.ts +15 -4
  24. package/dist/builder/scanner/entry-point.scanner.d.ts.map +1 -1
  25. package/dist/builder/scanner/entry-point.scanner.js +26 -13
  26. package/dist/builder/scanner/index.d.ts +2 -2
  27. package/dist/builder/scanner/index.d.ts.map +1 -1
  28. package/dist/builder/scanner/scanner.d.ts +15 -6
  29. package/dist/builder/scanner/scanner.d.ts.map +1 -1
  30. package/dist/builder/scanner/scanner.js +44 -7
  31. package/dist/builder/shared/prism-pipeline.d.ts +3 -1
  32. package/dist/builder/shared/prism-pipeline.d.ts.map +1 -1
  33. package/dist/builder/shared/prism-pipeline.js +31 -26
  34. package/dist/decorator/index.d.ts +1 -1
  35. package/dist/decorator/index.d.ts.map +1 -1
  36. package/dist/decorator/showcase.types.d.ts +8 -0
  37. package/dist/decorator/showcase.types.d.ts.map +1 -1
  38. package/package.json +1 -1
@@ -88,26 +88,36 @@ function PrismSidebarComponent_Conditional_9_Template(rf, ctx) { if (rf & 1) {
88
88
  i0.ɵɵadvance(3);
89
89
  i0.ɵɵtextInterpolate(ctx_r2.totalComponents());
90
90
  } }
91
+ function PrismSidebarComponent_For_11_Conditional_7_For_2_Conditional_4_Template(rf, ctx) { if (rf & 1) {
92
+ i0.ɵɵelementStart(0, "span", 25);
93
+ i0.ɵɵelement(1, "span", 26);
94
+ i0.ɵɵelementEnd();
95
+ } }
91
96
  function PrismSidebarComponent_For_11_Conditional_7_For_2_Template(rf, ctx) { if (rf & 1) {
92
97
  const _r8 = i0.ɵɵgetCurrentView();
93
98
  i0.ɵɵelementStart(0, "button", 18);
94
99
  i0.ɵɵlistener("click", function PrismSidebarComponent_For_11_Conditional_7_For_2_Template_button_click_0_listener() { const item_r9 = i0.ɵɵrestoreView(_r8).$implicit; const ctx_r2 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r2.onSelect(item_r9)); });
95
- i0.ɵɵelement(1, "prism-icon", 23);
100
+ i0.ɵɵelement(1, "prism-icon", 24);
96
101
  i0.ɵɵelementStart(2, "span", 19);
97
102
  i0.ɵɵtext(3);
98
- i0.ɵɵelementEnd()();
103
+ i0.ɵɵelementEnd();
104
+ i0.ɵɵconditionalCreate(4, PrismSidebarComponent_For_11_Conditional_7_For_2_Conditional_4_Template, 2, 0, "span", 25);
105
+ i0.ɵɵelementEnd();
99
106
  } if (rf & 2) {
100
107
  const item_r9 = ctx.$implicit;
101
108
  const ctx_r2 = i0.ɵɵnextContext(3);
102
- i0.ɵɵclassProp("sb-item--active", ctx_r2.isActive(item_r9));
109
+ i0.ɵɵclassProp("sb-item--active", ctx_r2.isActive(item_r9))("sb-item--deprecated", ctx_r2.itemStatus(item_r9) === "deprecated");
110
+ i0.ɵɵattribute("title", ctx_r2.itemTooltip(item_r9));
103
111
  i0.ɵɵadvance();
104
112
  i0.ɵɵproperty("size", 12);
105
113
  i0.ɵɵadvance(2);
106
114
  i0.ɵɵtextInterpolate(ctx_r2.itemLabel(item_r9));
115
+ i0.ɵɵadvance();
116
+ i0.ɵɵconditional(ctx_r2.itemStatus(item_r9) === "wip" ? 4 : -1);
107
117
  } }
108
118
  function PrismSidebarComponent_For_11_Conditional_7_Template(rf, ctx) { if (rf & 1) {
109
119
  i0.ɵɵelementStart(0, "div", 16);
110
- i0.ɵɵrepeaterCreate(1, PrismSidebarComponent_For_11_Conditional_7_For_2_Template, 4, 4, "button", 17, _forTrack1, true);
120
+ i0.ɵɵrepeaterCreate(1, PrismSidebarComponent_For_11_Conditional_7_For_2_Template, 5, 8, "button", 23, _forTrack1, true);
111
121
  i0.ɵɵelementEnd();
112
122
  } if (rf & 2) {
113
123
  const cat_r7 = i0.ɵɵnextContext().$implicit;
@@ -234,6 +244,19 @@ export class PrismSidebarComponent {
234
244
  ? item.data.meta.showcaseConfig.title
235
245
  : item.data.title;
236
246
  }
247
+ itemStatus(item) {
248
+ return item.kind === 'component'
249
+ ? item.data.meta.showcaseConfig.status
250
+ : undefined;
251
+ }
252
+ itemTooltip(item) {
253
+ const status = this.itemStatus(item);
254
+ if (status === 'wip')
255
+ return 'Work in progress';
256
+ if (status === 'deprecated')
257
+ return 'Deprecated / Legacy';
258
+ return null;
259
+ }
237
260
  isActive(item) {
238
261
  const active = this.navigationService.activeItem();
239
262
  if (!active || active.kind !== item.kind)
@@ -273,7 +296,7 @@ export class PrismSidebarComponent {
273
296
  i0.ɵɵqueryAdvance();
274
297
  } }, hostBindings: function PrismSidebarComponent_HostBindings(rf, ctx) { if (rf & 1) {
275
298
  i0.ɵɵlistener("keydown", function PrismSidebarComponent_keydown_HostBindingHandler($event) { return ctx.onGlobalKey($event); }, i0.ɵɵresolveDocument);
276
- } }, decls: 12, vars: 4, consts: [["filterInput", ""], [1, "prism-sidebar"], [1, "sb-filter"], ["name", "search", 3, "size"], ["placeholder", "Filter components\u2026", 3, "input", "value"], [1, "sb-scroll"], [1, "sb-pinned"], [1, "sb-section-head"], [1, "sb-group", 3, "sb-group--collapsed"], [1, "sb-pinned-head"], [1, "sb-pinned-head-l"], ["name", "pin", 1, "sb-pinned-pin", 3, "size"], [1, "sb-group"], [1, "sb-group-head", 3, "click"], ["name", "chevron-down", 3, "size"], [1, "sb-group-chip"], [1, "sb-group-body"], [1, "sb-item", 3, "sb-item--active"], [1, "sb-item", 3, "click"], [1, "sb-item-name"], [1, "sb-section-head-l"], ["name", "box", 1, "sb-section-icon", 3, "size"], [1, "sb-group-count"], ["name", "box", 1, "sb-item-icon", 3, "size"]], template: function PrismSidebarComponent_Template(rf, ctx) { if (rf & 1) {
299
+ } }, decls: 12, vars: 4, consts: [["filterInput", ""], [1, "prism-sidebar"], [1, "sb-filter"], ["name", "search", 3, "size"], ["placeholder", "Filter components\u2026", 3, "input", "value"], [1, "sb-scroll"], [1, "sb-pinned"], [1, "sb-section-head"], [1, "sb-group", 3, "sb-group--collapsed"], [1, "sb-pinned-head"], [1, "sb-pinned-head-l"], ["name", "pin", 1, "sb-pinned-pin", 3, "size"], [1, "sb-group"], [1, "sb-group-head", 3, "click"], ["name", "chevron-down", 3, "size"], [1, "sb-group-chip"], [1, "sb-group-body"], [1, "sb-item", 3, "sb-item--active"], [1, "sb-item", 3, "click"], [1, "sb-item-name"], [1, "sb-section-head-l"], ["name", "box", 1, "sb-section-icon", 3, "size"], [1, "sb-group-count"], [1, "sb-item", 3, "sb-item--active", "sb-item--deprecated"], ["name", "box", 1, "sb-item-icon", 3, "size"], ["title", "Work in progress", 1, "sb-item-status"], [1, "sb-item-status-dot"]], template: function PrismSidebarComponent_Template(rf, ctx) { if (rf & 1) {
277
300
  i0.ɵɵelementStart(0, "nav", 1)(1, "div", 2);
278
301
  i0.ɵɵelement(2, "prism-icon", 3);
279
302
  i0.ɵɵelementStart(3, "input", 4, 0);
@@ -298,7 +321,7 @@ export class PrismSidebarComponent {
298
321
  i0.ɵɵconditional(ctx.componentCategories().length > 0 ? 9 : -1);
299
322
  i0.ɵɵadvance();
300
323
  i0.ɵɵrepeater(ctx.componentCategories());
301
- } }, dependencies: [PrismIconComponent], styles: [".prism-sidebar[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n height: 100%;\n min-height: 0;\n overflow: hidden;\n }\n\n .sb-filter[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n margin: 12px;\n padding: 0 10px;\n height: 30px;\n background: var(--prism-input-bg);\n border: 1px solid var(--prism-border);\n border-radius: 6px;\n color: var(--prism-text-muted);\n }\n .sb-filter[_ngcontent-%COMP%] input[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 0;\n background: transparent;\n border: 0;\n outline: none;\n font-size: var(--fs-md);\n color: var(--prism-text);\n font-family: var(--font-sans);\n }\n .sb-filter[_ngcontent-%COMP%] input[_ngcontent-%COMP%]::placeholder { color: var(--prism-text-muted); }\n .sb-filter[_ngcontent-%COMP%] kbd[_ngcontent-%COMP%] {\n font-family: var(--font-mono);\n font-size: 10px;\n color: var(--prism-text-ghost);\n padding: 1px 5px;\n border: 1px solid var(--prism-border);\n border-radius: 3px;\n }\n\n .sb-scroll[_ngcontent-%COMP%] {\n flex: 1;\n overflow-y: auto;\n padding: 10px 0 16px;\n padding-top: 0;\n }\n .sb-scroll[_ngcontent-%COMP%]::-webkit-scrollbar { width: 8px; }\n .sb-scroll[_ngcontent-%COMP%]::-webkit-scrollbar-thumb { background: var(--prism-border-strong); border-radius: 4px; }\n .sb-scroll[_ngcontent-%COMP%]::-webkit-scrollbar-track { background: transparent; }\n\n .sb-pinned[_ngcontent-%COMP%] {\n padding: 0 0 10px;\n margin-bottom: 4px;\n border-bottom: 1px solid var(--prism-border);\n border-top: 1px solid var(--prism-border);\n }\n .sb-section-head[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 8px 14px 6px;\n font-size: 10.5px;\n font-weight: 700;\n letter-spacing: 0.09em;\n text-transform: uppercase;\n color: var(--prism-text-ghost);\n margin-top: 6px;\n }\n .sb-section-head-l[_ngcontent-%COMP%] { display: flex; align-items: center; gap: 6px; }\n .sb-section-icon[_ngcontent-%COMP%] { color: var(--prism-primary); }\n .sb-pinned-head[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 8px 14px 6px;\n margin-top: 6px;\n font-size: 10.5px;\n font-weight: 700;\n letter-spacing: 0.09em;\n text-transform: uppercase;\n color: var(--prism-text-ghost);\n }\n .sb-pinned-head-l[_ngcontent-%COMP%] { display: flex; align-items: center; gap: 6px; }\n .sb-pinned-pin[_ngcontent-%COMP%] { color: var(--prism-accent); }\n\n .sb-group[_ngcontent-%COMP%] { margin-bottom: 4px; }\n .sb-group-head[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 6px;\n width: 100%;\n padding: 8px 14px 6px;\n font-size: 10.5px;\n font-weight: 700;\n letter-spacing: 0.09em;\n text-transform: uppercase;\n color: var(--prism-text-ghost);\n cursor: pointer;\n user-select: none;\n background: none;\n border: none;\n text-align: left;\n font-family: var(--font-sans);\n }\n .sb-group-head[_ngcontent-%COMP%] prism-icon[_ngcontent-%COMP%] {\n transition: transform var(--dur-fast);\n color: var(--prism-text-ghost);\n }\n .sb-group--collapsed[_ngcontent-%COMP%] .sb-group-head[_ngcontent-%COMP%] prism-icon[_ngcontent-%COMP%] { transform: rotate(-90deg); }\n\n .sb-group-chip[_ngcontent-%COMP%] {\n width: 6px;\n height: 6px;\n border-radius: 2px;\n background: var(--chip, var(--prism-primary));\n box-shadow: 0 0 6px var(--chip, var(--prism-primary));\n }\n .sb-group-count[_ngcontent-%COMP%] {\n margin-left: auto;\n font-family: var(--font-mono);\n font-size: 10px;\n color: var(--prism-text-ghost);\n font-weight: 500;\n }\n\n .sb-item[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 10px;\n width: 100%;\n height: 30px;\n padding: 0 14px 0 28px;\n font-size: 13px;\n color: var(--prism-text-2);\n cursor: pointer;\n border: none;\n border-left: 2px solid transparent;\n background: none;\n position: relative;\n transition: background var(--dur-fast), color var(--dur-fast);\n text-align: left;\n font-family: var(--font-sans);\n }\n .sb-item[_ngcontent-%COMP%]:hover {\n background: color-mix(in srgb, var(--prism-primary) 5%, transparent);\n color: var(--prism-text);\n }\n .sb-item--active[_ngcontent-%COMP%] {\n border-left-color: var(--prism-primary);\n background: color-mix(in srgb, var(--prism-primary) 12%, transparent);\n color: var(--prism-text);\n font-weight: 500;\n }\n .sb-item--active[_ngcontent-%COMP%]::before {\n content: '';\n position: absolute;\n left: -1px;\n top: 0;\n bottom: 0;\n width: 3px;\n background: linear-gradient(180deg, var(--prism-primary-from), var(--prism-primary-to));\n }\n .sb-item-icon[_ngcontent-%COMP%] { flex: 0 0 12px; opacity: 0.7; }\n .sb-item-name[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 0;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n }\n\n\n [_ngcontent-%COMP%]:focus-visible {\n outline: 2px solid var(--prism-primary);\n outline-offset: 2px;\n }"], changeDetection: 0 });
324
+ } }, dependencies: [PrismIconComponent], styles: [".prism-sidebar[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n height: 100%;\n min-height: 0;\n overflow: hidden;\n }\n\n .sb-filter[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 8px;\n margin: 12px;\n padding: 0 10px;\n height: 30px;\n background: var(--prism-input-bg);\n border: 1px solid var(--prism-border);\n border-radius: 6px;\n color: var(--prism-text-muted);\n }\n .sb-filter[_ngcontent-%COMP%] input[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 0;\n background: transparent;\n border: 0;\n outline: none;\n font-size: var(--fs-md);\n color: var(--prism-text);\n font-family: var(--font-sans);\n }\n .sb-filter[_ngcontent-%COMP%] input[_ngcontent-%COMP%]::placeholder { color: var(--prism-text-muted); }\n .sb-filter[_ngcontent-%COMP%] kbd[_ngcontent-%COMP%] {\n font-family: var(--font-mono);\n font-size: 10px;\n color: var(--prism-text-ghost);\n padding: 1px 5px;\n border: 1px solid var(--prism-border);\n border-radius: 3px;\n }\n\n .sb-scroll[_ngcontent-%COMP%] {\n flex: 1;\n overflow-y: auto;\n padding: 10px 0 16px;\n padding-top: 0;\n }\n .sb-scroll[_ngcontent-%COMP%]::-webkit-scrollbar { width: 8px; }\n .sb-scroll[_ngcontent-%COMP%]::-webkit-scrollbar-thumb { background: var(--prism-border-strong); border-radius: 4px; }\n .sb-scroll[_ngcontent-%COMP%]::-webkit-scrollbar-track { background: transparent; }\n\n .sb-pinned[_ngcontent-%COMP%] {\n padding: 0 0 10px;\n margin-bottom: 4px;\n border-bottom: 1px solid var(--prism-border);\n border-top: 1px solid var(--prism-border);\n }\n .sb-section-head[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 8px 14px 6px;\n font-size: 10.5px;\n font-weight: 700;\n letter-spacing: 0.09em;\n text-transform: uppercase;\n color: var(--prism-text-ghost);\n margin-top: 6px;\n }\n .sb-section-head-l[_ngcontent-%COMP%] { display: flex; align-items: center; gap: 6px; }\n .sb-section-icon[_ngcontent-%COMP%] { color: var(--prism-primary); }\n .sb-pinned-head[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 8px 14px 6px;\n margin-top: 6px;\n font-size: 10.5px;\n font-weight: 700;\n letter-spacing: 0.09em;\n text-transform: uppercase;\n color: var(--prism-text-ghost);\n }\n .sb-pinned-head-l[_ngcontent-%COMP%] { display: flex; align-items: center; gap: 6px; }\n .sb-pinned-pin[_ngcontent-%COMP%] { color: var(--prism-accent); }\n\n .sb-group[_ngcontent-%COMP%] { margin-bottom: 4px; }\n .sb-group-head[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 6px;\n width: 100%;\n padding: 8px 14px 6px;\n font-size: 10.5px;\n font-weight: 700;\n letter-spacing: 0.09em;\n text-transform: uppercase;\n color: var(--prism-text-ghost);\n cursor: pointer;\n user-select: none;\n background: none;\n border: none;\n text-align: left;\n font-family: var(--font-sans);\n }\n .sb-group-head[_ngcontent-%COMP%] prism-icon[_ngcontent-%COMP%] {\n transition: transform var(--dur-fast);\n color: var(--prism-text-ghost);\n }\n .sb-group--collapsed[_ngcontent-%COMP%] .sb-group-head[_ngcontent-%COMP%] prism-icon[_ngcontent-%COMP%] { transform: rotate(-90deg); }\n\n .sb-group-chip[_ngcontent-%COMP%] {\n width: 6px;\n height: 6px;\n border-radius: 2px;\n background: var(--chip, var(--prism-primary));\n box-shadow: 0 0 6px var(--chip, var(--prism-primary));\n }\n .sb-group-count[_ngcontent-%COMP%] {\n margin-left: auto;\n font-family: var(--font-mono);\n font-size: 10px;\n color: var(--prism-text-ghost);\n font-weight: 500;\n }\n\n .sb-item[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 10px;\n width: 100%;\n height: 30px;\n padding: 0 14px 0 28px;\n font-size: 13px;\n color: var(--prism-text-2);\n cursor: pointer;\n border: none;\n border-left: 2px solid transparent;\n background: none;\n position: relative;\n transition: background var(--dur-fast), color var(--dur-fast);\n text-align: left;\n font-family: var(--font-sans);\n }\n .sb-item[_ngcontent-%COMP%]:hover {\n background: color-mix(in srgb, var(--prism-primary) 5%, transparent);\n color: var(--prism-text);\n }\n .sb-item--active[_ngcontent-%COMP%] {\n border-left-color: var(--prism-primary);\n background: color-mix(in srgb, var(--prism-primary) 12%, transparent);\n color: var(--prism-text);\n font-weight: 500;\n }\n .sb-item--active[_ngcontent-%COMP%]::before {\n content: '';\n position: absolute;\n left: -1px;\n top: 0;\n bottom: 0;\n width: 3px;\n background: linear-gradient(180deg, var(--prism-primary-from), var(--prism-primary-to));\n }\n .sb-item-icon[_ngcontent-%COMP%] { flex: 0 0 12px; opacity: 0.7; }\n .sb-item-name[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 0;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n }\n\n .sb-item-status[_ngcontent-%COMP%] {\n flex: 0 0 auto;\n margin-left: auto;\n display: flex;\n align-items: center;\n }\n .sb-item-status-dot[_ngcontent-%COMP%] {\n width: 6px;\n height: 6px;\n border-radius: 50%;\n background: var(--prism-warn);\n }\n\n .sb-item--deprecated[_ngcontent-%COMP%] .sb-item-name[_ngcontent-%COMP%] {\n text-decoration: line-through;\n text-decoration-thickness: 1px;\n color: var(--prism-text-ghost);\n opacity: 0.7;\n }\n\n\n [_ngcontent-%COMP%]:focus-visible {\n outline: 2px solid var(--prism-primary);\n outline-offset: 2px;\n }"], changeDetection: 0 });
302
325
  }
303
326
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(PrismSidebarComponent, [{
304
327
  type: Component,
@@ -384,10 +407,17 @@ export class PrismSidebarComponent {
384
407
  <button
385
408
  class="sb-item"
386
409
  [class.sb-item--active]="isActive(item)"
410
+ [class.sb-item--deprecated]="itemStatus(item) === 'deprecated'"
411
+ [attr.title]="itemTooltip(item)"
387
412
  (click)="onSelect(item)"
388
413
  >
389
414
  <prism-icon name="box" [size]="12" class="sb-item-icon" />
390
415
  <span class="sb-item-name">{{ itemLabel(item) }}</span>
416
+ @if (itemStatus(item) === 'wip') {
417
+ <span class="sb-item-status" title="Work in progress">
418
+ <span class="sb-item-status-dot"></span>
419
+ </span>
420
+ }
391
421
  </button>
392
422
  }
393
423
  </div>
@@ -396,9 +426,9 @@ export class PrismSidebarComponent {
396
426
  }
397
427
  </div>
398
428
  </nav>
399
- `, styles: ["\n .prism-sidebar {\n display: flex;\n flex-direction: column;\n height: 100%;\n min-height: 0;\n overflow: hidden;\n }\n\n .sb-filter {\n display: flex;\n align-items: center;\n gap: 8px;\n margin: 12px;\n padding: 0 10px;\n height: 30px;\n background: var(--prism-input-bg);\n border: 1px solid var(--prism-border);\n border-radius: 6px;\n color: var(--prism-text-muted);\n }\n .sb-filter input {\n flex: 1;\n min-width: 0;\n background: transparent;\n border: 0;\n outline: none;\n font-size: var(--fs-md);\n color: var(--prism-text);\n font-family: var(--font-sans);\n }\n .sb-filter input::placeholder { color: var(--prism-text-muted); }\n .sb-filter kbd {\n font-family: var(--font-mono);\n font-size: 10px;\n color: var(--prism-text-ghost);\n padding: 1px 5px;\n border: 1px solid var(--prism-border);\n border-radius: 3px;\n }\n\n .sb-scroll {\n flex: 1;\n overflow-y: auto;\n padding: 10px 0 16px;\n padding-top: 0;\n }\n .sb-scroll::-webkit-scrollbar { width: 8px; }\n .sb-scroll::-webkit-scrollbar-thumb { background: var(--prism-border-strong); border-radius: 4px; }\n .sb-scroll::-webkit-scrollbar-track { background: transparent; }\n\n .sb-pinned {\n padding: 0 0 10px;\n margin-bottom: 4px;\n border-bottom: 1px solid var(--prism-border);\n border-top: 1px solid var(--prism-border);\n }\n .sb-section-head {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 8px 14px 6px;\n font-size: 10.5px;\n font-weight: 700;\n letter-spacing: 0.09em;\n text-transform: uppercase;\n color: var(--prism-text-ghost);\n margin-top: 6px;\n }\n .sb-section-head-l { display: flex; align-items: center; gap: 6px; }\n .sb-section-icon { color: var(--prism-primary); }\n .sb-pinned-head {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 8px 14px 6px;\n margin-top: 6px;\n font-size: 10.5px;\n font-weight: 700;\n letter-spacing: 0.09em;\n text-transform: uppercase;\n color: var(--prism-text-ghost);\n }\n .sb-pinned-head-l { display: flex; align-items: center; gap: 6px; }\n .sb-pinned-pin { color: var(--prism-accent); }\n\n .sb-group { margin-bottom: 4px; }\n .sb-group-head {\n display: flex;\n align-items: center;\n gap: 6px;\n width: 100%;\n padding: 8px 14px 6px;\n font-size: 10.5px;\n font-weight: 700;\n letter-spacing: 0.09em;\n text-transform: uppercase;\n color: var(--prism-text-ghost);\n cursor: pointer;\n user-select: none;\n background: none;\n border: none;\n text-align: left;\n font-family: var(--font-sans);\n }\n .sb-group-head prism-icon {\n transition: transform var(--dur-fast);\n color: var(--prism-text-ghost);\n }\n .sb-group--collapsed .sb-group-head prism-icon { transform: rotate(-90deg); }\n\n .sb-group-chip {\n width: 6px;\n height: 6px;\n border-radius: 2px;\n background: var(--chip, var(--prism-primary));\n box-shadow: 0 0 6px var(--chip, var(--prism-primary));\n }\n .sb-group-count {\n margin-left: auto;\n font-family: var(--font-mono);\n font-size: 10px;\n color: var(--prism-text-ghost);\n font-weight: 500;\n }\n\n .sb-item {\n display: flex;\n align-items: center;\n gap: 10px;\n width: 100%;\n height: 30px;\n padding: 0 14px 0 28px;\n font-size: 13px;\n color: var(--prism-text-2);\n cursor: pointer;\n border: none;\n border-left: 2px solid transparent;\n background: none;\n position: relative;\n transition: background var(--dur-fast), color var(--dur-fast);\n text-align: left;\n font-family: var(--font-sans);\n }\n .sb-item:hover {\n background: color-mix(in srgb, var(--prism-primary) 5%, transparent);\n color: var(--prism-text);\n }\n .sb-item--active {\n border-left-color: var(--prism-primary);\n background: color-mix(in srgb, var(--prism-primary) 12%, transparent);\n color: var(--prism-text);\n font-weight: 500;\n }\n .sb-item--active::before {\n content: '';\n position: absolute;\n left: -1px;\n top: 0;\n bottom: 0;\n width: 3px;\n background: linear-gradient(180deg, var(--prism-primary-from), var(--prism-primary-to));\n }\n .sb-item-icon { flex: 0 0 12px; opacity: 0.7; }\n .sb-item-name {\n flex: 1;\n min-width: 0;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n }\n\n\n :focus-visible {\n outline: 2px solid var(--prism-primary);\n outline-offset: 2px;\n }\n "] }]
429
+ `, styles: ["\n .prism-sidebar {\n display: flex;\n flex-direction: column;\n height: 100%;\n min-height: 0;\n overflow: hidden;\n }\n\n .sb-filter {\n display: flex;\n align-items: center;\n gap: 8px;\n margin: 12px;\n padding: 0 10px;\n height: 30px;\n background: var(--prism-input-bg);\n border: 1px solid var(--prism-border);\n border-radius: 6px;\n color: var(--prism-text-muted);\n }\n .sb-filter input {\n flex: 1;\n min-width: 0;\n background: transparent;\n border: 0;\n outline: none;\n font-size: var(--fs-md);\n color: var(--prism-text);\n font-family: var(--font-sans);\n }\n .sb-filter input::placeholder { color: var(--prism-text-muted); }\n .sb-filter kbd {\n font-family: var(--font-mono);\n font-size: 10px;\n color: var(--prism-text-ghost);\n padding: 1px 5px;\n border: 1px solid var(--prism-border);\n border-radius: 3px;\n }\n\n .sb-scroll {\n flex: 1;\n overflow-y: auto;\n padding: 10px 0 16px;\n padding-top: 0;\n }\n .sb-scroll::-webkit-scrollbar { width: 8px; }\n .sb-scroll::-webkit-scrollbar-thumb { background: var(--prism-border-strong); border-radius: 4px; }\n .sb-scroll::-webkit-scrollbar-track { background: transparent; }\n\n .sb-pinned {\n padding: 0 0 10px;\n margin-bottom: 4px;\n border-bottom: 1px solid var(--prism-border);\n border-top: 1px solid var(--prism-border);\n }\n .sb-section-head {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 8px 14px 6px;\n font-size: 10.5px;\n font-weight: 700;\n letter-spacing: 0.09em;\n text-transform: uppercase;\n color: var(--prism-text-ghost);\n margin-top: 6px;\n }\n .sb-section-head-l { display: flex; align-items: center; gap: 6px; }\n .sb-section-icon { color: var(--prism-primary); }\n .sb-pinned-head {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 8px 14px 6px;\n margin-top: 6px;\n font-size: 10.5px;\n font-weight: 700;\n letter-spacing: 0.09em;\n text-transform: uppercase;\n color: var(--prism-text-ghost);\n }\n .sb-pinned-head-l { display: flex; align-items: center; gap: 6px; }\n .sb-pinned-pin { color: var(--prism-accent); }\n\n .sb-group { margin-bottom: 4px; }\n .sb-group-head {\n display: flex;\n align-items: center;\n gap: 6px;\n width: 100%;\n padding: 8px 14px 6px;\n font-size: 10.5px;\n font-weight: 700;\n letter-spacing: 0.09em;\n text-transform: uppercase;\n color: var(--prism-text-ghost);\n cursor: pointer;\n user-select: none;\n background: none;\n border: none;\n text-align: left;\n font-family: var(--font-sans);\n }\n .sb-group-head prism-icon {\n transition: transform var(--dur-fast);\n color: var(--prism-text-ghost);\n }\n .sb-group--collapsed .sb-group-head prism-icon { transform: rotate(-90deg); }\n\n .sb-group-chip {\n width: 6px;\n height: 6px;\n border-radius: 2px;\n background: var(--chip, var(--prism-primary));\n box-shadow: 0 0 6px var(--chip, var(--prism-primary));\n }\n .sb-group-count {\n margin-left: auto;\n font-family: var(--font-mono);\n font-size: 10px;\n color: var(--prism-text-ghost);\n font-weight: 500;\n }\n\n .sb-item {\n display: flex;\n align-items: center;\n gap: 10px;\n width: 100%;\n height: 30px;\n padding: 0 14px 0 28px;\n font-size: 13px;\n color: var(--prism-text-2);\n cursor: pointer;\n border: none;\n border-left: 2px solid transparent;\n background: none;\n position: relative;\n transition: background var(--dur-fast), color var(--dur-fast);\n text-align: left;\n font-family: var(--font-sans);\n }\n .sb-item:hover {\n background: color-mix(in srgb, var(--prism-primary) 5%, transparent);\n color: var(--prism-text);\n }\n .sb-item--active {\n border-left-color: var(--prism-primary);\n background: color-mix(in srgb, var(--prism-primary) 12%, transparent);\n color: var(--prism-text);\n font-weight: 500;\n }\n .sb-item--active::before {\n content: '';\n position: absolute;\n left: -1px;\n top: 0;\n bottom: 0;\n width: 3px;\n background: linear-gradient(180deg, var(--prism-primary-from), var(--prism-primary-to));\n }\n .sb-item-icon { flex: 0 0 12px; opacity: 0.7; }\n .sb-item-name {\n flex: 1;\n min-width: 0;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n }\n\n .sb-item-status {\n flex: 0 0 auto;\n margin-left: auto;\n display: flex;\n align-items: center;\n }\n .sb-item-status-dot {\n width: 6px;\n height: 6px;\n border-radius: 50%;\n background: var(--prism-warn);\n }\n\n .sb-item--deprecated .sb-item-name {\n text-decoration: line-through;\n text-decoration-thickness: 1px;\n color: var(--prism-text-ghost);\n opacity: 0.7;\n }\n\n\n :focus-visible {\n outline: 2px solid var(--prism-primary);\n outline-offset: 2px;\n }\n "] }]
400
430
  }], null, { filterInput: [{ type: i0.ViewChild, args: ['filterInput', { isSignal: true }] }], onGlobalKey: [{
401
431
  type: HostListener,
402
432
  args: ['document:keydown', ['$event']]
403
433
  }] }); })();
404
- (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(PrismSidebarComponent, { className: "PrismSidebarComponent", filePath: "app/sidebar/prism-sidebar.component.ts", lineNumber: 323 }); })();
434
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(PrismSidebarComponent, { className: "PrismSidebarComponent", filePath: "app/sidebar/prism-sidebar.component.ts", lineNumber: 351 }); })();
@@ -1 +1 @@
1
- {"version":3,"file":"component.scanner.d.ts","sourceRoot":"","sources":["../../../src/builder/scanner/component.scanner.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,YAAY,CAAC;AAC5B,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAiBrE;;GAEG;AACH,wBAAgB,cAAc,CAC5B,OAAO,EAAE,EAAE,CAAC,MAAM,EAAE,EACpB,OAAO,EAAE,EAAE,CAAC,WAAW,GACtB,gBAAgB,EAAE,CAyCpB"}
1
+ {"version":3,"file":"component.scanner.d.ts","sourceRoot":"","sources":["../../../src/builder/scanner/component.scanner.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,YAAY,CAAC;AAC5B,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AA6BrE;;GAEG;AACH,wBAAgB,cAAc,CAC5B,OAAO,EAAE,EAAE,CAAC,MAAM,EAAE,EACpB,OAAO,EAAE,EAAE,CAAC,WAAW,GACtB,gBAAgB,EAAE,CA8CpB"}
@@ -1,5 +1,10 @@
1
1
  import ts from 'typescript';
2
2
  import { CANVAS_BGS } from '../../shared/canvas-bg.type.js';
3
+ const COMPONENT_STATUSES = ['stable', 'beta', 'wip', 'deprecated'];
4
+ function isComponentStatus(value) {
5
+ return (typeof value === 'string' &&
6
+ COMPONENT_STATUSES.includes(value));
7
+ }
3
8
  import { evaluateExpression, findDecorator, getDecoratorArgument, } from './ast-utils.js';
4
9
  import { extractInputs, extractOutputs } from './input.extractor.js';
5
10
  function isCanvasBg(value) {
@@ -16,6 +21,11 @@ export function scanComponents(exports, checker) {
16
21
  const classDecl = resolved.declarations?.find(ts.isClassDeclaration);
17
22
  if (!classDecl)
18
23
  continue;
24
+ // Perf: cheap pre-filter — skip the full decorator walk for files that don't
25
+ // mention Showcase at all. False positives (string-literal containing "@Showcase")
26
+ // just lose the optimization for that file; correctness is unaffected.
27
+ if (!classDecl.getSourceFile().text.includes('@Showcase'))
28
+ continue;
19
29
  const showcaseDecorator = findDecorator(classDecl, 'Showcase');
20
30
  if (!showcaseDecorator)
21
31
  continue;
@@ -79,6 +89,15 @@ function extractShowcaseConfig(decorator, className) {
79
89
  config.host = obj['host'];
80
90
  if (obj['renderPage'])
81
91
  config.renderPage = obj['renderPage'];
92
+ if (obj['status'] !== undefined) {
93
+ if (isComponentStatus(obj['status'])) {
94
+ config.status = obj['status'];
95
+ }
96
+ else {
97
+ console.warn(`⚠ ng-prism: ${className} declares invalid status "${String(obj['status'])}" — ` +
98
+ `expected one of: ${COMPONENT_STATUSES.join(', ')}. Skipping.`);
99
+ }
100
+ }
82
101
  if (obj['bg'] !== undefined) {
83
102
  if (isCanvasBg(obj['bg'])) {
84
103
  config.bg = obj['bg'];
@@ -1,11 +1,22 @@
1
1
  import ts from 'typescript';
2
- export interface EntryPointResult {
3
- program: ts.Program;
2
+ export interface EntryPointInput {
3
+ entryFile: string;
4
+ importPath: string;
5
+ }
6
+ export interface ResolvedEntryPoint extends EntryPointInput {
4
7
  exports: ts.Symbol[];
5
8
  }
9
+ export interface MultiEntryResult {
10
+ program: ts.Program;
11
+ entries: ResolvedEntryPoint[];
12
+ }
6
13
  /**
7
- * Resolve all exported symbols from an entry-point file (e.g. public-api.ts).
14
+ * Resolve all exported symbols for one or more entry-point files (e.g. public-api.ts).
15
+ * A single shared `ts.Program` is created with every entry file as a root name, so the
16
+ * transitive type graph (Angular framework typings, etc.) is parsed once and reused
17
+ * across all entries via the shared `TypeChecker`.
18
+ *
8
19
  * Re-exports (`export * from '...'`) are resolved automatically by TypeScript.
9
20
  */
10
- export declare function resolveEntryPointExports(entryPointPath: string, compilerOptions: ts.CompilerOptions, previousProgram?: ts.Program): EntryPointResult;
21
+ export declare function resolveEntryPointExports(entryPoints: ReadonlyArray<EntryPointInput>, compilerOptions: ts.CompilerOptions, previousProgram?: ts.Program): MultiEntryResult;
11
22
  //# sourceMappingURL=entry-point.scanner.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"entry-point.scanner.d.ts","sourceRoot":"","sources":["../../../src/builder/scanner/entry-point.scanner.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,YAAY,CAAC;AAE5B,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC;IACpB,OAAO,EAAE,EAAE,CAAC,MAAM,EAAE,CAAC;CACtB;AAED;;;GAGG;AACH,wBAAgB,wBAAwB,CACtC,cAAc,EAAE,MAAM,EACtB,eAAe,EAAE,EAAE,CAAC,eAAe,EACnC,eAAe,CAAC,EAAE,EAAE,CAAC,OAAO,GAC3B,gBAAgB,CAqBlB"}
1
+ {"version":3,"file":"entry-point.scanner.d.ts","sourceRoot":"","sources":["../../../src/builder/scanner/entry-point.scanner.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,YAAY,CAAC;AAE5B,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,kBAAmB,SAAQ,eAAe;IACzD,OAAO,EAAE,EAAE,CAAC,MAAM,EAAE,CAAC;CACtB;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC;IACpB,OAAO,EAAE,kBAAkB,EAAE,CAAC;CAC/B;AAED;;;;;;;GAOG;AACH,wBAAgB,wBAAwB,CACtC,WAAW,EAAE,aAAa,CAAC,eAAe,CAAC,EAC3C,eAAe,EAAE,EAAE,CAAC,eAAe,EACnC,eAAe,CAAC,EAAE,EAAE,CAAC,OAAO,GAC3B,gBAAgB,CAoClB"}
@@ -1,19 +1,32 @@
1
1
  import ts from 'typescript';
2
2
  /**
3
- * Resolve all exported symbols from an entry-point file (e.g. public-api.ts).
3
+ * Resolve all exported symbols for one or more entry-point files (e.g. public-api.ts).
4
+ * A single shared `ts.Program` is created with every entry file as a root name, so the
5
+ * transitive type graph (Angular framework typings, etc.) is parsed once and reused
6
+ * across all entries via the shared `TypeChecker`.
7
+ *
4
8
  * Re-exports (`export * from '...'`) are resolved automatically by TypeScript.
5
9
  */
6
- export function resolveEntryPointExports(entryPointPath, compilerOptions, previousProgram) {
7
- const program = ts.createProgram([entryPointPath], compilerOptions, undefined, previousProgram);
10
+ export function resolveEntryPointExports(entryPoints, compilerOptions, previousProgram) {
11
+ const program = ts.createProgram(entryPoints.map((e) => e.entryFile), compilerOptions, undefined, previousProgram);
8
12
  const checker = program.getTypeChecker();
9
- const sourceFile = program.getSourceFile(entryPointPath);
10
- if (!sourceFile) {
11
- throw new Error(`Could not find source file: ${entryPointPath}`);
12
- }
13
- const moduleSymbol = checker.getSymbolAtLocation(sourceFile);
14
- if (!moduleSymbol) {
15
- return { program, exports: [] };
16
- }
17
- const exports = checker.getExportsOfModule(moduleSymbol);
18
- return { program, exports };
13
+ const entries = entryPoints.map(({ entryFile, importPath }) => {
14
+ try {
15
+ const sourceFile = program.getSourceFile(entryFile);
16
+ if (!sourceFile) {
17
+ console.warn(`⚠ ng-prism: source file not found for entry point ${entryFile}, skipping.`);
18
+ return { entryFile, importPath, exports: [] };
19
+ }
20
+ const moduleSymbol = checker.getSymbolAtLocation(sourceFile);
21
+ const exports = moduleSymbol
22
+ ? checker.getExportsOfModule(moduleSymbol)
23
+ : [];
24
+ return { entryFile, importPath, exports };
25
+ }
26
+ catch (err) {
27
+ console.error(`⚠ ng-prism: failed to resolve exports for ${entryFile}: ${err instanceof Error ? err.message : String(err)}`);
28
+ return { entryFile, importPath, exports: [] };
29
+ }
30
+ });
31
+ return { program, entries };
19
32
  }
@@ -1,7 +1,7 @@
1
1
  export { createScanner } from './scanner.js';
2
- export type { CreateScannerOptions, Scanner } from './scanner.js';
2
+ export type { CreateScannerOptions, Scanner, ScanResult } from './scanner.js';
3
3
  export { resolveEntryPointExports } from './entry-point.scanner.js';
4
- export type { EntryPointResult } from './entry-point.scanner.js';
4
+ export type { EntryPointInput, ResolvedEntryPoint, MultiEntryResult, } from './entry-point.scanner.js';
5
5
  export { scanComponents } from './component.scanner.js';
6
6
  export { extractInputs, extractOutputs } from './input.extractor.js';
7
7
  export { generateManifest } from './manifest.generator.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/builder/scanner/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,YAAY,EAAE,oBAAoB,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAClE,OAAO,EAAE,wBAAwB,EAAE,MAAM,0BAA0B,CAAC;AACpE,YAAY,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AACjE,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACrE,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/builder/scanner/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,YAAY,EAAE,oBAAoB,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC9E,OAAO,EAAE,wBAAwB,EAAE,MAAM,0BAA0B,CAAC;AACpE,YAAY,EACV,eAAe,EACf,kBAAkB,EAClB,gBAAgB,GACjB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACrE,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC"}
@@ -1,16 +1,25 @@
1
1
  import ts from 'typescript';
2
- import type { PrismManifest } from '../../plugin/plugin.types.js';
2
+ import type { ScannedComponent } from '../../plugin/plugin.types.js';
3
+ import { type EntryPointInput } from './entry-point.scanner.js';
3
4
  export interface CreateScannerOptions {
4
- entryPoint: string;
5
+ entryPoints: ReadonlyArray<EntryPointInput>;
5
6
  compilerOptions?: ts.CompilerOptions;
6
7
  }
8
+ export interface ScanResult {
9
+ components: ScannedComponent[];
10
+ }
7
11
  export interface Scanner {
8
- /** Scan the entry point. Reuses TypeScript program state from previous scans. */
9
- scan(): PrismManifest;
12
+ /** Scan all entry points. Reuses TypeScript program state from previous scans. */
13
+ scan(): ScanResult;
10
14
  }
11
15
  /**
12
- * Create a stateful scanner that retains the previous ts.Program between scans.
13
- * TypeScript reuses parsed SourceFile objects from the old program, making incremental scans fast.
16
+ * Create a stateful multi-entry scanner that retains the previous ts.Program between scans.
17
+ * A single shared program is created with every entry-point file as a root name, so the
18
+ * transitive type graph (Angular framework typings, etc.) is parsed once and shared via
19
+ * the program's `TypeChecker` — instead of N programs that each load Material/CDK/RxJS.
20
+ *
21
+ * TypeScript reuses parsed SourceFile objects from the old program on rebuild, making
22
+ * incremental scans fast.
14
23
  */
15
24
  export declare function createScanner(options: CreateScannerOptions): Scanner;
16
25
  //# sourceMappingURL=scanner.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"scanner.d.ts","sourceRoot":"","sources":["../../../src/builder/scanner/scanner.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,YAAY,CAAC;AAC5B,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAIlE,MAAM,WAAW,oBAAoB;IACnC,UAAU,EAAE,MAAM,CAAC;IACnB,eAAe,CAAC,EAAE,EAAE,CAAC,eAAe,CAAC;CACtC;AAED,MAAM,WAAW,OAAO;IACtB,iFAAiF;IACjF,IAAI,IAAI,aAAa,CAAC;CACvB;AAWD;;;GAGG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,oBAAoB,GAAG,OAAO,CAmBpE"}
1
+ {"version":3,"file":"scanner.d.ts","sourceRoot":"","sources":["../../../src/builder/scanner/scanner.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,YAAY,CAAC;AAC5B,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AACrE,OAAO,EAEL,KAAK,eAAe,EACrB,MAAM,0BAA0B,CAAC;AAGlC,MAAM,WAAW,oBAAoB;IACnC,WAAW,EAAE,aAAa,CAAC,eAAe,CAAC,CAAC;IAC5C,eAAe,CAAC,EAAE,EAAE,CAAC,eAAe,CAAC;CACtC;AAED,MAAM,WAAW,UAAU;IACzB,UAAU,EAAE,gBAAgB,EAAE,CAAC;CAChC;AAED,MAAM,WAAW,OAAO;IACtB,kFAAkF;IAClF,IAAI,IAAI,UAAU,CAAC;CACpB;AAkBD;;;;;;;;GAQG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,oBAAoB,GAAG,OAAO,CAoDpE"}
@@ -1,5 +1,5 @@
1
1
  import ts from 'typescript';
2
- import { resolveEntryPointExports } from './entry-point.scanner.js';
2
+ import { resolveEntryPointExports, } from './entry-point.scanner.js';
3
3
  import { scanComponents } from './component.scanner.js';
4
4
  const DEFAULT_COMPILER_OPTIONS = {
5
5
  target: ts.ScriptTarget.ES2022,
@@ -8,21 +8,58 @@ const DEFAULT_COMPILER_OPTIONS = {
8
8
  experimentalDecorators: true,
9
9
  strict: true,
10
10
  skipLibCheck: true,
11
+ // Perf: skip auto-loading every @types/* package; library source rarely needs ambient globals.
12
+ // Users with explicit needs can pass `types: ['node']` via tsconfig.json paths.
13
+ types: [],
14
+ // Perf: we never call program.emit(); skip emit-related setup work.
15
+ noEmit: true,
16
+ // Perf: complement to skipLibCheck — also skip type-checking lib.*.d.ts files.
17
+ skipDefaultLibCheck: true,
11
18
  };
12
19
  /**
13
- * Create a stateful scanner that retains the previous ts.Program between scans.
14
- * TypeScript reuses parsed SourceFile objects from the old program, making incremental scans fast.
20
+ * Create a stateful multi-entry scanner that retains the previous ts.Program between scans.
21
+ * A single shared program is created with every entry-point file as a root name, so the
22
+ * transitive type graph (Angular framework typings, etc.) is parsed once and shared via
23
+ * the program's `TypeChecker` — instead of N programs that each load Material/CDK/RxJS.
24
+ *
25
+ * TypeScript reuses parsed SourceFile objects from the old program on rebuild, making
26
+ * incremental scans fast.
15
27
  */
16
28
  export function createScanner(options) {
17
- const compilerOptions = { ...DEFAULT_COMPILER_OPTIONS, ...options.compilerOptions };
29
+ const compilerOptions = {
30
+ ...DEFAULT_COMPILER_OPTIONS,
31
+ ...options.compilerOptions,
32
+ };
18
33
  let previousProgram;
19
34
  return {
20
35
  scan() {
21
- const { program, exports } = resolveEntryPointExports(options.entryPoint, compilerOptions, previousProgram);
36
+ const { program, entries } = resolveEntryPointExports(options.entryPoints, compilerOptions, previousProgram);
22
37
  previousProgram = program;
23
38
  const checker = program.getTypeChecker();
24
- const components = scanComponents(exports, checker);
25
- return { components };
39
+ const allComponents = [];
40
+ for (const { exports, importPath } of entries) {
41
+ const components = scanComponents(exports, checker);
42
+ for (const c of components)
43
+ c.importPath = importPath;
44
+ allComponents.push(...components);
45
+ }
46
+ // Dedupe by (filePath, className): if a component class is re-exported from
47
+ // multiple entry points (e.g. atoms/button + barrel index.ts), we keep the first
48
+ // occurrence. The duplicate would otherwise produce duplicate imports in the
49
+ // generated manifest and a runtime collision in the Prism shell.
50
+ const seen = new Set();
51
+ const unique = [];
52
+ for (const c of allComponents) {
53
+ const key = `${c.filePath}::${c.className}`;
54
+ if (seen.has(key)) {
55
+ console.warn(`⚠ ng-prism: ${c.className} is exported by multiple entry points; ` +
56
+ `keeping the first occurrence (importPath: ${unique.find((u) => u.className === c.className && u.filePath === c.filePath)?.importPath}).`);
57
+ continue;
58
+ }
59
+ seen.add(key);
60
+ unique.push(c);
61
+ }
62
+ return { components: unique };
26
63
  },
27
64
  };
28
65
  }
@@ -14,7 +14,9 @@ export interface PrismPipelineResult {
14
14
  written: boolean;
15
15
  }
16
16
  export interface PrismPipelineState {
17
- scanners: Map<string, Scanner>;
17
+ scanner: Scanner | undefined;
18
+ /** Sorted, joined entry-file paths — used to detect when the entry set changed between rebuilds. */
19
+ lastEntrySetKey: string | undefined;
18
20
  }
19
21
  export declare function createPipelineState(): PrismPipelineState;
20
22
  export declare function runPrismPipeline(options: PrismPipelineOptions, context: BuilderContext, state: PrismPipelineState): Promise<PrismPipelineResult>;
@@ -1 +1 @@
1
- {"version":3,"file":"prism-pipeline.d.ts","sourceRoot":"","sources":["../../../src/builder/shared/prism-pipeline.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAMhE,OAAO,EAAiB,KAAK,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAMpE,MAAM,WAAW,oBAAoB;IACnC,UAAU,EAAE,MAAM,CAAC;IACnB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,mBAAmB;IAClC,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,mGAAmG;IACnG,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAChC;AAED,wBAAgB,mBAAmB,IAAI,kBAAkB,CAExD;AAED,wBAAsB,gBAAgB,CACpC,OAAO,EAAE,oBAAoB,EAC7B,OAAO,EAAE,cAAc,EACvB,KAAK,EAAE,kBAAkB,GACxB,OAAO,CAAC,mBAAmB,CAAC,CAoD9B"}
1
+ {"version":3,"file":"prism-pipeline.d.ts","sourceRoot":"","sources":["../../../src/builder/shared/prism-pipeline.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAGhE,OAAO,EAAiB,KAAK,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAOpE,MAAM,WAAW,oBAAoB;IACnC,UAAU,EAAE,MAAM,CAAC;IACnB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,mBAAmB;IAClC,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,mGAAmG;IACnG,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,OAAO,GAAG,SAAS,CAAC;IAC7B,oGAAoG;IACpG,eAAe,EAAE,MAAM,GAAG,SAAS,CAAC;CACrC;AAED,wBAAgB,mBAAmB,IAAI,kBAAkB,CAExD;AAED,wBAAsB,gBAAgB,CACpC,OAAO,EAAE,oBAAoB,EAC7B,OAAO,EAAE,cAAc,EACvB,KAAK,EAAE,kBAAkB,GACxB,OAAO,CAAC,mBAAmB,CAAC,CAoD9B"}
@@ -7,7 +7,7 @@ import { loadConfig } from '../config-loader/config-loader.js';
7
7
  import { runPluginHooks } from '../plugin-runner/plugin-runner.js';
8
8
  import { generateRuntimeManifest } from '../manifest/runtime-manifest.generator.js';
9
9
  export function createPipelineState() {
10
- return { scanners: new Map() };
10
+ return { scanner: undefined, lastEntrySetKey: undefined };
11
11
  }
12
12
  export async function runPrismPipeline(options, context, state) {
13
13
  const { workspaceRoot } = context;
@@ -106,36 +106,41 @@ function resolveTsconfigPaths(entryPointDir) {
106
106
  result.baseUrl = parsed.options.baseUrl;
107
107
  return result;
108
108
  }
109
- function scanEntryPoints(workspaceRoot, options, state) {
109
+ function resolveEntryPoints(workspaceRoot, options) {
110
110
  const absoluteEntryPoint = join(workspaceRoot, options.entryPoint);
111
- const pathOptions = resolveTsconfigPaths(dirname(absoluteEntryPoint));
111
+ const compilerOptions = resolveTsconfigPaths(dirname(absoluteEntryPoint));
112
112
  const entryIsDirectory = isDirectory(absoluteEntryPoint);
113
113
  const libraryRoot = entryIsDirectory
114
114
  ? absoluteEntryPoint
115
115
  : findLibraryRoot(absoluteEntryPoint);
116
- if (!libraryRoot) {
117
- return getOrCreateScanner(state, absoluteEntryPoint, pathOptions).scan();
118
- }
119
- const entryPoints = discoverSecondaryEntryPoints(libraryRoot, options.libraryImportPath);
120
- if (entryPoints.length === 0 && !entryIsDirectory) {
121
- return getOrCreateScanner(state, absoluteEntryPoint, pathOptions).scan();
122
- }
123
- const allComponents = [];
124
- for (const ep of entryPoints) {
125
- const scanner = getOrCreateScanner(state, ep.entryFile, pathOptions);
126
- const result = scanner.scan();
127
- for (const comp of result.components) {
128
- comp.importPath = ep.importPath;
129
- allComponents.push(comp);
130
- }
131
- }
132
- return { components: allComponents };
116
+ const discovered = libraryRoot
117
+ ? discoverSecondaryEntryPoints(libraryRoot, options.libraryImportPath)
118
+ : [];
119
+ // Fallback to a direct file scan when:
120
+ // - the entry is a file and no ng-package.json was found above it, OR
121
+ // - the entry is a file with an ng-package.json above it but discovery found nothing
122
+ // (e.g. primary-only library, root ng-package.json carries `dest`).
123
+ const entryPoints = discovered.length === 0 && !entryIsDirectory
124
+ ? [
125
+ {
126
+ entryFile: absoluteEntryPoint,
127
+ importPath: options.libraryImportPath,
128
+ },
129
+ ]
130
+ : discovered;
131
+ return { entryPoints, compilerOptions };
133
132
  }
134
- function getOrCreateScanner(state, entryFile, compilerOptions) {
135
- let scanner = state.scanners.get(entryFile);
136
- if (!scanner) {
137
- scanner = createScanner({ entryPoint: entryFile, compilerOptions });
138
- state.scanners.set(entryFile, scanner);
133
+ function scanEntryPoints(workspaceRoot, options, state) {
134
+ const { entryPoints, compilerOptions } = resolveEntryPoints(workspaceRoot, options);
135
+ const newKey = entryPoints
136
+ .map((e) => e.entryFile)
137
+ .slice()
138
+ .sort()
139
+ .join('|');
140
+ if (newKey !== state.lastEntrySetKey) {
141
+ state.scanner = undefined;
142
+ state.lastEntrySetKey = newKey;
139
143
  }
140
- return scanner;
144
+ state.scanner ??= createScanner({ entryPoints, compilerOptions });
145
+ return state.scanner.scan();
141
146
  }
@@ -1,3 +1,3 @@
1
- export type { ShowcaseConfig, Variant } from './showcase.types.js';
1
+ export type { ShowcaseConfig, Variant, ComponentStatus } from './showcase.types.js';
2
2
  export { Showcase } from './showcase.decorator.js';
3
3
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/decorator/index.ts"],"names":[],"mappings":"AACA,YAAY,EAAE,cAAc,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AACnE,OAAO,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/decorator/index.ts"],"names":[],"mappings":"AACA,YAAY,EAAE,cAAc,EAAE,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AACpF,OAAO,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC"}
@@ -1,5 +1,6 @@
1
1
  import type { Provider } from '@angular/core';
2
2
  import type { CanvasBg } from '../shared/canvas-bg.type.js';
3
+ export type ComponentStatus = 'stable' | 'beta' | 'wip' | 'deprecated';
3
4
  export interface DirectiveHost {
4
5
  selector: string;
5
6
  import: {
@@ -42,6 +43,13 @@ export interface ShowcaseConfig {
42
43
  host?: string | DirectiveHost;
43
44
  /** Title of a registered ComponentPage to render instead of the component itself. Use for complex components that need template projections or mock data. The page component can inject PrismRendererService to react to control panel changes. */
44
45
  renderPage?: string;
46
+ /**
47
+ * Migration / maturity status. When unset, the component is treated as `stable`
48
+ * but rendered without any indicator in the sidebar or header. Only set it
49
+ * when you want to draw attention (in-progress or deprecated work) or to
50
+ * explicitly badge a `stable` / `beta` component.
51
+ */
52
+ status?: ComponentStatus;
45
53
  }
46
54
  export interface Variant {
47
55
  /** Tab label */
@@ -1 +1 @@
1
- {"version":3,"file":"showcase.types.d.ts","sourceRoot":"","sources":["../../src/decorator/showcase.types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,6BAA6B,CAAC;AAE5D,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IACvC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAClC;AAED,MAAM,WAAW,cAAc;IAC7B,sCAAsC;IACtC,KAAK,EAAE,MAAM,CAAC;IACd,4CAA4C;IAC5C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,0CAA0C;IAC1C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,2IAA2I;IAC3I,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,iJAAiJ;IACjJ,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,wCAAwC;IACxC,QAAQ,CAAC,EAAE,OAAO,EAAE,CAAC;IACrB,oCAAoC;IACpC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB;;;;OAIG;IACH,SAAS,CAAC,EAAE,QAAQ,EAAE,CAAC;IACvB,qEAAqE;IACrE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B;;;;;OAKG;IACH,EAAE,CAAC,EAAE,QAAQ,CAAC;IACd,6HAA6H;IAC7H,IAAI,CAAC,EAAE,MAAM,GAAG,aAAa,CAAC;IAC9B,mPAAmP;IACnP,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,OAAO;IACtB,gBAAgB;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,uCAAuC;IACvC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC1C,4CAA4C;IAC5C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,mFAAmF;IACnF,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,qFAAqF;IACrF,EAAE,CAAC,EAAE,QAAQ,CAAC;CACf"}
1
+ {"version":3,"file":"showcase.types.d.ts","sourceRoot":"","sources":["../../src/decorator/showcase.types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,6BAA6B,CAAC;AAE5D,MAAM,MAAM,eAAe,GAAG,QAAQ,GAAG,MAAM,GAAG,KAAK,GAAG,YAAY,CAAC;AAEvE,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IACvC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAClC;AAED,MAAM,WAAW,cAAc;IAC7B,sCAAsC;IACtC,KAAK,EAAE,MAAM,CAAC;IACd,4CAA4C;IAC5C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,0CAA0C;IAC1C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,2IAA2I;IAC3I,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,iJAAiJ;IACjJ,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,wCAAwC;IACxC,QAAQ,CAAC,EAAE,OAAO,EAAE,CAAC;IACrB,oCAAoC;IACpC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB;;;;OAIG;IACH,SAAS,CAAC,EAAE,QAAQ,EAAE,CAAC;IACvB,qEAAqE;IACrE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B;;;;;OAKG;IACH,EAAE,CAAC,EAAE,QAAQ,CAAC;IACd,6HAA6H;IAC7H,IAAI,CAAC,EAAE,MAAM,GAAG,aAAa,CAAC;IAC9B,mPAAmP;IACnP,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;;;OAKG;IACH,MAAM,CAAC,EAAE,eAAe,CAAC;CAC1B;AAED,MAAM,WAAW,OAAO;IACtB,gBAAgB;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,uCAAuC;IACvC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC1C,4CAA4C;IAC5C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,mFAAmF;IACnF,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,qFAAqF;IACrF,EAAE,CAAC,EAAE,QAAQ,CAAC;CACf"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ng-prism/core",
3
- "version": "21.10.2",
3
+ "version": "21.11.0",
4
4
  "description": "ng-prism — the Angular-native Storybook alternative. Lightweight component showcase with @Showcase decorator, no story files needed.",
5
5
  "keywords": [
6
6
  "ng-prism",