|
| 1 | +import {mkdir, readFile, writeFile, rm} from 'node:fs/promises'; |
| 2 | +import * as esbuild from 'esbuild'; |
| 3 | +import {program} from 'commander'; |
| 4 | +import {promisify} from 'node:util'; |
| 5 | +import {exec} from 'node:child_process'; |
| 6 | +import {fileURLToPath} from 'node:url'; |
| 7 | +import {join as joinPath} from 'node:path'; |
| 8 | + |
| 9 | +const execAsyncNative = promisify(exec); |
| 10 | + |
| 11 | +const execAsync = async (command, opts) => { |
| 12 | + const result = execAsyncNative(command, opts); |
| 13 | + const [output] = await Promise.all([ |
| 14 | + result, |
| 15 | + new Promise((resolve) => { |
| 16 | + result.child.on('close', () => { |
| 17 | + resolve(result); |
| 18 | + }); |
| 19 | + }) |
| 20 | + ]); |
| 21 | + return output; |
| 22 | +}; |
| 23 | + |
| 24 | +const rootDir = fileURLToPath(new URL('..', import.meta.url)); |
| 25 | + |
| 26 | +const packageKeysToKeep = [ |
| 27 | + 'version', |
| 28 | + 'description', |
| 29 | + 'repository', |
| 30 | + 'author', |
| 31 | + 'license', |
| 32 | + 'bugs', |
| 33 | + 'homepage', |
| 34 | + 'engines' |
| 35 | +]; |
| 36 | + |
| 37 | +async function createBundle(opts) { |
| 38 | + const packageTemplatePath = joinPath( |
| 39 | + rootDir, |
| 40 | + './scripts/package-template.json' |
| 41 | + ); |
| 42 | + const packageTemplate = JSON.parse( |
| 43 | + await readFile(packageTemplatePath, {encoding: 'utf8'}) |
| 44 | + ); |
| 45 | + const name = opts.name.replaceAll(/[^@\w]/g, ''); |
| 46 | + const bundleDirName = 'temp_bundle'; |
| 47 | + const cwd = joinPath(rootDir, bundleDirName); |
| 48 | + const actualPackagePath = joinPath( |
| 49 | + rootDir, |
| 50 | + bundleDirName, |
| 51 | + 'node_modules', |
| 52 | + name, |
| 53 | + 'package.json' |
| 54 | + ); |
| 55 | + const bundlePath = joinPath(cwd, 'main.js'); |
| 56 | + |
| 57 | + packageTemplate.name = `@cjs-bundle/${name}`; |
| 58 | + packageTemplate.type = 'module'; |
| 59 | + packageTemplate.devDependencies[name] = 'latest'; |
| 60 | + |
| 61 | + console.log('Removing any existing bundle directory'); |
| 62 | + await rm(`./${bundleDirName}`, {recursive: true, force: true}); |
| 63 | + |
| 64 | + console.log('Creating bundle directory'); |
| 65 | + await mkdir(`./${bundleDirName}`); |
| 66 | + |
| 67 | + console.log('Creating package.json'); |
| 68 | + await writeFile( |
| 69 | + `./${bundleDirName}/package.json`, |
| 70 | + JSON.stringify(packageTemplate, null, 2), |
| 71 | + {encoding: 'utf8'} |
| 72 | + ); |
| 73 | + |
| 74 | + console.log('Running `npm i`'); |
| 75 | + await execAsync('npm i', { |
| 76 | + cwd |
| 77 | + }); |
| 78 | + |
| 79 | + const actualPackage = JSON.parse( |
| 80 | + await readFile(actualPackagePath, {encoding: 'utf8'}) |
| 81 | + ); |
| 82 | + |
| 83 | + console.log('Copying package.json fields across'); |
| 84 | + for (const key of packageKeysToKeep) { |
| 85 | + packageTemplate[key] = actualPackage[key]; |
| 86 | + } |
| 87 | + |
| 88 | + delete packageTemplate.type; |
| 89 | + delete packageTemplate.devDependencies[name]; |
| 90 | + |
| 91 | + console.log('Writing new package.json'); |
| 92 | + await writeFile( |
| 93 | + `./${bundleDirName}/package.json`, |
| 94 | + JSON.stringify(packageTemplate, null, 2), |
| 95 | + {encoding: 'utf8'} |
| 96 | + ); |
| 97 | + |
| 98 | + console.log('Bundling'); |
| 99 | + await esbuild.build({ |
| 100 | + bundle: true, |
| 101 | + absWorkingDir: cwd, |
| 102 | + stdin: {contents: `export * from 'chai';`, resolveDir: cwd}, |
| 103 | + format: 'cjs', |
| 104 | + outfile: bundlePath |
| 105 | + }); |
| 106 | + |
| 107 | + console.log('Running `npm pkg fix`'); |
| 108 | + await execAsync('npm pkg fix', {cwd}); |
| 109 | + |
| 110 | + console.log('Publishing'); |
| 111 | + const publishCommand = opts.dryRun ? 'npm publish --dry-run' : 'npm publish'; |
| 112 | + const publishResult = await execAsync(publishCommand, {cwd}); |
| 113 | + |
| 114 | + console.log(publishResult.stderr); |
| 115 | + console.log(publishResult.stdout); |
| 116 | +} |
| 117 | + |
| 118 | +program.option('--name <name>').option('--dry-run'); |
| 119 | + |
| 120 | +program.parse(); |
| 121 | + |
| 122 | +const options = program.opts(); |
| 123 | + |
| 124 | +if (options.name) { |
| 125 | + const dryRun = options.dryRun ?? false; |
| 126 | + createBundle({name: options.name, dryRun}); |
| 127 | +} |
0 commit comments