feat: fes create 和优化fes命令体验

This commit is contained in:
万纯 2021-01-15 17:59:28 +08:00
parent 05bb37c484
commit 9dc93be193
14 changed files with 366 additions and 146 deletions

View File

@ -1,21 +0,0 @@
MIT License
Copyright (c) 2020-present webank
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -1,5 +0,0 @@
# fes 项目管理脚本
* 初始化 fes 项目
* 创建页面
* 创建模块

View File

@ -1,3 +0,0 @@
#!/usr/bin/env node
require('../lib/cli');

View File

@ -1,35 +0,0 @@
{
"name": "@webank/create-fes-app",
"version": "2.0.0-alpha.0",
"description": "@webank/create-fes-app",
"main": "lib/index.js",
"files": [
"lib",
"bin",
"templates"
],
"bin": {
"create-umi-app": "bin/create-fes-app.js"
},
"repository": {
"type": "git",
"url": "git+https://github.com/WeBankFinTech/fes.js.git",
"directory": "packages/create-fes-app"
},
"keywords": [
"fes"
],
"sideEffects": false,
"author": "qlin",
"license": "MIT",
"bugs": {
"url": "https://github.com/WeBankFinTech/fes.js/issues"
},
"homepage": "https://github.com/WeBankFinTech/fes.js#readme",
"publishConfig": {
"access": "public"
},
"dependencies": {
"vue-router": "^4.0.1"
}
}

View File

@ -1,12 +0,0 @@
/**
* TODO
* 需要支持的命令
* v
* h
* [项目名称] 可选择 h5 pc 模版
*
* feature pc
* 根据API动态生产列表页
* feature h5
*/

View File

@ -29,6 +29,7 @@
"@umijs/utils": "3.3.3",
"dotenv": "8.2.0",
"joi": "17.3.0",
"readline": "^1.3.0",
"set-value": "3.0.2",
"tapable": "2.0.0"
}

View File

@ -2,6 +2,7 @@ import {
createDebug,
chalk
} from '@umijs/utils';
import readline from 'readline';
export default class Logger {
LOG = chalk.black.bgBlue('LOG');
@ -72,4 +73,16 @@ export default class Logger {
this.profilers[id] = time;
return msg;
}
clearConsole(title) {
if (process.stdout.isTTY) {
const blank = '\n'.repeat(process.stdout.rows);
console.log(blank);
readline.cursorTo(process.stdout, 0, 0);
readline.clearScreenDown(process.stdout);
if (title) {
console.log(title);
}
}
}
}

View File

@ -33,8 +33,12 @@
"@vue/preload-webpack-plugin": "1.1.2",
"@webank/fes-compiler": "^2.0.0-alpha.0",
"cliui": "6.0.0",
"fs-extra": "^9.0.1",
"html-webpack-plugin": "^3.2.0",
"html-webpack-tags-plugin": "2.0.17",
"inquirer": "^7.3.3",
"tar": "^6.1.0",
"validate-npm-package-name": "^3.0.0",
"vue-loader": "^16.1.2",
"webpack-bundle-analyzer": "4.3.0"
}

View File

@ -50,6 +50,7 @@ export default function () {
require.resolve('./plugins/misc/route'),
// commands
require.resolve('./plugins/commands/create'),
require.resolve('./plugins/commands/build'),
require.resolve('./plugins/commands/dev')
]

View File

@ -0,0 +1,115 @@
import path from 'path';
import { chalk } from '@umijs/utils';
import validateProjectName from 'validate-npm-package-name';
import fs from 'fs-extra';
import { execSync } from 'child_process';
import { Logger } from '@webank/fes-compiler';
import inquirer from 'inquirer';
import tar from 'tar';
const logger = new Logger('fes:plugin-built-in');
export default function (api) {
api.registerCommand({
name: 'create',
description: 'create a new project',
async fn({ args }) {
if (args.proxy) {
process.env.HTTP_PROXY = args.proxy;
}
const cwd = args.cwd || process.cwd();
const projectName = args._[0];
const inCurrent = projectName === '.';
const name = inCurrent ? path.relative('../', cwd) : projectName;
const targetDir = path.resolve(cwd, projectName || '.');
const result = validateProjectName(name);
if (!result.validForNewPackages) {
console.error(chalk.red(`Invalid project name: "${name}"`));
result.errors && result.errors.forEach((err) => {
console.error(chalk.red.dim(`Error: ${err}`));
});
result.warnings && result.warnings.forEach((warn) => {
console.error(chalk.red.dim(`Warning: ${warn}`));
});
throw new Error('Process exited');
}
if (fs.existsSync(targetDir) && !args.merge) {
if (args.force) {
await fs.remove(targetDir);
} else {
logger.clearConsole();
if (inCurrent) {
const { ok } = await inquirer.prompt([
{
name: 'ok',
type: 'confirm',
message: 'Generate project in current directory?'
}
]);
if (!ok) {
return null;
}
} else {
const { action } = await inquirer.prompt([
{
name: 'action',
type: 'list',
message: `Target directory ${chalk.cyan(targetDir)} already exists. Pick an action:`,
choices: [
{ name: 'Overwrite', value: 'overwrite' },
{ name: 'Merge', value: 'merge' },
{ name: 'Cancel', value: false }
]
}
]);
if (!action) {
return null;
}
if (action === 'overwrite') {
console.log(`\nRemoving ${chalk.cyan(targetDir)}...`);
await fs.remove(targetDir);
}
}
}
}
const { template } = await inquirer.prompt([
{
name: 'template',
type: 'list',
message: 'Pick an template:',
choices: [
{ name: 'PC, suitable for management desk front-end applications', value: 'pc' },
{ name: 'H5, suitable for mobile applications', value: 'h5' },
{ name: 'Cancel', value: false }
]
}
]);
if (template) {
const map = {
pc: '@webank/fes-template',
h5: '@webank/fes-template-h5'
};
fs.mkdirSync(targetDir);
const stdout = execSync(`npm pack ${map[template]}`, { encoding: 'utf8', stdio: [null] });
const tempFilePath = path.resolve(cwd, stdout.replace('\n', ''));
fs.createReadStream(tempFilePath).pipe(
tar.x({
strip: 1,
C: targetDir
})
).on('finish', () => {
fs.removeSync(tempFilePath);
console.log();
console.log(chalk.green(`project ${projectName} created successfully, please execute the following command to use:`));
console.log(`$ cd ${projectName}`);
console.log('$ yarn');
console.log('$ yarn dev');
console.log();
});
}
}
});
}

View File

@ -42,6 +42,12 @@
"@webank/fes-compiler": "^2.0.0-alpha.0",
"@webank/fes-preset-built-in": "^2.0.0-alpha.0",
"@webank/fes-runtime": "^2.0.0-alpha.0",
"commander": "^6.2.1",
"envinfo": "^7.7.3",
"leven": "^3.1.0",
"resolve-cwd": "^3.0.0"
},
"engines": {
"node": "^10.12.0 || ^12.0.0 || >= 14.0.0"
}
}

View File

@ -1,37 +1,84 @@
import {
chalk,
yParser
} from '@umijs/utils';
import {
Service
} from './serviceWithBuiltIn';
import { chalk, yParser, semver } from '@umijs/utils';
import program from 'commander';
import leven from 'leven';
import { Service } from './serviceWithBuiltIn';
import fork from './utils/fork';
import getCwd from './utils/getCwd';
import getPkg from './utils/getPkg';
import fesPkg from '../package.json';
// process.argv: [node, fes.js, command, args]
const args = yParser(process.argv.slice(2), {
alias: {
version: ['v'],
help: ['h']
},
boolean: ['version']
});
const requiredVersion = fesPkg.engines.node;
// TODO version 命令
if (args.version && !args._[0]) {
args._[0] = 'version';
console.log(`fes@${require('../package.json').version}`);
} else if (!args._[0]) {
// TODO 帮助命令
args._[0] = 'help';
function checkNodeVersion(wanted, id) {
if (
!semver.satisfies(process.version, wanted, { includePrerelease: true })
) {
console.log(
chalk.red(
`You are using Node ${process.version}, but this version of ${id} requires Node ${wanted}.\nPlease upgrade your Node version.`
)
);
process.exit(1);
}
}
(async () => {
checkNodeVersion(requiredVersion, '@webank/fes');
function suggestCommands(unknownCommand) {
const availableCommands = program.commands.map(cmd => cmd._name);
let suggestion;
availableCommands.forEach((cmd) => {
const isBestMatch = leven(cmd, unknownCommand) < leven(suggestion || '', unknownCommand);
if (leven(cmd, unknownCommand) < 3 && isBestMatch) {
suggestion = cmd;
}
});
if (suggestion) {
console.log(` ${chalk.red(`Did you mean ${chalk.yellow(suggestion)}?`)}`);
}
}
// process.argv: [node, fes.js, command, args]
const args = yParser(process.argv.slice(2));
program
.version(`@webank/fes ${fesPkg.version}`, '-v, --vers', 'output the current version')
.usage('<command> [options]')
.description(fesPkg.description);
program
.command('create <app-name>')
.description('create a new project powered by fes.js')
.option('-f, --force', 'Overwrite target directory if it exists')
.option('--merge', 'Merge target directory if it exists')
.option('-x, --proxy <proxyUrl>', 'Use specified proxy when creating project')
.action(async () => {
if (args._.length > 2) {
console.log(chalk.yellow('\n Info: You provided more than one argument. The first one will be used as the app\'s name, the rest are ignored.'));
}
try {
await new Service({
cwd: getCwd(),
pkg: getPkg(process.cwd())
}).run({
name: 'create',
args
});
} catch (e) {
console.error(chalk.red(e.message));
console.error(e.stack);
process.exit(1);
}
});
program
.command('dev')
.description('run local http service for development')
.action(() => {
try {
switch (args._[0]) {
case 'dev':
// eslint-disable-next-line
const child = fork({
scriptPath: require.resolve('./forkedDev')
});
@ -45,25 +92,83 @@ if (args.version && !args._[0]) {
child.kill('SIGTERM');
process.exit(1);
});
break;
default:
// eslint-disable-next-line
const name = args._[0];
if (name === 'build') {
process.env.NODE_ENV = 'production';
}
await new Service({
cwd: getCwd(),
pkg: getPkg(process.cwd())
}).run({
name,
args
});
break;
}
} catch (e) {
console.error(chalk.red(e.message));
console.error(e.stack);
process.exit(1);
}
})();
});
program
.command('build')
.description('compile and package code')
.action(async () => {
try {
process.env.NODE_ENV = 'production';
await new Service({
cwd: getCwd(),
pkg: getPkg(process.cwd())
}).run({
name: 'build',
args
});
} catch (e) {
console.error(chalk.red(e.message));
console.error(e.stack);
process.exit(1);
}
});
program
.command('info')
.description('print debugging information about your environment')
.action(() => {
console.log(chalk.bold('\nEnvironment Info:'));
require('envinfo')
.run(
{
System: ['OS', 'CPU'],
Binaries: ['Node', 'Yarn', 'npm'],
Browsers: ['Chrome', 'Edge', 'Firefox', 'Safari'],
npmPackages: '/**/{typescript,*vue*,@webank/*/}',
npmGlobalPackages: ['@webank/fes']
},
{
showNotFound: true,
duplicates: true,
fullTree: true
}
)
.then(console.log);
});
// output help information on unknown commands
program
.arguments('[command]')
.action((cmd) => {
if (cmd) {
program.outputHelp();
console.log(` ${chalk.red(`Unknown command ${chalk.yellow(cmd)}.`)}`);
console.log();
suggestCommands(cmd);
process.exitCode = 1;
}
});
program.on('--help', () => {
console.log();
console.log(
` Run ${chalk.cyan(
'fes <command> --help'
)} for detailed usage of given command.`
);
console.log();
});
program.commands.forEach(c => c.on('--help', () => console.log()));
program.parse(process.argv);
if (!process.argv.slice(2).length) {
program.outputHelp();
}

View File

@ -3828,7 +3828,7 @@ ansi-escapes@^3.2.0:
resolved "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz#8780b98ff9dbf5638152d1f1fe5c1d7b4442976b"
integrity sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==
ansi-escapes@^4.3.0, ansi-escapes@^4.3.1:
ansi-escapes@^4.2.1, ansi-escapes@^4.3.0, ansi-escapes@^4.3.1:
version "4.3.1"
resolved "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.1.tgz#a5c47cc43181f1f38ffd7076837700d395522a61"
integrity sha512-JWF7ocqNrp8u9oqpgV+wH5ftbt+cfvv+PTjOvKLT3AdYly/LmORARfEVT1iyjwN+4MqE5UmVKoAdIBqeoCHgLA==
@ -5000,6 +5000,11 @@ cli-width@^2.0.0:
resolved "https://registry.npmjs.org/cli-width/-/cli-width-2.2.1.tgz#b0433d0b4e9c847ef18868a4ef16fd5fc8271c48"
integrity sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw==
cli-width@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-3.0.0.tgz#a2f48437a2caa9a22436e794bf071ec9e61cedf6"
integrity sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==
clipboardy@2.3.0:
version "2.3.0"
resolved "https://registry.npmjs.org/clipboardy/-/clipboardy-2.3.0.tgz#3c2903650c68e46a91b388985bc2774287dba290"
@ -5207,6 +5212,11 @@ commander@^6.2.0:
resolved "https://registry.npmjs.org/commander/-/commander-6.2.0.tgz#b990bfb8ac030aedc6d11bc04d1488ffef56db75"
integrity sha512-zP4jEKbe8SHzKJYQmq8Y9gYjtO/POJLgIdKgV7B9qNmABVFVc+ctqSX6iXh4mCpJfRBOabiZ2YKPg8ciDw6C+Q==
commander@^6.2.1:
version "6.2.1"
resolved "https://registry.yarnpkg.com/commander/-/commander-6.2.1.tgz#0792eb682dfbc325999bb2b84fddddba110ac73c"
integrity sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==
commander@~2.19.0:
version "2.19.0"
resolved "https://registry.npmjs.org/commander/-/commander-2.19.0.tgz#f6198aa84e5b83c46054b94ddedbfed5ee9ff12a"
@ -6452,7 +6462,7 @@ env-paths@^2.2.0:
resolved "https://registry.npmjs.org/env-paths/-/env-paths-2.2.0.tgz#cdca557dc009152917d6166e2febe1f039685e43"
integrity sha512-6u0VYSCo/OW6IoD5WCLLy9JUGARbamfSavcNXry/eu8aHVFei6CD3Sw+VGX5alea1i9pgPHW0mbu6Xj0uBh7gA==
envinfo@^7.3.1:
envinfo@^7.3.1, envinfo@^7.7.3:
version "7.7.3"
resolved "https://registry.npmjs.org/envinfo/-/envinfo-7.7.3.tgz#4b2d8622e3e7366afb8091b23ed95569ea0208cc"
integrity sha512-46+j5QxbPWza0PB1i15nZx0xQ4I/EfQxg9J8Had3b408SV63nEtor2e+oiY63amTo9KTuh2a3XLObNwduxYwwA==
@ -7124,7 +7134,7 @@ figures@^2.0.0:
dependencies:
escape-string-regexp "^1.0.5"
figures@^3.2.0:
figures@^3.0.0, figures@^3.2.0:
version "3.2.0"
resolved "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz#625c18bd293c604dc4a8ddb2febf0c88341746af"
integrity sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==
@ -7407,7 +7417,7 @@ fs-extra@^7.0.0:
jsonfile "^4.0.0"
universalify "^0.1.0"
fs-extra@^9.0.0:
fs-extra@^9.0.0, fs-extra@^9.0.1:
version "9.0.1"
resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-9.0.1.tgz#910da0062437ba4c39fedd863f1675ccfefcb9fc"
integrity sha512-h2iAoN838FqAFJY2/qVpzFXy+EBxfVE220PalAqQLDVsFOHLJrZvut5puAbCdNv6WJk+B8ihI+k0c7JK5erwqQ==
@ -8423,6 +8433,25 @@ inquirer@6.5.2, inquirer@^6.2.0:
strip-ansi "^5.1.0"
through "^2.3.6"
inquirer@^7.3.3:
version "7.3.3"
resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-7.3.3.tgz#04d176b2af04afc157a83fd7c100e98ee0aad003"
integrity sha512-JG3eIAj5V9CwcGvuOmoo6LB9kbAYT8HXffUl6memuszlwDC/qvFAJw49XJ5NROSFNPxp3iQg1GqkFhaY/CR0IA==
dependencies:
ansi-escapes "^4.2.1"
chalk "^4.1.0"
cli-cursor "^3.1.0"
cli-width "^3.0.0"
external-editor "^3.0.3"
figures "^3.0.0"
lodash "^4.17.19"
mute-stream "0.0.8"
run-async "^2.4.0"
rxjs "^6.6.0"
string-width "^4.1.0"
strip-ansi "^6.0.0"
through "^2.3.6"
intersperse@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/intersperse/-/intersperse-1.0.0.tgz#f2561fb1cfef9f5277cc3347a22886b4351a5181"
@ -9228,6 +9257,11 @@ levdist@^1.0.0:
resolved "https://registry.npmjs.org/levdist/-/levdist-1.0.0.tgz#91d7a3044964f2ccc421a0477cac827fe75c5718"
integrity sha1-kdejBElk8szEIaBHfKyCf+dcVxg=
leven@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2"
integrity sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==
levn@^0.4.1:
version "0.4.1"
resolved "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade"
@ -10128,7 +10162,7 @@ mute-stream@0.0.7:
resolved "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab"
integrity sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=
mute-stream@~0.0.4:
mute-stream@0.0.8, mute-stream@~0.0.4:
version "0.0.8"
resolved "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d"
integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==
@ -12324,6 +12358,11 @@ readdirp@~3.5.0:
dependencies:
picomatch "^2.2.1"
readline@^1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/readline/-/readline-1.3.0.tgz#c580d77ef2cfc8752b132498060dc9793a7ac01c"
integrity sha1-xYDXfvLPyHUrEySYBg3JeTp6wBw=
redent@^1.0.0:
version "1.0.0"
resolved "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz#cf916ab1fd5f1f16dfb20822dd6ec7f730c2afde"
@ -12836,7 +12875,7 @@ rollup@1.27.8:
"@types/node" "*"
acorn "^7.1.0"
run-async@^2.2.0:
run-async@^2.2.0, run-async@^2.4.0:
version "2.4.1"
resolved "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz#8440eccf99ea3e70bd409d49aab88e10c189a455"
integrity sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==
@ -12853,7 +12892,7 @@ run-queue@^1.0.0, run-queue@^1.0.3:
dependencies:
aproba "^1.1.1"
rxjs@^6.4.0, rxjs@^6.6.3:
rxjs@^6.4.0, rxjs@^6.6.0, rxjs@^6.6.3:
version "6.6.3"
resolved "https://registry.npmjs.org/rxjs/-/rxjs-6.6.3.tgz#8ca84635c4daa900c0d3967a6ee7ac60271ee552"
integrity sha512-trsQc+xYYXZ3urjOiJOuCOa5N3jAZ3eiSpQB5hIT8zGlL2QfnHLJ2r7GMkBGuIausdJN1OneaI6gQlsqNHHmZQ==
@ -13821,6 +13860,18 @@ tar@^6.0.2:
mkdirp "^1.0.3"
yallist "^4.0.0"
tar@^6.1.0:
version "6.1.0"
resolved "https://registry.yarnpkg.com/tar/-/tar-6.1.0.tgz#d1724e9bcc04b977b18d5c573b333a2207229a83"
integrity sha512-DUCttfhsnLCjwoDoFcI+B2iJgYa93vBnDUATYEeRx6sntCTdN01VnqsIuTlALXla/LWooNg0yEGeB+Y8WdFxGA==
dependencies:
chownr "^2.0.0"
fs-minipass "^2.0.0"
minipass "^3.0.0"
minizlib "^2.1.1"
mkdirp "^1.0.3"
yallist "^4.0.0"
temp-dir@2.0.0:
version "2.0.0"
resolved "https://registry.npmjs.org/temp-dir/-/temp-dir-2.0.0.tgz#bde92b05bdfeb1516e804c9c00ad45177f31321e"
@ -14523,7 +14574,7 @@ validate-npm-package-license@^3.0.1, validate-npm-package-license@^3.0.3:
validate-npm-package-name@^3.0.0:
version "3.0.0"
resolved "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-3.0.0.tgz#5fa912d81eb7d0c74afc140de7317f0ca7df437e"
resolved "https://registry.yarnpkg.com/validate-npm-package-name/-/validate-npm-package-name-3.0.0.tgz#5fa912d81eb7d0c74afc140de7317f0ca7df437e"
integrity sha1-X6kS2B630MdK/BQN5zF/DKffQ34=
dependencies:
builtins "^1.0.3"