diff --git a/MIGRATION.md b/MIGRATION.md index 428bde622ebe..7ac06afbec05 100644 --- a/MIGRATION.md +++ b/MIGRATION.md @@ -586,6 +586,8 @@ When using a [Vite-based framework](#framework-field-mandatory), Storybook will Some settings will be overridden by storybook so that it can function properly, and the merged settings can be modified using `viteFinal` in `.storybook/main.js` (see the [Storybook Vite configuration docs](https://storybook.js.org/docs/react/builders/vite#configuration)). If you were using `viteFinal` in 6.5 to simply merge in your project's standard vite config, you can now remove it. +For Svelte projects this means that the `svelteOptions` property in the `main.js` config can be omitted in most cases, as it will be loaded automatically via the project's `vite.config.js`. An exception to this is when the project needs different Svelte options for Storybook than the Vite config provides for the application itself. + #### Vite cache moved to node_modules/.cache/.vite-storybook Previously, Storybook's Vite builder placed cache files in node_modules/.vite-storybook. However, it's more common for tools to place cached files into `node_modules/.cache`, and putting them there makes it quick and easy to clear the cache for multiple tools at once. We don't expect this change will cause any problems, but it's something that users of Storybook Vite projects should know about. It can be configured by setting `cacheDir` in `viteFinal` within `.storybook/main.js` [Storybook Vite configuration docs](https://storybook.js.org/docs/react/builders/vite#configuration)). @@ -601,6 +603,8 @@ export default { }; ``` +Also see the note in [Vite builder uses vite config automatically](#vite-builder-uses-vite-config-automatically) about removing `svelteOptions`. + #### Removed docs.getContainer and getPage parameters It is no longer possible to set `parameters.docs.getContainer()` and `getPage()`. Instead use `parameters.docs.container` or `parameters.docs.page` directly. diff --git a/code/frameworks/sveltekit/package.json b/code/frameworks/sveltekit/package.json index 6a0d8b91f055..8e10bb38ca72 100644 --- a/code/frameworks/sveltekit/package.json +++ b/code/frameworks/sveltekit/package.json @@ -52,6 +52,7 @@ }, "dependencies": { "@storybook/builder-vite": "7.0.0-beta.2", + "@storybook/svelte": "7.0.0-beta.2", "@storybook/svelte-vite": "7.0.0-beta.2" }, "devDependencies": { diff --git a/code/lib/cli/src/automigrate/fixes/index.ts b/code/lib/cli/src/automigrate/fixes/index.ts index 2ed72676b065..fbe9f4007843 100644 --- a/code/lib/cli/src/automigrate/fixes/index.ts +++ b/code/lib/cli/src/automigrate/fixes/index.ts @@ -12,6 +12,7 @@ import { newFrameworks } from './new-frameworks'; import { removedGlobalClientAPIs } from './remove-global-client-apis'; import { mdx1to2 } from './mdx-1-to-2'; import { docsPageAutomatic } from './docsPage-automatic'; +import { sveltekitFramework } from './sveltekit-framework'; import { addReact } from './add-react'; export * from '../types'; @@ -23,6 +24,7 @@ export const fixes: Fix[] = [ vue3, mainjsFramework, eslintPlugin, + sveltekitFramework, builderVite, sbScripts, newFrameworks, diff --git a/code/lib/cli/src/automigrate/fixes/new-frameworks.ts b/code/lib/cli/src/automigrate/fixes/new-frameworks.ts index cc3c03bef1fc..37f9add6b127 100644 --- a/code/lib/cli/src/automigrate/fixes/new-frameworks.ts +++ b/code/lib/cli/src/automigrate/fixes/new-frameworks.ts @@ -262,8 +262,7 @@ export const newFrameworks: Fix = { if (currentCore) { if (Object.keys(currentCore).length === 0) { - // TODO: this should delete the field instead - main.setFieldValue(['core'], {}); + main.removeField(['core']); } else { main.setFieldValue(['core'], currentCore); } diff --git a/code/lib/cli/src/automigrate/fixes/sveltekit-framework.test.ts b/code/lib/cli/src/automigrate/fixes/sveltekit-framework.test.ts new file mode 100644 index 000000000000..e24623faf510 --- /dev/null +++ b/code/lib/cli/src/automigrate/fixes/sveltekit-framework.test.ts @@ -0,0 +1,174 @@ +/* eslint-disable no-underscore-dangle */ +import type { StorybookConfig } from 'lib/types/src'; +import path from 'path'; +import type { JsPackageManager, PackageJson } from '../../js-package-manager'; +import { sveltekitFramework } from './sveltekit-framework'; + +// eslint-disable-next-line global-require, jest/no-mocks-import +jest.mock('fs-extra', () => require('../../../../../__mocks__/fs-extra')); + +const checkSvelteKitFramework = async ({ + packageJson, + main, +}: { + packageJson: PackageJson; + main?: Partial; +}) => { + if (main) { + // eslint-disable-next-line global-require + require('fs-extra').__setMockFiles({ + [path.join('.storybook', 'main.js')]: `module.exports = ${JSON.stringify(main)};`, + }); + } else { + // eslint-disable-next-line global-require + require('fs-extra').__setMockFiles({}); + } + const packageManager = { + retrievePackageJson: () => ({ dependencies: {}, devDependencies: {}, ...packageJson }), + } as JsPackageManager; + + return sveltekitFramework.check({ packageManager }); +}; + +describe('SvelteKit framework fix', () => { + describe('should no-op', () => { + it('in SB < v7.0.0', async () => { + const packageJson = { + dependencies: { '@sveltejs/kit': '^1.0.0-next.571', '@storybook/svelte': '^6.2.0' }, + }; + const main = { framework: '@storybook/svelte-vite' }; + await expect(checkSvelteKitFramework({ packageJson, main })).resolves.toBeFalsy(); + }); + + describe('in SB >= v7.0.0', () => { + it('in non-SvelteKit projects', async () => { + const packageJson = { + dependencies: { svelte: '^3.53.1', '@storybook/svelte-vite': '^7.0.0' }, + }; + const main = { + framework: '@storybook/svelte-vite', + }; + await expect(checkSvelteKitFramework({ packageJson, main })).resolves.toBeFalsy(); + }); + + it('without main', async () => { + const packageJson = { + dependencies: { '@sveltejs/kit': '^1.0.0-next.571', '@storybook/svelte': '^7.0.0' }, + }; + await expect(checkSvelteKitFramework({ packageJson })).rejects.toThrow(); + }); + + it('without framework field in main', async () => { + const packageJson = { + dependencies: { '@sveltejs/kit': '^1.0.0-next.571', '@storybook/svelte': '^7.0.0' }, + }; + const main = {}; + await expect(checkSvelteKitFramework({ packageJson, main })).rejects.toThrow(); + }); + + it('with unsupported framework', async () => { + const packageJson = { + dependencies: { + '@sveltejs/kit': '^1.0.0-next.571', + '@storybook/svelte-vite': '^7.0.0', + '@storybook/html': '^7.0.0', + }, + }; + const main = { + framework: '@storybook/html', + }; + await expect(checkSvelteKitFramework({ packageJson, main })).rejects.toThrow(); + }); + + it('with unsupported framework+builder from SB 6.5', async () => { + const packageJson = { + dependencies: { + '@sveltejs/kit': '^1.0.0-next.571', + '@storybook/svelte-webpack5': '^7.0.0', + '@storybook/svelte': '^7.0.0', + }, + }; + const main = { + framework: '@storybook/svelte', + core: { builder: '@storybook/builder-webpack5' }, + }; + await expect(checkSvelteKitFramework({ packageJson, main })).rejects.toThrow(); + }); + + it('with @storybook/svelte-webpack5 framework', async () => { + const packageJson = { + dependencies: { + '@storybook/svelte': '^7.0.0', + '@storybook/svelte-webpack5': '^7.0.0', + '@sveltejs/kit': '^1.0.0-next.571', + }, + }; + const main = { + framework: '@storybook/svelte-webpack5', + }; + await expect(checkSvelteKitFramework({ packageJson, main })).rejects.toThrow(); + }); + }); + }); + + describe('should migrate', () => { + it('from @storybook/svelte-vite', async () => { + const packageJson = { + dependencies: { + '@storybook/svelte': '^7.0.0', + '@storybook/svelte-vite': '^7.0.0', + '@sveltejs/kit': '^1.0.0-next.571', + }, + }; + const main = { + framework: '@storybook/svelte-vite', + }; + await expect(checkSvelteKitFramework({ packageJson, main })).resolves.toMatchObject({ + packageJson, + main: expect.objectContaining({}), + frameworkOptions: undefined, + dependenciesToRemove: ['@storybook/svelte-vite'], + }); + }); + + it('from @storybook/svelte framework and @storybook/builder-vite builder', async () => { + const packageJson = { + dependencies: { + '@storybook/svelte': '^7.0.0', + '@storybook/builder-vite': '^7.0.0', + '@sveltejs/kit': '^1.0.0-next.571', + }, + }; + const main = { + framework: '@storybook/svelte', + core: { builder: '@storybook/builder-vite' }, + }; + await expect(checkSvelteKitFramework({ packageJson, main })).resolves.toMatchObject({ + packageJson, + main: expect.objectContaining({}), + frameworkOptions: undefined, + dependenciesToRemove: ['@storybook/builder-vite'], + }); + }); + + it('from @storybook/svelte framework and storybook-builder-vite builder', async () => { + const packageJson = { + dependencies: { + '@storybook/svelte': '^7.0.0', + 'storybook-builder-vite': '^0.2.5', + '@sveltejs/kit': '^1.0.0-next.571', + }, + }; + const main = { + framework: '@storybook/svelte', + core: { builder: 'storybook-builder-vite' }, + }; + await expect(checkSvelteKitFramework({ packageJson, main })).resolves.toMatchObject({ + packageJson, + main: expect.objectContaining({}), + frameworkOptions: undefined, + dependenciesToRemove: ['storybook-builder-vite'], + }); + }); + }); +}); diff --git a/code/lib/cli/src/automigrate/fixes/sveltekit-framework.ts b/code/lib/cli/src/automigrate/fixes/sveltekit-framework.ts new file mode 100644 index 000000000000..dd4bfd09e5aa --- /dev/null +++ b/code/lib/cli/src/automigrate/fixes/sveltekit-framework.ts @@ -0,0 +1,186 @@ +import chalk from 'chalk'; +import dedent from 'ts-dedent'; +import semver from 'semver'; +import type { ConfigFile } from '@storybook/csf-tools'; +import { readConfig, writeConfig } from '@storybook/csf-tools'; +import { getStorybookInfo } from '@storybook/core-common'; + +import type { Fix } from '../types'; +import type { PackageJsonWithDepsAndDevDeps } from '../../js-package-manager'; +import { getStorybookVersionSpecifier } from '../../helpers'; + +const logger = console; + +interface SvelteKitFrameworkRunOptions { + main: ConfigFile; + packageJson: PackageJsonWithDepsAndDevDeps; + frameworkOptions: Record | undefined; + dependenciesToRemove: string[]; +} + +const fixId = 'sveltekitFramework'; + +/** + * Does the user have a SvelteKit project but is using a Svelte+Vite setup instead of the @storybook/sveltekit framework? + * + * If so: + * - Remove the dependencies (@storybook/svelte-vite, @storybook/builder-vite, storybook-builder-vite) + * - Add the dependencies (@storybook/sveltekit) + * - Update the main config to use the new framework + */ +export const sveltekitFramework: Fix = { + id: fixId, + + async check({ packageManager }) { + const packageJson = packageManager.retrievePackageJson(); + const allDeps = { ...packageJson.dependencies, ...packageJson.devDependencies }; + + if (!allDeps['@sveltejs/kit']) { + return null; + } + + const { mainConfig, version: storybookVersion } = getStorybookInfo(packageJson); + if (!mainConfig) { + logger.warn('Unable to find storybook main.js config, skipping'); + return null; + } + + const sbVersionCoerced = storybookVersion && semver.coerce(storybookVersion)?.version; + if (!sbVersionCoerced) { + logger.warn(dedent` + ❌ Unable to determine Storybook version, skipping ${chalk.cyan(fixId)} fix. + 🤔 Are you running automigrate from your project directory? + `); + return null; + } + + if (!semver.gte(sbVersionCoerced, '7.0.0')) { + return null; + } + + const main = await readConfig(mainConfig); + const frameworkConfig = main.getFieldValue(['framework']); + + if (!frameworkConfig) { + logger.warn(dedent` + ❌ Unable to determine Storybook framework, skipping ${chalk.cyan(fixId)} fix. + 🤔 Are you running automigrate from your project directory? + `); + return null; + } + + const framework = typeof frameworkConfig === 'string' ? frameworkConfig : frameworkConfig.name; + const frameworkOptions = main.getFieldValue(['framework', 'options']); + + if (framework === '@storybook/svelte-vite') { + // direct migration from svelte-vite projects + return { + main, + frameworkOptions, + packageJson, + dependenciesToRemove: ['@storybook/svelte-vite'], + }; + } + + if (framework !== '@storybook/svelte') { + // migration from projects using Svelte but with an unrecognized framework+builder setup - not supported + logger.warn(dedent` + We've detected you are using Storybook in a SvelteKit project. + + In Storybook 7, we introduced a new framework package for SvelteKit projects: @storybook/sveltekit. + + This package provides a better experience for SvelteKit users, however it is only compatible with the Svelte framework and the Vite builder, so we can't automigrate for you, as you are using another framework and builder combination. + + If you are interested in using this package, see: ${chalk.yellow( + 'https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#sveltekit-needs-the-storybooksveltekit-framework' + )} + `); + return null; + } + + const builder = main.getFieldValue(['core', 'builder']); + + if (!['@storybook/builder-vite', 'storybook-builder-vite'].includes(builder)) { + // migration from 6.x projects using Svelte with the Webpack builder - not supported + logger.warn(dedent` + We've detected you are using Storybook in a SvelteKit project. + + In Storybook 7, we introduced a new framework package for SvelteKit projects: @storybook/sveltekit. + + This package provides a better experience for SvelteKit users, however it is only compatible with the Vite builder, so we can't automigrate for you, as you are using another builder. + + If you are interested in using this package, see: ${chalk.yellow( + 'https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#sveltekit-needs-the-storybooksveltekit-framework' + )} + `); + + return null; + } + + // migration from 6.x projects using Svelte with the Vite builder + return { + main, + frameworkOptions, + packageJson, + dependenciesToRemove: [builder], + }; + }, + + prompt() { + return dedent` + We've detected you are using Storybook in a SvelteKit project. + + In Storybook 7, we introduced a new framework package for SvelteKit projects: @storybook/sveltekit + This package is a replacement for @storybook/svelte-vite and provides a better experience for SvelteKit users. + + We can automatically migrate your project to use the new SvelteKit framework package. + + To learn more about this change, see: ${chalk.yellow( + 'https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#sveltekit-needs-the-storybooksveltekit-framework' + )} + `; + }, + + async run({ + result: { main, frameworkOptions, packageJson, dependenciesToRemove }, + packageManager, + dryRun, + }) { + logger.info(`✅ Removing redundant packages: ${dependenciesToRemove.join(', ')}`); + if (!dryRun) { + packageManager.removeDependencies({ skipInstall: true, packageJson }, dependenciesToRemove); + } + + logger.info(`✅ Installing new dependencies: @storybook/sveltekit`); + if (!dryRun) { + const versionToInstall = getStorybookVersionSpecifier(packageJson); + packageManager.addDependencies({ installAsDevDependencies: true, packageJson }, [ + `@storybook/sveltekit@${versionToInstall}`, + ]); + } + + logger.info(`✅ Updating framework field in main.js`); + if (frameworkOptions) { + main.setFieldValue(['framework', 'options'], frameworkOptions); + main.setFieldValue(['framework', 'name'], '@storybook/sveltekit'); + } else { + main.setFieldValue(['framework'], '@storybook/sveltekit'); + } + + const currentCore = main.getFieldValue(['core']); + if (currentCore.builder) { + logger.info(`✅ Updating core field in main.js`); + const { builder, ...core } = currentCore; + + if (Object.keys(core).length === 0) { + main.removeField(['core']); + } else { + main.setFieldValue(['core'], core); + } + } + + if (!dryRun) { + await writeConfig(main); + } + }, +}; diff --git a/code/lib/csf-tools/src/ConfigFile.test.ts b/code/lib/csf-tools/src/ConfigFile.test.ts index 757ed1b05675..0c528a694cd7 100644 --- a/code/lib/csf-tools/src/ConfigFile.test.ts +++ b/code/lib/csf-tools/src/ConfigFile.test.ts @@ -19,6 +19,12 @@ const setField = (path: string[], value: any, source: string) => { return formatConfig(config); }; +const removeField = (path: string[], source: string) => { + const config = loadConfig(source).parse(); + config.removeField(path); + return formatConfig(config); +}; + describe('ConfigFile', () => { describe('getField', () => { describe('named exports', () => { @@ -432,4 +438,313 @@ describe('ConfigFile', () => { }); }); }); + + describe('removeField', () => { + describe('named exports', () => { + it('missing export', () => { + expect( + removeField( + ['core', 'builder'], + dedent` + export const addons = []; + ` + ) + ).toMatchInlineSnapshot(`export const addons = [];`); + }); + it('missing field', () => { + expect( + removeField( + ['core', 'builder'], + dedent` + export const core = { foo: 'bar' }; + ` + ) + ).toMatchInlineSnapshot(` + export const core = { + foo: 'bar' + }; + `); + }); + it('found scalar', () => { + expect( + removeField( + ['core', 'builder'], + dedent` + export const core = { builder: 'webpack4' }; + ` + ) + ).toMatchInlineSnapshot(`export const core = {};`); + }); + it('found object', () => { + expect( + removeField( + ['core', 'builder'], + dedent` + export const core = { builder: { name: 'webpack4' } }; + ` + ) + ).toMatchInlineSnapshot(`export const core = {};`); + }); + it('nested object', () => { + expect( + removeField( + ['core', 'builder', 'name'], + dedent` + export const core = { builder: { name: 'webpack4' } }; + ` + ) + ).toMatchInlineSnapshot(` + export const core = { + builder: {} + }; + `); + }); + it('string literal key', () => { + expect( + removeField( + ['core', 'builder'], + dedent` + export const core = { 'builder': 'webpack4' }; + ` + ) + ).toMatchInlineSnapshot(`export const core = {};`); + }); + it('variable export', () => { + expect( + removeField( + ['core', 'builder'], + dedent` + const coreVar = { builder: 'webpack4' }; + export const core = coreVar; + ` + ) + ).toMatchInlineSnapshot(` + const coreVar = {}; + export const core = coreVar; + `); + }); + it('root export variable', () => { + expect( + removeField( + ['core'], + dedent` + export const core = { builder: { name: 'webpack4' } }; + + export const addons = []; + ` + ) + ).toMatchInlineSnapshot(`export const addons = [];`); + }); + }); + + describe('module exports', () => { + it('missing export', () => { + expect( + removeField( + ['core', 'builder'], + dedent` + module.exports = { addons: [] }; + ` + ) + ).toMatchInlineSnapshot(` + module.exports = { + addons: [] + }; + `); + }); + it('missing field', () => { + expect( + removeField( + ['core', 'builder'], + dedent` + module.exports = { core: { foo: 'bar' }}; + ` + ) + ).toMatchInlineSnapshot(` + module.exports = { + core: { + foo: 'bar' + } + }; + `); + }); + it('found scalar', () => { + expect( + removeField( + ['core', 'builder'], + dedent` + module.exports = { core: { builder: 'webpack4' } }; + ` + ) + ).toMatchInlineSnapshot(` + module.exports = { + core: {} + }; + `); + }); + it('nested scalar', () => { + expect( + removeField( + ['core', 'builder', 'name'], + dedent` + module.exports = { core: { builder: { name: 'webpack4' } } }; + ` + ) + ).toMatchInlineSnapshot(` + module.exports = { + core: { + builder: {} + } + }; + `); + }); + it('string literal key', () => { + expect( + removeField( + ['core', 'builder'], + dedent` + module.exports = { 'core': { 'builder': 'webpack4' } }; + ` + ) + ).toMatchInlineSnapshot(` + module.exports = { + 'core': {} + }; + `); + }); + it('root property', () => { + expect( + removeField( + ['core'], + dedent` + module.exports = { core: { builder: { name: 'webpack4' } }, addons: [] }; + ` + ) + ).toMatchInlineSnapshot(` + module.exports = { + addons: [] + }; + `); + }); + }); + + describe('default export', () => { + it('missing export', () => { + expect( + removeField( + ['core', 'builder'], + dedent` + export default { addons: [] }; + ` + ) + ).toMatchInlineSnapshot(` + export default { + addons: [] + }; + `); + }); + it('missing field', () => { + expect( + removeField( + ['core', 'builder'], + dedent` + export default { core: { foo: 'bar' }}; + ` + ) + ).toMatchInlineSnapshot(` + export default { + core: { + foo: 'bar' + } + }; + `); + }); + it('found scalar', () => { + expect( + removeField( + ['core', 'builder'], + dedent` + export default { core: { builder: 'webpack4' } }; + ` + ) + ).toMatchInlineSnapshot(` + export default { + core: {} + }; + `); + }); + it('nested scalar', () => { + expect( + removeField( + ['core', 'builder', 'name'], + dedent` + export default { core: { builder: { name: 'webpack4' } } }; + ` + ) + ).toMatchInlineSnapshot(` + export default { + core: { + builder: {} + } + }; + `); + }); + it('string literal key', () => { + expect( + removeField( + ['core', 'builder'], + dedent` + export default { 'core': { 'builder': 'webpack4' } }; + ` + ) + ).toMatchInlineSnapshot(` + export default { + 'core': {} + }; + `); + }); + it('root property', () => { + expect( + removeField( + ['core'], + dedent` + export default { core: { builder: { name: 'webpack4' } }, addons: [] }; + ` + ) + ).toMatchInlineSnapshot(` + export default { + addons: [] + }; + `); + }); + }); + + describe('quotes', () => { + it('no quotes', () => { + expect(setField(['foo', 'bar'], 'baz', '')).toMatchInlineSnapshot(` + export const foo = { + bar: "baz" + }; + `); + }); + it('more single quotes', () => { + expect(setField(['foo', 'bar'], 'baz', `export const stories = ['a', 'b', "c"]`)) + .toMatchInlineSnapshot(` + export const stories = ['a', 'b', "c"]; + export const foo = { + bar: 'baz' + }; + `); + }); + it('more double quotes', () => { + expect(setField(['foo', 'bar'], 'baz', `export const stories = ['a', "b", "c"]`)) + .toMatchInlineSnapshot(` + export const stories = ['a', "b", "c"]; + export const foo = { + bar: "baz" + }; + `); + }); + }); + }); }); diff --git a/code/lib/csf-tools/src/ConfigFile.ts b/code/lib/csf-tools/src/ConfigFile.ts index e9fde5c61b19..37e1cb6c3e87 100644 --- a/code/lib/csf-tools/src/ConfigFile.ts +++ b/code/lib/csf-tools/src/ConfigFile.ts @@ -31,6 +31,27 @@ const _getPath = (path: string[], node: t.Node): t.Node | undefined => { return undefined; }; +// eslint-disable-next-line @typescript-eslint/naming-convention +const _getPathProperties = (path: string[], node: t.Node): t.ObjectProperty[] | undefined => { + if (path.length === 0) { + if (t.isObjectExpression(node)) { + return node.properties as t.ObjectProperty[]; + } + throw new Error('Expected object expression'); + } + if (t.isObjectExpression(node)) { + const [first, ...rest] = path; + const field = node.properties.find((p: t.ObjectProperty) => propKey(p) === first); + if (field) { + // FXIME handle spread etc. + if (rest.length === 0) return node.properties as t.ObjectProperty[]; + + return _getPathProperties(rest, (field as t.ObjectProperty).value); + } + } + return undefined; +}; + // eslint-disable-next-line @typescript-eslint/naming-convention const _findVarInitialization = (identifier: string, program: t.Program) => { let init: t.Expression | null | undefined = null; @@ -196,6 +217,13 @@ export class ConfigFile { return _getPath(rest, exported); } + getFieldProperties(path: string[]) { + const [root, ...rest] = path; + const exported = this._exports[root]; + if (!exported) return undefined; + return _getPathProperties(rest, exported); + } + getFieldValue(path: string[]) { const node = this.getFieldNode(path); if (node) { @@ -226,6 +254,63 @@ export class ConfigFile { } } + removeField(path: string[]) { + const removeProperty = (properties: t.ObjectProperty[], prop: string) => { + const index = properties.findIndex( + (p) => + (t.isIdentifier(p.key) && p.key.name === prop) || + (t.isStringLiteral(p.key) && p.key.value === prop) + ); + if (index >= 0) { + properties.splice(index, 1); + } + }; + // the structure of this._exports doesn't work for this use case + // so we have to manually bypass it here + if (path.length === 1) { + let removedRootProperty = false; + // removing the root export + this._ast.program.body.forEach((node) => { + // named export + if (t.isExportNamedDeclaration(node) && t.isVariableDeclaration(node.declaration)) { + const decl = node.declaration.declarations[0]; + if (t.isIdentifier(decl.id) && decl.id.name === path[0]) { + this._ast.program.body.splice(this._ast.program.body.indexOf(node), 1); + removedRootProperty = true; + } + } + // default export + if (t.isExportDefaultDeclaration(node) && t.isObjectExpression(node.declaration)) { + const properties = node.declaration.properties as t.ObjectProperty[]; + removeProperty(properties, path[0]); + removedRootProperty = true; + } + // module.exports + if ( + t.isExpressionStatement(node) && + t.isAssignmentExpression(node.expression) && + t.isMemberExpression(node.expression.left) && + t.isIdentifier(node.expression.left.object) && + node.expression.left.object.name === 'module' && + t.isIdentifier(node.expression.left.property) && + node.expression.left.property.name === 'exports' && + t.isObjectExpression(node.expression.right) + ) { + const properties = node.expression.right.properties as t.ObjectProperty[]; + removeProperty(properties, path[0]); + removedRootProperty = true; + } + }); + if (removedRootProperty) return; + } + + const properties = this.getFieldProperties(path) as t.ObjectProperty[]; + if (properties) { + const lastPath = path.at(-1); + removeProperty(properties, lastPath); + } + } + _inferQuotes() { if (!this._quotes) { // first 500 tokens for efficiency diff --git a/code/yarn.lock b/code/yarn.lock index ffa44e777780..2360cbd7fa6e 100644 --- a/code/yarn.lock +++ b/code/yarn.lock @@ -7498,6 +7498,7 @@ __metadata: resolution: "@storybook/sveltekit@workspace:frameworks/sveltekit" dependencies: "@storybook/builder-vite": 7.0.0-beta.2 + "@storybook/svelte": 7.0.0-beta.2 "@storybook/svelte-vite": 7.0.0-beta.2 "@types/node": ^16.0.0 typescript: ^4.9.3