diff --git a/code/addons/a11y/src/postinstall.ts b/code/addons/a11y/src/postinstall.ts index 0c2f457d5276..cf57bddb9853 100644 --- a/code/addons/a11y/src/postinstall.ts +++ b/code/addons/a11y/src/postinstall.ts @@ -25,7 +25,7 @@ export default async function postinstall(options: PostinstallOptions) { } if (options.configDir) { - command.push('--config-dir', options.configDir); + command.push('--config-dir', `"${options.configDir}"`); } await $`${command.join(' ')}`; diff --git a/code/addons/vitest/src/postinstall.ts b/code/addons/vitest/src/postinstall.ts index c327a3375881..2cce5d01bbfe 100644 --- a/code/addons/vitest/src/postinstall.ts +++ b/code/addons/vitest/src/postinstall.ts @@ -2,7 +2,7 @@ import { existsSync } from 'node:fs'; import * as fs from 'node:fs/promises'; import { writeFile } from 'node:fs/promises'; import { isAbsolute, posix, sep } from 'node:path'; -import { fileURLToPath } from 'node:url'; +import { fileURLToPath, pathToFileURL } from 'node:url'; import { babelParse, generate, traverse } from 'storybook/internal/babel'; import { @@ -513,7 +513,7 @@ export default async function postInstall(options: PostinstallOptions) { } if (options.configDir !== '.storybook') { - command.push('--config-dir', options.configDir); + command.push('--config-dir', `"${options.configDir}"`); } await execa('storybook', command, { @@ -579,7 +579,9 @@ async function getPackageNameFromPath(input: string): Promise { throw new Error(`Could not find package.json in path: ${path}`); } - const { default: packageJson } = await import(packageJsonPath, { with: { type: 'json' } }); + const { default: packageJson } = await import(pathToFileURL(packageJsonPath).href, { + with: { type: 'json' }, + }); return packageJson.name; } diff --git a/code/core/scripts/generate-source-files.ts b/code/core/scripts/generate-source-files.ts index 5cd6f7668fa5..0e8c6fe0e92e 100644 --- a/code/core/scripts/generate-source-files.ts +++ b/code/core/scripts/generate-source-files.ts @@ -3,6 +3,7 @@ import { mkdirSync } from 'node:fs'; import { readdir, realpath, writeFile } from 'node:fs/promises'; import os from 'node:os'; import { join } from 'node:path'; +import { pathToFileURL } from 'node:url'; import { GlobalRegistrator } from '@happy-dom/global-registrator'; import { isNotNil } from 'es-toolkit'; @@ -154,7 +155,7 @@ async function generateExportsFile(prettierConfig: prettier.Options | null): Pro supported: SUPPORTED_FEATURES, }); - const { globalsNameValueMap: data } = await import(outFile); + const { globalsNameValueMap: data } = await import(pathToFileURL(outFile).href); // loop over all values of the keys of the data object and remove the default key for (const key in data) { diff --git a/code/core/src/bin/dispatcher.ts b/code/core/src/bin/dispatcher.ts index 6e2b2e2abf1a..71cc19f5e076 100644 --- a/code/core/src/bin/dispatcher.ts +++ b/code/core/src/bin/dispatcher.ts @@ -1,5 +1,6 @@ #!/usr/bin/env node import { spawn } from 'node:child_process'; +import { pathToFileURL } from 'node:url'; import { logger } from 'storybook/internal/node-logger'; @@ -36,7 +37,7 @@ async function run() { const args = process.argv.slice(2); if (['dev', 'build', 'index'].includes(args[0])) { - const coreBin = join(resolvePackageDir('storybook'), 'dist/bin/core.js'); + const coreBin = pathToFileURL(join(resolvePackageDir('storybook'), 'dist/bin/core.js')).href; await import(coreBin); return; } @@ -60,7 +61,7 @@ async function run() { if (targetCliPackageJson.version === versions[targetCli.pkg]) { command = [ 'node', - join(resolvePackageDir(targetCli.pkg), 'dist/bin/index.js'), + `"${join(resolvePackageDir(targetCli.pkg), 'dist/bin/index.js')}"`, ...targetCli.args, ]; } diff --git a/code/core/src/builder-manager/utils/files.ts b/code/core/src/builder-manager/utils/files.ts index 352d558dd981..f4d405319fe6 100644 --- a/code/core/src/builder-manager/utils/files.ts +++ b/code/core/src/builder-manager/utils/files.ts @@ -1,6 +1,6 @@ import { existsSync } from 'node:fs'; import { mkdir, writeFile } from 'node:fs/promises'; -import { dirname, join, normalize } from 'node:path'; +import { dirname, join, normalize, relative } from 'node:path'; import type { OutputFile } from 'esbuild'; import slash from 'slash'; @@ -31,9 +31,9 @@ export async function readOrderedFiles( } export function sanitizePath(file: OutputFile, addonsDir: string) { - const filePath = file.path.replace(addonsDir, ''); + const filePath = relative(addonsDir, file.path); const location = normalize(join(addonsDir, filePath)); - const url = `./sb-addons${slash(filePath).split('/').map(encodeURIComponent).join('/')}`; + const url = `./sb-addons/${slash(filePath).split('/').map(encodeURIComponent).join('/')}`; return { location, url }; } diff --git a/code/core/src/common/js-package-manager/PNPMProxy.ts b/code/core/src/common/js-package-manager/PNPMProxy.ts index 329507195084..c5fddbdf6e50 100644 --- a/code/core/src/common/js-package-manager/PNPMProxy.ts +++ b/code/core/src/common/js-package-manager/PNPMProxy.ts @@ -1,5 +1,6 @@ import { existsSync, readFileSync } from 'node:fs'; import { join } from 'node:path'; +import { pathToFileURL } from 'node:url'; import { prompt } from 'storybook/internal/node-logger'; import { FindPackageVersionsError } from 'storybook/internal/server-errors'; @@ -149,7 +150,7 @@ export class PNPMProxy extends JsPackageManager { if (pnpapiPath) { try { - const pnpApi = await import(pnpapiPath); + const pnpApi = await import(pathToFileURL(pnpapiPath).href); const resolvedPath = pnpApi.resolveToUnqualified(packageName, this.cwd, { considerBuiltins: false, diff --git a/code/core/src/common/js-package-manager/Yarn2Proxy.ts b/code/core/src/common/js-package-manager/Yarn2Proxy.ts index 287eb6304af4..9ea3c474b885 100644 --- a/code/core/src/common/js-package-manager/Yarn2Proxy.ts +++ b/code/core/src/common/js-package-manager/Yarn2Proxy.ts @@ -1,5 +1,6 @@ import { existsSync, readFileSync } from 'node:fs'; import { join } from 'node:path'; +import { pathToFileURL } from 'node:url'; import { prompt } from 'storybook/internal/node-logger'; import { FindPackageVersionsError } from 'storybook/internal/server-errors'; @@ -165,7 +166,7 @@ export class Yarn2Proxy extends JsPackageManager { which is not always the case for us, because we spawn child processes directly with Node, eg. when running automigrations. */ - const { default: pnpApi } = await import(pnpapiPath); + const { default: pnpApi } = await import(pathToFileURL(pnpapiPath).href); const resolvedPath = pnpApi.resolveToUnqualified( packageName, diff --git a/code/core/src/telemetry/package-json.ts b/code/core/src/telemetry/package-json.ts index b6bc40130b91..5c668e75af4c 100644 --- a/code/core/src/telemetry/package-json.ts +++ b/code/core/src/telemetry/package-json.ts @@ -1,5 +1,5 @@ import { readFile } from 'node:fs/promises'; -import { fileURLToPath } from 'node:url'; +import { fileURLToPath, pathToFileURL } from 'node:url'; import { findUp } from 'find-up'; import { join } from 'pathe'; @@ -41,7 +41,7 @@ export const getActualPackageJson = async ( ); } - const { default: packageJson } = await import(resolvedPackageJsonPath, { + const { default: packageJson } = await import(pathToFileURL(resolvedPackageJsonPath).href, { with: { type: 'json' }, }); return packageJson; diff --git a/code/frameworks/angular/src/server/angular-cli-webpack.js b/code/frameworks/angular/src/server/angular-cli-webpack.js index 58a91fe62603..07c4cefe0b50 100644 --- a/code/frameworks/angular/src/server/angular-cli-webpack.js +++ b/code/frameworks/angular/src/server/angular-cli-webpack.js @@ -91,7 +91,7 @@ export const getWebpackConfig = async (baseConfig, { builderOptions, builderCont * Angular's automatic Tailwind detection, we need to manually add the correct Tailwind 4 * plugin to all PostCSS loader configurations. */ - const tailwindPackagePath = fileURLToPath(import.meta.resolve('@tailwindcss/postcss', root)); + const tailwindPackagePath = import.meta.resolve('@tailwindcss/postcss', root); const tailwindPackage = await import(tailwindPackagePath); const extraPostcssPlugins = [ typeof tailwindPackage === 'function' ? tailwindPackage() : tailwindPackage.default(), diff --git a/code/lib/cli-storybook/src/link.ts b/code/lib/cli-storybook/src/link.ts index 078c78f94115..99fbbaea0df4 100644 --- a/code/lib/cli-storybook/src/link.ts +++ b/code/lib/cli-storybook/src/link.ts @@ -101,7 +101,7 @@ export const link = async ({ target, local, start }: LinkOptions) => { } logger.info(`Linking ${reproDir}`); - await exec(`yarn link --all --relative ${storybookDir}`, { cwd: reproDir }); + await exec(`yarn link --all --relative "${storybookDir}"`, { cwd: reproDir }); logger.info(`Installing ${reproName}`); diff --git a/code/presets/react-webpack/src/cra-config.ts b/code/presets/react-webpack/src/cra-config.ts index fe89dcda4e2a..4a06c99fb1d4 100644 --- a/code/presets/react-webpack/src/cra-config.ts +++ b/code/presets/react-webpack/src/cra-config.ts @@ -1,5 +1,6 @@ import { existsSync, readFileSync, realpathSync } from 'node:fs'; import { join } from 'node:path'; +import { pathToFileURL } from 'node:url'; import { logger } from 'storybook/internal/node-logger'; @@ -52,7 +53,7 @@ export function getReactScriptsPath({ noCache }: { noCache?: boolean } = {}) { export async function isReactScriptsInstalled(minimumVersion = '2.0.0') { try { const { default: reactScriptsJson } = await import( - join(getReactScriptsPath(), 'package.json'), + pathToFileURL(join(getReactScriptsPath(), 'package.json')).href, { with: { type: 'json' }, } diff --git a/scripts/build/build-package.ts b/scripts/build/build-package.ts index c42fc11547b4..8255e5c32230 100644 --- a/scripts/build/build-package.ts +++ b/scripts/build/build-package.ts @@ -11,6 +11,7 @@ /* eslint-disable local-rules/no-uncategorized-errors */ import { mkdir, rm } from 'node:fs/promises'; +import { pathToFileURL } from 'node:url'; import { join, relative } from 'pathe'; import picocolors from 'picocolors'; @@ -39,7 +40,9 @@ async function run() { throw new Error('Cannot watch and build for production at the same time'); } - const { default: pkg } = await import(join(DIR_CWD, 'package.json'), { with: { type: 'json' } }); + const { default: pkg } = await import(pathToFileURL(join(DIR_CWD, 'package.json')).href, { + with: { type: 'json' }, + }); await rm(DIR_DIST, { recursive: true }).catch(() => {}); await mkdir(DIR_DIST); diff --git a/scripts/build/utils/entry-utils.ts b/scripts/build/utils/entry-utils.ts index 33bd87ffcf3b..33c19946b3cb 100644 --- a/scripts/build/utils/entry-utils.ts +++ b/scripts/build/utils/entry-utils.ts @@ -2,6 +2,7 @@ import { builtinModules } from 'node:module'; import { join } from 'node:path'; import * as esbuild from 'esbuild'; +import { pathToFileURL } from 'node:url'; export type BuildEntry = { exportEntries?: ('.' | `./${string}`)[]; // the keys in the package.json's export map, e.g. ["./internal/manager-api", "./manager-api"] @@ -50,7 +51,7 @@ export const measure = async (fn: () => Promise) => { }; export const getExternal = async (cwd: string) => { - const { default: packageJson } = await import(join(cwd, 'package.json'), { + const { default: packageJson } = await import(pathToFileURL(join(cwd, 'package.json')).href, { with: { type: 'json' }, }); diff --git a/scripts/build/utils/generate-types.ts b/scripts/build/utils/generate-types.ts index 3aaf19d2dd9f..099bc30233e8 100644 --- a/scripts/build/utils/generate-types.ts +++ b/scripts/build/utils/generate-types.ts @@ -29,9 +29,10 @@ export async function generateTypesFiles(cwd: string, data: BuildEntries) { return limited(async () => { let timer: ReturnType | undefined; const dtsProcess = spawn( - join(import.meta.dirname, '..', '..', 'node_modules', '.bin', 'jiti'), - [join(import.meta.dirname, 'dts-process.ts'), entryPoint], + `"${join(import.meta.dirname, '..', '..', 'node_modules', '.bin', 'jiti')}"`, + [`"${join(import.meta.dirname, 'dts-process.ts')}"`, `"${entryPoint}"`], { + shell: true, cwd: DIR_CWD, stdio: ['ignore', 'inherit', 'pipe'], } diff --git a/scripts/knip.config.ts b/scripts/knip.config.ts index d6369f900323..b48c00647484 100644 --- a/scripts/knip.config.ts +++ b/scripts/knip.config.ts @@ -1,4 +1,5 @@ import { join, relative } from 'node:path'; +import { pathToFileURL } from 'node:url'; // eslint-disable-next-line depend/ban-dependencies import fg from 'fast-glob'; @@ -81,7 +82,9 @@ const baseConfig = { // Knip maps package.json#export to source files but the entries are incomplete export const addBundlerEntries = async (config: KnipConfig) => { const baseDir = join(__dirname, '../code'); - const rootManifest = await import(join(baseDir, 'package.json')); + const rootManifest = await import(pathToFileURL(join(baseDir, 'package.json')).href, { + with: { type: 'json' }, + }); const workspaceDirs = await fg(rootManifest.workspaces.packages, { cwd: baseDir, onlyDirectories: true, @@ -90,7 +93,9 @@ export const addBundlerEntries = async (config: KnipConfig) => { for (const wsDir of workspaceDirectories) { for (const configKey of Object.keys(baseConfig.workspaces)) { if (match([wsDir], configKey)) { - const manifest = await import(join(baseDir, wsDir, 'package.json')); + const manifest = await import(pathToFileURL(join(baseDir, wsDir, 'package.json')).href, { + with: { type: 'json' }, + }); const configEntries = (config.workspaces[configKey].entry as string[]) ?? []; const bundler = manifest?.bundler; for (const value of Object.values(bundler ?? {})) { diff --git a/scripts/run-registry.ts b/scripts/run-registry.ts index d8c1a0268657..64002e327909 100755 --- a/scripts/run-registry.ts +++ b/scripts/run-registry.ts @@ -129,23 +129,21 @@ const publish = async (packages: { name: string; location: string }[], url: stri packages.map(({ name, location }) => limit( () => - new Promise((res, rej) => { - logger.log( - `🛫 publishing ${name} (${location.replace(resolvePath(join(__dirname, '..')), '.')})` - ); + new Promise((resolve, reject) => { + const loggedLocation = location.replace(resolvePath(join(__dirname, '..')), '.'); + const resolvedLocation = resolvePath('../code', location); + + logger.log(`🛫 publishing ${name} (${loggedLocation})`); const tarballFilename = `${name.replace('@', '').replace('/', '-')}.tgz`; - const command = `cd ${resolvePath( - '../code', - location - )} && yarn pack --out=${PACKS_DIRECTORY}/${tarballFilename} && cd ${PACKS_DIRECTORY} && npm publish ./${tarballFilename} --registry ${url} --force --tag="xyz" --ignore-scripts`; + const command = `cd "${resolvedLocation}" && yarn pack --out="${PACKS_DIRECTORY}/${tarballFilename}" && cd "${PACKS_DIRECTORY}" && npm publish "./${tarballFilename}" --registry ${url} --force --tag="xyz" --ignore-scripts`; exec(command, (e) => { if (e) { - rej(e); + reject(e); } else { i += 1; logger.log(`${i}/${packages.length} 🛬 successful publish of ${name}!`); - res(undefined); + resolve(undefined); } }); }) diff --git a/scripts/tasks/sandbox-parts.ts b/scripts/tasks/sandbox-parts.ts index 08fdced3bf5f..4309b57ab0b3 100644 --- a/scripts/tasks/sandbox-parts.ts +++ b/scripts/tasks/sandbox-parts.ts @@ -18,7 +18,7 @@ import JSON5 from 'json5'; import { createRequire } from 'module'; import { join, relative, resolve, sep } from 'path'; import slash from 'slash'; -import dedent from 'ts-dedent'; +import { dedent } from 'ts-dedent'; import { babelParse, types as t } from '../../code/core/src/babel'; import { detectLanguage } from '../../code/core/src/cli/detect'; @@ -99,7 +99,7 @@ export const install: Task['run'] = async ({ sandboxDir, key }, { link, dryRun, if (link) { await executeCLIStep(steps.link, { - argument: sandboxDir, + argument: `"${sandboxDir}"`, cwd: CODE_DIRECTORY, optionValues: { local: true, start: false }, dryRun, diff --git a/scripts/utils/cli-step.ts b/scripts/utils/cli-step.ts index 35405be4c338..836865954ba2 100644 --- a/scripts/utils/cli-step.ts +++ b/scripts/utils/cli-step.ts @@ -112,10 +112,10 @@ export async function executeCLIStep( const cliCommand = cliStep.command; const prefix = ['dev', 'build'].includes(cliCommand) - ? `node ${cliExecutable} ${cliCommand}` + ? `node "${cliExecutable}" ${cliCommand}` : cliCommand === 'init' - ? `node ${createStorybookExecutable} ${cliCommand}` - : `node ${toolboxExecutable} ${cliCommand}`; + ? `node "${createStorybookExecutable}" ${cliCommand}` + : `node "${toolboxExecutable}" ${cliCommand}`; const command = getCommand( cliStep.hasArgument ? `${prefix} ${options.argument}` : prefix, cliStep.options,