UNPKG

9.14 kBJavaScriptView Raw
1"use strict";
2var __importDefault = (this && this.__importDefault) || function (mod) {
3 return (mod && mod.__esModule) ? mod : { "default": mod };
4};
5var _a;
6Object.defineProperty(exports, "__esModule", { value: true });
7exports.PropertyExtractor = exports.uniqueArray = exports.REMOVED_MODULES = exports.reflectionCapabilities = void 0;
8/* eslint-disable no-console */
9const common_1 = require("@angular/common");
10const core_1 = require("@angular/core");
11const platform_browser_1 = require("@angular/platform-browser");
12const animations_1 = require("@angular/platform-browser/animations");
13const ts_dedent_1 = __importDefault(require("ts-dedent"));
14const NgModulesAnalyzer_1 = require("./NgModulesAnalyzer");
15exports.reflectionCapabilities = new core_1.ɵReflectionCapabilities();
16exports.REMOVED_MODULES = new core_1.InjectionToken('REMOVED_MODULES');
17const uniqueArray = (arr) => {
18 return arr
19 .flat(Number.MAX_VALUE)
20 .filter(Boolean)
21 .filter((value, index, self) => self.indexOf(value) === index);
22};
23exports.uniqueArray = uniqueArray;
24class PropertyExtractor {
25 /* eslint-enable @typescript-eslint/lines-between-class-members */
26 constructor(metadata, component) {
27 this.metadata = metadata;
28 this.component = component;
29 /* eslint-disable @typescript-eslint/lines-between-class-members */
30 this.declarations = [];
31 /**
32 * Analyze NgModule Metadata
33 *
34 * - Removes Restricted Imports
35 * - Extracts providers from ModuleWithProviders
36 * - Returns a new NgModuleMetadata object
37 *
38 *
39 */
40 this.analyzeMetadata = (metadata) => {
41 const declarations = [...(metadata?.declarations || [])];
42 const providers = [...(metadata?.providers || [])];
43 const applicationProviders = [];
44 const imports = [...(metadata?.imports || [])].reduce((acc, imported) => {
45 // remove ngModule and use only its providers if it is restricted
46 // (e.g. BrowserModule, BrowserAnimationsModule, NoopAnimationsModule, ...etc)
47 const [isRestricted, restrictedProviders] = PropertyExtractor.analyzeRestricted(imported);
48 if (isRestricted) {
49 applicationProviders.unshift(restrictedProviders || []);
50 return acc;
51 }
52 acc.push(imported);
53 return acc;
54 }, []);
55 return { ...metadata, imports, providers, applicationProviders, declarations };
56 };
57 this.init();
58 }
59 // With the new way of mounting standalone components to the DOM via bootstrapApplication API,
60 // we should now pass ModuleWithProviders to the providers array of the bootstrapApplication function.
61 static warnImportsModuleWithProviders(propertyExtractor) {
62 const hasModuleWithProvidersImport = propertyExtractor.imports.some((importedModule) => 'ngModule' in importedModule);
63 if (hasModuleWithProvidersImport) {
64 console.warn((0, ts_dedent_1.default)(`
65 Storybook Warning:
66 moduleMetadata property 'imports' contains one or more ModuleWithProviders, likely the result of a 'Module.forRoot()'-style call.
67 In Storybook 7.0 we use Angular's new 'bootstrapApplication' API to mount the component to the DOM, which accepts a list of providers to set up application-wide providers.
68 Use the 'applicationConfig' decorator from '@storybook/angular' to pass your ModuleWithProviders to the 'providers' property in combination with the importProvidersFrom helper function from '@angular/core' to extract all the necessary providers.
69 Visit https://angular.io/guide/standalone-components#configuring-dependency-injection for more information
70 `));
71 }
72 }
73 init() {
74 const analyzed = this.analyzeMetadata(this.metadata);
75 this.imports = (0, exports.uniqueArray)([common_1.CommonModule, analyzed.imports]);
76 this.providers = (0, exports.uniqueArray)(analyzed.providers);
77 this.applicationProviders = (0, exports.uniqueArray)(analyzed.applicationProviders);
78 this.declarations = (0, exports.uniqueArray)(analyzed.declarations);
79 if (this.component) {
80 const { isDeclarable, isStandalone } = PropertyExtractor.analyzeDecorators(this.component);
81 const isDeclared = (0, NgModulesAnalyzer_1.isComponentAlreadyDeclared)(this.component, analyzed.declarations, this.imports);
82 if (isStandalone) {
83 this.imports.push(this.component);
84 }
85 else if (isDeclarable && !isDeclared) {
86 this.declarations.push(this.component);
87 }
88 }
89 }
90}
91exports.PropertyExtractor = PropertyExtractor;
92_a = PropertyExtractor;
93PropertyExtractor.analyzeRestricted = (ngModule) => {
94 if (ngModule === platform_browser_1.BrowserModule) {
95 console.warn((0, ts_dedent_1.default) `
96 Storybook Warning:
97 You have imported the "BrowserModule", which is not necessary anymore.
98 In Storybook v7.0 we are using Angular's new bootstrapApplication API to mount an Angular application to the DOM.
99 Note that the BrowserModule providers are automatically included when starting an application with bootstrapApplication()
100 Please remove the "BrowserModule" from the list of imports in your moduleMetadata definition to remove this warning.
101 `);
102 return [true];
103 }
104 if (ngModule === animations_1.BrowserAnimationsModule) {
105 console.warn((0, ts_dedent_1.default) `
106 Storybook Warning:
107 You have added the "BrowserAnimationsModule" to the list of "imports" in your moduleMetadata definition of your Story.
108 In Storybook 7.0 we use Angular's new 'bootstrapApplication' API to mount the component to the DOM, which accepts a list of providers to set up application-wide providers.
109 Use the 'applicationConfig' decorator from '@storybook/angular' and add the "provideAnimations" function to the list of "providers".
110 If your Angular version does not support "provide-like" functions, use the helper function importProvidersFrom instead to set up animations. For this case, please add "importProvidersFrom(BrowserAnimationsModule)" to the list of providers of your applicationConfig definition.
111 Please visit https://angular.io/guide/standalone-components#configuring-dependency-injection for more information.
112 `);
113 return [true, (0, animations_1.provideAnimations)()];
114 }
115 if (ngModule === animations_1.NoopAnimationsModule) {
116 console.warn((0, ts_dedent_1.default) `
117 Storybook Warning:
118 You have added the "NoopAnimationsModule" to the list of "imports" in your moduleMetadata definition of your Story.
119 In Storybook v7.0 we are using Angular's new bootstrapApplication API to mount an Angular application to the DOM, which accepts a list of providers to set up application-wide providers.
120 Use the 'applicationConfig' decorator from '@storybook/angular' and add the "provideNoopAnimations" function to the list of "providers".
121 If your Angular version does not support "provide-like" functions, use the helper function importProvidersFrom instead to set up noop animations and to extract all necessary providers from NoopAnimationsModule. For this case, please add "importProvidersFrom(NoopAnimationsModule)" to the list of providers of your applicationConfig definition.
122 Please visit https://angular.io/guide/standalone-components#configuring-dependency-injection for more information.
123 `);
124 return [true, (0, animations_1.provideNoopAnimations)()];
125 }
126 return [false];
127};
128PropertyExtractor.analyzeDecorators = (component) => {
129 const decorators = exports.reflectionCapabilities.annotations(component);
130 const isComponent = decorators.some((d) => _a.isDecoratorInstanceOf(d, 'Component'));
131 const isDirective = decorators.some((d) => _a.isDecoratorInstanceOf(d, 'Directive'));
132 const isPipe = decorators.some((d) => _a.isDecoratorInstanceOf(d, 'Pipe'));
133 const isDeclarable = isComponent || isDirective || isPipe;
134 const isStandalone = isComponent && decorators.some((d) => d.standalone);
135 return { isDeclarable, isStandalone };
136};
137PropertyExtractor.isDecoratorInstanceOf = (decorator, name) => {
138 let factory;
139 switch (name) {
140 case 'Component':
141 factory = core_1.Component;
142 break;
143 case 'Directive':
144 factory = core_1.Directive;
145 break;
146 case 'Pipe':
147 factory = core_1.Pipe;
148 break;
149 case 'Injectable':
150 factory = core_1.Injectable;
151 break;
152 case 'Input':
153 factory = core_1.Input;
154 break;
155 case 'Output':
156 factory = core_1.Output;
157 break;
158 default:
159 throw new Error(`Unknown decorator type: ${name}`);
160 }
161 return decorator instanceof factory || decorator.ngMetadataName === name;
162};