@ng-prism/core 22.5.0 → 22.6.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 +2 -0
- package/dist/app/canvas/prism-canvas-toolbar.component.d.ts +22 -1
- package/dist/app/canvas/prism-canvas-toolbar.component.d.ts.map +1 -1
- package/dist/app/canvas/prism-canvas-toolbar.component.js +111 -38
- package/dist/app/canvas/state-chips.d.ts +50 -0
- package/dist/app/canvas/state-chips.d.ts.map +1 -0
- package/dist/app/canvas/state-chips.js +40 -0
- package/dist/app/component-head/prism-component-head.component.d.ts +1 -0
- 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 -6
- package/dist/app/component-head/prism-head-info.component.d.ts +2 -1
- package/dist/app/component-head/prism-head-info.component.d.ts.map +1 -1
- package/dist/app/component-head/prism-head-info.component.js +30 -7
- package/dist/app/directives/resize-value.d.ts +1 -1
- package/dist/app/directives/resize-value.js +1 -1
- package/dist/app/discovery-manifest.d.ts +2 -2
- package/dist/app/discovery-manifest.d.ts.map +1 -1
- package/dist/app/discovery-manifest.js +15 -3
- package/dist/app/overview/open-in-playground.d.ts +11 -0
- package/dist/app/overview/open-in-playground.d.ts.map +1 -0
- package/dist/app/overview/open-in-playground.js +12 -0
- package/dist/app/overview/overview-matrix.d.ts +79 -0
- package/dist/app/overview/overview-matrix.d.ts.map +1 -0
- package/dist/app/overview/overview-matrix.js +98 -0
- package/dist/app/overview/overview-visibility.d.ts +10 -2
- package/dist/app/overview/overview-visibility.d.ts.map +1 -1
- package/dist/app/overview/overview-visibility.js +14 -3
- package/dist/app/overview/prism-overview-cell.component.d.ts +23 -2
- package/dist/app/overview/prism-overview-cell.component.d.ts.map +1 -1
- package/dist/app/overview/prism-overview-cell.component.js +133 -27
- package/dist/app/overview/prism-overview-matrix.component.d.ts +29 -0
- package/dist/app/overview/prism-overview-matrix.component.d.ts.map +1 -0
- package/dist/app/overview/prism-overview-matrix.component.js +164 -0
- package/dist/app/overview/prism-overview.component.d.ts +4 -0
- package/dist/app/overview/prism-overview.component.d.ts.map +1 -1
- package/dist/app/overview/prism-overview.component.js +37 -14
- package/dist/app/panels/a11y/a11y-core.plugin.d.ts.map +1 -1
- package/dist/app/panels/a11y/a11y-core.plugin.js +0 -1
- package/dist/app/panels/controls/controls-plugin.d.ts.map +1 -1
- package/dist/app/panels/controls/controls-plugin.js +1 -2
- package/dist/app/panels/events/events-plugin.d.ts.map +1 -1
- package/dist/app/panels/events/events-plugin.js +1 -2
- package/dist/app/pseudo/pseudo-state-marker.d.ts +32 -10
- package/dist/app/pseudo/pseudo-state-marker.d.ts.map +1 -1
- package/dist/app/pseudo/pseudo-state-marker.js +83 -67
- package/dist/app/pseudo/pseudo-targets.d.ts +11 -0
- package/dist/app/pseudo/pseudo-targets.d.ts.map +1 -0
- package/dist/app/pseudo/pseudo-targets.js +46 -0
- package/dist/app/pseudo/state-fit.d.ts +28 -0
- package/dist/app/pseudo/state-fit.d.ts.map +1 -0
- package/dist/app/pseudo/state-fit.js +97 -0
- package/dist/app/renderer/input-bindings.d.ts +16 -0
- package/dist/app/renderer/input-bindings.d.ts.map +1 -0
- package/dist/app/renderer/input-bindings.js +21 -0
- package/dist/app/renderer/known-inputs.d.ts +8 -1
- package/dist/app/renderer/known-inputs.d.ts.map +1 -1
- package/dist/app/renderer/known-inputs.js +13 -5
- package/dist/app/renderer/prism-renderer.component.d.ts +10 -3
- package/dist/app/renderer/prism-renderer.component.d.ts.map +1 -1
- package/dist/app/renderer/prism-renderer.component.js +51 -29
- package/dist/app/renderer/projectable-content.d.ts +8 -1
- package/dist/app/renderer/projectable-content.d.ts.map +1 -1
- package/dist/app/renderer/projectable-content.js +40 -29
- package/dist/app/renderer/rendered-key.d.ts +20 -6
- package/dist/app/renderer/rendered-key.d.ts.map +1 -1
- package/dist/app/renderer/rendered-key.js +25 -8
- package/dist/app/renderer/snippet-generator.js +7 -5
- package/dist/app/services/prism-pseudo-state.service.d.ts +59 -14
- package/dist/app/services/prism-pseudo-state.service.d.ts.map +1 -1
- package/dist/app/services/prism-pseudo-state.service.js +86 -29
- package/dist/app/services/prism-renderer.service.d.ts +17 -0
- package/dist/app/services/prism-renderer.service.d.ts.map +1 -1
- package/dist/app/services/prism-renderer.service.js +37 -2
- package/dist/app/services/prism-url-state.service.d.ts.map +1 -1
- package/dist/app/services/prism-url-state.service.js +39 -8
- package/dist/app/theme/prism-default-theme.d.ts.map +1 -1
- package/dist/app/theme/prism-default-theme.js +6 -5
- package/dist/builder/config-loader/deprecated-options.d.ts +7 -0
- package/dist/builder/config-loader/deprecated-options.d.ts.map +1 -0
- package/dist/builder/config-loader/deprecated-options.js +23 -0
- package/dist/builder/manifest/runtime-manifest.generator.d.ts.map +1 -1
- package/dist/builder/manifest/runtime-manifest.generator.js +3 -2
- package/dist/builder/scanner/component.scanner.d.ts.map +1 -1
- package/dist/builder/scanner/component.scanner.js +20 -1
- package/dist/builder/scanner/entry-point-discovery.d.ts +5 -0
- package/dist/builder/scanner/entry-point-discovery.d.ts.map +1 -1
- package/dist/builder/scanner/entry-point-discovery.js +14 -0
- package/dist/builder/scanner/entry-point.scanner.d.ts +3 -1
- package/dist/builder/scanner/entry-point.scanner.d.ts.map +1 -1
- package/dist/builder/scanner/entry-point.scanner.js +7 -6
- package/dist/builder/scanner/input.extractor.d.ts.map +1 -1
- package/dist/builder/scanner/input.extractor.js +22 -3
- package/dist/builder/scanner/pseudo-states.d.ts +1 -0
- package/dist/builder/scanner/pseudo-states.d.ts.map +1 -1
- package/dist/builder/scanner/pseudo-states.js +1 -1
- package/dist/builder/scanner/scanner.d.ts +2 -2
- package/dist/builder/scanner/scanner.d.ts.map +1 -1
- package/dist/builder/scanner/scanner.js +16 -6
- package/dist/builder/scanner/showcase-diagnostics.js +9 -9
- package/dist/builder/scanner/showcase-states.d.ts +17 -0
- package/dist/builder/scanner/showcase-states.d.ts.map +1 -0
- package/dist/builder/scanner/showcase-states.js +58 -0
- package/dist/builder/scanner/source-file-cache.d.ts +26 -0
- package/dist/builder/scanner/source-file-cache.d.ts.map +1 -0
- package/dist/builder/scanner/source-file-cache.js +60 -0
- package/dist/builder/shared/prism-pipeline.d.ts.map +1 -1
- package/dist/builder/shared/prism-pipeline.js +28 -13
- package/dist/decorator/index.d.ts +1 -1
- package/dist/decorator/index.d.ts.map +1 -1
- package/dist/decorator/showcase.types.d.ts +23 -0
- package/dist/decorator/showcase.types.d.ts.map +1 -1
- package/dist/plugin/index.d.ts +1 -1
- package/dist/plugin/index.d.ts.map +1 -1
- package/dist/plugin/plugin.types.d.ts +44 -5
- package/dist/plugin/plugin.types.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/builder/build/schema.json +6 -6
- package/src/builder/serve/schema.json +6 -6
|
@@ -4,8 +4,9 @@ import { CANVAS_LAYOUTS } from '../../shared/canvas-layout.type.js';
|
|
|
4
4
|
import { evaluateExpression, evaluateStatic, findDecorator, getDecoratorArgument, UNEVALUABLE } from './ast-utils.js';
|
|
5
5
|
import { getClassHierarchy } from './class-hierarchy.js';
|
|
6
6
|
import { extractInputs, extractOutputs } from './input.extractor.js';
|
|
7
|
-
import { readPseudoStates } from './pseudo-states.js';
|
|
7
|
+
import { describeValue, readPseudoStates } from './pseudo-states.js';
|
|
8
8
|
import { describeDeprecatedProviders, describeUnevaluable, describeUnreadableBase } from './showcase-diagnostics.js';
|
|
9
|
+
import { readShowcaseStates } from './showcase-states.js';
|
|
9
10
|
const COMPONENT_STATUSES = ['stable', 'beta', 'wip', 'deprecated'];
|
|
10
11
|
function isComponentStatus(value) {
|
|
11
12
|
return typeof value === 'string' && COMPONENT_STATUSES.includes(value);
|
|
@@ -123,6 +124,8 @@ function extractShowcaseConfig(decorator, className, report, checker) {
|
|
|
123
124
|
return undefined;
|
|
124
125
|
// Reported once for the whole field below, wherever it came from: the literal, a spread or a constant.
|
|
125
126
|
let providers;
|
|
127
|
+
// A state the evaluator dropped whole leaves no element behind, so its position is noted to keep the later states where the source has them.
|
|
128
|
+
const unevaluableStates = new Set();
|
|
126
129
|
const raw = evaluateStatic(arg, {
|
|
127
130
|
checker,
|
|
128
131
|
report: (issue) => {
|
|
@@ -130,6 +133,8 @@ function extractShowcaseConfig(decorator, className, report, checker) {
|
|
|
130
133
|
providers ??= issue.node;
|
|
131
134
|
return;
|
|
132
135
|
}
|
|
136
|
+
if (issue.path[0] === 'states' && issue.path.length === 2 && typeof issue.path[1] === 'number')
|
|
137
|
+
unevaluableStates.add(issue.path[1]);
|
|
133
138
|
report(describeUnevaluable(className, arg, issue));
|
|
134
139
|
}
|
|
135
140
|
});
|
|
@@ -169,6 +174,16 @@ function extractShowcaseConfig(decorator, className, report, checker) {
|
|
|
169
174
|
config.host = obj['host'];
|
|
170
175
|
if (obj['renderPage'])
|
|
171
176
|
config.renderPage = obj['renderPage'];
|
|
177
|
+
if (obj['states'] !== undefined) {
|
|
178
|
+
if (config.renderPage) {
|
|
179
|
+
report(`${className} declares states together with renderPage; a component page has no Overview to show them in. Skipping states.`);
|
|
180
|
+
}
|
|
181
|
+
else {
|
|
182
|
+
const states = readShowcaseStates(obj['states'], className, report, unevaluableStates);
|
|
183
|
+
if (states)
|
|
184
|
+
config.states = states;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
172
187
|
if (obj['status'] !== undefined) {
|
|
173
188
|
if (isComponentStatus(obj['status'])) {
|
|
174
189
|
config.status = obj['status'];
|
|
@@ -218,6 +233,10 @@ function extractShowcaseConfig(decorator, className, report, checker) {
|
|
|
218
233
|
else
|
|
219
234
|
delete cleaned['pseudo'];
|
|
220
235
|
}
|
|
236
|
+
if (variant['states'] !== undefined && variant['states'] !== false) {
|
|
237
|
+
report(`${className} variant "${String(variant['name'])}" declares invalid states ${describeValue(variant['states'])}, expected false. Skipping.`);
|
|
238
|
+
delete cleaned['states'];
|
|
239
|
+
}
|
|
221
240
|
return cleaned;
|
|
222
241
|
});
|
|
223
242
|
}
|
|
@@ -3,4 +3,9 @@ export interface DiscoveredEntryPoint {
|
|
|
3
3
|
importPath: string;
|
|
4
4
|
}
|
|
5
5
|
export declare function discoverSecondaryEntryPoints(libraryRoot: string, baseImportPath: string): DiscoveredEntryPoint[];
|
|
6
|
+
/**
|
|
7
|
+
* The primary entry file of the library at `libraryRoot`: `lib.entryFile` of its
|
|
8
|
+
* own `ng-package.json`, or `undefined` when there is no such file.
|
|
9
|
+
*/
|
|
10
|
+
export declare function findPrimaryEntryFile(libraryRoot: string): string | undefined;
|
|
6
11
|
//# sourceMappingURL=entry-point-discovery.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"entry-point-discovery.d.ts","sourceRoot":"","sources":["../../../src/builder/scanner/entry-point-discovery.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,oBAAoB;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;CACtB;AAED,wBAAgB,4BAA4B,CAAC,WAAW,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,GAAG,oBAAoB,EAAE,CAKhH"}
|
|
1
|
+
{"version":3,"file":"entry-point-discovery.d.ts","sourceRoot":"","sources":["../../../src/builder/scanner/entry-point-discovery.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,oBAAoB;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;CACtB;AAED,wBAAgB,4BAA4B,CAAC,WAAW,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,GAAG,oBAAoB,EAAE,CAKhH;AAKD;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAS5E"}
|
|
@@ -5,6 +5,20 @@ export function discoverSecondaryEntryPoints(libraryRoot, baseImportPath) {
|
|
|
5
5
|
findNgPackageJsons(libraryRoot, libraryRoot, baseImportPath, entryPoints);
|
|
6
6
|
return entryPoints;
|
|
7
7
|
}
|
|
8
|
+
/** ng-packagr's default for `lib.entryFile`. */
|
|
9
|
+
const NG_PACKAGR_DEFAULT_ENTRY_FILE = 'src/public_api.ts';
|
|
10
|
+
/**
|
|
11
|
+
* The primary entry file of the library at `libraryRoot`: `lib.entryFile` of its
|
|
12
|
+
* own `ng-package.json`, or `undefined` when there is no such file.
|
|
13
|
+
*/
|
|
14
|
+
export function findPrimaryEntryFile(libraryRoot) {
|
|
15
|
+
const ngPackagePath = join(libraryRoot, 'ng-package.json');
|
|
16
|
+
if (!existsSync(ngPackagePath))
|
|
17
|
+
return undefined;
|
|
18
|
+
const ngPackage = JSON.parse(readFileSync(ngPackagePath, 'utf-8'));
|
|
19
|
+
const entryFilePath = join(libraryRoot, ngPackage.lib?.entryFile ?? NG_PACKAGR_DEFAULT_ENTRY_FILE);
|
|
20
|
+
return existsSync(entryFilePath) ? entryFilePath : undefined;
|
|
21
|
+
}
|
|
8
22
|
function findNgPackageJsons(dir, libraryRoot, baseImportPath, result) {
|
|
9
23
|
const isLibraryRoot = dir === libraryRoot;
|
|
10
24
|
const ngPackagePath = join(dir, 'ng-package.json');
|
|
@@ -2,6 +2,8 @@ import ts from 'typescript';
|
|
|
2
2
|
export interface EntryPointInput {
|
|
3
3
|
entryFile: string;
|
|
4
4
|
importPath: string;
|
|
5
|
+
/** The library's primary entry point. A component it re-exports from a secondary one keeps that one, silently. */
|
|
6
|
+
primary?: boolean;
|
|
5
7
|
}
|
|
6
8
|
export interface ResolvedEntryPoint extends EntryPointInput {
|
|
7
9
|
exports: ts.Symbol[];
|
|
@@ -18,5 +20,5 @@ export interface MultiEntryResult {
|
|
|
18
20
|
*
|
|
19
21
|
* Re-exports (`export * from '...'`) are resolved automatically by TypeScript.
|
|
20
22
|
*/
|
|
21
|
-
export declare function resolveEntryPointExports(entryPoints: ReadonlyArray<EntryPointInput>, compilerOptions: ts.CompilerOptions, previousProgram?: ts.Program): MultiEntryResult;
|
|
23
|
+
export declare function resolveEntryPointExports(entryPoints: ReadonlyArray<EntryPointInput>, compilerOptions: ts.CompilerOptions, previousProgram?: ts.Program, host?: ts.CompilerHost): MultiEntryResult;
|
|
22
24
|
//# 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,eAAe;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;
|
|
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;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,kHAAkH;IAClH,OAAO,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,WAAW,kBAAmB,SAAQ,eAAe;IACvD,OAAO,EAAE,EAAE,CAAC,MAAM,EAAE,CAAC;CACxB;AAED,MAAM,WAAW,gBAAgB;IAC7B,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC;IACpB,OAAO,EAAE,kBAAkB,EAAE,CAAC;CACjC;AAED;;;;;;;GAOG;AACH,wBAAgB,wBAAwB,CACpC,WAAW,EAAE,aAAa,CAAC,eAAe,CAAC,EAC3C,eAAe,EAAE,EAAE,CAAC,eAAe,EACnC,eAAe,CAAC,EAAE,EAAE,CAAC,OAAO,EAC5B,IAAI,CAAC,EAAE,EAAE,CAAC,YAAY,GACvB,gBAAgB,CA8BlB"}
|
|
@@ -7,23 +7,24 @@ import ts from 'typescript';
|
|
|
7
7
|
*
|
|
8
8
|
* Re-exports (`export * from '...'`) are resolved automatically by TypeScript.
|
|
9
9
|
*/
|
|
10
|
-
export function resolveEntryPointExports(entryPoints, compilerOptions, previousProgram) {
|
|
11
|
-
const program = ts.createProgram(entryPoints.map((e) => e.entryFile), compilerOptions,
|
|
10
|
+
export function resolveEntryPointExports(entryPoints, compilerOptions, previousProgram, host) {
|
|
11
|
+
const program = ts.createProgram(entryPoints.map((e) => e.entryFile), compilerOptions, host, previousProgram);
|
|
12
12
|
const checker = program.getTypeChecker();
|
|
13
|
-
const entries = entryPoints.map((
|
|
13
|
+
const entries = entryPoints.map((entryPoint) => {
|
|
14
|
+
const { entryFile } = entryPoint;
|
|
14
15
|
try {
|
|
15
16
|
const sourceFile = program.getSourceFile(entryFile);
|
|
16
17
|
if (!sourceFile) {
|
|
17
18
|
console.warn(`⚠ ng-prism: source file not found for entry point ${entryFile}, skipping.`);
|
|
18
|
-
return {
|
|
19
|
+
return { ...entryPoint, exports: [] };
|
|
19
20
|
}
|
|
20
21
|
const moduleSymbol = checker.getSymbolAtLocation(sourceFile);
|
|
21
22
|
const exports = moduleSymbol ? checker.getExportsOfModule(moduleSymbol) : [];
|
|
22
|
-
return {
|
|
23
|
+
return { ...entryPoint, exports };
|
|
23
24
|
}
|
|
24
25
|
catch (err) {
|
|
25
26
|
console.error(`⚠ ng-prism: failed to resolve exports for ${entryFile}: ${err instanceof Error ? err.message : String(err)}`);
|
|
26
|
-
return {
|
|
27
|
+
return { ...entryPoint, exports: [] };
|
|
27
28
|
}
|
|
28
29
|
});
|
|
29
30
|
return { program, entries };
|
|
@@ -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;AAI1E;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,SAAS,EAAE,EAAE,CAAC,gBAAgB,EAAE,OAAO,EAAE,EAAE,CAAC,WAAW,EAAE,SAAS,gDAAwC,GAAG,SAAS,EAAE,CAuCrJ;
|
|
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;AAwFD;;;GAGG;AACH,wBAAgB,cAAc,CAAC,SAAS,EAAE,EAAE,CAAC,gBAAgB,EAAE,OAAO,EAAE,EAAE,CAAC,WAAW,EAAE,SAAS,gDAAwC,GAAG,UAAU,EAAE,CA4BvJ"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import ts from 'typescript';
|
|
2
|
-
import { evaluateStatic, findDecorator, getDecoratorArgument, getJsDocComment } from './ast-utils.js';
|
|
2
|
+
import { evaluateExpression, evaluateStatic, findDecorator, getDecoratorArgument, getJsDocComment } from './ast-utils.js';
|
|
3
3
|
import { getClassHierarchy } from './class-hierarchy.js';
|
|
4
4
|
/**
|
|
5
5
|
* Extract all @Input(), input() and model() signal metadata from a class
|
|
@@ -58,12 +58,14 @@ function readInput(member, name, checker, owner, subclass) {
|
|
|
58
58
|
const inputDecorator = findDecorator(member, 'Input');
|
|
59
59
|
if (inputDecorator) {
|
|
60
60
|
const required = isDecoratorInputRequired(inputDecorator);
|
|
61
|
+
const alias = readAlias(getDecoratorArgument(inputDecorator), name, checker);
|
|
61
62
|
const defaultValue = readInitialValue(member, checker);
|
|
62
63
|
const doc = getJsDocComment(member, checker);
|
|
63
64
|
const instantiated = subclass && usesTypeParameters(member.type ?? member.initializer, owner, checker) ? getInstantiatedType(name, subclass, checker) : undefined;
|
|
64
65
|
const { type, values, rawType } = instantiated ? mapType(instantiated, checker) : resolveDecoratorInputType(member, checker);
|
|
65
66
|
return {
|
|
66
67
|
name,
|
|
68
|
+
...(alias && { alias }),
|
|
67
69
|
type,
|
|
68
70
|
rawType,
|
|
69
71
|
required,
|
|
@@ -76,6 +78,8 @@ function readInput(member, name, checker, owner, subclass) {
|
|
|
76
78
|
if (!signalCall)
|
|
77
79
|
return undefined;
|
|
78
80
|
const required = isSignalInputRequired(signalCall);
|
|
81
|
+
// `input(initial, options)`, but `input.required(options)`.
|
|
82
|
+
const alias = readAlias(signalCall.arguments[required ? 0 : 1], name, checker);
|
|
79
83
|
const defaultValue = readInitialValue(member, checker);
|
|
80
84
|
const doc = getJsDocComment(member, checker);
|
|
81
85
|
const declaredType = signalCall.typeArguments?.[0] ?? signalCall.arguments[0];
|
|
@@ -84,6 +88,7 @@ function readInput(member, name, checker, owner, subclass) {
|
|
|
84
88
|
const { type, values, rawType } = instantiated ? mapType(instantiated, checker) : resolveSignalInputType(signalCall, checker);
|
|
85
89
|
return {
|
|
86
90
|
name,
|
|
91
|
+
...(alias && { alias }),
|
|
87
92
|
type,
|
|
88
93
|
rawType,
|
|
89
94
|
required,
|
|
@@ -92,6 +97,17 @@ function readInput(member, name, checker, owner, subclass) {
|
|
|
92
97
|
...(doc && { doc })
|
|
93
98
|
};
|
|
94
99
|
}
|
|
100
|
+
/**
|
|
101
|
+
* The `alias` of an input or output, from a decorator argument (`'x'` or
|
|
102
|
+
* `{ alias: 'x' }`) or the options of `input()`, `model()` and `output()`.
|
|
103
|
+
* It counts when the builder can evaluate it statically to a string (a literal
|
|
104
|
+
* or a constant) that differs from the member name.
|
|
105
|
+
*/
|
|
106
|
+
function readAlias(arg, name, checker) {
|
|
107
|
+
const value = arg ? evaluateExpression(arg, checker) : undefined;
|
|
108
|
+
const alias = typeof value === 'object' && value !== null ? value['alias'] : value;
|
|
109
|
+
return typeof alias === 'string' && alias !== name ? alias : undefined;
|
|
110
|
+
}
|
|
95
111
|
/**
|
|
96
112
|
* Extract all @Output() and output() signal metadata from a class declaration
|
|
97
113
|
* and the base classes Angular inherits outputs from.
|
|
@@ -108,11 +124,14 @@ export function extractOutputs(classDecl, checker, hierarchy = getClassHierarchy
|
|
|
108
124
|
const name = member.name && ts.isIdentifier(member.name) ? member.name.text : undefined;
|
|
109
125
|
if (!name || seen.has(name))
|
|
110
126
|
continue;
|
|
111
|
-
|
|
127
|
+
const outputDecorator = findDecorator(member, 'Output');
|
|
128
|
+
if (!outputDecorator && !isOutputSignal(member))
|
|
112
129
|
continue;
|
|
113
130
|
const doc = getJsDocComment(member, checker);
|
|
131
|
+
const options = outputDecorator ? getDecoratorArgument(outputDecorator) : member.initializer.arguments[0];
|
|
132
|
+
const alias = readAlias(options, name, checker);
|
|
114
133
|
seen.add(name);
|
|
115
|
-
outputs.push({ name, ...(doc && { doc }) });
|
|
134
|
+
outputs.push({ name, ...(alias && { alias }), ...(doc && { doc }) });
|
|
116
135
|
}
|
|
117
136
|
}
|
|
118
137
|
return outputs;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type ForcedPseudoStates } from '../../shared/pseudo-state.type.js';
|
|
2
|
+
export declare function describeValue(value: unknown): string;
|
|
2
3
|
/**
|
|
3
4
|
* `Variant.pseudo` as the scanner evaluated it, with everything it cannot use
|
|
4
5
|
* reported and dropped: a value that is no object, an unknown state, and a
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pseudo-states.d.ts","sourceRoot":"","sources":["../../../src/builder/scanner/pseudo-states.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,kBAAkB,EAAsD,MAAM,mCAAmC,CAAC;
|
|
1
|
+
{"version":3,"file":"pseudo-states.d.ts","sourceRoot":"","sources":["../../../src/builder/scanner/pseudo-states.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,kBAAkB,EAAsD,MAAM,mCAAmC,CAAC;AAUhI,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAGpD;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,GAAG,kBAAkB,GAAG,SAAS,CAmBjI"}
|
|
@@ -5,7 +5,7 @@ function isPseudoState(value) {
|
|
|
5
5
|
function isSelector(value) {
|
|
6
6
|
return typeof value === 'string' && value.trim() !== '';
|
|
7
7
|
}
|
|
8
|
-
function describeValue(value) {
|
|
8
|
+
export function describeValue(value) {
|
|
9
9
|
if (typeof value === 'string' || (typeof value === 'object' && value !== null))
|
|
10
10
|
return JSON.stringify(value) ?? String(value);
|
|
11
11
|
return String(value);
|
|
@@ -20,8 +20,8 @@ export interface Scanner {
|
|
|
20
20
|
* transitive type graph (Angular framework typings, etc.) is parsed once and shared via
|
|
21
21
|
* the program's `TypeChecker`, instead of N programs that each load Material/CDK/RxJS.
|
|
22
22
|
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
23
|
+
* On rebuild, the source-file cache hands TypeScript the already parsed SourceFile of
|
|
24
|
+
* every unchanged file, so only the changed files are parsed again.
|
|
25
25
|
*/
|
|
26
26
|
export declare function createScanner(options: CreateScannerOptions): Scanner;
|
|
27
27
|
//# 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,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAErE,OAAO,EAAE,KAAK,eAAe,EAA4B,MAAM,0BAA0B,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;AAG1F,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,CA0DpE"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import ts from 'typescript';
|
|
2
2
|
import { scanComponents } from './component.scanner.js';
|
|
3
3
|
import { resolveEntryPointExports } from './entry-point.scanner.js';
|
|
4
|
+
import { createSourceFileCache } from './source-file-cache.js';
|
|
4
5
|
const DEFAULT_COMPILER_OPTIONS = {
|
|
5
6
|
target: ts.ScriptTarget.ES2022,
|
|
6
7
|
module: ts.ModuleKind.ES2022,
|
|
@@ -22,38 +23,47 @@ const DEFAULT_COMPILER_OPTIONS = {
|
|
|
22
23
|
* transitive type graph (Angular framework typings, etc.) is parsed once and shared via
|
|
23
24
|
* the program's `TypeChecker`, instead of N programs that each load Material/CDK/RxJS.
|
|
24
25
|
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
26
|
+
* On rebuild, the source-file cache hands TypeScript the already parsed SourceFile of
|
|
27
|
+
* every unchanged file, so only the changed files are parsed again.
|
|
27
28
|
*/
|
|
28
29
|
export function createScanner(options) {
|
|
29
30
|
const compilerOptions = {
|
|
30
31
|
...DEFAULT_COMPILER_OPTIONS,
|
|
31
32
|
...options.compilerOptions
|
|
32
33
|
};
|
|
34
|
+
const sourceFiles = createSourceFileCache(compilerOptions);
|
|
33
35
|
let previousProgram;
|
|
34
36
|
return {
|
|
35
37
|
scan() {
|
|
36
|
-
const { program, entries } = resolveEntryPointExports(options.entryPoints, compilerOptions, previousProgram);
|
|
38
|
+
const { program, entries } = resolveEntryPointExports(options.entryPoints, compilerOptions, previousProgram, sourceFiles.host);
|
|
37
39
|
previousProgram = program;
|
|
40
|
+
sourceFiles.prune(program);
|
|
38
41
|
const checker = program.getTypeChecker();
|
|
39
42
|
const allComponents = [];
|
|
40
43
|
const diagnostics = [];
|
|
41
44
|
const notices = new Set();
|
|
42
|
-
|
|
45
|
+
const fromPrimary = new Set();
|
|
46
|
+
for (const { exports, importPath, primary } of entries) {
|
|
43
47
|
const components = scanComponents(exports, checker, diagnostics, notices);
|
|
44
|
-
for (const c of components)
|
|
48
|
+
for (const c of components) {
|
|
45
49
|
c.importPath = importPath;
|
|
50
|
+
if (primary)
|
|
51
|
+
fromPrimary.add(c);
|
|
52
|
+
}
|
|
46
53
|
allComponents.push(...components);
|
|
47
54
|
}
|
|
48
55
|
// Dedupe by (filePath, className): if a component class is re-exported from
|
|
49
56
|
// multiple entry points (e.g. atoms/button + barrel index.ts), we keep the first
|
|
50
57
|
// occurrence. The duplicate would otherwise produce duplicate imports in the
|
|
51
|
-
// generated manifest and a runtime collision in the Prism shell.
|
|
58
|
+
// generated manifest and a runtime collision in the Prism shell. The primary
|
|
59
|
+
// entry point comes last and re-exporting its secondaries is normal there.
|
|
52
60
|
const seen = new Set();
|
|
53
61
|
const unique = [];
|
|
54
62
|
for (const c of allComponents) {
|
|
55
63
|
const key = `${c.filePath}::${c.className}`;
|
|
56
64
|
if (seen.has(key)) {
|
|
65
|
+
if (fromPrimary.has(c))
|
|
66
|
+
continue;
|
|
57
67
|
console.warn(`⚠ ng-prism: ${c.className} is exported by multiple entry points; ` +
|
|
58
68
|
`keeping the first occurrence (importPath: ${unique.find((u) => u.className === c.className && u.filePath === c.filePath)?.importPath}).`);
|
|
59
69
|
continue;
|
|
@@ -49,14 +49,14 @@ export function describeUnreadableBase(className, base) {
|
|
|
49
49
|
return (`${className} inherits ${base.inputs.join(', ')} from ${baseName}, which only exists as a declaration (${location(base.classDecl)}); ` +
|
|
50
50
|
`without its source these inputs cannot be read, so they are missing from the manifest and variants cannot set them.`);
|
|
51
51
|
}
|
|
52
|
-
/** A variant is named by its `name` as well as its index, since that is what the styleguide shows. */
|
|
52
|
+
/** A variant or a state is named by its `name` as well as its index, since that is what the styleguide shows. */
|
|
53
53
|
function formatShowcasePath(path, config) {
|
|
54
54
|
const [head, index, ...rest] = path;
|
|
55
|
-
if (head !== 'variants' || typeof index !== 'number')
|
|
55
|
+
if ((head !== 'variants' && head !== 'states') || typeof index !== 'number')
|
|
56
56
|
return formatPath(path);
|
|
57
|
-
const name =
|
|
58
|
-
const
|
|
59
|
-
return rest.length === 0 ?
|
|
57
|
+
const name = elementName(config, head, index);
|
|
58
|
+
const element = name === undefined ? `${head}[${index}]` : `${head}[${index}] ${JSON.stringify(name)}`;
|
|
59
|
+
return rest.length === 0 ? element : `${element} › ${formatPath(rest)}`;
|
|
60
60
|
}
|
|
61
61
|
function formatPath(path) {
|
|
62
62
|
return path
|
|
@@ -70,10 +70,10 @@ function formatPath(path) {
|
|
|
70
70
|
.join('');
|
|
71
71
|
}
|
|
72
72
|
/** Read from the source, because the evaluated array has already lost the elements before the index. */
|
|
73
|
-
function
|
|
74
|
-
const
|
|
75
|
-
const
|
|
76
|
-
const name =
|
|
73
|
+
function elementName(config, key, index) {
|
|
74
|
+
const elements = ts.isObjectLiteralExpression(config) ? findInitializer(config, key) : undefined;
|
|
75
|
+
const element = elements && ts.isArrayLiteralExpression(elements) ? elements.elements[index] : undefined;
|
|
76
|
+
const name = element && ts.isObjectLiteralExpression(element) ? findInitializer(element, 'name') : undefined;
|
|
77
77
|
const value = name && evaluateExpression(name);
|
|
78
78
|
return typeof value === 'string' ? value : undefined;
|
|
79
79
|
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { ShowcaseState } from '../../decorator/showcase.types.js';
|
|
2
|
+
/**
|
|
3
|
+
* `ShowcaseConfig.states` as the scanner evaluated it, with everything it
|
|
4
|
+
* cannot use reported. `undefined` when it is no list, or an empty one.
|
|
5
|
+
*
|
|
6
|
+
* Every slot of the list survives, because a state is identified by its
|
|
7
|
+
* position (the URL, the marker and the discovery manifest use it): an
|
|
8
|
+
* unusable entry becomes a state without pseudo states, which the styleguide
|
|
9
|
+
* shows as an empty column, instead of shifting the entries behind it.
|
|
10
|
+
* A state without a usable name is called `State <position>`.
|
|
11
|
+
*
|
|
12
|
+
* `unevaluable` holds the source positions of the entries the evaluator could
|
|
13
|
+
* not read at all. They are missing from `value`, so an empty slot goes back
|
|
14
|
+
* in at each of them, without a message of its own.
|
|
15
|
+
*/
|
|
16
|
+
export declare function readShowcaseStates(value: unknown, className: string, report: (message: string) => void, unevaluable?: ReadonlySet<number>): ShowcaseState[] | undefined;
|
|
17
|
+
//# sourceMappingURL=showcase-states.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"showcase-states.d.ts","sourceRoot":"","sources":["../../../src/builder/scanner/showcase-states.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mCAAmC,CAAC;AAUvE;;;;;;;;;;;;;GAaG;AACH,wBAAgB,kBAAkB,CAC9B,KAAK,EAAE,OAAO,EACd,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,EACjC,WAAW,GAAE,WAAW,CAAC,MAAM,CAAa,GAC7C,aAAa,EAAE,GAAG,SAAS,CA4C7B"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { describeValue, readPseudoStates } from './pseudo-states.js';
|
|
2
|
+
function isEmptyObject(value) {
|
|
3
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value) && Object.keys(value).length === 0;
|
|
4
|
+
}
|
|
5
|
+
/** Stands in for a state the evaluator dropped, which its own diagnostic already explains. */
|
|
6
|
+
const GAP = Symbol('unevaluable state');
|
|
7
|
+
/**
|
|
8
|
+
* `ShowcaseConfig.states` as the scanner evaluated it, with everything it
|
|
9
|
+
* cannot use reported. `undefined` when it is no list, or an empty one.
|
|
10
|
+
*
|
|
11
|
+
* Every slot of the list survives, because a state is identified by its
|
|
12
|
+
* position (the URL, the marker and the discovery manifest use it): an
|
|
13
|
+
* unusable entry becomes a state without pseudo states, which the styleguide
|
|
14
|
+
* shows as an empty column, instead of shifting the entries behind it.
|
|
15
|
+
* A state without a usable name is called `State <position>`.
|
|
16
|
+
*
|
|
17
|
+
* `unevaluable` holds the source positions of the entries the evaluator could
|
|
18
|
+
* not read at all. They are missing from `value`, so an empty slot goes back
|
|
19
|
+
* in at each of them, without a message of its own.
|
|
20
|
+
*/
|
|
21
|
+
export function readShowcaseStates(value, className, report, unevaluable = new Set()) {
|
|
22
|
+
if (!Array.isArray(value)) {
|
|
23
|
+
report(`${className} declares invalid states ${describeValue(value)}, expected a list of { name, pseudo }. Skipping.`);
|
|
24
|
+
return undefined;
|
|
25
|
+
}
|
|
26
|
+
const entries = [...value];
|
|
27
|
+
// Ascending, so that each position is already the one the source gives it once the earlier gaps are back.
|
|
28
|
+
for (const index of [...unevaluable].sort((a, b) => a - b))
|
|
29
|
+
entries.splice(index, 0, GAP);
|
|
30
|
+
if (entries.length === 0)
|
|
31
|
+
return undefined;
|
|
32
|
+
const firstIndexOfName = new Map();
|
|
33
|
+
return entries.map((entry, index) => {
|
|
34
|
+
const state = typeof entry === 'object' && entry !== null && !Array.isArray(entry) ? entry : undefined;
|
|
35
|
+
const declaredName = state?.['name'];
|
|
36
|
+
const hasName = typeof declaredName === 'string' && declaredName.trim() !== '';
|
|
37
|
+
if (state && !hasName)
|
|
38
|
+
report(`${className} states[${index}] has no name, expected a non-empty string. Calling it "State ${index + 1}".`);
|
|
39
|
+
else if (!state && entry !== GAP)
|
|
40
|
+
report(`${className} states[${index}] is ${describeValue(entry)}, expected { name, pseudo }. Its column stays empty.`);
|
|
41
|
+
const name = hasName ? declaredName : `State ${index + 1}`;
|
|
42
|
+
const first = firstIndexOfName.get(name);
|
|
43
|
+
if (first !== undefined) {
|
|
44
|
+
report(`${className} state "${name}" repeats the name of states[${first}]; only the first one is used. Its column stays empty.`);
|
|
45
|
+
return { name, pseudo: {} };
|
|
46
|
+
}
|
|
47
|
+
firstIndexOfName.set(name, index);
|
|
48
|
+
if (!state)
|
|
49
|
+
return { name, pseudo: {} };
|
|
50
|
+
const pseudo = state['pseudo'];
|
|
51
|
+
// `readPseudoStates` reports what it drops, but an empty object has nothing to drop.
|
|
52
|
+
if (pseudo === undefined || isEmptyObject(pseudo)) {
|
|
53
|
+
report(`${className} state "${name}" declares no pseudo states. Its column stays empty.`);
|
|
54
|
+
return { name, pseudo: {} };
|
|
55
|
+
}
|
|
56
|
+
return { name, pseudo: readPseudoStates(pseudo, `${className} state "${name}"`, report) ?? {} };
|
|
57
|
+
});
|
|
58
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import ts from 'typescript';
|
|
2
|
+
export interface SourceFileCache {
|
|
3
|
+
/** Pass to `ts.createProgram` together with the previous program. */
|
|
4
|
+
host: ts.CompilerHost;
|
|
5
|
+
/** Drop every cached file the given program no longer contains. */
|
|
6
|
+
prune(program: ts.Program): void;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* A compiler host that hands out the same `SourceFile` for a file that has
|
|
10
|
+
* not changed since it was last parsed.
|
|
11
|
+
*
|
|
12
|
+
* `ts.createProgram(…, oldProgram)` only reuses a file from the old program
|
|
13
|
+
* when the host returns the identical object. The default host reads and
|
|
14
|
+
* parses on every call, so without this cache each rebuild re-parses the
|
|
15
|
+
* whole program, Angular's typings included.
|
|
16
|
+
*
|
|
17
|
+
* A file counts as unchanged while its mtime and size are. An edit that keeps
|
|
18
|
+
* the size and lands within the file system's mtime resolution goes unseen;
|
|
19
|
+
* APFS and ext4 record nanoseconds, so in practice that does not happen.
|
|
20
|
+
*
|
|
21
|
+
* Module resolutions are recomputed on every program. Reusing them would
|
|
22
|
+
* miss a file created after an import of it had already failed to resolve,
|
|
23
|
+
* because the importing file itself has not changed.
|
|
24
|
+
*/
|
|
25
|
+
export declare function createSourceFileCache(compilerOptions: ts.CompilerOptions): SourceFileCache;
|
|
26
|
+
//# sourceMappingURL=source-file-cache.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"source-file-cache.d.ts","sourceRoot":"","sources":["../../../src/builder/scanner/source-file-cache.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,YAAY,CAAC;AAE5B,MAAM,WAAW,eAAe;IAC5B,qEAAqE;IACrE,IAAI,EAAE,EAAE,CAAC,YAAY,CAAC;IACtB,mEAAmE;IACnE,KAAK,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,GAAG,IAAI,CAAC;CACpC;AAOD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,qBAAqB,CAAC,eAAe,EAAE,EAAE,CAAC,eAAe,GAAG,eAAe,CAmC1F"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { statSync } from 'fs';
|
|
2
|
+
import ts from 'typescript';
|
|
3
|
+
/**
|
|
4
|
+
* A compiler host that hands out the same `SourceFile` for a file that has
|
|
5
|
+
* not changed since it was last parsed.
|
|
6
|
+
*
|
|
7
|
+
* `ts.createProgram(…, oldProgram)` only reuses a file from the old program
|
|
8
|
+
* when the host returns the identical object. The default host reads and
|
|
9
|
+
* parses on every call, so without this cache each rebuild re-parses the
|
|
10
|
+
* whole program, Angular's typings included.
|
|
11
|
+
*
|
|
12
|
+
* A file counts as unchanged while its mtime and size are. An edit that keeps
|
|
13
|
+
* the size and lands within the file system's mtime resolution goes unseen;
|
|
14
|
+
* APFS and ext4 record nanoseconds, so in practice that does not happen.
|
|
15
|
+
*
|
|
16
|
+
* Module resolutions are recomputed on every program. Reusing them would
|
|
17
|
+
* miss a file created after an import of it had already failed to resolve,
|
|
18
|
+
* because the importing file itself has not changed.
|
|
19
|
+
*/
|
|
20
|
+
export function createSourceFileCache(compilerOptions) {
|
|
21
|
+
const host = ts.createCompilerHost(compilerOptions);
|
|
22
|
+
const parse = host.getSourceFile.bind(host);
|
|
23
|
+
const cache = new Map();
|
|
24
|
+
host.getSourceFile = (fileName, languageVersionOrOptions, onError, shouldCreateNewSourceFile) => {
|
|
25
|
+
const stamp = readStamp(fileName);
|
|
26
|
+
if (stamp === undefined) {
|
|
27
|
+
cache.delete(fileName);
|
|
28
|
+
return undefined;
|
|
29
|
+
}
|
|
30
|
+
const cached = cache.get(fileName);
|
|
31
|
+
if (cached?.stamp === stamp && !shouldCreateNewSourceFile)
|
|
32
|
+
return cached.sourceFile;
|
|
33
|
+
const sourceFile = parse(fileName, languageVersionOrOptions, onError, shouldCreateNewSourceFile);
|
|
34
|
+
if (sourceFile)
|
|
35
|
+
cache.set(fileName, { stamp, sourceFile });
|
|
36
|
+
else
|
|
37
|
+
cache.delete(fileName);
|
|
38
|
+
return sourceFile;
|
|
39
|
+
};
|
|
40
|
+
host.hasInvalidatedResolutions = () => true;
|
|
41
|
+
return {
|
|
42
|
+
host,
|
|
43
|
+
prune(program) {
|
|
44
|
+
const live = new Set(program.getSourceFiles().map((sf) => sf.fileName));
|
|
45
|
+
for (const fileName of cache.keys()) {
|
|
46
|
+
if (!live.has(fileName))
|
|
47
|
+
cache.delete(fileName);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
function readStamp(fileName) {
|
|
53
|
+
try {
|
|
54
|
+
const { mtimeMs, size } = statSync(fileName);
|
|
55
|
+
return `${mtimeMs}:${size}`;
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
return undefined;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prism-pipeline.d.ts","sourceRoot":"","sources":["../../../src/builder/shared/prism-pipeline.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;
|
|
1
|
+
{"version":3,"file":"prism-pipeline.d.ts","sourceRoot":"","sources":["../../../src/builder/shared/prism-pipeline.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAUhE,OAAO,EAAiB,KAAK,OAAO,EAAmB,MAAM,uBAAuB,CAAC;AAErF,MAAM,WAAW,oBAAoB;IACjC,UAAU,EAAE,MAAM,CAAC;IACnB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,8FAA8F;IAC9F,QAAQ,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,mBAAmB;IAChC,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,mGAAmG;IACnG,OAAO,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,kBAAkB;IAC/B,OAAO,EAAE,OAAO,GAAG,SAAS,CAAC;IAC7B,mGAAmG;IACnG,eAAe,EAAE,MAAM,GAAG,SAAS,CAAC;CACvC;AAED,wBAAgB,mBAAmB,IAAI,kBAAkB,CAExD;AAED,wBAAsB,gBAAgB,CAAC,OAAO,EAAE,oBAAoB,EAAE,OAAO,EAAE,cAAc,EAAE,KAAK,EAAE,kBAAkB,GAAG,OAAO,CAAC,mBAAmB,CAAC,CA2FtJ"}
|
|
@@ -3,9 +3,10 @@ import { dirname, join } from 'path';
|
|
|
3
3
|
import ts from 'typescript';
|
|
4
4
|
import { checkA11yThresholds, DEFAULT_A11Y_REPORT_PATH, readA11yForComponents, readA11yMeta } from '../a11y/a11y-report-reader.js';
|
|
5
5
|
import { loadConfig } from '../config-loader/config-loader.js';
|
|
6
|
+
import { describeDeprecatedOptions } from '../config-loader/deprecated-options.js';
|
|
6
7
|
import { generateRuntimeManifest } from '../manifest/runtime-manifest.generator.js';
|
|
7
8
|
import { runPluginHooks } from '../plugin-runner/plugin-runner.js';
|
|
8
|
-
import { discoverSecondaryEntryPoints } from '../scanner/entry-point-discovery.js';
|
|
9
|
+
import { discoverSecondaryEntryPoints, findPrimaryEntryFile } from '../scanner/entry-point-discovery.js';
|
|
9
10
|
import { createScanner } from '../scanner/scanner.js';
|
|
10
11
|
export function createPipelineState() {
|
|
11
12
|
return { scanner: undefined, lastEntrySetKey: undefined };
|
|
@@ -17,6 +18,9 @@ export async function runPrismPipeline(options, context, state) {
|
|
|
17
18
|
workspaceRoot,
|
|
18
19
|
configFileName: options.configFile
|
|
19
20
|
});
|
|
21
|
+
for (const notice of describeDeprecatedOptions(config, options.configFile)) {
|
|
22
|
+
console.warn(`⚠ ng-prism: ${notice}`);
|
|
23
|
+
}
|
|
20
24
|
context.reportStatus('Scanning components...');
|
|
21
25
|
const { components, diagnostics } = scanEntryPoints(workspaceRoot, options, state);
|
|
22
26
|
if (config.strictShowcase && diagnostics.length > 0) {
|
|
@@ -115,6 +119,18 @@ function findLibraryRoot(filePath) {
|
|
|
115
119
|
}
|
|
116
120
|
return undefined;
|
|
117
121
|
}
|
|
122
|
+
/**
|
|
123
|
+
* Reads config files, `extends` included, but lists no directories. Only
|
|
124
|
+
* `paths` and `baseUrl` are taken from the config, so enumerating the files it
|
|
125
|
+
* includes would only cost time: with no `include`, that is every source file
|
|
126
|
+
* below the config, on every rebuild.
|
|
127
|
+
*/
|
|
128
|
+
const CONFIG_HOST = {
|
|
129
|
+
useCaseSensitiveFileNames: ts.sys.useCaseSensitiveFileNames,
|
|
130
|
+
fileExists: ts.sys.fileExists,
|
|
131
|
+
readFile: ts.sys.readFile,
|
|
132
|
+
readDirectory: () => []
|
|
133
|
+
};
|
|
118
134
|
function resolveTsconfigPaths(entryPointDir) {
|
|
119
135
|
const configPath = ts.findConfigFile(entryPointDir, ts.sys.fileExists, 'tsconfig.json');
|
|
120
136
|
if (!configPath)
|
|
@@ -122,7 +138,7 @@ function resolveTsconfigPaths(entryPointDir) {
|
|
|
122
138
|
const configFile = ts.readConfigFile(configPath, ts.sys.readFile);
|
|
123
139
|
if (configFile.error)
|
|
124
140
|
return {};
|
|
125
|
-
const parsed = ts.parseJsonConfigFileContent(configFile.config,
|
|
141
|
+
const parsed = ts.parseJsonConfigFileContent(configFile.config, CONFIG_HOST, dirname(configPath));
|
|
126
142
|
const result = {};
|
|
127
143
|
if (parsed.options.paths)
|
|
128
144
|
result.paths = parsed.options.paths;
|
|
@@ -136,18 +152,17 @@ function resolveEntryPoints(workspaceRoot, options) {
|
|
|
136
152
|
const entryIsDirectory = isDirectory(absoluteEntryPoint);
|
|
137
153
|
const libraryRoot = entryIsDirectory ? absoluteEntryPoint : findLibraryRoot(absoluteEntryPoint);
|
|
138
154
|
const discovered = libraryRoot ? discoverSecondaryEntryPoints(libraryRoot, options.libraryImportPath) : [];
|
|
139
|
-
//
|
|
140
|
-
//
|
|
141
|
-
//
|
|
142
|
-
|
|
143
|
-
const entryPoints = discovered.
|
|
144
|
-
? [
|
|
145
|
-
{
|
|
146
|
-
entryFile: absoluteEntryPoint,
|
|
147
|
-
importPath: options.libraryImportPath
|
|
148
|
-
}
|
|
149
|
-
]
|
|
155
|
+
// The primary entry point is scanned after the secondary ones: a file entryPoint is
|
|
156
|
+
// the primary itself, a directory names it in its ng-package.json. A root
|
|
157
|
+
// ng-package.json without `dest` is already among the discovered ones.
|
|
158
|
+
const primaryEntryFile = entryIsDirectory ? findPrimaryEntryFile(absoluteEntryPoint) : absoluteEntryPoint;
|
|
159
|
+
const entryPoints = primaryEntryFile && !discovered.some((e) => e.entryFile === primaryEntryFile)
|
|
160
|
+
? [...discovered, { entryFile: primaryEntryFile, importPath: options.libraryImportPath, primary: true }]
|
|
150
161
|
: discovered;
|
|
162
|
+
if (entryPoints.length === 0) {
|
|
163
|
+
console.warn(`⚠ ng-prism: entryPoint "${options.entryPoint}" resolves to no entry file: no ng-package.json with a lib.entryFile ` +
|
|
164
|
+
`that exists, and no secondary entry points below it. Point entryPoint at the library's barrel file.`);
|
|
165
|
+
}
|
|
151
166
|
return { entryPoints, compilerOptions };
|
|
152
167
|
}
|
|
153
168
|
function scanEntryPoints(workspaceRoot, options, state) {
|