@ng-prism/core 22.3.0 → 22.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -12
- package/dist/app/canvas/canvas-bg.styles.d.ts +7 -12
- package/dist/app/canvas/canvas-bg.styles.d.ts.map +1 -1
- package/dist/app/canvas/canvas-bg.styles.js +35 -37
- package/dist/app/canvas/measure-geometry.d.ts +140 -0
- package/dist/app/canvas/measure-geometry.d.ts.map +1 -0
- package/dist/app/canvas/measure-geometry.js +217 -0
- package/dist/app/canvas/measure-keyboard.d.ts +20 -0
- package/dist/app/canvas/measure-keyboard.d.ts.map +1 -0
- package/dist/app/canvas/measure-keyboard.js +34 -0
- package/dist/app/canvas/measure-quad.d.ts +114 -0
- package/dist/app/canvas/measure-quad.d.ts.map +1 -0
- package/dist/app/canvas/measure-quad.js +173 -0
- package/dist/app/canvas/measure-snap.d.ts +35 -0
- package/dist/app/canvas/measure-snap.d.ts.map +1 -0
- package/dist/app/canvas/measure-snap.js +63 -0
- package/dist/app/canvas/prism-canvas-measure.component.d.ts +142 -0
- package/dist/app/canvas/prism-canvas-measure.component.d.ts.map +1 -0
- package/dist/app/canvas/prism-canvas-measure.component.js +554 -0
- package/dist/app/canvas/prism-canvas-pin-row.component.d.ts +23 -0
- package/dist/app/canvas/prism-canvas-pin-row.component.d.ts.map +1 -0
- package/dist/app/canvas/prism-canvas-pin-row.component.js +64 -0
- package/dist/app/canvas/prism-canvas-toolbar.component.d.ts +22 -39
- package/dist/app/canvas/prism-canvas-toolbar.component.d.ts.map +1 -1
- package/dist/app/canvas/prism-canvas-toolbar.component.js +61 -69
- package/dist/app/canvas/prism-template-popover.component.js +1 -1
- package/dist/app/canvas/viewport-snap.d.ts +1 -1
- package/dist/app/canvas/viewport-snap.js +1 -1
- package/dist/app/component-head/head-metrics.d.ts +2 -2
- package/dist/app/component-head/head-metrics.js +1 -1
- package/dist/app/component-head/prism-component-head.component.d.ts +2 -2
- package/dist/app/component-head/prism-component-head.component.d.ts.map +1 -1
- package/dist/app/component-head/prism-component-head.component.js +11 -18
- package/dist/app/component-head/prism-head-gauge.component.js +1 -1
- package/dist/app/component-head/prism-head-info.component.d.ts +1 -1
- package/dist/app/component-head/prism-head-info.component.js +2 -2
- package/dist/app/component-head/prism-stat.component.d.ts +1 -1
- package/dist/app/component-head/prism-stat.component.js +2 -2
- package/dist/app/directives/prism-resizer.directive.d.ts +1 -1
- package/dist/app/directives/prism-resizer.directive.js +2 -2
- package/dist/app/directives/resize-value.d.ts +2 -2
- package/dist/app/directives/resize-value.js +2 -2
- package/dist/app/discovery-manifest.d.ts +2 -2
- package/dist/app/discovery-manifest.d.ts.map +1 -1
- package/dist/app/discovery-manifest.js +11 -15
- package/dist/app/header/prism-header.component.js +1 -1
- package/dist/app/icons/icon-registry.d.ts +2 -2
- package/dist/app/icons/icon-registry.d.ts.map +1 -1
- package/dist/app/icons/icon-registry.js +3 -2
- package/dist/app/icons/prism-icon.component.d.ts +2 -2
- package/dist/app/icons/prism-icon.component.js +4 -4
- package/dist/app/index.d.ts.map +1 -1
- package/dist/app/index.js +14 -21
- package/dist/app/overview/overview-visibility.d.ts +1 -1
- package/dist/app/overview/overview-visibility.js +1 -1
- package/dist/app/overview/prism-overview-cell.component.d.ts +2 -2
- package/dist/app/overview/prism-overview-cell.component.d.ts.map +1 -1
- package/dist/app/overview/prism-overview-cell.component.js +9 -10
- package/dist/app/overview/prism-overview.component.d.ts +2 -2
- package/dist/app/overview/prism-overview.component.js +2 -2
- package/dist/app/page-renderer/prism-page-renderer.component.js +1 -1
- package/dist/app/panels/a11y/a11y-audit.service.js +2 -2
- package/dist/app/panels/a11y/a11y-summary.d.ts +3 -4
- package/dist/app/panels/a11y/a11y-summary.d.ts.map +1 -1
- package/dist/app/panels/a11y/a11y-summary.js +3 -4
- package/dist/app/panels/a11y/a11y-thresholds.d.ts +1 -1
- package/dist/app/panels/a11y/a11y-thresholds.d.ts.map +1 -1
- package/dist/app/panels/a11y/a11y-thresholds.js +1 -1
- package/dist/app/panels/a11y/a11y.types.d.ts +1 -1
- package/dist/app/panels/a11y/a11y.types.d.ts.map +1 -1
- package/dist/app/panels/builtin-navigation-decorations.d.ts +1 -1
- package/dist/app/panels/builtin-navigation-decorations.js +1 -1
- package/dist/app/panels/controls/non-editable-input-types.js +1 -1
- package/dist/app/panels/panel-host/panel-badge.d.ts +1 -1
- package/dist/app/provide-prism.js +1 -1
- package/dist/app/renderer/known-inputs.d.ts +1 -1
- package/dist/app/renderer/known-inputs.js +1 -1
- package/dist/app/renderer/overlay-resolver.d.ts +17 -3
- package/dist/app/renderer/overlay-resolver.d.ts.map +1 -1
- package/dist/app/renderer/overlay-resolver.js +9 -4
- package/dist/app/renderer/prism-renderer.component.d.ts +3 -3
- package/dist/app/renderer/prism-renderer.component.d.ts.map +1 -1
- package/dist/app/renderer/prism-renderer.component.js +25 -16
- package/dist/app/renderer/projectable-content.js +3 -3
- package/dist/app/services/prism-canvas.service.d.ts +12 -1
- package/dist/app/services/prism-canvas.service.d.ts.map +1 -1
- package/dist/app/services/prism-canvas.service.js +23 -5
- package/dist/app/services/prism-capture.service.d.ts +24 -50
- package/dist/app/services/prism-capture.service.d.ts.map +1 -1
- package/dist/app/services/prism-capture.service.js +60 -140
- package/dist/app/services/prism-measure.service.d.ts +44 -0
- package/dist/app/services/prism-measure.service.d.ts.map +1 -0
- package/dist/app/services/prism-measure.service.js +91 -0
- package/dist/app/services/prism-panel.service.d.ts +2 -2
- package/dist/app/services/prism-panel.service.js +2 -2
- package/dist/app/services/prism-persistence.service.js +1 -1
- package/dist/app/services/prism-renderer.service.js +1 -1
- package/dist/app/services/prism-url-state.service.js +1 -1
- package/dist/app/services/prism-variant-bg.service.d.ts +10 -24
- package/dist/app/services/prism-variant-bg.service.d.ts.map +1 -1
- package/dist/app/services/prism-variant-bg.service.js +10 -24
- package/dist/app/shared/prism-metric-badge.component.d.ts +9 -15
- package/dist/app/shared/prism-metric-badge.component.d.ts.map +1 -1
- package/dist/app/shared/prism-metric-badge.component.js +10 -16
- package/dist/app/shell/prism-shell.component.d.ts.map +1 -1
- package/dist/app/shell/prism-shell.component.js +11 -8
- package/dist/app/sidebar/navigation-decorations.d.ts +4 -4
- package/dist/app/sidebar/navigation-decorations.js +2 -2
- package/dist/app/sidebar/prism-sidebar.component.d.ts +2 -2
- package/dist/app/sidebar/prism-sidebar.component.js +3 -3
- package/dist/app/theme/prism-default-theme.js +3 -3
- package/dist/app/variant-ribbon/spectrum.d.ts +1 -1
- package/dist/app/variant-ribbon/spectrum.js +1 -1
- package/dist/app/view-tab-bar/next-view-id.d.ts +1 -1
- package/dist/app/view-tab-bar/next-view-id.js +1 -1
- package/dist/builder/a11y/a11y-report-reader.d.ts +1 -1
- package/dist/builder/a11y/a11y-report-reader.js +1 -1
- package/dist/builder/manifest/runtime-manifest.generator.js +6 -2
- package/dist/builder/plugin-runner/plugin-runner.js +1 -1
- package/dist/builder/scanner/ast-utils.d.ts +46 -2
- package/dist/builder/scanner/ast-utils.d.ts.map +1 -1
- package/dist/builder/scanner/ast-utils.js +337 -31
- package/dist/builder/scanner/class-hierarchy.d.ts +33 -0
- package/dist/builder/scanner/class-hierarchy.d.ts.map +1 -0
- package/dist/builder/scanner/class-hierarchy.js +87 -0
- package/dist/builder/scanner/component.scanner.d.ts +7 -1
- package/dist/builder/scanner/component.scanner.d.ts.map +1 -1
- package/dist/builder/scanner/component.scanner.js +106 -58
- package/dist/builder/scanner/input.extractor.d.ts +7 -4
- package/dist/builder/scanner/input.extractor.d.ts.map +1 -1
- package/dist/builder/scanner/input.extractor.js +153 -55
- package/dist/builder/scanner/manifest.generator.js +6 -2
- package/dist/builder/scanner/scanner.d.ts +3 -1
- package/dist/builder/scanner/scanner.d.ts.map +1 -1
- package/dist/builder/scanner/scanner.js +6 -4
- package/dist/builder/scanner/showcase-diagnostics.d.ts +25 -0
- package/dist/builder/scanner/showcase-diagnostics.d.ts.map +1 -0
- package/dist/builder/scanner/showcase-diagnostics.js +96 -0
- package/dist/builder/shared/prism-pipeline.d.ts +1 -1
- package/dist/builder/shared/prism-pipeline.d.ts.map +1 -1
- package/dist/builder/shared/prism-pipeline.js +12 -14
- package/dist/builder/watcher/prism-watcher.js +2 -2
- package/dist/decorator/showcase.types.d.ts +11 -9
- package/dist/decorator/showcase.types.d.ts.map +1 -1
- package/dist/index.js +3 -3
- package/dist/plugin/define-config.js +1 -1
- package/dist/plugin/index.d.ts.map +1 -1
- package/dist/plugin/index.js +5 -9
- package/dist/plugin/plugin.types.d.ts +30 -13
- package/dist/plugin/plugin.types.d.ts.map +1 -1
- package/dist/schematics/migrations/v22-0-cache-dir-rename/index.js +2 -2
- package/dist/schematics/ng-add/index.js +4 -4
- package/dist/shared/canvas-bg.type.d.ts +5 -6
- package/dist/shared/canvas-bg.type.d.ts.map +1 -1
- package/dist/shared/canvas-bg.type.js +4 -5
- package/dist/shared/measure.type.d.ts +52 -0
- package/dist/shared/measure.type.d.ts.map +1 -0
- package/dist/shared/measure.type.js +21 -0
- package/dist/shared/variant-bg.d.ts +20 -31
- package/dist/shared/variant-bg.d.ts.map +1 -1
- package/dist/shared/variant-bg.js +20 -31
- package/dist/shared/viewport.type.d.ts +15 -19
- package/dist/shared/viewport.type.d.ts.map +1 -1
- package/dist/shared/viewport.type.js +15 -19
- package/dist/transformer/showcase-strip.transformer.js +1 -1
- package/package.json +2 -2
|
@@ -1,8 +1,10 @@
|
|
|
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, findDecorator, getDecoratorArgument } from './ast-utils.js';
|
|
4
|
+
import { evaluateExpression, evaluateStatic, findDecorator, getDecoratorArgument, UNEVALUABLE } from './ast-utils.js';
|
|
5
|
+
import { getClassHierarchy } from './class-hierarchy.js';
|
|
5
6
|
import { extractInputs, extractOutputs } from './input.extractor.js';
|
|
7
|
+
import { describeDeprecatedProviders, describeUnevaluable, describeUnreadableBase } from './showcase-diagnostics.js';
|
|
6
8
|
const COMPONENT_STATUSES = ['stable', 'beta', 'wip', 'deprecated'];
|
|
7
9
|
function isComponentStatus(value) {
|
|
8
10
|
return typeof value === 'string' && COMPONENT_STATUSES.includes(value);
|
|
@@ -11,14 +13,14 @@ function isComponentStatus(value) {
|
|
|
11
13
|
* Backgrounds that still work but should not be reached for any more.
|
|
12
14
|
*
|
|
13
15
|
* `checker` draws the same checkerboard as `transparent` while browsing, so
|
|
14
|
-
* the canvas cannot tell them apart
|
|
16
|
+
* the canvas cannot tell them apart. It captures as `--prism-bg-surface`, though,
|
|
15
17
|
* a *theme* token, which makes a baseline recorded on it depend on the theme
|
|
16
18
|
* the runner's browser started in. Since `transparent` took over as the
|
|
17
19
|
* default, it is the value that looks like transparency and is not.
|
|
18
20
|
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
21
|
+
* Only warned about: the value is valid, and rejecting it would change what a
|
|
22
|
+
* component renders on, which is a breaking change. Scheduled for removal in
|
|
23
|
+
* 23.0.0, the next Angular-aligned major.
|
|
22
24
|
*/
|
|
23
25
|
const DEPRECATED_BGS = {
|
|
24
26
|
checker: "use 'transparent' for the same look with a capture that keeps its alpha, or 'light'/'dark' for an absolute colour"
|
|
@@ -27,7 +29,7 @@ function warnDeprecatedBg(bg, where) {
|
|
|
27
29
|
const advice = DEPRECATED_BGS[bg];
|
|
28
30
|
if (!advice)
|
|
29
31
|
return;
|
|
30
|
-
console.warn(`⚠ ng-prism: ${where} declares bg "${bg}", which is deprecated and will ` + `be removed in 23.0.0
|
|
32
|
+
console.warn(`⚠ ng-prism: ${where} declares bg "${bg}", which is deprecated and will ` + `be removed in 23.0.0; ${advice}.`);
|
|
31
33
|
}
|
|
32
34
|
function isCanvasBg(value) {
|
|
33
35
|
return typeof value === 'string' && CANVAS_BGS.includes(value);
|
|
@@ -37,15 +39,33 @@ function isCanvasLayout(value) {
|
|
|
37
39
|
}
|
|
38
40
|
/**
|
|
39
41
|
* Scan exported symbols for Angular components annotated with @Showcase.
|
|
42
|
+
*
|
|
43
|
+
* Every @Showcase value the scan has to drop is printed and collected in
|
|
44
|
+
* `diagnostics`, once: sharing the array across entry points keeps a
|
|
45
|
+
* component exported from several of them from repeating its warnings.
|
|
46
|
+
* `notices` does the same for warnings about what a component inherits,
|
|
47
|
+
* which are not diagnostics.
|
|
40
48
|
*/
|
|
41
|
-
export function scanComponents(exports, checker) {
|
|
49
|
+
export function scanComponents(exports, checker, diagnostics = [], notices = new Set()) {
|
|
42
50
|
const components = [];
|
|
51
|
+
const report = (message) => {
|
|
52
|
+
if (diagnostics.includes(message))
|
|
53
|
+
return;
|
|
54
|
+
diagnostics.push(message);
|
|
55
|
+
console.warn(`⚠ ng-prism: ${message}`);
|
|
56
|
+
};
|
|
57
|
+
const notify = (message) => {
|
|
58
|
+
if (notices.has(message))
|
|
59
|
+
return;
|
|
60
|
+
notices.add(message);
|
|
61
|
+
console.warn(`⚠ ng-prism: ${message}`);
|
|
62
|
+
};
|
|
43
63
|
for (const sym of exports) {
|
|
44
64
|
const resolved = sym.flags & ts.SymbolFlags.Alias ? checker.getAliasedSymbol(sym) : sym;
|
|
45
65
|
const classDecl = resolved.declarations?.find(ts.isClassDeclaration);
|
|
46
66
|
if (!classDecl)
|
|
47
67
|
continue;
|
|
48
|
-
// Perf: cheap pre-filter
|
|
68
|
+
// Perf: cheap pre-filter that skips the full decorator walk for files that don't
|
|
49
69
|
// mention Showcase at all. False positives (string-literal containing "@Showcase")
|
|
50
70
|
// just lose the optimization for that file; correctness is unaffected.
|
|
51
71
|
if (!classDecl.getSourceFile().text.includes('@Showcase'))
|
|
@@ -54,15 +74,23 @@ export function scanComponents(exports, checker) {
|
|
|
54
74
|
if (!showcaseDecorator)
|
|
55
75
|
continue;
|
|
56
76
|
const className = classDecl.name?.text ?? 'Anonymous';
|
|
57
|
-
const showcaseConfig = extractShowcaseConfig(showcaseDecorator, className);
|
|
77
|
+
const showcaseConfig = extractShowcaseConfig(showcaseDecorator, className, report, checker);
|
|
58
78
|
if (!showcaseConfig)
|
|
59
79
|
continue;
|
|
60
|
-
const componentMeta = extractComponentMeta(classDecl);
|
|
61
|
-
const
|
|
62
|
-
const
|
|
80
|
+
const componentMeta = extractComponentMeta(classDecl, checker);
|
|
81
|
+
const hierarchy = getClassHierarchy(classDecl, checker);
|
|
82
|
+
const inputs = extractInputs(classDecl, checker, hierarchy);
|
|
83
|
+
const outputs = extractOutputs(classDecl, checker, hierarchy);
|
|
63
84
|
const filePath = classDecl.getSourceFile().fileName;
|
|
64
|
-
|
|
65
|
-
|
|
85
|
+
const decoratorInputs = hierarchy.classes.find((c) => c.definesMetadata && hasDecoratorInputs(c.classDecl))?.classDecl;
|
|
86
|
+
if (decoratorInputs) {
|
|
87
|
+
const where = decoratorInputs === classDecl ? 'uses @Input() decorators' : `inherits @Input() decorators from ${decoratorInputs.name?.text ?? 'an anonymous class'},`;
|
|
88
|
+
notify(`${className} ${where} which are not fully supported. Migrate to input() signals for full ng-prism support.`);
|
|
89
|
+
}
|
|
90
|
+
// Not diagnostics: strictShowcase would fail the build over a base
|
|
91
|
+
// class in a package, which the component's author cannot change.
|
|
92
|
+
for (const base of hierarchy.unreadable) {
|
|
93
|
+
notify(describeUnreadableBase(className, base));
|
|
66
94
|
}
|
|
67
95
|
components.push({
|
|
68
96
|
className,
|
|
@@ -70,7 +98,11 @@ export function scanComponents(exports, checker) {
|
|
|
70
98
|
showcaseConfig,
|
|
71
99
|
inputs,
|
|
72
100
|
outputs,
|
|
73
|
-
componentMeta
|
|
101
|
+
componentMeta,
|
|
102
|
+
// Plugins look a base class up by name, so an anonymous one is of no use to them.
|
|
103
|
+
baseClasses: hierarchy.classes
|
|
104
|
+
.slice(1)
|
|
105
|
+
.flatMap(({ classDecl: base }) => (base.name ? [{ className: base.name.text, filePath: base.getSourceFile().fileName }] : []))
|
|
74
106
|
});
|
|
75
107
|
}
|
|
76
108
|
return components;
|
|
@@ -84,15 +116,29 @@ function hasDecoratorInputs(classDecl) {
|
|
|
84
116
|
}
|
|
85
117
|
return false;
|
|
86
118
|
}
|
|
87
|
-
function extractShowcaseConfig(decorator, className) {
|
|
119
|
+
function extractShowcaseConfig(decorator, className, report, checker) {
|
|
88
120
|
const arg = getDecoratorArgument(decorator);
|
|
89
121
|
if (!arg)
|
|
90
122
|
return undefined;
|
|
91
|
-
|
|
92
|
-
|
|
123
|
+
// Reported once for the whole field below, wherever it came from: the literal, a spread or a constant.
|
|
124
|
+
let providers;
|
|
125
|
+
const raw = evaluateStatic(arg, {
|
|
126
|
+
checker,
|
|
127
|
+
report: (issue) => {
|
|
128
|
+
if (issue.path[0] === 'providers') {
|
|
129
|
+
providers ??= issue.node;
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
report(describeUnevaluable(className, arg, issue));
|
|
133
|
+
}
|
|
134
|
+
});
|
|
135
|
+
if (providers || (typeof raw === 'object' && raw !== null && 'providers' in raw)) {
|
|
136
|
+
report(describeDeprecatedProviders(className, arg, providers));
|
|
137
|
+
}
|
|
138
|
+
if (raw === UNEVALUABLE || !raw || typeof raw !== 'object')
|
|
93
139
|
return undefined;
|
|
94
140
|
if (!('title' in raw)) {
|
|
95
|
-
|
|
141
|
+
report(`${className} has @Showcase without a "title" field, skipping. ` + `Add a title so it can appear in the styleguide.`);
|
|
96
142
|
return undefined;
|
|
97
143
|
}
|
|
98
144
|
const obj = raw;
|
|
@@ -108,6 +154,12 @@ function extractShowcaseConfig(decorator, className) {
|
|
|
108
154
|
if (typeof obj['sectionOrder'] === 'number') {
|
|
109
155
|
config.sectionOrder = obj['sectionOrder'];
|
|
110
156
|
}
|
|
157
|
+
if (typeof obj['categoryOrder'] === 'number') {
|
|
158
|
+
config.categoryOrder = obj['categoryOrder'];
|
|
159
|
+
}
|
|
160
|
+
if (typeof obj['componentOrder'] === 'number') {
|
|
161
|
+
config.componentOrder = obj['componentOrder'];
|
|
162
|
+
}
|
|
111
163
|
if (obj['tags'])
|
|
112
164
|
config.tags = obj['tags'];
|
|
113
165
|
if (obj['meta'])
|
|
@@ -121,7 +173,7 @@ function extractShowcaseConfig(decorator, className) {
|
|
|
121
173
|
config.status = obj['status'];
|
|
122
174
|
}
|
|
123
175
|
else {
|
|
124
|
-
|
|
176
|
+
report(`${className} declares invalid status "${String(obj['status'])}", ` + `expected one of: ${COMPONENT_STATUSES.join(', ')}. Skipping.`);
|
|
125
177
|
}
|
|
126
178
|
}
|
|
127
179
|
if (obj['bg'] !== undefined) {
|
|
@@ -130,7 +182,7 @@ function extractShowcaseConfig(decorator, className) {
|
|
|
130
182
|
warnDeprecatedBg(obj['bg'], className);
|
|
131
183
|
}
|
|
132
184
|
else {
|
|
133
|
-
|
|
185
|
+
report(`${className} declares invalid bg "${String(obj['bg'])}", ` + `expected one of: ${CANVAS_BGS.join(', ')}. Skipping.`);
|
|
134
186
|
}
|
|
135
187
|
}
|
|
136
188
|
if (obj['canvasLayout'] !== undefined) {
|
|
@@ -138,7 +190,7 @@ function extractShowcaseConfig(decorator, className) {
|
|
|
138
190
|
config.canvasLayout = obj['canvasLayout'];
|
|
139
191
|
}
|
|
140
192
|
else {
|
|
141
|
-
|
|
193
|
+
report(`${className} declares invalid canvasLayout "${String(obj['canvasLayout'])}", ` + `expected one of: ${CANVAS_LAYOUTS.join(', ')}. Skipping.`);
|
|
142
194
|
}
|
|
143
195
|
}
|
|
144
196
|
if (Array.isArray(obj['variants'])) {
|
|
@@ -148,14 +200,14 @@ function extractShowcaseConfig(decorator, className) {
|
|
|
148
200
|
warnDeprecatedBg(variant['bg'], `${className} variant "${String(variant['name'])}"`);
|
|
149
201
|
}
|
|
150
202
|
if (variant['bg'] !== undefined && !isCanvasBg(variant['bg'])) {
|
|
151
|
-
|
|
152
|
-
`invalid bg "${String(variant['bg'])}"
|
|
203
|
+
report(`${className} variant "${String(variant['name'])}" declares ` +
|
|
204
|
+
`invalid bg "${String(variant['bg'])}", expected one of: ` +
|
|
153
205
|
`${CANVAS_BGS.join(', ')}. Skipping.`);
|
|
154
206
|
delete cleaned['bg'];
|
|
155
207
|
}
|
|
156
208
|
if (variant['canvasLayout'] !== undefined && !isCanvasLayout(variant['canvasLayout'])) {
|
|
157
|
-
|
|
158
|
-
`invalid canvasLayout "${String(variant['canvasLayout'])}"
|
|
209
|
+
report(`${className} variant "${String(variant['name'])}" declares ` +
|
|
210
|
+
`invalid canvasLayout "${String(variant['canvasLayout'])}", expected one of: ${CANVAS_LAYOUTS.join(', ')}. Skipping.`);
|
|
159
211
|
delete cleaned['canvasLayout'];
|
|
160
212
|
}
|
|
161
213
|
return cleaned;
|
|
@@ -163,38 +215,34 @@ function extractShowcaseConfig(decorator, className) {
|
|
|
163
215
|
}
|
|
164
216
|
return config;
|
|
165
217
|
}
|
|
166
|
-
function extractComponentMeta(classDecl) {
|
|
218
|
+
function extractComponentMeta(classDecl, checker) {
|
|
167
219
|
const componentDecorator = findDecorator(classDecl, 'Component');
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
const
|
|
189
|
-
if (!
|
|
190
|
-
return
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
return {
|
|
194
|
-
selector: obj['selector'] ?? '',
|
|
195
|
-
standalone: obj['standalone'] !== false,
|
|
196
|
-
isDirective: true
|
|
197
|
-
};
|
|
220
|
+
const decorator = componentDecorator ?? findDecorator(classDecl, 'Directive');
|
|
221
|
+
const isDirective = !componentDecorator && decorator !== undefined;
|
|
222
|
+
const arg = decorator && getDecoratorArgument(decorator);
|
|
223
|
+
if (!arg)
|
|
224
|
+
return { selector: '', standalone: true, isDirective };
|
|
225
|
+
const selector = readDecoratorField(arg, 'selector', checker);
|
|
226
|
+
return {
|
|
227
|
+
selector: typeof selector === 'string' ? selector : '',
|
|
228
|
+
standalone: readDecoratorField(arg, 'standalone', checker) !== false,
|
|
229
|
+
isDirective
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* One field of `@Component`/`@Directive` metadata, read from its own
|
|
234
|
+
* property where the literal has one, so that `imports`, `providers` and the
|
|
235
|
+
* rest are not resolved only to be thrown away. A spread or a shorthand could
|
|
236
|
+
* supply the field from elsewhere, so then the whole argument is evaluated.
|
|
237
|
+
*/
|
|
238
|
+
function readDecoratorField(arg, key, checker) {
|
|
239
|
+
if (ts.isObjectLiteralExpression(arg) && !arg.properties.some(ts.isSpreadAssignment)) {
|
|
240
|
+
const prop = arg.properties.find((p) => p.name !== undefined && (ts.isIdentifier(p.name) || ts.isStringLiteral(p.name)) && p.name.text === key);
|
|
241
|
+
if (!prop)
|
|
242
|
+
return undefined;
|
|
243
|
+
if (ts.isPropertyAssignment(prop))
|
|
244
|
+
return evaluateExpression(prop.initializer, checker);
|
|
198
245
|
}
|
|
199
|
-
|
|
246
|
+
const raw = evaluateExpression(arg, checker);
|
|
247
|
+
return typeof raw === 'object' && raw !== null ? raw[key] : undefined;
|
|
200
248
|
}
|
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
import ts from 'typescript';
|
|
2
2
|
import type { InputMeta, OutputMeta } from '../../plugin/plugin.types.js';
|
|
3
3
|
/**
|
|
4
|
-
* Extract all @Input(), input() and model() signal metadata from a class
|
|
4
|
+
* Extract all @Input(), input() and model() signal metadata from a class
|
|
5
|
+
* declaration and the base classes Angular inherits inputs from. An input the
|
|
6
|
+
* subclass redeclares wins over the one in its base class.
|
|
5
7
|
*/
|
|
6
|
-
export declare function extractInputs(classDecl: ts.ClassDeclaration, checker: ts.TypeChecker): InputMeta[];
|
|
8
|
+
export declare function extractInputs(classDecl: ts.ClassDeclaration, checker: ts.TypeChecker, hierarchy?: import("./class-hierarchy.js").ClassHierarchy): InputMeta[];
|
|
7
9
|
/**
|
|
8
|
-
* Extract all @Output() and output() signal metadata from a class declaration
|
|
10
|
+
* Extract all @Output() and output() signal metadata from a class declaration
|
|
11
|
+
* and the base classes Angular inherits outputs from.
|
|
9
12
|
*/
|
|
10
|
-
export declare function extractOutputs(classDecl: ts.ClassDeclaration, checker: ts.TypeChecker): OutputMeta[];
|
|
13
|
+
export declare function extractOutputs(classDecl: ts.ClassDeclaration, checker: ts.TypeChecker, hierarchy?: import("./class-hierarchy.js").ClassHierarchy): OutputMeta[];
|
|
11
14
|
//# sourceMappingURL=input.extractor.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"input.extractor.d.ts","sourceRoot":"","sources":["../../../src/builder/scanner/input.extractor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,YAAY,CAAC;AAC5B,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAC;
|
|
1
|
+
{"version":3,"file":"input.extractor.d.ts","sourceRoot":"","sources":["../../../src/builder/scanner/input.extractor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,YAAY,CAAC;AAC5B,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAC;AAI1E;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,SAAS,EAAE,EAAE,CAAC,gBAAgB,EAAE,OAAO,EAAE,EAAE,CAAC,WAAW,EAAE,SAAS,gDAAwC,GAAG,SAAS,EAAE,CAuCrJ;AAsED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,SAAS,EAAE,EAAE,CAAC,gBAAgB,EAAE,OAAO,EAAE,EAAE,CAAC,WAAW,EAAE,SAAS,gDAAwC,GAAG,UAAU,EAAE,CAuBvJ"}
|
|
@@ -1,76 +1,174 @@
|
|
|
1
1
|
import ts from 'typescript';
|
|
2
|
-
import {
|
|
2
|
+
import { evaluateStatic, findDecorator, getDecoratorArgument, getJsDocComment } from './ast-utils.js';
|
|
3
|
+
import { getClassHierarchy } from './class-hierarchy.js';
|
|
3
4
|
/**
|
|
4
|
-
* Extract all @Input(), input() and model() signal metadata from a class
|
|
5
|
+
* Extract all @Input(), input() and model() signal metadata from a class
|
|
6
|
+
* declaration and the base classes Angular inherits inputs from. An input the
|
|
7
|
+
* subclass redeclares wins over the one in its base class.
|
|
5
8
|
*/
|
|
6
|
-
export function extractInputs(classDecl, checker) {
|
|
9
|
+
export function extractInputs(classDecl, checker, hierarchy = getClassHierarchy(classDecl, checker)) {
|
|
7
10
|
const inputs = [];
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
const
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
const
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
const { type, values, rawType } = resolveSignalInputType(signalCall, checker);
|
|
37
|
-
inputs.push({
|
|
38
|
-
name,
|
|
39
|
-
type,
|
|
40
|
-
rawType,
|
|
41
|
-
required,
|
|
42
|
-
...(values && { values }),
|
|
43
|
-
...(defaultValue !== undefined && { defaultValue }),
|
|
44
|
-
...(doc && { doc })
|
|
45
|
-
});
|
|
11
|
+
const seen = new Set();
|
|
12
|
+
// Fields a more derived class initializes without declaring them an input.
|
|
13
|
+
// Angular keeps the inherited input, but the component starts out with that value.
|
|
14
|
+
const reinitialized = new Map();
|
|
15
|
+
for (const { classDecl: owner, definesMetadata } of hierarchy.classes) {
|
|
16
|
+
const subclass = owner === classDecl ? undefined : classDecl;
|
|
17
|
+
for (const member of owner.members) {
|
|
18
|
+
if (!ts.isPropertyDeclaration(member) || isStatic(member))
|
|
19
|
+
continue;
|
|
20
|
+
const name = member.name && ts.isIdentifier(member.name) ? member.name.text : undefined;
|
|
21
|
+
if (!name || seen.has(name))
|
|
22
|
+
continue;
|
|
23
|
+
const input = definesMetadata ? readInput(member, name, checker, owner, subclass) : undefined;
|
|
24
|
+
if (!input) {
|
|
25
|
+
if (member.initializer && !reinitialized.has(name))
|
|
26
|
+
reinitialized.set(name, member);
|
|
27
|
+
continue;
|
|
28
|
+
}
|
|
29
|
+
const initializedBy = reinitialized.get(name);
|
|
30
|
+
if (initializedBy) {
|
|
31
|
+
const defaultValue = readInitialValue(initializedBy, checker);
|
|
32
|
+
if (defaultValue === undefined)
|
|
33
|
+
delete input.defaultValue;
|
|
34
|
+
else
|
|
35
|
+
input.defaultValue = defaultValue;
|
|
36
|
+
}
|
|
37
|
+
seen.add(name);
|
|
38
|
+
inputs.push(input);
|
|
46
39
|
}
|
|
47
40
|
}
|
|
48
41
|
return inputs;
|
|
49
42
|
}
|
|
43
|
+
function isStatic(member) {
|
|
44
|
+
return !!ts.getModifiers(member)?.some((m) => m.kind === ts.SyntaxKind.StaticKeyword);
|
|
45
|
+
}
|
|
46
|
+
/** What a field starts out with: its initializer, or for `input()` and `model()` the value passed to them. */
|
|
47
|
+
function readInitialValue(member, checker) {
|
|
48
|
+
const signalCall = getInputSignalCall(member);
|
|
49
|
+
if (!signalCall)
|
|
50
|
+
return member.initializer ? evaluateDefault(member.initializer, checker) : undefined;
|
|
51
|
+
return !isSignalInputRequired(signalCall) && signalCall.arguments.length > 0 ? evaluateDefault(signalCall.arguments[0], checker) : undefined;
|
|
52
|
+
}
|
|
50
53
|
/**
|
|
51
|
-
*
|
|
54
|
+
* `owner` declares the member. `subclass` is the showcased class when that is
|
|
55
|
+
* a different one, which decides what the type parameters of `owner` stand for.
|
|
52
56
|
*/
|
|
53
|
-
|
|
57
|
+
function readInput(member, name, checker, owner, subclass) {
|
|
58
|
+
const inputDecorator = findDecorator(member, 'Input');
|
|
59
|
+
if (inputDecorator) {
|
|
60
|
+
const required = isDecoratorInputRequired(inputDecorator);
|
|
61
|
+
const defaultValue = readInitialValue(member, checker);
|
|
62
|
+
const doc = getJsDocComment(member, checker);
|
|
63
|
+
const instantiated = subclass && usesTypeParameters(member.type ?? member.initializer, owner, checker) ? getInstantiatedType(name, subclass, checker) : undefined;
|
|
64
|
+
const { type, values, rawType } = instantiated ? mapType(instantiated, checker) : resolveDecoratorInputType(member, checker);
|
|
65
|
+
return {
|
|
66
|
+
name,
|
|
67
|
+
type,
|
|
68
|
+
rawType,
|
|
69
|
+
required,
|
|
70
|
+
...(values && { values }),
|
|
71
|
+
...(defaultValue !== undefined && { defaultValue }),
|
|
72
|
+
...(doc && { doc })
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
const signalCall = getInputSignalCall(member);
|
|
76
|
+
if (!signalCall)
|
|
77
|
+
return undefined;
|
|
78
|
+
const required = isSignalInputRequired(signalCall);
|
|
79
|
+
const defaultValue = readInitialValue(member, checker);
|
|
80
|
+
const doc = getJsDocComment(member, checker);
|
|
81
|
+
const declaredType = signalCall.typeArguments?.[0] ?? signalCall.arguments[0];
|
|
82
|
+
// A signal is a getter function, so its call signature returns the value type.
|
|
83
|
+
const instantiated = subclass && usesTypeParameters(declaredType, owner, checker) ? getInstantiatedType(name, subclass, checker)?.getCallSignatures()[0]?.getReturnType() : undefined;
|
|
84
|
+
const { type, values, rawType } = instantiated ? mapType(instantiated, checker) : resolveSignalInputType(signalCall, checker);
|
|
85
|
+
return {
|
|
86
|
+
name,
|
|
87
|
+
type,
|
|
88
|
+
rawType,
|
|
89
|
+
required,
|
|
90
|
+
...(values && { values }),
|
|
91
|
+
...(defaultValue !== undefined && { defaultValue }),
|
|
92
|
+
...(doc && { doc })
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Extract all @Output() and output() signal metadata from a class declaration
|
|
97
|
+
* and the base classes Angular inherits outputs from.
|
|
98
|
+
*/
|
|
99
|
+
export function extractOutputs(classDecl, checker, hierarchy = getClassHierarchy(classDecl, checker)) {
|
|
54
100
|
const outputs = [];
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
const name = member.name && ts.isIdentifier(member.name) ? member.name.text : undefined;
|
|
59
|
-
if (!name)
|
|
60
|
-
continue;
|
|
61
|
-
const outputDecorator = findDecorator(member, 'Output');
|
|
62
|
-
if (outputDecorator) {
|
|
63
|
-
const doc = getJsDocComment(member, checker);
|
|
64
|
-
outputs.push({ name, ...(doc && { doc }) });
|
|
101
|
+
const seen = new Set();
|
|
102
|
+
for (const { classDecl: owner, definesMetadata } of hierarchy.classes) {
|
|
103
|
+
if (!definesMetadata)
|
|
65
104
|
continue;
|
|
66
|
-
|
|
67
|
-
|
|
105
|
+
for (const member of owner.members) {
|
|
106
|
+
if (!ts.isPropertyDeclaration(member))
|
|
107
|
+
continue;
|
|
108
|
+
const name = member.name && ts.isIdentifier(member.name) ? member.name.text : undefined;
|
|
109
|
+
if (!name || seen.has(name))
|
|
110
|
+
continue;
|
|
111
|
+
if (!findDecorator(member, 'Output') && !isOutputSignal(member))
|
|
112
|
+
continue;
|
|
68
113
|
const doc = getJsDocComment(member, checker);
|
|
114
|
+
seen.add(name);
|
|
69
115
|
outputs.push({ name, ...(doc && { doc }) });
|
|
70
116
|
}
|
|
71
117
|
}
|
|
72
118
|
return outputs;
|
|
73
119
|
}
|
|
120
|
+
/**
|
|
121
|
+
* Whether a declared type, or the expression a type is inferred from,
|
|
122
|
+
* mentions a type parameter of the class that declares it. Only then does the
|
|
123
|
+
* subclass change the type; otherwise the source text stays, alias names included.
|
|
124
|
+
*/
|
|
125
|
+
function usesTypeParameters(node, owner, checker) {
|
|
126
|
+
const parameters = owner.typeParameters;
|
|
127
|
+
if (!node || !parameters?.length)
|
|
128
|
+
return false;
|
|
129
|
+
const isOwnParameter = (declaration) => !!declaration && ts.isTypeParameterDeclaration(declaration) && parameters.includes(declaration);
|
|
130
|
+
const visit = (child) => {
|
|
131
|
+
if (ts.isTypeReferenceNode(child) && ts.isIdentifier(child.typeName) && isOwnParameter(checker.getSymbolAtLocation(child.typeName)?.declarations?.[0])) {
|
|
132
|
+
return true;
|
|
133
|
+
}
|
|
134
|
+
return ts.forEachChild(child, visit) ?? false;
|
|
135
|
+
};
|
|
136
|
+
// An inferred type can depend on `T` without the source naming it: `model(this.initial)`.
|
|
137
|
+
return visit(node) || (!ts.isTypeNode(node) && typeMentions(checker.getTypeAtLocation(node), isOwnParameter, checker));
|
|
138
|
+
}
|
|
139
|
+
function typeMentions(type, isOwnParameter, checker, visited = new Set()) {
|
|
140
|
+
if (visited.has(type))
|
|
141
|
+
return false;
|
|
142
|
+
visited.add(type);
|
|
143
|
+
if (type.flags & ts.TypeFlags.TypeParameter)
|
|
144
|
+
return isOwnParameter(type.symbol?.declarations?.[0]);
|
|
145
|
+
const isReference = type.flags & ts.TypeFlags.Object && type.objectFlags & ts.ObjectFlags.Reference;
|
|
146
|
+
const nested = [
|
|
147
|
+
...(type.isUnionOrIntersection() ? type.types : []),
|
|
148
|
+
...(type.aliasTypeArguments ?? []),
|
|
149
|
+
...(isReference ? checker.getTypeArguments(type) : [])
|
|
150
|
+
];
|
|
151
|
+
return nested.some((t) => typeMentions(t, isOwnParameter, checker, visited));
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* The type of a property declared in a generic base class, as the subclass
|
|
155
|
+
* sees it: `items = input.required<T[]>()` in `Field<T>` is an
|
|
156
|
+
* `InputSignal<Country[]>` on `Picker extends Field<Country>`.
|
|
157
|
+
*/
|
|
158
|
+
function getInstantiatedType(name, subclass, checker) {
|
|
159
|
+
const property = checker.getPropertyOfType(checker.getTypeAtLocation(subclass), name);
|
|
160
|
+
return property && checker.getTypeOfSymbolAtLocation(property, subclass);
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* A default is all or nothing. The renderer applies it to the component, so
|
|
164
|
+
* the part of `{ ...shared, size: 'm' }` that can be read would overwrite the
|
|
165
|
+
* whole default the component actually declares.
|
|
166
|
+
*/
|
|
167
|
+
function evaluateDefault(node, checker) {
|
|
168
|
+
let complete = true;
|
|
169
|
+
const value = evaluateStatic(node, { checker, report: () => (complete = false) });
|
|
170
|
+
return complete ? value : undefined;
|
|
171
|
+
}
|
|
74
172
|
function getInputSignalCall(member) {
|
|
75
173
|
const init = member.initializer;
|
|
76
174
|
if (!init || !ts.isCallExpression(init))
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
export function generateManifest(components) {
|
|
5
5
|
const lines = [
|
|
6
|
-
'// AUTO-GENERATED by ng-prism
|
|
6
|
+
'// AUTO-GENERATED by ng-prism. Do not edit!',
|
|
7
7
|
"import type { PrismManifest } from 'ng-prism/plugin';",
|
|
8
8
|
'',
|
|
9
9
|
'export const PRISM_MANIFEST: PrismManifest = {',
|
|
@@ -30,6 +30,10 @@ function json(value) {
|
|
|
30
30
|
function indent(depth) {
|
|
31
31
|
return ' '.repeat(depth);
|
|
32
32
|
}
|
|
33
|
+
/** `'aria-label'` and content slots like `'[card-header]'` are only valid keys in quotes. */
|
|
34
|
+
function formatKey(key) {
|
|
35
|
+
return /^[A-Za-z_$][\w$]*$/.test(key) ? key : JSON.stringify(key);
|
|
36
|
+
}
|
|
33
37
|
function formatObject(obj, baseIndent) {
|
|
34
38
|
const entries = Object.entries(obj).filter(([, v]) => v !== undefined);
|
|
35
39
|
if (entries.length === 0)
|
|
@@ -41,7 +45,7 @@ function formatObject(obj, baseIndent) {
|
|
|
41
45
|
: typeof value === 'object' && value !== null
|
|
42
46
|
? formatObject(value, inner)
|
|
43
47
|
: json(value);
|
|
44
|
-
return `${indent(inner)}${key}: ${formatted},`;
|
|
48
|
+
return `${indent(inner)}${formatKey(key)}: ${formatted},`;
|
|
45
49
|
});
|
|
46
50
|
return `{\n${lines.join('\n')}\n${indent(baseIndent)}}`;
|
|
47
51
|
}
|
|
@@ -7,6 +7,8 @@ export interface CreateScannerOptions {
|
|
|
7
7
|
}
|
|
8
8
|
export interface ScanResult {
|
|
9
9
|
components: ScannedComponent[];
|
|
10
|
+
/** One message per @Showcase value the scan had to drop, already printed as a warning. */
|
|
11
|
+
diagnostics: string[];
|
|
10
12
|
}
|
|
11
13
|
export interface Scanner {
|
|
12
14
|
/** Scan all entry points. Reuses TypeScript program state from previous scans. */
|
|
@@ -16,7 +18,7 @@ export interface Scanner {
|
|
|
16
18
|
* Create a stateful multi-entry scanner that retains the previous ts.Program between scans.
|
|
17
19
|
* A single shared program is created with every entry-point file as a root name, so the
|
|
18
20
|
* transitive type graph (Angular framework typings, etc.) is parsed once and shared via
|
|
19
|
-
* the program's `TypeChecker
|
|
21
|
+
* the program's `TypeChecker`, instead of N programs that each load Material/CDK/RxJS.
|
|
20
22
|
*
|
|
21
23
|
* TypeScript reuses parsed SourceFile objects from the old program on rebuild, making
|
|
22
24
|
* incremental scans fast.
|
|
@@ -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,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAErE,OAAO,EAAE,KAAK,eAAe,EAA4B,MAAM,0BAA0B,CAAC;AAE1F,MAAM,WAAW,oBAAoB;IACjC,WAAW,EAAE,aAAa,CAAC,eAAe,CAAC,CAAC;IAC5C,eAAe,CAAC,EAAE,EAAE,CAAC,eAAe,CAAC;CACxC;AAED,MAAM,WAAW,UAAU;IACvB,UAAU,EAAE,gBAAgB,EAAE,CAAC;
|
|
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;AAErE,OAAO,EAAE,KAAK,eAAe,EAA4B,MAAM,0BAA0B,CAAC;AAE1F,MAAM,WAAW,oBAAoB;IACjC,WAAW,EAAE,aAAa,CAAC,eAAe,CAAC,CAAC;IAC5C,eAAe,CAAC,EAAE,EAAE,CAAC,eAAe,CAAC;CACxC;AAED,MAAM,WAAW,UAAU;IACvB,UAAU,EAAE,gBAAgB,EAAE,CAAC;IAC/B,0FAA0F;IAC1F,WAAW,EAAE,MAAM,EAAE,CAAC;CACzB;AAED,MAAM,WAAW,OAAO;IACpB,kFAAkF;IAClF,IAAI,IAAI,UAAU,CAAC;CACtB;AAkBD;;;;;;;;GAQG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,oBAAoB,GAAG,OAAO,CAiDpE"}
|
|
@@ -13,14 +13,14 @@ const DEFAULT_COMPILER_OPTIONS = {
|
|
|
13
13
|
types: [],
|
|
14
14
|
// Perf: we never call program.emit(); skip emit-related setup work.
|
|
15
15
|
noEmit: true,
|
|
16
|
-
// Perf:
|
|
16
|
+
// Perf: complements skipLibCheck by also skipping type-checking of lib.*.d.ts files.
|
|
17
17
|
skipDefaultLibCheck: true
|
|
18
18
|
};
|
|
19
19
|
/**
|
|
20
20
|
* Create a stateful multi-entry scanner that retains the previous ts.Program between scans.
|
|
21
21
|
* A single shared program is created with every entry-point file as a root name, so the
|
|
22
22
|
* transitive type graph (Angular framework typings, etc.) is parsed once and shared via
|
|
23
|
-
* the program's `TypeChecker
|
|
23
|
+
* the program's `TypeChecker`, instead of N programs that each load Material/CDK/RxJS.
|
|
24
24
|
*
|
|
25
25
|
* TypeScript reuses parsed SourceFile objects from the old program on rebuild, making
|
|
26
26
|
* incremental scans fast.
|
|
@@ -37,8 +37,10 @@ export function createScanner(options) {
|
|
|
37
37
|
previousProgram = program;
|
|
38
38
|
const checker = program.getTypeChecker();
|
|
39
39
|
const allComponents = [];
|
|
40
|
+
const diagnostics = [];
|
|
41
|
+
const notices = new Set();
|
|
40
42
|
for (const { exports, importPath } of entries) {
|
|
41
|
-
const components = scanComponents(exports, checker);
|
|
43
|
+
const components = scanComponents(exports, checker, diagnostics, notices);
|
|
42
44
|
for (const c of components)
|
|
43
45
|
c.importPath = importPath;
|
|
44
46
|
allComponents.push(...components);
|
|
@@ -59,7 +61,7 @@ export function createScanner(options) {
|
|
|
59
61
|
seen.add(key);
|
|
60
62
|
unique.push(c);
|
|
61
63
|
}
|
|
62
|
-
return { components: unique };
|
|
64
|
+
return { components: unique, diagnostics };
|
|
63
65
|
}
|
|
64
66
|
};
|
|
65
67
|
}
|