@storybook/angular 9.0.0-beta.6 → 9.0.0-beta.7
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/dist/builders/build-storybook/index.mjs +78 -0
- package/dist/builders/build-storybook/index.spec.mjs +187 -0
- package/dist/builders/start-storybook/index.mjs +99 -0
- package/dist/builders/start-storybook/index.spec.mjs +186 -0
- package/dist/builders/utils/error-handler.mjs +33 -0
- package/dist/builders/utils/run-compodoc.mjs +31 -0
- package/dist/builders/utils/run-compodoc.spec.mjs +74 -0
- package/dist/builders/utils/standalone-options.mjs +1 -0
- package/dist/client/angular-beta/AbstractRenderer.mjs +164 -0
- package/dist/client/angular-beta/CanvasRenderer.mjs +9 -0
- package/dist/client/angular-beta/ComputesTemplateFromComponent.mjs +154 -0
- package/dist/client/angular-beta/ComputesTemplateFromComponent.test.mjs +728 -0
- package/dist/client/angular-beta/DocsRenderer.mjs +35 -0
- package/dist/client/angular-beta/RendererFactory.mjs +50 -0
- package/dist/client/angular-beta/RendererFactory.test.mjs +233 -0
- package/dist/client/angular-beta/StorybookModule.mjs +23 -0
- package/dist/client/angular-beta/StorybookModule.test.mjs +319 -0
- package/dist/client/angular-beta/StorybookProvider.mjs +22 -0
- package/dist/client/angular-beta/StorybookWrapperComponent.mjs +123 -0
- package/dist/client/angular-beta/__testfixtures__/input.component.mjs +73 -0
- package/dist/client/angular-beta/__testfixtures__/test.module.mjs +17 -0
- package/dist/client/angular-beta/utils/BootstrapQueue.mjs +49 -0
- package/dist/client/angular-beta/utils/BootstrapQueue.test.mjs +162 -0
- package/dist/client/angular-beta/utils/NgComponentAnalyzer.mjs +84 -0
- package/dist/client/angular-beta/utils/NgComponentAnalyzer.test.mjs +386 -0
- package/dist/client/angular-beta/utils/NgModulesAnalyzer.mjs +37 -0
- package/dist/client/angular-beta/utils/NgModulesAnalyzer.test.mjs +22 -0
- package/dist/client/angular-beta/utils/PropertyExtractor.mjs +158 -0
- package/dist/client/angular-beta/utils/PropertyExtractor.test.mjs +175 -0
- package/dist/client/angular-beta/utils/StoryUID.mjs +38 -0
- package/dist/client/argsToTemplate.mjs +55 -0
- package/dist/client/argsToTemplate.test.mjs +100 -0
- package/dist/client/config.mjs +4 -0
- package/dist/client/decorateStory.mjs +45 -0
- package/dist/client/decorateStory.test.mjs +301 -0
- package/dist/client/decorators.mjs +63 -0
- package/dist/client/decorators.test.mjs +157 -0
- package/dist/client/docs/__testfixtures__/doc-button/input.mjs +201 -0
- package/dist/client/docs/angular-properties.test.mjs +34 -0
- package/dist/client/docs/compodoc.mjs +244 -0
- package/dist/client/docs/compodoc.test.mjs +130 -0
- package/dist/client/docs/config.mjs +16 -0
- package/dist/client/docs/index.mjs +1 -0
- package/dist/client/docs/sourceDecorator.mjs +48 -0
- package/dist/client/docs/types.mjs +1 -0
- package/dist/client/globals.mjs +31 -0
- package/dist/client/index.mjs +9 -0
- package/dist/client/portable-stories.mjs +26 -0
- package/dist/client/preview-prod.mjs +2 -0
- package/dist/client/public-types.mjs +1 -0
- package/dist/client/render.mjs +14 -0
- package/dist/client/types.mjs +1 -0
- package/dist/node/index.mjs +3 -0
- package/dist/server/__mocks-ng-workspace__/minimal-config/src/main.mjs +2 -0
- package/dist/server/__mocks-ng-workspace__/some-config/src/main.mjs +2 -0
- package/dist/server/__mocks-ng-workspace__/with-angularBrowserTarget/src/main.mjs +2 -0
- package/dist/server/__mocks-ng-workspace__/with-lib/projects/pattern-lib/src/main.mjs +2 -0
- package/dist/server/__mocks-ng-workspace__/with-nx/src/main.mjs +2 -0
- package/dist/server/__mocks-ng-workspace__/with-nx-workspace/src/main.mjs +2 -0
- package/dist/server/__mocks-ng-workspace__/with-options-styles/src/main.mjs +2 -0
- package/dist/server/__mocks-ng-workspace__/without-projects-entry/projects/pattern-lib/src/main.mjs +2 -0
- package/dist/server/__mocks-ng-workspace__/without-tsConfig/src/main.mjs +2 -0
- package/dist/server/angular-cli-webpack.mjs +80 -0
- package/dist/server/framework-preset-angular-cli.mjs +81 -0
- package/dist/server/framework-preset-angular-docs.mjs +6 -0
- package/dist/server/framework-preset-angular-ivy.mjs +56 -0
- package/dist/server/plugins/storybook-normalize-angular-entry-plugin.mjs +52 -0
- package/dist/server/preset-options.mjs +1 -0
- package/dist/server/utils/filter-out-styling-rules.mjs +13 -0
- package/dist/server/utils/module-is-available.mjs +9 -0
- package/package.json +4 -4
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { getEnvConfig, versions } from 'storybook/internal/common';
|
|
2
|
+
import { buildStaticStandalone, withTelemetry } from 'storybook/internal/core-server';
|
|
3
|
+
import { addToGlobalContext } from 'storybook/internal/telemetry';
|
|
4
|
+
import { createBuilder, targetFromTargetString, } from '@angular-devkit/architect';
|
|
5
|
+
import { findPackageSync } from 'fd-package-json';
|
|
6
|
+
import { sync as findUpSync } from 'find-up';
|
|
7
|
+
import { from, of, throwError } from 'rxjs';
|
|
8
|
+
import { catchError, map, mapTo, switchMap } from 'rxjs/operators';
|
|
9
|
+
import { errorSummary, printErrorDetails } from '../utils/error-handler';
|
|
10
|
+
import { runCompodoc } from '../utils/run-compodoc';
|
|
11
|
+
addToGlobalContext('cliVersion', versions.storybook);
|
|
12
|
+
const commandBuilder = (options, context) => {
|
|
13
|
+
const builder = from(setup(options, context)).pipe(switchMap(({ tsConfig }) => {
|
|
14
|
+
const docTSConfig = findUpSync('tsconfig.doc.json', { cwd: options.configDir });
|
|
15
|
+
const runCompodoc$ = options.compodoc
|
|
16
|
+
? runCompodoc({ compodocArgs: options.compodocArgs, tsconfig: docTSConfig ?? tsConfig }, context).pipe(mapTo({ tsConfig }))
|
|
17
|
+
: of({});
|
|
18
|
+
return runCompodoc$.pipe(mapTo({ tsConfig }));
|
|
19
|
+
}), map(({ tsConfig }) => {
|
|
20
|
+
getEnvConfig(options, {
|
|
21
|
+
staticDir: 'SBCONFIG_STATIC_DIR',
|
|
22
|
+
outputDir: 'SBCONFIG_OUTPUT_DIR',
|
|
23
|
+
configDir: 'SBCONFIG_CONFIG_DIR',
|
|
24
|
+
});
|
|
25
|
+
const { browserTarget, stylePreprocessorOptions, styles, configDir, docs, loglevel, test, outputDir, quiet, enableProdMode = true, webpackStatsJson, statsJson, debugWebpack, disableTelemetry, assets, previewUrl, sourceMap = false, preserveSymlinks = false, experimentalZoneless = false, } = options;
|
|
26
|
+
const standaloneOptions = {
|
|
27
|
+
packageJson: findPackageSync(__dirname),
|
|
28
|
+
configDir,
|
|
29
|
+
...(docs ? { docs } : {}),
|
|
30
|
+
loglevel,
|
|
31
|
+
outputDir,
|
|
32
|
+
test,
|
|
33
|
+
quiet,
|
|
34
|
+
enableProdMode,
|
|
35
|
+
disableTelemetry,
|
|
36
|
+
angularBrowserTarget: browserTarget,
|
|
37
|
+
angularBuilderContext: context,
|
|
38
|
+
angularBuilderOptions: {
|
|
39
|
+
...(stylePreprocessorOptions ? { stylePreprocessorOptions } : {}),
|
|
40
|
+
...(styles ? { styles } : {}),
|
|
41
|
+
...(assets ? { assets } : {}),
|
|
42
|
+
sourceMap,
|
|
43
|
+
preserveSymlinks,
|
|
44
|
+
experimentalZoneless,
|
|
45
|
+
},
|
|
46
|
+
tsConfig,
|
|
47
|
+
webpackStatsJson,
|
|
48
|
+
statsJson,
|
|
49
|
+
debugWebpack,
|
|
50
|
+
previewUrl,
|
|
51
|
+
};
|
|
52
|
+
return standaloneOptions;
|
|
53
|
+
}), switchMap((standaloneOptions) => runInstance({ ...standaloneOptions, mode: 'static' })), map(() => {
|
|
54
|
+
return { success: true };
|
|
55
|
+
}));
|
|
56
|
+
return builder;
|
|
57
|
+
};
|
|
58
|
+
export default createBuilder(commandBuilder);
|
|
59
|
+
async function setup(options, context) {
|
|
60
|
+
let browserOptions;
|
|
61
|
+
let browserTarget;
|
|
62
|
+
if (options.browserTarget) {
|
|
63
|
+
browserTarget = targetFromTargetString(options.browserTarget);
|
|
64
|
+
browserOptions = await context.validateOptions(await context.getTargetOptions(browserTarget), await context.getBuilderNameForTarget(browserTarget));
|
|
65
|
+
}
|
|
66
|
+
return {
|
|
67
|
+
tsConfig: options.tsConfig ??
|
|
68
|
+
findUpSync('tsconfig.json', { cwd: options.configDir }) ??
|
|
69
|
+
browserOptions.tsConfig,
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
function runInstance(options) {
|
|
73
|
+
return from(withTelemetry('build', {
|
|
74
|
+
cliOptions: options,
|
|
75
|
+
presetOptions: { ...options, corePresets: [], overridePresets: [] },
|
|
76
|
+
printError: printErrorDetails,
|
|
77
|
+
}, () => buildStaticStandalone(options))).pipe(catchError((error) => throwError(errorSummary(error))));
|
|
78
|
+
}
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
import { Architect, createBuilder } from '@angular-devkit/architect';
|
|
2
|
+
import { TestingArchitectHost } from '@angular-devkit/architect/testing';
|
|
3
|
+
import { schema } from '@angular-devkit/core';
|
|
4
|
+
import * as path from 'node:path';
|
|
5
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
6
|
+
const buildDevStandaloneMock = vi.fn();
|
|
7
|
+
const buildStaticStandaloneMock = vi.fn();
|
|
8
|
+
const buildMock = {
|
|
9
|
+
buildDevStandalone: buildDevStandaloneMock,
|
|
10
|
+
buildStaticStandalone: buildStaticStandaloneMock,
|
|
11
|
+
withTelemetry: (name, options, fn) => fn(),
|
|
12
|
+
};
|
|
13
|
+
vi.doMock('storybook/internal/core-server', () => buildMock);
|
|
14
|
+
vi.doMock('storybook/internal/common', () => ({
|
|
15
|
+
JsPackageManagerFactory: {
|
|
16
|
+
getPackageManager: () => ({
|
|
17
|
+
runPackageCommand: mockRunScript,
|
|
18
|
+
}),
|
|
19
|
+
},
|
|
20
|
+
getEnvConfig: (options) => options,
|
|
21
|
+
versions: {
|
|
22
|
+
storybook: 'x.x.x',
|
|
23
|
+
},
|
|
24
|
+
}));
|
|
25
|
+
vi.doMock('find-up', () => ({ sync: () => './storybook/tsconfig.ts' }));
|
|
26
|
+
const mockRunScript = vi.fn();
|
|
27
|
+
// Randomly fails on CI. TODO: investigate why
|
|
28
|
+
describe.skip('Build Storybook Builder', () => {
|
|
29
|
+
let architect;
|
|
30
|
+
let architectHost;
|
|
31
|
+
beforeEach(async () => {
|
|
32
|
+
const registry = new schema.CoreSchemaRegistry();
|
|
33
|
+
registry.addPostTransform(schema.transforms.addUndefinedDefaults);
|
|
34
|
+
architectHost = new TestingArchitectHost();
|
|
35
|
+
architect = new Architect(architectHost, registry);
|
|
36
|
+
architectHost.addBuilder('@angular-devkit/build-angular:browser', createBuilder(() => {
|
|
37
|
+
return { success: true };
|
|
38
|
+
}));
|
|
39
|
+
architectHost.addTarget({ project: 'angular-cli', target: 'build-2' }, '@angular-devkit/build-angular:browser', {
|
|
40
|
+
outputPath: 'dist/angular-cli',
|
|
41
|
+
index: 'src/index.html',
|
|
42
|
+
main: 'src/main.ts',
|
|
43
|
+
polyfills: 'src/polyfills.ts',
|
|
44
|
+
tsConfig: 'src/tsconfig.app.json',
|
|
45
|
+
assets: ['src/favicon.ico', 'src/assets'],
|
|
46
|
+
styles: ['src/styles.css'],
|
|
47
|
+
scripts: [],
|
|
48
|
+
});
|
|
49
|
+
// This will either take a Node package name, or a path to the directory
|
|
50
|
+
// for the package.json file.
|
|
51
|
+
await architectHost.addBuilderFromPackage(path.join(__dirname, '../../..'));
|
|
52
|
+
});
|
|
53
|
+
beforeEach(() => {
|
|
54
|
+
buildStaticStandaloneMock.mockImplementation((_options) => Promise.resolve(_options));
|
|
55
|
+
});
|
|
56
|
+
afterEach(() => {
|
|
57
|
+
vi.clearAllMocks();
|
|
58
|
+
});
|
|
59
|
+
it('should start storybook with angularBrowserTarget', async () => {
|
|
60
|
+
const run = await architect.scheduleBuilder('@storybook/angular:build-storybook', {
|
|
61
|
+
browserTarget: 'angular-cli:build-2',
|
|
62
|
+
compodoc: false,
|
|
63
|
+
});
|
|
64
|
+
const output = await run.result;
|
|
65
|
+
await run.stop();
|
|
66
|
+
expect(output.success).toBeTruthy();
|
|
67
|
+
expect(mockRunScript).not.toHaveBeenCalledWith();
|
|
68
|
+
expect(buildStaticStandaloneMock).toHaveBeenCalledWith(expect.objectContaining({
|
|
69
|
+
angularBrowserTarget: 'angular-cli:build-2',
|
|
70
|
+
angularBuilderContext: expect.any(Object),
|
|
71
|
+
configDir: '.storybook',
|
|
72
|
+
loglevel: undefined,
|
|
73
|
+
quiet: false,
|
|
74
|
+
disableTelemetry: undefined,
|
|
75
|
+
outputDir: 'storybook-static',
|
|
76
|
+
packageJson: expect.any(Object),
|
|
77
|
+
mode: 'static',
|
|
78
|
+
tsConfig: './storybook/tsconfig.ts',
|
|
79
|
+
statsJson: false,
|
|
80
|
+
}));
|
|
81
|
+
});
|
|
82
|
+
it('should start storybook with tsConfig', async () => {
|
|
83
|
+
const run = await architect.scheduleBuilder('@storybook/angular:build-storybook', {
|
|
84
|
+
tsConfig: 'path/to/tsConfig.json',
|
|
85
|
+
compodoc: false,
|
|
86
|
+
});
|
|
87
|
+
const output = await run.result;
|
|
88
|
+
await run.stop();
|
|
89
|
+
expect(output.success).toBeTruthy();
|
|
90
|
+
expect(mockRunScript).not.toHaveBeenCalledWith();
|
|
91
|
+
expect(buildStaticStandaloneMock).toHaveBeenCalledWith(expect.objectContaining({
|
|
92
|
+
angularBrowserTarget: null,
|
|
93
|
+
angularBuilderContext: expect.any(Object),
|
|
94
|
+
configDir: '.storybook',
|
|
95
|
+
loglevel: undefined,
|
|
96
|
+
quiet: false,
|
|
97
|
+
disableTelemetry: undefined,
|
|
98
|
+
outputDir: 'storybook-static',
|
|
99
|
+
packageJson: expect.any(Object),
|
|
100
|
+
mode: 'static',
|
|
101
|
+
tsConfig: 'path/to/tsConfig.json',
|
|
102
|
+
statsJson: false,
|
|
103
|
+
}));
|
|
104
|
+
});
|
|
105
|
+
it('should build storybook with webpack stats.json', async () => {
|
|
106
|
+
const run = await architect.scheduleBuilder('@storybook/angular:build-storybook', {
|
|
107
|
+
tsConfig: 'path/to/tsConfig.json',
|
|
108
|
+
compodoc: false,
|
|
109
|
+
statsJson: true,
|
|
110
|
+
});
|
|
111
|
+
const output = await run.result;
|
|
112
|
+
await run.stop();
|
|
113
|
+
expect(output.success).toBeTruthy();
|
|
114
|
+
expect(mockRunScript).not.toHaveBeenCalledWith();
|
|
115
|
+
expect(buildStaticStandaloneMock).toHaveBeenCalledWith(expect.objectContaining({
|
|
116
|
+
angularBrowserTarget: null,
|
|
117
|
+
angularBuilderContext: expect.any(Object),
|
|
118
|
+
configDir: '.storybook',
|
|
119
|
+
loglevel: undefined,
|
|
120
|
+
quiet: false,
|
|
121
|
+
outputDir: 'storybook-static',
|
|
122
|
+
packageJson: expect.any(Object),
|
|
123
|
+
mode: 'static',
|
|
124
|
+
tsConfig: 'path/to/tsConfig.json',
|
|
125
|
+
statsJson: true,
|
|
126
|
+
}));
|
|
127
|
+
});
|
|
128
|
+
it('should throw error', async () => {
|
|
129
|
+
buildStaticStandaloneMock.mockRejectedValue(true);
|
|
130
|
+
const run = await architect.scheduleBuilder('@storybook/angular:build-storybook', {
|
|
131
|
+
browserTarget: 'angular-cli:build-2',
|
|
132
|
+
compodoc: false,
|
|
133
|
+
});
|
|
134
|
+
try {
|
|
135
|
+
await run.result;
|
|
136
|
+
expect(false).toEqual('Throw expected');
|
|
137
|
+
}
|
|
138
|
+
catch (error) {
|
|
139
|
+
expect(error).toEqual('Broken build, fix the error above.\nYou may need to refresh the browser.');
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
it('should run compodoc', async () => {
|
|
143
|
+
const run = await architect.scheduleBuilder('@storybook/angular:build-storybook', {
|
|
144
|
+
browserTarget: 'angular-cli:build-2',
|
|
145
|
+
});
|
|
146
|
+
const output = await run.result;
|
|
147
|
+
await run.stop();
|
|
148
|
+
expect(output.success).toBeTruthy();
|
|
149
|
+
expect(mockRunScript).toHaveBeenCalledWith('compodoc', ['-p', './storybook/tsconfig.ts', '-d', '.', '-e', 'json'], '');
|
|
150
|
+
expect(buildStaticStandaloneMock).toHaveBeenCalledWith(expect.objectContaining({
|
|
151
|
+
angularBrowserTarget: 'angular-cli:build-2',
|
|
152
|
+
angularBuilderContext: expect.any(Object),
|
|
153
|
+
configDir: '.storybook',
|
|
154
|
+
loglevel: undefined,
|
|
155
|
+
quiet: false,
|
|
156
|
+
outputDir: 'storybook-static',
|
|
157
|
+
packageJson: expect.any(Object),
|
|
158
|
+
mode: 'static',
|
|
159
|
+
tsConfig: './storybook/tsconfig.ts',
|
|
160
|
+
statsJson: false,
|
|
161
|
+
}));
|
|
162
|
+
});
|
|
163
|
+
it('should start storybook with styles options', async () => {
|
|
164
|
+
const run = await architect.scheduleBuilder('@storybook/angular:build-storybook', {
|
|
165
|
+
tsConfig: 'path/to/tsConfig.json',
|
|
166
|
+
compodoc: false,
|
|
167
|
+
styles: ['style.scss'],
|
|
168
|
+
});
|
|
169
|
+
const output = await run.result;
|
|
170
|
+
await run.stop();
|
|
171
|
+
expect(output.success).toBeTruthy();
|
|
172
|
+
expect(mockRunScript).not.toHaveBeenCalledWith();
|
|
173
|
+
expect(buildStaticStandaloneMock).toHaveBeenCalledWith(expect.objectContaining({
|
|
174
|
+
angularBrowserTarget: null,
|
|
175
|
+
angularBuilderContext: expect.any(Object),
|
|
176
|
+
angularBuilderOptions: { assets: [], styles: ['style.scss'] },
|
|
177
|
+
configDir: '.storybook',
|
|
178
|
+
loglevel: undefined,
|
|
179
|
+
quiet: false,
|
|
180
|
+
outputDir: 'storybook-static',
|
|
181
|
+
packageJson: expect.any(Object),
|
|
182
|
+
mode: 'static',
|
|
183
|
+
tsConfig: 'path/to/tsConfig.json',
|
|
184
|
+
statsJson: false,
|
|
185
|
+
}));
|
|
186
|
+
});
|
|
187
|
+
});
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { getEnvConfig, versions } from 'storybook/internal/common';
|
|
2
|
+
import { buildDevStandalone, withTelemetry } from 'storybook/internal/core-server';
|
|
3
|
+
import { addToGlobalContext } from 'storybook/internal/telemetry';
|
|
4
|
+
import { createBuilder, targetFromTargetString, } from '@angular-devkit/architect';
|
|
5
|
+
import { findPackageSync } from 'fd-package-json';
|
|
6
|
+
import { sync as findUpSync } from 'find-up';
|
|
7
|
+
import { Observable, from, of } from 'rxjs';
|
|
8
|
+
import { map, mapTo, switchMap } from 'rxjs/operators';
|
|
9
|
+
import { errorSummary, printErrorDetails } from '../utils/error-handler';
|
|
10
|
+
import { runCompodoc } from '../utils/run-compodoc';
|
|
11
|
+
addToGlobalContext('cliVersion', versions.storybook);
|
|
12
|
+
const commandBuilder = (options, context) => {
|
|
13
|
+
const builder = from(setup(options, context)).pipe(switchMap(({ tsConfig }) => {
|
|
14
|
+
const docTSConfig = findUpSync('tsconfig.doc.json', { cwd: options.configDir });
|
|
15
|
+
const runCompodoc$ = options.compodoc
|
|
16
|
+
? runCompodoc({
|
|
17
|
+
compodocArgs: [...options.compodocArgs, ...(options.quiet ? ['--silent'] : [])],
|
|
18
|
+
tsconfig: docTSConfig ?? tsConfig,
|
|
19
|
+
}, context).pipe(mapTo({ tsConfig }))
|
|
20
|
+
: of({});
|
|
21
|
+
return runCompodoc$.pipe(mapTo({ tsConfig }));
|
|
22
|
+
}), map(({ tsConfig }) => {
|
|
23
|
+
getEnvConfig(options, {
|
|
24
|
+
port: 'SBCONFIG_PORT',
|
|
25
|
+
host: 'SBCONFIG_HOSTNAME',
|
|
26
|
+
staticDir: 'SBCONFIG_STATIC_DIR',
|
|
27
|
+
configDir: 'SBCONFIG_CONFIG_DIR',
|
|
28
|
+
ci: 'CI',
|
|
29
|
+
});
|
|
30
|
+
options.port = parseInt(`${options.port}`, 10);
|
|
31
|
+
const { browserTarget, stylePreprocessorOptions, styles, ci, configDir, docs, host, https, port, quiet, enableProdMode = false, smokeTest, sslCa, sslCert, sslKey, disableTelemetry, assets, initialPath, open, debugWebpack, loglevel, webpackStatsJson, statsJson, previewUrl, sourceMap = false, preserveSymlinks = false, experimentalZoneless = false, } = options;
|
|
32
|
+
const standaloneOptions = {
|
|
33
|
+
packageJson: findPackageSync(__dirname),
|
|
34
|
+
ci,
|
|
35
|
+
configDir,
|
|
36
|
+
...(docs ? { docs } : {}),
|
|
37
|
+
host,
|
|
38
|
+
https,
|
|
39
|
+
port,
|
|
40
|
+
quiet,
|
|
41
|
+
enableProdMode,
|
|
42
|
+
smokeTest,
|
|
43
|
+
sslCa,
|
|
44
|
+
sslCert,
|
|
45
|
+
sslKey,
|
|
46
|
+
disableTelemetry,
|
|
47
|
+
angularBrowserTarget: browserTarget,
|
|
48
|
+
angularBuilderContext: context,
|
|
49
|
+
angularBuilderOptions: {
|
|
50
|
+
...(stylePreprocessorOptions ? { stylePreprocessorOptions } : {}),
|
|
51
|
+
...(styles ? { styles } : {}),
|
|
52
|
+
...(assets ? { assets } : {}),
|
|
53
|
+
preserveSymlinks,
|
|
54
|
+
sourceMap,
|
|
55
|
+
experimentalZoneless,
|
|
56
|
+
},
|
|
57
|
+
tsConfig,
|
|
58
|
+
initialPath,
|
|
59
|
+
open,
|
|
60
|
+
debugWebpack,
|
|
61
|
+
webpackStatsJson,
|
|
62
|
+
statsJson,
|
|
63
|
+
loglevel,
|
|
64
|
+
previewUrl,
|
|
65
|
+
};
|
|
66
|
+
return standaloneOptions;
|
|
67
|
+
}), switchMap((standaloneOptions) => runInstance(standaloneOptions)), map((port) => {
|
|
68
|
+
return { success: true, info: { port } };
|
|
69
|
+
}));
|
|
70
|
+
return builder;
|
|
71
|
+
};
|
|
72
|
+
export default createBuilder(commandBuilder);
|
|
73
|
+
async function setup(options, context) {
|
|
74
|
+
let browserOptions;
|
|
75
|
+
let browserTarget;
|
|
76
|
+
if (options.browserTarget) {
|
|
77
|
+
browserTarget = targetFromTargetString(options.browserTarget);
|
|
78
|
+
browserOptions = await context.validateOptions(await context.getTargetOptions(browserTarget), await context.getBuilderNameForTarget(browserTarget));
|
|
79
|
+
}
|
|
80
|
+
return {
|
|
81
|
+
tsConfig: options.tsConfig ??
|
|
82
|
+
findUpSync('tsconfig.json', { cwd: options.configDir }) ??
|
|
83
|
+
browserOptions.tsConfig,
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
function runInstance(options) {
|
|
87
|
+
return new Observable((observer) => {
|
|
88
|
+
// This Observable intentionally never complete, leaving the process running ;)
|
|
89
|
+
withTelemetry('dev', {
|
|
90
|
+
cliOptions: options,
|
|
91
|
+
presetOptions: { ...options, corePresets: [], overridePresets: [] },
|
|
92
|
+
printError: printErrorDetails,
|
|
93
|
+
}, () => buildDevStandalone(options))
|
|
94
|
+
.then(({ port }) => observer.next(port))
|
|
95
|
+
.catch((error) => {
|
|
96
|
+
observer.error(errorSummary(error));
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
}
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
import { Architect, createBuilder } from '@angular-devkit/architect';
|
|
2
|
+
import { TestingArchitectHost } from '@angular-devkit/architect/testing';
|
|
3
|
+
import { schema } from '@angular-devkit/core';
|
|
4
|
+
import { join } from 'node:path';
|
|
5
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
6
|
+
const buildDevStandaloneMock = vi.fn();
|
|
7
|
+
const buildStaticStandaloneMock = vi.fn();
|
|
8
|
+
const buildMock = {
|
|
9
|
+
buildDevStandalone: buildDevStandaloneMock,
|
|
10
|
+
buildStaticStandalone: buildStaticStandaloneMock,
|
|
11
|
+
withTelemetry: (_, __, fn) => fn(),
|
|
12
|
+
};
|
|
13
|
+
vi.doMock('storybook/internal/core-server', () => buildMock);
|
|
14
|
+
vi.doMock('find-up', () => ({ sync: () => './storybook/tsconfig.ts' }));
|
|
15
|
+
const mockRunScript = vi.fn();
|
|
16
|
+
vi.mock('storybook/internal/common', () => ({
|
|
17
|
+
getEnvConfig: (options) => options,
|
|
18
|
+
versions: {
|
|
19
|
+
storybook: 'x.x.x',
|
|
20
|
+
},
|
|
21
|
+
JsPackageManagerFactory: {
|
|
22
|
+
getPackageManager: () => ({
|
|
23
|
+
runPackageCommand: mockRunScript,
|
|
24
|
+
}),
|
|
25
|
+
},
|
|
26
|
+
}));
|
|
27
|
+
// Randomly fails on CI. TODO: investigate why
|
|
28
|
+
describe.skip('Start Storybook Builder', () => {
|
|
29
|
+
let architect;
|
|
30
|
+
let architectHost;
|
|
31
|
+
beforeEach(async () => {
|
|
32
|
+
const registry = new schema.CoreSchemaRegistry();
|
|
33
|
+
registry.addPostTransform(schema.transforms.addUndefinedDefaults);
|
|
34
|
+
architectHost = new TestingArchitectHost();
|
|
35
|
+
architect = new Architect(architectHost, registry);
|
|
36
|
+
architectHost.addBuilder('@angular-devkit/build-angular:browser', createBuilder(() => {
|
|
37
|
+
return { success: true };
|
|
38
|
+
}));
|
|
39
|
+
architectHost.addTarget({ project: 'angular-cli', target: 'build-2' }, '@angular-devkit/build-angular:browser', {
|
|
40
|
+
outputPath: 'dist/angular-cli',
|
|
41
|
+
index: 'src/index.html',
|
|
42
|
+
main: 'src/main.ts',
|
|
43
|
+
polyfills: 'src/polyfills.ts',
|
|
44
|
+
tsConfig: 'src/tsconfig.app.json',
|
|
45
|
+
assets: ['src/favicon.ico', 'src/assets'],
|
|
46
|
+
styles: ['src/styles.css'],
|
|
47
|
+
scripts: [],
|
|
48
|
+
});
|
|
49
|
+
// This will either take a Node package name, or a path to the directory
|
|
50
|
+
// for the package.json file.
|
|
51
|
+
await architectHost.addBuilderFromPackage(join(__dirname, '../../..'));
|
|
52
|
+
});
|
|
53
|
+
beforeEach(() => {
|
|
54
|
+
buildDevStandaloneMock.mockImplementation((_options) => Promise.resolve(_options));
|
|
55
|
+
});
|
|
56
|
+
afterEach(() => {
|
|
57
|
+
vi.clearAllMocks();
|
|
58
|
+
});
|
|
59
|
+
it('should start storybook with angularBrowserTarget', async () => {
|
|
60
|
+
const run = await architect.scheduleBuilder('@storybook/angular:start-storybook', {
|
|
61
|
+
browserTarget: 'angular-cli:build-2',
|
|
62
|
+
port: 4400,
|
|
63
|
+
compodoc: false,
|
|
64
|
+
});
|
|
65
|
+
const output = await run.result;
|
|
66
|
+
await run.stop();
|
|
67
|
+
expect(output.success).toBeTruthy();
|
|
68
|
+
expect(mockRunScript).not.toHaveBeenCalledWith();
|
|
69
|
+
expect(buildDevStandaloneMock).toHaveBeenCalledWith(expect.objectContaining({
|
|
70
|
+
angularBrowserTarget: 'angular-cli:build-2',
|
|
71
|
+
angularBuilderContext: expect.any(Object),
|
|
72
|
+
ci: false,
|
|
73
|
+
configDir: '.storybook',
|
|
74
|
+
disableTelemetry: undefined,
|
|
75
|
+
host: 'localhost',
|
|
76
|
+
https: false,
|
|
77
|
+
packageJson: expect.any(Object),
|
|
78
|
+
port: 4400,
|
|
79
|
+
quiet: false,
|
|
80
|
+
smokeTest: false,
|
|
81
|
+
sslCa: undefined,
|
|
82
|
+
sslCert: undefined,
|
|
83
|
+
sslKey: undefined,
|
|
84
|
+
tsConfig: './storybook/tsconfig.ts',
|
|
85
|
+
}));
|
|
86
|
+
});
|
|
87
|
+
it('should start storybook with tsConfig', async () => {
|
|
88
|
+
const run = await architect.scheduleBuilder('@storybook/angular:start-storybook', {
|
|
89
|
+
tsConfig: 'path/to/tsConfig.json',
|
|
90
|
+
port: 4400,
|
|
91
|
+
compodoc: false,
|
|
92
|
+
});
|
|
93
|
+
const output = await run.result;
|
|
94
|
+
await run.stop();
|
|
95
|
+
expect(output.success).toBeTruthy();
|
|
96
|
+
expect(mockRunScript).not.toHaveBeenCalledWith();
|
|
97
|
+
expect(buildDevStandaloneMock).toHaveBeenCalledWith(expect.objectContaining({
|
|
98
|
+
angularBrowserTarget: null,
|
|
99
|
+
angularBuilderContext: expect.any(Object),
|
|
100
|
+
ci: false,
|
|
101
|
+
configDir: '.storybook',
|
|
102
|
+
disableTelemetry: undefined,
|
|
103
|
+
host: 'localhost',
|
|
104
|
+
https: false,
|
|
105
|
+
packageJson: expect.any(Object),
|
|
106
|
+
port: 4400,
|
|
107
|
+
quiet: false,
|
|
108
|
+
smokeTest: false,
|
|
109
|
+
sslCa: undefined,
|
|
110
|
+
sslCert: undefined,
|
|
111
|
+
sslKey: undefined,
|
|
112
|
+
tsConfig: 'path/to/tsConfig.json',
|
|
113
|
+
}));
|
|
114
|
+
});
|
|
115
|
+
it('should throw error', async () => {
|
|
116
|
+
buildDevStandaloneMock.mockRejectedValue(true);
|
|
117
|
+
const run = await architect.scheduleBuilder('@storybook/angular:start-storybook', {
|
|
118
|
+
browserTarget: 'angular-cli:build-2',
|
|
119
|
+
port: 4400,
|
|
120
|
+
compodoc: false,
|
|
121
|
+
});
|
|
122
|
+
try {
|
|
123
|
+
await run.result;
|
|
124
|
+
expect(false).toEqual('Throw expected');
|
|
125
|
+
}
|
|
126
|
+
catch (error) {
|
|
127
|
+
expect(error).toEqual('Broken build, fix the error above.\nYou may need to refresh the browser.');
|
|
128
|
+
}
|
|
129
|
+
});
|
|
130
|
+
it('should run compodoc', async () => {
|
|
131
|
+
const run = await architect.scheduleBuilder('@storybook/angular:start-storybook', {
|
|
132
|
+
browserTarget: 'angular-cli:build-2',
|
|
133
|
+
});
|
|
134
|
+
const output = await run.result;
|
|
135
|
+
await run.stop();
|
|
136
|
+
expect(output.success).toBeTruthy();
|
|
137
|
+
expect(mockRunScript).toHaveBeenCalledWith('compodoc', ['-p', './storybook/tsconfig.ts', '-d', '.', '-e', 'json'], '');
|
|
138
|
+
expect(buildDevStandaloneMock).toHaveBeenCalledWith(expect.objectContaining({
|
|
139
|
+
angularBrowserTarget: 'angular-cli:build-2',
|
|
140
|
+
angularBuilderContext: expect.any(Object),
|
|
141
|
+
ci: false,
|
|
142
|
+
disableTelemetry: undefined,
|
|
143
|
+
configDir: '.storybook',
|
|
144
|
+
host: 'localhost',
|
|
145
|
+
https: false,
|
|
146
|
+
packageJson: expect.any(Object),
|
|
147
|
+
port: 9009,
|
|
148
|
+
quiet: false,
|
|
149
|
+
smokeTest: false,
|
|
150
|
+
sslCa: undefined,
|
|
151
|
+
sslCert: undefined,
|
|
152
|
+
sslKey: undefined,
|
|
153
|
+
tsConfig: './storybook/tsconfig.ts',
|
|
154
|
+
}));
|
|
155
|
+
});
|
|
156
|
+
it('should start storybook with styles options', async () => {
|
|
157
|
+
const run = await architect.scheduleBuilder('@storybook/angular:start-storybook', {
|
|
158
|
+
tsConfig: 'path/to/tsConfig.json',
|
|
159
|
+
port: 4400,
|
|
160
|
+
compodoc: false,
|
|
161
|
+
styles: ['src/styles.css'],
|
|
162
|
+
});
|
|
163
|
+
const output = await run.result;
|
|
164
|
+
await run.stop();
|
|
165
|
+
expect(output.success).toBeTruthy();
|
|
166
|
+
expect(mockRunScript).not.toHaveBeenCalledWith();
|
|
167
|
+
expect(buildDevStandaloneMock).toHaveBeenCalledWith({
|
|
168
|
+
angularBrowserTarget: null,
|
|
169
|
+
angularBuilderContext: expect.any(Object),
|
|
170
|
+
angularBuilderOptions: { assets: [], styles: ['src/styles.css'] },
|
|
171
|
+
disableTelemetry: undefined,
|
|
172
|
+
ci: false,
|
|
173
|
+
configDir: '.storybook',
|
|
174
|
+
host: 'localhost',
|
|
175
|
+
https: false,
|
|
176
|
+
port: 4400,
|
|
177
|
+
packageJson: expect.any(Object),
|
|
178
|
+
quiet: false,
|
|
179
|
+
smokeTest: false,
|
|
180
|
+
sslCa: undefined,
|
|
181
|
+
sslCert: undefined,
|
|
182
|
+
sslKey: undefined,
|
|
183
|
+
tsConfig: 'path/to/tsConfig.json',
|
|
184
|
+
});
|
|
185
|
+
});
|
|
186
|
+
});
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { logger, instance as npmLog } from 'storybook/internal/node-logger';
|
|
2
|
+
import { dedent } from 'ts-dedent';
|
|
3
|
+
export const printErrorDetails = (error) => {
|
|
4
|
+
// Duplicate code for Standalone error handling
|
|
5
|
+
// Source: https://github.com/storybookjs/storybook/blob/39c7ba09ad84fbd466f9c25d5b92791a5450b9f6/lib/core-server/src/build-dev.ts#L136
|
|
6
|
+
npmLog.heading = '';
|
|
7
|
+
if (error instanceof Error) {
|
|
8
|
+
if (error.error) {
|
|
9
|
+
logger.error(error.error);
|
|
10
|
+
}
|
|
11
|
+
else if (error.stats && error.stats.compilation.errors) {
|
|
12
|
+
error.stats.compilation.errors.forEach((e) => logger.plain(e));
|
|
13
|
+
}
|
|
14
|
+
else {
|
|
15
|
+
logger.error(error);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
else if (error.compilation?.errors) {
|
|
19
|
+
error.compilation.errors.forEach((e) => logger.plain(e));
|
|
20
|
+
}
|
|
21
|
+
logger.line();
|
|
22
|
+
};
|
|
23
|
+
export const errorSummary = (error) => {
|
|
24
|
+
return error.close
|
|
25
|
+
? dedent `
|
|
26
|
+
FATAL broken build!, will close the process,
|
|
27
|
+
Fix the error below and restart storybook.
|
|
28
|
+
`
|
|
29
|
+
: dedent `
|
|
30
|
+
Broken build, fix the error above.
|
|
31
|
+
You may need to refresh the browser.
|
|
32
|
+
`;
|
|
33
|
+
};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { isAbsolute, relative } from 'node:path';
|
|
2
|
+
import { JsPackageManagerFactory } from 'storybook/internal/common';
|
|
3
|
+
import { Observable } from 'rxjs';
|
|
4
|
+
const hasTsConfigArg = (args) => args.indexOf('-p') !== -1;
|
|
5
|
+
const hasOutputArg = (args) => args.indexOf('-d') !== -1 || args.indexOf('--output') !== -1;
|
|
6
|
+
// relative is necessary to workaround a compodoc issue with
|
|
7
|
+
// absolute paths on windows machines
|
|
8
|
+
const toRelativePath = (pathToTsConfig) => {
|
|
9
|
+
return isAbsolute(pathToTsConfig) ? relative('.', pathToTsConfig) : pathToTsConfig;
|
|
10
|
+
};
|
|
11
|
+
export const runCompodoc = ({ compodocArgs, tsconfig }, context) => {
|
|
12
|
+
return new Observable((observer) => {
|
|
13
|
+
const tsConfigPath = toRelativePath(tsconfig);
|
|
14
|
+
const finalCompodocArgs = [
|
|
15
|
+
...(hasTsConfigArg(compodocArgs) ? [] : ['-p', tsConfigPath]),
|
|
16
|
+
...(hasOutputArg(compodocArgs) ? [] : ['-d', `${context.workspaceRoot || '.'}`]),
|
|
17
|
+
...compodocArgs,
|
|
18
|
+
];
|
|
19
|
+
const packageManager = JsPackageManagerFactory.getPackageManager();
|
|
20
|
+
try {
|
|
21
|
+
const stdout = packageManager.runPackageCommandSync('compodoc', finalCompodocArgs, context.workspaceRoot, 'inherit');
|
|
22
|
+
context.logger.info(stdout);
|
|
23
|
+
observer.next();
|
|
24
|
+
observer.complete();
|
|
25
|
+
}
|
|
26
|
+
catch (e) {
|
|
27
|
+
context.logger.error(e);
|
|
28
|
+
observer.error();
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
};
|