diff --git a/scripts/build-package.js b/scripts/build-package.js index 70468be2e0ea..3e9843b83282 100644 --- a/scripts/build-package.js +++ b/scripts/build-package.js @@ -115,7 +115,7 @@ async function run() { selection?.filter(Boolean).forEach(async (v) => { const commmand = (await readJSON(resolve(v.location, 'package.json'))).scripts.prep; const cwd = resolve(__dirname, '..', 'code', v.location); - const sub = require('execa').command( + const sub = await import('execa').execaCommand( `${commmand}${watchMode ? ' --watch' : ''}${prodMode ? ' --optimized' : ''}`, { cwd, diff --git a/scripts/check-package.js b/scripts/check-package.js index dc675d9bff1a..1cee8b12cd9b 100644 --- a/scripts/check-package.js +++ b/scripts/check-package.js @@ -98,7 +98,7 @@ async function run() { selection?.filter(Boolean).forEach(async (v) => { const commmand = (await readJSON(resolve(v.location, 'package.json'))).scripts.check; const cwd = resolve(__dirname, '..', 'code', v.location); - const sub = require('execa').command(`${commmand}${watchMode ? ' --watch' : ''}`, { + const sub = await import('execa').execaCommand(`${commmand}${watchMode ? ' --watch' : ''}`, { cwd, buffer: false, shell: true, diff --git a/scripts/combine-compodoc.ts b/scripts/combine-compodoc.ts index 79a02dc0c34c..7dd04a7f509b 100755 --- a/scripts/combine-compodoc.ts +++ b/scripts/combine-compodoc.ts @@ -3,7 +3,7 @@ // then combine the results into one large documentation.json import { join, resolve } from 'path'; -import execa from 'execa'; +import { execaCommand } from './utils/exec'; import { realpath, readFile, writeFile, lstat } from 'fs-extra'; import glob from 'glob'; import { directory } from 'tempy'; @@ -37,7 +37,7 @@ async function run(cwd: string) { dirs.map(async (dir) => { const outputDir = directory(); const resolvedDir = await realpath(dir); - await execa.command( + await execaCommand( `yarn compodoc ${resolvedDir} -p ./tsconfig.json -e json -d ${outputDir}`, { cwd } ); diff --git a/scripts/next-repro-generators/generate-repros.ts b/scripts/next-repro-generators/generate-repros.ts index 380c7a0b2f1f..c4a48350a0a7 100755 --- a/scripts/next-repro-generators/generate-repros.ts +++ b/scripts/next-repro-generators/generate-repros.ts @@ -1,12 +1,12 @@ /* eslint-disable no-console */ import { join, relative } from 'path'; -import { command } from 'execa'; import type { Options as ExecaOptions } from 'execa'; import pLimit from 'p-limit'; import prettyTime from 'pretty-hrtime'; import { copy, emptyDir, ensureDir, move, remove, rename, writeFile } from 'fs-extra'; import { program } from 'commander'; import { directory } from 'tempy'; +import { execaCommand } from '../utils/exec'; import type { OptionValues } from '../utils/options'; import { createOptions } from '../utils/options'; @@ -85,7 +85,11 @@ export const runCommand = async (script: string, options: ExecaOptions) => { console.log(`Running command: ${script}`); } - return command(script, { stdout: shouldDebug ? 'inherit' : 'ignore', shell: true, ...options }); + return execaCommand(script, { + stdout: shouldDebug ? 'inherit' : 'ignore', + shell: true, + ...options, + }); }; const addDocumentation = async ( diff --git a/scripts/next-repro-generators/publish.ts b/scripts/next-repro-generators/publish.ts index 72aee2720b78..75bf2a606570 100755 --- a/scripts/next-repro-generators/publish.ts +++ b/scripts/next-repro-generators/publish.ts @@ -1,7 +1,7 @@ import program from 'commander'; import { join } from 'path'; import { existsSync } from 'fs'; -import { command } from 'execa'; +import { execaCommand } from '../utils/exec'; import * as tempy from 'tempy'; import { copy, emptyDir, readdir, remove, stat, writeFile } from 'fs-extra'; @@ -27,8 +27,8 @@ const publish = async (options: PublishOptions & { tmpFolder: string }) => { const templatesData = await getTemplatesData(); logger.log(`👯‍♂️ Cloning the repository ${remote} in branch ${gitBranch}`); - await command(`git clone ${remote} .`, { cwd: tmpFolder }); - await command(`git checkout ${gitBranch}`, { cwd: tmpFolder }); + await execaCommand(`git clone ${remote} .`, { cwd: tmpFolder }); + await execaCommand(`git checkout ${gitBranch}`, { cwd: tmpFolder }); // otherwise old files will stick around and result inconsistent states logger.log(`🗑 Delete existing template dirs from clone`); @@ -67,7 +67,7 @@ const publish = async (options: PublishOptions & { tmpFolder: string }) => { `); if (push) { - await command(`git push --set-upstream origin ${gitBranch}`, { + await execaCommand(`git push --set-upstream origin ${gitBranch}`, { cwd: tmpFolder, }); const remoteRepoUrl = `${remote.replace('.git', '')}/tree/${gitBranch}`; diff --git a/scripts/next-repro-generators/utils/git.ts b/scripts/next-repro-generators/utils/git.ts index 728034765652..bb828a7b6858 100644 --- a/scripts/next-repro-generators/utils/git.ts +++ b/scripts/next-repro-generators/utils/git.ts @@ -1,14 +1,14 @@ -import { command } from 'execa'; +import { execaCommand } from '../../utils/exec'; import { logger } from '../publish'; export async function commitAllToGit(cwd: string) { try { logger.log(`💪 Committing everything to the repository`); - await command('git add .', { cwd }); + await execaCommand('git add .', { cwd }); - const currentCommitSHA = await command('git rev-parse HEAD'); - await command( + const currentCommitSHA = await execaCommand('git rev-parse HEAD'); + await execaCommand( `git commit -m "Update examples - ${new Date().toDateString()} - ${currentCommitSHA.stdout .toString() .slice(0, 12)}"`, diff --git a/scripts/package.json b/scripts/package.json index fa686887b0b6..a741721e6a5a 100644 --- a/scripts/package.json +++ b/scripts/package.json @@ -117,7 +117,7 @@ "eslint-plugin-import": "^2.26.0", "eslint-plugin-react": "^7.31.10", "eslint-plugin-storybook": "^0.6.6", - "execa": "^5.0.0", + "execa": "^6.1.0", "express": "^4.17.1", "find-up": "^5.0.0", "fs-extra": "^9.0.1", @@ -138,7 +138,6 @@ "lodash": "^4.17.21", "memoizerific": "^1.11.3", "mocha-list-tests": "^1.0.5", - "node-abort-controller": "^3.0.1", "node-cleanup": "^2.1.2", "node-fetch": "^2.6.1", "node-gyp": "^8.4.0", diff --git a/scripts/task.ts b/scripts/task.ts index 69f9db0ec147..a01a07fba690 100644 --- a/scripts/task.ts +++ b/scripts/task.ts @@ -1,5 +1,4 @@ /* eslint-disable no-await-in-loop */ -import type { AbortController } from 'node-abort-controller'; import { getJunitXml } from 'junit-xml'; import { outputFile, readFile, pathExists } from 'fs-extra'; import { join, resolve } from 'path'; @@ -470,11 +469,10 @@ async function run() { await new Promise(() => {}); } } - controllers.forEach((controller) => { - controller.abort(); - }); } - + controllers.forEach((controller) => { + controller.abort(); + }); return 0; } diff --git a/scripts/tasks/dev.ts b/scripts/tasks/dev.ts index 64bf8dd59dac..67dac5d2a255 100644 --- a/scripts/tasks/dev.ts +++ b/scripts/tasks/dev.ts @@ -1,4 +1,3 @@ -import { AbortController } from 'node-abort-controller'; import detectFreePort from 'detect-port'; import type { Task } from '../task'; diff --git a/scripts/tasks/run-registry.ts b/scripts/tasks/run-registry.ts index b98325869a22..750765ecb6b4 100644 --- a/scripts/tasks/run-registry.ts +++ b/scripts/tasks/run-registry.ts @@ -1,4 +1,3 @@ -import { AbortController } from 'node-abort-controller'; import detectFreePort from 'detect-port'; import { resolve } from 'path'; @@ -13,7 +12,7 @@ export async function runRegistry({ dryRun, debug }: { dryRun?: boolean; debug?: exec( 'CI=true yarn local-registry --open', { cwd: codeDir }, - { dryRun, debug, signal: controller.signal as AbortSignal } + { dryRun, debug, signal: controller.signal } ).catch((err) => { // If aborted, we want to make sure the rejection is handled. if (!err.killed) throw err; diff --git a/scripts/tasks/serve.ts b/scripts/tasks/serve.ts index f7aa5db7bdc5..fd630f6e7301 100644 --- a/scripts/tasks/serve.ts +++ b/scripts/tasks/serve.ts @@ -1,4 +1,3 @@ -import { AbortController } from 'node-abort-controller'; import detectFreePort from 'detect-port'; import type { Task } from '../task'; diff --git a/scripts/utils/compile-babel.js b/scripts/utils/compile-babel.js index 269b38168708..d402e079159b 100644 --- a/scripts/utils/compile-babel.js +++ b/scripts/utils/compile-babel.js @@ -1,7 +1,6 @@ /* eslint-disable no-console */ const fs = require('fs-extra'); const path = require('path'); -const execa = require('execa'); const { join } = require('path'); function getCommand(watch, dir) { @@ -55,11 +54,13 @@ function handleExit(code, stderr, errorCallback) { } async function run({ watch, dir, silent, errorCallback }) { + const execa = await import('execa'); + return new Promise((resolve, reject) => { const command = getCommand(watch, dir); if (command !== '') { - const child = execa.command(command, { + const child = execa.execaCommand(command, { cwd: join(__dirname, '..'), buffer: false, env: { BABEL_MODE: path.basename(dir) }, diff --git a/scripts/utils/compile-tsc.js b/scripts/utils/compile-tsc.js index bdc824f143b5..a0bdf95e17f8 100644 --- a/scripts/utils/compile-tsc.js +++ b/scripts/utils/compile-tsc.js @@ -1,7 +1,6 @@ /* eslint-disable no-console */ const fs = require('fs-extra'); const path = require('path'); -const execa = require('execa'); function getCommand(watch) { const args = [ @@ -41,11 +40,13 @@ function handleExit(code, stderr, errorCallback) { } async function run({ optimized, watch, silent, errorCallback }) { + const execa = await import('execa'); + return new Promise((resolve, reject) => { const [command, tscOnly] = getCommand(watch); if (tscOnly || optimized) { - const child = execa.command(command, { + const child = execa.execaCommand(command, { buffer: false, }); let stderr = ''; diff --git a/scripts/utils/exec.ts b/scripts/utils/exec.ts index 86f9b59e047f..cf2f5e4bd624 100644 --- a/scripts/utils/exec.ts +++ b/scripts/utils/exec.ts @@ -1,6 +1,5 @@ /* eslint-disable no-await-in-loop, no-restricted-syntax */ import type { ExecaChildProcess, Options } from 'execa'; -import execa from 'execa'; import chalk from 'chalk'; const logger = console; @@ -13,11 +12,29 @@ type StepOptions = { signal?: AbortSignal; }; +// Note this is to fool `ts-node` into not turning the `import()` into a `require()`. +// See: https://github.com/TypeStrong/ts-node/discussions/1290 +// eslint-disable-next-line @typescript-eslint/no-implied-eval +const dynamicImport = new Function('specifier', 'return import(specifier)'); +export const getExeca = async () => (await dynamicImport('execa')) as typeof import('execa'); + +// Reimplementation of `execaCommand` to use `getExeca` +export const execaCommand = async ( + command: string, + options: Options = {} +): Promise> => { + const execa = await getExeca(); + // We await here because execaCommand returns a promise, but that's not what the user expects + // eslint-disable-next-line @typescript-eslint/return-await + return await execa.execaCommand(command, options); +}; + export const exec = async ( command: string | string[], options: Options = {}, { startMessage, errorMessage, dryRun, debug, signal }: StepOptions = {} ): Promise => { + const execa = await getExeca(); logger.info(); if (startMessage) logger.info(startMessage); @@ -30,23 +47,19 @@ export const exec = async ( shell: true, stdout: debug ? 'inherit' : 'pipe', stderr: debug ? 'inherit' : 'pipe', + signal, }; - let currentChild: ExecaChildProcess; - - // Newer versions of execa have explicit support for abort signals, but this works - if (signal) { - signal.addEventListener('abort', () => currentChild.kill()); - } + let currentChild: ExecaChildProcess; try { if (typeof command === 'string') { logger.debug(`> ${command}`); - currentChild = execa.command(command, { ...defaultOptions, ...options }); + currentChild = execa.execaCommand(command, { ...defaultOptions, ...options }); await currentChild; } else { for (const subcommand of command) { logger.debug(`> ${subcommand}`); - currentChild = execa.command(subcommand, { ...defaultOptions, ...options }); + currentChild = execa.execaCommand(subcommand, { ...defaultOptions, ...options }); await currentChild; } } diff --git a/scripts/utils/workspace.ts b/scripts/utils/workspace.ts index 982cdbc2fc5c..40fa0d159f19 100644 --- a/scripts/utils/workspace.ts +++ b/scripts/utils/workspace.ts @@ -1,4 +1,4 @@ -import command from 'execa'; +import { execaCommand } from './exec'; import memoize from 'memoizerific'; import { resolve } from 'path'; @@ -7,7 +7,7 @@ export type Workspace = { name: string; location: string }; const codeDir = resolve(__dirname, '../../code'); async function getWorkspaces() { - const { stdout } = await command('yarn workspaces list --json', { + const { stdout } = await execaCommand('yarn workspaces list --json', { cwd: codeDir, shell: true, }); diff --git a/scripts/yarn.lock b/scripts/yarn.lock index 801c1c81126d..8ec4709bac20 100644 --- a/scripts/yarn.lock +++ b/scripts/yarn.lock @@ -3695,7 +3695,7 @@ __metadata: eslint-plugin-import: ^2.26.0 eslint-plugin-react: ^7.31.10 eslint-plugin-storybook: ^0.6.6 - execa: ^5.0.0 + execa: ^6.1.0 express: ^4.17.1 find-up: ^5.0.0 fs-extra: ^9.0.1 @@ -3716,7 +3716,6 @@ __metadata: lodash: ^4.17.21 memoizerific: ^1.11.3 mocha-list-tests: ^1.0.5 - node-abort-controller: ^3.0.1 node-cleanup: ^2.1.2 node-fetch: ^2.6.1 node-gyp: ^8.4.0 @@ -8847,6 +8846,23 @@ __metadata: languageName: node linkType: hard +"execa@npm:^6.1.0": + version: 6.1.0 + resolution: "execa@npm:6.1.0" + dependencies: + cross-spawn: ^7.0.3 + get-stream: ^6.0.1 + human-signals: ^3.0.1 + is-stream: ^3.0.0 + merge-stream: ^2.0.0 + npm-run-path: ^5.1.0 + onetime: ^6.0.0 + signal-exit: ^3.0.7 + strip-final-newline: ^3.0.0 + checksum: 004ee32092af745766a1b0352fdba8701a4001bc3fe08e63101c04276d4c860bbe11bb8ab85f37acdff13d3da83d60e044041dcf24bd7e25e645a543828d9c41 + languageName: node + linkType: hard + "exit@npm:^0.1.2": version: 0.1.2 resolution: "exit@npm:0.1.2" @@ -9661,7 +9677,7 @@ __metadata: languageName: node linkType: hard -"get-stream@npm:^6.0.0": +"get-stream@npm:^6.0.0, get-stream@npm:^6.0.1": version: 6.0.1 resolution: "get-stream@npm:6.0.1" checksum: 49825d57d3fd6964228e6200a58169464b8e8970489b3acdc24906c782fb7f01f9f56f8e6653c4a50713771d6658f7cfe051e5eb8c12e334138c9c918b296341 @@ -10391,6 +10407,13 @@ __metadata: languageName: node linkType: hard +"human-signals@npm:^3.0.1": + version: 3.0.1 + resolution: "human-signals@npm:3.0.1" + checksum: 0bb27e72aea1666322f69ab9816e05df952ef2160346f2293f98f45d472edb1b62d0f1a596697b50d48d8f8222e6db3b9f9dc0b6bf6113866121001f0a8e48e9 + languageName: node + linkType: hard + "humanize-ms@npm:^1.2.1": version: 1.2.1 resolution: "humanize-ms@npm:1.2.1" @@ -10976,6 +10999,13 @@ __metadata: languageName: node linkType: hard +"is-stream@npm:^3.0.0": + version: 3.0.0 + resolution: "is-stream@npm:3.0.0" + checksum: eb2f7127af02ee9aa2a0237b730e47ac2de0d4e76a4a905a50a11557f2339df5765eaea4ceb8029f1efa978586abe776908720bfcb1900c20c6ec5145f6f29d8 + languageName: node + linkType: hard + "is-string@npm:^1.0.5, is-string@npm:^1.0.7": version: 1.0.7 resolution: "is-string@npm:1.0.7" @@ -13436,6 +13466,13 @@ __metadata: languageName: node linkType: hard +"mimic-fn@npm:^4.0.0": + version: 4.0.0 + resolution: "mimic-fn@npm:4.0.0" + checksum: de9cc32be9996fd941e512248338e43407f63f6d497abe8441fa33447d922e927de54d4cc3c1a3c6d652857acd770389d5a3823f311a744132760ce2be15ccbf + languageName: node + linkType: hard + "min-document@npm:^2.19.0": version: 2.19.0 resolution: "min-document@npm:2.19.0" @@ -13799,13 +13836,6 @@ __metadata: languageName: node linkType: hard -"node-abort-controller@npm:^3.0.1": - version: 3.0.1 - resolution: "node-abort-controller@npm:3.0.1" - checksum: 37f895533f7a18a2d83fa4853da1cc00fcae1e0a71553f9ffc94d3153f5fc886d6d4ef3a33bf60c38be161fab78c5b2275cbbf2359351fb12f5edad68d88d8ca - languageName: node - linkType: hard - "node-addon-api@npm:^3.2.1": version: 3.2.1 resolution: "node-addon-api@npm:3.2.1" @@ -14005,6 +14035,15 @@ __metadata: languageName: node linkType: hard +"npm-run-path@npm:^5.1.0": + version: 5.1.0 + resolution: "npm-run-path@npm:5.1.0" + dependencies: + path-key: ^4.0.0 + checksum: ff6d77514489f47fa1c3b1311d09cd4b6d09a874cc1866260f9dea12cbaabda0436ed7f8c2ee44d147bf99a3af29307c6f63b0f83d242b0b6b0ab25dff2629e3 + languageName: node + linkType: hard + "npmlog@npm:^5.0.1": version: 5.0.1 resolution: "npmlog@npm:5.0.1" @@ -14236,6 +14275,15 @@ __metadata: languageName: node linkType: hard +"onetime@npm:^6.0.0": + version: 6.0.0 + resolution: "onetime@npm:6.0.0" + dependencies: + mimic-fn: ^4.0.0 + checksum: 4eef7c6abfef697dd4479345a4100c382d73c149d2d56170a54a07418c50816937ad09500e1ed1e79d235989d073a9bade8557122aee24f0576ecde0f392bb6c + languageName: node + linkType: hard + "open@npm:8.4.0, open@npm:^8.4.0": version: 8.4.0 resolution: "open@npm:8.4.0" @@ -14586,6 +14634,13 @@ __metadata: languageName: node linkType: hard +"path-key@npm:^4.0.0": + version: 4.0.0 + resolution: "path-key@npm:4.0.0" + checksum: 794efeef32863a65ac312f3c0b0a99f921f3e827ff63afa5cb09a377e202c262b671f7b3832a4e64731003fa94af0263713962d317b9887bd1e0c48a342efba3 + languageName: node + linkType: hard + "path-parse@npm:^1.0.7": version: 1.0.7 resolution: "path-parse@npm:1.0.7" @@ -17015,6 +17070,13 @@ __metadata: languageName: node linkType: hard +"strip-final-newline@npm:^3.0.0": + version: 3.0.0 + resolution: "strip-final-newline@npm:3.0.0" + checksum: a771a17901427bac6293fd416db7577e2bc1c34a19d38351e9d5478c3c415f523f391003b42ed475f27e33a78233035df183525395f731d3bfb8cdcbd4da08ce + languageName: node + linkType: hard + "strip-indent@npm:^3.0.0": version: 3.0.0 resolution: "strip-indent@npm:3.0.0"