diff --git a/CHANGELOG.prerelease.md b/CHANGELOG.prerelease.md index 2ad71c357e65..baec48071eda 100644 --- a/CHANGELOG.prerelease.md +++ b/CHANGELOG.prerelease.md @@ -1,3 +1,12 @@ +## 8.5.0-alpha.18 + +- Addon Test: Clarify message when `vitest` detects missing deps - [#29763](https://github.com/storybookjs/storybook/pull/29763), thanks @ndelangen! +- Addon Test: Refactor test addon to include stories automatically - [#29367](https://github.com/storybookjs/storybook/pull/29367), thanks @yannbf! +- Addon Test: Replace `glob` with `tinyglobby` - [#29817](https://github.com/storybookjs/storybook/pull/29817), thanks @ghengeveld! +- Addon Test: Support Storybook environment variables in Vitest - [#29792](https://github.com/storybookjs/storybook/pull/29792), thanks @ghengeveld! +- Composition: Hide contextMenu on composed storybooks - [#29803](https://github.com/storybookjs/storybook/pull/29803), thanks @ndelangen! +- Vue: Properly resolve Vite plugin - [#29795](https://github.com/storybookjs/storybook/pull/29795), thanks @tobiasdiez! + ## 8.5.0-alpha.17 - CLI: Fix new-frameworks automigration - [#29804](https://github.com/storybookjs/storybook/pull/29804), thanks @yannbf! diff --git a/code/.storybook/vitest.config.ts b/code/.storybook/vitest.config.ts index 05205f3e762a..4b177f409281 100644 --- a/code/.storybook/vitest.config.ts +++ b/code/.storybook/vitest.config.ts @@ -34,20 +34,13 @@ export default mergeConfig( ], test: { name: 'storybook-ui', - include: [ - '../addons/**/*.{story,stories}.?(c|m)[jt]s?(x)', - // '../core/template/stories/**/*.{story,stories}.?(c|m)[jt]s?(x)', - '../core/src/manager/**/*.{story,stories}.?(c|m)[jt]s?(x)', - '../core/src/preview-api/**/*.{story,stories}.?(c|m)[jt]s?(x)', - '../core/src/components/{brand,components}/**/*.{story,stories}.?(c|m)[jt]s?(x)', - ], exclude: [ ...defaultExclude, '../node_modules/**', '**/__mockdata__/**', '../**/__mockdata__/**', - // expected to fail in Vitest because of fetching /iframe.html to cause ECONNREFUSED - '**/Zoom.stories.tsx', + '**/Zoom.stories.tsx', // expected to fail in Vitest because of fetching /iframe.html to cause ECONNREFUSED + '**/lib/blocks/src/**', // won't work because of https://github.com/storybookjs/storybook/issues/29783 ], // TODO: bring this back once portable stories support @storybook/core/preview-api hooks // @ts-expect-error this type does not exist but the property does! diff --git a/code/addons/test/package.json b/code/addons/test/package.json index d26462ebdb52..29d77a92968c 100644 --- a/code/addons/test/package.json +++ b/code/addons/test/package.json @@ -111,6 +111,7 @@ "semver": "^7.6.3", "slash": "^5.0.0", "strip-ansi": "^7.1.0", + "tinyglobby": "^0.2.10", "ts-dedent": "^2.2.0", "typescript": "^5.3.2", "vitest": "^2.1.3" diff --git a/code/addons/test/src/node/test-manager.ts b/code/addons/test/src/node/test-manager.ts index 3660081de58c..139fffa3ef6b 100644 --- a/code/addons/test/src/node/test-manager.ts +++ b/code/addons/test/src/node/test-manager.ts @@ -56,6 +56,13 @@ export class TestManager { this.coverage = payload.config.coverage; await this.restartVitest({ watchMode: this.watchMode, coverage: this.coverage }); } catch (e) { + const isV8 = e.message?.includes('@vitest/coverage-v8'); + const isIstanbul = e.message?.includes('@vitest/coverage-istanbul'); + + if (e.message?.includes('Error: Failed to load url') && (isIstanbul || isV8)) { + const coveragePackage = isIstanbul ? 'coverage-istanbul' : 'coverage-v8'; + e.message = `Please install the @vitest/${coveragePackage} package to run with coverage`; + } this.reportFatalError('Failed to change coverage mode', e); } } diff --git a/code/addons/test/src/node/vitest-manager.ts b/code/addons/test/src/node/vitest-manager.ts index 59aba03e7c71..0296945b43c9 100644 --- a/code/addons/test/src/node/vitest-manager.ts +++ b/code/addons/test/src/node/vitest-manager.ts @@ -83,6 +83,14 @@ export class VitestManager { try { await this.vitest.init(); } catch (e) { + const isV8 = e.message?.includes('@vitest/coverage-v8'); + const isIstanbul = e.message?.includes('@vitest/coverage-istanbul'); + + if (e.message?.includes('Error: Failed to load url') && (isIstanbul || isV8)) { + const coveragePackage = isIstanbul ? 'coverage-istanbul' : 'coverage-v8'; + e.message = `Please install the @vitest/${coveragePackage} package to run with coverage`; + } + this.testManager.reportFatalError('Failed to init Vitest', e); } diff --git a/code/addons/test/src/postinstall.ts b/code/addons/test/src/postinstall.ts index f6772f7691c1..3ea45bd01bf7 100644 --- a/code/addons/test/src/postinstall.ts +++ b/code/addons/test/src/postinstall.ts @@ -336,8 +336,6 @@ export default async function postInstall(options: PostinstallOptions) { // If there's an existing config, we create a workspace file so we can run Storybook tests alongside. const extension = extname(rootConfig); const browserWorkspaceFile = resolve(dirname(rootConfig), `vitest.workspace${extension}`); - // to be set in vitest config - const vitestSetupFilePath = relative(dirname(browserWorkspaceFile), vitestSetupFile); logger.line(1); logger.plain(`${step} Creating a Vitest project workspace file:`); @@ -355,6 +353,7 @@ export default async function postInstall(options: PostinstallOptions) { { extends: '${viteConfigFile ? relative(dirname(browserWorkspaceFile), viteConfigFile) : ''}', plugins: [ + // The plugin will run tests for the stories defined in your Storybook config // See options at: https://storybook.js.org/docs/writing-tests/vitest-plugin#storybooktest storybookTest({ configDir: '${options.configDir}' }),${vitestInfo.frameworkPluginDocs + vitestInfo.frameworkPluginCall} ], @@ -366,9 +365,7 @@ export default async function postInstall(options: PostinstallOptions) { name: 'chromium', provider: 'playwright', }, - // Make sure to adjust this pattern to match your stories files. - include: ['**/*.stories.?(m)[jt]s?(x)'], - setupFiles: ['${vitestSetupFilePath}'], + setupFiles: ['./.storybook/vitest.setup.ts'], }, }, ]); @@ -393,6 +390,7 @@ export default async function postInstall(options: PostinstallOptions) { // More info at: https://storybook.js.org/docs/writing-tests/vitest-plugin export default defineConfig({ plugins: [ + // The plugin will run tests for the stories defined in your Storybook config // See options at: https://storybook.js.org/docs/writing-tests/vitest-plugin#storybooktest storybookTest({ configDir: '${options.configDir}' }),${vitestInfo.frameworkPluginDocs + vitestInfo.frameworkPluginCall} ], @@ -404,8 +402,6 @@ export default async function postInstall(options: PostinstallOptions) { name: 'chromium', provider: 'playwright', }, - // Make sure to adjust this pattern to match your stories files. - include: ['**/*.stories.?(m)[jt]s?(x)'], setupFiles: ['${vitestSetupFilePath}'], }, }); diff --git a/code/addons/test/src/vitest-plugin/index.ts b/code/addons/test/src/vitest-plugin/index.ts index b93eed96ddcf..111e53fd2a8f 100644 --- a/code/addons/test/src/vitest-plugin/index.ts +++ b/code/addons/test/src/vitest-plugin/index.ts @@ -4,13 +4,16 @@ import type { Plugin } from 'vitest/config'; import { getInterpretedFile, loadAllPresets, + normalizeStories, validateConfigurationFiles, } from 'storybook/internal/common'; +import { StoryIndexGenerator } from 'storybook/internal/core-server'; import { readConfig, vitestTransform } from 'storybook/internal/csf-tools'; import { MainFileMissingError } from 'storybook/internal/server-errors'; -import type { StoriesEntry } from 'storybook/internal/types'; +import type { DocsOptions, StoriesEntry } from 'storybook/internal/types'; import { join, resolve } from 'pathe'; +import { convertPathToPattern } from 'tinyglobby'; import type { InternalOptions, UserOptions } from './types'; @@ -51,8 +54,6 @@ export const storybookTest = (options?: UserOptions): Plugin => { process.env.__STORYBOOK_URL__ = storybookUrl; process.env.__STORYBOOK_SCRIPT__ = finalOptions.storybookScript; - let stories: StoriesEntry[]; - if (!finalOptions.configDir) { finalOptions.configDir = resolve(join(process.cwd(), '.storybook')); } else { @@ -60,6 +61,8 @@ export const storybookTest = (options?: UserOptions): Plugin => { } let previewLevelTags: string[]; + let storiesGlobs: StoriesEntry[]; + let storiesFiles: string[]; return { name: 'vite-plugin-storybook-test', @@ -82,20 +85,49 @@ export const storybookTest = (options?: UserOptions): Plugin => { packageJson: {}, }); - stories = await presets.apply('stories', []); + const workingDir = process.cwd(); + const directories = { + configDir, + workingDir, + }; + storiesGlobs = await presets.apply('stories'); + const indexers = await presets.apply('experimental_indexers', []); + const docsOptions = await presets.apply('docs', {}); + const normalizedStories = normalizeStories(await storiesGlobs, directories); + + const generator = new StoryIndexGenerator(normalizedStories, { + ...directories, + indexers: indexers, + docs: docsOptions, + workingDir, + }); + + await generator.initialize(); + + storiesFiles = generator.storyFileNames(); + previewLevelTags = await extractTagsFromPreview(configDir); const framework = await presets.apply('framework', undefined); const frameworkName = typeof framework === 'string' ? framework : framework.name; + const storybookEnv = await presets.apply('env', {}); // If we end up needing to know if we are running in browser mode later // const isRunningInBrowserMode = config.plugins.find((plugin: Plugin) => // plugin.name?.startsWith('vitest:browser') // ) + config.test ??= {}; + config.test.include ??= []; + config.test.include.push(...storiesFiles.map((path) => convertPathToPattern(path))); + + config.test.exclude ??= []; + config.test.exclude.push('**/*.mdx'); + config.test.env ??= {}; config.test.env = { + ...storybookEnv, ...config.test.env, // To be accessed by the setup file __STORYBOOK_URL__: storybookUrl, @@ -104,6 +136,8 @@ export const storybookTest = (options?: UserOptions): Plugin => { __VITEST_SKIP_TAGS__: finalOptions.tags.skip.join(','), }; + config.envPrefix = Array.from(new Set([...(config.envPrefix || []), 'STORYBOOK_', 'VITE_'])); + if (config.test.browser) { config.test.browser.screenshotFailures ??= false; } @@ -163,13 +197,13 @@ export const storybookTest = (options?: UserOptions): Plugin => { return code; } - if (id.match(/(story|stories)\.[cm]?[jt]sx?$/)) { + if (storiesFiles.includes(id)) { return vitestTransform({ code, fileName: id, configDir: finalOptions.configDir, tagsFilter: finalOptions.tags, - stories, + stories: storiesGlobs, previewLevelTags, }); } diff --git a/code/core/src/core-server/index.ts b/code/core/src/core-server/index.ts index 4906ddd9b1f5..3163e70875ea 100644 --- a/code/core/src/core-server/index.ts +++ b/code/core/src/core-server/index.ts @@ -6,3 +6,4 @@ export * from './build-static'; export * from './build-dev'; export * from './withTelemetry'; export { default as build } from './standalone'; +export { StoryIndexGenerator } from './utils/StoryIndexGenerator'; diff --git a/code/core/src/manager/components/sidebar/Tree.tsx b/code/core/src/manager/components/sidebar/Tree.tsx index 0a22df1cb420..d08ab8ffc4d7 100644 --- a/code/core/src/manager/components/sidebar/Tree.tsx +++ b/code/core/src/manager/components/sidebar/Tree.tsx @@ -273,7 +273,10 @@ const Node = React.memo(function Node({ ]); const id = createId(item.id, refId); - const contextMenu = useContextMenu(item, statusLinks, api); + const contextMenu = + refId === 'storybook_internal' + ? useContextMenu(item, statusLinks, api) + : { node: null, onMouseEnter: () => {} }; if (item.type === 'story' || item.type === 'docs') { const LeafNode = item.type === 'docs' ? DocumentNode : StoryNode; diff --git a/code/core/src/types/modules/core-common.ts b/code/core/src/types/modules/core-common.ts index 07372bc308dd..3254723fc4ee 100644 --- a/code/core/src/types/modules/core-common.ts +++ b/code/core/src/types/modules/core-common.ts @@ -71,6 +71,7 @@ export interface Presets { apply(extension: 'babel', config?: {}, args?: any): Promise; apply(extension: 'swc', config?: {}, args?: any): Promise; apply(extension: 'entries', config?: [], args?: any): Promise; + apply(extension: 'env', config?: {}, args?: any): Promise; apply(extension: 'stories', config?: [], args?: any): Promise; apply(extension: 'managerEntries', config: [], args?: any): Promise; apply(extension: 'refs', config?: [], args?: any): Promise; diff --git a/code/frameworks/vue3-vite/src/plugins/vue-component-meta.ts b/code/frameworks/vue3-vite/src/plugins/vue-component-meta.ts index 2f3c13b59897..82c9f4dc3109 100644 --- a/code/frameworks/vue3-vite/src/plugins/vue-component-meta.ts +++ b/code/frameworks/vue3-vite/src/plugins/vue-component-meta.ts @@ -3,7 +3,7 @@ import { dirname, join, parse, relative, resolve } from 'node:path'; import findPackageJson from 'find-package-json'; import MagicString from 'magic-string'; -import type { ModuleNode, PluginOption } from 'vite'; +import type { ModuleNode, Plugin } from 'vite'; import { type ComponentMeta, type MetaCheckerOptions, @@ -21,7 +21,7 @@ type MetaSource = { } & ComponentMeta & MetaCheckerOptions['schema']; -export async function vueComponentMeta(tsconfigPath = 'tsconfig.json'): Promise { +export async function vueComponentMeta(tsconfigPath = 'tsconfig.json'): Promise { const { createFilter } = await import('vite'); // exclude stories, virtual modules and storybook internals diff --git a/code/frameworks/vue3-vite/src/plugins/vue-docgen.ts b/code/frameworks/vue3-vite/src/plugins/vue-docgen.ts index 502264f88f14..c8b9268d0f46 100644 --- a/code/frameworks/vue3-vite/src/plugins/vue-docgen.ts +++ b/code/frameworks/vue3-vite/src/plugins/vue-docgen.ts @@ -1,8 +1,8 @@ import MagicString from 'magic-string'; -import type { PluginOption } from 'vite'; +import type { Plugin } from 'vite'; import { parse } from 'vue-docgen-api'; -export async function vueDocgen(): Promise { +export async function vueDocgen(): Promise { const { createFilter } = await import('vite'); const include = /\.(vue)$/; diff --git a/code/frameworks/vue3-vite/src/plugins/vue-template.ts b/code/frameworks/vue3-vite/src/plugins/vue-template.ts index 325bc20341b4..22751c20222b 100644 --- a/code/frameworks/vue3-vite/src/plugins/vue-template.ts +++ b/code/frameworks/vue3-vite/src/plugins/vue-template.ts @@ -1,6 +1,6 @@ import type { Plugin } from 'vite'; -export async function templateCompilation() { +export async function templateCompilation(): Promise { return { name: 'storybook:vue-template-compilation', config: () => ({ diff --git a/code/frameworks/vue3-vite/src/preset.ts b/code/frameworks/vue3-vite/src/preset.ts index 8bbaf394d442..d565b947587c 100644 --- a/code/frameworks/vue3-vite/src/preset.ts +++ b/code/frameworks/vue3-vite/src/preset.ts @@ -2,7 +2,7 @@ import { dirname, join } from 'node:path'; import type { PresetProperty } from 'storybook/internal/types'; -import type { PluginOption } from 'vite'; +import type { Plugin } from 'vite'; import { vueComponentMeta } from './plugins/vue-component-meta'; import { vueDocgen } from './plugins/vue-docgen'; @@ -18,7 +18,7 @@ export const core: PresetProperty<'core'> = { }; export const viteFinal: StorybookConfig['viteFinal'] = async (config, options) => { - const plugins: PluginOption[] = [templateCompilation()]; + const plugins: Plugin[] = [await templateCompilation()]; const framework = await options.presets.apply('framework'); const frameworkOptions: FrameworkOptions = diff --git a/code/frameworks/vue3-vite/src/vite-plugin.ts b/code/frameworks/vue3-vite/src/vite-plugin.ts index eb2a3345e937..8b90ffe73ffa 100644 --- a/code/frameworks/vue3-vite/src/vite-plugin.ts +++ b/code/frameworks/vue3-vite/src/vite-plugin.ts @@ -1,5 +1,7 @@ +import type { Plugin } from 'vite'; + import { templateCompilation } from './plugins/vue-template'; -export const storybookVuePlugin = () => { +export const storybookVuePlugin = (): Promise[] => { return [templateCompilation()]; }; diff --git a/code/package.json b/code/package.json index b030cd2c70a9..d85d0a6817c0 100644 --- a/code/package.json +++ b/code/package.json @@ -293,5 +293,6 @@ "Dependency Upgrades" ] ] - } + }, + "deferredNextVersion": "8.5.0-alpha.18" } diff --git a/code/yarn.lock b/code/yarn.lock index 2be3e8503969..389084993441 100644 --- a/code/yarn.lock +++ b/code/yarn.lock @@ -6633,6 +6633,7 @@ __metadata: semver: "npm:^7.6.3" slash: "npm:^5.0.0" strip-ansi: "npm:^7.1.0" + tinyglobby: "npm:^0.2.10" ts-dedent: "npm:^2.2.0" typescript: "npm:^5.3.2" vitest: "npm:^2.1.3" @@ -15758,7 +15759,7 @@ __metadata: languageName: node linkType: hard -"fdir@npm:^6.2.0": +"fdir@npm:^6.2.0, fdir@npm:^6.4.2": version: 6.4.2 resolution: "fdir@npm:6.4.2" peerDependencies: @@ -23192,6 +23193,13 @@ __metadata: languageName: node linkType: hard +"picomatch@npm:^4.0.2": + version: 4.0.2 + resolution: "picomatch@npm:4.0.2" + checksum: 10c0/7c51f3ad2bb42c776f49ebf964c644958158be30d0a510efd5a395e8d49cb5acfed5b82c0c5b365523ce18e6ab85013c9ebe574f60305892ec3fa8eee8304ccc + languageName: node + linkType: hard + "picoquery@npm:^1.4.0": version: 1.4.0 resolution: "picoquery@npm:1.4.0" @@ -27703,6 +27711,16 @@ __metadata: languageName: node linkType: hard +"tinyglobby@npm:^0.2.10": + version: 0.2.10 + resolution: "tinyglobby@npm:0.2.10" + dependencies: + fdir: "npm:^6.4.2" + picomatch: "npm:^4.0.2" + checksum: 10c0/ce946135d39b8c0e394e488ad59f4092e8c4ecd675ef1bcd4585c47de1b325e61ec6adfbfbe20c3c2bfa6fd674c5b06de2a2e65c433f752ae170aff11793e5ef + languageName: node + linkType: hard + "tinypool@npm:^1.0.0": version: 1.0.0 resolution: "tinypool@npm:1.0.0" diff --git a/docs/versions/next.json b/docs/versions/next.json index 37255d98f54a..0fee1f4e6446 100644 --- a/docs/versions/next.json +++ b/docs/versions/next.json @@ -1 +1 @@ -{"version":"8.5.0-alpha.17","info":{"plain":"- CLI: Fix new-frameworks automigration - [#29804](https://github.com/storybookjs/storybook/pull/29804), thanks @yannbf!\n- ReactVite: Add `@storybook/test` as optional peer dependency - [#29754](https://github.com/storybookjs/storybook/pull/29754), thanks @yannbf!\n- Vite: Fix preview runtime import - [#29802](https://github.com/storybookjs/storybook/pull/29802), thanks @yannbf!"}} +{"version":"8.5.0-alpha.18","info":{"plain":"- Addon Test: Clarify message when `vitest` detects missing deps - [#29763](https://github.com/storybookjs/storybook/pull/29763), thanks @ndelangen!\n- Addon Test: Refactor test addon to include stories automatically - [#29367](https://github.com/storybookjs/storybook/pull/29367), thanks @yannbf!\n- Addon Test: Replace `glob` with `tinyglobby` - [#29817](https://github.com/storybookjs/storybook/pull/29817), thanks @ghengeveld!\n- Addon Test: Support Storybook environment variables in Vitest - [#29792](https://github.com/storybookjs/storybook/pull/29792), thanks @ghengeveld!\n- Composition: Hide contextMenu on composed storybooks - [#29803](https://github.com/storybookjs/storybook/pull/29803), thanks @ndelangen!\n- Vue: Properly resolve Vite plugin - [#29795](https://github.com/storybookjs/storybook/pull/29795), thanks @tobiasdiez!"}} diff --git a/scripts/build-package.ts b/scripts/build-package.ts index ee6cf109cbe8..8b74b5db9bfc 100644 --- a/scripts/build-package.ts +++ b/scripts/build-package.ts @@ -8,6 +8,7 @@ import picocolors from 'picocolors'; import prompts from 'prompts'; import windowSize from 'window-size'; +import { findMostMatchText } from './utils/diff'; import { getWorkspaces } from './utils/workspace'; async function run() { @@ -80,60 +81,79 @@ async function run() { tasks[key].value = containsFlag || opts.all; }); - let selection; - let watchMode = false; - let prodMode = false; - if ( - !Object.keys(tasks) - .map((key) => tasks[key].value) - .filter(Boolean).length - ) { - selection = await prompts([ - { - type: 'toggle', - name: 'watch', - message: 'Start in watch mode', - initial: false, - active: 'yes', - inactive: 'no', - }, - { - type: 'toggle', - name: 'prod', - message: 'Start in production mode', - initial: false, - active: 'yes', - inactive: 'no', - }, - { - type: 'autocompleteMultiselect', - message: 'Select the packages to build', - name: 'todo', - min: 1, - hint: 'You can also run directly with package name like `yarn build core`, or `yarn build --all` for all packages!', - // @ts-expect-error @types incomplete - optionsPerPage: windowSize.height - 3, // 3 lines for extra info - choices: packages.map(({ name: key }) => ({ - value: key, - title: tasks[key].name || key, - selected: (tasks[key] && tasks[key].defaultValue) || false, - })), - }, - ]).then(({ watch, prod, todo }: { watch: boolean; prod: boolean; todo: Array }) => { + let watchMode = process.argv.includes('--watch'); + let prodMode = process.argv.includes('--prod'); + let selection = Object.keys(tasks) + .map((key) => tasks[key]) + .filter((item) => !['watch', 'prod'].includes(item.name) && item.value === true); + + // user has passed invalid package name(s) - try to guess the correct package name(s) + if ((!selection.length && main.args.length >= 1) || selection.length !== main.args.length) { + const suffixList = Object.values(tasks) + .filter((t) => t.name.includes('@storybook')) + .map((t) => t.suffix); + + for (const arg of main.args) { + if (!suffixList.includes(arg)) { + const matchText = findMostMatchText(suffixList, arg); + + if (matchText) { + console.log( + `${picocolors.red('Error')}: ${picocolors.cyan( + arg + )} is not a valid package name, Did you mean ${picocolors.cyan(matchText)}?` + ); + } + } + } + + process.exit(0); + } + + if (!selection.length) { + selection = await prompts( + [ + { + type: 'toggle', + name: 'watch', + message: 'Start in watch mode', + initial: false, + active: 'yes', + inactive: 'no', + }, + { + type: 'toggle', + name: 'prod', + message: 'Start in production mode', + initial: false, + active: 'yes', + inactive: 'no', + }, + { + type: 'autocompleteMultiselect', + message: 'Select the packages to build', + name: 'todo', + min: 1, + hint: 'You can also run directly with package name like `yarn build core`, or `yarn build --all` for all packages!', + // @ts-expect-error @types incomplete + optionsPerPage: windowSize.height - 3, // 3 lines for extra info + choices: packages.map(({ name: key }) => ({ + value: key, + title: tasks[key].name || key, + selected: (tasks[key] && tasks[key].defaultValue) || false, + })), + }, + ], + { onCancel: () => process.exit(0) } + ).then(({ watch, prod, todo }: { watch: boolean; prod: boolean; todo: Array }) => { watchMode = watch; prodMode = prod; return todo?.map((key) => tasks[key]); }); - } else { - // hits here when running yarn build --packagename - watchMode = process.argv.includes('--watch'); - prodMode = process.argv.includes('--prod'); - selection = Object.keys(tasks) - .map((key) => tasks[key]) - .filter((item) => !['watch', 'prod'].includes(item.name) && item.value === true); } - selection?.filter(Boolean).forEach(async (v) => { + console.log('Building selected packages...'); + selection.forEach(async (v) => { const command = (await readJSON(resolve('../code', v.location, 'package.json'))).scripts?.prep .split(posix.sep) .join(sep); diff --git a/scripts/package.json b/scripts/package.json index ee3aff691838..ae72fcc9783a 100644 --- a/scripts/package.json +++ b/scripts/package.json @@ -105,6 +105,7 @@ "danger": "^12.3.3", "dataloader": "^2.2.2", "detect-port": "^1.6.1", + "diff-match-patch-es": "^0.1.0", "ejs": "^3.1.10", "ejs-lint": "^2.0.0", "es-toolkit": "^1.22.0", diff --git a/scripts/tasks/sandbox-parts.ts b/scripts/tasks/sandbox-parts.ts index 27b73c36de4e..920b31857a8b 100644 --- a/scripts/tasks/sandbox-parts.ts +++ b/scripts/tasks/sandbox-parts.ts @@ -498,14 +498,11 @@ export async function setupVitest(details: TemplateDetails, options: PassedOptio test: { name: "storybook", pool: "threads", - include: [ - "src/**/*.{story,stories}.?(c|m)[jt]s?(x)", - "template-stories/**/*.{story,stories}.?(c|m)[jt]s?(x)", - ], exclude: [ ...defaultExclude, // TODO: investigate TypeError: Cannot read properties of null (reading 'useContext') "**/*argtypes*", + ${template.expected.renderer === '@storybook/svelte' ? '"**/*.stories.svelte",' : ''} ], /** * TODO: Either fix or acknowledge limitation of: diff --git a/scripts/utils/diff.ts b/scripts/utils/diff.ts new file mode 100644 index 000000000000..a07dce4abe20 --- /dev/null +++ b/scripts/utils/diff.ts @@ -0,0 +1,35 @@ +import { diff } from 'diff-match-patch-es'; + +function matchTextScore(text: string, pattern: string) { + const result = diff(text, pattern); + + if (!result.length) { + return 0; + } + + return result.reduce((pre, cur) => { + const [matchIndex, matchText] = cur; + + if (matchIndex === 0) { + return pre + matchText.length; + } + + return pre; + }, 0); +} + +export function findMostMatchText(list: string[], pattern: string) { + let maxScore = 0; + let result = ''; + + for (const text of list) { + const score = matchTextScore(text, pattern); + + if (score > maxScore) { + maxScore = score; + result = text; + } + } + + return result !== '' ? result : null; +} diff --git a/scripts/yarn.lock b/scripts/yarn.lock index 015159a4b042..3f740c74a6a4 100644 --- a/scripts/yarn.lock +++ b/scripts/yarn.lock @@ -83,11 +83,9 @@ __metadata: linkType: hard "@babel/helper-environment-visitor@npm:^7.22.20": - version: 7.24.7 - resolution: "@babel/helper-environment-visitor@npm:7.24.7" - dependencies: - "@babel/types": "npm:^7.24.7" - checksum: 10c0/36ece78882b5960e2d26abf13cf15ff5689bf7c325b10a2895a74a499e712de0d305f8d78bb382dd3c05cfba7e47ec98fe28aab5674243e0625cd38438dd0b2d + version: 7.22.20 + resolution: "@babel/helper-environment-visitor@npm:7.22.20" + checksum: 10c0/e762c2d8f5d423af89bd7ae9abe35bd4836d2eb401af868a63bbb63220c513c783e25ef001019418560b3fdc6d9a6fb67e6c0b650bcdeb3a2ac44b5c3d2bdd94 languageName: node linkType: hard @@ -102,20 +100,27 @@ __metadata: linkType: hard "@babel/helper-hoist-variables@npm:^7.22.5": - version: 7.24.7 - resolution: "@babel/helper-hoist-variables@npm:7.24.7" + version: 7.22.5 + resolution: "@babel/helper-hoist-variables@npm:7.22.5" dependencies: - "@babel/types": "npm:^7.24.7" - checksum: 10c0/19ee37563bbd1219f9d98991ad0e9abef77803ee5945fd85aa7aa62a67c69efca9a801696a1b58dda27f211e878b3327789e6fd2a6f6c725ccefe36774b5ce95 + "@babel/types": "npm:^7.22.5" + checksum: 10c0/60a3077f756a1cd9f14eb89f0037f487d81ede2b7cfe652ea6869cd4ec4c782b0fb1de01b8494b9a2d2050e3d154d7d5ad3be24806790acfb8cbe2073bf1e208 languageName: node linkType: hard "@babel/helper-split-export-declaration@npm:^7.22.6": - version: 7.24.7 - resolution: "@babel/helper-split-export-declaration@npm:7.24.7" + version: 7.22.6 + resolution: "@babel/helper-split-export-declaration@npm:7.22.6" dependencies: - "@babel/types": "npm:^7.24.7" - checksum: 10c0/0254577d7086bf09b01bbde98f731d4fcf4b7c3fa9634fdb87929801307c1f6202a1352e3faa5492450fa8da4420542d44de604daf540704ff349594a78184f6 + "@babel/types": "npm:^7.22.5" + checksum: 10c0/d83e4b623eaa9622c267d3c83583b72f3aac567dc393dda18e559d79187961cb29ae9c57b2664137fc3d19508370b12ec6a81d28af73a50e0846819cb21c6e44 + languageName: node + linkType: hard + +"@babel/helper-string-parser@npm:^7.23.4": + version: 7.23.4 + resolution: "@babel/helper-string-parser@npm:7.23.4" + checksum: 10c0/f348d5637ad70b6b54b026d6544bd9040f78d24e7ec245a0fc42293968181f6ae9879c22d89744730d246ce8ec53588f716f102addd4df8bbc79b73ea10004ac languageName: node linkType: hard @@ -133,6 +138,13 @@ __metadata: languageName: node linkType: hard +"@babel/helper-validator-identifier@npm:^7.22.20": + version: 7.22.20 + resolution: "@babel/helper-validator-identifier@npm:7.22.20" + checksum: 10c0/dcad63db345fb110e032de46c3688384b0008a42a4845180ce7cd62b1a9c0507a1bed727c4d1060ed1a03ae57b4d918570259f81724aaac1a5b776056f37504e + languageName: node + linkType: hard + "@babel/highlight@npm:^7.24.7": version: 7.24.7 resolution: "@babel/highlight@npm:7.24.7" @@ -145,7 +157,7 @@ __metadata: languageName: node linkType: hard -"@babel/parser@npm:^7.20.5, @babel/parser@npm:^7.22.5, @babel/parser@npm:^7.23.0, @babel/parser@npm:^7.24.4, @babel/parser@npm:^7.25.0, @babel/parser@npm:^7.25.3": +"@babel/parser@npm:^7.20.5, @babel/parser@npm:^7.22.5, @babel/parser@npm:^7.24.4, @babel/parser@npm:^7.25.0, @babel/parser@npm:^7.25.3": version: 7.25.3 resolution: "@babel/parser@npm:7.25.3" dependencies: @@ -156,6 +168,15 @@ __metadata: languageName: node linkType: hard +"@babel/parser@npm:^7.23.0": + version: 7.23.9 + resolution: "@babel/parser@npm:7.23.9" + bin: + parser: ./bin/babel-parser.js + checksum: 10c0/7df97386431366d4810538db4b9ec538f4377096f720c0591c7587a16f6810e62747e9fbbfa1ff99257fd4330035e4fb1b5b77c7bd3b97ce0d2e3780a6618975 + languageName: node + linkType: hard + "@babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.15.4, @babel/runtime@npm:^7.23.2": version: 7.23.2 resolution: "@babel/runtime@npm:7.23.2" @@ -219,7 +240,7 @@ __metadata: languageName: node linkType: hard -"@babel/types@npm:^7.17.0, @babel/types@npm:^7.23.0, @babel/types@npm:^7.24.0, @babel/types@npm:^7.24.7, @babel/types@npm:^7.25.0, @babel/types@npm:^7.25.2": +"@babel/types@npm:^7.17.0, @babel/types@npm:^7.24.0, @babel/types@npm:^7.24.7, @babel/types@npm:^7.25.0, @babel/types@npm:^7.25.2": version: 7.25.2 resolution: "@babel/types@npm:7.25.2" dependencies: @@ -230,6 +251,17 @@ __metadata: languageName: node linkType: hard +"@babel/types@npm:^7.22.5, @babel/types@npm:^7.23.0, @babel/types@npm:^7.8.3": + version: 7.23.9 + resolution: "@babel/types@npm:7.23.9" + dependencies: + "@babel/helper-string-parser": "npm:^7.23.4" + "@babel/helper-validator-identifier": "npm:^7.22.20" + to-fast-properties: "npm:^2.0.0" + checksum: 10c0/edc7bb180ce7e4d2aea10c6972fb10474341ac39ba8fdc4a27ffb328368dfdfbf40fca18e441bbe7c483774500d5c05e222cec276c242e952853dcaf4eb884f7 + languageName: node + linkType: hard + "@bcoe/v8-coverage@npm:^0.2.3": version: 0.2.3 resolution: "@bcoe/v8-coverage@npm:0.2.3" @@ -442,13 +474,20 @@ __metadata: languageName: node linkType: hard -"@eslint-community/regexpp@npm:^4.10.0, @eslint-community/regexpp@npm:^4.5.1, @eslint-community/regexpp@npm:^4.6.1": +"@eslint-community/regexpp@npm:^4.10.0": version: 4.10.1 resolution: "@eslint-community/regexpp@npm:4.10.1" checksum: 10c0/f59376025d0c91dd9fdf18d33941df499292a3ecba3e9889c360f3f6590197d30755604588786cdca0f9030be315a26b206014af4b65c0ff85b4ec49043de780 languageName: node linkType: hard +"@eslint-community/regexpp@npm:^4.5.1, @eslint-community/regexpp@npm:^4.6.1": + version: 4.10.0 + resolution: "@eslint-community/regexpp@npm:4.10.0" + checksum: 10c0/c5f60ef1f1ea7649fa7af0e80a5a79f64b55a8a8fa5086de4727eb4c86c652aedee407a9c143b8995d2c0b2d75c1222bec9ba5d73dbfc1f314550554f0979ef4 + languageName: node + linkType: hard + "@eslint/eslintrc@npm:^2.1.4": version: 2.1.4 resolution: "@eslint/eslintrc@npm:2.1.4" @@ -1589,6 +1628,7 @@ __metadata: danger: "npm:^12.3.3" dataloader: "npm:^2.2.2" detect-port: "npm:^1.6.1" + diff-match-patch-es: "npm:^0.1.0" ejs: "npm:^3.1.10" ejs-lint: "npm:^2.0.0" es-toolkit: "npm:^1.22.0" @@ -4321,13 +4361,20 @@ __metadata: languageName: node linkType: hard -"core-js@npm:3.35.0, core-js@npm:^3.8.2": +"core-js@npm:3.35.0": version: 3.35.0 resolution: "core-js@npm:3.35.0" checksum: 10c0/1d545ff4406f2afa5e681f44b45ed5f7f119d158b380234d5aa7787ce7e47fc7a635b98b74c28c766ba8191e3db8c2316ad6ab4ff1ddecbc3fd618413a52c29c languageName: node linkType: hard +"core-js@npm:^3.8.2": + version: 3.33.2 + resolution: "core-js@npm:3.33.2" + checksum: 10c0/d6a56ad3e134846c805ce936788dd58cb51e861f173ed1f830979735d7865ea6f6a5a437076c36c8d8b842ba0384d052998f160774a8da7712f0f51df60167fe + languageName: node + linkType: hard + "core-util-is@npm:1.0.2": version: 1.0.2 resolution: "core-util-is@npm:1.0.2" @@ -4828,6 +4875,13 @@ __metadata: languageName: node linkType: hard +"diff-match-patch-es@npm:^0.1.0": + version: 0.1.0 + resolution: "diff-match-patch-es@npm:0.1.0" + checksum: 10c0/c456d10662506f676489c1572af2a48ad52d015a856b74bf16594d39f11c9a352cd763fd66b5a5952c86a18818f4b7de28d55876e7ffd47f5d71282e3a5056a2 + languageName: node + linkType: hard + "diff-sequences@npm:^29.6.3": version: 29.6.3 resolution: "diff-sequences@npm:29.6.3" @@ -5088,7 +5142,7 @@ __metadata: languageName: node linkType: hard -"ejs@npm:^3.1.10, ejs@npm:^3.1.7": +"ejs@npm:^3.1.10": version: 3.1.10 resolution: "ejs@npm:3.1.10" dependencies: @@ -5099,6 +5153,17 @@ __metadata: languageName: node linkType: hard +"ejs@npm:^3.1.7": + version: 3.1.9 + resolution: "ejs@npm:3.1.9" + dependencies: + jake: "npm:^10.8.5" + bin: + ejs: bin/cli.js + checksum: 10c0/f0e249c79128810f5f6d5cbf347fc906d86bb9384263db0b2a9004aea649f2bc2d112736de5716c509c80afb4721c47281bd5b57c757d3b63f1bf5ac5f885893 + languageName: node + linkType: hard + "emoji-regex@npm:^10.2.1, emoji-regex@npm:^10.3.0": version: 10.3.0 resolution: "emoji-regex@npm:10.3.0" @@ -8868,7 +8933,14 @@ __metadata: languageName: node linkType: hard -"lru-cache@npm:^10.0.1, lru-cache@npm:^10.2.0": +"lru-cache@npm:^10.0.1": + version: 10.0.1 + resolution: "lru-cache@npm:10.0.1" + checksum: 10c0/982dabfb227b9a2daf56d712ae0e72e01115a28c0a2068cd71277bca04568f3417bbf741c6c7941abc5c620fd8059e34f15607f90ebccbfa0a17533322d27a8e + languageName: node + linkType: hard + +"lru-cache@npm:^10.2.0": version: 10.2.2 resolution: "lru-cache@npm:10.2.2" checksum: 10c0/402d31094335851220d0b00985084288136136992979d0e015f0f1697e15d1c86052d7d53ae86b614e5b058425606efffc6969a31a091085d7a2b80a8a1e26d6