diff --git a/code/builders/builder-webpack5/src/preview/loaders.ts b/code/builders/builder-webpack5/src/preview/loaders.ts index 26943cd90e06..f10bd93a5ebc 100644 --- a/code/builders/builder-webpack5/src/preview/loaders.ts +++ b/code/builders/builder-webpack5/src/preview/loaders.ts @@ -10,6 +10,7 @@ export const createBabelLoader = ( typescriptOptions: TypescriptOptions, excludes: string[] = [] ) => { + logger.info(dedent`Using Babel compiler`); return { test: typescriptOptions.skipBabel ? /\.(mjs|jsx?)$/ : /\.(mjs|tsx?|jsx?)$/, use: [ @@ -24,9 +25,7 @@ export const createBabelLoader = ( }; export const createSWCLoader = async (excludes: string[] = [], options: Options) => { - logger.warn(dedent` - The SWC loader is an experimental feature and may change or even be removed at any time. - `); + logger.info(dedent`Using SWC compiler`); const swc = await options.presets.apply('swc', {}, options); const typescriptOptions = await options.presets.apply<{ skipCompiler?: boolean }>( @@ -49,12 +48,8 @@ export const createSWCLoader = async (excludes: string[] = [], options: Options) }; return { test: typescriptOptions.skipCompiler ? /\.(mjs|cjs|jsx?)$/ : /\.(mjs|cjs|tsx?|jsx?)$/, - use: [ - { - loader: require.resolve('swc-loader'), - options: config, - }, - ], + loader: require.resolve('swc-loader'), + options: config, include: [getProjectRoot()], exclude: [/node_modules/, ...excludes], }; diff --git a/code/e2e-tests/addon-controls.spec.ts b/code/e2e-tests/addon-controls.spec.ts index df376782aae8..2c388d7ef598 100644 --- a/code/e2e-tests/addon-controls.spec.ts +++ b/code/e2e-tests/addon-controls.spec.ts @@ -31,18 +31,22 @@ test.describe('addon-controls', () => { ); const toggle = sbPage.panelContent().locator('input[name=primary]'); await toggle.click(); - await expect(sbPage.previewRoot().locator('button')).toHaveCSS( - 'background-color', - 'rgba(0, 0, 0, 0)' - ); + await expect(async () => { + await expect(sbPage.previewRoot().locator('button')).toHaveCSS( + 'background-color', + 'rgba(0, 0, 0, 0)' + ); + }).toPass(); // Color picker: Background color const color = sbPage.panelContent().locator('input[placeholder="Choose color..."]'); await color.fill('red'); - await expect(sbPage.previewRoot().locator('button')).toHaveCSS( - 'background-color', - 'rgb(255, 0, 0)' - ); + await expect(async () => { + await expect(sbPage.previewRoot().locator('button')).toHaveCSS( + 'background-color', + 'rgb(255, 0, 0)' + ); + }).toPass(); // TODO: enable this once the controls for size are aligned in all CLI templates. // Radio buttons: Size diff --git a/code/frameworks/nextjs/src/swc/loader.ts b/code/frameworks/nextjs/src/swc/loader.ts index 3c235c343f74..201bdc52e0d8 100644 --- a/code/frameworks/nextjs/src/swc/loader.ts +++ b/code/frameworks/nextjs/src/swc/loader.ts @@ -6,8 +6,7 @@ import type { NextConfig } from 'next'; import path from 'path'; import type { RuleSetRule } from 'webpack'; import semver from 'semver'; -import { dedent } from 'ts-dedent'; -import { logger } from '@storybook/node-logger'; +import { NextjsSWCNotSupportedError } from 'lib/core-events/src/errors/server-errors'; import { getNextjsVersion } from '../utils'; export const configureSWCLoader = async ( @@ -19,13 +18,7 @@ export const configureSWCLoader = async ( const version = getNextjsVersion(); if (semver.lt(version, '14.0.0')) { - logger.warn( - dedent`You have activated the SWC mode for Next.js, but you are not using Next.js 14.0.0 or higher. - SWC is only supported in Next.js 14.0.0 and higher. - Skipping SWC and using Babel instead. - ` - ); - return; + throw new NextjsSWCNotSupportedError(); } const dir = getProjectRoot(); @@ -43,14 +36,14 @@ export const configureSWCLoader = async ( baseConfig.module.rules = [ // TODO: Remove filtering in Storybook 8.0 - ...baseConfig.module.rules.filter( - (r: RuleSetRule) => - !(typeof r.use === 'object' && 'loader' in r.use && r.use.loader?.includes('swc-loader')) - ), + ...baseConfig.module.rules.filter((r: RuleSetRule) => { + return !r.loader?.includes('swc-loader'); + }), { test: /\.(m?(j|t)sx?)$/, include: [getProjectRoot()], exclude: [/(node_modules)/, ...Object.keys(virtualModules)], + enforce: 'post', use: { // we use our own patch because we need to remove tracing from the original code // which is not possible otherwise @@ -61,14 +54,12 @@ export const configureSWCLoader = async ( pagesDir: `${dir}/pages`, appDir: `${dir}/apps`, hasReactRefresh: isDevelopment, - hasServerComponents: true, nextConfig, supportedBrowsers: require('next/dist/build/utils').getSupportedBrowsers( dir, isDevelopment ), swcCacheDir: path.join(dir, nextConfig?.distDir ?? '.next', 'cache', 'swc'), - isServerLayer: false, bundleTarget: 'default', }, }, diff --git a/code/frameworks/nextjs/src/swc/next-swc-loader-patch.ts b/code/frameworks/nextjs/src/swc/next-swc-loader-patch.ts index 9fd155951fcd..114daaddc293 100644 --- a/code/frameworks/nextjs/src/swc/next-swc-loader-patch.ts +++ b/code/frameworks/nextjs/src/swc/next-swc-loader-patch.ts @@ -165,11 +165,20 @@ export function pitch(this: any) { }, callback); } +function sanitizeSourceMap(rawSourceMap: any): any { + const { sourcesContent, ...sourceMap } = rawSourceMap ?? {}; + + // JSON parse/stringify trick required for swc to accept the SourceMap + return JSON.parse(JSON.stringify(sourceMap)); +} + export default function swcLoader(this: any, inputSource: string, inputSourceMap: any) { const loaderSpan = mockCurrentTraceSpan.traceChild('next-swc-loader'); const callback = this.async(); loaderSpan - .traceAsyncFn(() => loaderTransform.call(this, loaderSpan, inputSource, inputSourceMap)) + .traceAsyncFn(() => + loaderTransform.call(this, loaderSpan, inputSource, sanitizeSourceMap(inputSourceMap)) + ) .then( ([transformedSource, outputSourceMap]: any) => { callback(null, transformedSource, outputSourceMap || inputSourceMap); diff --git a/code/lib/cli/src/generators/ANGULAR/index.ts b/code/lib/cli/src/generators/ANGULAR/index.ts index 3c4d9a1f0ca9..c8c7f3f288b3 100644 --- a/code/lib/cli/src/generators/ANGULAR/index.ts +++ b/code/lib/cli/src/generators/ANGULAR/index.ts @@ -1,5 +1,4 @@ import { join } from 'path'; -import semver from 'semver'; import { baseGenerator } from '../baseGenerator'; import type { Generator } from '../types'; import { CoreBuilder } from '../../project_types'; @@ -13,10 +12,6 @@ const generator: Generator<{ projectName: string }> = async ( options, commandOptions ) => { - const angularVersion = await packageManager.getPackageVersion('@angular/core'); - const isWebpack5 = angularVersion && semver.gte(angularVersion, '12.0.0'); - const updatedOptions = isWebpack5 ? { ...options, builder: CoreBuilder.Webpack5 } : options; - const angularJSON = new AngularJSON(); if ( @@ -62,7 +57,8 @@ const generator: Generator<{ projectName: string }> = async ( packageManager, npmOptions, { - ...updatedOptions, + ...options, + builder: CoreBuilder.Webpack5, ...(useCompodoc && { frameworkPreviewParts: { prefix: compoDocPreviewPrefix, diff --git a/code/lib/cli/src/generators/HTML/index.ts b/code/lib/cli/src/generators/HTML/index.ts index 781d580d2067..c4e0af830fbd 100755 --- a/code/lib/cli/src/generators/HTML/index.ts +++ b/code/lib/cli/src/generators/HTML/index.ts @@ -1,8 +1,11 @@ +import { CoreBuilder } from '../../project_types'; import { baseGenerator } from '../baseGenerator'; import type { Generator } from '../types'; const generator: Generator = async (packageManager, npmOptions, options) => { - await baseGenerator(packageManager, npmOptions, options, 'html'); + await baseGenerator(packageManager, npmOptions, options, 'html', { + useSWC: ({ builder }) => builder === CoreBuilder.Webpack5, + }); }; export default generator; diff --git a/code/lib/cli/src/generators/PREACT/index.ts b/code/lib/cli/src/generators/PREACT/index.ts index e5bf286467a6..6bbab88e16a3 100644 --- a/code/lib/cli/src/generators/PREACT/index.ts +++ b/code/lib/cli/src/generators/PREACT/index.ts @@ -1,8 +1,11 @@ +import { CoreBuilder } from '../../project_types'; import { baseGenerator } from '../baseGenerator'; import type { Generator } from '../types'; const generator: Generator = async (packageManager, npmOptions, options) => { - await baseGenerator(packageManager, npmOptions, options, 'preact'); + await baseGenerator(packageManager, npmOptions, options, 'preact', { + useSWC: ({ builder }) => builder === CoreBuilder.Webpack5, + }); }; export default generator; diff --git a/code/lib/cli/src/generators/REACT/index.ts b/code/lib/cli/src/generators/REACT/index.ts index 208c62bf25d4..046860356c56 100644 --- a/code/lib/cli/src/generators/REACT/index.ts +++ b/code/lib/cli/src/generators/REACT/index.ts @@ -1,5 +1,5 @@ import { detectLanguage } from '../../detect'; -import { SupportedLanguage } from '../../project_types'; +import { CoreBuilder, SupportedLanguage } from '../../project_types'; import { baseGenerator } from '../baseGenerator'; import type { Generator } from '../types'; @@ -10,6 +10,7 @@ const generator: Generator = async (packageManager, npmOptions, options) => { await baseGenerator(packageManager, npmOptions, options, 'react', { extraPackages, + useSWC: ({ builder }) => builder === CoreBuilder.Webpack5, extraAddons: ['@storybook/addon-onboarding'], }); }; diff --git a/code/lib/cli/src/generators/REACT_SCRIPTS/index.ts b/code/lib/cli/src/generators/REACT_SCRIPTS/index.ts index 866b2210664a..2177a9d5090e 100644 --- a/code/lib/cli/src/generators/REACT_SCRIPTS/index.ts +++ b/code/lib/cli/src/generators/REACT_SCRIPTS/index.ts @@ -59,6 +59,7 @@ const generator: Generator = async (packageManager, npmOptions, options) => { { ...options, builder: CoreBuilder.Webpack5 }, 'react', { + useSWC: () => true, extraAddons, extraPackages, staticDir: fs.existsSync(path.resolve('./public')) ? 'public' : undefined, diff --git a/code/lib/cli/src/generators/SERVER/index.ts b/code/lib/cli/src/generators/SERVER/index.ts index c99b69e4902d..7ced80f7441c 100755 --- a/code/lib/cli/src/generators/SERVER/index.ts +++ b/code/lib/cli/src/generators/SERVER/index.ts @@ -9,6 +9,7 @@ const generator: Generator = async (packageManager, npmOptions, options) => { { ...options, builder: CoreBuilder.Webpack5 }, 'server', { + useSWC: () => true, extensions: ['json', 'yaml', 'yml'], } ); diff --git a/code/lib/cli/src/generators/SFC_VUE/index.ts b/code/lib/cli/src/generators/SFC_VUE/index.ts index e2849a352d90..a3e2f15ea604 100644 --- a/code/lib/cli/src/generators/SFC_VUE/index.ts +++ b/code/lib/cli/src/generators/SFC_VUE/index.ts @@ -1,8 +1,11 @@ +import { CoreBuilder } from '../../project_types'; import { baseGenerator } from '../baseGenerator'; import type { Generator } from '../types'; const generator: Generator = async (packageManager, npmOptions, options) => { - await baseGenerator(packageManager, npmOptions, options, 'vue'); + await baseGenerator(packageManager, npmOptions, options, 'vue', { + useSWC: ({ builder }) => builder === CoreBuilder.Webpack5, + }); }; export default generator; diff --git a/code/lib/cli/src/generators/VUE/index.ts b/code/lib/cli/src/generators/VUE/index.ts index c1869a539695..6b771973a283 100644 --- a/code/lib/cli/src/generators/VUE/index.ts +++ b/code/lib/cli/src/generators/VUE/index.ts @@ -7,6 +7,7 @@ const generator: Generator = async (packageManager, npmOptions, options) => { extraPackages: async ({ builder }) => { return builder === CoreBuilder.Webpack5 ? ['vue-loader@^15.7.0'] : []; }, + useSWC: ({ builder }) => builder === CoreBuilder.Webpack5, }); }; diff --git a/code/lib/cli/src/generators/VUE3/index.ts b/code/lib/cli/src/generators/VUE3/index.ts index 63dbddede7b5..ec20a5b946a1 100644 --- a/code/lib/cli/src/generators/VUE3/index.ts +++ b/code/lib/cli/src/generators/VUE3/index.ts @@ -9,6 +9,7 @@ const generator: Generator = async (packageManager, npmOptions, options) => { ? ['vue-loader@^17.0.0', '@vue/compiler-sfc@^3.2.0'] : []; }, + useSWC: ({ builder }) => builder === CoreBuilder.Webpack5, }); }; diff --git a/code/lib/cli/src/generators/WEB-COMPONENTS/index.ts b/code/lib/cli/src/generators/WEB-COMPONENTS/index.ts index 667395096743..bf5ceee43c15 100755 --- a/code/lib/cli/src/generators/WEB-COMPONENTS/index.ts +++ b/code/lib/cli/src/generators/WEB-COMPONENTS/index.ts @@ -1,9 +1,11 @@ +import { CoreBuilder } from '../../project_types'; import { baseGenerator } from '../baseGenerator'; import type { Generator } from '../types'; const generator: Generator = async (packageManager, npmOptions, options) => { return baseGenerator(packageManager, npmOptions, options, 'web-components', { extraPackages: ['lit'], + useSWC: ({ builder }) => builder === CoreBuilder.Webpack5, }); }; diff --git a/code/lib/cli/src/generators/WEBPACK_REACT/index.ts b/code/lib/cli/src/generators/WEBPACK_REACT/index.ts index 867bd82b80c2..94e8babee466 100644 --- a/code/lib/cli/src/generators/WEBPACK_REACT/index.ts +++ b/code/lib/cli/src/generators/WEBPACK_REACT/index.ts @@ -1,9 +1,11 @@ +import { CoreBuilder } from '../../project_types'; import { baseGenerator } from '../baseGenerator'; import type { Generator } from '../types'; const generator: Generator = async (packageManager, npmOptions, options) => { await baseGenerator(packageManager, npmOptions, options, 'react', { extraAddons: ['@storybook/addon-onboarding'], + useSWC: ({ builder }) => builder === CoreBuilder.Webpack5, }); }; diff --git a/code/lib/cli/src/generators/baseGenerator.ts b/code/lib/cli/src/generators/baseGenerator.ts index a7bdb1764668..6083fae9e873 100644 --- a/code/lib/cli/src/generators/baseGenerator.ts +++ b/code/lib/cli/src/generators/baseGenerator.ts @@ -29,6 +29,7 @@ const defaultOptions: FrameworkOptions = { addMainFile: true, addComponents: true, skipBabel: false, + useSWC: () => false, extraMain: undefined, framework: undefined, extensions: undefined, @@ -194,6 +195,21 @@ export async function baseGenerator( builder = await detectBuilder(packageManager, projectType); } + const { + packages: frameworkPackages, + type, + rendererId, + framework: frameworkInclude, + builder: builderInclude, + } = getFrameworkDetails( + renderer, + builder, + pnp, + language, + framework, + shouldApplyRequireWrapperOnPackageNames + ); + const { extraAddons: extraAddonPackages, extraPackages, @@ -201,30 +217,26 @@ export async function baseGenerator( addScripts, addMainFile, addComponents, - skipBabel, extraMain, extensions, storybookConfigFolder, componentsDestinationPath, + useSWC, } = { ...defaultOptions, ...options, }; - const { - packages: frameworkPackages, - type, - rendererId, - framework: frameworkInclude, - builder: builderInclude, - } = getFrameworkDetails( - renderer, - builder, - pnp, - language, - framework, - shouldApplyRequireWrapperOnPackageNames - ); + let { skipBabel } = { + ...defaultOptions, + ...options, + }; + + const swc = useSWC({ builder }); + + if (swc) { + skipBabel = true; + } const extraAddonsToInstall = typeof extraAddonPackages === 'function' @@ -401,7 +413,18 @@ export async function baseGenerator( : []; await configureMain({ - framework: { name: frameworkInclude, options: options.framework || {} }, + framework: { + name: frameworkInclude, + options: swc + ? { + ...(options.framework ?? {}), + builder: { + ...(options.framework?.builder ?? {}), + useSWC: true, + }, + } + : options.framework || {}, + }, prefixes, storybookConfigFolder, docs: { autodocs: 'tag' }, diff --git a/code/lib/cli/src/generators/types.ts b/code/lib/cli/src/generators/types.ts index 1711505e0bdc..2f97a34df126 100644 --- a/code/lib/cli/src/generators/types.ts +++ b/code/lib/cli/src/generators/types.ts @@ -24,6 +24,7 @@ export interface FrameworkOptions { addMainFile?: boolean; addComponents?: boolean; skipBabel?: boolean; + useSWC?: ({ builder }: { builder: Builder }) => boolean; extraMain?: any; extensions?: string[]; framework?: Record; diff --git a/code/lib/cli/src/initiate.ts b/code/lib/cli/src/initiate.ts index e2966a0c1798..3afd703a1e08 100644 --- a/code/lib/cli/src/initiate.ts +++ b/code/lib/cli/src/initiate.ts @@ -57,7 +57,7 @@ const installStorybook = async ( linkable: !!options.linkable, pnp: pnp || options.usePnp, yes: options.yes, - projectType: options.type, + projectType, }; const runGenerator: () => Promise = async () => { diff --git a/code/lib/codemod/package.json b/code/lib/codemod/package.json index c805f990a8de..ac98a974c4b3 100644 --- a/code/lib/codemod/package.json +++ b/code/lib/codemod/package.json @@ -62,13 +62,13 @@ "@types/cross-spawn": "^6.0.2", "cross-spawn": "^7.0.3", "globby": "^11.0.2", - "jscodeshift": "^0.14.0", + "jscodeshift": "^0.15.1", "lodash": "^4.17.21", "prettier": "^2.8.0", "recast": "^0.23.1" }, "devDependencies": { - "@types/jscodeshift": "^0.11.6", + "@types/jscodeshift": "^0.11.10", "ansi-regex": "^5.0.1", "jest": "^29.7.0", "jest-specific-snapshot": "^8.0.0", diff --git a/code/lib/core-events/src/errors/server-errors.ts b/code/lib/core-events/src/errors/server-errors.ts index 951a482e9570..6ca430ae1966 100644 --- a/code/lib/core-events/src/errors/server-errors.ts +++ b/code/lib/core-events/src/errors/server-errors.ts @@ -368,3 +368,20 @@ export class GoogleFontsLoadingError extends StorybookError { `; } } + +export class NextjsSWCNotSupportedError extends StorybookError { + readonly category = Category.FRAMEWORK_NEXTJS; + + readonly code = 3; + + public readonly documentation = + 'https://github.com/storybookjs/storybook/blob/next/code/frameworks/nextjs/README.md#manual-migration'; + + template() { + return dedent` + You have activated the SWC mode for Next.js, but you are not using Next.js 14.0.0 or higher. + SWC is only supported in Next.js 14.0.0 and higher. Please go to your .storybook/main. file + and remove the { framework: { options: { builder: { useSWC: true } } } } option or upgrade to Next.js v14 or later. + `; + } +} diff --git a/code/lib/postinstall/package.json b/code/lib/postinstall/package.json index a9779b34bd82..9e2a19920e07 100644 --- a/code/lib/postinstall/package.json +++ b/code/lib/postinstall/package.json @@ -47,7 +47,7 @@ "devDependencies": { "jest": "^29.7.0", "jest-specific-snapshot": "^8.0.0", - "jscodeshift": "^0.14.0", + "jscodeshift": "^0.15.1", "typescript": "~4.9.3" }, "publishConfig": { diff --git a/code/yarn.lock b/code/yarn.lock index 26430758888f..df84273184ce 100644 --- a/code/yarn.lock +++ b/code/yarn.lock @@ -6311,13 +6311,13 @@ __metadata: "@storybook/node-logger": "workspace:*" "@storybook/types": "workspace:*" "@types/cross-spawn": "npm:^6.0.2" - "@types/jscodeshift": "npm:^0.11.6" + "@types/jscodeshift": "npm:^0.11.10" ansi-regex: "npm:^5.0.1" cross-spawn: "npm:^7.0.3" globby: "npm:^11.0.2" jest: "npm:^29.7.0" jest-specific-snapshot: "npm:^8.0.0" - jscodeshift: "npm:^0.14.0" + jscodeshift: "npm:^0.15.1" lodash: "npm:^4.17.21" mdast-util-mdx-jsx: "npm:^2.1.2" mdast-util-mdxjs-esm: "npm:^1.3.1" @@ -6925,7 +6925,7 @@ __metadata: dependencies: jest: "npm:^29.7.0" jest-specific-snapshot: "npm:^8.0.0" - jscodeshift: "npm:^0.14.0" + jscodeshift: "npm:^0.15.1" typescript: "npm:~4.9.3" languageName: unknown linkType: soft @@ -8939,13 +8939,13 @@ __metadata: languageName: node linkType: hard -"@types/jscodeshift@npm:^0.11.6": - version: 0.11.7 - resolution: "@types/jscodeshift@npm:0.11.7" +"@types/jscodeshift@npm:^0.11.10": + version: 0.11.10 + resolution: "@types/jscodeshift@npm:0.11.10" dependencies: ast-types: "npm:^0.14.1" recast: "npm:^0.20.3" - checksum: a2c26f8e64950296bae6176c52e832e1f5c5eb3672adad3c1cdc63e23b8bd3de47890ac8eaae7eb0788feea7628ce540513ff5189379f79e882ddcfa1c855cfc + checksum: 1d477ea1addd62a5949f028ef16bac3226341d65052e4f51d61e51789c6c7aa17e953dac34eb6d1e5a2b761fc4c7920df875e20e85cdf4122fc08836e7da547a languageName: node linkType: hard @@ -11157,15 +11157,6 @@ __metadata: languageName: node linkType: hard -"ast-types@npm:0.15.2": - version: 0.15.2 - resolution: "ast-types@npm:0.15.2" - dependencies: - tslib: "npm:^2.0.1" - checksum: 5b26e3656e9e8d1db8c8d14971d0cb88ca0138aacce72171cb4cd4555fc8dc53c07e821c568e57fe147366931708fefd25cb9d7e880d42ce9cb569947844c962 - languageName: node - linkType: hard - "ast-types@npm:^0.16.1": version: 0.16.1 resolution: "ast-types@npm:0.16.1" @@ -20130,37 +20121,6 @@ __metadata: languageName: node linkType: hard -"jscodeshift@npm:^0.14.0": - version: 0.14.0 - resolution: "jscodeshift@npm:0.14.0" - dependencies: - "@babel/core": "npm:^7.13.16" - "@babel/parser": "npm:^7.13.16" - "@babel/plugin-proposal-class-properties": "npm:^7.13.0" - "@babel/plugin-proposal-nullish-coalescing-operator": "npm:^7.13.8" - "@babel/plugin-proposal-optional-chaining": "npm:^7.13.12" - "@babel/plugin-transform-modules-commonjs": "npm:^7.13.8" - "@babel/preset-flow": "npm:^7.13.13" - "@babel/preset-typescript": "npm:^7.13.0" - "@babel/register": "npm:^7.13.16" - babel-core: "npm:^7.0.0-bridge.0" - chalk: "npm:^4.1.2" - flow-parser: "npm:0.*" - graceful-fs: "npm:^4.2.4" - micromatch: "npm:^4.0.4" - neo-async: "npm:^2.5.0" - node-dir: "npm:^0.1.17" - recast: "npm:^0.21.0" - temp: "npm:^0.8.4" - write-file-atomic: "npm:^2.3.0" - peerDependencies: - "@babel/preset-env": ^7.1.6 - bin: - jscodeshift: bin/jscodeshift.js - checksum: dab63bdb4b7e67d79634fcd3f5dc8b227146e9f68aa88700bc49c5a45b6339d05bd934a98aa53d29abd04f81237d010e7e037799471b2aab66ec7b9a7d752786 - languageName: node - linkType: hard - "jscodeshift@npm:^0.15.1": version: 0.15.1 resolution: "jscodeshift@npm:0.15.1" @@ -25957,18 +25917,6 @@ __metadata: languageName: node linkType: hard -"recast@npm:^0.21.0": - version: 0.21.5 - resolution: "recast@npm:0.21.5" - dependencies: - ast-types: "npm:0.15.2" - esprima: "npm:~4.0.0" - source-map: "npm:~0.6.1" - tslib: "npm:^2.0.1" - checksum: a45168c82195f24fa2c70293a624fece0069a2e8e8adb637f9963777735f81cb3bb62e55172db677ec3573b08b2daaf1eddd85b74da6fe0bd37c9b15eeaf94b4 - languageName: node - linkType: hard - "recast@npm:^0.23.1, recast@npm:^0.23.3": version: 0.23.4 resolution: "recast@npm:0.23.4"