Repository: snowpackjs/pack Branch: master Commit: db05a6c653f4 Files: 135 Total size: 536.7 KB Directory structure: gitextract_c_u851k3/ ├── .babelrc ├── .github/ │ └── ISSUE_TEMPLATE.md ├── .gitignore ├── .prettierrc ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── checkpoint/ │ ├── LICENSE │ ├── README.md │ ├── dist-node/ │ │ ├── index.bin.js │ │ └── index.js │ ├── dist-src/ │ │ ├── commands/ │ │ │ └── build.js │ │ ├── config.js │ │ ├── constants.js │ │ ├── errors.js │ │ ├── index.js │ │ ├── reporters/ │ │ │ ├── base-reporter.js │ │ │ ├── console/ │ │ │ │ ├── console-reporter.js │ │ │ │ ├── helpers/ │ │ │ │ │ └── tree-helper.js │ │ │ │ ├── progress-bar.js │ │ │ │ ├── spinner-progress.js │ │ │ │ └── util.js │ │ │ ├── format.js │ │ │ ├── index.js │ │ │ ├── json-reporter.js │ │ │ ├── lang/ │ │ │ │ ├── en.js │ │ │ │ └── index.js │ │ │ ├── noop-reporter.js │ │ │ └── types.js │ │ ├── types.js │ │ └── util/ │ │ ├── babel-plugin-import-rewrite.js │ │ ├── babel-validate-specifier.js │ │ ├── blocking-queue.js │ │ ├── child.js │ │ ├── conversion.js │ │ ├── execute-lifecycle-script.js │ │ ├── fix-cmd-win-slashes.js │ │ ├── fs-normalized.js │ │ ├── fs.js │ │ ├── map.js │ │ ├── misc.js │ │ ├── normalize-manifest/ │ │ │ ├── fix.js │ │ │ ├── for-publish.js │ │ │ ├── index.js │ │ │ ├── infer-license.js │ │ │ ├── licenses.js │ │ │ ├── typos.js │ │ │ ├── util.js │ │ │ └── validate.js │ │ ├── promise.js │ │ └── signal-handler.js │ ├── dist-types/ │ │ ├── commands/ │ │ │ └── build.d.ts │ │ ├── config.d.ts │ │ ├── constants.d.ts │ │ ├── errors.d.ts │ │ ├── index.d.ts │ │ ├── reporters/ │ │ │ ├── base-reporter.d.ts │ │ │ ├── console/ │ │ │ │ ├── console-reporter.d.ts │ │ │ │ ├── helpers/ │ │ │ │ │ └── tree-helper.d.ts │ │ │ │ ├── progress-bar.d.ts │ │ │ │ ├── spinner-progress.d.ts │ │ │ │ └── util.d.ts │ │ │ ├── format.d.ts │ │ │ ├── index.d.ts │ │ │ ├── json-reporter.d.ts │ │ │ ├── lang/ │ │ │ │ ├── en.d.ts │ │ │ │ └── index.d.ts │ │ │ ├── noop-reporter.d.ts │ │ │ └── types.d.ts │ │ ├── types.d.ts │ │ └── util/ │ │ ├── babel-plugin-import-rewrite.d.ts │ │ ├── babel-validate-specifier.d.ts │ │ ├── blocking-queue.d.ts │ │ ├── child.d.ts │ │ ├── conversion.d.ts │ │ ├── execute-lifecycle-script.d.ts │ │ ├── fix-cmd-win-slashes.d.ts │ │ ├── fs-normalized.d.ts │ │ ├── fs.d.ts │ │ ├── map.d.ts │ │ ├── misc.d.ts │ │ ├── normalize-manifest/ │ │ │ ├── fix.d.ts │ │ │ ├── for-publish.d.ts │ │ │ ├── index.d.ts │ │ │ ├── infer-license.d.ts │ │ │ ├── licenses.d.ts │ │ │ ├── typos.d.ts │ │ │ ├── util.d.ts │ │ │ └── validate.d.ts │ │ ├── promise.d.ts │ │ └── signal-handler.d.ts │ └── package.json ├── package.json ├── src/ │ ├── commands/ │ │ └── build.ts │ ├── config.ts │ ├── constants.ts │ ├── errors.ts │ ├── index.ts │ ├── reporters/ │ │ ├── base-reporter.ts │ │ ├── console/ │ │ │ ├── console-reporter.ts │ │ │ ├── helpers/ │ │ │ │ └── tree-helper.ts │ │ │ ├── progress-bar.ts │ │ │ ├── spinner-progress.ts │ │ │ └── util.ts │ │ ├── format.ts │ │ ├── index.ts │ │ ├── json-reporter.ts │ │ ├── lang/ │ │ │ ├── en.ts │ │ │ └── index.ts │ │ ├── noop-reporter.ts │ │ └── types.ts │ ├── types.ts │ └── util/ │ ├── babel-plugin-import-rewrite.ts │ ├── babel-validate-specifier.ts │ ├── blocking-queue.ts │ ├── child.ts │ ├── conversion.ts │ ├── execute-lifecycle-script.ts │ ├── fix-cmd-win-slashes.ts │ ├── fs-normalized.ts │ ├── fs.ts │ ├── map.ts │ ├── misc.ts │ ├── normalize-manifest/ │ │ ├── fix.ts │ │ ├── for-publish.ts │ │ ├── index.ts │ │ ├── infer-license.ts │ │ ├── licenses.ts │ │ ├── typos.ts │ │ ├── util.ts │ │ └── validate.ts │ ├── promise.ts │ └── signal-handler.ts └── tsconfig.json ================================================ FILE CONTENTS ================================================ ================================================ FILE: .babelrc ================================================ { "presets": [], "plugins": [ "@babel/plugin-proposal-class-properties" ] } ================================================ FILE: .github/ISSUE_TEMPLATE.md ================================================ To create a new issue or search existing discussions, start here: 👉 **https://www.pika.dev/packages/@pika/pack/discuss** 👈 All new issues created directly through GitHub will be closed. Learn more: https://www.pika.dev/discussions ================================================ FILE: .gitignore ================================================ lib-node/ local/ .DS_Store /pkg /lib /lib-legacy /node_modules *.log /.nyc_output /coverage /dist-* /dist /dist-debug /artifacts /updates /resources/winsetup/generated.wxs /resources/winsetup/obj /resources/winsetup/bin /resources/win-chocolatey/tools/chocolateyinstall.ps1 .vs *.msi *.nupkg test/fixtures/**/.fbkpm /tmp/ /__tests__/fixtures/**/_* /__tests__/fixtures/request-cache/GET/localhost/.bin .idea .pika-meta .pnp.js .pnp /packages/lockfile/index.js .vscode/ ================================================ FILE: .prettierrc ================================================ { "singleQuote": true, "trailingComma": "all", "bracketSpacing": false, "printWidth": 120 } ================================================ FILE: CODE_OF_CONDUCT.md ================================================ # Contributor Covenant Code of Conduct ## Our Pledge In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation. ## Our Standards Examples of behavior that contributes to creating a positive environment include: * Using welcoming and inclusive language * Being respectful of differing viewpoints and experiences * Gracefully accepting constructive criticism * Focusing on what is best for the community * Showing empathy towards other community members Examples of unacceptable behavior by participants include: * The use of sexualized language or imagery and unwelcome sexual attention or advances * Trolling, insulting/derogatory comments, and personal or political attacks * Public or private harassment * Publishing others' private information, such as a physical or electronic address, without explicit permission * Other conduct which could reasonably be considered inappropriate in a professional setting ## Our Responsibilities Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. ## Scope This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. ## Enforcement Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at fkschott@gmail.com. All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. ## Attribution This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html [homepage]: https://www.contributor-covenant.org For answers to common questions about this code of conduct, see https://www.contributor-covenant.org/faq ================================================ FILE: CONTRIBUTING.md ================================================ # Contributing to @pika/pack All contributions are welcome! ## Building the Project It is very cool being able to use @pika/pack to build @pika/pack. Unfortunately, npm doesn't make it easy to install a package as a dependency of itself. So to get around this, we keep a `checkpoint/` folder in the project which is a checkpoint build of a working @pika/pack. We then use this to build our package in development. ``` git clone https://github.com/pikapkg/pack.git npm install npm run build ``` ## Testing the Project Writing unit tests for the project is still TODO. I know, I know, I'm more embarassed than anyone. The good news is that we have several example projects, including @pika/pack itself. First I'd like to get Travis running builds of all of our example projects with the PR'd version of @pika/pack. Until then, our only automated test is to use @pika/pack to build @pika/pack. ``` npm t ``` ================================================ FILE: LICENSE ================================================ """ The MIT License Copyright (c) 2019 Fred K. Schott 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. "" This license applies to parts of @pika/pack originating from the https://github.com/sindresorhus/np repository: """ MIT License Copyright (c) Sindre Sorhus (sindresorhus.com) 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. """ This license applies to parts of @pika/pack originating from the https://github.com/yarnpkg/yarn repository: """ BSD 2-Clause License For Yarn software Copyright (c) 2016-present, Yarn Contributors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. """ ================================================ FILE: README.md ================================================

Logo

@pika/pack • npm package building, reimagined.

Demo

## @pika/pack helps you build amazing packages without the hassle: - **Simple**  ⚡️  Use pre-configured plugins to build your package for you. - **Flexible**  🏋️‍♀️  Choose plugins and optimizations to match your needs. - **Holistic**  ⚛️  Let us build the entire package... *including package.json.* ## Quickstart ```bash npx @pika/pack # Run once. npm install --dev @pika/pack # Or, run multiple times using "pika pack" in any package.json scripts ``` 😎🆒! So now what? If you run `pika build` with an empty pipeline, you'll get an empty package build. **@pika/pack** lets you connect pre-configured plugins to build and optimize your package for you. Plugins wrap already-popular tools like Babel and Rollup with npm-optimized config options, removing the need to fiddle with much (if any) configuration yourself. You even get a generated package.json manifest configured for you ***automatically***. ### 1. Create a project pipeline out of simple, pluggable builders. ```js // Before: Your top-level package.json manifest: { "name": "simple-package", "version": "1.0.0", "@pika/pack": { "pipeline": [ ["@pika/plugin-standard-pkg", {"exclude": ["__tests__/**/*"]}], ["@pika/plugin-build-node"], ["@pika/plugin-build-web"], ["@pika/plugin-build-types"] ] } } ``` Builders are simple, single-purpose build plugins defined in your `package.json`. For example, `@pika/plugin-build-node` & `@pika/plugin-build-web` build your package for those different environments. Other, more interesting builders can bundle your web build for [unpkg](https://unpkg.com), generate TypeScript definitions from your JavaScript, addon a standard CLI wrapper for Node.js builds, and even compile non-JS languages to WASM (with JS bindings added). ### 2. Builders handle everything, including package configuration. ```js // After: your built "pkg/" package.json manifest: { "name": "simple-package", "version": "1.0.0", // Multiple distributions, built & configured automatically: "esnext": "dist-src/index.js", "main": "dist-node/index.js", "module": "dist-web/index.js", "types": "dist-types/index.d.ts", // With sensible package defaults: "sideEffects": false, "files": ["dist-*/", "assets/", "bin/"] } ``` This is all possible because **@pika/pack** builds your entire package: code, assets, and even package.json manifest. By building the entire package, you end up with a fully-built `pkg/` directory, ready to publish. Entry points like "main", "module", "umd:main", "types", "unpkg", "files", and even advanced options like "sideEffects" are all handled by your build pipeline. ## Build Plugins **[Check out the full list](https://github.com/pikapkg/builders)** of official & community-written @pika/pack plugins! ## Lerna Support Curious about integrating @pika/pack with Lerna? Our official collection of plugins is a Lerna repo that uses @pika/pack to build each package! [Check it out](https://github.com/pikapkg/builders) to see how easy it is to use the two tools together. ================================================ FILE: checkpoint/LICENSE ================================================ """ The MIT License Copyright (c) 2019 Fred K. Schott 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. "" This license applies to parts of @pika/pack originating from the https://github.com/sindresorhus/np repository: """ MIT License Copyright (c) Sindre Sorhus (sindresorhus.com) 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. """ This license applies to parts of @pika/pack originating from the https://github.com/yarnpkg/yarn repository: """ BSD 2-Clause License For Yarn software Copyright (c) 2016-present, Yarn Contributors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. """ ================================================ FILE: checkpoint/README.md ================================================

Logo

@pika/pack • npm package building, reimagined.

Demo

## @pika/pack helps you build amazing packages without the hassle: - **Simple**  ⚡️  Use pre-configured plugins to build your package for you. - **Flexible**  🏋️‍♀️  Choose plugins and optimizations to match your needs. - **Holistic**  ⚛️  Let us build the entire package... *including package.json.* ## Quickstart Getting started is easy: ```js // 1. Install it! $ npm install -g @pika/pack // 2. Add this to your package.json manifest: "@pika/pack": { "pipeline": [] } // 3. Run it! $ pack build ``` ### 😎 🆒 So now what? If you run `pack build` with an empty pipeline, you'll get an empty package build. **@pika/pack** lets you connect pre-configured plugins to build and optimize your package for you. Plugins wrap already-popular tools like Babel and Rollup with npm-optimized config options, removing the need to fiddle with much (if any) configuration yourself. You even get a generated package.json manifest configured for you ***automatically***. ### 1. Create a project pipeline out of simple, pluggable builders. ```js // Before: Your top-level package.json manifest: { "name": "simple-package", "version": "1.0.0", "@pika/pack": { "pipeline": [ ["@pika/plugin-standard-pkg", {"exclude": ["__tests__/**/*"]}], ["@pika/plugin-build-node"], ["@pika/plugin-build-web"], ["@pika/plugin-build-types"] ] } } ``` Builders are simple, single-purpose build plugins defined in your `package.json`. For example, `@pika/plugin-build-node` & `@pika/plugin-build-web` build your package for those different environments. Other, more interesting builders can bundle your web build for [unpkg](https://unpkg.com), generate TypeScript definitions from your JavaScript, addon a standard CLI wrapper for Node.js builds, and even compile non-JS languages to WASM (with JS bindings added). ### 2. Builders handle everything, including package configuration. ```js // After: your built "pkg/" package.json manifest: { "name": "simple-package", "version": "1.0.0", // Multiple distributions, built & configured automatically: "esnext": "dist-src/index.js", "main": "dist-node/index.js", "module": "dist-web/index.js", "types": "dist-types/index.d.ts", // With sensible package defaults: "sideEffects": false, "files": ["dist-*/", "assets/", "bin/"] } ``` This is all possible because **@pika/pack** builds your entire package: code, assets, and even package.json manifest. By building the entire package, you end up with a fully-built `pkg/` directory, ready to publish. Entry points like "main", "module", "umd:main", "types", "unpkg", "files", and even advanced options like "sideEffects" are all handled by your build pipeline. ## Build Plugins **[Check out the full list](https://github.com/pikapkg/builders)** of official & community-written @pika/pack plugins! ## Lerna Support Curious about integrating @pika/pack with Lerna? Our official collection of plugins is a Lerna repo that uses @pika/pack to build each package! [Check it out](https://github.com/pikapkg/builders) to see how easy it is to use the two tools together. ================================================ FILE: checkpoint/dist-node/index.bin.js ================================================ #!/usr/bin/env node 'use strict'; const ver = process.versions.node; const majorVer = parseInt(ver.split('.')[0], 10); if (majorVer < 8) { console.error('Node version ' + ver + ' is not supported, please use Node.js 8.0 or higher.'); process.exit(1); } let hasBundled = true try { require.resolve('./index.bundled.js'); } catch(err) { // We don't have/need this on legacy builds and dev builds // If an error happens here, throw it, that means no Node.js distribution exists at all. hasBundled = false; } const cli = !hasBundled ? require('../') : require('./index.bundled.js'); if (cli.autoRun) { return; } const run = cli.run || cli.cli || cli.default; run(process.argv).catch(function (error) { console.error(error.stack || error.message || error); process.exitCode = 1; }); ================================================ FILE: checkpoint/dist-node/index.js ================================================ 'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; } var path = require('path'); var chalk = _interopDefault(require('chalk')); var fs = require('fs'); var invariant = _interopDefault(require('invariant')); var loudRejection = _interopDefault(require('loud-rejection')); var readline = require('readline'); var stripAnsi = _interopDefault(require('strip-ansi')); var util = require('util'); require('camelcase'); var isCI = require('is-ci'); var os = require('os'); var events = require('events'); var tty = require('tty'); var _rimraf = _interopDefault(require('rimraf')); var _mkdirp = _interopDefault(require('mkdirp')); var _glob = _interopDefault(require('glob')); var stripBOM = _interopDefault(require('strip-bom')); var types = require('@pika/types'); var isBuiltinModule = _interopDefault(require('is-builtin-module')); var validateLicense = _interopDefault(require('validate-npm-package-license')); var semver = _interopDefault(require('semver')); var nodeUrl = require('url'); var child_process = require('child_process'); var importFrom = _interopDefault(require('import-from')); var uri2path = _interopDefault(require('file-uri-to-path')); var yargs = _interopDefault(require('yargs-parser')); /* @flow */ function removeSuffix(pattern, suffix) { if (pattern.endsWith(suffix)) { return pattern.slice(0, -suffix.length); } return pattern; } function formatFunction(...strs) { return strs.join(' '); } const defaultFormatter = { bold: formatFunction, dim: formatFunction, italic: formatFunction, underline: formatFunction, inverse: formatFunction, strikethrough: formatFunction, black: formatFunction, red: formatFunction, green: formatFunction, yellow: formatFunction, blue: formatFunction, magenta: formatFunction, cyan: formatFunction, white: formatFunction, gray: formatFunction, grey: formatFunction, stripColor: formatFunction }; const messages = { upToDate: 'Already up-to-date.', folderInSync: 'Folder in sync.', nothingToInstall: 'Nothing to install.', resolvingPackages: 'Resolving packages', checkingManifest: 'Validating package.json', fetchingPackages: 'Fetching packages', linkingDependencies: 'Linking dependencies', rebuildingPackages: 'Rebuilding all packages', buildingFreshPackages: 'Building fresh packages', cleaningModules: 'Cleaning modules', bumpingVersion: 'Bumping version', savingHar: 'Saving HAR file: $0', answer: 'Answer?', usage: 'Usage', installCommandRenamed: '`install` has been replaced with `add` to add new dependencies. Run $0 instead.', globalFlagRemoved: '`--global` has been deprecated. Please run $0 instead.', waitingInstance: 'Waiting for the other pika instance to finish (pid $0, inside $1)', waitingNamedInstance: 'Waiting for the other pika instance to finish ($0)', offlineRetrying: 'There appears to be trouble with your network connection. Retrying...', internalServerErrorRetrying: 'There appears to be trouble with the npm registry (returned $1). Retrying...', clearedCache: 'Cleared cache.', couldntClearPackageFromCache: "Couldn't clear package $0 from cache", clearedPackageFromCache: 'Cleared package $0 from cache', packWroteTarball: 'Wrote tarball to $0.', helpExamples: ' Examples:\n$0\n', helpCommands: ' Commands:\n$0\n', helpCommandsMore: ' Run `$0` for more information on specific commands.', helpLearnMore: ' Visit $0 to learn more about Pika.\n', manifestPotentialTypo: 'Potential typo $0, did you mean $1?', manifestBuiltinModule: '$0 is also the name of a node core module', manifestNameDot: "Name can't start with a dot", manifestNameIllegalChars: 'Name contains illegal characters', manifestNameBlacklisted: 'Name is blacklisted', manifestLicenseInvalid: 'License should be a valid SPDX license expression', manifestLicenseNone: 'No license field', manifestStringExpected: '$0 is not a string', manifestDependencyCollision: '$0 has dependency $1 with range $2 that collides with a dependency in $3 of the same name with version $4', manifestDirectoryNotFound: 'Unable to read $0 directory of module $1', verboseFileCopy: 'Copying $0 to $1.', verboseFileLink: 'Creating hardlink at $0 to $1.', verboseFileSymlink: 'Creating symlink at $0 to $1.', verboseFileSkip: 'Skipping copying of file $0 as the file at $1 is the same size ($2) and mtime ($3).', verboseFileSkipSymlink: 'Skipping copying of $0 as the file at $1 is the same symlink ($2).', verboseFileSkipHardlink: 'Skipping copying of $0 as the file at $1 is the same hardlink ($2).', verboseFileRemoveExtraneous: 'Removing extraneous file $0.', verboseFilePhantomExtraneous: "File $0 would be marked as extraneous but has been removed as it's listed as a phantom file.", verboseFileSkipArtifact: 'Skipping copying of $0 as the file is marked as a built artifact and subject to change.', verboseFileFolder: 'Creating directory $0.', verboseRequestStart: 'Performing $0 request to $1.', verboseRequestFinish: 'Request $0 finished with status code $1.', configSet: 'Set $0 to $1.', configDelete: 'Deleted $0.', configNpm: 'npm config', configPika: 'pika config', couldntFindPackagejson: "Couldn't find a package.json file in $0", couldntFindMatch: "Couldn't find match for $0 in $1 for $2.", couldntFindPackageInCache: "Couldn't find any versions for $0 that matches $1 in our cache (possible versions are $2). This is usually caused by a missing entry in the lockfile, running Pika without the --offline flag may help fix this issue.", couldntFindVersionThatMatchesRange: "Couldn't find any versions for $0 that matches $1", chooseVersionFromList: 'Please choose a version of $0 from this list:', moduleNotInManifest: "This module isn't specified in a package.json file.", moduleAlreadyInManifest: '$0 is already in $1. Please remove existing entry first before adding it to $2.', unknownFolderOrTarball: "Passed folder/tarball doesn't exist,", unknownPackage: "Couldn't find package $0.", unknownPackageName: "Couldn't find package name.", unknownUser: "Couldn't find user $0.", unknownRegistryResolver: 'Unknown registry resolver $0', userNotAnOwner: "User $0 isn't an owner of this package.", invalidVersionArgument: 'Use the $0 flag to create a new version.', invalidVersion: 'Invalid version supplied.', requiredVersionInRange: 'Required version in range.', packageNotFoundRegistry: "Couldn't find package $0 on the $1 registry.", requiredPackageNotFoundRegistry: "Couldn't find package $0 required by $1 on the $2 registry.", doesntExist: "Package $1 refers to a non-existing file '$0'.", missingRequiredPackageKey: `Package $0 doesn't have a $1.`, invalidAccess: 'Invalid argument for access, expected public or restricted.', invalidCommand: 'Invalid subcommand. Try $0', invalidGistFragment: 'Invalid gist fragment $0.', invalidHostedGitFragment: 'Invalid hosted git fragment $0.', invalidFragment: 'Invalid fragment $0.', invalidPackageName: 'Invalid package name.', invalidPackageVersion: "Can't add $0: invalid package version $1.", couldntFindManifestIn: "Couldn't find manifest in $0.", shrinkwrapWarning: 'npm-shrinkwrap.json found. This will not be updated or respected. See https://yarnpkg.com/en/docs/migrating-from-npm for more information.', npmLockfileWarning: 'package-lock.json found. Your project contains lock files generated by tools other than Pika. It is advised not to mix package managers in order to avoid resolution inconsistencies caused by unsynchronized lock files. To clear this warning, remove package-lock.json.', lockfileOutdated: 'Outdated lockfile. Please run `pika install` and try again.', lockfileMerged: 'Merge conflict detected in pika.lock and successfully merged.', lockfileConflict: 'A merge conflict was found in pika.lock but it could not be successfully merged, regenerating pika.lock from scratch.', ignoredScripts: 'Ignored scripts due to flag.', missingAddDependencies: 'Missing list of packages to add to your project.', yesWarning: 'The yes flag has been set. This will automatically answer yes to all questions, which may have security implications.', networkWarning: "You don't appear to have an internet connection. Try the --offline flag to use the cache for registry queries.", flatGlobalError: 'The package $0 requires a flat dependency graph. Add `"flat": true` to your package.json and try again.', noName: `Package doesn't have a name.`, noVersion: `Package doesn't have a version.`, answerRequired: 'An answer is required.', missingWhyDependency: 'Missing package name, folder or path to file to identify why a package has been installed', bugReport: 'If you think this is a bug, please open a bug report with the information provided in $0.', unexpectedError: 'An unexpected error occurred: $0.', jsonError: 'Error parsing JSON at $0, $1.', noPermission: 'Cannot create $0 due to insufficient permissions.', noGlobalFolder: 'Cannot find a suitable global folder. Tried these: $0', allDependenciesUpToDate: 'All of your dependencies are up to date.', legendColorsForVersionUpdates: 'Color legend : \n $0 : Major Update backward-incompatible updates \n $1 : Minor Update backward-compatible features \n $2 : Patch Update backward-compatible bug fixes', frozenLockfileError: 'Your lockfile needs to be updated, but pika was run with `--frozen-lockfile`.', fileWriteError: 'Could not write file $0: $1', fileDeleteError: 'Could not delete file $0: $1', multiplePackagesCantUnpackInSameDestination: 'Pattern $0 is trying to unpack in the same destination $1 as pattern $2. This could result in non-deterministic behavior, skipping.', incorrectLockfileEntry: 'Lockfile has incorrect entry for $0. Ignoring it.', invalidResolutionName: 'Resolution field $0 does not end with a valid package name and will be ignored', invalidResolutionVersion: 'Resolution field $0 has an invalid version entry and may be ignored', incompatibleResolutionVersion: 'Resolution field $0 is incompatible with requested version $1', pikaOutdated: "Your current version of Pika is out of date. The latest version is $0, while you're on $1.", pikaOutdatedInstaller: 'To upgrade, download the latest installer at $0.', pikaOutdatedCommand: 'To upgrade, run the following command:', tooManyArguments: 'Too many arguments, maximum of $0.', tooFewArguments: 'Not enough arguments, expected at least $0.', noArguments: "This command doesn't require any arguments.", ownerRemoving: 'Removing owner $0 from package $1.', ownerRemoved: 'Owner removed.', ownerRemoveError: "Couldn't remove owner.", ownerGetting: 'Getting owners for package $0', ownerGettingFailed: "Couldn't get list of owners.", ownerAlready: 'This user is already an owner of this package.', ownerAdded: 'Added owner.', ownerAdding: 'Adding owner $0 to package $1', ownerAddingFailed: "Couldn't add owner.", ownerNone: 'No owners.', teamCreating: 'Creating team', teamRemoving: 'Removing team', teamAddingUser: 'Adding user to team', teamRemovingUser: 'Removing user from team', teamListing: 'Listing teams', distFailed: `⚠️ Distribution "$0" failed to build: $1 $2`, distExiting: ` Exiting...`, distContinuing: ` Continuing...`, cleaning: 'Cleaning modules', cleanCreatingFile: 'Creating $0', cleanCreatedFile: 'Created $0. Please review the contents of this file then run "pika autoclean --force" to perform a clean.', cleanAlreadyExists: '$0 already exists. To revert to the default file, delete $0 then rerun this command.', cleanRequiresForce: 'This command required the "--force" flag to perform the clean. This is a destructive operation. Files specified in $0 will be deleted.', cleanDoesNotExist: '$0 does not exist. Autoclean will delete files specified by $0. Run "autoclean --init" to create $0 with the default entries.', binLinkCollision: "There's already a linked binary called $0 in your global Pika bin. Could not link this package's $0 bin entry.", linkCollision: "There's already a package called $0 registered. This command has had no effect. If this command was run in another folder with the same name, the other folder is still linked. Please run pika unlink in the other folder if you want to register this folder.", linkMissing: 'No registered package found called $0.', linkRegistered: 'Registered $0.', linkRegisteredMessage: 'You can now run `pika link $0` in the projects where you want to use this package and it will be used instead.', linkUnregistered: 'Unregistered $0.', linkUnregisteredMessage: 'You can now run `pika unlink $0` in the projects where you no longer want to use this package.', linkUsing: 'Using linked package for $0.', linkDisusing: 'Removed linked package $0.', linkDisusingMessage: 'You will need to run `pika` to re-install the package that was linked.', linkTargetMissing: 'The target of linked package $0 is missing. Removing link.', createInvalidBin: 'Invalid bin entry found in package $0.', createMissingPackage: 'Package not found - this is probably an internal error, and should be reported at https://github.com/yarnpkg/yarn/issues.', workspacesAddRootCheck: 'Running this command will add the dependency to the workspace root rather than the workspace itself, which might not be what you want - if you really meant it, make it explicit by running this command again with the -W flag (or --ignore-workspace-root-check).', workspacesRemoveRootCheck: 'Running this command will remove the dependency from the workspace root rather than the workspace itself, which might not be what you want - if you really meant it, make it explicit by running this command again with the -W flag (or --ignore-workspace-root-check).', workspacesFocusRootCheck: 'This command can only be run inside an individual workspace.', workspacesRequirePrivateProjects: 'Workspaces can only be enabled in private projects.', workspacesSettingMustBeArray: 'The workspaces field in package.json must be an array.', workspacesDisabled: 'Your project root defines workspaces but the feature is disabled in your Pika config. Please check "workspaces-experimental" in your .pikarc file.', workspacesNohoistRequirePrivatePackages: 'nohoist config is ignored in $0 because it is not a private package. If you think nohoist should be allowed in public packages, please submit an issue for your use case.', workspacesNohoistDisabled: `$0 defines nohoist but the feature is disabled in your Pika config ("workspaces-nohoist-experimental" in .pikarc file)`, workspaceRootNotFound: "Cannot find the root of your workspace - are you sure you're currently in a workspace?", workspaceMissingWorkspace: 'Missing workspace name.', workspaceMissingCommand: 'Missing command name.', workspaceUnknownWorkspace: 'Unknown workspace $0.', workspaceVersionMandatory: 'Missing version in workspace at $0, ignoring.', workspaceNameMandatory: 'Missing name in workspace at $0, ignoring.', workspaceNameDuplicate: 'There are more than one workspace with name $0', cacheFolderSkipped: 'Skipping preferred cache folder $0 because it is not writable.', cacheFolderMissing: "Pika hasn't been able to find a cache folder it can use. Please use the explicit --cache-folder option to tell it what location to use, or make one of the preferred locations writable.", cacheFolderSelected: 'Selected the next writable cache folder in the list, will be $0.', execMissingCommand: 'Missing command name.', noScriptsAvailable: 'There are no scripts specified inside package.json.', noBinAvailable: 'There are no binary scripts available.', dashDashDeprecation: `From Pika 1.0 onwards, scripts don't require "--" for options to be forwarded. In a future version, any explicit "--" will be forwarded as-is to the scripts.`, commandNotSpecified: 'No command specified.', binCommands: 'Commands available from binary scripts: ', possibleCommands: 'Project commands', commandQuestion: 'Which command would you like to run?', commandFailedWithCode: 'Command failed with exit code $0.', commandFailedWithSignal: 'Command failed with signal $0.', packageRequiresNodeGyp: 'This package requires node-gyp, which is not currently installed. Pika will attempt to automatically install it. If this fails, you can run "pika global add node-gyp" to manually install it.', nodeGypAutoInstallFailed: 'Failed to auto-install node-gyp. Please run "pika global add node-gyp" manually. Error: $0', foundIncompatible: 'Found incompatible module', incompatibleEngine: 'The engine $0 is incompatible with this module. Expected version $1. Got $2', incompatibleCPU: 'The CPU architecture $0 is incompatible with this module.', incompatibleOS: 'The platform $0 is incompatible with this module.', invalidEngine: 'The engine $0 appears to be invalid.', optionalCompatibilityExcluded: '$0 is an optional dependency and failed compatibility check. Excluding it from installation.', optionalModuleFail: 'This module is OPTIONAL, you can safely ignore this error', optionalModuleScriptFail: 'Error running install script for optional dependency: $0', optionalModuleCleanupFail: 'Could not cleanup build artifacts from failed install: $0', unmetPeer: '$0 has unmet peer dependency $1.', incorrectPeer: '$0 has incorrect peer dependency $1.', selectedPeer: 'Selecting $1 at level $2 as the peer dependency of $0.', missingBundledDependency: '$0 is missing a bundled dependency $1. This should be reported to the package maintainer.', savedNewDependency: 'Saved 1 new dependency.', savedNewDependencies: 'Saved $0 new dependencies.', directDependencies: 'Direct dependencies', allDependencies: 'All dependencies', foundWarnings: 'Found $0 warnings.', foundErrors: 'Found $0 errors.', savedLockfile: 'Saved lockfile.', noRequiredLockfile: 'No lockfile in this directory. Run `pika install` to generate one.', noLockfileFound: 'No lockfile found.', invalidSemver: 'Invalid semver version', newVersion: 'New version', currentVersion: 'Current version', noVersionOnPublish: 'Proceeding with current version', manualVersionResolution: 'Unable to find a suitable version for $0, please choose one by typing one of the numbers below:', manualVersionResolutionOption: '$0 which resolved to $1', createdTag: 'Created tag.', createdTagFail: "Couldn't add tag.", deletedTag: 'Deleted tag.', deletedTagFail: "Couldn't delete tag.", gettingTags: 'Getting tags', deletingTags: 'Deleting tag', creatingTag: 'Creating tag $0 = $1', whyStart: 'Why do we have the module $0?', whyFinding: 'Finding dependency', whyCalculating: 'Calculating file sizes', whyUnknownMatch: "We couldn't find a match!", whyInitGraph: 'Initialising dependency graph', whyWhoKnows: "We don't know why this module exists", whyDiskSizeWithout: 'Disk size without dependencies: $0', whyDiskSizeUnique: 'Disk size with unique dependencies: $0', whyDiskSizeTransitive: 'Disk size with transitive dependencies: $0', whySharedDependencies: 'Number of shared dependencies: $0', whyHoistedTo: `Has been hoisted to $0`, whyHoistedFromSimple: `This module exists because it's hoisted from $0.`, whyNotHoistedSimple: `This module exists here because it's in the nohoist list $0.`, whyDependedOnSimple: `This module exists because $0 depends on it.`, whySpecifiedSimple: `This module exists because it's specified in $0.`, whyReasons: 'Reasons this module exists', whyHoistedFrom: 'Hoisted from $0', whyNotHoisted: `in the nohoist list $0`, whyDependedOn: '$0 depends on it', whySpecified: `Specified in $0`, whyMatch: `\r=> Found $0`, uninstalledPackages: 'Uninstalled packages.', uninstallRegenerate: 'Regenerating lockfile and installing missing dependencies', cleanRemovedFiles: 'Removed $0 files', cleanSavedSize: 'Saved $0 MB.', configFileFound: 'Found configuration file $0.', configPossibleFile: 'Checking for configuration file $0.', npmUsername: 'npm username', npmPassword: 'npm password', npmEmail: 'npm email', npmOneTimePassword: 'npm one-time password', loggingIn: 'Logging in', loggedIn: 'Logged in.', notRevokingEnvToken: 'Not revoking login token, specified via environment variable.', notRevokingConfigToken: 'Not revoking login token, specified via config file.', noTokenToRevoke: 'No login token to revoke.', revokingToken: 'Revoking token', revokedToken: 'Revoked login token.', loginAsPublic: 'Logging in as public', incorrectCredentials: 'Incorrect username or password.', incorrectOneTimePassword: 'Incorrect one-time password.', twoFactorAuthenticationEnabled: 'Two factor authentication enabled.', clearedCredentials: 'Cleared login credentials.', publishFail: "Couldn't publish package: $0", publishPrivate: 'Package marked as private, not publishing.', published: 'Published.', publishing: 'Publishing', nonInteractiveNoVersionSpecified: 'You must specify a new version with --new-version when running with --non-interactive.', nonInteractiveNoToken: "No token found and can't prompt for login when running with --non-interactive.", infoFail: 'Received invalid response from npm.', malformedRegistryResponse: 'Received malformed response from registry for $0. The registry may be down.', registryNoVersions: 'No valid versions found for $0. The package may be unpublished.', cantRequestOffline: "Can't make a request in offline mode ($0)", requestManagerNotSetupHAR: 'RequestManager was not setup to capture HAR files', requestError: 'Request $0 returned a $1', requestFailed: 'Request failed $0', tarballNotInNetworkOrCache: '$0: Tarball is not in network and can not be located in cache ($1)', fetchBadHashWithPath: "Integrity check failed for $0 (computed integrity doesn't match our records, got $2)", fetchBadIntegrityAlgorithm: 'Integrity checked failed for $0 (none of the specified algorithms are supported)', fetchErrorCorrupt: '$0. Mirror tarball appears to be corrupt. You can resolve this by running:\n\n rm -rf $1\n pika install', errorExtractingTarball: 'Extracting tar content of $1 failed, the file appears to be corrupt: $0', updateInstalling: 'Installing $0...', hostedGitResolveError: 'Error connecting to repository. Please, check the url.', unknownFetcherFor: 'Unknown fetcher for $0', downloadGitWithoutCommit: 'Downloading the git repo $0 over plain git without a commit hash', downloadHTTPWithoutCommit: 'Downloading the git repo $0 over HTTP without a commit hash', unplugDisabled: "Packages can only be unplugged when Plug'n'Play is enabled.", plugnplayWindowsSupport: "Plug'n'Play on Windows doesn't support the cache and project to be kept on separate drives", packageInstalledWithBinaries: 'Installed $0 with binaries:', packageHasBinaries: '$0 has binaries:', packageHasNoBinaries: '$0 has no binaries', packageBinaryNotFound: "Couldn't find a binary named $0", couldBeDeduped: '$0 could be deduped from $1 to $2', lockfileNotContainPattern: 'Lockfile does not contain pattern: $0', integrityCheckFailed: 'Integrity check failed', noIntegrityFile: "Couldn't find an integrity file", integrityFailedExpectedIsNotAJSON: 'Integrity check: integrity file is not a json', integrityCheckLinkedModulesDontMatch: "Integrity check: Linked modules don't match", integrityFlagsDontMatch: "Integrity check: Flags don't match", integrityLockfilesDontMatch: "Integrity check: Lock files don't match", integrityFailedFilesMissing: 'Integrity check: Files are missing', integrityPatternsDontMatch: "Integrity check: Top level patterns don't match", integrityModulesFoldersMissing: 'Integrity check: Some module folders are missing', integritySystemParamsDontMatch: "Integrity check: System parameters don't match", packageNotInstalled: '$0 not installed', optionalDepNotInstalled: 'Optional dependency $0 not installed', packageWrongVersion: '$0 is wrong version: expected $1, got $2', packageDontSatisfy: "$0 doesn't satisfy found match of $1", lockfileExists: 'Lockfile already exists, not migrating.', pikaManifestExists: 'pika.package.json manifest already exists, not migrating.', noManifestExists: 'No package.json manifest found. Run `pika init` to generate a new pika.package.json manifest.', skippingImport: 'Skipping import of $0 for $1', importFailed: 'Import of $0 for $1 failed, resolving normally.', importResolveFailed: 'Import of $0 failed starting in $1', importResolvedRangeMatch: 'Using version $0 of $1 instead of $2 for $3', importSourceFilesCorrupted: 'Failed to import from package-lock.json, source file(s) corrupted', importPackageLock: 'found npm package-lock.json, converting to pika.lock', importYarnLock: 'found yarn.lock, converting to pika.lock', importNodeModules: 'creating pika.lock from local node_modules folder', packageContainsPikaAsGlobal: 'Installing Pika via Pika will result in you having two separate versions of Pika installed at the same time, which is not recommended. To update Pika please follow https://yarnpkg.com/en/docs/install .', watchStarting: `Starting up`, watchRunning: `Ready! Watching source tree for changes`, watchRebuild: `Rebuilding...`, watchError: `Build error!`, noValidationErrors: `0 Validation Errors found.`, validationErrors: `$0 Validation Error(s) found. Resolve before publishing.`, scopeNotValid: 'The specified scope is not valid.', deprecatedCommand: '$0 is deprecated. Please use $1.', deprecatedListArgs: 'Filtering by arguments is deprecated. Please use the pattern option instead.', implicitFileDeprecated: 'Using the "file:" protocol implicitly is deprecated. Please either prepend the protocol or prepend the path $0 with "./".', unsupportedNodeVersion: 'You are using Node $0 which is not supported and may encounter bugs or unexpected behavior. Pika supports the following semver range: $1', verboseUpgradeBecauseRequested: 'Considering upgrade of $0 to $1 because it was directly requested.', verboseUpgradeBecauseOutdated: 'Considering upgrade of $0 to $1 because a newer version exists in the registry.', verboseUpgradeNotUnlocking: 'Not unlocking $0 in the lockfile because it is a new or direct dependency.', verboseUpgradeUnlocking: 'Unlocking $0 in the lockfile.', folderMissing: "Directory $0 doesn't exist", mutexPortBusy: 'Cannot use the network mutex on port $0. It is probably used by another app.', auditRunning: 'Auditing packages', auditSummary: '$0 vulnerabilities found - Packages audited: $1', auditSummarySeverity: 'Severity:', auditCritical: '$0 Critical', auditHigh: '$0 High', auditModerate: '$0 Moderate', auditLow: '$0 Low', auditInfo: '$0 Info', auditResolveCommand: '# Run $0 to resolve $1 $2', auditSemverMajorChange: 'SEMVER WARNING: Recommended action is a potentially breaking change', auditManualReview: 'Manual Review\nSome vulnerabilities require your attention to resolve\n\nVisit https://go.npm.me/audit-guide for additional guidance', auditRunAuditForDetails: 'Security audit found potential problems. Run "pika audit" for additional details.', auditOffline: 'Skipping audit. Security audit cannot be performed in offline mode.' }; var languages = /*#__PURE__*/Object.freeze({ en: messages }); function stringifyLangArgs(args) { return args.map(function (val) { if (val != null && val.inspect) { return val.inspect(); } else { try { const str = JSON.stringify(val) || val + ''; // should match all literal line breaks and // "u001b" that follow an odd number of backslashes and convert them to ESC // we do this because the JSON.stringify process has escaped these characters return str.replace(/((?:^|[^\\])(?:\\{2})*)\\u001[bB]/g, '$1\u001b').replace(/[\\]r[\\]n|([\\])?[\\]n/g, (match, precededBacklash) => { // precededBacklash not null when "\n" is preceded by a backlash ("\\n") // match will be "\\n" and we don't replace it with os.EOL return precededBacklash ? match : os.EOL; }); } catch (e) { return util.inspect(val); } } }); } class BaseReporter { constructor(opts = {}) { const lang = 'en'; this.language = lang; this.stdout = opts.stdout || process.stdout; this.stderr = opts.stderr || process.stderr; this.stdin = opts.stdin || this._getStandardInput(); this.emoji = !!opts.emoji; this.nonInteractive = !!opts.nonInteractive; this.noProgress = !!opts.noProgress || isCI; this.isVerbose = !!opts.verbose; // @ts-ignore this.isTTY = this.stdout.isTTY; this.peakMemory = 0; this.startTime = Date.now(); this.format = defaultFormatter; } lang(key, ...args) { const msg = languages[this.language][key] || messages[key]; if (!msg) { throw new ReferenceError(`No message defined for language key ${key}`); } // stringify args const stringifiedArgs = stringifyLangArgs(args); // replace $0 placeholders with args return msg.replace(/\$(\d+)/g, (str, i) => { return stringifiedArgs[i]; }); } /** * `stringifyLangArgs` run `JSON.stringify` on strings too causing * them to appear quoted. This marks them as "raw" and prevents * the quoting and escaping */ rawText(str) { return { inspect() { return str; } }; } verbose(msg) { if (this.isVerbose) { this._verbose(msg); } } verboseInspect(val) { if (this.isVerbose) { this._verboseInspect(val); } } _verbose(msg) {} _verboseInspect(val) {} _getStandardInput() { let standardInput; // Accessing stdin in a win32 headless process (e.g., Visual Studio) may throw an exception. try { standardInput = process.stdin; } catch (e) { console.warn(e.message); delete process.stdin; // @ts-ignore process.stdin = new events.EventEmitter(); standardInput = process.stdin; } return standardInput; } initPeakMemoryCounter() { this.checkPeakMemory(); this.peakMemoryInterval = setInterval(() => { this.checkPeakMemory(); }, 1000); // $FlowFixMe: Node's setInterval returns a Timeout, not a Number this.peakMemoryInterval.unref(); } checkPeakMemory() { const { heapTotal } = process.memoryUsage(); if (heapTotal > this.peakMemory) { this.peakMemory = heapTotal; } } close() { if (this.peakMemoryInterval) { clearInterval(this.peakMemoryInterval); this.peakMemoryInterval = null; } } getTotalTime() { return Date.now() - this.startTime; } // TODO list(key, items, hints) {} // Outputs basic tree structure to console tree(key, obj, { force = false } = {}) {} // called whenever we begin a step in the CLI. step(current, total, message, emoji) {} // a error message has been triggered. this however does not always meant an abrupt // program end. error(message) {} // an info message has been triggered. this provides things like stats and diagnostics. info(message) {} // a warning message has been triggered. warn(message) {} // a success message has been triggered. success(message) {} // a simple log message // TODO: rethink the {force} parameter. In the meantime, please don't use it (cf comments in #4143). log(message, { force = false } = {}) {} // a shell command has been executed command(command) {} // inspect and pretty-print any value inspect(value) {} // the screen shown at the very start of the CLI header(pkg) {} // the screen shown at the very end of the CLI footer(showPeakMemory) {} // a table structure table(head, body) {} // render an activity spinner and return a function that will trigger an update activity() { return { tick(name) {}, end() {} }; } // activitySet(total, workers) { return { spinners: Array(workers).fill({ clear() {}, setPrefix() {}, tick() {}, end() {} }), end() {} }; } // render a progress bar and return a function which when called will trigger an update progress(total) { return function () {}; } // utility function to disable progress bar disableProgress() { this.noProgress = true; } } // public function sortTrees(trees) { return trees.sort(function (tree1, tree2) { return tree1.name.localeCompare(tree2.name); }); } function recurseTree(tree, prefix, recurseFunc) { const treeLen = tree.length; const treeEnd = treeLen - 1; for (let i = 0; i < treeLen; i++) { const atEnd = i === treeEnd; recurseFunc(tree[i], prefix + getLastIndentChar(atEnd), prefix + getNextIndentChar(atEnd)); } } function getFormattedOutput(fmt) { const item = formatColor(fmt.color, fmt.name, fmt.formatter); const suffix = getSuffix(fmt.hint, fmt.formatter); return `${fmt.prefix}─ ${item}${suffix}\n`; } function getNextIndentChar(end) { return end ? ' ' : '│ '; } function getLastIndentChar(end) { return end ? '└' : '├'; } function getSuffix(hint, formatter) { return hint ? ` (${formatter.grey(hint)})` : ''; } function formatColor(color, strToFormat, formatter) { return color ? formatter[color](strToFormat) : strToFormat; } const CLEAR_WHOLE_LINE = 0; const CLEAR_RIGHT_OF_CURSOR = 1; function clearLine(stdout) { if (!chalk.supportsColor) { if (stdout instanceof tty.WriteStream) { if (stdout.columns > 0) { stdout.write(`\r${' '.repeat(stdout.columns - 1)}`); } stdout.write(`\r`); } return; } readline.clearLine(stdout, CLEAR_WHOLE_LINE); readline.cursorTo(stdout, 0); } function toStartOfLine(stdout) { if (!chalk.supportsColor) { stdout.write('\r'); return; } readline.cursorTo(stdout, 0); } function writeOnNthLine(stdout, n, msg) { if (!chalk.supportsColor) { return; } if (n == 0) { readline.cursorTo(stdout, 0); stdout.write(msg); readline.clearLine(stdout, CLEAR_RIGHT_OF_CURSOR); return; } readline.cursorTo(stdout, 0); readline.moveCursor(stdout, 0, -n); stdout.write(msg); readline.clearLine(stdout, CLEAR_RIGHT_OF_CURSOR); readline.cursorTo(stdout, 0); readline.moveCursor(stdout, 0, n); } function clearNthLine(stdout, n) { if (!chalk.supportsColor) { return; } if (n == 0) { clearLine(stdout); return; } readline.cursorTo(stdout, 0); readline.moveCursor(stdout, 0, -n); readline.clearLine(stdout, CLEAR_WHOLE_LINE); readline.moveCursor(stdout, 0, n); } class ProgressBar { constructor(total, stdout = process.stderr, callback) { this.stdout = stdout; this.total = total; this.chars = ProgressBar.bars[0]; this.delay = 60; this.curr = 0; this._callback = callback; clearLine(stdout); } tick() { if (this.curr >= this.total) { return; } this.curr++; // schedule render if (!this.id) { this.id = setTimeout(() => this.render(), this.delay); } } cancelTick() { if (this.id) { clearTimeout(this.id); this.id = null; } } stop() { // "stop" by setting current to end so `tick` becomes noop this.curr = this.total; this.cancelTick(); clearLine(this.stdout); if (this._callback) { this._callback(this); } } render() { // clear throttle this.cancelTick(); let ratio = this.curr / this.total; ratio = Math.min(Math.max(ratio, 0), 1); // progress without bar let bar = ` ${this.curr}/${this.total}`; // calculate size of actual bar // $FlowFixMe: investigate process.stderr.columns flow error // @ts-ignore const availableSpace = Math.max(0, this.stdout.columns - bar.length - 3); const width = Math.min(this.total, availableSpace); const completeLength = Math.round(width * ratio); const complete = this.chars[0].repeat(completeLength); const incomplete = this.chars[1].repeat(width - completeLength); bar = `[${complete}${incomplete}]${bar}`; toStartOfLine(this.stdout); this.stdout.write(bar); } } ProgressBar.bars = [['#', '-']]; class Spinner { constructor(stdout = process.stderr, lineNumber = 0) { this.current = 0; this.prefix = ''; this.lineNumber = lineNumber; this.stdout = stdout; this.delay = 60; this.chars = Spinner.spinners[28].split(''); this.text = ''; this.id = null; } setPrefix(prefix) { this.prefix = prefix; } setText(text) { this.text = text; } start() { this.current = 0; this.render(); } render() { if (this.id) { clearTimeout(this.id); } // build line ensuring we don't wrap to the next line let msg = `${this.prefix}${this.chars[this.current]} ${this.text}`; // @ts-ignore const columns = typeof this.stdout.columns === 'number' ? this.stdout.columns : 100; msg = msg.slice(0, columns); writeOnNthLine(this.stdout, this.lineNumber, msg); this.current = ++this.current % this.chars.length; this.id = setTimeout(() => this.render(), this.delay); } stop() { if (this.id) { clearTimeout(this.id); this.id = null; } clearNthLine(this.stdout, this.lineNumber); } } Spinner.spinners = ['|/-\\', '⠂-–—–-', '◐◓◑◒', '◴◷◶◵', '◰◳◲◱', '▖▘▝▗', '■□▪▫', '▌▀▐▄', '▉▊▋▌▍▎▏▎▍▌▋▊▉', '▁▃▄▅▆▇█▇▆▅▄▃', '←↖↑↗→↘↓↙', '┤┘┴└├┌┬┐', '◢◣◤◥', '.oO°Oo.', '.oO@*', '🌍🌎🌏', '◡◡ ⊙⊙ ◠◠', '☱☲☴', '⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏', '⠋⠙⠚⠞⠖⠦⠴⠲⠳⠓', '⠄⠆⠇⠋⠙⠸⠰⠠⠰⠸⠙⠋⠇⠆', '⠋⠙⠚⠒⠂⠂⠒⠲⠴⠦⠖⠒⠐⠐⠒⠓⠋', '⠁⠉⠙⠚⠒⠂⠂⠒⠲⠴⠤⠄⠄⠤⠴⠲⠒⠂⠂⠒⠚⠙⠉⠁', '⠈⠉⠋⠓⠒⠐⠐⠒⠖⠦⠤⠠⠠⠤⠦⠖⠒⠐⠐⠒⠓⠋⠉⠈', '⠁⠁⠉⠙⠚⠒⠂⠂⠒⠲⠴⠤⠄⠄⠤⠠⠠⠤⠦⠖⠒⠐⠐⠒⠓⠋⠉⠈⠈', '⢄⢂⢁⡁⡈⡐⡠', '⢹⢺⢼⣸⣇⡧⡗⡏', '⣾⣽⣻⢿⡿⣟⣯⣷', '⠁⠂⠄⡀⢀⠠⠐⠈']; const auditSeverityColors = { info: chalk.bold, low: chalk.bold, moderate: chalk.yellow, high: chalk.red, critical: chalk.bgRed }; // fixes bold on windows if (process.platform === 'win32' && !(process.env.TERM && /^xterm/i.test(process.env.TERM))) { // @ts-ignore chalk.bold._styles[0].close += '\u001b[m'; } class ConsoleReporter extends BaseReporter { constructor(opts) { super(opts); this._lastCategorySize = 0; this._spinners = new Set(); this.format = chalk; this.format.stripColor = stripAnsi; this.isSilent = !!opts.isSilent; } _prependEmoji(msg, emoji) { if (this.emoji && emoji && this.isTTY) { msg = `${emoji} ${msg}`; } return msg; } _logCategory(category, color, msg) { this._lastCategorySize = category.length; this._log(`${this.format[color](category)} ${msg}`); } _verbose(msg) { this._logCategory('verbose', 'grey', `${process.uptime()} ${msg}`); } _verboseInspect(obj) { this.inspect(obj); } close() { for (const spinner of this._spinners) { spinner.stop(); } this._spinners.clear(); this.stopProgress(); super.close(); } table(head, body) { // head = head.map(field => this.format.underline(field)); // const rows = [head].concat(body); // get column widths const cols = []; for (let i = 0; i < head.length; i++) { const widths = rows.map(row => this.format.stripColor(row[i]).length); cols[i] = Math.max(...widths); } // const builtRows = rows.map(row => { for (let i = 0; i < row.length; i++) { const field = row[i]; const padding = cols[i] - this.format.stripColor(field).length; row[i] = field + ' '.repeat(padding); } return row.join(' '); }); this.log(builtRows.join('\n')); } step(current, total, msg, emoji) { msg = this._prependEmoji(msg, emoji); if (msg.endsWith('?')) { msg = `${removeSuffix(msg, '?')}...?`; } else { msg += '...'; } this.log(`${this.format.dim(`[${current}/${total}]`)} ${msg}`); } inspect(value) { if (typeof value !== 'number' && typeof value !== 'string') { value = util.inspect(value, { breakLength: 0, colors: this.isTTY, depth: null, maxArrayLength: null }); } this.log(String(value), { force: true }); } list(key, items, hints) { const gutterWidth = (this._lastCategorySize || 2) - 1; if (hints) { for (const item of items) { this._log(`${' '.repeat(gutterWidth)}- ${this.format.bold(item)}`); this._log(` ${' '.repeat(gutterWidth)} ${hints[item]}`); } } else { for (const item of items) { this._log(`${' '.repeat(gutterWidth)}- ${item}`); } } } header(pkg) { this.log(this.format.bold(`${pkg.name} v${pkg.version}`)); } footer(showPeakMemory) { this.stopProgress(); const totalTime = (this.getTotalTime() / 1000).toFixed(2); let msg = `Done in ${totalTime}s.`; if (showPeakMemory) { const peakMemory = (this.peakMemory / 1024 / 1024).toFixed(2); msg += ` Peak memory usage ${peakMemory}MB.`; } this.log(this._prependEmoji(msg, '✨')); } log(msg, { force = false } = {}) { this._lastCategorySize = 0; this._log(msg, { force }); } _log(msg, { force = false } = {}) { if (this.isSilent && !force) { return; } clearLine(this.stdout); this.stdout.write(`${msg}\n`); } success(msg) { this._logCategory('success', 'green', msg); } error(msg) { clearLine(this.stderr); this.stderr.write(`${this.format.red('error')} ${msg}\n`); } info(msg) { this._logCategory('info', 'blue', msg); } command(command) { this.log(this.format.dim(`$ ${command}`)); } warn(msg) { clearLine(this.stderr); this.stderr.write(`${this.format.yellow('warning')} ${msg}\n`); } // handles basic tree output to console tree(key, trees, { force = false } = {}) { this.stopProgress(); // if (this.isSilent && !force) { return; } const output = ({ name, children, hint, color }, titlePrefix, childrenPrefix) => { const formatter = this.format; const out = getFormattedOutput({ prefix: titlePrefix, hint, color, name, formatter }); this.stdout.write(out); if (children && children.length) { recurseTree(sortTrees(children), childrenPrefix, output); } }; recurseTree(sortTrees(trees), '', output); } activitySet(total, workers) { if (!this.isTTY || this.noProgress) { return super.activitySet(total, workers); } const spinners = []; const reporterSpinners = this._spinners; for (let i = 1; i < workers; i++) { this.log(''); } for (let i = 0; i < workers; i++) { const spinner = new Spinner(this.stderr, i); reporterSpinners.add(spinner); spinner.start(); let prefix = null; let current = 0; const updatePrefix = () => { spinner.setPrefix(`${this.format.dim(`[${current === 0 ? '-' : current}/${total}]`)} `); }; const clear = () => { prefix = null; current = 0; updatePrefix(); spinner.setText('waiting...'); }; clear(); spinners.unshift({ clear, setPrefix(_current, _prefix) { current = _current; prefix = _prefix; spinner.setText(prefix); updatePrefix(); }, tick(msg) { if (prefix) { msg = `${prefix}: ${msg}`; } spinner.setText(msg); }, end() { spinner.stop(); reporterSpinners.delete(spinner); } }); } return { spinners, end: () => { for (const spinner of spinners) { spinner.end(); } readline.moveCursor(this.stdout, 0, -workers + 1); } }; } activity() { if (!this.isTTY) { return { tick() {}, end() {} }; } const reporterSpinners = this._spinners; const spinner = new Spinner(this.stderr); spinner.start(); reporterSpinners.add(spinner); return { tick(name) { spinner.setText(name); }, end() { spinner.stop(); reporterSpinners.delete(spinner); } }; } progress(count) { if (this.noProgress || count <= 0) { return function () {// noop }; } if (!this.isTTY) { return function () {// TODO what should the behaviour here be? we could buffer progress messages maybe }; } // Clear any potentially old progress bars this.stopProgress(); const bar = this._progressBar = new ProgressBar(count, this.stderr, progress => { if (progress === this._progressBar) { this._progressBar = null; } }); bar.render(); return function () { bar.tick(); }; } stopProgress() { if (this._progressBar) { this._progressBar.stop(); } } } function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; } function _objectSpread2(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(source, true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(source).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } class JSONReporter extends BaseReporter { constructor(opts) { super(opts); this._activityId = 0; this._progressId = 0; } _dump(type, data, error) { let stdout = this.stdout; if (error) { stdout = this.stderr; } stdout.write(`${JSON.stringify({ type, data })}\n`); } _verbose(msg) { this._dump('verbose', msg); } list(type, items, hints) { this._dump('list', { type, items, hints }); } tree(type, trees) { this._dump('tree', { type, trees }); } step(current, total, message) { this._dump('step', { message, current, total }); } inspect(value) { this._dump('inspect', value); } footer(showPeakMemory) { this._dump('finished', this.getTotalTime()); } log(msg) { this._dump('log', msg); } command(msg) { this._dump('command', msg); } table(head, body) { this._dump('table', { head, body }); } success(msg) { this._dump('success', msg); } error(msg) { this._dump('error', msg, true); } warn(msg) { this._dump('warning', msg, true); } info(msg) { this._dump('info', msg); } activitySet(total, workers) { if (!this.isTTY || this.noProgress) { return super.activitySet(total, workers); } const id = this._activityId++; this._dump('activitySetStart', { id, total, workers }); const spinners = []; for (let i = 0; i < workers; i++) { let current = 0; let header = ''; spinners.push({ clear() {}, setPrefix(_current, _header) { current = _current; header = _header; }, tick: msg => { this._dump('activitySetTick', { id, header, current, worker: i, message: msg }); }, end() {} }); } return { spinners, end: () => { this._dump('activitySetEnd', { id }); } }; } activity() { return this._activity({}); } _activity(data) { if (!this.isTTY || this.noProgress) { return { tick() {}, end() {} }; } const id = this._activityId++; this._dump('activityStart', _objectSpread2({ id }, data)); return { tick: name => { this._dump('activityTick', { id, name }); }, end: () => { this._dump('activityEnd', { id }); } }; } progress(total) { if (this.noProgress) { return function () {// noop }; } const id = this._progressId++; let current = 0; this._dump('progressStart', { id, total }); return () => { current++; this._dump('progressTick', { id, current }); if (current === total) { this._dump('progressFinish', { id }); } }; } } // import os from 'os'; // import * as path from 'path'; // import userHome from './util/user-home-dir.js'; // import {getCacheDir, getConfigDir, getDataDir} from './util/user-dirs.js'; const DEPENDENCY_TYPES = ['devDependencies', 'dependencies', 'legacyDependencies']; // export const OWNED_DEPENDENCY_TYPES = ['devDependencies', 'dependencies', 'legacyDependencies']; const RESOLUTIONS = 'resolutions'; const MANIFEST_FIELDS = [RESOLUTIONS, ...DEPENDENCY_TYPES]; // export const NPM_REGISTRY_RE = /https?:\/\/registry\.npmjs\.org/g; // export const PIKA_DOCS = 'https://yarnpkg.com/en/docs/cli/'; // export const PIKA_INSTALLER_SH = 'https://yarnpkg.com/install.sh'; // export const PIKA_INSTALLER_MSI = 'https://yarnpkg.com/latest.msi'; // export const SELF_UPDATE_VERSION_URL = 'https://www.pikapkg.com/downloads/latest-version'; // // cache version, bump whenever we make backwards incompatible changes // export const CACHE_VERSION = 3; // // lockfile version, bump whenever we make backwards incompatible changes // export const LOCKFILE_VERSION = 1; // // max amount of network requests to perform concurrently // export const NETWORK_CONCURRENCY = 8; // // HTTP timeout used when downloading packages // export const NETWORK_TIMEOUT = 30 * 1000; // in milliseconds // // max amount of child processes to execute concurrently const CHILD_CONCURRENCY = 5; // export const REQUIRED_PACKAGE_KEYS = ['name', 'version', '_uid']; const NODE_PACKAGE_JSON = 'package.json'; // export const PNP_FILENAME = '.pnp'; // export const POSIX_GLOBAL_PREFIX = `${process.env.DESTDIR || ''}/usr/local`; // export const FALLBACK_GLOBAL_PREFIX = path.join(userHome, '.pika'); // export const META_FOLDER = '.pika-meta'; // export const INTEGRITY_FILENAME = '.pika-integrity'; // export const LOCKFILE_FILENAME = 'pika.lock'; // export const LEGACY_LOCKFILE_FILENAME = 'yarn.lock'; // export const METADATA_FILENAME = '.pika-metadata.json'; // export const TARBALL_FILENAME = '.pika-tarball.tgz'; // export const CLEAN_FILENAME = '.pikaclean'; // export const NPM_LOCK_FILENAME = 'package-lock.json'; // export const NPM_SHRINKWRAP_FILENAME = 'npm-shrinkwrap.json'; const DEFAULT_INDENT = ' '; // export const SINGLE_INSTANCE_PORT = 31997; // export const SINGLE_INSTANCE_FILENAME = '.pika-single-instance'; const ENV_PATH_KEY = getPathKey(process.platform, process.env); function getPathKey(platform, env) { let pathKey = 'PATH'; // windows calls its path "Path" usually, but this is not guaranteed. if (platform === 'win32') { pathKey = 'Path'; for (const key in env) { if (key.toLowerCase() === 'path') { pathKey = key; } } } return pathKey; } // export const VERSION_COLOR_SCHEME: {[key: string]: VersionColor} = { // major: 'red', // premajor: 'red', // minor: 'yellow', // preminor: 'yellow', // patch: 'green', // prepatch: 'green', // prerelease: 'red', // unchanged: 'white', // unknown: 'red', // }; // export type VersionColor = 'red' | 'yellow' | 'green' | 'white'; // export type RequestHint = 'dev' | 'optional' | 'resolution' | 'workspaces'; function nullify(obj) { if (Array.isArray(obj)) { for (const item of obj) { nullify(item); } } else if (obj !== null && typeof obj === 'object' || typeof obj === 'function') { Object.setPrototypeOf(obj, null); // for..in can only be applied to 'object', not 'function' if (typeof obj === 'object') { for (const key in obj) { nullify(obj[key]); } } } return obj; } const unlink = util.promisify(_rimraf); const glob = util.promisify(_glob); const mkdirp = util.promisify(_mkdirp); // const open = util.promisify(fs.open); const writeFile = util.promisify(fs.writeFile); const readlink = util.promisify(fs.readlink); const realpath = util.promisify(fs.realpath); const readdir = util.promisify(fs.readdir); const rename = util.promisify(fs.rename); const access = util.promisify(fs.access); const stat = util.promisify(fs.stat); const exists = util.promisify(fs.exists); const lstat = util.promisify(fs.lstat); const chmod = util.promisify(fs.chmod); const link = util.promisify(fs.link); const copyFile = util.promisify(fs.copyFile); const readFileBuffer = util.promisify(fs.readFile); const readFile = path => { return util.promisify(fs.readFile)(path, { encoding: 'utf-8' }); }; // export {unlink}; // export type CopyQueueItem = { // src: string, // dest: string, // type?: string, // onFresh?: () => void, // onDone?: () => void, // }; // type CopyQueue = Array; // type LinkFileAction = { // src: string, // dest: string, // removeDest: boolean, // }; // type CopySymlinkAction = { // dest: string, // linkname: string, // }; // type CopyActions = { // file: Array, // symlink: Array, // link: Array, // }; // type CopyOptions = { // onProgress: (dest: string) => void, // onStart: (num: number) => void, // possibleExtraneous: Set, // ignoreBasenames: Array, // artifactFiles: Array, // }; // type FailedFolderQuery = { // error: Error, // folder: string, // }; // type FolderQueryResult = { // skipped: Array, // folder?: string, // }; // async function buildActionsForCopy( // queue: CopyQueue, // events: CopyOptions, // possibleExtraneous: Set, // reporter: Reporter, // ): Promise { // const artifactFiles: Set = new Set(events.artifactFiles || []); // const files: Set = new Set(); // // initialise events // for (const item of queue) { // const onDone = item.onDone; // item.onDone = () => { // events.onProgress(item.dest); // if (onDone) { // onDone(); // } // }; // } // events.onStart(queue.length); // // start building actions // const actions: CopyActions = { // file: [], // symlink: [], // link: [], // }; // // custom concurrency logic as we're always executing stacks of CONCURRENT_QUEUE_ITEMS queue items // // at a time due to the requirement to push items onto the queue // while (queue.length) { // const items = queue.splice(0, CONCURRENT_QUEUE_ITEMS); // await Promise.all(items.map(build)); // } // // simulate the existence of some files to prevent considering them extraneous // for (const file of artifactFiles) { // if (possibleExtraneous.has(file)) { // reporter.verbose(reporter.lang('verboseFilePhantomExtraneous', file)); // possibleExtraneous.delete(file); // } // } // for (const loc of possibleExtraneous) { // if (files.has(loc.toLowerCase())) { // possibleExtraneous.delete(loc); // } // } // return actions; // // // async function build(data: CopyQueueItem): Promise { // const {src, dest, type} = data; // const onFresh = data.onFresh || noop; // const onDone = data.onDone || noop; // // TODO https://github.com/yarnpkg/yarn/issues/3751 // // related to bundled dependencies handling // if (files.has(dest.toLowerCase())) { // reporter.verbose(`The case-insensitive file ${dest} shouldn't be copied twice in one bulk copy`); // } else { // files.add(dest.toLowerCase()); // } // if (type === 'symlink') { // await mkdirp(path.dirname(dest)); // onFresh(); // actions.symlink.push({ // dest, // linkname: src, // }); // onDone(); // return; // } // if (events.ignoreBasenames.indexOf(path.basename(src)) >= 0) { // // ignored file // return; // } // const srcStat = await lstat(src); // let srcFiles; // if (srcStat.isDirectory()) { // srcFiles = await readdir(src); // } // let destStat; // try { // // try accessing the destination // destStat = await lstat(dest); // } catch (e) { // // proceed if destination doesn't exist, otherwise error // if (e.code !== 'ENOENT') { // throw e; // } // } // // if destination exists // if (destStat) { // const bothSymlinks = srcStat.isSymbolicLink() && destStat.isSymbolicLink(); // const bothFolders = srcStat.isDirectory() && destStat.isDirectory(); // const bothFiles = srcStat.isFile() && destStat.isFile(); // // EINVAL access errors sometimes happen which shouldn't because node shouldn't be giving // // us modes that aren't valid. investigate this, it's generally safe to proceed. // /* if (srcStat.mode !== destStat.mode) { // try { // await access(dest, srcStat.mode); // } catch (err) {} // } */ // if (bothFiles && artifactFiles.has(dest)) { // // this file gets changed during build, likely by a custom install script. Don't bother checking it. // onDone(); // reporter.verbose(reporter.lang('verboseFileSkipArtifact', src)); // return; // } // if (bothFiles && srcStat.size === destStat.size && fileDatesEqual(srcStat.mtime, destStat.mtime)) { // // we can safely assume this is the same file // onDone(); // reporter.verbose(reporter.lang('verboseFileSkip', src, dest, srcStat.size, +srcStat.mtime)); // return; // } // if (bothSymlinks) { // const srcReallink = await readlink(src); // if (srcReallink === (await readlink(dest))) { // // if both symlinks are the same then we can continue on // onDone(); // reporter.verbose(reporter.lang('verboseFileSkipSymlink', src, dest, srcReallink)); // return; // } // } // if (bothFolders) { // // mark files that aren't in this folder as possibly extraneous // const destFiles = await readdir(dest); // invariant(srcFiles, 'src files not initialised'); // for (const file of destFiles) { // if (srcFiles.indexOf(file) < 0) { // const loc = path.join(dest, file); // possibleExtraneous.add(loc); // if ((await lstat(loc)).isDirectory()) { // for (const file of await readdir(loc)) { // possibleExtraneous.add(path.join(loc, file)); // } // } // } // } // } // } // if (destStat && destStat.isSymbolicLink()) { // await unlink(dest); // destStat = null; // } // if (srcStat.isSymbolicLink()) { // onFresh(); // const linkname = await readlink(src); // actions.symlink.push({ // dest, // linkname, // }); // onDone(); // } else if (srcStat.isDirectory()) { // if (!destStat) { // reporter.verbose(reporter.lang('verboseFileFolder', dest)); // await mkdirp(dest); // } // const destParts = dest.split(path.sep); // while (destParts.length) { // files.add(destParts.join(path.sep).toLowerCase()); // destParts.pop(); // } // // push all files to queue // invariant(srcFiles, 'src files not initialised'); // let remaining = srcFiles.length; // if (!remaining) { // onDone(); // } // for (const file of srcFiles) { // queue.push({ // dest: path.join(dest, file), // onFresh, // onDone: () => { // if (--remaining === 0) { // onDone(); // } // }, // src: path.join(src, file), // }); // } // } else if (srcStat.isFile()) { // onFresh(); // actions.file.push({ // src, // dest, // atime: srcStat.atime, // mtime: srcStat.mtime, // mode: srcStat.mode, // }); // onDone(); // } else { // throw new Error(`unsure how to copy this: ${src}`); // } // } // } // async function buildActionsForHardlink( // queue: CopyQueue, // events: CopyOptions, // possibleExtraneous: Set, // reporter: Reporter, // ): Promise { // const artifactFiles: Set = new Set(events.artifactFiles || []); // const files: Set = new Set(); // // initialise events // for (const item of queue) { // const onDone = item.onDone || noop; // item.onDone = () => { // events.onProgress(item.dest); // onDone(); // }; // } // events.onStart(queue.length); // // start building actions // const actions: CopyActions = { // file: [], // symlink: [], // link: [], // }; // // custom concurrency logic as we're always executing stacks of CONCURRENT_QUEUE_ITEMS queue items // // at a time due to the requirement to push items onto the queue // while (queue.length) { // const items = queue.splice(0, CONCURRENT_QUEUE_ITEMS); // await Promise.all(items.map(build)); // } // // simulate the existence of some files to prevent considering them extraneous // for (const file of artifactFiles) { // if (possibleExtraneous.has(file)) { // reporter.verbose(reporter.lang('verboseFilePhantomExtraneous', file)); // possibleExtraneous.delete(file); // } // } // for (const loc of possibleExtraneous) { // if (files.has(loc.toLowerCase())) { // possibleExtraneous.delete(loc); // } // } // return actions; // // // async function build(data: CopyQueueItem): Promise { // const {src, dest} = data; // const onFresh = data.onFresh || noop; // const onDone = data.onDone || noop; // if (files.has(dest.toLowerCase())) { // // Fixes issue https://github.com/yarnpkg/yarn/issues/2734 // // When bulk hardlinking we have A -> B structure that we want to hardlink to A1 -> B1, // // package-linker passes that modules A1 and B1 need to be hardlinked, // // the recursive linking algorithm of A1 ends up scheduling files in B1 to be linked twice which will case // // an exception. // onDone(); // return; // } // files.add(dest.toLowerCase()); // if (events.ignoreBasenames.indexOf(path.basename(src)) >= 0) { // // ignored file // return; // } // const srcStat = await lstat(src); // let srcFiles; // if (srcStat.isDirectory()) { // srcFiles = await readdir(src); // } // const destExists = await exists(dest); // if (destExists) { // const destStat = await lstat(dest); // const bothSymlinks = srcStat.isSymbolicLink() && destStat.isSymbolicLink(); // const bothFolders = srcStat.isDirectory() && destStat.isDirectory(); // const bothFiles = srcStat.isFile() && destStat.isFile(); // if (srcStat.mode !== destStat.mode) { // try { // await access(dest, srcStat.mode); // } catch (err) { // // EINVAL access errors sometimes happen which shouldn't because node shouldn't be giving // // us modes that aren't valid. investigate this, it's generally safe to proceed. // reporter.verbose(err); // } // } // if (bothFiles && artifactFiles.has(dest)) { // // this file gets changed during build, likely by a custom install script. Don't bother checking it. // onDone(); // reporter.verbose(reporter.lang('verboseFileSkipArtifact', src)); // return; // } // // correct hardlink // if (bothFiles && srcStat.ino !== null && srcStat.ino === destStat.ino) { // onDone(); // reporter.verbose(reporter.lang('verboseFileSkip', src, dest, srcStat.ino)); // return; // } // if (bothSymlinks) { // const srcReallink = await readlink(src); // if (srcReallink === (await readlink(dest))) { // // if both symlinks are the same then we can continue on // onDone(); // reporter.verbose(reporter.lang('verboseFileSkipSymlink', src, dest, srcReallink)); // return; // } // } // if (bothFolders) { // // mark files that aren't in this folder as possibly extraneous // const destFiles = await readdir(dest); // invariant(srcFiles, 'src files not initialised'); // for (const file of destFiles) { // if (srcFiles.indexOf(file) < 0) { // const loc = path.join(dest, file); // possibleExtraneous.add(loc); // if ((await lstat(loc)).isDirectory()) { // for (const file of await readdir(loc)) { // possibleExtraneous.add(path.join(loc, file)); // } // } // } // } // } // } // if (srcStat.isSymbolicLink()) { // onFresh(); // const linkname = await readlink(src); // actions.symlink.push({ // dest, // linkname, // }); // onDone(); // } else if (srcStat.isDirectory()) { // reporter.verbose(reporter.lang('verboseFileFolder', dest)); // await mkdirp(dest); // const destParts = dest.split(path.sep); // while (destParts.length) { // files.add(destParts.join(path.sep).toLowerCase()); // destParts.pop(); // } // // push all files to queue // invariant(srcFiles, 'src files not initialised'); // let remaining = srcFiles.length; // if (!remaining) { // onDone(); // } // for (const file of srcFiles) { // queue.push({ // onFresh, // src: path.join(src, file), // dest: path.join(dest, file), // onDone: () => { // if (--remaining === 0) { // onDone(); // } // }, // }); // } // } else if (srcStat.isFile()) { // onFresh(); // actions.link.push({ // src, // dest, // removeDest: destExists, // }); // onDone(); // } else { // throw new Error(`unsure how to copy this: ${src}`); // } // } // } // export function copy(src: string, dest: string, reporter: Reporter): Promise { // return copyBulk([{src, dest}], reporter); // } // export async function copyBulk( // queue: CopyQueue, // reporter: Reporter, // _events?: { // onProgress?: (dest: string) => void, // onStart?: (num: number) => void, // possibleExtraneous: Set, // ignoreBasenames?: Array, // artifactFiles?: Array, // }, // ): Promise { // const events: CopyOptions = { // onStart: (_events && _events.onStart) || noop, // onProgress: (_events && _events.onProgress) || noop, // possibleExtraneous: _events ? _events.possibleExtraneous : new Set(), // ignoreBasenames: (_events && _events.ignoreBasenames) || [], // artifactFiles: (_events && _events.artifactFiles) || [], // }; // const actions: CopyActions = await buildActionsForCopy(queue, events, events.possibleExtraneous, reporter); // events.onStart(actions.file.length + actions.symlink.length + actions.link.length); // const fileActions: Array = actions.file; // const currentlyWriting: Map> = new Map(); // await promise.queue( // fileActions, // async (data: CopyFileAction): Promise => { // let writePromise; // while ((writePromise = currentlyWriting.get(data.dest))) { // await writePromise; // } // reporter.verbose(reporter.lang('verboseFileCopy', data.src, data.dest)); // const copier = copyFile(data, () => currentlyWriting.delete(data.dest)); // currentlyWriting.set(data.dest, copier); // events.onProgress(data.dest); // return copier; // }, // CONCURRENT_QUEUE_ITEMS, // ); // // we need to copy symlinks last as they could reference files we were copying // const symlinkActions: Array = actions.symlink; // await promise.queue(symlinkActions, (data): Promise => { // const linkname = path.resolve(path.dirname(data.dest), data.linkname); // reporter.verbose(reporter.lang('verboseFileSymlink', data.dest, linkname)); // return symlink(linkname, data.dest); // }); // } // export async function hardlinkBulk( // queue: CopyQueue, // reporter: Reporter, // _events?: { // onProgress?: (dest: string) => void, // onStart?: (num: number) => void, // possibleExtraneous: Set, // artifactFiles?: Array, // }, // ): Promise { // const events: CopyOptions = { // onStart: (_events && _events.onStart) || noop, // onProgress: (_events && _events.onProgress) || noop, // possibleExtraneous: _events ? _events.possibleExtraneous : new Set(), // artifactFiles: (_events && _events.artifactFiles) || [], // ignoreBasenames: [], // }; // const actions: CopyActions = await buildActionsForHardlink(queue, events, events.possibleExtraneous, reporter); // events.onStart(actions.file.length + actions.symlink.length + actions.link.length); // const fileActions: Array = actions.link; // await promise.queue( // fileActions, // async (data): Promise => { // reporter.verbose(reporter.lang('verboseFileLink', data.src, data.dest)); // if (data.removeDest) { // await unlink(data.dest); // } // await link(data.src, data.dest); // }, // CONCURRENT_QUEUE_ITEMS, // ); // // we need to copy symlinks last as they could reference files we were copying // const symlinkActions: Array = actions.symlink; // await promise.queue(symlinkActions, (data): Promise => { // const linkname = path.resolve(path.dirname(data.dest), data.linkname); // reporter.verbose(reporter.lang('verboseFileSymlink', data.dest, linkname)); // return symlink(linkname, data.dest); // }); // } // function _readFile(loc: string, encoding: string): Promise { // return new Promise((resolve, reject) => { // fs.readFile(loc, encoding, function(err, content) { // if (err) { // reject(err); // } else { // resolve(content); // } // }); // }); // } // export function readFile(loc: string): Promise { // return _readFile(loc, 'utf8').then(normalizeOS); // } // export function readFileRaw(loc: string): Promise { // return _readFile(loc, 'binary'); // } // export async function readFileAny(files: Array): Promise { // for (const file of files) { // if (await exists(file)) { // return readFile(file); // } // } // return null; // } async function readJson(loc) { return (await readJsonAndFile(loc)).object; } async function readJsonAndFile(loc) { const file = await readFile(loc); try { return { object: nullify(JSON.parse(stripBOM(file))), content: file }; } catch (err) { err.message = `${loc}: ${err.message}`; throw err; } } // const stat = await lstat(loc); // const {size, blksize: blockSize} = stat; // return Math.ceil(size / blockSize) * blockSize; // } // export function normalizeOS(body: string): string { // return body.replace(/\r\n/g, '\n'); // } const cr = '\r'.charCodeAt(0); const lf = '\n'.charCodeAt(0); async function getEolFromFile(path) { if (!(await exists(path))) { return undefined; } const buffer = await readFileBuffer(path); for (let i = 0; i < buffer.length; ++i) { if (buffer[i] === cr) { return '\r\n'; } if (buffer[i] === lf) { return '\n'; } } return undefined; } async function writeFilePreservingEol(path, data) { const eol = (await getEolFromFile(path)) || os.EOL; if (eol !== '\n') { data = data.replace(/\n/g, eol); } await writeFile(path, data); } // export async function hardlinksWork(dir: string): Promise { // const filename = 'test-file' + Math.random(); // const file = path.join(dir, filename); // const fileLink = path.join(dir, filename + '-link'); // try { // await writeFile(file, 'test'); // await link(file, fileLink); // } catch (err) { // return false; // } finally { // await unlink(file); // await unlink(fileLink); // } // return true; // } // // not a strict polyfill for Node's fs.mkdtemp // export async function makeTempDir(prefix?: string): Promise { // const dir = path.join(os.tmpdir(), `pika-${prefix || ''}-${Date.now()}-${Math.random()}`); // await unlink(dir); // await mkdirp(dir); // return dir; // } // export async function readFirstAvailableStream(paths: Iterable): Promise { // for (const path of paths) { // try { // const fd = await open(path, 'r'); // return fs.createReadStream(path, {fd}); // } catch (err) { // // Try the next one // } // } // return null; // } // export async function getFirstSuitableFolder( // paths: Iterable, // mode: number = constants.W_OK | constants.X_OK, // eslint-disable-line no-bitwise // ): Promise { // const result: FolderQueryResult = { // skipped: [], // folder: null, // }; // for (const folder of paths) { // try { // await mkdirp(folder); // await access(folder, mode); // result.folder = folder; // return result; // } catch (error) { // result.skipped.push({ // error, // folder, // }); // } // } // return result; // } async function generatePublishManifest(manifest, config, _dists) { const { name, version, description, keywords, homepage, bugs, bin, license, authors, contributors, man, sideEffects, repository, dependencies, peerDependencies, devDependencies, bundledDependencies, optionalDependencies, engines, enginesStrict, private: priv, publishConfig } = manifest; const newManifest = { name, description, version, license, bin, files: ['dist-*/', 'bin/'], pika: true, sideEffects: sideEffects || false, keywords, homepage, bugs, authors, contributors, man, repository, dependencies: dependencies || {}, peerDependencies, devDependencies, bundledDependencies, optionalDependencies, engines, enginesStrict, private: priv, publishConfig }; const dists = _dists || (await config.getDistributions()); for (const [runner, options] of dists) { if (runner.manifest) { await runner.manifest(newManifest, { cwd: config.cwd, isFull: true, manifest, options }); } } newManifest.pika = true; return newManifest; } function generatePrettyManifest(manifest) { return JSON.stringify(_objectSpread2({}, manifest, { dependencies: Object.keys(manifest.dependencies).length === 0 ? {} : '{ ... }' }), null, 2); } function hasWrapper() { return true; } const examples = null; class Build { constructor(flags, config, reporter) { this.flags = flags; this.config = config; this.reporter = reporter; this.totalNum = 0; this.out = path.resolve(config.cwd, flags.out || 'pkg/'); if (this.out === this.config.cwd) { throw new Error('On publish, you cannot write to cwd because a package.json is created'); } } async cleanup() { const { out } = this; await unlink(path.join(out, '*')); } async init(isFull) { const { config, out, reporter, flags } = this; const { cwd } = config; const outPretty = path.relative(cwd, out) + path.sep; const manifest = await config.manifest; const { sourcemap } = manifest['@pika/pack'] || { sourcemap: true }; const distRunners = await config.getDistributions(); const builderConfig = { out, cwd, reporter: { info: msg => reporter.log(chalk.dim(` » ${msg}`)), warning: msg => reporter.log(chalk.yellow(` » ${msg}`)), success: msg => reporter.log(chalk.green(` » ${msg}`)), created: (filename, entrypoint) => reporter.log(` 📝 ${chalk.green(path.relative(cwd, filename))} ${entrypoint ? chalk.dim(`[${entrypoint}]`) : ''}`) }, isFull, manifest, src: { loc: path.join(out, 'dist-src'), entrypoint: path.join(out, 'dist-src', 'index.js'), // TODO: Deprecated, remove options: {}, // TODO: Deprecated, remove files: await (async () => { const ignoreSet = new Set([]); ignoreSet.add('**/*/README.md'); const files = await glob(`src/**/*`, { cwd, nodir: true, absolute: true, ignore: Array.from(ignoreSet).map(g => path.join('src', g)) }); return files.filter(fileAbs => !fileAbs.endsWith('.d.ts')); })() } }; const steps = []; steps.push(async (curr, total) => { this.reporter.step(curr, total, 'Validating source'); for (const [runner, options] of distRunners) { if (runner.validate) { const result = await runner.validate(_objectSpread2({}, builderConfig, { options: _objectSpread2({ sourcemap }, options) })); if (result instanceof Error) { throw result; } } } }); steps.push(async (curr, total) => { this.reporter.step(curr, total, `Preparing pipeline`); await this.cleanup(); reporter.log(` ❇️ ${chalk.green(outPretty)}`); for (const [runner, options] of distRunners) { await (runner.beforeBuild && runner.beforeBuild(_objectSpread2({}, builderConfig, { options: _objectSpread2({ sourcemap }, options) }))); } }); if (distRunners.length === 0) { steps.push(async (curr, total) => { this.reporter.step(curr, total, `Pipeline is empty! See ${chalk.underline('https://github.com/pikapkg/pack')} for help getting started`); }); } for (const [runner, options] of distRunners) { steps.push(async (curr, total) => { this.reporter.step(curr, total, `Running ${chalk.bold(runner.name)}`); // return Promise.resolve( try { await (runner.beforeJob && runner.beforeJob(_objectSpread2({}, builderConfig, { options: _objectSpread2({ sourcemap }, options) }))); await (runner.build && runner.build(_objectSpread2({}, builderConfig, { options: _objectSpread2({ sourcemap }, options) }))); await (runner.afterJob && runner.afterJob(_objectSpread2({}, builderConfig, { options: _objectSpread2({ sourcemap }, options) }))); } catch (err) { if (flags.force) { console.log(' ❗️ ', chalk.red(err.message), chalk.dim('--force, continuing...')); } else { throw err; } } // ).catch(err => { // log(chalk.red(err.message)); // reporter.log( // reporter.lang("distFailed", runner.name, err.code, err.message), // { force: true } // ); // if (err.forceExit === true) { // reporter.log(reporter.lang("distExiting")); // throw err; // return; // } // reporter.log(reporter.lang("distContinuing")); // }); }); } steps.push(async (curr, total) => { this.reporter.step(curr, total, `Finalizing package`); for (const [runner, options] of distRunners) { await (runner.afterBuild && runner.afterBuild(_objectSpread2({}, builderConfig, { options: _objectSpread2({ sourcemap }, options) }))); } if (await exists(path.join(cwd, 'CHANGELOG'))) { copyFile(path.join(cwd, 'CHANGELOG'), path.join(out, 'CHANGELOG')); reporter.log(chalk.dim(` » copying CHANGELOG...`)); } else if (await exists(path.join(cwd, 'CHANGELOG.md'))) { copyFile(path.join(cwd, 'CHANGELOG.md'), path.join(out, 'CHANGELOG.md')); reporter.log(chalk.dim(` » copying CHANGELOG.md...`)); } if (await exists(path.join(cwd, 'LICENSE'))) { copyFile(path.join(cwd, 'LICENSE'), path.join(out, 'LICENSE')); reporter.log(chalk.dim(` » copying LICENSE...`)); } else if (await exists(path.join(cwd, 'LICENSE.md'))) { copyFile(path.join(cwd, 'LICENSE.md'), path.join(out, 'LICENSE.md')); reporter.log(chalk.dim(` » copying LICENSE.md...`)); } if (await exists(path.join(cwd, 'README'))) { copyFile(path.join(cwd, 'README'), path.join(out, 'README')); reporter.log(chalk.dim(` » copying README...`)); } else if (await exists(path.join(cwd, 'README.md'))) { copyFile(path.join(cwd, 'README.md'), path.join(out, 'README.md')); reporter.log(chalk.dim(` » copying README.md...`)); } const publishManifest = await generatePublishManifest(config._manifest, config, distRunners); if (out === cwd) { reporter.log(`NEW MANIFEST:\n\n`); reporter.log(generatePrettyManifest(publishManifest)); reporter.log(`\n\n`); } else { await writeFilePreservingEol(path.join(out, 'package.json'), JSON.stringify(publishManifest, null, DEFAULT_INDENT) + '\n'); reporter.log(` 📝 ` + chalk.green(outPretty + 'package.json')); } reporter.log(` 📦 ` + chalk.green(outPretty)); }); let currentStep = 0; for (const step of steps) { await step(++currentStep, steps.length); } } } async function run(config, reporter, flags, args) { const isProduction = flags.publish; const builder = new Build(flags, config, reporter); await builder.init(isProduction); } var buildCommand = /*#__PURE__*/Object.freeze({ hasWrapper: hasWrapper, examples: examples, Build: Build, run: run }); var typos = { autohr: 'author', autor: 'author', contributers: 'contributors', depdenencies: 'dependencies', dependancies: 'dependencies', dependecies: 'dependencies', depends: 'dependencies', 'dev-dependencies': 'devDependencies', devDependences: 'devDependencies', devDepenencies: 'devDependencies', devEependencies: 'devDependencies', devdependencies: 'devDependencies', hampage: 'homepage', hompage: 'homepage', prefereGlobal: 'preferGlobal', publicationConfig: 'publishConfig', repo: 'repository', repostitory: 'repository', script: 'scripts' }; const strings = ['name', 'version']; const dependencyKeys = [// npm registry will include optionalDependencies in dependencies and we'll want to dedupe them from the // other fields first 'optionalDependencies', // it's seemingly common to include a dependency in dependencies and devDependencies of the same name but // different ranges, this can cause a lot of issues with our determinism and the behaviour of npm is // currently unspecified. 'dependencies', 'devDependencies']; function isValidName(name) { return !name.match(/[\/@\s\+%:]/) && encodeURIComponent(name) === name; } function isValidScopedName(name) { if (name[0] !== '@') { return false; } const parts = name.slice(1).split('/'); return parts.length === 2 && isValidName(parts[0]) && isValidName(parts[1]); } function isValidPackageName(name) { return isValidName(name) || isValidScopedName(name); } function validate (info, isRoot, reporter, warn) { if (isRoot) { for (const key in typos) { if (key in info) { warn(reporter.lang('manifestPotentialTypo', key, typos[key])); } } } // validate name const { name } = info; if (typeof name === 'string') { if (isRoot && isBuiltinModule(name)) { warn(reporter.lang('manifestBuiltinModule', name)); } // cannot start with a dot if (name[0] === '.') { throw new types.MessageError(reporter.lang('manifestNameDot')); } // cannot contain the following characters if (!isValidPackageName(name)) { throw new types.MessageError(reporter.lang('manifestNameIllegalChars')); } // cannot equal node_modules or favicon.ico const lower = name.toLowerCase(); if (lower === 'node_modules' || lower === 'favicon.ico') { throw new types.MessageError(reporter.lang('manifestNameBlacklisted')); } } // Only care if you are trying to publish to npm. // // validate license // if (isRoot && !info.private) { // if (typeof info.license === 'string') { // const license = info.license.replace(/\*$/g, ''); // if (!isValidLicense(license)) { // warn(reporter.lang('manifestLicenseInvalid')); // } // } else { // warn(reporter.lang('manifestLicenseNone')); // } // } // validate strings for (const key of strings) { const val = info[key]; if (val && typeof val !== 'string') { throw new types.MessageError(reporter.lang('manifestStringExpected', key)); } } cleanDependencies(info, isRoot, reporter, warn); } function cleanDependencies(info, isRoot, reporter, warn) { // get dependency objects const depTypes = []; for (const type of dependencyKeys) { const deps = info[type]; if (!deps || typeof deps !== 'object') { continue; } depTypes.push([type, deps]); } // aggregate all non-trivial deps (not '' or '*') const nonTrivialDeps = new Map(); for (const [type, deps] of depTypes) { for (const name of Object.keys(deps)) { const version = deps[name]; if (!nonTrivialDeps.has(name) && version && version !== '*') { nonTrivialDeps.set(name, { type, version }); } } } // overwrite first dep of package with non-trivial version, remove the rest const setDeps = new Set(); for (const [type, deps] of depTypes) { for (const name of Object.keys(deps)) { let version = deps[name]; const dep = nonTrivialDeps.get(name); if (dep) { if (version && version !== '*' && version !== dep.version && isRoot) { // only throw a warning when at the root warn(reporter.lang('manifestDependencyCollision', dep.type, name, dep.version, type, version)); } version = dep.version; } if (setDeps.has(name)) { delete deps[name]; } else { deps[name] = version; setDeps.add(name); } } } } function isValidLicense(license) { return !!license && validateLicense(license).validForNewPackages; } function stringifyPerson(person) { if (!person || typeof person !== 'object') { return person; } const parts = []; if (person.name) { parts.push(person.name); } const email = person.email || person.mail; if (typeof email === 'string') { parts.push(`<${email}>`); } const url = person.url || person.web; if (typeof url === 'string') { parts.push(`(${url})`); } return parts.join(' '); } function parsePerson(person) { if (typeof person !== 'string') { return person; } // format: name (url) const obj = {}; let name = person.match(/^([^\(<]+)/); if (name && name[0].trim()) { obj.name = name[0].trim(); } const email = person.match(/<([^>]+)>/); if (email) { obj.email = email[1]; } const url = person.match(/\(([^\)]+)\)/); if (url) { obj.url = url[1]; } return obj; } function normalizePerson(person) { return parsePerson(stringifyPerson(person)); } function extractDescription(readme) { if (typeof readme !== 'string' || readme === '') { return undefined; } // split into lines const lines = readme.trim().split('\n').map(line => line.trim()); // find the start of the first paragraph, ignore headings let start = 0; for (; start < lines.length; start++) { const line = lines[start]; if (line && line.match(/^(#|$)/)) { // line isn't empty and isn't a heading so this is the start of a paragraph start++; break; } } // skip newlines from the header to the first line while (start < lines.length && !lines[start]) { start++; } // continue to the first non empty line let end = start; while (end < lines.length && lines[end]) { end++; } return lines.slice(start, end).join(' '); } var LICENSES = { 'Apache-2.0': new RegExp('(licensed under the apache license version the license you may not use this file except in compliance with the license you may obtain a copy of the license at http www apache org licenses license unless required by applicable law or agreed to in writing software distributed under the license is distributed on an as is basis without warranties or conditions of any kind either express or implied see the license for the specific language governing permissions and limitations under the license$|apache license version january http www apache org licenses terms and conditions for use reproduction and distribution definitions license shall mean the terms and conditions for use reproduction and distribution as defined by sections through of this document licensor shall mean the copyright owner or entity authorized by the copyright owner that is granting the license legal entity shall mean the union of the acting entity and all other entities that control are controlled by or are under common control with that entity for the purposes of this definition control means i the power direct or indirect to cause the direction or management of such entity whether by contract or otherwise or ii ownership of fifty percent or more of the outstanding shares or iii beneficial ownership of such entity you or your shall mean an individual or legal entity exercising permissions granted by this license source form shall mean the preferred form for making modifications including but not limited to software source code documentation source and configuration files object form shall mean any form resulting from mechanical transformation or translation of a source form including but not limited to compiled object code generated documentation and conversions to other media types work shall mean the work of authorship whether in source or object form made available under the license as indicated by a copyright notice that is included in or attached to the work an example is provided in the appendix below derivative works shall mean any work whether in source or object form that is based on or derived from the work and for which the editorial revisions annotations elaborations or other modifications represent as a whole an original work of authorship for the purposes of this license derivative works shall not include works that remain separable from or merely link or bind by name to the interfaces of the work and derivative works thereof contribution shall mean any work of authorship including the original version of the work and any modifications or additions to that work or derivative works thereof that is intentionally submitted to licensor for inclusion in the work by the copyright owner or by an individual or legal entity authorized to submit on behalf of the copyright owner for the purposes of this definition submitted means any form of electronic verbal or written communication sent to the licensor or its representatives including but not limited to communication on electronic mailing lists source code control systems and issue tracking systems that are managed by or on behalf of the licensor for the purpose of discussing and improving the work but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as not a contribution contributor shall mean licensor and any individual or legal entity on behalf of whom a contribution has been received by licensor and subsequently incorporated within the work grant of copyright license subject to the terms and conditions of this license each contributor hereby grants to you a perpetual worldwide non exclusive no charge royalty free irrevocable copyright license to reproduce prepare derivative works of publicly display publicly perform sublicense and distribute the work and such derivative works in source or object form grant of patent license subject to the terms and conditions of this license each contributor hereby grants to you a perpetual worldwide non exclusive no charge royalty free irrevocable except as stated in this section patent license to make have made use offer to sell sell import and otherwise transfer the work where such license applies only to those patent claims licensable by such contributor that are necessarily infringed by their contribution s alone or by combination of their contribution s with the work to which such contribution s was submitted if you institute patent litigation against any entity including a cross claim or counterclaim in a lawsuit alleging that the work or a contribution incorporated within the work constitutes direct or contributory patent infringement then any patent licenses granted to you under this license for that work shall terminate as of the date such litigation is filed redistribution you may reproduce and distribute copies of the work or derivative works thereof in any medium with or without modifications and in source or object form provided that you meet the following conditions a you must give any other recipients of the work or derivative works a copy of this license and b you must cause any modified files to carry prominent notices stating that you changed the files and c you must retain in the source form of any derivative works that you distribute all copyright patent trademark and attribution notices from the source form of the work excluding those notices that do not pertain to any part of the derivative works and d if the work includes a notice text file as part of its distribution then any derivative works that you distribute must include a readable copy of the attribution notices contained within such notice file excluding those notices that do not pertain to any part of the derivative works in at least one of the following places within a notice text file distributed as part of the derivative works within the source form or documentation if provided along with the derivative works or within a display generated by the derivative works if and wherever such third party notices normally appear the contents of the notice file are for informational purposes only and do not modify the license you may add your own attribution notices within derivative works that you distribute alongside or as an addendum to the notice text from the work provided that such additional attribution notices cannot be construed as modifying the license you may add your own copyright statement to your modifications and may provide additional or different license terms and conditions for use reproduction or distribution of your modifications or for any such derivative works as a whole provided your use reproduction and distribution of the work otherwise complies with the conditions stated in this license submission of contributions unless you explicitly state otherwise any contribution intentionally submitted for inclusion in the work by you to the licensor shall be under the terms and conditions of this license without any additional terms or conditions notwithstanding the above nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with licensor regarding such contributions trademarks this license does not grant permission to use the trade names trademarks service marks or product names of the licensor except as required for reasonable and customary use in describing the origin of the work and reproducing the content of the notice file disclaimer of warranty unless required by applicable law or agreed to in writing licensor provides the work and each contributor provides its contributions on an as is basis without warranties or conditions of any kind either express or implied including without limitation any warranties or conditions of title non infringement merchantability or fitness for a particular purpose you are solely responsible for determining the appropriateness of using or redistributing the work and assume any risks associated with your exercise of permissions under this license limitation of liability in no event and under no legal theory whether in tort including negligence contract or otherwise unless required by applicable law such as deliberate and grossly negligent acts or agreed to in writing shall any contributor be liable to you for damages including any direct indirect special incidental or consequential damages of any character arising as a result of this license or out of the use or inability to use the work including but not limited to damages for loss of goodwill work stoppage computer failure or malfunction or any and all other commercial damages or losses even if such contributor has been advised of the possibility of such damages accepting warranty or additional liability while redistributing the work or derivative works thereof you may choose to offer and charge a fee for acceptance of support warranty indemnity or other liability obligations and or rights consistent with this license however in accepting such obligations you may act only on your own behalf and on your sole responsibility not on behalf of any other contributor and only if you agree to indemnify defend and hold each contributor harmless for any liability incurred by or claims asserted against such contributor by reason of your accepting any such warranty or additional liability end of terms and conditions$)', 'g'), 'BSD-2-Clause': new RegExp('(redistribution and use in source and binary forms with or without modification are permitted provided that the following conditions are met redistributions of source code must retain the above copyright notice this list of conditions and the following disclaimer redistributions in binary form must reproduce the above copyright notice this list of conditions and the following disclaimer in the documentation and or other materials provided with the distribution this(.*?| )is provided by the copyright holders and contributors as is and any express or implied warranties including but not limited to the implied warranties of merchantability and fitness for a particular purpose are disclaimed in no event shall(.*?| )be liable for any direct indirect incidental special exemplary or consequential damages including but not limited to procurement of substitute goods or services loss of use data or profits or business interruption however caused and on any theory of liability whether in contract strict liability or tort including negligence or otherwise arising in any way out of the use of this(.*?| )even if advised of the possibility of such damage$|redistribution and use in source and binary forms with or without modification are permitted provided that the following conditions are met redistributions of source code must retain the above copyright notice this list of conditions and the following disclaimer redistributions in binary form must reproduce the above copyright notice this list of conditions and the following disclaimer in the documentation and or other materials provided with the distribution this software is provided by the copyright holders and contributors as is and any express or implied warranties including but not limited to the implied warranties of merchantability and fitness for a particular purpose are disclaimed in no event shall(.*?| )be liable for any direct indirect incidental special exemplary or consequential damages including but not limited to procurement of substitute goods or services loss of use data or profits or business interruption however caused and on any theory of liability whether in contract strict liability or tort including negligence or otherwise arising in any way out of the use of this software even if advised of the possibility of such damage$)', 'g'), 'BSD-3-Clause': new RegExp('(redistribution and use in source and binary forms with or without modification are permitted provided that the following conditions are met redistributions of source code must retain the above copyright notice this list of conditions and the following disclaimer redistributions in binary form must reproduce the above copyright notice this list of conditions and the following disclaimer in the documentation and or other materials provided with the distribution neither the name of(.*?| )nor the names of the contributors may be used to endorse or promote products derived from this software without specific prior written permission this software is provided by the copyright holders and contributors as is and any express or implied warranties including but not limited to the implied warranties of merchantability and fitness for a particular purpose are disclaimed in no event shall(.*?| )be liable for any direct indirect incidental special exemplary or consequential damages including but not limited to procurement of substitute goods or services loss of use data or profits or business interruption however caused and on any theory of liability whether in contract strict liability or tort including negligence or otherwise arising in any way out of the use of this software even if advised of the possibility of such damage$|(redistribution and use in source and binary forms with or without modification are permitted provided that the following conditions are met redistributions of source code must retain the above copyright notice this list of conditions and the following disclaimer redistributions in binary form must reproduce the above copyright notice this list of conditions and the following disclaimer in the documentation and or other materials provided with the distribution the names of any contributors may not be used to endorse or promote products derived from this software without specific prior written permission this software is provided by the copyright holders and contributors as is and any express or implied warranties including but not limited to the implied warranties of merchantability and fitness for a particular purpose are disclaimed in no event shall the copyright holders and contributors be liable for any direct indirect incidental special exemplary or consequential damages including but not limited to procurement of substitute goods or services loss of use data or profits or business interruption however caused and on any theory of liability whether in contract strict liability or tort including negligence or otherwise arising in any way out of the use of this software even if advised of the possibility of such damage$|redistribution and use in source and binary forms with or without modification are permitted provided that the following conditions are met redistributions of source code must retain the above copyright notice this list of conditions and the following disclaimer redistributions in binary form must reproduce the above copyright notice this list of conditions and the following disclaimer in the documentation and or other materials provided with the distribution neither the name(.*?| )nor the names of(.*?| )contributors may be used to endorse or promote products derived from this software without specific prior written permission this software is provided by(.*?| )as is and any express or implied warranties including but not limited to the implied warranties of merchantability and fitness for a particular purpose are disclaimed in no event shall(.*?| )be liable for any direct indirect incidental special exemplary or consequential damages including but not limited to procurement of substitute goods or services loss of use data or profits or business interruption however caused and on any theory of liability whether in contract strict liability or tort including negligence or otherwise arising in any way out of the use of this software even if advised of the possibility of such damage$))', 'g'), MIT: new RegExp('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$', 'g'), Unlicense: new RegExp('this is free and unencumbered software released into the public domain anyone is free to copy modify publish use compile sell or distribute this software either in source code form or as a compiled binary for any purpose commercial or non commercial and by any means in jurisdictions that recognize copyright laws the author or authors of this software dedicate any and all copyright interest in the software to the public domain we make this dedication for the benefit of the public at large and to the detriment of our heirs and successors we intend this dedication to be an overt act of relinquishment in perpetuity of all present and future rights to this software under copyright law 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 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 for more information please refer to wildcard$', 'g') }; function clean(str) { return str.replace(/[^A-Za-z\s]/g, ' ').replace(/[\s]+/g, ' ').trim().toLowerCase(); } const REGEXES = { Apache: [/Apache License\b/], BSD: [/BSD\b/], ISC: [/The ISC License/, /ISC\b/], MIT: [/MIT\b/], Unlicense: [/http:\/\/unlicense.org\//], WTFPL: [/DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE/, /WTFPL\b/] }; function inferLicense(license) { // check if we have any explicit licenses const cleanLicense = clean(license); for (const licenseName in LICENSES) { const testLicense = LICENSES[licenseName]; if (cleanLicense.search(testLicense) >= 0) { return licenseName; } } // infer based on some keywords for (const licenseName in REGEXES) { for (const regex of REGEXES[licenseName]) { if (license.search(regex) >= 0) { return `${licenseName}*`; } } } return null; } const LICENSE_RENAMES = { 'MIT/X11': 'MIT', X11: 'MIT' }; var fix = (async function (info, moduleLoc, reporter, warn) { const files = await readdir(moduleLoc); // clean info.version if (typeof info.version === 'string') { info.version = semver.clean(info.version) || info.version; } // if name or version aren't set then set them to empty strings info.name = info.name || ''; info.version = info.version || ''; // if the man field is a string then coerce it to an array if (typeof info.man === 'string') { info.man = [info.man]; } // if the keywords field is a string then split it on any whitespace if (typeof info.keywords === 'string') { info.keywords = info.keywords.split(/\s+/g); } // if there's no contributors field but an authors field then expand it if (!info.contributors && files.indexOf('AUTHORS') >= 0) { const authorsFilepath = path.join(moduleLoc, 'AUTHORS'); const authorsFilestats = await stat(authorsFilepath); if (authorsFilestats.isFile()) { let authors = await readFile(authorsFilepath); info.contributors = authors.split(/\r?\n/g) // split on lines .map(line => line.replace(/^\s*#.*$/, '').trim()) // remove comments .filter(line => !!line); // remove empty lines; } } // expand people fields to objects if (typeof info.author === 'string' || typeof info.author === 'object') { info.author = normalizePerson(info.author); } if (Array.isArray(info.contributors)) { info.contributors = info.contributors.map(normalizePerson); } if (Array.isArray(info.maintainers)) { info.maintainers = info.maintainers.map(normalizePerson); } // if there's no readme field then load the README file from the cwd if (!info.readme) { const readmeCandidates = files.filter(filename => { const lower = filename.toLowerCase(); return lower === 'readme' || lower.indexOf('readme.') === 0; }).sort((filename1, filename2) => { // favor files with extensions return filename2.indexOf('.') - filename1.indexOf('.'); }); for (const readmeFilename of readmeCandidates) { const readmeFilepath = path.join(moduleLoc, readmeFilename); const readmeFileStats = await stat(readmeFilepath); if (readmeFileStats.isFile()) { info.readmeFilename = readmeFilename; info.readme = await readFile(readmeFilepath); break; } } } // if there's no description then take the first paragraph from the readme if (!info.description && info.readme) { const desc = extractDescription(info.readme); if (desc) { info.description = desc; } } // support array of engine keys if (Array.isArray(info.engines)) { const engines = {}; for (const str of info.engines) { if (typeof str === 'string') { const [name, ...patternParts] = str.trim().split(/ +/g); engines[name] = patternParts.join(' '); } } info.engines = engines; } // allow bugs to be specified as a string, expand it to an object with a single url prop if (typeof info.bugs === 'string') { info.bugs = { url: info.bugs }; } // normalize homepage url to http if (typeof info.homepage === 'string') { const parts = nodeUrl.parse(info.homepage); parts.protocol = parts.protocol || 'http:'; if (parts.pathname && !parts.hostname) { parts.hostname = parts.pathname; parts.pathname = ''; } info.homepage = nodeUrl.format(parts); } // if the `bin` field is as string then expand it to an object with a single property // based on the original `bin` field and `name field` // { name: "foo", bin: "cli.js" } -> { name: "foo", bin: { foo: "cli.js" } } if (typeof info.name === 'string' && typeof info.bin === 'string' && info.bin.length > 0) { // Remove scoped package name for consistency with NPM's bin field fixing behaviour const name = info.name.replace(/^@[^\/]+\//, ''); info.bin = { [name]: info.bin }; } // bundleDependencies is an alias for bundledDependencies if (info.bundledDependencies) { info.bundleDependencies = info.bundledDependencies; delete info.bundledDependencies; } let scripts; // dummy script object to shove file inferred scripts onto if (info.scripts && typeof info.scripts === 'object') { scripts = info.scripts; } else { scripts = {}; } // if there's a server.js file and no start script then set it to `node server.js` if (!scripts.start && files.indexOf('server.js') >= 0) { scripts.start = 'node server'; } // if there's a binding.gyp file and no install script then set it to `node-gyp rebuild` if (!scripts.install && files.indexOf('binding.gyp') >= 0) { scripts.install = 'node-gyp rebuild'; } // set scripts if we've polluted the empty object if (Object.keys(scripts).length) { info.scripts = scripts; } const dirs = info.directories; if (dirs && typeof dirs === 'object') { const binDir = dirs.bin; if (!info.bin && binDir && typeof binDir === 'string') { const bin = info.bin = {}; const fullBinDir = path.join(moduleLoc, binDir); if (await exists(fullBinDir)) { for (const scriptName of await readdir(fullBinDir)) { if (scriptName[0] === '.') { continue; } bin[scriptName] = path.join('.', binDir, scriptName); } } else { warn(reporter.lang('manifestDirectoryNotFound', binDir, info.name)); } } const manDir = dirs.man; if (!info.man && typeof manDir === 'string') { const man = info.man = []; const fullManDir = path.join(moduleLoc, manDir); if (await exists(fullManDir)) { for (const filename of await readdir(fullManDir)) { if (/^(.*?)\.[0-9]$/.test(filename)) { man.push(path.join('.', manDir, filename)); } } } else { warn(reporter.lang('manifestDirectoryNotFound', manDir, info.name)); } } } delete info.directories; // normalize licenses field const licenses = info.licenses; if (Array.isArray(licenses) && !info.license) { let licenseTypes = []; for (let license of licenses) { if (license && typeof license === 'object') { license = license.type; } if (typeof license === 'string') { licenseTypes.push(license); } } licenseTypes = licenseTypes.filter(isValidLicense); if (licenseTypes.length === 1) { info.license = licenseTypes[0]; } else if (licenseTypes.length) { info.license = `(${licenseTypes.join(' OR ')})`; } } const license = info.license; // normalize license if (license && typeof license === 'object') { info.license = license.type; } // get license file const licenseFile = files.find(filename => { const lower = filename.toLowerCase(); return lower === 'license' || lower.startsWith('license.') || lower === 'unlicense' || lower.startsWith('unlicense.'); }); if (licenseFile) { const licenseFilepath = path.join(moduleLoc, licenseFile); const licenseFileStats = await stat(licenseFilepath); if (licenseFileStats.isFile()) { const licenseContent = await readFile(licenseFilepath); const inferredLicense = inferLicense(licenseContent); info.licenseText = licenseContent; const license = info.license; if (typeof license === 'string') { if (inferredLicense && isValidLicense(inferredLicense) && !isValidLicense(license)) { // some packages don't specify their license version but we can infer it based on their license file const basicLicense = license.toLowerCase().replace(/(-like|\*)$/g, ''); const expandedLicense = inferredLicense.toLowerCase(); if (expandedLicense.startsWith(basicLicense)) { // TODO consider doing something to notify the user info.license = inferredLicense; } } } else if (inferredLicense) { // if there's no license then infer it based on the license file info.license = inferredLicense; } else { // valid expression to refer to a license in a file info.license = `SEE LICENSE IN ${licenseFile}`; } } } if (typeof info.license === 'string') { // sometimes licenses are known by different names, reduce them info.license = LICENSE_RENAMES[info.license] || info.license; } else if (typeof info.readme === 'string') { // the license might be at the bottom of the README const inferredLicense = inferLicense(info.readme); if (inferredLicense) { info.license = inferredLicense; } } // get notice file const noticeFile = files.find(filename => { const lower = filename.toLowerCase(); return lower === 'notice' || lower.startsWith('notice.'); }); if (noticeFile) { const noticeFilepath = path.join(moduleLoc, noticeFile); const noticeFileStats = await stat(noticeFilepath); if (noticeFileStats.isFile()) { info.noticeText = await readFile(noticeFilepath); } } for (const dependencyType of MANIFEST_FIELDS) { const dependencyList = info[dependencyType]; if (dependencyList && typeof dependencyList === 'object') { delete dependencyList['//']; for (const name in dependencyList) { dependencyList[name] = dependencyList[name] || ''; } } } }); var normalizeManifest = (async function (info, moduleLoc, config, isRoot) { // Append dependencies // if (depInfo) { // info.dependencies = depInfo.main; // info.devDependencies = depInfo.dev; // } // create human readable name const { name, version } = info; let human; if (typeof name === 'string') { human = name; } if (human && typeof version === 'string' && version) { human += `@${version}`; } if (isRoot && info._loc) { human = path.relative(config.cwd, info._loc); } function warn(msg) { if (human) { msg = `${human}: ${msg}`; } config.reporter.warn(msg); } await fix(info, moduleLoc, config.reporter, warn); try { validate(info, isRoot, config.reporter, warn); } catch (err) { if (human) { err.message = `${human}: ${err.message}`; } throw err; } return info; }); class BlockingQueue { constructor(alias, maxConcurrency = Infinity) { this.concurrencyQueue = []; this.maxConcurrency = maxConcurrency; this.runningCount = 0; this.warnedStuck = false; this.alias = alias; this.first = true; this.running = nullify() || {}; this.queue = nullify() || {}; this.stuckTick = this.stuckTick.bind(this); } stillActive() { if (this.stuckTimer) { clearTimeout(this.stuckTimer); } this.stuckTimer = setTimeout(this.stuckTick, 5000); // We need to check the existence of unref because of https://github.com/facebook/jest/issues/4559 // $FlowFixMe: Node's setInterval returns a Timeout, not a Number this.stuckTimer.unref && this.stuckTimer.unref(); } stuckTick() { if (this.runningCount === 1) { this.warnedStuck = true; console.log(`The ${JSON.stringify(this.alias)} blocking queue may be stuck. 5 seconds ` + `without any activity with 1 worker: ${Object.keys(this.running)[0]}`); } } push(key, factory) { if (this.first) { this.first = false; } else { this.stillActive(); } return new Promise((resolve, reject) => { // we're already running so push ourselves to the queue const queue = this.queue[key] = this.queue[key] || []; queue.push({ factory, resolve, reject }); if (!this.running[key]) { this.shift(key); } }); } shift(key) { if (this.running[key]) { delete this.running[key]; this.runningCount--; if (this.stuckTimer) { clearTimeout(this.stuckTimer); this.stuckTimer = null; } if (this.warnedStuck) { this.warnedStuck = false; console.log(`${JSON.stringify(this.alias)} blocking queue finally resolved. Nothing to worry about.`); } } const queue = this.queue[key]; if (!queue) { return; } const { resolve, reject, factory } = queue.shift(); if (!queue.length) { delete this.queue[key]; } const next = () => { this.shift(key); this.shiftConcurrencyQueue(); }; const run = () => { this.running[key] = true; this.runningCount++; factory().then(function (val) { resolve(val); next(); return null; }).catch(function (err) { reject(err); next(); }); }; this.maybePushConcurrencyQueue(run); } maybePushConcurrencyQueue(run) { if (this.runningCount < this.maxConcurrency) { run(); } else { this.concurrencyQueue.push(run); } } shiftConcurrencyQueue() { if (this.runningCount < this.maxConcurrency) { const fn = this.concurrencyQueue.shift(); if (fn) { fn(); } } } } class ProcessSpawnError extends types.MessageError { constructor(msg, code, process) { super(msg); this.code = code; this.process = process; } } class ProcessTermError extends types.MessageError {} /* global child_process$spawnOpts */ const queue = new BlockingQueue('child', CHILD_CONCURRENCY); // TODO: this uid check is kinda whack let uid = 0; const spawnedProcesses = {}; function forwardSignalToSpawnedProcesses(signal) { for (const key of Object.keys(spawnedProcesses)) { spawnedProcesses[key].kill(signal); } } function spawn(program, args, opts = {}, onData) { const key = opts.cwd || String(++uid); return queue.push(key, () => new Promise((resolve, reject) => { const proc = child_process.spawn(program, args, opts); spawnedProcesses[key] = proc; let processingDone = false; let processClosed = false; let err = null; let stdout = ''; proc.on('error', err => { if (err.code === 'ENOENT') { reject(new ProcessSpawnError(`Couldn't find the binary ${program}`, err.code, program)); } else { reject(err); } }); function updateStdout(chunk) { stdout += chunk; if (onData) { onData(chunk); } } function finish() { delete spawnedProcesses[key]; if (err) { reject(err); } else { resolve(stdout.trim()); } } if (typeof opts.process === 'function') { opts.process(proc, updateStdout, reject, function () { if (processClosed) { finish(); } else { processingDone = true; } }); } else { if (proc.stderr) { proc.stderr.on('data', updateStdout); } if (proc.stdout) { proc.stdout.on('data', updateStdout); } processingDone = true; } proc.on('close', (code, signal) => { if (signal || code >= 1) { err = new ProcessTermError(['Command failed.', signal ? `Exit signal: ${signal}` : `Exit code: ${code}`, `Command: ${program}`, `Arguments: ${args.join(' ')}`, `Directory: ${opts.cwd || process.cwd()}`, `Output:\n${stdout.trim()}`].join('\n')); err.EXIT_SIGNAL = signal; err.EXIT_CODE = code; } if (processingDone || err) { finish(); } else { processClosed = true; } }); })); } function fixCmdWinSlashes(cmd) { function findQuotes(quoteSymbol) { const quotes = []; const addQuote = (_, index) => { quotes.push({ from: index, to: index + _.length }); return _; }; const regEx = new RegExp(quoteSymbol + '.*' + quoteSymbol); cmd.replace(regEx, addQuote); return quotes; } const quotes = findQuotes('"').concat(findQuotes("'")); function isInsideQuotes(index) { return quotes.reduce((result, quote) => { return result || quote.from <= index && index <= quote.to; }, false); } const cmdPrePattern = '((?:^|&&|&|\\|\\||\\|)\\s*)'; const cmdPattern = '(".*?"|\'.*?\'|\\S*)'; const regExp = new RegExp(`${cmdPrePattern}${cmdPattern}`, 'g'); return cmd.replace(regExp, (whole, pre, cmd, index) => { if ((pre[0] === '&' || pre[0] === '|') && isInsideQuotes(index)) { return whole; } return pre + cmd.replace(/\//g, '\\'); }); } // // We treat these configs as internal, thus not expose them to process.env. // // This helps us avoid some gyp issues when building native modules. // // See https://github.com/yarnpkg/yarn/issues/2286. // const IGNORE_CONFIG_KEYS = ['lastUpdateCheck']; // async function getPnpParameters(config: Config): Promise> { // if (await fs.exists(`${config.lockfileFolder}/${constants.PNP_FILENAME}`)) { // return ['-r', `${config.lockfileFolder}/${constants.PNP_FILENAME}`]; // } else { // return []; // } // } // let wrappersFolder = null; // export async function getWrappersFolder(config: Config): Promise { // if (wrappersFolder) { // return wrappersFolder; // } // wrappersFolder = await fs.makeTempDir(); // await makePortableProxyScript(process.execPath, wrappersFolder, { // proxyBasename: 'node', // prependArguments: [...(await getPnpParameters(config))], // }); // await makePortableProxyScript(process.execPath, wrappersFolder, { // proxyBasename: 'pika', // prependArguments: [process.argv[1]], // }); // return wrappersFolder; // } // const INVALID_CHAR_REGEX = /\W/g; async function makeEnv() { // stage: string, // cwd: string, // config: Config, const env = _objectSpread2({ NODE: process.execPath, INIT_CWD: process.cwd() }, process.env); return env; } // // Merge in the `env` object specified in .pikarc // const customEnv = config.getOption('env'); // if (customEnv && typeof customEnv === 'object') { // Object.assign(env, customEnv); // } // env.npm_lifecycle_event = stage; // env.npm_node_execpath = env.NODE; // env.npm_execpath = env.npm_execpath || (process.mainModule && process.mainModule.filename); // // Set the env to production for npm compat if production mode. // // https://github.com/npm/npm/blob/30d75e738b9cb7a6a3f9b50e971adcbe63458ed3/lib/utils/lifecycle.js#L336 // if (config.production) { // env.NODE_ENV = 'production'; // } // // Note: npm_config_argv environment variable contains output of nopt - command-line // // parser used by npm. Since we use other parser, we just roughly emulate it's output. (See: #684) // env.npm_config_argv = JSON.stringify({ // remain: [], // cooked: config.commandName === 'run' ? [config.commandName, stage] : [config.commandName], // original: process.argv.slice(2), // }); // const manifest = await config.maybeReadManifest(cwd); // if (manifest) { // if (manifest.scripts && Object.prototype.hasOwnProperty.call(manifest.scripts, stage)) { // env.npm_lifecycle_script = manifest.scripts[stage]; // } // // add npm_package_* // const queue = [['', manifest]]; // while (queue.length) { // const [key, val] = queue.pop(); // if (typeof val === 'object') { // for (const subKey in val) { // const fullKey = [key, subKey].filter(Boolean).join('_'); // if (fullKey && fullKey[0] !== '_' && !IGNORE_MANIFEST_KEYS.has(fullKey)) { // queue.push([fullKey, val[subKey]]); // } // } // } else { // let cleanVal = String(val); // if (cleanVal.indexOf('\n') >= 0) { // cleanVal = JSON.stringify(cleanVal); // } // //replacing invalid chars with underscore // const cleanKey = key.replace(INVALID_CHAR_REGEX, '_'); // env[`npm_package_${cleanKey}`] = cleanVal; // } // } // } // // add npm_config_* and npm_package_config_* from pika config // const keys: Set = new Set([ // ...Object.keys(config.registries.pika.config), // ...Object.keys(config.registries.npm.config), // ]); // const cleaned = Array.from(keys) // .filter(key => !key.match(/:_/) && IGNORE_CONFIG_KEYS.indexOf(key) === -1) // .map(key => { // let val = config.getOption(key); // if (!val) { // val = ''; // } else if (typeof val === 'number') { // val = '' + val; // } else if (typeof val !== 'string') { // val = JSON.stringify(val); // } // if (val.indexOf('\n') >= 0) { // val = JSON.stringify(val); // } // return [key, val]; // }); // // add npm_config_* // for (const [key, val] of cleaned) { // const cleanKey = key.replace(/^_+/, ''); // const envKey = `npm_config_${cleanKey}`.replace(INVALID_CHAR_REGEX, '_'); // env[envKey] = val; // } // // add npm_package_config_* // if (manifest && manifest.name) { // const packageConfigPrefix = `${manifest.name}:`; // for (const [key, val] of cleaned) { // if (key.indexOf(packageConfigPrefix) !== 0) { // continue; // } // const cleanKey = key.replace(/^_+/, '').replace(packageConfigPrefix, ''); // const envKey = `npm_package_config_${cleanKey}`.replace(INVALID_CHAR_REGEX, '_'); // env[envKey] = val; // } // } // // split up the path // const envPath = env[constants.ENV_PATH_KEY]; // const pathParts = envPath ? envPath.split(path.delimiter) : []; // // Include the directory that contains node so that we can guarantee that the scripts // // will always run with the exact same Node release than the one use to run Pika // const execBin = path.dirname(process.execPath); // if (pathParts.indexOf(execBin) === -1) { // pathParts.unshift(execBin); // } // // Include node-gyp version that was bundled with the current Node.js version, // // if available. // pathParts.unshift(path.join(path.dirname(process.execPath), 'node_modules', 'npm', 'bin', 'node-gyp-bin')); // pathParts.unshift( // path.join(path.dirname(process.execPath), '..', 'lib', 'node_modules', 'npm', 'bin', 'node-gyp-bin'), // ); // // Include node-gyp version from homebrew managed npm, if available. // pathParts.unshift( // path.join(path.dirname(process.execPath), '..', 'libexec', 'lib', 'node_modules', 'npm', 'bin', 'node-gyp-bin'), // ); // // Add global bin folder if it is not present already, as some packages depend // // on a globally-installed version of node-gyp. // const globalBin = await getGlobalBinFolder(config, {}); // if (pathParts.indexOf(globalBin) === -1) { // pathParts.unshift(globalBin); // } // // Add node_modules .bin folders to the PATH // for (const registry of Object.keys(registries)) { // const binFolder = path.join(config.registries[registry].folder, '.bin'); // if (config.workspacesEnabled && config.workspaceRootFolder) { // pathParts.unshift(path.join(config.workspaceRootFolder, binFolder)); // } // pathParts.unshift(path.join(config.linkFolder, binFolder)); // pathParts.unshift(path.join(cwd, binFolder)); // if (config.modulesFolder) { // pathParts.unshift(path.join(config.modulesFolder, '.bin')); // } // } // if (await fs.exists(`${config.lockfileFolder}/${constants.PNP_FILENAME}`)) { // // TODO: Fix. import()? Do we even like that it does this? // throw new Error("pnp temporarily not supported"); // const pnpApi = {}; //dynamicRequire(`${config.lockfileFolder}/${constants.PNP_FILENAME}`); // const packageLocator = pnpApi.findPackageLocator(`${config.cwd}/`); // const packageInformation = pnpApi.getPackageInformation(packageLocator); // for (const [name, reference] of packageInformation.packageDependencies.entries()) { // const dependencyInformation = pnpApi.getPackageInformation({name, reference}); // if (!dependencyInformation || !dependencyInformation.packageLocation) { // continue; // } // pathParts.unshift(`${dependencyInformation.packageLocation}/.bin`); // } // } // pathParts.unshift(await getWrappersFolder(config)); // // join path back together // env[constants.ENV_PATH_KEY] = pathParts.join(path.delimiter); // return env; // } async function executeLifecycleScript({ // config, cwd, cmd, args, isInteractive, onProgress, customShell }) { const env = await makeEnv(); // await checkForGypIfNeeded(config, cmd, env[constants.ENV_PATH_KEY].split(path.delimiter)); if (process.platform === 'win32' && (!customShell || customShell === 'cmd')) { // handle windows run scripts starting with a relative path cmd = fixCmdWinSlashes(cmd); } // By default (non-interactive), pipe everything to the terminal and run child process detached // as long as it's not Windows (since windows does not have /dev/tty) let stdio = ['ignore', 'pipe', 'pipe']; let detached = process.platform !== 'win32'; if (isInteractive) { stdio = 'inherit'; detached = false; } const shell = customShell || true; const stdout = await spawn(cmd, args, { cwd, env, stdio, detached, shell }, onProgress); return { cwd, command: cmd, stdout }; } // // /** // // * Special case: Some packages depend on node-gyp, but don't specify this in // // * their package.json dependencies. They assume that node-gyp is available // // * globally. We need to detect this case and show an error message. // // */ // function checkForGypIfNeeded(config: Config, cmd: string, paths: Array): Promise { // if (cmd.substr(0, cmd.indexOf(' ')) !== 'node-gyp') { // return Promise.resolve(); // } // // Ensure this only runs once, rather than multiple times in parallel. // if (!checkGypPromise) { // checkGypPromise = _checkForGyp(config, paths); // } // return checkGypPromise; // } // async function _checkForGyp(config: Config, paths: Array): Promise { // const {reporter} = config; // // Check every directory in the PATH // const allChecks = await Promise.all(paths.map(dir => fs.exists(path.join(dir, 'node-gyp')))); // if (allChecks.some(Boolean)) { // // node-gyp is available somewhere // return; // } // reporter.info(reporter.lang('packageRequiresNodeGyp')); // } // export async function execFromDistributions(config: Config, cwd: string, dist: string, step: string): Promise { // const pkg = await config.maybeReadManifest(cwd); // if (!pkg || !pkg.distributions || !pkg.distributions[dist] || typeof pkg.distributions[dist][step] !== 'string') { // return false; // } // const cmd: ?string = pkg.distributions[dist][step]; // await execCommand({stage: 'build', config, cmd, cwd, isInteractive: true}); // return true; // } // export async function execFromManifest(config: Config, commandName: string, cwd: string): Promise { // const pkg = await config.maybeReadManifest(cwd); // if (!pkg || !pkg.scripts) { // return; // } // const cmd: ?string = pkg.scripts[commandName]; // if (cmd) { // await execCommand({stage: commandName, config, cmd, cwd, isInteractive: true}); // } // } // export async function execCommand({ // stage, // config, // cmd, // cwd, // isInteractive, // customShell, // }: { // stage: string; // config: Config; // cmd: string; // cwd: string; // isInteractive: boolean; // customShell?: string; // }): Promise { // const {reporter} = config; // try { // reporter.command(cmd); // await executeLifecycleScript({config, cwd, cmd, isInteractive, customShell}); // return Promise.resolve(); // } catch (err) { // if (err instanceof ProcessTermError) { // throw new MessageError( // err.EXIT_SIGNAL // ? reporter.lang('commandFailedWithSignal', err.EXIT_SIGNAL) // : reporter.lang('commandFailedWithCode', err.EXIT_CODE), // ); // } else { // throw err; // } // } // } class Config { constructor(reporter, cwd, flags) { this.reporter = reporter; // Ensure the cwd is always an absolute path. this.cwd = path.resolve(cwd || process.cwd()); this.flags = flags; } async loadPackageManifest() { const loc = path.join(this.cwd, NODE_PACKAGE_JSON); if (await exists(loc)) { const info = await this.readJson(loc, readJsonAndFile); this._manifest = _objectSpread2({}, info.object); this.manifest = await normalizeManifest(info.object, this.cwd, this, true); return this.manifest; } else { return null; } } readJson(loc, factory = readJson) { try { return factory(loc); } catch (err) { if (err instanceof SyntaxError) { throw new types.MessageError(this.reporter.lang('jsonError', loc, err.message)); } else { throw err; } } } async getDistributions() { const raw = this.manifest[`@pika/pack`] || {}; const override = this.flags.pipeline && JSON.parse(this.flags.pipeline); const cwd = this.cwd; function cleanRawDistObject(rawVal) { if (Array.isArray(rawVal)) { let importStr = rawVal[0].startsWith('./') || rawVal[0].startsWith('../') ? path.join(cwd, rawVal[0]) : rawVal[0]; return [_objectSpread2({}, importFrom(cwd, importStr), { name: rawVal[0] }), rawVal[1] || {}]; } if (typeof rawVal === 'string') { return [{ build: ({ cwd }) => { return executeLifecycleScript({ // config: this, args: [], cwd, cmd: rawVal, isInteractive: false }); } }, {}]; } if (!rawVal) { throw new Error('Cannot be false'); } return false; } const pipeline = override || raw.pipeline || []; return pipeline.map(cleanRawDistObject).filter(Boolean); } } function forwardSignalAndExit(signal) { forwardSignalToSpawnedProcesses(signal); // We want to exit immediately here since `SIGTERM` means that // If we lose stdout messages due to abrupt exit, shoot the messenger? process.exit(1); // eslint-disable-line no-process-exit } function handleSignals() { process.on('SIGTERM', () => { forwardSignalAndExit('SIGTERM'); }); } const FALSY_STRINGS = new Set(['0', 'false']); function boolify(val) { return !FALSY_STRINGS.has(val.toString().toLowerCase()); } function boolifyWithDefault(val, defaultResult) { return val === '' || val === null || val === undefined ? defaultResult : boolify(val); } const currentFilename = uri2path((typeof document === 'undefined' ? new (require('u' + 'rl').URL)('file:' + __filename).href : (document.currentScript && document.currentScript.src || new URL('index.js', document.baseURI).href))); function getVersion() { const packageJsonContent = fs.readFileSync(path.resolve(currentFilename, '../../package.json'), { encoding: 'utf-8' }); const { version } = nullify(JSON.parse(stripBOM(packageJsonContent))); return version; } function printHelp() { console.log(` ${chalk.bold(`@pika/pack`)} - Build npm packages without the mess. ${chalk.bold('Options:')} --cwd Set the current working directory. --out Set the output directory. Defaults to "pkg/". --pipeline Set a build pipeline via JSON string. --force Continue with the build when a build plugin fails or throws an exception. --json Log output as JSON. --verbose Log additional debugging information. --silent Log almost nothing. --help Print help. --version, -v Print version. `.trim()); } async function cli(args) { const version = getVersion(); loudRejection(); handleSignals(); // Handle special flags if (args.find(arg => arg === '--version' || arg === '-v')) { console.log(version.trim()); process.exitCode = 0; return; } if (args.find(arg => arg === '--help')) { printHelp(); process.exitCode = 0; return; } // Handle the legacy CLI interface if (args[2] === 'publish') { console.log(`The publish flow has moved to the @pika/cli package (included with this package). Update your publish script to: ${chalk.bold('pika publish [flags]')} `); process.exitCode = 1; return; } if (args[2] === 'build') { console.log(chalk.yellow(`Note: This CLI was recently deprecated. Update your build script to: ${chalk.bold('pika build [flags]')}`)); args.splice(2, 1); } const flags = yargs(args); const cwd = flags.cwd || process.cwd(); const Reporter = flags.json ? JSONReporter : ConsoleReporter; const reporter = new Reporter({ emoji: true, verbose: flags.verbose, isSilent: boolifyWithDefault(process.env.PIKA_SILENT, false) || flags.silent }); const exit = (exitCode = 0) => { process.exitCode = exitCode; reporter.close(); }; const command = buildCommand; reporter.initPeakMemoryCounter(); const outputWrapperEnabled = boolifyWithDefault(process.env.PIKA_WRAP_OUTPUT, true); const shouldWrapOutput = outputWrapperEnabled && !flags.json && command.hasWrapper(); if (shouldWrapOutput) { reporter.header({ name: '@pika/pack', version }); } const run = () => { invariant(command, 'missing command'); return command.run(config, reporter, flags, args).then(exitCode => { if (shouldWrapOutput) { reporter.footer(false); } return exitCode; }); }; function onUnexpectedError(err) { function indent(str) { return '\n ' + str.trim().split('\n').join('\n '); } const log = []; log.push(`Arguments: ${indent(process.argv.join(' '))}`); log.push(`PATH: ${indent(process.env.PATH || 'undefined')}`); log.push(`Pika version: ${indent(version)}`); log.push(`Node version: ${indent(process.versions.node)}`); log.push(`Platform: ${indent(process.platform + ' ' + process.arch)}`); log.push(`Trace: ${indent(err.stack)}`); reporter.error(reporter.lang('unexpectedError', err.message)); } const config = new Config(reporter, cwd, flags); await config.loadPackageManifest(); try { // option "no-progress" stored in pika config const noProgressConfig = false; //config.registries.pika.getOption('no-progress'); if (noProgressConfig) { reporter.disableProgress(); } // verbose logs outputs process.uptime() with this line we can sync uptime to absolute time on the computer reporter.verbose(`current time: ${new Date().toISOString()}`); return run().then(exit); } catch (err) { reporter.verbose(err.stack); if (err instanceof types.MessageError) { reporter.error(err.message); } else { onUnexpectedError(err); } return exit(1); } } exports.cli = cli; //# sourceMappingURL=index.js.map ================================================ FILE: checkpoint/dist-src/commands/build.js ================================================ import chalk from 'chalk'; import * as path from 'path'; import { DEFAULT_INDENT } from '../constants.js'; import * as fs from '../util/fs.js'; import { generatePrettyManifest, generatePublishManifest } from '../util/normalize-manifest/for-publish.js'; export function hasWrapper() { return true; } export const examples = null; export class Build { constructor(flags, config, reporter) { this.flags = flags; this.config = config; this.reporter = reporter; this.totalNum = 0; this.out = path.resolve(config.cwd, flags.out || 'pkg/'); if (this.out === this.config.cwd) { throw new Error('On publish, you cannot write to cwd because a package.json is created'); } } async cleanup() { const { out } = this; await fs.unlink(path.join(out, '*')); } async init(isFull) { const { config, out, reporter, flags } = this; const { cwd } = config; const outPretty = path.relative(cwd, out) + path.sep; const manifest = await config.manifest; const { sourcemap } = manifest['@pika/pack'] || { sourcemap: true }; const distRunners = await config.getDistributions(); const builderConfig = { out, cwd, reporter: { info: msg => reporter.log(chalk.dim(` » ${msg}`)), warning: msg => reporter.log(chalk.yellow(` » ${msg}`)), success: msg => reporter.log(chalk.green(` » ${msg}`)), created: (filename, entrypoint) => reporter.log(` 📝 ${chalk.green(path.relative(cwd, filename))} ${entrypoint ? chalk.dim(`[${entrypoint}]`) : ''}`), }, isFull, manifest, src: { loc: path.join(out, 'dist-src'), entrypoint: path.join(out, 'dist-src', 'index.js'), // TODO: Deprecated, remove options: {}, // TODO: Deprecated, remove files: await (async () => { const ignoreSet = new Set([]); ignoreSet.add('**/*/README.md'); const files = await fs.glob(`src/**/*`, { cwd, nodir: true, absolute: true, ignore: Array.from(ignoreSet).map(g => path.join('src', g)), }); return files.filter(fileAbs => !fileAbs.endsWith('.d.ts')); })(), }, }; const steps = []; steps.push(async (curr, total) => { this.reporter.step(curr, total, 'Validating source'); for (const [runner, options] of distRunners) { if (runner.validate) { const result = await runner.validate({ ...builderConfig, options: { sourcemap, ...options }, }); if (result instanceof Error) { throw result; } } } }); steps.push(async (curr, total) => { this.reporter.step(curr, total, `Preparing pipeline`); await this.cleanup(); reporter.log(` ❇️ ${chalk.green(outPretty)}`); for (const [runner, options] of distRunners) { await (runner.beforeBuild && runner.beforeBuild({ ...builderConfig, options: { sourcemap, ...options }, })); } }); if (distRunners.length === 0) { steps.push(async (curr, total) => { this.reporter.step(curr, total, `Pipeline is empty! See ${chalk.underline('https://github.com/pikapkg/pack')} for help getting started`); }); } for (const [runner, options] of distRunners) { steps.push(async (curr, total) => { this.reporter.step(curr, total, `Running ${chalk.bold(runner.name)}`); // return Promise.resolve( try { await (runner.beforeJob && runner.beforeJob({ ...builderConfig, options: { sourcemap, ...options }, })); await (runner.build && runner.build({ ...builderConfig, options: { sourcemap, ...options }, })); await (runner.afterJob && runner.afterJob({ ...builderConfig, options: { sourcemap, ...options }, })); } catch (err) { if (flags.force) { console.log(' ❗️ ', chalk.red(err.message), chalk.dim('--force, continuing...')); } else { throw err; } } // ).catch(err => { // log(chalk.red(err.message)); // reporter.log( // reporter.lang("distFailed", runner.name, err.code, err.message), // { force: true } // ); // if (err.forceExit === true) { // reporter.log(reporter.lang("distExiting")); // throw err; // return; // } // reporter.log(reporter.lang("distContinuing")); // }); }); } steps.push(async (curr, total) => { this.reporter.step(curr, total, `Finalizing package`); for (const [runner, options] of distRunners) { await (runner.afterBuild && runner.afterBuild({ ...builderConfig, options: { sourcemap, ...options }, })); } if (await fs.exists(path.join(cwd, 'CHANGELOG'))) { fs.copyFile(path.join(cwd, 'CHANGELOG'), path.join(out, 'CHANGELOG')); reporter.log(chalk.dim(` » copying CHANGELOG...`)); } else if (await fs.exists(path.join(cwd, 'CHANGELOG.md'))) { fs.copyFile(path.join(cwd, 'CHANGELOG.md'), path.join(out, 'CHANGELOG.md')); reporter.log(chalk.dim(` » copying CHANGELOG.md...`)); } if (await fs.exists(path.join(cwd, 'LICENSE'))) { fs.copyFile(path.join(cwd, 'LICENSE'), path.join(out, 'LICENSE')); reporter.log(chalk.dim(` » copying LICENSE...`)); } else if (await fs.exists(path.join(cwd, 'LICENSE.md'))) { fs.copyFile(path.join(cwd, 'LICENSE.md'), path.join(out, 'LICENSE.md')); reporter.log(chalk.dim(` » copying LICENSE.md...`)); } if (await fs.exists(path.join(cwd, 'README'))) { fs.copyFile(path.join(cwd, 'README'), path.join(out, 'README')); reporter.log(chalk.dim(` » copying README...`)); } else if (await fs.exists(path.join(cwd, 'README.md'))) { fs.copyFile(path.join(cwd, 'README.md'), path.join(out, 'README.md')); reporter.log(chalk.dim(` » copying README.md...`)); } const publishManifest = await generatePublishManifest(config._manifest, config, distRunners); if (out === cwd) { reporter.log(`NEW MANIFEST:\n\n`); reporter.log(generatePrettyManifest(publishManifest)); reporter.log(`\n\n`); } else { await fs.writeFilePreservingEol(path.join(out, 'package.json'), JSON.stringify(publishManifest, null, DEFAULT_INDENT) + '\n'); reporter.log(` 📝 ` + chalk.green(outPretty + 'package.json')); } reporter.log(` 📦 ` + chalk.green(outPretty)); }); let currentStep = 0; for (const step of steps) { await step(++currentStep, steps.length); } } } export async function run(config, reporter, flags, args) { const isProduction = flags.publish; const builder = new Build(flags, config, reporter); await builder.init(isProduction); } ================================================ FILE: checkpoint/dist-src/config.js ================================================ import * as path from 'path'; import * as constants from './constants.js'; import { MessageError } from '@pika/types'; import * as fs from './util/fs.js'; import normalizeManifest from './util/normalize-manifest/index.js'; import executeLifecycleScript from './util/execute-lifecycle-script.js'; import importFrom from 'import-from'; ; ; export default class Config { constructor(reporter, cwd, flags) { this.reporter = reporter; // Ensure the cwd is always an absolute path. this.cwd = path.resolve(cwd || process.cwd()); this.flags = flags; } async loadPackageManifest() { const loc = path.join(this.cwd, constants.NODE_PACKAGE_JSON); if (await fs.exists(loc)) { const info = await this.readJson(loc, fs.readJsonAndFile); this._manifest = { ...info.object }; this.manifest = await normalizeManifest(info.object, this.cwd, this, true); return this.manifest; } else { return null; } } readJson(loc, factory = fs.readJson) { try { return factory(loc); } catch (err) { if (err instanceof SyntaxError) { throw new MessageError(this.reporter.lang('jsonError', loc, err.message)); } else { throw err; } } } async getDistributions() { const raw = this.manifest[`@pika/pack`] || {}; const override = this.flags.pipeline && JSON.parse(this.flags.pipeline); const cwd = this.cwd; function cleanRawDistObject(rawVal) { if (Array.isArray(rawVal)) { let importStr = (rawVal[0].startsWith('./') || rawVal[0].startsWith('../')) ? path.join(cwd, rawVal[0]) : rawVal[0]; return [{ ...importFrom(cwd, importStr), name: rawVal[0] }, rawVal[1] || {}]; } if (typeof rawVal === 'string') { return [{ build: ({ cwd }) => { return executeLifecycleScript({ // config: this, args: [], cwd, cmd: rawVal, isInteractive: false }); } }, {}]; } if (!rawVal) { throw new Error('Cannot be false'); } return false; } const pipeline = override || raw.pipeline || []; return pipeline.map(cleanRawDistObject).filter(Boolean); } } ================================================ FILE: checkpoint/dist-src/constants.js ================================================ // import os from 'os'; // import * as path from 'path'; // import userHome from './util/user-home-dir.js'; // import {getCacheDir, getConfigDir, getDataDir} from './util/user-dirs.js'; export const DEPENDENCY_TYPES = ['devDependencies', 'dependencies', 'legacyDependencies']; // export const OWNED_DEPENDENCY_TYPES = ['devDependencies', 'dependencies', 'legacyDependencies']; export const RESOLUTIONS = 'resolutions'; export const MANIFEST_FIELDS = [RESOLUTIONS, ...DEPENDENCY_TYPES]; export const SUPPORTED_NODE_VERSIONS = '>=8.5.0'; // export const PIKA_REGISTRY = 'https://registry.npmjs.org'; // export const NPM_REGISTRY_RE = /https?:\/\/registry\.npmjs\.org/g; // export const PIKA_DOCS = 'https://yarnpkg.com/en/docs/cli/'; // export const PIKA_INSTALLER_SH = 'https://yarnpkg.com/install.sh'; // export const PIKA_INSTALLER_MSI = 'https://yarnpkg.com/latest.msi'; // export const SELF_UPDATE_VERSION_URL = 'https://www.pikapkg.com/downloads/latest-version'; // // cache version, bump whenever we make backwards incompatible changes // export const CACHE_VERSION = 3; // // lockfile version, bump whenever we make backwards incompatible changes // export const LOCKFILE_VERSION = 1; // // max amount of network requests to perform concurrently // export const NETWORK_CONCURRENCY = 8; // // HTTP timeout used when downloading packages // export const NETWORK_TIMEOUT = 30 * 1000; // in milliseconds // // max amount of child processes to execute concurrently export const CHILD_CONCURRENCY = 5; // export const REQUIRED_PACKAGE_KEYS = ['name', 'version', '_uid']; // function getPreferredCacheDirectories(): Array { // const preferredCacheDirectories = [getCacheDir()]; // if (process.getuid) { // // $FlowFixMe: process.getuid exists, dammit // preferredCacheDirectories.push(path.join(os.tmpdir(), `.pika-cache-${process.getuid()}`)); // } // preferredCacheDirectories.push(path.join(os.tmpdir(), `.pika-cache`)); // return preferredCacheDirectories; // } // export const PREFERRED_MODULE_CACHE_DIRECTORIES = getPreferredCacheDirectories(); // export const CONFIG_DIRECTORY = getConfigDir(); // export const DATA_DIRECTORY = getDataDir(); // export const LINK_REGISTRY_DIRECTORY = path.join(DATA_DIRECTORY, 'link'); // export const GLOBAL_MODULE_DIRECTORY = path.join(DATA_DIRECTORY, 'global'); // export const NODE_BIN_PATH = process.execPath; export const NODE_MODULES_FOLDER = 'node_modules'; export const NODE_PACKAGE_JSON = 'package.json'; // export const PNP_FILENAME = '.pnp'; // export const POSIX_GLOBAL_PREFIX = `${process.env.DESTDIR || ''}/usr/local`; // export const FALLBACK_GLOBAL_PREFIX = path.join(userHome, '.pika'); // export const META_FOLDER = '.pika-meta'; // export const INTEGRITY_FILENAME = '.pika-integrity'; // export const LOCKFILE_FILENAME = 'pika.lock'; // export const LEGACY_LOCKFILE_FILENAME = 'yarn.lock'; // export const METADATA_FILENAME = '.pika-metadata.json'; // export const TARBALL_FILENAME = '.pika-tarball.tgz'; // export const CLEAN_FILENAME = '.pikaclean'; // export const NPM_LOCK_FILENAME = 'package-lock.json'; // export const NPM_SHRINKWRAP_FILENAME = 'npm-shrinkwrap.json'; export const DEFAULT_INDENT = ' '; // export const SINGLE_INSTANCE_PORT = 31997; // export const SINGLE_INSTANCE_FILENAME = '.pika-single-instance'; export const ENV_PATH_KEY = getPathKey(process.platform, process.env); export function getPathKey(platform, env) { let pathKey = 'PATH'; // windows calls its path "Path" usually, but this is not guaranteed. if (platform === 'win32') { pathKey = 'Path'; for (const key in env) { if (key.toLowerCase() === 'path') { pathKey = key; } } } return pathKey; } // export const VERSION_COLOR_SCHEME: {[key: string]: VersionColor} = { // major: 'red', // premajor: 'red', // minor: 'yellow', // preminor: 'yellow', // patch: 'green', // prepatch: 'green', // prerelease: 'red', // unchanged: 'white', // unknown: 'red', // }; // export type VersionColor = 'red' | 'yellow' | 'green' | 'white'; // export type RequestHint = 'dev' | 'optional' | 'resolution' | 'workspaces'; ================================================ FILE: checkpoint/dist-src/errors.js ================================================ import { MessageError } from '@pika/types'; export class ProcessSpawnError extends MessageError { constructor(msg, code, process) { super(msg); this.code = code; this.process = process; } } export class SecurityError extends MessageError { } export class ProcessTermError extends MessageError { } export class ResponseError extends Error { constructor(msg, responseCode) { super(msg); this.responseCode = responseCode; } } export class OneTimePasswordError extends Error { } ================================================ FILE: checkpoint/dist-src/index.js ================================================ import * as path from 'path'; import chalk from 'chalk'; import * as fs from 'fs'; import invariant from 'invariant'; import loudRejection from 'loud-rejection'; import { ConsoleReporter, JSONReporter } from './reporters/index.js'; import * as buildCommand from './commands/build.js'; import { MessageError } from '@pika/types'; import Config from './config.js'; import handleSignals from './util/signal-handler.js'; import { boolifyWithDefault } from './util/conversion.js'; import map from './util/map.js'; import stripBOM from 'strip-bom'; import uri2path from 'file-uri-to-path'; import yargs from 'yargs-parser'; // @ts-ignore const currentFilename = uri2path(import.meta.url); function getVersion() { const packageJsonContent = fs.readFileSync(path.resolve(currentFilename, '../../package.json'), { encoding: 'utf-8' }); const { version } = map(JSON.parse(stripBOM(packageJsonContent))); return version; } function printHelp() { console.log(` ${chalk.bold(`@pika/pack`)} - Build npm packages without the mess. ${chalk.bold('Options:')} --cwd Set the current working directory. --out Set the output directory. Defaults to "pkg/". --pipeline Set a build pipeline via JSON string. --force Continue with the build when a build plugin fails or throws an exception. --json Log output as JSON. --verbose Log additional debugging information. --silent Log almost nothing. --help Print help. --version, -v Print version. `.trim()); } export async function cli(args) { const version = getVersion(); loudRejection(); handleSignals(); // Handle special flags if (args.find(arg => arg === '--version' || arg === '-v')) { console.log(version.trim()); process.exitCode = 0; return; } if (args.find(arg => arg === '--help')) { printHelp(); process.exitCode = 0; return; } // Handle the legacy CLI interface if (args[2] === 'publish') { console.log(`The publish flow has moved to the @pika/cli package (included with this package). Update your publish script to: ${chalk.bold('pika publish [flags]')} `); process.exitCode = 1; return; } if (args[2] === 'build') { console.log(chalk.yellow(`Note: This CLI was recently deprecated. Update your build script to: ${chalk.bold('pika build [flags]')}`)); args.splice(2, 1); } const flags = yargs(args); const cwd = flags.cwd || process.cwd(); const Reporter = flags.json ? JSONReporter : ConsoleReporter; const reporter = new Reporter({ emoji: true, verbose: flags.verbose, isSilent: boolifyWithDefault(process.env.PIKA_SILENT, false) || flags.silent, }); const exit = (exitCode = 0) => { process.exitCode = exitCode; reporter.close(); }; const command = buildCommand; reporter.initPeakMemoryCounter(); const outputWrapperEnabled = boolifyWithDefault(process.env.PIKA_WRAP_OUTPUT, true); const shouldWrapOutput = outputWrapperEnabled && !flags.json && command.hasWrapper(); if (shouldWrapOutput) { reporter.header({ name: '@pika/pack', version }); } const run = () => { invariant(command, 'missing command'); return command.run(config, reporter, flags, args).then(exitCode => { if (shouldWrapOutput) { reporter.footer(false); } return exitCode; }); }; function onUnexpectedError(err) { function indent(str) { return '\n ' + str.trim().split('\n').join('\n '); } const log = []; log.push(`Arguments: ${indent(process.argv.join(' '))}`); log.push(`PATH: ${indent(process.env.PATH || 'undefined')}`); log.push(`Pika version: ${indent(version)}`); log.push(`Node version: ${indent(process.versions.node)}`); log.push(`Platform: ${indent(process.platform + ' ' + process.arch)}`); log.push(`Trace: ${indent(err.stack)}`); reporter.error(reporter.lang('unexpectedError', err.message)); } const config = new Config(reporter, cwd, flags); await config.loadPackageManifest(); try { // option "no-progress" stored in pika config const noProgressConfig = false; //config.registries.pika.getOption('no-progress'); if (noProgressConfig) { reporter.disableProgress(); } // verbose logs outputs process.uptime() with this line we can sync uptime to absolute time on the computer reporter.verbose(`current time: ${new Date().toISOString()}`); return run().then(exit); } catch (err) { reporter.verbose(err.stack); if (err instanceof MessageError) { reporter.error(err.message); } else { onUnexpectedError(err); } return exit(1); } } ================================================ FILE: checkpoint/dist-src/reporters/base-reporter.js ================================================ import { defaultFormatter } from './format.js'; import * as languages from './lang/index.js'; import * as isCI from 'is-ci'; import * as os from 'os'; import * as util from 'util'; import { EventEmitter } from 'events'; export function stringifyLangArgs(args) { return args.map(function (val) { if (val != null && val.inspect) { return val.inspect(); } else { try { const str = JSON.stringify(val) || val + ''; // should match all literal line breaks and // "u001b" that follow an odd number of backslashes and convert them to ESC // we do this because the JSON.stringify process has escaped these characters return str .replace(/((?:^|[^\\])(?:\\{2})*)\\u001[bB]/g, '$1\u001b') .replace(/[\\]r[\\]n|([\\])?[\\]n/g, (match, precededBacklash) => { // precededBacklash not null when "\n" is preceded by a backlash ("\\n") // match will be "\\n" and we don't replace it with os.EOL return precededBacklash ? match : os.EOL; }); } catch (e) { return util.inspect(val); } } }); } export default class BaseReporter { constructor(opts = {}) { const lang = 'en'; this.language = lang; this.stdout = opts.stdout || process.stdout; this.stderr = opts.stderr || process.stderr; this.stdin = opts.stdin || this._getStandardInput(); this.emoji = !!opts.emoji; this.nonInteractive = !!opts.nonInteractive; this.noProgress = !!opts.noProgress || isCI; this.isVerbose = !!opts.verbose; // @ts-ignore this.isTTY = this.stdout.isTTY; this.peakMemory = 0; this.startTime = Date.now(); this.format = defaultFormatter; } lang(key, ...args) { const msg = languages[this.language][key] || languages.en[key]; if (!msg) { throw new ReferenceError(`No message defined for language key ${key}`); } // stringify args const stringifiedArgs = stringifyLangArgs(args); // replace $0 placeholders with args return msg.replace(/\$(\d+)/g, (str, i) => { return stringifiedArgs[i]; }); } /** * `stringifyLangArgs` run `JSON.stringify` on strings too causing * them to appear quoted. This marks them as "raw" and prevents * the quoting and escaping */ rawText(str) { return { inspect() { return str; }, }; } verbose(msg) { if (this.isVerbose) { this._verbose(msg); } } verboseInspect(val) { if (this.isVerbose) { this._verboseInspect(val); } } _verbose(msg) { } _verboseInspect(val) { } _getStandardInput() { let standardInput; // Accessing stdin in a win32 headless process (e.g., Visual Studio) may throw an exception. try { standardInput = process.stdin; } catch (e) { console.warn(e.message); delete process.stdin; // @ts-ignore process.stdin = new EventEmitter(); standardInput = process.stdin; } return standardInput; } initPeakMemoryCounter() { this.checkPeakMemory(); this.peakMemoryInterval = setInterval(() => { this.checkPeakMemory(); }, 1000); // $FlowFixMe: Node's setInterval returns a Timeout, not a Number this.peakMemoryInterval.unref(); } checkPeakMemory() { const { heapTotal } = process.memoryUsage(); if (heapTotal > this.peakMemory) { this.peakMemory = heapTotal; } } close() { if (this.peakMemoryInterval) { clearInterval(this.peakMemoryInterval); this.peakMemoryInterval = null; } } getTotalTime() { return Date.now() - this.startTime; } // TODO list(key, items, hints) { } // Outputs basic tree structure to console tree(key, obj, { force = false } = {}) { } // called whenever we begin a step in the CLI. step(current, total, message, emoji) { } // a error message has been triggered. this however does not always meant an abrupt // program end. error(message) { } // an info message has been triggered. this provides things like stats and diagnostics. info(message) { } // a warning message has been triggered. warn(message) { } // a success message has been triggered. success(message) { } // a simple log message // TODO: rethink the {force} parameter. In the meantime, please don't use it (cf comments in #4143). log(message, { force = false } = {}) { } // a shell command has been executed command(command) { } // inspect and pretty-print any value inspect(value) { } // the screen shown at the very start of the CLI header(pkg) { } // the screen shown at the very end of the CLI footer(showPeakMemory) { } // a table structure table(head, body) { } // render an activity spinner and return a function that will trigger an update activity() { return { tick(name) { }, end() { }, }; } // activitySet(total, workers) { return { spinners: Array(workers).fill({ clear() { }, setPrefix() { }, tick() { }, end() { }, }), end() { }, }; } // render a progress bar and return a function which when called will trigger an update progress(total) { return function () { }; } // utility function to disable progress bar disableProgress() { this.noProgress = true; } } ================================================ FILE: checkpoint/dist-src/reporters/console/console-reporter.js ================================================ import chalk from 'chalk'; import * as readline from 'readline'; import stripAnsi from 'strip-ansi'; import { inspect } from 'util'; import { removeSuffix } from '../../util/misc.js'; import BaseReporter from '../base-reporter.js'; import { getFormattedOutput, recurseTree, sortTrees } from './helpers/tree-helper.js'; import Progress from './progress-bar.js'; import Spinner from './spinner-progress.js'; import { clearLine } from './util.js'; const AUDIT_COL_WIDTHS = [15, 62]; const auditSeverityColors = { info: chalk.bold, low: chalk.bold, moderate: chalk.yellow, high: chalk.red, critical: chalk.bgRed, }; // fixes bold on windows if (process.platform === 'win32' && !(process.env.TERM && /^xterm/i.test(process.env.TERM))) { // @ts-ignore chalk.bold._styles[0].close += '\u001b[m'; } export default class ConsoleReporter extends BaseReporter { constructor(opts) { super(opts); this._lastCategorySize = 0; this._spinners = new Set(); this.format = chalk; this.format.stripColor = stripAnsi; this.isSilent = !!opts.isSilent; } _prependEmoji(msg, emoji) { if (this.emoji && emoji && this.isTTY) { msg = `${emoji} ${msg}`; } return msg; } _logCategory(category, color, msg) { this._lastCategorySize = category.length; this._log(`${this.format[color](category)} ${msg}`); } _verbose(msg) { this._logCategory('verbose', 'grey', `${process.uptime()} ${msg}`); } _verboseInspect(obj) { this.inspect(obj); } close() { for (const spinner of this._spinners) { spinner.stop(); } this._spinners.clear(); this.stopProgress(); super.close(); } table(head, body) { // head = head.map((field) => this.format.underline(field)); // const rows = [head].concat(body); // get column widths const cols = []; for (let i = 0; i < head.length; i++) { const widths = rows.map((row) => this.format.stripColor(row[i]).length); cols[i] = Math.max(...widths); } // const builtRows = rows.map((row) => { for (let i = 0; i < row.length; i++) { const field = row[i]; const padding = cols[i] - this.format.stripColor(field).length; row[i] = field + ' '.repeat(padding); } return row.join(' '); }); this.log(builtRows.join('\n')); } step(current, total, msg, emoji) { msg = this._prependEmoji(msg, emoji); if (msg.endsWith('?')) { msg = `${removeSuffix(msg, '?')}...?`; } else { msg += '...'; } this.log(`${this.format.dim(`[${current}/${total}]`)} ${msg}`); } inspect(value) { if (typeof value !== 'number' && typeof value !== 'string') { value = inspect(value, { breakLength: 0, colors: this.isTTY, depth: null, maxArrayLength: null, }); } this.log(String(value), { force: true }); } list(key, items, hints) { const gutterWidth = (this._lastCategorySize || 2) - 1; if (hints) { for (const item of items) { this._log(`${' '.repeat(gutterWidth)}- ${this.format.bold(item)}`); this._log(` ${' '.repeat(gutterWidth)} ${hints[item]}`); } } else { for (const item of items) { this._log(`${' '.repeat(gutterWidth)}- ${item}`); } } } header(pkg) { this.log(this.format.bold(`${pkg.name} v${pkg.version}`)); } footer(showPeakMemory) { this.stopProgress(); const totalTime = (this.getTotalTime() / 1000).toFixed(2); let msg = `Done in ${totalTime}s.`; if (showPeakMemory) { const peakMemory = (this.peakMemory / 1024 / 1024).toFixed(2); msg += ` Peak memory usage ${peakMemory}MB.`; } this.log(this._prependEmoji(msg, '✨')); } log(msg, { force = false } = {}) { this._lastCategorySize = 0; this._log(msg, { force }); } _log(msg, { force = false } = {}) { if (this.isSilent && !force) { return; } clearLine(this.stdout); this.stdout.write(`${msg}\n`); } success(msg) { this._logCategory('success', 'green', msg); } error(msg) { clearLine(this.stderr); this.stderr.write(`${this.format.red('error')} ${msg}\n`); } info(msg) { this._logCategory('info', 'blue', msg); } command(command) { this.log(this.format.dim(`$ ${command}`)); } warn(msg) { clearLine(this.stderr); this.stderr.write(`${this.format.yellow('warning')} ${msg}\n`); } // handles basic tree output to console tree(key, trees, { force = false } = {}) { this.stopProgress(); // if (this.isSilent && !force) { return; } const output = ({ name, children, hint, color }, titlePrefix, childrenPrefix) => { const formatter = this.format; const out = getFormattedOutput({ prefix: titlePrefix, hint, color, name, formatter, }); this.stdout.write(out); if (children && children.length) { recurseTree(sortTrees(children), childrenPrefix, output); } }; recurseTree(sortTrees(trees), '', output); } activitySet(total, workers) { if (!this.isTTY || this.noProgress) { return super.activitySet(total, workers); } const spinners = []; const reporterSpinners = this._spinners; for (let i = 1; i < workers; i++) { this.log(''); } for (let i = 0; i < workers; i++) { const spinner = new Spinner(this.stderr, i); reporterSpinners.add(spinner); spinner.start(); let prefix = null; let current = 0; const updatePrefix = () => { spinner.setPrefix(`${this.format.dim(`[${current === 0 ? '-' : current}/${total}]`)} `); }; const clear = () => { prefix = null; current = 0; updatePrefix(); spinner.setText('waiting...'); }; clear(); spinners.unshift({ clear, setPrefix(_current, _prefix) { current = _current; prefix = _prefix; spinner.setText(prefix); updatePrefix(); }, tick(msg) { if (prefix) { msg = `${prefix}: ${msg}`; } spinner.setText(msg); }, end() { spinner.stop(); reporterSpinners.delete(spinner); }, }); } return { spinners, end: () => { for (const spinner of spinners) { spinner.end(); } readline.moveCursor(this.stdout, 0, -workers + 1); }, }; } activity() { if (!this.isTTY) { return { tick() { }, end() { }, }; } const reporterSpinners = this._spinners; const spinner = new Spinner(this.stderr); spinner.start(); reporterSpinners.add(spinner); return { tick(name) { spinner.setText(name); }, end() { spinner.stop(); reporterSpinners.delete(spinner); }, }; } progress(count) { if (this.noProgress || count <= 0) { return function () { // noop }; } if (!this.isTTY) { return function () { // TODO what should the behaviour here be? we could buffer progress messages maybe }; } // Clear any potentially old progress bars this.stopProgress(); const bar = (this._progressBar = new Progress(count, this.stderr, (progress) => { if (progress === this._progressBar) { this._progressBar = null; } })); bar.render(); return function () { bar.tick(); }; } stopProgress() { if (this._progressBar) { this._progressBar.stop(); } } } ================================================ FILE: checkpoint/dist-src/reporters/console/helpers/tree-helper.js ================================================ // public export function sortTrees(trees) { return trees.sort(function (tree1, tree2) { return tree1.name.localeCompare(tree2.name); }); } export function recurseTree(tree, prefix, recurseFunc) { const treeLen = tree.length; const treeEnd = treeLen - 1; for (let i = 0; i < treeLen; i++) { const atEnd = i === treeEnd; recurseFunc(tree[i], prefix + getLastIndentChar(atEnd), prefix + getNextIndentChar(atEnd)); } } export function getFormattedOutput(fmt) { const item = formatColor(fmt.color, fmt.name, fmt.formatter); const suffix = getSuffix(fmt.hint, fmt.formatter); return `${fmt.prefix}─ ${item}${suffix}\n`; } function getNextIndentChar(end) { return end ? ' ' : '│ '; } function getLastIndentChar(end) { return end ? '└' : '├'; } function getSuffix(hint, formatter) { return hint ? ` (${formatter.grey(hint)})` : ''; } function formatColor(color, strToFormat, formatter) { return color ? formatter[color](strToFormat) : strToFormat; } ================================================ FILE: checkpoint/dist-src/reporters/console/progress-bar.js ================================================ import { clearLine, toStartOfLine } from './util.js'; export default class ProgressBar { constructor(total, stdout = process.stderr, callback) { this.stdout = stdout; this.total = total; this.chars = ProgressBar.bars[0]; this.delay = 60; this.curr = 0; this._callback = callback; clearLine(stdout); } tick() { if (this.curr >= this.total) { return; } this.curr++; // schedule render if (!this.id) { this.id = setTimeout(() => this.render(), this.delay); } } cancelTick() { if (this.id) { clearTimeout(this.id); this.id = null; } } stop() { // "stop" by setting current to end so `tick` becomes noop this.curr = this.total; this.cancelTick(); clearLine(this.stdout); if (this._callback) { this._callback(this); } } render() { // clear throttle this.cancelTick(); let ratio = this.curr / this.total; ratio = Math.min(Math.max(ratio, 0), 1); // progress without bar let bar = ` ${this.curr}/${this.total}`; // calculate size of actual bar // $FlowFixMe: investigate process.stderr.columns flow error // @ts-ignore const availableSpace = Math.max(0, this.stdout.columns - bar.length - 3); const width = Math.min(this.total, availableSpace); const completeLength = Math.round(width * ratio); const complete = this.chars[0].repeat(completeLength); const incomplete = this.chars[1].repeat(width - completeLength); bar = `[${complete}${incomplete}]${bar}`; toStartOfLine(this.stdout); this.stdout.write(bar); } } ProgressBar.bars = [['#', '-']]; ================================================ FILE: checkpoint/dist-src/reporters/console/spinner-progress.js ================================================ import { writeOnNthLine, clearNthLine } from './util.js'; export default class Spinner { constructor(stdout = process.stderr, lineNumber = 0) { this.current = 0; this.prefix = ''; this.lineNumber = lineNumber; this.stdout = stdout; this.delay = 60; this.chars = Spinner.spinners[28].split(''); this.text = ''; this.id = null; } setPrefix(prefix) { this.prefix = prefix; } setText(text) { this.text = text; } start() { this.current = 0; this.render(); } render() { if (this.id) { clearTimeout(this.id); } // build line ensuring we don't wrap to the next line let msg = `${this.prefix}${this.chars[this.current]} ${this.text}`; // @ts-ignore const columns = typeof this.stdout.columns === 'number' ? this.stdout.columns : 100; msg = msg.slice(0, columns); writeOnNthLine(this.stdout, this.lineNumber, msg); this.current = ++this.current % this.chars.length; this.id = setTimeout(() => this.render(), this.delay); } stop() { if (this.id) { clearTimeout(this.id); this.id = null; } clearNthLine(this.stdout, this.lineNumber); } } Spinner.spinners = [ '|/-\\', '⠂-–—–-', '◐◓◑◒', '◴◷◶◵', '◰◳◲◱', '▖▘▝▗', '■□▪▫', '▌▀▐▄', '▉▊▋▌▍▎▏▎▍▌▋▊▉', '▁▃▄▅▆▇█▇▆▅▄▃', '←↖↑↗→↘↓↙', '┤┘┴└├┌┬┐', '◢◣◤◥', '.oO°Oo.', '.oO@*', '🌍🌎🌏', '◡◡ ⊙⊙ ◠◠', '☱☲☴', '⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏', '⠋⠙⠚⠞⠖⠦⠴⠲⠳⠓', '⠄⠆⠇⠋⠙⠸⠰⠠⠰⠸⠙⠋⠇⠆', '⠋⠙⠚⠒⠂⠂⠒⠲⠴⠦⠖⠒⠐⠐⠒⠓⠋', '⠁⠉⠙⠚⠒⠂⠂⠒⠲⠴⠤⠄⠄⠤⠴⠲⠒⠂⠂⠒⠚⠙⠉⠁', '⠈⠉⠋⠓⠒⠐⠐⠒⠖⠦⠤⠠⠠⠤⠦⠖⠒⠐⠐⠒⠓⠋⠉⠈', '⠁⠁⠉⠙⠚⠒⠂⠂⠒⠲⠴⠤⠄⠄⠤⠠⠠⠤⠦⠖⠒⠐⠐⠒⠓⠋⠉⠈⠈', '⢄⢂⢁⡁⡈⡐⡠', '⢹⢺⢼⣸⣇⡧⡗⡏', '⣾⣽⣻⢿⡿⣟⣯⣷', '⠁⠂⠄⡀⢀⠠⠐⠈', ]; ================================================ FILE: checkpoint/dist-src/reporters/console/util.js ================================================ import * as tty from 'tty'; import * as readline from 'readline'; import chalk from 'chalk'; const CLEAR_WHOLE_LINE = 0; const CLEAR_RIGHT_OF_CURSOR = 1; export function clearLine(stdout) { if (!chalk.supportsColor) { if (stdout instanceof tty.WriteStream) { if (stdout.columns > 0) { stdout.write(`\r${' '.repeat(stdout.columns - 1)}`); } stdout.write(`\r`); } return; } readline.clearLine(stdout, CLEAR_WHOLE_LINE); readline.cursorTo(stdout, 0); } export function toStartOfLine(stdout) { if (!chalk.supportsColor) { stdout.write('\r'); return; } readline.cursorTo(stdout, 0); } export function writeOnNthLine(stdout, n, msg) { if (!chalk.supportsColor) { return; } if (n == 0) { readline.cursorTo(stdout, 0); stdout.write(msg); readline.clearLine(stdout, CLEAR_RIGHT_OF_CURSOR); return; } readline.cursorTo(stdout, 0); readline.moveCursor(stdout, 0, -n); stdout.write(msg); readline.clearLine(stdout, CLEAR_RIGHT_OF_CURSOR); readline.cursorTo(stdout, 0); readline.moveCursor(stdout, 0, n); } export function clearNthLine(stdout, n) { if (!chalk.supportsColor) { return; } if (n == 0) { clearLine(stdout); return; } readline.cursorTo(stdout, 0); readline.moveCursor(stdout, 0, -n); readline.clearLine(stdout, CLEAR_WHOLE_LINE); readline.moveCursor(stdout, 0, n); } ================================================ FILE: checkpoint/dist-src/reporters/format.js ================================================ function formatFunction(...strs) { return strs.join(' '); } export const defaultFormatter = { bold: formatFunction, dim: formatFunction, italic: formatFunction, underline: formatFunction, inverse: formatFunction, strikethrough: formatFunction, black: formatFunction, red: formatFunction, green: formatFunction, yellow: formatFunction, blue: formatFunction, magenta: formatFunction, cyan: formatFunction, white: formatFunction, gray: formatFunction, grey: formatFunction, stripColor: formatFunction, }; ================================================ FILE: checkpoint/dist-src/reporters/index.js ================================================ export { default as ConsoleReporter } from './console/console-reporter'; export { default as JSONReporter } from './json-reporter'; export { default as NoopReporter } from './noop-reporter'; export { default as Reporter } from './base-reporter'; ================================================ FILE: checkpoint/dist-src/reporters/json-reporter.js ================================================ import BaseReporter from './base-reporter.js'; export default class JSONReporter extends BaseReporter { constructor(opts) { super(opts); this._activityId = 0; this._progressId = 0; } _dump(type, data, error) { let stdout = this.stdout; if (error) { stdout = this.stderr; } stdout.write(`${JSON.stringify({ type, data })}\n`); } _verbose(msg) { this._dump('verbose', msg); } list(type, items, hints) { this._dump('list', { type, items, hints }); } tree(type, trees) { this._dump('tree', { type, trees }); } step(current, total, message) { this._dump('step', { message, current, total }); } inspect(value) { this._dump('inspect', value); } footer(showPeakMemory) { this._dump('finished', this.getTotalTime()); } log(msg) { this._dump('log', msg); } command(msg) { this._dump('command', msg); } table(head, body) { this._dump('table', { head, body }); } success(msg) { this._dump('success', msg); } error(msg) { this._dump('error', msg, true); } warn(msg) { this._dump('warning', msg, true); } info(msg) { this._dump('info', msg); } activitySet(total, workers) { if (!this.isTTY || this.noProgress) { return super.activitySet(total, workers); } const id = this._activityId++; this._dump('activitySetStart', { id, total, workers }); const spinners = []; for (let i = 0; i < workers; i++) { let current = 0; let header = ''; spinners.push({ clear() { }, setPrefix(_current, _header) { current = _current; header = _header; }, tick: msg => { this._dump('activitySetTick', { id, header, current, worker: i, message: msg, }); }, end() { }, }); } return { spinners, end: () => { this._dump('activitySetEnd', { id }); }, }; } activity() { return this._activity({}); } _activity(data) { if (!this.isTTY || this.noProgress) { return { tick() { }, end() { }, }; } const id = this._activityId++; this._dump('activityStart', { id, ...data }); return { tick: (name) => { this._dump('activityTick', { id, name }); }, end: () => { this._dump('activityEnd', { id }); }, }; } progress(total) { if (this.noProgress) { return function () { // noop }; } const id = this._progressId++; let current = 0; this._dump('progressStart', { id, total }); return () => { current++; this._dump('progressTick', { id, current }); if (current === total) { this._dump('progressFinish', { id }); } }; } } ================================================ FILE: checkpoint/dist-src/reporters/lang/en.js ================================================ const messages = { upToDate: 'Already up-to-date.', folderInSync: 'Folder in sync.', nothingToInstall: 'Nothing to install.', resolvingPackages: 'Resolving packages', checkingManifest: 'Validating package.json', fetchingPackages: 'Fetching packages', linkingDependencies: 'Linking dependencies', rebuildingPackages: 'Rebuilding all packages', buildingFreshPackages: 'Building fresh packages', cleaningModules: 'Cleaning modules', bumpingVersion: 'Bumping version', savingHar: 'Saving HAR file: $0', answer: 'Answer?', usage: 'Usage', installCommandRenamed: '`install` has been replaced with `add` to add new dependencies. Run $0 instead.', globalFlagRemoved: '`--global` has been deprecated. Please run $0 instead.', waitingInstance: 'Waiting for the other pika instance to finish (pid $0, inside $1)', waitingNamedInstance: 'Waiting for the other pika instance to finish ($0)', offlineRetrying: 'There appears to be trouble with your network connection. Retrying...', internalServerErrorRetrying: 'There appears to be trouble with the npm registry (returned $1). Retrying...', clearedCache: 'Cleared cache.', couldntClearPackageFromCache: "Couldn't clear package $0 from cache", clearedPackageFromCache: 'Cleared package $0 from cache', packWroteTarball: 'Wrote tarball to $0.', helpExamples: ' Examples:\n$0\n', helpCommands: ' Commands:\n$0\n', helpCommandsMore: ' Run `$0` for more information on specific commands.', helpLearnMore: ' Visit $0 to learn more about Pika.\n', manifestPotentialTypo: 'Potential typo $0, did you mean $1?', manifestBuiltinModule: '$0 is also the name of a node core module', manifestNameDot: "Name can't start with a dot", manifestNameIllegalChars: 'Name contains illegal characters', manifestNameBlacklisted: 'Name is blacklisted', manifestLicenseInvalid: 'License should be a valid SPDX license expression', manifestLicenseNone: 'No license field', manifestStringExpected: '$0 is not a string', manifestDependencyCollision: '$0 has dependency $1 with range $2 that collides with a dependency in $3 of the same name with version $4', manifestDirectoryNotFound: 'Unable to read $0 directory of module $1', verboseFileCopy: 'Copying $0 to $1.', verboseFileLink: 'Creating hardlink at $0 to $1.', verboseFileSymlink: 'Creating symlink at $0 to $1.', verboseFileSkip: 'Skipping copying of file $0 as the file at $1 is the same size ($2) and mtime ($3).', verboseFileSkipSymlink: 'Skipping copying of $0 as the file at $1 is the same symlink ($2).', verboseFileSkipHardlink: 'Skipping copying of $0 as the file at $1 is the same hardlink ($2).', verboseFileRemoveExtraneous: 'Removing extraneous file $0.', verboseFilePhantomExtraneous: "File $0 would be marked as extraneous but has been removed as it's listed as a phantom file.", verboseFileSkipArtifact: 'Skipping copying of $0 as the file is marked as a built artifact and subject to change.', verboseFileFolder: 'Creating directory $0.', verboseRequestStart: 'Performing $0 request to $1.', verboseRequestFinish: 'Request $0 finished with status code $1.', configSet: 'Set $0 to $1.', configDelete: 'Deleted $0.', configNpm: 'npm config', configPika: 'pika config', couldntFindPackagejson: "Couldn't find a package.json file in $0", couldntFindMatch: "Couldn't find match for $0 in $1 for $2.", couldntFindPackageInCache: "Couldn't find any versions for $0 that matches $1 in our cache (possible versions are $2). This is usually caused by a missing entry in the lockfile, running Pika without the --offline flag may help fix this issue.", couldntFindVersionThatMatchesRange: "Couldn't find any versions for $0 that matches $1", chooseVersionFromList: 'Please choose a version of $0 from this list:', moduleNotInManifest: "This module isn't specified in a package.json file.", moduleAlreadyInManifest: '$0 is already in $1. Please remove existing entry first before adding it to $2.', unknownFolderOrTarball: "Passed folder/tarball doesn't exist,", unknownPackage: "Couldn't find package $0.", unknownPackageName: "Couldn't find package name.", unknownUser: "Couldn't find user $0.", unknownRegistryResolver: 'Unknown registry resolver $0', userNotAnOwner: "User $0 isn't an owner of this package.", invalidVersionArgument: 'Use the $0 flag to create a new version.', invalidVersion: 'Invalid version supplied.', requiredVersionInRange: 'Required version in range.', packageNotFoundRegistry: "Couldn't find package $0 on the $1 registry.", requiredPackageNotFoundRegistry: "Couldn't find package $0 required by $1 on the $2 registry.", doesntExist: "Package $1 refers to a non-existing file '$0'.", missingRequiredPackageKey: `Package $0 doesn't have a $1.`, invalidAccess: 'Invalid argument for access, expected public or restricted.', invalidCommand: 'Invalid subcommand. Try $0', invalidGistFragment: 'Invalid gist fragment $0.', invalidHostedGitFragment: 'Invalid hosted git fragment $0.', invalidFragment: 'Invalid fragment $0.', invalidPackageName: 'Invalid package name.', invalidPackageVersion: "Can't add $0: invalid package version $1.", couldntFindManifestIn: "Couldn't find manifest in $0.", shrinkwrapWarning: 'npm-shrinkwrap.json found. This will not be updated or respected. See https://yarnpkg.com/en/docs/migrating-from-npm for more information.', npmLockfileWarning: 'package-lock.json found. Your project contains lock files generated by tools other than Pika. It is advised not to mix package managers in order to avoid resolution inconsistencies caused by unsynchronized lock files. To clear this warning, remove package-lock.json.', lockfileOutdated: 'Outdated lockfile. Please run `pika install` and try again.', lockfileMerged: 'Merge conflict detected in pika.lock and successfully merged.', lockfileConflict: 'A merge conflict was found in pika.lock but it could not be successfully merged, regenerating pika.lock from scratch.', ignoredScripts: 'Ignored scripts due to flag.', missingAddDependencies: 'Missing list of packages to add to your project.', yesWarning: 'The yes flag has been set. This will automatically answer yes to all questions, which may have security implications.', networkWarning: "You don't appear to have an internet connection. Try the --offline flag to use the cache for registry queries.", flatGlobalError: 'The package $0 requires a flat dependency graph. Add `"flat": true` to your package.json and try again.', noName: `Package doesn't have a name.`, noVersion: `Package doesn't have a version.`, answerRequired: 'An answer is required.', missingWhyDependency: 'Missing package name, folder or path to file to identify why a package has been installed', bugReport: 'If you think this is a bug, please open a bug report with the information provided in $0.', unexpectedError: 'An unexpected error occurred: $0.', jsonError: 'Error parsing JSON at $0, $1.', noPermission: 'Cannot create $0 due to insufficient permissions.', noGlobalFolder: 'Cannot find a suitable global folder. Tried these: $0', allDependenciesUpToDate: 'All of your dependencies are up to date.', legendColorsForVersionUpdates: 'Color legend : \n $0 : Major Update backward-incompatible updates \n $1 : Minor Update backward-compatible features \n $2 : Patch Update backward-compatible bug fixes', frozenLockfileError: 'Your lockfile needs to be updated, but pika was run with `--frozen-lockfile`.', fileWriteError: 'Could not write file $0: $1', fileDeleteError: 'Could not delete file $0: $1', multiplePackagesCantUnpackInSameDestination: 'Pattern $0 is trying to unpack in the same destination $1 as pattern $2. This could result in non-deterministic behavior, skipping.', incorrectLockfileEntry: 'Lockfile has incorrect entry for $0. Ignoring it.', invalidResolutionName: 'Resolution field $0 does not end with a valid package name and will be ignored', invalidResolutionVersion: 'Resolution field $0 has an invalid version entry and may be ignored', incompatibleResolutionVersion: 'Resolution field $0 is incompatible with requested version $1', pikaOutdated: "Your current version of Pika is out of date. The latest version is $0, while you're on $1.", pikaOutdatedInstaller: 'To upgrade, download the latest installer at $0.', pikaOutdatedCommand: 'To upgrade, run the following command:', tooManyArguments: 'Too many arguments, maximum of $0.', tooFewArguments: 'Not enough arguments, expected at least $0.', noArguments: "This command doesn't require any arguments.", ownerRemoving: 'Removing owner $0 from package $1.', ownerRemoved: 'Owner removed.', ownerRemoveError: "Couldn't remove owner.", ownerGetting: 'Getting owners for package $0', ownerGettingFailed: "Couldn't get list of owners.", ownerAlready: 'This user is already an owner of this package.', ownerAdded: 'Added owner.', ownerAdding: 'Adding owner $0 to package $1', ownerAddingFailed: "Couldn't add owner.", ownerNone: 'No owners.', teamCreating: 'Creating team', teamRemoving: 'Removing team', teamAddingUser: 'Adding user to team', teamRemovingUser: 'Removing user from team', teamListing: 'Listing teams', distFailed: `⚠️ Distribution "$0" failed to build: $1 $2`, distExiting: ` Exiting...`, distContinuing: ` Continuing...`, cleaning: 'Cleaning modules', cleanCreatingFile: 'Creating $0', cleanCreatedFile: 'Created $0. Please review the contents of this file then run "pika autoclean --force" to perform a clean.', cleanAlreadyExists: '$0 already exists. To revert to the default file, delete $0 then rerun this command.', cleanRequiresForce: 'This command required the "--force" flag to perform the clean. This is a destructive operation. Files specified in $0 will be deleted.', cleanDoesNotExist: '$0 does not exist. Autoclean will delete files specified by $0. Run "autoclean --init" to create $0 with the default entries.', binLinkCollision: "There's already a linked binary called $0 in your global Pika bin. Could not link this package's $0 bin entry.", linkCollision: "There's already a package called $0 registered. This command has had no effect. If this command was run in another folder with the same name, the other folder is still linked. Please run pika unlink in the other folder if you want to register this folder.", linkMissing: 'No registered package found called $0.', linkRegistered: 'Registered $0.', linkRegisteredMessage: 'You can now run `pika link $0` in the projects where you want to use this package and it will be used instead.', linkUnregistered: 'Unregistered $0.', linkUnregisteredMessage: 'You can now run `pika unlink $0` in the projects where you no longer want to use this package.', linkUsing: 'Using linked package for $0.', linkDisusing: 'Removed linked package $0.', linkDisusingMessage: 'You will need to run `pika` to re-install the package that was linked.', linkTargetMissing: 'The target of linked package $0 is missing. Removing link.', createInvalidBin: 'Invalid bin entry found in package $0.', createMissingPackage: 'Package not found - this is probably an internal error, and should be reported at https://github.com/yarnpkg/yarn/issues.', workspacesAddRootCheck: 'Running this command will add the dependency to the workspace root rather than the workspace itself, which might not be what you want - if you really meant it, make it explicit by running this command again with the -W flag (or --ignore-workspace-root-check).', workspacesRemoveRootCheck: 'Running this command will remove the dependency from the workspace root rather than the workspace itself, which might not be what you want - if you really meant it, make it explicit by running this command again with the -W flag (or --ignore-workspace-root-check).', workspacesFocusRootCheck: 'This command can only be run inside an individual workspace.', workspacesRequirePrivateProjects: 'Workspaces can only be enabled in private projects.', workspacesSettingMustBeArray: 'The workspaces field in package.json must be an array.', workspacesDisabled: 'Your project root defines workspaces but the feature is disabled in your Pika config. Please check "workspaces-experimental" in your .pikarc file.', workspacesNohoistRequirePrivatePackages: 'nohoist config is ignored in $0 because it is not a private package. If you think nohoist should be allowed in public packages, please submit an issue for your use case.', workspacesNohoistDisabled: `$0 defines nohoist but the feature is disabled in your Pika config ("workspaces-nohoist-experimental" in .pikarc file)`, workspaceRootNotFound: "Cannot find the root of your workspace - are you sure you're currently in a workspace?", workspaceMissingWorkspace: 'Missing workspace name.', workspaceMissingCommand: 'Missing command name.', workspaceUnknownWorkspace: 'Unknown workspace $0.', workspaceVersionMandatory: 'Missing version in workspace at $0, ignoring.', workspaceNameMandatory: 'Missing name in workspace at $0, ignoring.', workspaceNameDuplicate: 'There are more than one workspace with name $0', cacheFolderSkipped: 'Skipping preferred cache folder $0 because it is not writable.', cacheFolderMissing: "Pika hasn't been able to find a cache folder it can use. Please use the explicit --cache-folder option to tell it what location to use, or make one of the preferred locations writable.", cacheFolderSelected: 'Selected the next writable cache folder in the list, will be $0.', execMissingCommand: 'Missing command name.', noScriptsAvailable: 'There are no scripts specified inside package.json.', noBinAvailable: 'There are no binary scripts available.', dashDashDeprecation: `From Pika 1.0 onwards, scripts don't require "--" for options to be forwarded. In a future version, any explicit "--" will be forwarded as-is to the scripts.`, commandNotSpecified: 'No command specified.', binCommands: 'Commands available from binary scripts: ', possibleCommands: 'Project commands', commandQuestion: 'Which command would you like to run?', commandFailedWithCode: 'Command failed with exit code $0.', commandFailedWithSignal: 'Command failed with signal $0.', packageRequiresNodeGyp: 'This package requires node-gyp, which is not currently installed. Pika will attempt to automatically install it. If this fails, you can run "pika global add node-gyp" to manually install it.', nodeGypAutoInstallFailed: 'Failed to auto-install node-gyp. Please run "pika global add node-gyp" manually. Error: $0', foundIncompatible: 'Found incompatible module', incompatibleEngine: 'The engine $0 is incompatible with this module. Expected version $1. Got $2', incompatibleCPU: 'The CPU architecture $0 is incompatible with this module.', incompatibleOS: 'The platform $0 is incompatible with this module.', invalidEngine: 'The engine $0 appears to be invalid.', optionalCompatibilityExcluded: '$0 is an optional dependency and failed compatibility check. Excluding it from installation.', optionalModuleFail: 'This module is OPTIONAL, you can safely ignore this error', optionalModuleScriptFail: 'Error running install script for optional dependency: $0', optionalModuleCleanupFail: 'Could not cleanup build artifacts from failed install: $0', unmetPeer: '$0 has unmet peer dependency $1.', incorrectPeer: '$0 has incorrect peer dependency $1.', selectedPeer: 'Selecting $1 at level $2 as the peer dependency of $0.', missingBundledDependency: '$0 is missing a bundled dependency $1. This should be reported to the package maintainer.', savedNewDependency: 'Saved 1 new dependency.', savedNewDependencies: 'Saved $0 new dependencies.', directDependencies: 'Direct dependencies', allDependencies: 'All dependencies', foundWarnings: 'Found $0 warnings.', foundErrors: 'Found $0 errors.', savedLockfile: 'Saved lockfile.', noRequiredLockfile: 'No lockfile in this directory. Run `pika install` to generate one.', noLockfileFound: 'No lockfile found.', invalidSemver: 'Invalid semver version', newVersion: 'New version', currentVersion: 'Current version', noVersionOnPublish: 'Proceeding with current version', manualVersionResolution: 'Unable to find a suitable version for $0, please choose one by typing one of the numbers below:', manualVersionResolutionOption: '$0 which resolved to $1', createdTag: 'Created tag.', createdTagFail: "Couldn't add tag.", deletedTag: 'Deleted tag.', deletedTagFail: "Couldn't delete tag.", gettingTags: 'Getting tags', deletingTags: 'Deleting tag', creatingTag: 'Creating tag $0 = $1', whyStart: 'Why do we have the module $0?', whyFinding: 'Finding dependency', whyCalculating: 'Calculating file sizes', whyUnknownMatch: "We couldn't find a match!", whyInitGraph: 'Initialising dependency graph', whyWhoKnows: "We don't know why this module exists", whyDiskSizeWithout: 'Disk size without dependencies: $0', whyDiskSizeUnique: 'Disk size with unique dependencies: $0', whyDiskSizeTransitive: 'Disk size with transitive dependencies: $0', whySharedDependencies: 'Number of shared dependencies: $0', whyHoistedTo: `Has been hoisted to $0`, whyHoistedFromSimple: `This module exists because it's hoisted from $0.`, whyNotHoistedSimple: `This module exists here because it's in the nohoist list $0.`, whyDependedOnSimple: `This module exists because $0 depends on it.`, whySpecifiedSimple: `This module exists because it's specified in $0.`, whyReasons: 'Reasons this module exists', whyHoistedFrom: 'Hoisted from $0', whyNotHoisted: `in the nohoist list $0`, whyDependedOn: '$0 depends on it', whySpecified: `Specified in $0`, whyMatch: `\r=> Found $0`, uninstalledPackages: 'Uninstalled packages.', uninstallRegenerate: 'Regenerating lockfile and installing missing dependencies', cleanRemovedFiles: 'Removed $0 files', cleanSavedSize: 'Saved $0 MB.', configFileFound: 'Found configuration file $0.', configPossibleFile: 'Checking for configuration file $0.', npmUsername: 'npm username', npmPassword: 'npm password', npmEmail: 'npm email', npmOneTimePassword: 'npm one-time password', loggingIn: 'Logging in', loggedIn: 'Logged in.', notRevokingEnvToken: 'Not revoking login token, specified via environment variable.', notRevokingConfigToken: 'Not revoking login token, specified via config file.', noTokenToRevoke: 'No login token to revoke.', revokingToken: 'Revoking token', revokedToken: 'Revoked login token.', loginAsPublic: 'Logging in as public', incorrectCredentials: 'Incorrect username or password.', incorrectOneTimePassword: 'Incorrect one-time password.', twoFactorAuthenticationEnabled: 'Two factor authentication enabled.', clearedCredentials: 'Cleared login credentials.', publishFail: "Couldn't publish package: $0", publishPrivate: 'Package marked as private, not publishing.', published: 'Published.', publishing: 'Publishing', nonInteractiveNoVersionSpecified: 'You must specify a new version with --new-version when running with --non-interactive.', nonInteractiveNoToken: "No token found and can't prompt for login when running with --non-interactive.", infoFail: 'Received invalid response from npm.', malformedRegistryResponse: 'Received malformed response from registry for $0. The registry may be down.', registryNoVersions: 'No valid versions found for $0. The package may be unpublished.', cantRequestOffline: "Can't make a request in offline mode ($0)", requestManagerNotSetupHAR: 'RequestManager was not setup to capture HAR files', requestError: 'Request $0 returned a $1', requestFailed: 'Request failed $0', tarballNotInNetworkOrCache: '$0: Tarball is not in network and can not be located in cache ($1)', fetchBadHashWithPath: "Integrity check failed for $0 (computed integrity doesn't match our records, got $2)", fetchBadIntegrityAlgorithm: 'Integrity checked failed for $0 (none of the specified algorithms are supported)', fetchErrorCorrupt: '$0. Mirror tarball appears to be corrupt. You can resolve this by running:\n\n rm -rf $1\n pika install', errorExtractingTarball: 'Extracting tar content of $1 failed, the file appears to be corrupt: $0', updateInstalling: 'Installing $0...', hostedGitResolveError: 'Error connecting to repository. Please, check the url.', unknownFetcherFor: 'Unknown fetcher for $0', downloadGitWithoutCommit: 'Downloading the git repo $0 over plain git without a commit hash', downloadHTTPWithoutCommit: 'Downloading the git repo $0 over HTTP without a commit hash', unplugDisabled: "Packages can only be unplugged when Plug'n'Play is enabled.", plugnplayWindowsSupport: "Plug'n'Play on Windows doesn't support the cache and project to be kept on separate drives", packageInstalledWithBinaries: 'Installed $0 with binaries:', packageHasBinaries: '$0 has binaries:', packageHasNoBinaries: '$0 has no binaries', packageBinaryNotFound: "Couldn't find a binary named $0", couldBeDeduped: '$0 could be deduped from $1 to $2', lockfileNotContainPattern: 'Lockfile does not contain pattern: $0', integrityCheckFailed: 'Integrity check failed', noIntegrityFile: "Couldn't find an integrity file", integrityFailedExpectedIsNotAJSON: 'Integrity check: integrity file is not a json', integrityCheckLinkedModulesDontMatch: "Integrity check: Linked modules don't match", integrityFlagsDontMatch: "Integrity check: Flags don't match", integrityLockfilesDontMatch: "Integrity check: Lock files don't match", integrityFailedFilesMissing: 'Integrity check: Files are missing', integrityPatternsDontMatch: "Integrity check: Top level patterns don't match", integrityModulesFoldersMissing: 'Integrity check: Some module folders are missing', integritySystemParamsDontMatch: "Integrity check: System parameters don't match", packageNotInstalled: '$0 not installed', optionalDepNotInstalled: 'Optional dependency $0 not installed', packageWrongVersion: '$0 is wrong version: expected $1, got $2', packageDontSatisfy: "$0 doesn't satisfy found match of $1", lockfileExists: 'Lockfile already exists, not migrating.', pikaManifestExists: 'pika.package.json manifest already exists, not migrating.', noManifestExists: 'No package.json manifest found. Run `pika init` to generate a new pika.package.json manifest.', skippingImport: 'Skipping import of $0 for $1', importFailed: 'Import of $0 for $1 failed, resolving normally.', importResolveFailed: 'Import of $0 failed starting in $1', importResolvedRangeMatch: 'Using version $0 of $1 instead of $2 for $3', importSourceFilesCorrupted: 'Failed to import from package-lock.json, source file(s) corrupted', importPackageLock: 'found npm package-lock.json, converting to pika.lock', importYarnLock: 'found yarn.lock, converting to pika.lock', importNodeModules: 'creating pika.lock from local node_modules folder', packageContainsPikaAsGlobal: 'Installing Pika via Pika will result in you having two separate versions of Pika installed at the same time, which is not recommended. To update Pika please follow https://yarnpkg.com/en/docs/install .', watchStarting: `Starting up`, watchRunning: `Ready! Watching source tree for changes`, watchRebuild: `Rebuilding...`, watchError: `Build error!`, noValidationErrors: `0 Validation Errors found.`, validationErrors: `$0 Validation Error(s) found. Resolve before publishing.`, scopeNotValid: 'The specified scope is not valid.', deprecatedCommand: '$0 is deprecated. Please use $1.', deprecatedListArgs: 'Filtering by arguments is deprecated. Please use the pattern option instead.', implicitFileDeprecated: 'Using the "file:" protocol implicitly is deprecated. Please either prepend the protocol or prepend the path $0 with "./".', unsupportedNodeVersion: 'You are using Node $0 which is not supported and may encounter bugs or unexpected behavior. Pika supports the following semver range: $1', verboseUpgradeBecauseRequested: 'Considering upgrade of $0 to $1 because it was directly requested.', verboseUpgradeBecauseOutdated: 'Considering upgrade of $0 to $1 because a newer version exists in the registry.', verboseUpgradeNotUnlocking: 'Not unlocking $0 in the lockfile because it is a new or direct dependency.', verboseUpgradeUnlocking: 'Unlocking $0 in the lockfile.', folderMissing: "Directory $0 doesn't exist", mutexPortBusy: 'Cannot use the network mutex on port $0. It is probably used by another app.', auditRunning: 'Auditing packages', auditSummary: '$0 vulnerabilities found - Packages audited: $1', auditSummarySeverity: 'Severity:', auditCritical: '$0 Critical', auditHigh: '$0 High', auditModerate: '$0 Moderate', auditLow: '$0 Low', auditInfo: '$0 Info', auditResolveCommand: '# Run $0 to resolve $1 $2', auditSemverMajorChange: 'SEMVER WARNING: Recommended action is a potentially breaking change', auditManualReview: 'Manual Review\nSome vulnerabilities require your attention to resolve\n\nVisit https://go.npm.me/audit-guide for additional guidance', auditRunAuditForDetails: 'Security audit found potential problems. Run "pika audit" for additional details.', auditOffline: 'Skipping audit. Security audit cannot be performed in offline mode.', }; export default messages; ================================================ FILE: checkpoint/dist-src/reporters/lang/index.js ================================================ import en from './en.js'; export { en }; ================================================ FILE: checkpoint/dist-src/reporters/noop-reporter.js ================================================ import BaseReporter from './base-reporter.js'; export default class NoopReporter extends BaseReporter { lang(key, ...args) { return 'do nothing'; } verbose(msg) { } verboseInspect(val) { } initPeakMemoryCounter() { } checkPeakMemory() { } close() { } getTotalTime() { return 0; } list(key, items, hints) { } tree(key, obj) { } step(current, total, message, emoji) { } error(message) { } info(message) { } warn(message) { } success(message) { } log(message) { } command(command) { } inspect(value) { } header(pkg) { } footer(showPeakMemory) { } table(head, body) { } activity() { return { tick(name) { }, end() { }, }; } activitySet(total, workers) { return { spinners: Array(workers).fill({ clear() { }, setPrefix() { }, tick() { }, end() { }, }), end() { }, }; } progress(total) { return function () { }; } disableProgress() { this.noProgress = true; } } ================================================ FILE: checkpoint/dist-src/reporters/types.js ================================================ ================================================ FILE: checkpoint/dist-src/types.js ================================================ ================================================ FILE: checkpoint/dist-src/util/babel-plugin-import-rewrite.js ================================================ // @flow import * as nodeFs from 'fs'; import * as nodePath from 'path'; import * as url from 'url'; import chalk from 'chalk'; import { validateDynamicImportArguments } from './babel-validate-specifier.js'; const BareIdentifierFormat = /^((?:@[^\/]+\/)?[^\/]+)(\/.*)?$/; function log(symbol, fileName, errors) { if (!Array.isArray(errors)) { errors = [errors]; } console.log(`${symbol} `, chalk.bold(fileName)); for (const error of errors) { console.log(` ${chalk.dim('≫')} ${error}`); } } export default function transform({ template, types: t }) { function rewriteImport(specifier, { opts, file }) { const { deps, addExtensions } = opts; try { url.parse(specifier); } catch (err) { return; } // URL w/o protocol if (specifier.substr(0, 2) === '//') { return; // Leave it alone } // Local path if (['.', '/'].indexOf(specifier.charAt(0)) >= 0) { if (addExtensions) { const extname = nodePath.extname(specifier); if (extname === '.js') { return; } if (extname) { console.warn('Unexpected file extension:', specifier); return; } const resolvedPath = nodePath.resolve(nodePath.dirname(file.opts.filename), specifier); try { const stat = nodeFs.lstatSync(resolvedPath); if (stat.isDirectory()) { return specifier + '/index'; } } catch (err) { // do nothing } return specifier + '.js'; } return; } // A 'bare' identifier const match = BareIdentifierFormat.exec(specifier); if (deps && match) { const packageName = match[1]; // const file = match[2] || ''; return deps[packageName]; } } return { visitor: { 'ImportDeclaration|ExportNamedDeclaration|ExportAllDeclaration'(path, { opts, file }) { if (!path.node.source) { return; } const rewrittenSpecifier = rewriteImport(path.node.source.value, { opts, file }); if (rewrittenSpecifier) { path.node.source.value = rewrittenSpecifier; } }, Import(path, { opts, file }) { const errors = validateDynamicImportArguments(path); if (errors.size > 0) { return; } const [importPath] = path.parent.arguments; const rewrittenSpecifier = rewriteImport(importPath.value, { opts, file }); if (rewrittenSpecifier) { importPath.value = rewrittenSpecifier; } }, }, }; } ================================================ FILE: checkpoint/dist-src/util/babel-validate-specifier.js ================================================ // @flow import chalk from 'chalk'; function getLineCol(node) { const loc = node.loc.start; return chalk.dim(`[${loc.line}:${loc.column}]`); } export function validateDynamicImportArguments(path) { if (path.parent.arguments.length !== 1) { return new Set([ `${getLineCol(path.node)} "\`import()\` only accepts 1 argument, but got ${path.parent.arguments.length}`, ]); } const [argNode] = path.parent.arguments; if (argNode.type !== 'StringLiteral') { return new Set([ `${getLineCol(path.node)} Pika expects strings as \`import()\` arguments. Treating this as an absolute file path.`, ]); } return new Set(); } ================================================ FILE: checkpoint/dist-src/util/blocking-queue.js ================================================ import map from './map.js'; export default class BlockingQueue { constructor(alias, maxConcurrency = Infinity) { this.concurrencyQueue = []; this.maxConcurrency = maxConcurrency; this.runningCount = 0; this.warnedStuck = false; this.alias = alias; this.first = true; this.running = map() || {}; this.queue = map() || {}; this.stuckTick = this.stuckTick.bind(this); } stillActive() { if (this.stuckTimer) { clearTimeout(this.stuckTimer); } this.stuckTimer = setTimeout(this.stuckTick, 5000); // We need to check the existence of unref because of https://github.com/facebook/jest/issues/4559 // $FlowFixMe: Node's setInterval returns a Timeout, not a Number this.stuckTimer.unref && this.stuckTimer.unref(); } stuckTick() { if (this.runningCount === 1) { this.warnedStuck = true; console.log(`The ${JSON.stringify(this.alias)} blocking queue may be stuck. 5 seconds ` + `without any activity with 1 worker: ${Object.keys(this.running)[0]}`); } } push(key, factory) { if (this.first) { this.first = false; } else { this.stillActive(); } return new Promise((resolve, reject) => { // we're already running so push ourselves to the queue const queue = (this.queue[key] = this.queue[key] || []); queue.push({ factory, resolve, reject }); if (!this.running[key]) { this.shift(key); } }); } shift(key) { if (this.running[key]) { delete this.running[key]; this.runningCount--; if (this.stuckTimer) { clearTimeout(this.stuckTimer); this.stuckTimer = null; } if (this.warnedStuck) { this.warnedStuck = false; console.log(`${JSON.stringify(this.alias)} blocking queue finally resolved. Nothing to worry about.`); } } const queue = this.queue[key]; if (!queue) { return; } const { resolve, reject, factory } = queue.shift(); if (!queue.length) { delete this.queue[key]; } const next = () => { this.shift(key); this.shiftConcurrencyQueue(); }; const run = () => { this.running[key] = true; this.runningCount++; factory() .then(function (val) { resolve(val); next(); return null; }) .catch(function (err) { reject(err); next(); }); }; this.maybePushConcurrencyQueue(run); } maybePushConcurrencyQueue(run) { if (this.runningCount < this.maxConcurrency) { run(); } else { this.concurrencyQueue.push(run); } } shiftConcurrencyQueue() { if (this.runningCount < this.maxConcurrency) { const fn = this.concurrencyQueue.shift(); if (fn) { fn(); } } } } ================================================ FILE: checkpoint/dist-src/util/child.js ================================================ /* global child_process$spawnOpts */ import * as constants from '../constants.js'; import BlockingQueue from './blocking-queue.js'; import { ProcessSpawnError, ProcessTermError } from '../errors.js'; import { promisify } from './promise.js'; import { exec as _exec, spawn as _spawn } from 'child_process'; export const queue = new BlockingQueue('child', constants.CHILD_CONCURRENCY); // TODO: this uid check is kinda whack let uid = 0; export const exec = promisify(_exec); const spawnedProcesses = {}; export function forwardSignalToSpawnedProcesses(signal) { for (const key of Object.keys(spawnedProcesses)) { spawnedProcesses[key].kill(signal); } } export function spawn(program, args, opts = {}, onData) { const key = opts.cwd || String(++uid); return queue.push(key, () => new Promise((resolve, reject) => { const proc = _spawn(program, args, opts); spawnedProcesses[key] = proc; let processingDone = false; let processClosed = false; let err = null; let stdout = ''; proc.on('error', (err) => { if (err.code === 'ENOENT') { reject(new ProcessSpawnError(`Couldn't find the binary ${program}`, err.code, program)); } else { reject(err); } }); function updateStdout(chunk) { stdout += chunk; if (onData) { onData(chunk); } } function finish() { delete spawnedProcesses[key]; if (err) { reject(err); } else { resolve(stdout.trim()); } } if (typeof opts.process === 'function') { opts.process(proc, updateStdout, reject, function () { if (processClosed) { finish(); } else { processingDone = true; } }); } else { if (proc.stderr) { proc.stderr.on('data', updateStdout); } if (proc.stdout) { proc.stdout.on('data', updateStdout); } processingDone = true; } proc.on('close', (code, signal) => { if (signal || code >= 1) { err = new ProcessTermError([ 'Command failed.', signal ? `Exit signal: ${signal}` : `Exit code: ${code}`, `Command: ${program}`, `Arguments: ${args.join(' ')}`, `Directory: ${opts.cwd || process.cwd()}`, `Output:\n${stdout.trim()}`, ].join('\n')); err.EXIT_SIGNAL = signal; err.EXIT_CODE = code; } if (processingDone || err) { finish(); } else { processClosed = true; } }); })); } ================================================ FILE: checkpoint/dist-src/util/conversion.js ================================================ const FALSY_STRINGS = new Set(['0', 'false']); export function boolify(val) { return !FALSY_STRINGS.has(val.toString().toLowerCase()); } export function boolifyWithDefault(val, defaultResult) { return val === '' || val === null || val === undefined ? defaultResult : boolify(val); } ================================================ FILE: checkpoint/dist-src/util/execute-lifecycle-script.js ================================================ import * as child from './child.js'; import { fixCmdWinSlashes } from './fix-cmd-win-slashes.js'; // export const IGNORE_MANIFEST_KEYS: Set = new Set(['readme', 'notice', 'licenseText']); // // We treat these configs as internal, thus not expose them to process.env. // // This helps us avoid some gyp issues when building native modules. // // See https://github.com/yarnpkg/yarn/issues/2286. // const IGNORE_CONFIG_KEYS = ['lastUpdateCheck']; // async function getPnpParameters(config: Config): Promise> { // if (await fs.exists(`${config.lockfileFolder}/${constants.PNP_FILENAME}`)) { // return ['-r', `${config.lockfileFolder}/${constants.PNP_FILENAME}`]; // } else { // return []; // } // } // let wrappersFolder = null; // export async function getWrappersFolder(config: Config): Promise { // if (wrappersFolder) { // return wrappersFolder; // } // wrappersFolder = await fs.makeTempDir(); // await makePortableProxyScript(process.execPath, wrappersFolder, { // proxyBasename: 'node', // prependArguments: [...(await getPnpParameters(config))], // }); // await makePortableProxyScript(process.execPath, wrappersFolder, { // proxyBasename: 'pika', // prependArguments: [process.argv[1]], // }); // return wrappersFolder; // } // const INVALID_CHAR_REGEX = /\W/g; export async function makeEnv() { // stage: string, // cwd: string, // config: Config, const env = { NODE: process.execPath, INIT_CWD: process.cwd(), // This lets `process.env.NODE` to override our `process.execPath`. // This is a bit confusing but it is how `npm` was designed so we // try to be compatible with that. ...process.env, }; return env; } // // Merge in the `env` object specified in .pikarc // const customEnv = config.getOption('env'); // if (customEnv && typeof customEnv === 'object') { // Object.assign(env, customEnv); // } // env.npm_lifecycle_event = stage; // env.npm_node_execpath = env.NODE; // env.npm_execpath = env.npm_execpath || (process.mainModule && process.mainModule.filename); // // Set the env to production for npm compat if production mode. // // https://github.com/npm/npm/blob/30d75e738b9cb7a6a3f9b50e971adcbe63458ed3/lib/utils/lifecycle.js#L336 // if (config.production) { // env.NODE_ENV = 'production'; // } // // Note: npm_config_argv environment variable contains output of nopt - command-line // // parser used by npm. Since we use other parser, we just roughly emulate it's output. (See: #684) // env.npm_config_argv = JSON.stringify({ // remain: [], // cooked: config.commandName === 'run' ? [config.commandName, stage] : [config.commandName], // original: process.argv.slice(2), // }); // const manifest = await config.maybeReadManifest(cwd); // if (manifest) { // if (manifest.scripts && Object.prototype.hasOwnProperty.call(manifest.scripts, stage)) { // env.npm_lifecycle_script = manifest.scripts[stage]; // } // // add npm_package_* // const queue = [['', manifest]]; // while (queue.length) { // const [key, val] = queue.pop(); // if (typeof val === 'object') { // for (const subKey in val) { // const fullKey = [key, subKey].filter(Boolean).join('_'); // if (fullKey && fullKey[0] !== '_' && !IGNORE_MANIFEST_KEYS.has(fullKey)) { // queue.push([fullKey, val[subKey]]); // } // } // } else { // let cleanVal = String(val); // if (cleanVal.indexOf('\n') >= 0) { // cleanVal = JSON.stringify(cleanVal); // } // //replacing invalid chars with underscore // const cleanKey = key.replace(INVALID_CHAR_REGEX, '_'); // env[`npm_package_${cleanKey}`] = cleanVal; // } // } // } // // add npm_config_* and npm_package_config_* from pika config // const keys: Set = new Set([ // ...Object.keys(config.registries.pika.config), // ...Object.keys(config.registries.npm.config), // ]); // const cleaned = Array.from(keys) // .filter(key => !key.match(/:_/) && IGNORE_CONFIG_KEYS.indexOf(key) === -1) // .map(key => { // let val = config.getOption(key); // if (!val) { // val = ''; // } else if (typeof val === 'number') { // val = '' + val; // } else if (typeof val !== 'string') { // val = JSON.stringify(val); // } // if (val.indexOf('\n') >= 0) { // val = JSON.stringify(val); // } // return [key, val]; // }); // // add npm_config_* // for (const [key, val] of cleaned) { // const cleanKey = key.replace(/^_+/, ''); // const envKey = `npm_config_${cleanKey}`.replace(INVALID_CHAR_REGEX, '_'); // env[envKey] = val; // } // // add npm_package_config_* // if (manifest && manifest.name) { // const packageConfigPrefix = `${manifest.name}:`; // for (const [key, val] of cleaned) { // if (key.indexOf(packageConfigPrefix) !== 0) { // continue; // } // const cleanKey = key.replace(/^_+/, '').replace(packageConfigPrefix, ''); // const envKey = `npm_package_config_${cleanKey}`.replace(INVALID_CHAR_REGEX, '_'); // env[envKey] = val; // } // } // // split up the path // const envPath = env[constants.ENV_PATH_KEY]; // const pathParts = envPath ? envPath.split(path.delimiter) : []; // // Include the directory that contains node so that we can guarantee that the scripts // // will always run with the exact same Node release than the one use to run Pika // const execBin = path.dirname(process.execPath); // if (pathParts.indexOf(execBin) === -1) { // pathParts.unshift(execBin); // } // // Include node-gyp version that was bundled with the current Node.js version, // // if available. // pathParts.unshift(path.join(path.dirname(process.execPath), 'node_modules', 'npm', 'bin', 'node-gyp-bin')); // pathParts.unshift( // path.join(path.dirname(process.execPath), '..', 'lib', 'node_modules', 'npm', 'bin', 'node-gyp-bin'), // ); // // Include node-gyp version from homebrew managed npm, if available. // pathParts.unshift( // path.join(path.dirname(process.execPath), '..', 'libexec', 'lib', 'node_modules', 'npm', 'bin', 'node-gyp-bin'), // ); // // Add global bin folder if it is not present already, as some packages depend // // on a globally-installed version of node-gyp. // const globalBin = await getGlobalBinFolder(config, {}); // if (pathParts.indexOf(globalBin) === -1) { // pathParts.unshift(globalBin); // } // // Add node_modules .bin folders to the PATH // for (const registry of Object.keys(registries)) { // const binFolder = path.join(config.registries[registry].folder, '.bin'); // if (config.workspacesEnabled && config.workspaceRootFolder) { // pathParts.unshift(path.join(config.workspaceRootFolder, binFolder)); // } // pathParts.unshift(path.join(config.linkFolder, binFolder)); // pathParts.unshift(path.join(cwd, binFolder)); // if (config.modulesFolder) { // pathParts.unshift(path.join(config.modulesFolder, '.bin')); // } // } // if (await fs.exists(`${config.lockfileFolder}/${constants.PNP_FILENAME}`)) { // // TODO: Fix. import()? Do we even like that it does this? // throw new Error("pnp temporarily not supported"); // const pnpApi = {}; //dynamicRequire(`${config.lockfileFolder}/${constants.PNP_FILENAME}`); // const packageLocator = pnpApi.findPackageLocator(`${config.cwd}/`); // const packageInformation = pnpApi.getPackageInformation(packageLocator); // for (const [name, reference] of packageInformation.packageDependencies.entries()) { // const dependencyInformation = pnpApi.getPackageInformation({name, reference}); // if (!dependencyInformation || !dependencyInformation.packageLocation) { // continue; // } // pathParts.unshift(`${dependencyInformation.packageLocation}/.bin`); // } // } // pathParts.unshift(await getWrappersFolder(config)); // // join path back together // env[constants.ENV_PATH_KEY] = pathParts.join(path.delimiter); // return env; // } export async function executeLifecycleScript({ // config, cwd, cmd, args, isInteractive, onProgress, customShell, }) { const env = await makeEnv(); // await checkForGypIfNeeded(config, cmd, env[constants.ENV_PATH_KEY].split(path.delimiter)); if (process.platform === 'win32' && (!customShell || customShell === 'cmd')) { // handle windows run scripts starting with a relative path cmd = fixCmdWinSlashes(cmd); } // By default (non-interactive), pipe everything to the terminal and run child process detached // as long as it's not Windows (since windows does not have /dev/tty) let stdio = ['ignore', 'pipe', 'pipe']; let detached = process.platform !== 'win32'; if (isInteractive) { stdio = 'inherit'; detached = false; } const shell = customShell || true; const stdout = await child.spawn(cmd, args, { cwd, env, stdio, detached, shell }, onProgress); return { cwd, command: cmd, stdout }; } export default executeLifecycleScript; // let checkGypPromise: Promise = null; // // /** // // * Special case: Some packages depend on node-gyp, but don't specify this in // // * their package.json dependencies. They assume that node-gyp is available // // * globally. We need to detect this case and show an error message. // // */ // function checkForGypIfNeeded(config: Config, cmd: string, paths: Array): Promise { // if (cmd.substr(0, cmd.indexOf(' ')) !== 'node-gyp') { // return Promise.resolve(); // } // // Ensure this only runs once, rather than multiple times in parallel. // if (!checkGypPromise) { // checkGypPromise = _checkForGyp(config, paths); // } // return checkGypPromise; // } // async function _checkForGyp(config: Config, paths: Array): Promise { // const {reporter} = config; // // Check every directory in the PATH // const allChecks = await Promise.all(paths.map(dir => fs.exists(path.join(dir, 'node-gyp')))); // if (allChecks.some(Boolean)) { // // node-gyp is available somewhere // return; // } // reporter.info(reporter.lang('packageRequiresNodeGyp')); // } // export async function execFromDistributions(config: Config, cwd: string, dist: string, step: string): Promise { // const pkg = await config.maybeReadManifest(cwd); // if (!pkg || !pkg.distributions || !pkg.distributions[dist] || typeof pkg.distributions[dist][step] !== 'string') { // return false; // } // const cmd: ?string = pkg.distributions[dist][step]; // await execCommand({stage: 'build', config, cmd, cwd, isInteractive: true}); // return true; // } // export async function execFromManifest(config: Config, commandName: string, cwd: string): Promise { // const pkg = await config.maybeReadManifest(cwd); // if (!pkg || !pkg.scripts) { // return; // } // const cmd: ?string = pkg.scripts[commandName]; // if (cmd) { // await execCommand({stage: commandName, config, cmd, cwd, isInteractive: true}); // } // } // export async function execCommand({ // stage, // config, // cmd, // cwd, // isInteractive, // customShell, // }: { // stage: string; // config: Config; // cmd: string; // cwd: string; // isInteractive: boolean; // customShell?: string; // }): Promise { // const {reporter} = config; // try { // reporter.command(cmd); // await executeLifecycleScript({config, cwd, cmd, isInteractive, customShell}); // return Promise.resolve(); // } catch (err) { // if (err instanceof ProcessTermError) { // throw new MessageError( // err.EXIT_SIGNAL // ? reporter.lang('commandFailedWithSignal', err.EXIT_SIGNAL) // : reporter.lang('commandFailedWithCode', err.EXIT_CODE), // ); // } else { // throw err; // } // } // } ================================================ FILE: checkpoint/dist-src/util/fix-cmd-win-slashes.js ================================================ export function fixCmdWinSlashes(cmd) { function findQuotes(quoteSymbol) { const quotes = []; const addQuote = (_, index) => { quotes.push({ from: index, to: index + _.length }); return _; }; const regEx = new RegExp(quoteSymbol + '.*' + quoteSymbol); cmd.replace(regEx, addQuote); return quotes; } const quotes = findQuotes('"').concat(findQuotes("'")); function isInsideQuotes(index) { return quotes.reduce((result, quote) => { return result || (quote.from <= index && index <= quote.to); }, false); } const cmdPrePattern = '((?:^|&&|&|\\|\\||\\|)\\s*)'; const cmdPattern = '(".*?"|\'.*?\'|\\S*)'; const regExp = new RegExp(`${cmdPrePattern}${cmdPattern}`, 'g'); return cmd.replace(regExp, (whole, pre, cmd, index) => { if ((pre[0] === '&' || pre[0] === '|') && isInsideQuotes(index)) { return whole; } return pre + cmd.replace(/\//g, '\\'); }); } ================================================ FILE: checkpoint/dist-src/util/fs-normalized.js ================================================ // // // This module serves as a wrapper for file operations that are inconsistant across node and OS versions. // import fs from 'fs'; // import {promisify} from './promise.js'; // import {constants} from './fs.js'; // export type CopyFileAction = { // src: string, // dest: string, // atime: Date, // mtime: Date, // mode: number, // }; // let disableTimestampCorrection: boolean; // OS dependent. will be detected on first file copy. // const readFileBuffer = promisify(fs.readFile); // const close: (fd: number) => Promise = promisify(fs.close); // const lstat: (path: string) => Promise = promisify(fs.lstat); // const open: (path: string, flags: string | number, mode: number) => Promise = promisify(fs.open); // const futimes: (fd: number, atime: number, mtime: number) => Promise = promisify(fs.futimes); // const write: ( // fd: number, // buffer: Buffer, // offset?: number, // length?: number, // position?: number, // ) => Promise = promisify(fs.write); // /** // * Unlinks the destination to force a recreation. This is needed on case-insensitive file systems // * to force the correct naming when the filename has changed only in character-casing. (Jest -> jest). // */ // export const copyFile = async function(data: CopyFileAction, cleanup: () => any): Promise { // // $FlowFixMe: Flow doesn't currently support COPYFILE_FICLONE // const ficloneFlag = (constants as any).COPYFILE_FICLONE || 0; // try { // await unlink(data.dest); // await copyFilePoly(data.src, data.dest, ficloneFlag, data); // } finally { // if (cleanup) { // cleanup(); // } // } // }; // // Node 8.5.0 introduced `fs.copyFile` which is much faster, so use that when available. // // Otherwise we fall back to reading and writing files as buffers. // const copyFilePoly: (src: string, dest: string, flags: number, data: CopyFileAction) => Promise = ( // src, // dest, // flags, // data, // ) => { // if (fs.copyFile) { // return new Promise((resolve, reject) => // fs.copyFile(src, dest, flags, err => { // if (err) { // reject(err); // } else { // fixTimes(undefined, dest, data).then(() => resolve()).catch(ex => reject(ex)); // } // }), // ); // } else { // return copyWithBuffer(src, dest, flags, data); // } // }; // const copyWithBuffer: (src: string, dest: string, flags: number, data: CopyFileAction) => Promise = async ( // src, // dest, // flags, // data, // ) => { // // Use open -> write -> futimes -> close sequence to avoid opening the file twice: // // one with writeFile and one with utimes // const fd = await open(dest, 'w', data.mode); // try { // const buffer = await readFileBuffer(src); // await write(fd, buffer, 0, buffer.length); // await fixTimes(fd, dest, data); // } finally { // await close(fd); // } // }; // // We want to preserve file timestamps when copying a file, since pika uses them to decide if a file has // // changed compared to the cache. // // There are some OS specific cases here: // // * On linux, fs.copyFile does not preserve timestamps, but does on OSX and Win. // // * On windows, you must open a file with write permissions to call `fs.futimes`. // // * On OSX you can open with read permissions and still call `fs.futimes`. // async function fixTimes(fd: number | undefined, dest: string, data: CopyFileAction): Promise { // const doOpen = fd === undefined; // let openfd: number = fd ? fd : -1; // if (disableTimestampCorrection === undefined) { // // if timestamps match already, no correction is needed. // // the need to correct timestamps varies based on OS and node versions. // const destStat = await lstat(dest); // disableTimestampCorrection = fileDatesEqual(destStat.mtime, data.mtime); // } // if (disableTimestampCorrection) { // return; // } // if (doOpen) { // try { // openfd = await open(dest, 'a', data.mode); // } catch (er) { // // file is likely read-only // try { // openfd = await open(dest, 'r', data.mode); // } catch (err) { // // We can't even open this file for reading. // return; // } // } // } // try { // if (openfd) { // await futimes(openfd, data.atime, data.mtime); // } // } catch (er) { // // If `futimes` throws an exception, we probably have a case of a read-only file on Windows. // // In this case we can just return. The incorrect timestamp will just cause that file to be recopied // // on subsequent installs, which will effect pika performance but not break anything. // } finally { // if (doOpen && openfd) { // await close(openfd); // } // } // } // // Compare file timestamps. // // Some versions of Node on windows zero the milliseconds when utime is used. // export const fileDatesEqual = (a: Date, b: Date) => { // const aTime = a.getTime(); // const bTime = b.getTime(); // if (process.platform !== 'win32') { // return aTime === bTime; // } // // See https://github.com/nodejs/node/pull/12607 // // Submillisecond times from stat and utimes are truncated on Windows, // // causing a file with mtime 8.0079998 and 8.0081144 to become 8.007 and 8.008 // // and making it impossible to update these files to their correct timestamps. // if (Math.abs(aTime - bTime) <= 1) { // return true; // } // const aTimeSec = Math.floor(aTime / 1000); // const bTimeSec = Math.floor(bTime / 1000); // // See https://github.com/nodejs/node/issues/2069 // // Some versions of Node on windows zero the milliseconds when utime is used // // So if any of the time has a milliseconds part of zero we suspect that the // // bug is present and compare only seconds. // if (aTime - aTimeSec * 1000 === 0 || bTime - bTimeSec * 1000 === 0) { // return aTimeSec === bTimeSec; // } // return aTime === bTime; // }; ================================================ FILE: checkpoint/dist-src/util/fs.js ================================================ import { promisify } from 'util'; import _rimraf from 'rimraf'; import _mkdirp from 'mkdirp'; import _glob from 'glob'; export const unlink = promisify(_rimraf); export const glob = promisify(_glob); export const mkdirp = promisify(_mkdirp); // // import {ReadStream} from 'fs'; // import Reporter from '../reporters/base-reporter.js'; // import {CopyFileAction} from './fs-normalized.js'; import * as os from 'os'; import * as path from 'path'; // import BlockingQueue from './blocking-queue.js'; // import * as promise from './promise.js'; import map from './map.js'; // import {copyFile, fileDatesEqual, unlink} from './fs-normalized.js'; // export const constants = // typeof fs.constants !== 'undefined' // ? fs.constants // : { // R_OK: fs.R_OK, // W_OK: fs.W_OK, // X_OK: fs.X_OK, // }; // export const lockQueue = new BlockingQueue('fs lock'); import * as fs from 'fs'; import * as util from 'util'; export const open = util.promisify(fs.open); export const writeFile = util.promisify(fs.writeFile); export const readlink = util.promisify(fs.readlink); export const realpath = util.promisify(fs.realpath); export const readdir = util.promisify(fs.readdir); export const rename = util.promisify(fs.rename); export const access = util.promisify(fs.access); export const stat = util.promisify(fs.stat); export const exists = util.promisify(fs.exists); export const lstat = util.promisify(fs.lstat); export const chmod = util.promisify(fs.chmod); export const link = util.promisify(fs.link); export const copyFile = util.promisify(fs.copyFile); const readFileBuffer = util.promisify(fs.readFile); export const readFile = (path) => { return util.promisify(fs.readFile)(path, { encoding: 'utf-8' }); }; // export {unlink}; // // fs.copyFile uses the native file copying instructions on the system, performing much better // // than any JS-based solution and consumes fewer resources. Repeated testing to fine tune the // // concurrency level revealed 128 as the sweet spot on a quad-core, 16 CPU Intel system with SSD. // const CONCURRENT_QUEUE_ITEMS = fs.copyFile ? 128 : 4; // const fsSymlink: (target: string, path: string, type?: 'dir' | 'file' | 'junction') => Promise = promisify( // fs.symlink, // ); // import invariant from 'invariant'; import stripBOM from 'strip-bom'; // const noop = () => {}; // export type CopyQueueItem = { // src: string, // dest: string, // type?: string, // onFresh?: () => void, // onDone?: () => void, // }; // type CopyQueue = Array; // type LinkFileAction = { // src: string, // dest: string, // removeDest: boolean, // }; // type CopySymlinkAction = { // dest: string, // linkname: string, // }; // type CopyActions = { // file: Array, // symlink: Array, // link: Array, // }; // type CopyOptions = { // onProgress: (dest: string) => void, // onStart: (num: number) => void, // possibleExtraneous: Set, // ignoreBasenames: Array, // artifactFiles: Array, // }; // type FailedFolderQuery = { // error: Error, // folder: string, // }; // type FolderQueryResult = { // skipped: Array, // folder?: string, // }; // async function buildActionsForCopy( // queue: CopyQueue, // events: CopyOptions, // possibleExtraneous: Set, // reporter: Reporter, // ): Promise { // const artifactFiles: Set = new Set(events.artifactFiles || []); // const files: Set = new Set(); // // initialise events // for (const item of queue) { // const onDone = item.onDone; // item.onDone = () => { // events.onProgress(item.dest); // if (onDone) { // onDone(); // } // }; // } // events.onStart(queue.length); // // start building actions // const actions: CopyActions = { // file: [], // symlink: [], // link: [], // }; // // custom concurrency logic as we're always executing stacks of CONCURRENT_QUEUE_ITEMS queue items // // at a time due to the requirement to push items onto the queue // while (queue.length) { // const items = queue.splice(0, CONCURRENT_QUEUE_ITEMS); // await Promise.all(items.map(build)); // } // // simulate the existence of some files to prevent considering them extraneous // for (const file of artifactFiles) { // if (possibleExtraneous.has(file)) { // reporter.verbose(reporter.lang('verboseFilePhantomExtraneous', file)); // possibleExtraneous.delete(file); // } // } // for (const loc of possibleExtraneous) { // if (files.has(loc.toLowerCase())) { // possibleExtraneous.delete(loc); // } // } // return actions; // // // async function build(data: CopyQueueItem): Promise { // const {src, dest, type} = data; // const onFresh = data.onFresh || noop; // const onDone = data.onDone || noop; // // TODO https://github.com/yarnpkg/yarn/issues/3751 // // related to bundled dependencies handling // if (files.has(dest.toLowerCase())) { // reporter.verbose(`The case-insensitive file ${dest} shouldn't be copied twice in one bulk copy`); // } else { // files.add(dest.toLowerCase()); // } // if (type === 'symlink') { // await mkdirp(path.dirname(dest)); // onFresh(); // actions.symlink.push({ // dest, // linkname: src, // }); // onDone(); // return; // } // if (events.ignoreBasenames.indexOf(path.basename(src)) >= 0) { // // ignored file // return; // } // const srcStat = await lstat(src); // let srcFiles; // if (srcStat.isDirectory()) { // srcFiles = await readdir(src); // } // let destStat; // try { // // try accessing the destination // destStat = await lstat(dest); // } catch (e) { // // proceed if destination doesn't exist, otherwise error // if (e.code !== 'ENOENT') { // throw e; // } // } // // if destination exists // if (destStat) { // const bothSymlinks = srcStat.isSymbolicLink() && destStat.isSymbolicLink(); // const bothFolders = srcStat.isDirectory() && destStat.isDirectory(); // const bothFiles = srcStat.isFile() && destStat.isFile(); // // EINVAL access errors sometimes happen which shouldn't because node shouldn't be giving // // us modes that aren't valid. investigate this, it's generally safe to proceed. // /* if (srcStat.mode !== destStat.mode) { // try { // await access(dest, srcStat.mode); // } catch (err) {} // } */ // if (bothFiles && artifactFiles.has(dest)) { // // this file gets changed during build, likely by a custom install script. Don't bother checking it. // onDone(); // reporter.verbose(reporter.lang('verboseFileSkipArtifact', src)); // return; // } // if (bothFiles && srcStat.size === destStat.size && fileDatesEqual(srcStat.mtime, destStat.mtime)) { // // we can safely assume this is the same file // onDone(); // reporter.verbose(reporter.lang('verboseFileSkip', src, dest, srcStat.size, +srcStat.mtime)); // return; // } // if (bothSymlinks) { // const srcReallink = await readlink(src); // if (srcReallink === (await readlink(dest))) { // // if both symlinks are the same then we can continue on // onDone(); // reporter.verbose(reporter.lang('verboseFileSkipSymlink', src, dest, srcReallink)); // return; // } // } // if (bothFolders) { // // mark files that aren't in this folder as possibly extraneous // const destFiles = await readdir(dest); // invariant(srcFiles, 'src files not initialised'); // for (const file of destFiles) { // if (srcFiles.indexOf(file) < 0) { // const loc = path.join(dest, file); // possibleExtraneous.add(loc); // if ((await lstat(loc)).isDirectory()) { // for (const file of await readdir(loc)) { // possibleExtraneous.add(path.join(loc, file)); // } // } // } // } // } // } // if (destStat && destStat.isSymbolicLink()) { // await unlink(dest); // destStat = null; // } // if (srcStat.isSymbolicLink()) { // onFresh(); // const linkname = await readlink(src); // actions.symlink.push({ // dest, // linkname, // }); // onDone(); // } else if (srcStat.isDirectory()) { // if (!destStat) { // reporter.verbose(reporter.lang('verboseFileFolder', dest)); // await mkdirp(dest); // } // const destParts = dest.split(path.sep); // while (destParts.length) { // files.add(destParts.join(path.sep).toLowerCase()); // destParts.pop(); // } // // push all files to queue // invariant(srcFiles, 'src files not initialised'); // let remaining = srcFiles.length; // if (!remaining) { // onDone(); // } // for (const file of srcFiles) { // queue.push({ // dest: path.join(dest, file), // onFresh, // onDone: () => { // if (--remaining === 0) { // onDone(); // } // }, // src: path.join(src, file), // }); // } // } else if (srcStat.isFile()) { // onFresh(); // actions.file.push({ // src, // dest, // atime: srcStat.atime, // mtime: srcStat.mtime, // mode: srcStat.mode, // }); // onDone(); // } else { // throw new Error(`unsure how to copy this: ${src}`); // } // } // } // async function buildActionsForHardlink( // queue: CopyQueue, // events: CopyOptions, // possibleExtraneous: Set, // reporter: Reporter, // ): Promise { // const artifactFiles: Set = new Set(events.artifactFiles || []); // const files: Set = new Set(); // // initialise events // for (const item of queue) { // const onDone = item.onDone || noop; // item.onDone = () => { // events.onProgress(item.dest); // onDone(); // }; // } // events.onStart(queue.length); // // start building actions // const actions: CopyActions = { // file: [], // symlink: [], // link: [], // }; // // custom concurrency logic as we're always executing stacks of CONCURRENT_QUEUE_ITEMS queue items // // at a time due to the requirement to push items onto the queue // while (queue.length) { // const items = queue.splice(0, CONCURRENT_QUEUE_ITEMS); // await Promise.all(items.map(build)); // } // // simulate the existence of some files to prevent considering them extraneous // for (const file of artifactFiles) { // if (possibleExtraneous.has(file)) { // reporter.verbose(reporter.lang('verboseFilePhantomExtraneous', file)); // possibleExtraneous.delete(file); // } // } // for (const loc of possibleExtraneous) { // if (files.has(loc.toLowerCase())) { // possibleExtraneous.delete(loc); // } // } // return actions; // // // async function build(data: CopyQueueItem): Promise { // const {src, dest} = data; // const onFresh = data.onFresh || noop; // const onDone = data.onDone || noop; // if (files.has(dest.toLowerCase())) { // // Fixes issue https://github.com/yarnpkg/yarn/issues/2734 // // When bulk hardlinking we have A -> B structure that we want to hardlink to A1 -> B1, // // package-linker passes that modules A1 and B1 need to be hardlinked, // // the recursive linking algorithm of A1 ends up scheduling files in B1 to be linked twice which will case // // an exception. // onDone(); // return; // } // files.add(dest.toLowerCase()); // if (events.ignoreBasenames.indexOf(path.basename(src)) >= 0) { // // ignored file // return; // } // const srcStat = await lstat(src); // let srcFiles; // if (srcStat.isDirectory()) { // srcFiles = await readdir(src); // } // const destExists = await exists(dest); // if (destExists) { // const destStat = await lstat(dest); // const bothSymlinks = srcStat.isSymbolicLink() && destStat.isSymbolicLink(); // const bothFolders = srcStat.isDirectory() && destStat.isDirectory(); // const bothFiles = srcStat.isFile() && destStat.isFile(); // if (srcStat.mode !== destStat.mode) { // try { // await access(dest, srcStat.mode); // } catch (err) { // // EINVAL access errors sometimes happen which shouldn't because node shouldn't be giving // // us modes that aren't valid. investigate this, it's generally safe to proceed. // reporter.verbose(err); // } // } // if (bothFiles && artifactFiles.has(dest)) { // // this file gets changed during build, likely by a custom install script. Don't bother checking it. // onDone(); // reporter.verbose(reporter.lang('verboseFileSkipArtifact', src)); // return; // } // // correct hardlink // if (bothFiles && srcStat.ino !== null && srcStat.ino === destStat.ino) { // onDone(); // reporter.verbose(reporter.lang('verboseFileSkip', src, dest, srcStat.ino)); // return; // } // if (bothSymlinks) { // const srcReallink = await readlink(src); // if (srcReallink === (await readlink(dest))) { // // if both symlinks are the same then we can continue on // onDone(); // reporter.verbose(reporter.lang('verboseFileSkipSymlink', src, dest, srcReallink)); // return; // } // } // if (bothFolders) { // // mark files that aren't in this folder as possibly extraneous // const destFiles = await readdir(dest); // invariant(srcFiles, 'src files not initialised'); // for (const file of destFiles) { // if (srcFiles.indexOf(file) < 0) { // const loc = path.join(dest, file); // possibleExtraneous.add(loc); // if ((await lstat(loc)).isDirectory()) { // for (const file of await readdir(loc)) { // possibleExtraneous.add(path.join(loc, file)); // } // } // } // } // } // } // if (srcStat.isSymbolicLink()) { // onFresh(); // const linkname = await readlink(src); // actions.symlink.push({ // dest, // linkname, // }); // onDone(); // } else if (srcStat.isDirectory()) { // reporter.verbose(reporter.lang('verboseFileFolder', dest)); // await mkdirp(dest); // const destParts = dest.split(path.sep); // while (destParts.length) { // files.add(destParts.join(path.sep).toLowerCase()); // destParts.pop(); // } // // push all files to queue // invariant(srcFiles, 'src files not initialised'); // let remaining = srcFiles.length; // if (!remaining) { // onDone(); // } // for (const file of srcFiles) { // queue.push({ // onFresh, // src: path.join(src, file), // dest: path.join(dest, file), // onDone: () => { // if (--remaining === 0) { // onDone(); // } // }, // }); // } // } else if (srcStat.isFile()) { // onFresh(); // actions.link.push({ // src, // dest, // removeDest: destExists, // }); // onDone(); // } else { // throw new Error(`unsure how to copy this: ${src}`); // } // } // } // export function copy(src: string, dest: string, reporter: Reporter): Promise { // return copyBulk([{src, dest}], reporter); // } // export async function copyBulk( // queue: CopyQueue, // reporter: Reporter, // _events?: { // onProgress?: (dest: string) => void, // onStart?: (num: number) => void, // possibleExtraneous: Set, // ignoreBasenames?: Array, // artifactFiles?: Array, // }, // ): Promise { // const events: CopyOptions = { // onStart: (_events && _events.onStart) || noop, // onProgress: (_events && _events.onProgress) || noop, // possibleExtraneous: _events ? _events.possibleExtraneous : new Set(), // ignoreBasenames: (_events && _events.ignoreBasenames) || [], // artifactFiles: (_events && _events.artifactFiles) || [], // }; // const actions: CopyActions = await buildActionsForCopy(queue, events, events.possibleExtraneous, reporter); // events.onStart(actions.file.length + actions.symlink.length + actions.link.length); // const fileActions: Array = actions.file; // const currentlyWriting: Map> = new Map(); // await promise.queue( // fileActions, // async (data: CopyFileAction): Promise => { // let writePromise; // while ((writePromise = currentlyWriting.get(data.dest))) { // await writePromise; // } // reporter.verbose(reporter.lang('verboseFileCopy', data.src, data.dest)); // const copier = copyFile(data, () => currentlyWriting.delete(data.dest)); // currentlyWriting.set(data.dest, copier); // events.onProgress(data.dest); // return copier; // }, // CONCURRENT_QUEUE_ITEMS, // ); // // we need to copy symlinks last as they could reference files we were copying // const symlinkActions: Array = actions.symlink; // await promise.queue(symlinkActions, (data): Promise => { // const linkname = path.resolve(path.dirname(data.dest), data.linkname); // reporter.verbose(reporter.lang('verboseFileSymlink', data.dest, linkname)); // return symlink(linkname, data.dest); // }); // } // export async function hardlinkBulk( // queue: CopyQueue, // reporter: Reporter, // _events?: { // onProgress?: (dest: string) => void, // onStart?: (num: number) => void, // possibleExtraneous: Set, // artifactFiles?: Array, // }, // ): Promise { // const events: CopyOptions = { // onStart: (_events && _events.onStart) || noop, // onProgress: (_events && _events.onProgress) || noop, // possibleExtraneous: _events ? _events.possibleExtraneous : new Set(), // artifactFiles: (_events && _events.artifactFiles) || [], // ignoreBasenames: [], // }; // const actions: CopyActions = await buildActionsForHardlink(queue, events, events.possibleExtraneous, reporter); // events.onStart(actions.file.length + actions.symlink.length + actions.link.length); // const fileActions: Array = actions.link; // await promise.queue( // fileActions, // async (data): Promise => { // reporter.verbose(reporter.lang('verboseFileLink', data.src, data.dest)); // if (data.removeDest) { // await unlink(data.dest); // } // await link(data.src, data.dest); // }, // CONCURRENT_QUEUE_ITEMS, // ); // // we need to copy symlinks last as they could reference files we were copying // const symlinkActions: Array = actions.symlink; // await promise.queue(symlinkActions, (data): Promise => { // const linkname = path.resolve(path.dirname(data.dest), data.linkname); // reporter.verbose(reporter.lang('verboseFileSymlink', data.dest, linkname)); // return symlink(linkname, data.dest); // }); // } // function _readFile(loc: string, encoding: string): Promise { // return new Promise((resolve, reject) => { // fs.readFile(loc, encoding, function(err, content) { // if (err) { // reject(err); // } else { // resolve(content); // } // }); // }); // } // export function readFile(loc: string): Promise { // return _readFile(loc, 'utf8').then(normalizeOS); // } // export function readFileRaw(loc: string): Promise { // return _readFile(loc, 'binary'); // } // export async function readFileAny(files: Array): Promise { // for (const file of files) { // if (await exists(file)) { // return readFile(file); // } // } // return null; // } export async function readJson(loc) { return (await readJsonAndFile(loc)).object; } export async function readJsonAndFile(loc) { const file = await readFile(loc); try { return { object: map(JSON.parse(stripBOM(file))), content: file, }; } catch (err) { err.message = `${loc}: ${err.message}`; throw err; } } export async function walk(dir, relativeDir, ignoreBasenames = new Set()) { let files = []; let filenames = await readdir(dir); if (ignoreBasenames.size) { filenames = filenames.filter(name => !ignoreBasenames.has(name)); } for (const name of filenames) { const relative = relativeDir ? path.join(relativeDir, name) : name; const loc = path.join(dir, name); const stat = await lstat(loc); files.push({ relative, basename: name, absolute: loc, mtime: +stat.mtime, }); if (stat.isDirectory()) { files = files.concat(await walk(loc, relative, ignoreBasenames)); } } return files; } // export async function getFileSizeOnDisk(loc: string): Promise { // const stat = await lstat(loc); // const {size, blksize: blockSize} = stat; // return Math.ceil(size / blockSize) * blockSize; // } // export function normalizeOS(body: string): string { // return body.replace(/\r\n/g, '\n'); // } const cr = '\r'.charCodeAt(0); const lf = '\n'.charCodeAt(0); async function getEolFromFile(path) { if (!(await exists(path))) { return undefined; } const buffer = await readFileBuffer(path); for (let i = 0; i < buffer.length; ++i) { if (buffer[i] === cr) { return '\r\n'; } if (buffer[i] === lf) { return '\n'; } } return undefined; } export async function writeFilePreservingEol(path, data) { const eol = (await getEolFromFile(path)) || os.EOL; if (eol !== '\n') { data = data.replace(/\n/g, eol); } await writeFile(path, data); } // export async function hardlinksWork(dir: string): Promise { // const filename = 'test-file' + Math.random(); // const file = path.join(dir, filename); // const fileLink = path.join(dir, filename + '-link'); // try { // await writeFile(file, 'test'); // await link(file, fileLink); // } catch (err) { // return false; // } finally { // await unlink(file); // await unlink(fileLink); // } // return true; // } // // not a strict polyfill for Node's fs.mkdtemp // export async function makeTempDir(prefix?: string): Promise { // const dir = path.join(os.tmpdir(), `pika-${prefix || ''}-${Date.now()}-${Math.random()}`); // await unlink(dir); // await mkdirp(dir); // return dir; // } // export async function readFirstAvailableStream(paths: Iterable): Promise { // for (const path of paths) { // try { // const fd = await open(path, 'r'); // return fs.createReadStream(path, {fd}); // } catch (err) { // // Try the next one // } // } // return null; // } // export async function getFirstSuitableFolder( // paths: Iterable, // mode: number = constants.W_OK | constants.X_OK, // eslint-disable-line no-bitwise // ): Promise { // const result: FolderQueryResult = { // skipped: [], // folder: null, // }; // for (const folder of paths) { // try { // await mkdirp(folder); // await access(folder, mode); // result.folder = folder; // return result; // } catch (error) { // result.skipped.push({ // error, // folder, // }); // } // } // return result; // } ================================================ FILE: checkpoint/dist-src/util/map.js ================================================ export default function nullify(obj) { if (Array.isArray(obj)) { for (const item of obj) { nullify(item); } } else if ((obj !== null && typeof obj === 'object') || typeof obj === 'function') { Object.setPrototypeOf(obj, null); // for..in can only be applied to 'object', not 'function' if (typeof obj === 'object') { for (const key in obj) { nullify(obj[key]); } } } return obj; } ================================================ FILE: checkpoint/dist-src/util/misc.js ================================================ /* @flow */ import _camelCase from 'camelcase'; export function sortAlpha(a, b) { // sort alphabetically in a deterministic way const shortLen = Math.min(a.length, b.length); for (let i = 0; i < shortLen; i++) { const aChar = a.charCodeAt(i); const bChar = b.charCodeAt(i); if (aChar !== bChar) { return aChar - bChar; } } return a.length - b.length; } export function sortOptionsByFlags(a, b) { const aOpt = a.flags.replace(/-/g, ''); const bOpt = b.flags.replace(/-/g, ''); return sortAlpha(aOpt, bOpt); } export function entries(obj) { const entries = []; if (obj) { for (const key in obj) { entries.push([key, obj[key]]); } } return entries; } export function removePrefix(pattern, prefix) { if (pattern.startsWith(prefix)) { pattern = pattern.slice(prefix.length); } return pattern; } export function removeSuffix(pattern, suffix) { if (pattern.endsWith(suffix)) { return pattern.slice(0, -suffix.length); } return pattern; } export function addSuffix(pattern, suffix) { if (!pattern.endsWith(suffix)) { return pattern + suffix; } return pattern; } export function hyphenate(str) { return str.replace(/[A-Z]/g, match => { return '-' + match.charAt(0).toLowerCase(); }); } export function camelCase(str) { if (/[A-Z]/.test(str)) { return null; } else { return _camelCase(str); } } export function compareSortedArrays(array1, array2) { if (array1.length !== array2.length) { return false; } for (let i = 0, len = array1.length; i < len; i++) { if (array1[i] !== array2[i]) { return false; } } return true; } export function sleep(ms) { return new Promise(resolve => { setTimeout(resolve, ms); }); } ================================================ FILE: checkpoint/dist-src/util/normalize-manifest/fix.js ================================================ import { MANIFEST_FIELDS } from '../../constants.js'; import { isValidLicense } from './util.js'; import { normalizePerson, extractDescription } from './util.js'; import inferLicense from './infer-license.js'; import * as fs from '../fs.js'; import semver from 'semver'; import * as path from 'path'; import * as nodeUrl from 'url'; const LICENSE_RENAMES = { 'MIT/X11': 'MIT', X11: 'MIT', }; export default (async function (info, moduleLoc, reporter, warn) { const files = await fs.readdir(moduleLoc); // clean info.version if (typeof info.version === 'string') { info.version = semver.clean(info.version) || info.version; } // if name or version aren't set then set them to empty strings info.name = info.name || ''; info.version = info.version || ''; // if the man field is a string then coerce it to an array if (typeof info.man === 'string') { info.man = [info.man]; } // if the keywords field is a string then split it on any whitespace if (typeof info.keywords === 'string') { info.keywords = info.keywords.split(/\s+/g); } // if there's no contributors field but an authors field then expand it if (!info.contributors && files.indexOf('AUTHORS') >= 0) { const authorsFilepath = path.join(moduleLoc, 'AUTHORS'); const authorsFilestats = await fs.stat(authorsFilepath); if (authorsFilestats.isFile()) { let authors = await fs.readFile(authorsFilepath); info.contributors = authors .split(/\r?\n/g) // split on lines .map((line) => line.replace(/^\s*#.*$/, '').trim()) // remove comments .filter((line) => !!line); // remove empty lines; } } // expand people fields to objects if (typeof info.author === 'string' || typeof info.author === 'object') { info.author = normalizePerson(info.author); } if (Array.isArray(info.contributors)) { info.contributors = info.contributors.map(normalizePerson); } if (Array.isArray(info.maintainers)) { info.maintainers = info.maintainers.map(normalizePerson); } // if there's no readme field then load the README file from the cwd if (!info.readme) { const readmeCandidates = files .filter((filename) => { const lower = filename.toLowerCase(); return lower === 'readme' || lower.indexOf('readme.') === 0; }) .sort((filename1, filename2) => { // favor files with extensions return filename2.indexOf('.') - filename1.indexOf('.'); }); for (const readmeFilename of readmeCandidates) { const readmeFilepath = path.join(moduleLoc, readmeFilename); const readmeFileStats = await fs.stat(readmeFilepath); if (readmeFileStats.isFile()) { info.readmeFilename = readmeFilename; info.readme = await fs.readFile(readmeFilepath); break; } } } // if there's no description then take the first paragraph from the readme if (!info.description && info.readme) { const desc = extractDescription(info.readme); if (desc) { info.description = desc; } } // support array of engine keys if (Array.isArray(info.engines)) { const engines = {}; for (const str of info.engines) { if (typeof str === 'string') { const [name, ...patternParts] = str.trim().split(/ +/g); engines[name] = patternParts.join(' '); } } info.engines = engines; } // allow bugs to be specified as a string, expand it to an object with a single url prop if (typeof info.bugs === 'string') { info.bugs = { url: info.bugs }; } // normalize homepage url to http if (typeof info.homepage === 'string') { const parts = nodeUrl.parse(info.homepage); parts.protocol = parts.protocol || 'http:'; if (parts.pathname && !parts.hostname) { parts.hostname = parts.pathname; parts.pathname = ''; } info.homepage = nodeUrl.format(parts); } // if the `bin` field is as string then expand it to an object with a single property // based on the original `bin` field and `name field` // { name: "foo", bin: "cli.js" } -> { name: "foo", bin: { foo: "cli.js" } } if (typeof info.name === 'string' && typeof info.bin === 'string' && info.bin.length > 0) { // Remove scoped package name for consistency with NPM's bin field fixing behaviour const name = info.name.replace(/^@[^\/]+\//, ''); info.bin = { [name]: info.bin }; } // bundleDependencies is an alias for bundledDependencies if (info.bundledDependencies) { info.bundleDependencies = info.bundledDependencies; delete info.bundledDependencies; } let scripts; // dummy script object to shove file inferred scripts onto if (info.scripts && typeof info.scripts === 'object') { scripts = info.scripts; } else { scripts = {}; } // if there's a server.js file and no start script then set it to `node server.js` if (!scripts.start && files.indexOf('server.js') >= 0) { scripts.start = 'node server'; } // if there's a binding.gyp file and no install script then set it to `node-gyp rebuild` if (!scripts.install && files.indexOf('binding.gyp') >= 0) { scripts.install = 'node-gyp rebuild'; } // set scripts if we've polluted the empty object if (Object.keys(scripts).length) { info.scripts = scripts; } const dirs = info.directories; if (dirs && typeof dirs === 'object') { const binDir = dirs.bin; if (!info.bin && binDir && typeof binDir === 'string') { const bin = (info.bin = {}); const fullBinDir = path.join(moduleLoc, binDir); if (await fs.exists(fullBinDir)) { for (const scriptName of await fs.readdir(fullBinDir)) { if (scriptName[0] === '.') { continue; } bin[scriptName] = path.join('.', binDir, scriptName); } } else { warn(reporter.lang('manifestDirectoryNotFound', binDir, info.name)); } } const manDir = dirs.man; if (!info.man && typeof manDir === 'string') { const man = (info.man = []); const fullManDir = path.join(moduleLoc, manDir); if (await fs.exists(fullManDir)) { for (const filename of await fs.readdir(fullManDir)) { if (/^(.*?)\.[0-9]$/.test(filename)) { man.push(path.join('.', manDir, filename)); } } } else { warn(reporter.lang('manifestDirectoryNotFound', manDir, info.name)); } } } delete info.directories; // normalize licenses field const licenses = info.licenses; if (Array.isArray(licenses) && !info.license) { let licenseTypes = []; for (let license of licenses) { if (license && typeof license === 'object') { license = license.type; } if (typeof license === 'string') { licenseTypes.push(license); } } licenseTypes = licenseTypes.filter(isValidLicense); if (licenseTypes.length === 1) { info.license = licenseTypes[0]; } else if (licenseTypes.length) { info.license = `(${licenseTypes.join(' OR ')})`; } } const license = info.license; // normalize license if (license && typeof license === 'object') { info.license = license.type; } // get license file const licenseFile = files.find((filename) => { const lower = filename.toLowerCase(); return (lower === 'license' || lower.startsWith('license.') || lower === 'unlicense' || lower.startsWith('unlicense.')); }); if (licenseFile) { const licenseFilepath = path.join(moduleLoc, licenseFile); const licenseFileStats = await fs.stat(licenseFilepath); if (licenseFileStats.isFile()) { const licenseContent = await fs.readFile(licenseFilepath); const inferredLicense = inferLicense(licenseContent); info.licenseText = licenseContent; const license = info.license; if (typeof license === 'string') { if (inferredLicense && isValidLicense(inferredLicense) && !isValidLicense(license)) { // some packages don't specify their license version but we can infer it based on their license file const basicLicense = license.toLowerCase().replace(/(-like|\*)$/g, ''); const expandedLicense = inferredLicense.toLowerCase(); if (expandedLicense.startsWith(basicLicense)) { // TODO consider doing something to notify the user info.license = inferredLicense; } } } else if (inferredLicense) { // if there's no license then infer it based on the license file info.license = inferredLicense; } else { // valid expression to refer to a license in a file info.license = `SEE LICENSE IN ${licenseFile}`; } } } if (typeof info.license === 'string') { // sometimes licenses are known by different names, reduce them info.license = LICENSE_RENAMES[info.license] || info.license; } else if (typeof info.readme === 'string') { // the license might be at the bottom of the README const inferredLicense = inferLicense(info.readme); if (inferredLicense) { info.license = inferredLicense; } } // get notice file const noticeFile = files.find((filename) => { const lower = filename.toLowerCase(); return lower === 'notice' || lower.startsWith('notice.'); }); if (noticeFile) { const noticeFilepath = path.join(moduleLoc, noticeFile); const noticeFileStats = await fs.stat(noticeFilepath); if (noticeFileStats.isFile()) { info.noticeText = await fs.readFile(noticeFilepath); } } for (const dependencyType of MANIFEST_FIELDS) { const dependencyList = info[dependencyType]; if (dependencyList && typeof dependencyList === 'object') { delete dependencyList['//']; for (const name in dependencyList) { dependencyList[name] = dependencyList[name] || ''; } } } }); ================================================ FILE: checkpoint/dist-src/util/normalize-manifest/for-publish.js ================================================ export async function generatePublishManifest(manifest, config, _dists) { const { name, version, description, keywords, homepage, bugs, bin, license, authors, contributors, man, sideEffects, repository, dependencies, peerDependencies, devDependencies, bundledDependencies, optionalDependencies, engines, enginesStrict, private: priv, publishConfig, } = manifest; const newManifest = { name, description, version, license, bin, files: ['dist-*/', 'bin/'], pika: true, sideEffects: sideEffects || false, keywords, homepage, bugs, authors, contributors, man, repository, dependencies: dependencies || {}, peerDependencies, devDependencies, bundledDependencies, optionalDependencies, engines, enginesStrict, private: priv, publishConfig, }; const dists = _dists || (await config.getDistributions()); for (const [runner, options] of dists) { if (runner.manifest) { await runner.manifest(newManifest, { cwd: config.cwd, isFull: true, manifest, options, }); } } newManifest.pika = true; return newManifest; } export function generatePrettyManifest(manifest) { return JSON.stringify({ ...manifest, dependencies: Object.keys(manifest.dependencies).length === 0 ? {} : '{ ... }', }, null, 2); } ================================================ FILE: checkpoint/dist-src/util/normalize-manifest/index.js ================================================ import validate from './validate.js'; import fix from './fix.js'; import * as path from 'path'; export default (async function (info, moduleLoc, config, isRoot) { // Append dependencies // if (depInfo) { // info.dependencies = depInfo.main; // info.devDependencies = depInfo.dev; // } // create human readable name const { name, version } = info; let human; if (typeof name === 'string') { human = name; } if (human && typeof version === 'string' && version) { human += `@${version}`; } if (isRoot && info._loc) { human = path.relative(config.cwd, info._loc); } function warn(msg) { if (human) { msg = `${human}: ${msg}`; } config.reporter.warn(msg); } await fix(info, moduleLoc, config.reporter, warn); try { validate(info, isRoot, config.reporter, warn); } catch (err) { if (human) { err.message = `${human}: ${err.message}`; } throw err; } return info; }); ================================================ FILE: checkpoint/dist-src/util/normalize-manifest/infer-license.js ================================================ import LICENSES from './licenses.js'; function clean(str) { return str.replace(/[^A-Za-z\s]/g, ' ').replace(/[\s]+/g, ' ').trim().toLowerCase(); } const REGEXES = { Apache: [/Apache License\b/], BSD: [/BSD\b/], ISC: [/The ISC License/, /ISC\b/], MIT: [/MIT\b/], Unlicense: [/http:\/\/unlicense.org\//], WTFPL: [/DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE/, /WTFPL\b/], }; export default function inferLicense(license) { // check if we have any explicit licenses const cleanLicense = clean(license); for (const licenseName in LICENSES) { const testLicense = LICENSES[licenseName]; if (cleanLicense.search(testLicense) >= 0) { return licenseName; } } // infer based on some keywords for (const licenseName in REGEXES) { for (const regex of REGEXES[licenseName]) { if (license.search(regex) >= 0) { return `${licenseName}*`; } } } return null; } ================================================ FILE: checkpoint/dist-src/util/normalize-manifest/licenses.js ================================================ export default ({ 'Apache-2.0': new RegExp('(licensed under the apache license version the license you may not use this file except in compliance with the license you may obtain a copy of the license at http www apache org licenses license unless required by applicable law or agreed to in writing software distributed under the license is distributed on an as is basis without warranties or conditions of any kind either express or implied see the license for the specific language governing permissions and limitations under the license$|apache license version january http www apache org licenses terms and conditions for use reproduction and distribution definitions license shall mean the terms and conditions for use reproduction and distribution as defined by sections through of this document licensor shall mean the copyright owner or entity authorized by the copyright owner that is granting the license legal entity shall mean the union of the acting entity and all other entities that control are controlled by or are under common control with that entity for the purposes of this definition control means i the power direct or indirect to cause the direction or management of such entity whether by contract or otherwise or ii ownership of fifty percent or more of the outstanding shares or iii beneficial ownership of such entity you or your shall mean an individual or legal entity exercising permissions granted by this license source form shall mean the preferred form for making modifications including but not limited to software source code documentation source and configuration files object form shall mean any form resulting from mechanical transformation or translation of a source form including but not limited to compiled object code generated documentation and conversions to other media types work shall mean the work of authorship whether in source or object form made available under the license as indicated by a copyright notice that is included in or attached to the work an example is provided in the appendix below derivative works shall mean any work whether in source or object form that is based on or derived from the work and for which the editorial revisions annotations elaborations or other modifications represent as a whole an original work of authorship for the purposes of this license derivative works shall not include works that remain separable from or merely link or bind by name to the interfaces of the work and derivative works thereof contribution shall mean any work of authorship including the original version of the work and any modifications or additions to that work or derivative works thereof that is intentionally submitted to licensor for inclusion in the work by the copyright owner or by an individual or legal entity authorized to submit on behalf of the copyright owner for the purposes of this definition submitted means any form of electronic verbal or written communication sent to the licensor or its representatives including but not limited to communication on electronic mailing lists source code control systems and issue tracking systems that are managed by or on behalf of the licensor for the purpose of discussing and improving the work but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as not a contribution contributor shall mean licensor and any individual or legal entity on behalf of whom a contribution has been received by licensor and subsequently incorporated within the work grant of copyright license subject to the terms and conditions of this license each contributor hereby grants to you a perpetual worldwide non exclusive no charge royalty free irrevocable copyright license to reproduce prepare derivative works of publicly display publicly perform sublicense and distribute the work and such derivative works in source or object form grant of patent license subject to the terms and conditions of this license each contributor hereby grants to you a perpetual worldwide non exclusive no charge royalty free irrevocable except as stated in this section patent license to make have made use offer to sell sell import and otherwise transfer the work where such license applies only to those patent claims licensable by such contributor that are necessarily infringed by their contribution s alone or by combination of their contribution s with the work to which such contribution s was submitted if you institute patent litigation against any entity including a cross claim or counterclaim in a lawsuit alleging that the work or a contribution incorporated within the work constitutes direct or contributory patent infringement then any patent licenses granted to you under this license for that work shall terminate as of the date such litigation is filed redistribution you may reproduce and distribute copies of the work or derivative works thereof in any medium with or without modifications and in source or object form provided that you meet the following conditions a you must give any other recipients of the work or derivative works a copy of this license and b you must cause any modified files to carry prominent notices stating that you changed the files and c you must retain in the source form of any derivative works that you distribute all copyright patent trademark and attribution notices from the source form of the work excluding those notices that do not pertain to any part of the derivative works and d if the work includes a notice text file as part of its distribution then any derivative works that you distribute must include a readable copy of the attribution notices contained within such notice file excluding those notices that do not pertain to any part of the derivative works in at least one of the following places within a notice text file distributed as part of the derivative works within the source form or documentation if provided along with the derivative works or within a display generated by the derivative works if and wherever such third party notices normally appear the contents of the notice file are for informational purposes only and do not modify the license you may add your own attribution notices within derivative works that you distribute alongside or as an addendum to the notice text from the work provided that such additional attribution notices cannot be construed as modifying the license you may add your own copyright statement to your modifications and may provide additional or different license terms and conditions for use reproduction or distribution of your modifications or for any such derivative works as a whole provided your use reproduction and distribution of the work otherwise complies with the conditions stated in this license submission of contributions unless you explicitly state otherwise any contribution intentionally submitted for inclusion in the work by you to the licensor shall be under the terms and conditions of this license without any additional terms or conditions notwithstanding the above nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with licensor regarding such contributions trademarks this license does not grant permission to use the trade names trademarks service marks or product names of the licensor except as required for reasonable and customary use in describing the origin of the work and reproducing the content of the notice file disclaimer of warranty unless required by applicable law or agreed to in writing licensor provides the work and each contributor provides its contributions on an as is basis without warranties or conditions of any kind either express or implied including without limitation any warranties or conditions of title non infringement merchantability or fitness for a particular purpose you are solely responsible for determining the appropriateness of using or redistributing the work and assume any risks associated with your exercise of permissions under this license limitation of liability in no event and under no legal theory whether in tort including negligence contract or otherwise unless required by applicable law such as deliberate and grossly negligent acts or agreed to in writing shall any contributor be liable to you for damages including any direct indirect special incidental or consequential damages of any character arising as a result of this license or out of the use or inability to use the work including but not limited to damages for loss of goodwill work stoppage computer failure or malfunction or any and all other commercial damages or losses even if such contributor has been advised of the possibility of such damages accepting warranty or additional liability while redistributing the work or derivative works thereof you may choose to offer and charge a fee for acceptance of support warranty indemnity or other liability obligations and or rights consistent with this license however in accepting such obligations you may act only on your own behalf and on your sole responsibility not on behalf of any other contributor and only if you agree to indemnify defend and hold each contributor harmless for any liability incurred by or claims asserted against such contributor by reason of your accepting any such warranty or additional liability end of terms and conditions$)', 'g'), 'BSD-2-Clause': new RegExp('(redistribution and use in source and binary forms with or without modification are permitted provided that the following conditions are met redistributions of source code must retain the above copyright notice this list of conditions and the following disclaimer redistributions in binary form must reproduce the above copyright notice this list of conditions and the following disclaimer in the documentation and or other materials provided with the distribution this(.*?| )is provided by the copyright holders and contributors as is and any express or implied warranties including but not limited to the implied warranties of merchantability and fitness for a particular purpose are disclaimed in no event shall(.*?| )be liable for any direct indirect incidental special exemplary or consequential damages including but not limited to procurement of substitute goods or services loss of use data or profits or business interruption however caused and on any theory of liability whether in contract strict liability or tort including negligence or otherwise arising in any way out of the use of this(.*?| )even if advised of the possibility of such damage$|redistribution and use in source and binary forms with or without modification are permitted provided that the following conditions are met redistributions of source code must retain the above copyright notice this list of conditions and the following disclaimer redistributions in binary form must reproduce the above copyright notice this list of conditions and the following disclaimer in the documentation and or other materials provided with the distribution this software is provided by the copyright holders and contributors as is and any express or implied warranties including but not limited to the implied warranties of merchantability and fitness for a particular purpose are disclaimed in no event shall(.*?| )be liable for any direct indirect incidental special exemplary or consequential damages including but not limited to procurement of substitute goods or services loss of use data or profits or business interruption however caused and on any theory of liability whether in contract strict liability or tort including negligence or otherwise arising in any way out of the use of this software even if advised of the possibility of such damage$)', 'g'), 'BSD-3-Clause': new RegExp('(redistribution and use in source and binary forms with or without modification are permitted provided that the following conditions are met redistributions of source code must retain the above copyright notice this list of conditions and the following disclaimer redistributions in binary form must reproduce the above copyright notice this list of conditions and the following disclaimer in the documentation and or other materials provided with the distribution neither the name of(.*?| )nor the names of the contributors may be used to endorse or promote products derived from this software without specific prior written permission this software is provided by the copyright holders and contributors as is and any express or implied warranties including but not limited to the implied warranties of merchantability and fitness for a particular purpose are disclaimed in no event shall(.*?| )be liable for any direct indirect incidental special exemplary or consequential damages including but not limited to procurement of substitute goods or services loss of use data or profits or business interruption however caused and on any theory of liability whether in contract strict liability or tort including negligence or otherwise arising in any way out of the use of this software even if advised of the possibility of such damage$|(redistribution and use in source and binary forms with or without modification are permitted provided that the following conditions are met redistributions of source code must retain the above copyright notice this list of conditions and the following disclaimer redistributions in binary form must reproduce the above copyright notice this list of conditions and the following disclaimer in the documentation and or other materials provided with the distribution the names of any contributors may not be used to endorse or promote products derived from this software without specific prior written permission this software is provided by the copyright holders and contributors as is and any express or implied warranties including but not limited to the implied warranties of merchantability and fitness for a particular purpose are disclaimed in no event shall the copyright holders and contributors be liable for any direct indirect incidental special exemplary or consequential damages including but not limited to procurement of substitute goods or services loss of use data or profits or business interruption however caused and on any theory of liability whether in contract strict liability or tort including negligence or otherwise arising in any way out of the use of this software even if advised of the possibility of such damage$|redistribution and use in source and binary forms with or without modification are permitted provided that the following conditions are met redistributions of source code must retain the above copyright notice this list of conditions and the following disclaimer redistributions in binary form must reproduce the above copyright notice this list of conditions and the following disclaimer in the documentation and or other materials provided with the distribution neither the name(.*?| )nor the names of(.*?| )contributors may be used to endorse or promote products derived from this software without specific prior written permission this software is provided by(.*?| )as is and any express or implied warranties including but not limited to the implied warranties of merchantability and fitness for a particular purpose are disclaimed in no event shall(.*?| )be liable for any direct indirect incidental special exemplary or consequential damages including but not limited to procurement of substitute goods or services loss of use data or profits or business interruption however caused and on any theory of liability whether in contract strict liability or tort including negligence or otherwise arising in any way out of the use of this software even if advised of the possibility of such damage$))', 'g'), MIT: new RegExp('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$', 'g'), Unlicense: new RegExp('this is free and unencumbered software released into the public domain anyone is free to copy modify publish use compile sell or distribute this software either in source code form or as a compiled binary for any purpose commercial or non commercial and by any means in jurisdictions that recognize copyright laws the author or authors of this software dedicate any and all copyright interest in the software to the public domain we make this dedication for the benefit of the public at large and to the detriment of our heirs and successors we intend this dedication to be an overt act of relinquishment in perpetuity of all present and future rights to this software under copyright law 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 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 for more information please refer to wildcard$', 'g'), }); ================================================ FILE: checkpoint/dist-src/util/normalize-manifest/typos.js ================================================ export default { autohr: 'author', autor: 'author', contributers: 'contributors', depdenencies: 'dependencies', dependancies: 'dependencies', dependecies: 'dependencies', depends: 'dependencies', 'dev-dependencies': 'devDependencies', devDependences: 'devDependencies', devDepenencies: 'devDependencies', devEependencies: 'devDependencies', devdependencies: 'devDependencies', hampage: 'homepage', hompage: 'homepage', prefereGlobal: 'preferGlobal', publicationConfig: 'publishConfig', repo: 'repository', repostitory: 'repository', script: 'scripts', }; ================================================ FILE: checkpoint/dist-src/util/normalize-manifest/util.js ================================================ import validateLicense from 'validate-npm-package-license'; export function isValidLicense(license) { return !!license && validateLicense(license).validForNewPackages; } export function stringifyPerson(person) { if (!person || typeof person !== 'object') { return person; } const parts = []; if (person.name) { parts.push(person.name); } const email = person.email || person.mail; if (typeof email === 'string') { parts.push(`<${email}>`); } const url = person.url || person.web; if (typeof url === 'string') { parts.push(`(${url})`); } return parts.join(' '); } export function parsePerson(person) { if (typeof person !== 'string') { return person; } // format: name (url) const obj = {}; let name = person.match(/^([^\(<]+)/); if (name && name[0].trim()) { obj.name = name[0].trim(); } const email = person.match(/<([^>]+)>/); if (email) { obj.email = email[1]; } const url = person.match(/\(([^\)]+)\)/); if (url) { obj.url = url[1]; } return obj; } export function normalizePerson(person) { return parsePerson(stringifyPerson(person)); } export function extractDescription(readme) { if (typeof readme !== 'string' || readme === '') { return undefined; } // split into lines const lines = readme.trim().split('\n').map((line) => line.trim()); // find the start of the first paragraph, ignore headings let start = 0; for (; start < lines.length; start++) { const line = lines[start]; if (line && line.match(/^(#|$)/)) { // line isn't empty and isn't a heading so this is the start of a paragraph start++; break; } } // skip newlines from the header to the first line while (start < lines.length && !lines[start]) { start++; } // continue to the first non empty line let end = start; while (end < lines.length && lines[end]) { end++; } return lines.slice(start, end).join(' '); } ================================================ FILE: checkpoint/dist-src/util/normalize-manifest/validate.js ================================================ import { MessageError } from '@pika/types'; import typos from './typos.js'; import isBuiltinModule from 'is-builtin-module'; const strings = ['name', 'version']; const dependencyKeys = [ // npm registry will include optionalDependencies in dependencies and we'll want to dedupe them from the // other fields first 'optionalDependencies', // it's seemingly common to include a dependency in dependencies and devDependencies of the same name but // different ranges, this can cause a lot of issues with our determinism and the behaviour of npm is // currently unspecified. 'dependencies', 'devDependencies', ]; function isValidName(name) { return !name.match(/[\/@\s\+%:]/) && encodeURIComponent(name) === name; } function isValidScopedName(name) { if (name[0] !== '@') { return false; } const parts = name.slice(1).split('/'); return parts.length === 2 && isValidName(parts[0]) && isValidName(parts[1]); } export function isValidPackageName(name) { return isValidName(name) || isValidScopedName(name); } export default function (info, isRoot, reporter, warn) { if (isRoot) { for (const key in typos) { if (key in info) { warn(reporter.lang('manifestPotentialTypo', key, typos[key])); } } } // validate name const { name } = info; if (typeof name === 'string') { if (isRoot && isBuiltinModule(name)) { warn(reporter.lang('manifestBuiltinModule', name)); } // cannot start with a dot if (name[0] === '.') { throw new MessageError(reporter.lang('manifestNameDot')); } // cannot contain the following characters if (!isValidPackageName(name)) { throw new MessageError(reporter.lang('manifestNameIllegalChars')); } // cannot equal node_modules or favicon.ico const lower = name.toLowerCase(); if (lower === 'node_modules' || lower === 'favicon.ico') { throw new MessageError(reporter.lang('manifestNameBlacklisted')); } } // Only care if you are trying to publish to npm. // // validate license // if (isRoot && !info.private) { // if (typeof info.license === 'string') { // const license = info.license.replace(/\*$/g, ''); // if (!isValidLicense(license)) { // warn(reporter.lang('manifestLicenseInvalid')); // } // } else { // warn(reporter.lang('manifestLicenseNone')); // } // } // validate strings for (const key of strings) { const val = info[key]; if (val && typeof val !== 'string') { throw new MessageError(reporter.lang('manifestStringExpected', key)); } } cleanDependencies(info, isRoot, reporter, warn); } export function cleanDependencies(info, isRoot, reporter, warn) { // get dependency objects const depTypes = []; for (const type of dependencyKeys) { const deps = info[type]; if (!deps || typeof deps !== 'object') { continue; } depTypes.push([type, deps]); } // aggregate all non-trivial deps (not '' or '*') const nonTrivialDeps = new Map(); for (const [type, deps] of depTypes) { for (const name of Object.keys(deps)) { const version = deps[name]; if (!nonTrivialDeps.has(name) && version && version !== '*') { nonTrivialDeps.set(name, { type, version }); } } } // overwrite first dep of package with non-trivial version, remove the rest const setDeps = new Set(); for (const [type, deps] of depTypes) { for (const name of Object.keys(deps)) { let version = deps[name]; const dep = nonTrivialDeps.get(name); if (dep) { if (version && version !== '*' && version !== dep.version && isRoot) { // only throw a warning when at the root warn(reporter.lang('manifestDependencyCollision', dep.type, name, dep.version, type, version)); } version = dep.version; } if (setDeps.has(name)) { delete deps[name]; } else { deps[name] = version; setDeps.add(name); } } } } ================================================ FILE: checkpoint/dist-src/util/promise.js ================================================ export function wait(delay) { return new Promise(resolve => { setTimeout(resolve, delay); }); } export function promisify(fn, firstData) { return function (...args) { return new Promise(function (resolve, reject) { args.push(function (err, ...result) { let res = result; if (result.length <= 1) { res = result[0]; } if (firstData) { res = err; err = null; } if (err) { reject(err); } else { resolve(res); } }); fn.apply(null, args); }); }; } export function queue(arr, promiseProducer, concurrency = Infinity) { concurrency = Math.min(concurrency, arr.length); // clone arr = arr.slice(); const results = []; let total = arr.length; if (!total) { return Promise.resolve(results); } return new Promise((resolve, reject) => { for (let i = 0; i < concurrency; i++) { next(); } function next() { const item = arr.shift(); const promise = promiseProducer(item); promise.then(function (result) { results.push(result); total--; if (total === 0) { resolve(results); } else { if (arr.length) { next(); } } }, reject); } }); } ================================================ FILE: checkpoint/dist-src/util/signal-handler.js ================================================ import { forwardSignalToSpawnedProcesses } from './child.js'; function forwardSignalAndExit(signal) { forwardSignalToSpawnedProcesses(signal); // We want to exit immediately here since `SIGTERM` means that // If we lose stdout messages due to abrupt exit, shoot the messenger? process.exit(1); // eslint-disable-line no-process-exit } export default function handleSignals() { process.on('SIGTERM', () => { forwardSignalAndExit('SIGTERM'); }); } ================================================ FILE: checkpoint/dist-types/commands/build.d.ts ================================================ import Config, { BuildFlags } from '../config.js'; import { Reporter } from '../reporters/index.js'; export declare function hasWrapper(): boolean; export declare const examples: any; export declare class Build { constructor(flags: BuildFlags, config: Config, reporter: Reporter); out: string; flags: BuildFlags; config: Config; reporter: Reporter; totalNum: number; cleanup(): Promise; init(isFull?: boolean): Promise; } export declare function run(config: Config, reporter: Reporter, flags: BuildFlags, args: Array): Promise; ================================================ FILE: checkpoint/dist-types/config.d.ts ================================================ import { Manifest } from './types.js'; import BaseReporter from './reporters/base-reporter.js'; export interface BuildFlags { publish?: boolean; out?: string; silent?: boolean; force?: boolean; } export interface GlobalFlags extends BuildFlags { cwd?: string; pipeline?: string; verbose?: boolean; json?: boolean; } export default class Config { cwd: string; reporter: BaseReporter; _manifest: any; manifest: Manifest; flags: GlobalFlags; constructor(reporter: BaseReporter, cwd: string, flags: GlobalFlags); loadPackageManifest(): Promise; readJson(loc: string, factory?: (filename: string) => Promise): Promise; getDistributions(): Promise<[any, any][]>; } ================================================ FILE: checkpoint/dist-types/constants.d.ts ================================================ /// export declare const DEPENDENCY_TYPES: string[]; export declare const RESOLUTIONS = "resolutions"; export declare const MANIFEST_FIELDS: string[]; export declare const SUPPORTED_NODE_VERSIONS = ">=8.5.0"; export declare const CHILD_CONCURRENCY = 5; export declare const NODE_MODULES_FOLDER = "node_modules"; export declare const NODE_PACKAGE_JSON = "package.json"; export declare const DEFAULT_INDENT = " "; export declare const ENV_PATH_KEY: string; export declare function getPathKey(platform: string, env: NodeJS.ProcessEnv): string; ================================================ FILE: checkpoint/dist-types/errors.d.ts ================================================ import { MessageError } from '@pika/types'; export declare class ProcessSpawnError extends MessageError { constructor(msg: string, code?: string, process?: string); code?: string; process?: string; } export declare class SecurityError extends MessageError { } export declare class ProcessTermError extends MessageError { EXIT_CODE?: number; EXIT_SIGNAL?: string; } export declare class ResponseError extends Error { constructor(msg: string, responseCode: number); responseCode: number; } export declare class OneTimePasswordError extends Error { } ================================================ FILE: checkpoint/dist-types/index.d.ts ================================================ export declare function cli(args: string[]): Promise; ================================================ FILE: checkpoint/dist-types/reporters/base-reporter.d.ts ================================================ /// import { ReporterSpinnerSet, Trees, Stdout, Stdin, Package, ReporterSpinner } from './types'; import { LanguageKeys } from './lang/en.js'; import { Formatter } from './format.js'; import * as languages from './lang/index.js'; declare type Language = keyof typeof languages; export declare type ReporterOptions = { verbose?: boolean; language?: Language; stdout?: Stdout; stderr?: Stdout; stdin?: Stdin; emoji?: boolean; noProgress?: boolean; silent?: boolean; isSilent?: boolean; nonInteractive?: boolean; }; export declare function stringifyLangArgs(args: Array): Array; export default class BaseReporter { constructor(opts?: ReporterOptions); formatter: Formatter; language: Language; stdout: Stdout; stderr: Stdout; stdin: Stdin; isTTY: boolean; emoji: boolean; noProgress: boolean; isVerbose: boolean; isSilent: boolean; nonInteractive: boolean; format: Formatter; peakMemoryInterval?: NodeJS.Timer; peakMemory: number; startTime: number; lang(key: LanguageKeys, ...args: Array): string; /** * `stringifyLangArgs` run `JSON.stringify` on strings too causing * them to appear quoted. This marks them as "raw" and prevents * the quoting and escaping */ rawText(str: string): { inspect(): string; }; verbose(msg: string): void; verboseInspect(val: any): void; _verbose(msg: string): void; _verboseInspect(val: any): void; _getStandardInput(): Stdin; initPeakMemoryCounter(): void; checkPeakMemory(): void; close(): void; getTotalTime(): number; list(key: string, items: Array, hints?: Object): void; tree(key: string, obj: Trees, { force }?: { force?: boolean; }): void; step(current: number, total: number, message: string, emoji?: string): void; error(message: string): void; info(message: string): void; warn(message: string): void; success(message: string): void; log(message: string, { force }?: { force?: boolean; }): void; command(command: string): void; inspect(value: any): void; header(pkg: Package): void; footer(showPeakMemory: boolean): void; table(head: Array, body: Array>): void; activity(): ReporterSpinner; activitySet(total: number, workers: number): ReporterSpinnerSet; progress(total: number): () => void; disableProgress(): void; } export {}; ================================================ FILE: checkpoint/dist-types/reporters/console/console-reporter.d.ts ================================================ import BaseReporter, { ReporterOptions } from '../base-reporter.js'; import { FormatKeys } from '../format.js'; import { Package, ReporterSpinner, ReporterSpinnerSet, Trees } from '../types.js'; import Progress from './progress-bar.js'; import Spinner from './spinner-progress.js'; declare type Row = Array; export default class ConsoleReporter extends BaseReporter { _lastCategorySize: number; _progressBar?: Progress; _spinners: Set; constructor(opts: ReporterOptions); _prependEmoji(msg: string, emoji?: string): string; _logCategory(category: string, color: FormatKeys, msg: string): void; _verbose(msg: string): void; _verboseInspect(obj: any): void; close(): void; table(head: Array, body: Array): void; step(current: number, total: number, msg: string, emoji?: string): void; inspect(value: any): void; list(key: string, items: Array, hints?: Object): void; header(pkg: Package): void; footer(showPeakMemory?: boolean): void; log(msg: string, { force }?: { force?: boolean; }): void; _log(msg: string, { force }?: { force?: boolean; }): void; success(msg: string): void; error(msg: string): void; info(msg: string): void; command(command: string): void; warn(msg: string): void; tree(key: string, trees: Trees, { force }?: { force?: boolean; }): void; activitySet(total: number, workers: number): ReporterSpinnerSet; activity(): ReporterSpinner; progress(count: number): () => void; stopProgress(): void; } export {}; ================================================ FILE: checkpoint/dist-types/reporters/console/helpers/tree-helper.d.ts ================================================ import { Trees } from '../../types.js'; export declare type FormattedOutput = { prefix: string; hint: any; color: string; name: string; formatter: any; }; export declare function sortTrees(trees: Trees): Trees; export declare function recurseTree(tree: Trees, prefix: string, recurseFunc: Function): void; export declare function getFormattedOutput(fmt: FormattedOutput): string; ================================================ FILE: checkpoint/dist-types/reporters/console/progress-bar.d.ts ================================================ /// import { Stdout } from '../types.js'; export default class ProgressBar { constructor(total: number, stdout?: Stdout, callback?: (progressBar: ProgressBar) => void); stdout: Stdout; curr: number; total: number; width: number; chars: [string, string]; delay: number; id?: NodeJS.Timeout; _callback?: (progressBar: ProgressBar) => void; static bars: [string, string][]; tick(): void; cancelTick(): void; stop(): void; render(): void; } ================================================ FILE: checkpoint/dist-types/reporters/console/spinner-progress.d.ts ================================================ /// import { Stdout } from '../types.js'; export default class Spinner { constructor(stdout?: Stdout, lineNumber?: number); stdout: Stdout; prefix: string; current: number; lineNumber: number; delay: number; chars: Array; text: string; id?: NodeJS.Timeout; static spinners: Array; setPrefix(prefix: string): void; setText(text: string): void; start(): void; render(): void; stop(): void; } ================================================ FILE: checkpoint/dist-types/reporters/console/util.d.ts ================================================ import { Stdout } from '../types.js'; export declare function clearLine(stdout: Stdout): void; export declare function toStartOfLine(stdout: Stdout): void; export declare function writeOnNthLine(stdout: Stdout, n: number, msg: string): void; export declare function clearNthLine(stdout: Stdout, n: number): void; ================================================ FILE: checkpoint/dist-types/reporters/format.d.ts ================================================ declare function formatFunction(...strs: Array): string; export declare const defaultFormatter: { bold: typeof formatFunction; dim: typeof formatFunction; italic: typeof formatFunction; underline: typeof formatFunction; inverse: typeof formatFunction; strikethrough: typeof formatFunction; black: typeof formatFunction; red: typeof formatFunction; green: typeof formatFunction; yellow: typeof formatFunction; blue: typeof formatFunction; magenta: typeof formatFunction; cyan: typeof formatFunction; white: typeof formatFunction; gray: typeof formatFunction; grey: typeof formatFunction; stripColor: typeof formatFunction; }; declare type FormatFunction = (...strs: Array) => string; export declare type FormatKeys = keyof typeof defaultFormatter; export declare type Formatter = { bold: FormatFunction; dim: FormatFunction; italic: FormatFunction; underline: FormatFunction; inverse: FormatFunction; strikethrough: FormatFunction; black: FormatFunction; red: FormatFunction; green: FormatFunction; yellow: FormatFunction; blue: FormatFunction; magenta: FormatFunction; cyan: FormatFunction; white: FormatFunction; gray: FormatFunction; grey: FormatFunction; stripColor: FormatFunction; }; export {}; ================================================ FILE: checkpoint/dist-types/reporters/index.d.ts ================================================ export { default as ConsoleReporter } from './console/console-reporter'; export { default as JSONReporter } from './json-reporter'; export { default as NoopReporter } from './noop-reporter'; export { default as Reporter } from './base-reporter'; ================================================ FILE: checkpoint/dist-types/reporters/json-reporter.d.ts ================================================ import { ReporterSpinnerSet, Trees, ReporterSpinner } from './types.js'; import BaseReporter from './base-reporter.js'; export default class JSONReporter extends BaseReporter { constructor(opts?: Object); _activityId: number; _progressId: number; _dump(type: string, data: any, error?: boolean): void; _verbose(msg: string): void; list(type: string, items: Array, hints?: Object): void; tree(type: string, trees: Trees): void; step(current: number, total: number, message: string): void; inspect(value: any): void; footer(showPeakMemory: boolean): void; log(msg: string): void; command(msg: string): void; table(head: Array, body: Array>): void; success(msg: string): void; error(msg: string): void; warn(msg: string): void; info(msg: string): void; activitySet(total: number, workers: number): ReporterSpinnerSet; activity(): ReporterSpinner; _activity(data: Object): ReporterSpinner; progress(total: number): () => void; } ================================================ FILE: checkpoint/dist-types/reporters/lang/en.d.ts ================================================ declare const messages: { upToDate: string; folderInSync: string; nothingToInstall: string; resolvingPackages: string; checkingManifest: string; fetchingPackages: string; linkingDependencies: string; rebuildingPackages: string; buildingFreshPackages: string; cleaningModules: string; bumpingVersion: string; savingHar: string; answer: string; usage: string; installCommandRenamed: string; globalFlagRemoved: string; waitingInstance: string; waitingNamedInstance: string; offlineRetrying: string; internalServerErrorRetrying: string; clearedCache: string; couldntClearPackageFromCache: string; clearedPackageFromCache: string; packWroteTarball: string; helpExamples: string; helpCommands: string; helpCommandsMore: string; helpLearnMore: string; manifestPotentialTypo: string; manifestBuiltinModule: string; manifestNameDot: string; manifestNameIllegalChars: string; manifestNameBlacklisted: string; manifestLicenseInvalid: string; manifestLicenseNone: string; manifestStringExpected: string; manifestDependencyCollision: string; manifestDirectoryNotFound: string; verboseFileCopy: string; verboseFileLink: string; verboseFileSymlink: string; verboseFileSkip: string; verboseFileSkipSymlink: string; verboseFileSkipHardlink: string; verboseFileRemoveExtraneous: string; verboseFilePhantomExtraneous: string; verboseFileSkipArtifact: string; verboseFileFolder: string; verboseRequestStart: string; verboseRequestFinish: string; configSet: string; configDelete: string; configNpm: string; configPika: string; couldntFindPackagejson: string; couldntFindMatch: string; couldntFindPackageInCache: string; couldntFindVersionThatMatchesRange: string; chooseVersionFromList: string; moduleNotInManifest: string; moduleAlreadyInManifest: string; unknownFolderOrTarball: string; unknownPackage: string; unknownPackageName: string; unknownUser: string; unknownRegistryResolver: string; userNotAnOwner: string; invalidVersionArgument: string; invalidVersion: string; requiredVersionInRange: string; packageNotFoundRegistry: string; requiredPackageNotFoundRegistry: string; doesntExist: string; missingRequiredPackageKey: string; invalidAccess: string; invalidCommand: string; invalidGistFragment: string; invalidHostedGitFragment: string; invalidFragment: string; invalidPackageName: string; invalidPackageVersion: string; couldntFindManifestIn: string; shrinkwrapWarning: string; npmLockfileWarning: string; lockfileOutdated: string; lockfileMerged: string; lockfileConflict: string; ignoredScripts: string; missingAddDependencies: string; yesWarning: string; networkWarning: string; flatGlobalError: string; noName: string; noVersion: string; answerRequired: string; missingWhyDependency: string; bugReport: string; unexpectedError: string; jsonError: string; noPermission: string; noGlobalFolder: string; allDependenciesUpToDate: string; legendColorsForVersionUpdates: string; frozenLockfileError: string; fileWriteError: string; fileDeleteError: string; multiplePackagesCantUnpackInSameDestination: string; incorrectLockfileEntry: string; invalidResolutionName: string; invalidResolutionVersion: string; incompatibleResolutionVersion: string; pikaOutdated: string; pikaOutdatedInstaller: string; pikaOutdatedCommand: string; tooManyArguments: string; tooFewArguments: string; noArguments: string; ownerRemoving: string; ownerRemoved: string; ownerRemoveError: string; ownerGetting: string; ownerGettingFailed: string; ownerAlready: string; ownerAdded: string; ownerAdding: string; ownerAddingFailed: string; ownerNone: string; teamCreating: string; teamRemoving: string; teamAddingUser: string; teamRemovingUser: string; teamListing: string; distFailed: string; distExiting: string; distContinuing: string; cleaning: string; cleanCreatingFile: string; cleanCreatedFile: string; cleanAlreadyExists: string; cleanRequiresForce: string; cleanDoesNotExist: string; binLinkCollision: string; linkCollision: string; linkMissing: string; linkRegistered: string; linkRegisteredMessage: string; linkUnregistered: string; linkUnregisteredMessage: string; linkUsing: string; linkDisusing: string; linkDisusingMessage: string; linkTargetMissing: string; createInvalidBin: string; createMissingPackage: string; workspacesAddRootCheck: string; workspacesRemoveRootCheck: string; workspacesFocusRootCheck: string; workspacesRequirePrivateProjects: string; workspacesSettingMustBeArray: string; workspacesDisabled: string; workspacesNohoistRequirePrivatePackages: string; workspacesNohoistDisabled: string; workspaceRootNotFound: string; workspaceMissingWorkspace: string; workspaceMissingCommand: string; workspaceUnknownWorkspace: string; workspaceVersionMandatory: string; workspaceNameMandatory: string; workspaceNameDuplicate: string; cacheFolderSkipped: string; cacheFolderMissing: string; cacheFolderSelected: string; execMissingCommand: string; noScriptsAvailable: string; noBinAvailable: string; dashDashDeprecation: string; commandNotSpecified: string; binCommands: string; possibleCommands: string; commandQuestion: string; commandFailedWithCode: string; commandFailedWithSignal: string; packageRequiresNodeGyp: string; nodeGypAutoInstallFailed: string; foundIncompatible: string; incompatibleEngine: string; incompatibleCPU: string; incompatibleOS: string; invalidEngine: string; optionalCompatibilityExcluded: string; optionalModuleFail: string; optionalModuleScriptFail: string; optionalModuleCleanupFail: string; unmetPeer: string; incorrectPeer: string; selectedPeer: string; missingBundledDependency: string; savedNewDependency: string; savedNewDependencies: string; directDependencies: string; allDependencies: string; foundWarnings: string; foundErrors: string; savedLockfile: string; noRequiredLockfile: string; noLockfileFound: string; invalidSemver: string; newVersion: string; currentVersion: string; noVersionOnPublish: string; manualVersionResolution: string; manualVersionResolutionOption: string; createdTag: string; createdTagFail: string; deletedTag: string; deletedTagFail: string; gettingTags: string; deletingTags: string; creatingTag: string; whyStart: string; whyFinding: string; whyCalculating: string; whyUnknownMatch: string; whyInitGraph: string; whyWhoKnows: string; whyDiskSizeWithout: string; whyDiskSizeUnique: string; whyDiskSizeTransitive: string; whySharedDependencies: string; whyHoistedTo: string; whyHoistedFromSimple: string; whyNotHoistedSimple: string; whyDependedOnSimple: string; whySpecifiedSimple: string; whyReasons: string; whyHoistedFrom: string; whyNotHoisted: string; whyDependedOn: string; whySpecified: string; whyMatch: string; uninstalledPackages: string; uninstallRegenerate: string; cleanRemovedFiles: string; cleanSavedSize: string; configFileFound: string; configPossibleFile: string; npmUsername: string; npmPassword: string; npmEmail: string; npmOneTimePassword: string; loggingIn: string; loggedIn: string; notRevokingEnvToken: string; notRevokingConfigToken: string; noTokenToRevoke: string; revokingToken: string; revokedToken: string; loginAsPublic: string; incorrectCredentials: string; incorrectOneTimePassword: string; twoFactorAuthenticationEnabled: string; clearedCredentials: string; publishFail: string; publishPrivate: string; published: string; publishing: string; nonInteractiveNoVersionSpecified: string; nonInteractiveNoToken: string; infoFail: string; malformedRegistryResponse: string; registryNoVersions: string; cantRequestOffline: string; requestManagerNotSetupHAR: string; requestError: string; requestFailed: string; tarballNotInNetworkOrCache: string; fetchBadHashWithPath: string; fetchBadIntegrityAlgorithm: string; fetchErrorCorrupt: string; errorExtractingTarball: string; updateInstalling: string; hostedGitResolveError: string; unknownFetcherFor: string; downloadGitWithoutCommit: string; downloadHTTPWithoutCommit: string; unplugDisabled: string; plugnplayWindowsSupport: string; packageInstalledWithBinaries: string; packageHasBinaries: string; packageHasNoBinaries: string; packageBinaryNotFound: string; couldBeDeduped: string; lockfileNotContainPattern: string; integrityCheckFailed: string; noIntegrityFile: string; integrityFailedExpectedIsNotAJSON: string; integrityCheckLinkedModulesDontMatch: string; integrityFlagsDontMatch: string; integrityLockfilesDontMatch: string; integrityFailedFilesMissing: string; integrityPatternsDontMatch: string; integrityModulesFoldersMissing: string; integritySystemParamsDontMatch: string; packageNotInstalled: string; optionalDepNotInstalled: string; packageWrongVersion: string; packageDontSatisfy: string; lockfileExists: string; pikaManifestExists: string; noManifestExists: string; skippingImport: string; importFailed: string; importResolveFailed: string; importResolvedRangeMatch: string; importSourceFilesCorrupted: string; importPackageLock: string; importYarnLock: string; importNodeModules: string; packageContainsPikaAsGlobal: string; watchStarting: string; watchRunning: string; watchRebuild: string; watchError: string; noValidationErrors: string; validationErrors: string; scopeNotValid: string; deprecatedCommand: string; deprecatedListArgs: string; implicitFileDeprecated: string; unsupportedNodeVersion: string; verboseUpgradeBecauseRequested: string; verboseUpgradeBecauseOutdated: string; verboseUpgradeNotUnlocking: string; verboseUpgradeUnlocking: string; folderMissing: string; mutexPortBusy: string; auditRunning: string; auditSummary: string; auditSummarySeverity: string; auditCritical: string; auditHigh: string; auditModerate: string; auditLow: string; auditInfo: string; auditResolveCommand: string; auditSemverMajorChange: string; auditManualReview: string; auditRunAuditForDetails: string; auditOffline: string; }; export declare type LanguageKeys = keyof typeof messages; export default messages; ================================================ FILE: checkpoint/dist-types/reporters/lang/index.d.ts ================================================ import en from './en.js'; export { en }; ================================================ FILE: checkpoint/dist-types/reporters/noop-reporter.d.ts ================================================ import BaseReporter from './base-reporter.js'; import { LanguageKeys } from './lang/en.js'; import { Package, ReporterSpinner, ReporterSpinnerSet, Trees } from './types.js'; export default class NoopReporter extends BaseReporter { lang(key: LanguageKeys, ...args: Array): string; verbose(msg: string): void; verboseInspect(val: any): void; initPeakMemoryCounter(): void; checkPeakMemory(): void; close(): void; getTotalTime(): number; list(key: string, items: Array, hints?: Object): void; tree(key: string, obj: Trees): void; step(current: number, total: number, message: string, emoji?: string): void; error(message: string): void; info(message: string): void; warn(message: string): void; success(message: string): void; log(message: string): void; command(command: string): void; inspect(value: any): void; header(pkg: Package): void; footer(showPeakMemory: boolean): void; table(head: Array, body: Array>): void; activity(): ReporterSpinner; activitySet(total: number, workers: number): ReporterSpinnerSet; progress(total: number): () => void; disableProgress(): void; } ================================================ FILE: checkpoint/dist-types/reporters/types.d.ts ================================================ /// import { Writable, Readable } from 'stream'; import { WriteStream, ReadStream } from 'fs'; export declare type Stdout = Writable | WriteStream; export declare type Stdin = Readable | ReadStream; export declare type Package = { name: string; version: string; }; export declare type Tree = { name: string; children?: Trees; hint?: string; hidden?: boolean; color?: string; }; export declare type Trees = Array; export declare type ReporterSpinner = { tick: (name: string) => void; end: () => void; }; export declare type ReporterSpinnerSet = { spinners: Array; end: () => void; }; export declare type ReporterSetSpinner = { clear: () => void; setPrefix: (current: number, prefix: string) => void; tick: (msg: string) => void; end: () => void; }; ================================================ FILE: checkpoint/dist-types/types.d.ts ================================================ import { Reporter } from './reporters/index.js'; import Config from './config.js'; export declare type CLIFunction = (config: Config, reporter: Reporter, flags: Object, args: Array) => CLIFunctionReturn; declare type _CLIFunctionReturn = boolean; export declare type CLIFunctionReturn = _CLIFunctionReturn | Promise<_CLIFunctionReturn>; export declare type PersonObject = { email?: string; name?: string; url?: string; }; declare type Dependencies = { [key: string]: string; }; export declare type Manifest = { name: string; version: string; description?: string; keywords?: string[]; sideEffects?: boolean; private?: boolean; distributions?: any; author?: { name?: string; email?: string; url?: string; }; homepage?: string; flat?: boolean; license?: string; licenseText?: string; noticeText?: string; readme?: string; readmeFilename?: string; repository?: { type: 'git'; url: string; }; bugs?: { url: string; }; dist?: { tarball: string; shasum: string; }; directories?: { man: string; bin: string; }; man?: Array; bin?: { [name: string]: string; }; scripts?: { [name: string]: string; }; engines?: { [engineName: string]: string; }; os?: Array; cpu?: Array; dependencies?: Dependencies; devDependencies?: Dependencies; peerDependencies?: Dependencies; optionalDependencies?: Dependencies; bundleDependencies?: Array; bundledDependencies?: Array; installConfig?: { pnp?: boolean; }; deprecated?: string; files?: Array; main?: string; fresh?: boolean; prebuiltVariants?: { [filename: string]: string; }; }; export declare type Dependency = { name: string; current: string; wanted: string; latest: string; url: string; hint?: string; range: string; upgradeTo: string; workspaceName: string; workspaceLoc: string; }; export {}; ================================================ FILE: checkpoint/dist-types/util/babel-plugin-import-rewrite.d.ts ================================================ export default function transform({ template, types: t }: { template: any; types: any; }): any; ================================================ FILE: checkpoint/dist-types/util/babel-validate-specifier.d.ts ================================================ export declare function validateDynamicImportArguments(path: any): Set; ================================================ FILE: checkpoint/dist-types/util/blocking-queue.d.ts ================================================ /// export default class BlockingQueue { constructor(alias: string, maxConcurrency?: number); concurrencyQueue: Array<() => void>; warnedStuck: boolean; maxConcurrency: number; runningCount: number; stuckTimer?: NodeJS.Timeout; alias: string; first: boolean; queue: { [key: string]: Array<{ factory: () => Promise; resolve: (val: any) => void; reject: Function; }>; }; running: { [key: string]: boolean; }; stillActive(): void; stuckTick(): void; push(key: string, factory: () => Promise): Promise; shift(key: string): void; maybePushConcurrencyQueue(run: () => void): void; shiftConcurrencyQueue(): void; } ================================================ FILE: checkpoint/dist-types/util/child.d.ts ================================================ /// import BlockingQueue from './blocking-queue.js'; import { ChildProcess, SpawnOptions } from 'child_process'; export declare const queue: BlockingQueue; export declare const exec: (...args: any[]) => Promise; export declare function forwardSignalToSpawnedProcesses(signal: string): void; declare type ProcessFn = (proc: ChildProcess, update: (chunk: string) => void, reject: (err: any) => void, done: () => void) => void; export declare function spawn(program: string, args: Array, opts?: SpawnOptions & { detached?: boolean; process?: ProcessFn; }, onData?: (chunk: Buffer | string) => void): Promise; export {}; ================================================ FILE: checkpoint/dist-types/util/conversion.d.ts ================================================ export declare function boolify(val: string | number | boolean): boolean; export declare function boolifyWithDefault(val: string | number | boolean, defaultResult: boolean): boolean; ================================================ FILE: checkpoint/dist-types/util/execute-lifecycle-script.d.ts ================================================ /// export declare type LifecycleReturn = Promise<{ cwd: string; command: string; stdout: string; }>; export declare function makeEnv(): Promise<{ [key: string]: string; }>; export declare function executeLifecycleScript({ cwd, cmd, args, isInteractive, onProgress, customShell, }: { cwd: string; args: string[]; cmd: string; isInteractive?: boolean; onProgress?: (chunk: Buffer | string) => void; customShell?: string; }): LifecycleReturn; export default executeLifecycleScript; ================================================ FILE: checkpoint/dist-types/util/fix-cmd-win-slashes.d.ts ================================================ export declare function fixCmdWinSlashes(cmd: string): string; ================================================ FILE: checkpoint/dist-types/util/fs-normalized.d.ts ================================================ ================================================ FILE: checkpoint/dist-types/util/fs.d.ts ================================================ /// export declare const unlink: (path: string) => Promise; export declare const glob: (path: string, options?: Object) => Promise>; export declare const mkdirp: (path: string) => Promise; import * as fs from 'fs'; export declare const open: typeof fs.open.__promisify__; export declare const writeFile: typeof fs.writeFile.__promisify__; export declare const readlink: typeof fs.readlink.__promisify__; export declare const realpath: typeof fs.realpath.__promisify__; export declare const readdir: typeof fs.readdir.__promisify__; export declare const rename: typeof fs.rename.__promisify__; export declare const access: typeof fs.access.__promisify__; export declare const stat: typeof fs.stat.__promisify__; export declare const exists: typeof fs.exists.__promisify__; export declare const lstat: typeof fs.lstat.__promisify__; export declare const chmod: typeof fs.chmod.__promisify__; export declare const link: (arg1: fs.PathLike, arg2: fs.PathLike) => Promise; export declare const copyFile: typeof fs.copyFile.__promisify__; export declare const readFile: (path: string) => Promise; export declare function readJson(loc: string): Promise; export declare function readJsonAndFile(loc: string): Promise<{ object: Object; content: string; }>; export declare type WalkFiles = Array<{ relative: string; absolute: string; basename: string; mtime: number; }>; export declare function walk(dir: string, relativeDir?: string, ignoreBasenames?: Set): Promise; export declare function writeFilePreservingEol(path: string, data: string): Promise; ================================================ FILE: checkpoint/dist-types/util/map.d.ts ================================================ export default function nullify(obj?: T): T; ================================================ FILE: checkpoint/dist-types/util/misc.d.ts ================================================ export declare function sortAlpha(a: string, b: string): number; export declare function sortOptionsByFlags(a: any, b: any): number; export declare function entries(obj: { [key: string]: T; }): Array<[string, T]>; export declare function removePrefix(pattern: string, prefix: string): string; export declare function removeSuffix(pattern: string, suffix: string): string; export declare function addSuffix(pattern: string, suffix: string): string; export declare function hyphenate(str: string): string; export declare function camelCase(str: string): string | null; export declare function compareSortedArrays(array1: Array, array2: Array): boolean; export declare function sleep(ms: number): Promise; ================================================ FILE: checkpoint/dist-types/util/normalize-manifest/fix.d.ts ================================================ import { Reporter } from '../../reporters/index.js'; declare type Dict = { [key: string]: T; }; declare type WarnFunction = (msg: string) => void; declare const _default: (info: Dict, moduleLoc: string, reporter: Reporter, warn: WarnFunction) => Promise; export default _default; ================================================ FILE: checkpoint/dist-types/util/normalize-manifest/for-publish.d.ts ================================================ import Config from '../../config'; export declare function generatePublishManifest(manifest: any, config: Config, _dists?: Array<[Function, any]>): Promise; export declare function generatePrettyManifest(manifest: any): string; ================================================ FILE: checkpoint/dist-types/util/normalize-manifest/index.d.ts ================================================ import { Manifest } from '../../types.js'; import Config from '../../config.js'; declare const _default: (info: any, moduleLoc: string, config: Config, isRoot: boolean) => Promise; export default _default; ================================================ FILE: checkpoint/dist-types/util/normalize-manifest/infer-license.d.ts ================================================ export default function inferLicense(license: string): string | null; ================================================ FILE: checkpoint/dist-types/util/normalize-manifest/licenses.d.ts ================================================ declare const _default: { 'Apache-2.0': RegExp; 'BSD-2-Clause': RegExp; 'BSD-3-Clause': RegExp; MIT: RegExp; Unlicense: RegExp; }; export default _default; ================================================ FILE: checkpoint/dist-types/util/normalize-manifest/typos.d.ts ================================================ declare const _default: { autohr: string; autor: string; contributers: string; depdenencies: string; dependancies: string; dependecies: string; depends: string; 'dev-dependencies': string; devDependences: string; devDepenencies: string; devEependencies: string; devdependencies: string; hampage: string; hompage: string; prefereGlobal: string; publicationConfig: string; repo: string; repostitory: string; script: string; }; export default _default; ================================================ FILE: checkpoint/dist-types/util/normalize-manifest/util.d.ts ================================================ import { PersonObject } from '../../types.js'; export declare function isValidLicense(license: string): boolean; export declare function stringifyPerson(person: any): any; export declare function parsePerson(person: any): PersonObject; export declare function normalizePerson(person: any): any | PersonObject; export declare function extractDescription(readme: any): string; ================================================ FILE: checkpoint/dist-types/util/normalize-manifest/validate.d.ts ================================================ import { Reporter } from '../../reporters/index.js'; export declare function isValidPackageName(name: string): boolean; declare type WarnFunction = (msg: string) => void; export default function (info: any, isRoot: boolean, reporter: Reporter, warn: WarnFunction): void; export declare function cleanDependencies(info: Object, isRoot: boolean, reporter: Reporter, warn: WarnFunction): void; export {}; ================================================ FILE: checkpoint/dist-types/util/promise.d.ts ================================================ export declare function wait(delay: number): Promise; export declare function promisify(fn: Function, firstData?: boolean): (...args: Array) => Promise; export declare function queue(arr: Array, promiseProducer: (result: U) => Promise, concurrency?: number): Promise>; ================================================ FILE: checkpoint/dist-types/util/signal-handler.d.ts ================================================ export default function handleSignals(): void; ================================================ FILE: checkpoint/package.json ================================================ { "name": "@pika/pack", "description": "package building, reimagined.", "version": "0.4.0", "license": "MIT", "bin": { "pika-pack": "dist-node/index.bin.js" }, "files": [ "dist-*/", "bin/" ], "pika": true, "sideEffects": false, "homepage": "https://www.pikapkg.com/blog/introducing-pika-pack/", "repository": { "type": "git", "url": "https://github.com/pikapkg/pack.git" }, "dependencies": { "@pika/cli": "latest", "@pika/types": "^0.6.0", "camelcase": "^4.0.0", "chalk": "^2.1.0", "commander": "^2.9.0", "file-uri-to-path": "^1.0.0", "glob": "^7.1.1", "import-from": "^3.0.0", "invariant": "^2.2.0", "is-builtin-module": "^2.0.0", "is-ci": "^1.0.10", "loud-rejection": "^1.2.0", "mkdirp": "^0.5.1", "np": "^5.0.2", "rimraf": "^2.5.0", "strip-ansi": "^4.0.0", "strip-bom": "^3.0.0", "validate-npm-package-license": "^3.0.4", "yargs-parser": "^13.1.1" }, "devDependencies": { "@pika/plugin-build-node": "^0.6.0", "@pika/plugin-simple-bin": "^0.6.0", "@pika/plugin-ts-standard-pkg": "^0.6.0", "prettier": "^1.15.3", "typescript": "^3.2.2" }, "engines": { "node": ">=8" }, "publishConfig": { "access": "public" }, "source": "dist-src/index.js", "types": "dist-types/index.d.ts", "main": "dist-node/index.js" } ================================================ FILE: package.json ================================================ { "name": "@pika/pack", "description": "package building, reimagined.", "version": "0.6.0", "license": "MIT", "homepage": "https://www.pikapkg.com/blog/introducing-pika-pack/", "engines": { "node": ">=8" }, "repository": { "type": "git", "url": "https://github.com/pikapkg/pack.git" }, "scripts": { "format": "prettier --write src/**/*.ts", "build": "node checkpoint/dist-node/index.bin.js", "publish": "pika publish", "test": "node pkg/dist-node/index.bin.js", "version": "node pkg/dist-node/index.bin.js", "update-checkpoint": "rm -rf checkpoint/ && cp -r pkg/ checkpoint/" }, "@pika/pack": { "pipeline": [ [ "@pika/plugin-ts-standard-pkg" ], [ "@pika/plugin-build-node" ], [ "@pika/plugin-simple-bin", { "bin": "pika-pack", "minNodeVersion": 8 } ] ] }, "publishConfig": { "access": "public" }, "dependencies": { "commander": "^6.2.1", "file-uri-to-path": "^2.0.0", "glob": "^7.1.6", "import-from": "^3.0.0", "invariant": "^2.2.4", "is-builtin-module": "^3.0.0", "is-ci": "^2.0.0", "kleur": "^4.1.3", "loud-rejection": "^2.2.0", "mkdirp": "^1.0.4", "np": "^7.1.0", "rimraf": "^3.0.2", "strip-ansi": "^6.0.0", "strip-bom": "^4.0.0", "validate-npm-package-license": "^3.0.4", "yargs-parser": "^20.2.4" }, "devDependencies": { "@pika/plugin-build-node": "^0.9.2", "@pika/plugin-simple-bin": "^0.9.2", "@pika/plugin-ts-standard-pkg": "^0.9.2", "@types/yargs-parser": "^20.2.0", "prettier": "^2.2.1", "typescript": "^4.1.3" } } ================================================ FILE: src/commands/build.ts ================================================ import {BuilderOptions} from '@pika/types'; import chalk from 'chalk'; import * as path from 'path'; import Config, {BuildFlags} from '../config.js'; import {DEFAULT_INDENT} from '../constants.js'; import {Reporter} from '../reporters/index.js'; import * as fs from '../util/fs.js'; import {generatePrettyManifest, generatePublishManifest} from '../util/normalize-manifest/for-publish.js'; export function hasWrapper(): boolean { return true; } export const examples = null; export class Build { constructor(flags: BuildFlags, config: Config, reporter: Reporter) { this.flags = flags; this.config = config; this.reporter = reporter; this.totalNum = 0; this.out = path.resolve(config.cwd, flags.out || 'pkg/'); if (this.out === this.config.cwd) { throw new Error('On publish, you cannot write to cwd because a package.json is created'); } } out: string; flags: BuildFlags; config: Config; reporter: Reporter; totalNum: number; async cleanup(): Promise { const {out} = this; await fs.unlink(path.join(out, '*')); } async init(isFull?: boolean): Promise { const {config, out, reporter, flags} = this; const {cwd} = config; const outPretty = path.relative(cwd, out) + path.sep; const manifest = await config.manifest; const {sourcemap} = manifest['@pika/pack'] || {sourcemap: true}; const distRunners = await config.getDistributions(); const builderConfig: Partial = { out, cwd, reporter: { info: (msg) => reporter.log(chalk.dim(` » ${msg}`)), warning: (msg) => reporter.log(chalk.yellow(` » ${msg}`)), success: (msg) => reporter.log(chalk.green(` » ${msg}`)), created: (filename: string, entrypoint?: string) => reporter.log( ` 📝 ${chalk.green(path.relative(cwd, filename))} ${entrypoint ? chalk.dim(`[${entrypoint}]`) : ''}`, ), }, isFull, manifest, src: { loc: path.join(out, 'dist-src'), entrypoint: path.join(out, 'dist-src', 'index.js'), // TODO: Deprecated, remove options: {}, // TODO: Deprecated, remove files: await (async (): Promise> => { const ignoreSet = new Set([]); ignoreSet.add('**/*/README.md'); const files = await fs.glob(`src/**/*`, { cwd, nodir: true, absolute: true, ignore: Array.from(ignoreSet).map((g) => path.join('src', g)), }); return files.filter((fileAbs) => !fileAbs.endsWith('.d.ts')); })(), }, }; const steps: Array<(curr: number, total: number) => Promise<{bailout: boolean} | void>> = []; steps.push(async (curr: number, total: number) => { this.reporter.step(curr, total, 'Validating source'); for (const [runner, options] of distRunners) { if (runner.validate) { const result = await runner.validate({ ...builderConfig, options: {sourcemap, ...options}, }); if (result instanceof Error) { throw result; } } } }); steps.push(async (curr: number, total: number) => { this.reporter.step(curr, total, `Preparing pipeline`); await this.cleanup(); reporter.log(` ❇️ ${chalk.green(outPretty)}`); for (const [runner, options] of distRunners) { await (runner.beforeBuild && runner.beforeBuild({ ...builderConfig, options: {sourcemap, ...options}, })); } }); if (distRunners.length === 0) { steps.push(async (curr: number, total: number) => { this.reporter.step( curr, total, `Pipeline is empty! See ${chalk.underline('https://github.com/pikapkg/pack')} for help getting started`, ); }); } for (const [runner, options] of distRunners) { steps.push(async (curr: number, total: number) => { this.reporter.step(curr, total, `Running ${chalk.bold(runner.name)}`); // return Promise.resolve( try { await (runner.beforeJob && runner.beforeJob({ ...builderConfig, options: {sourcemap, ...options}, })); await (runner.build && runner.build({ ...builderConfig, options: {sourcemap, ...options}, })); await (runner.afterJob && runner.afterJob({ ...builderConfig, options: {sourcemap, ...options}, })); } catch (err) { if (flags.force) { console.error(' ❗️ ', chalk.red(err.message), chalk.dim('--force, continuing...')); } else { console.error(' ❗️ ', chalk.red(err.message)); if (err.all) { console.error(' ❗️ ', chalk.bold('ERROR OUTPUT:')); console.error(err.all); } throw err; } } // ).catch(err => { // log(chalk.red(err.message)); // reporter.log( // reporter.lang("distFailed", runner.name, err.code, err.message), // { force: true } // ); // if (err.forceExit === true) { // reporter.log(reporter.lang("distExiting")); // throw err; // return; // } // reporter.log(reporter.lang("distContinuing")); // }); }); } steps.push(async (curr: number, total: number) => { this.reporter.step(curr, total, `Finalizing package`); for (const [runner, options] of distRunners) { await (runner.afterBuild && runner.afterBuild({ ...builderConfig, options: {sourcemap, ...options}, })); } if (await fs.exists(path.join(cwd, 'CHANGELOG'))) { fs.copyFile(path.join(cwd, 'CHANGELOG'), path.join(out, 'CHANGELOG')); reporter.log(chalk.dim(` » copying CHANGELOG...`)); } else if (await fs.exists(path.join(cwd, 'CHANGELOG.md'))) { fs.copyFile(path.join(cwd, 'CHANGELOG.md'), path.join(out, 'CHANGELOG.md')); reporter.log(chalk.dim(` » copying CHANGELOG.md...`)); } if (await fs.exists(path.join(cwd, 'LICENSE'))) { fs.copyFile(path.join(cwd, 'LICENSE'), path.join(out, 'LICENSE')); reporter.log(chalk.dim(` » copying LICENSE...`)); } else if (await fs.exists(path.join(cwd, 'LICENSE.md'))) { fs.copyFile(path.join(cwd, 'LICENSE.md'), path.join(out, 'LICENSE.md')); reporter.log(chalk.dim(` » copying LICENSE.md...`)); } if (await fs.exists(path.join(cwd, 'README'))) { fs.copyFile(path.join(cwd, 'README'), path.join(out, 'README')); reporter.log(chalk.dim(` » copying README...`)); } else if (await fs.exists(path.join(cwd, 'README.md'))) { fs.copyFile(path.join(cwd, 'README.md'), path.join(out, 'README.md')); reporter.log(chalk.dim(` » copying README.md...`)); } const publishManifest = await generatePublishManifest(config._manifest, config, distRunners); if (out === cwd) { reporter.log(`NEW MANIFEST:\n\n`); reporter.log(generatePrettyManifest(publishManifest)); reporter.log(`\n\n`); } else { await fs.writeFilePreservingEol( path.join(out, 'package.json'), JSON.stringify(publishManifest, null, DEFAULT_INDENT) + '\n', ); reporter.log(` 📝 ` + chalk.green(outPretty + 'package.json')); } reporter.log(` 📦 ` + chalk.green(outPretty)); }); let currentStep = 0; for (const step of steps) { await step(++currentStep, steps.length); } } } export async function run(config: Config, reporter: Reporter, flags: BuildFlags, args: Array): Promise { const isProduction = flags.publish; const builder = new Build(flags, config, reporter); await builder.init(isProduction); } ================================================ FILE: src/config.ts ================================================ declare function __non_webpack_require__(m: string): any; import * as path from 'path'; import * as constants from './constants.js'; import {MessageError} from '@pika/types'; import {Manifest} from './types.js'; import * as fs from './util/fs.js'; import normalizeManifest from './util/normalize-manifest/index.js'; import BaseReporter from './reporters/base-reporter.js'; import executeLifecycleScript from './util/execute-lifecycle-script.js'; import importFrom from 'import-from'; export interface BuildFlags { publish?: boolean; out?: string; silent?: boolean; force?: boolean; } export interface GlobalFlags extends BuildFlags { cwd?: string; pipeline?: string; verbose?: boolean; json?: boolean; } export default class Config { cwd: string; reporter: BaseReporter; _manifest: any; manifest: Manifest; flags: GlobalFlags; constructor(reporter: BaseReporter, cwd: string, flags: GlobalFlags) { this.reporter = reporter; // Ensure the cwd is always an absolute path. this.cwd = path.resolve(cwd || process.cwd()); this.flags = flags; } async loadPackageManifest() { const loc = path.join(this.cwd, constants.NODE_PACKAGE_JSON); if (await fs.exists(loc)) { const info = await this.readJson(loc, fs.readJsonAndFile); this._manifest = {...info.object}; this.manifest = await normalizeManifest(info.object, this.cwd, this, true); return this.manifest; } else { return null; } } readJson(loc: string, factory: (filename: string) => Promise = fs.readJson): Promise { try { return factory(loc); } catch (err) { if (err instanceof SyntaxError) { throw new MessageError(this.reporter.lang('jsonError', loc, err.message)); } else { throw err; } } } async getDistributions(): Promise<[any, any][]> { const raw = this.manifest[`@pika/pack`] || {}; const override = this.flags.pipeline && JSON.parse(this.flags.pipeline); const cwd = this.cwd; function cleanRawDistObject(rawVal): false | [any, any] { if (Array.isArray(rawVal)) { let importStr = rawVal[0].startsWith('./') || rawVal[0].startsWith('../') ? path.join(cwd, rawVal[0]) : rawVal[0]; const importResult = importFrom(cwd, importStr) as any; return [{...importResult, name: rawVal[0]}, rawVal[1] || {}]; } if (typeof rawVal === 'string') { return [ { build: ({cwd}) => { return executeLifecycleScript({ // config: this, args: [], cwd, cmd: rawVal, isInteractive: false, }); }, }, {}, ]; } if (!rawVal) { throw new Error('Cannot be false'); } return false; } const pipeline: any[] = override || raw.pipeline || []; return pipeline.map(cleanRawDistObject).filter(Boolean) as [any, any][]; } } ================================================ FILE: src/constants.ts ================================================ // import os from 'os'; // import * as path from 'path'; // import userHome from './util/user-home-dir.js'; // import {getCacheDir, getConfigDir, getDataDir} from './util/user-dirs.js'; export const DEPENDENCY_TYPES = ['devDependencies', 'dependencies', 'legacyDependencies']; // export const OWNED_DEPENDENCY_TYPES = ['devDependencies', 'dependencies', 'legacyDependencies']; export const RESOLUTIONS = 'resolutions'; export const MANIFEST_FIELDS = [RESOLUTIONS, ...DEPENDENCY_TYPES]; export const SUPPORTED_NODE_VERSIONS = '>=8.5.0'; // export const PIKA_REGISTRY = 'https://registry.npmjs.org'; // export const NPM_REGISTRY_RE = /https?:\/\/registry\.npmjs\.org/g; // export const PIKA_DOCS = 'https://yarnpkg.com/en/docs/cli/'; // export const PIKA_INSTALLER_SH = 'https://yarnpkg.com/install.sh'; // export const PIKA_INSTALLER_MSI = 'https://yarnpkg.com/latest.msi'; // export const SELF_UPDATE_VERSION_URL = 'https://www.pikapkg.com/downloads/latest-version'; // // cache version, bump whenever we make backwards incompatible changes // export const CACHE_VERSION = 3; // // lockfile version, bump whenever we make backwards incompatible changes // export const LOCKFILE_VERSION = 1; // // max amount of network requests to perform concurrently // export const NETWORK_CONCURRENCY = 8; // // HTTP timeout used when downloading packages // export const NETWORK_TIMEOUT = 30 * 1000; // in milliseconds // // max amount of child processes to execute concurrently export const CHILD_CONCURRENCY = 5; // export const REQUIRED_PACKAGE_KEYS = ['name', 'version', '_uid']; // function getPreferredCacheDirectories(): Array { // const preferredCacheDirectories = [getCacheDir()]; // if (process.getuid) { // // $FlowFixMe: process.getuid exists, dammit // preferredCacheDirectories.push(path.join(os.tmpdir(), `.pika-cache-${process.getuid()}`)); // } // preferredCacheDirectories.push(path.join(os.tmpdir(), `.pika-cache`)); // return preferredCacheDirectories; // } // export const PREFERRED_MODULE_CACHE_DIRECTORIES = getPreferredCacheDirectories(); // export const CONFIG_DIRECTORY = getConfigDir(); // export const DATA_DIRECTORY = getDataDir(); // export const LINK_REGISTRY_DIRECTORY = path.join(DATA_DIRECTORY, 'link'); // export const GLOBAL_MODULE_DIRECTORY = path.join(DATA_DIRECTORY, 'global'); // export const NODE_BIN_PATH = process.execPath; export const NODE_MODULES_FOLDER = 'node_modules'; export const NODE_PACKAGE_JSON = 'package.json'; // export const PNP_FILENAME = '.pnp'; // export const POSIX_GLOBAL_PREFIX = `${process.env.DESTDIR || ''}/usr/local`; // export const FALLBACK_GLOBAL_PREFIX = path.join(userHome, '.pika'); // export const META_FOLDER = '.pika-meta'; // export const INTEGRITY_FILENAME = '.pika-integrity'; // export const LOCKFILE_FILENAME = 'pika.lock'; // export const LEGACY_LOCKFILE_FILENAME = 'yarn.lock'; // export const METADATA_FILENAME = '.pika-metadata.json'; // export const TARBALL_FILENAME = '.pika-tarball.tgz'; // export const CLEAN_FILENAME = '.pikaclean'; // export const NPM_LOCK_FILENAME = 'package-lock.json'; // export const NPM_SHRINKWRAP_FILENAME = 'npm-shrinkwrap.json'; export const DEFAULT_INDENT = ' '; // export const SINGLE_INSTANCE_PORT = 31997; // export const SINGLE_INSTANCE_FILENAME = '.pika-single-instance'; export const ENV_PATH_KEY = getPathKey(process.platform, process.env); export function getPathKey(platform: string, env: NodeJS.ProcessEnv): string { let pathKey = 'PATH'; // windows calls its path "Path" usually, but this is not guaranteed. if (platform === 'win32') { pathKey = 'Path'; for (const key in env) { if (key.toLowerCase() === 'path') { pathKey = key; } } } return pathKey; } // export const VERSION_COLOR_SCHEME: {[key: string]: VersionColor} = { // major: 'red', // premajor: 'red', // minor: 'yellow', // preminor: 'yellow', // patch: 'green', // prepatch: 'green', // prerelease: 'red', // unchanged: 'white', // unknown: 'red', // }; // export type VersionColor = 'red' | 'yellow' | 'green' | 'white'; // export type RequestHint = 'dev' | 'optional' | 'resolution' | 'workspaces'; ================================================ FILE: src/errors.ts ================================================ import {MessageError} from '@pika/types'; export class ProcessSpawnError extends MessageError { constructor(msg: string, code?: string, process?: string) { super(msg); this.code = code; this.process = process; } code?: string; process?: string; } export class SecurityError extends MessageError {} export class ProcessTermError extends MessageError { EXIT_CODE?: number; EXIT_SIGNAL?: string; } export class ResponseError extends Error { constructor(msg: string, responseCode: number) { super(msg); this.responseCode = responseCode; } responseCode: number; } export class OneTimePasswordError extends Error {} ================================================ FILE: src/index.ts ================================================ import * as path from 'path'; import * as kleur from 'kleur'; import * as fs from 'fs'; import invariant from 'invariant'; import loudRejection from 'loud-rejection'; import {ConsoleReporter, JSONReporter} from './reporters/index.js'; import * as buildCommand from './commands/build.js'; import {MessageError} from '@pika/types'; import Config, {GlobalFlags} from './config.js'; import handleSignals from './util/signal-handler.js'; import {boolifyWithDefault} from './util/conversion.js'; import map from './util/map.js'; import stripBOM from 'strip-bom'; import uri2path from 'file-uri-to-path'; import yargs from 'yargs-parser'; // @ts-ignore const currentFilename = uri2path(import.meta.url); function getVersion() { const packageJsonContent = fs.readFileSync(path.resolve(currentFilename, '../../package.json'), {encoding: 'utf-8'}); const {version} = map(JSON.parse(stripBOM(packageJsonContent))); return version; } function printHelp() { console.log( ` ${kleur.bold(`@pika/pack`)} - Build npm packages without the mess. ${kleur.bold('Options:')} --cwd Set the current working directory. --out Set the output directory. Defaults to "pkg/". --pipeline Set a build pipeline via JSON string. --force Continue with the build when a build plugin fails or throws an exception. --json Log output as JSON. --verbose Log additional debugging information. --silent Log almost nothing. --help Print help. --version, -v Print version. `.trim(), ); } export async function cli(args: string[]) { const version = getVersion(); loudRejection(); handleSignals(); // Handle special flags if (args.find((arg) => arg === '--version' || arg === '-v')) { console.log(version.trim()); process.exitCode = 0; return; } if (args.find((arg) => arg === '--help')) { printHelp(); process.exitCode = 0; return; } // Handle the legacy CLI interface if (args[2] === 'publish') { console.log(`The publish flow has moved to the @pika/cli package (included with this package). Update your publish script to: ${kleur.bold('pika publish [flags]')} `); process.exitCode = 1; return; } if (args[2] === 'build') { console.log( kleur.yellow( `Note: This CLI was recently deprecated. Update your build script to: ${kleur.bold('pika build [flags]')}`, ), ); args.splice(2, 1); } const flags = yargs(args) as GlobalFlags; const cwd = flags.cwd || process.cwd(); const Reporter = flags.json ? JSONReporter : ConsoleReporter; const reporter = new Reporter({ emoji: true, verbose: flags.verbose, isSilent: boolifyWithDefault(process.env.PIKA_SILENT, false) || flags.silent, }); const exit = (exitCode: any = 0) => { process.exitCode = exitCode; reporter.close(); }; const command = buildCommand; reporter.initPeakMemoryCounter(); const outputWrapperEnabled = boolifyWithDefault(process.env.PIKA_WRAP_OUTPUT, true); const shouldWrapOutput = outputWrapperEnabled && !flags.json && command.hasWrapper(); if (shouldWrapOutput) { reporter.header({name: '@pika/pack', version}); } const run = (): Promise => { invariant(command, 'missing command'); return command.run(config, reporter, flags, args).then((exitCode) => { if (shouldWrapOutput) { reporter.footer(false); } return exitCode; }); }; function onUnexpectedError(err: Error) { function indent(str: string): string { return '\n ' + str.trim().split('\n').join('\n '); } const log = []; log.push(`Arguments: ${indent(process.argv.join(' '))}`); log.push(`PATH: ${indent(process.env.PATH || 'undefined')}`); log.push(`Pika version: ${indent(version)}`); log.push(`Node version: ${indent(process.versions.node)}`); log.push(`Platform: ${indent(process.platform + ' ' + process.arch)}`); log.push(`Trace: ${indent(err.stack)}`); reporter.error(reporter.lang('unexpectedError', err.message)); } const config = new Config(reporter, cwd, flags); await config.loadPackageManifest(); try { // option "no-progress" stored in pika config const noProgressConfig = false; //config.registries.pika.getOption('no-progress'); if (noProgressConfig) { reporter.disableProgress(); } // verbose logs outputs process.uptime() with this line we can sync uptime to absolute time on the computer reporter.verbose(`current time: ${new Date().toISOString()}`); return run().then(exit); } catch (err) { reporter.verbose(err.stack); if (err instanceof MessageError) { reporter.error(err.message); } else { onUnexpectedError(err); } return exit(1); } } ================================================ FILE: src/reporters/base-reporter.ts ================================================ import {ReporterSpinnerSet, Trees, Stdout, Stdin, Package, ReporterSpinner} from './types'; import {LanguageKeys} from './lang/en.js'; import {Formatter} from './format.js'; import {defaultFormatter} from './format.js'; import * as languages from './lang/index.js'; import * as isCI from 'is-ci'; import * as os from 'os'; import * as util from 'util'; import {EventEmitter} from 'events'; type Language = keyof typeof languages; export type ReporterOptions = { verbose?: boolean; language?: Language; stdout?: Stdout; stderr?: Stdout; stdin?: Stdin; emoji?: boolean; noProgress?: boolean; silent?: boolean; isSilent?: boolean; nonInteractive?: boolean; }; export function stringifyLangArgs(args: Array): Array { return args.map(function (val): string { if (val != null && val.inspect) { return val.inspect(); } else { try { const str = JSON.stringify(val) || val + ''; // should match all literal line breaks and // "u001b" that follow an odd number of backslashes and convert them to ESC // we do this because the JSON.stringify process has escaped these characters return str .replace(/((?:^|[^\\])(?:\\{2})*)\\u001[bB]/g, '$1\u001b') .replace(/[\\]r[\\]n|([\\])?[\\]n/g, (match, precededBacklash) => { // precededBacklash not null when "\n" is preceded by a backlash ("\\n") // match will be "\\n" and we don't replace it with os.EOL return precededBacklash ? match : os.EOL; }); } catch (e) { return util.inspect(val); } } }); } export default class BaseReporter { constructor(opts: ReporterOptions = {}) { const lang = 'en'; this.language = lang; this.stdout = opts.stdout || process.stdout; this.stderr = opts.stderr || process.stderr; this.stdin = opts.stdin || this._getStandardInput(); this.emoji = !!opts.emoji; this.nonInteractive = !!opts.nonInteractive; this.noProgress = !!opts.noProgress || isCI; this.isVerbose = !!opts.verbose; // @ts-ignore this.isTTY = this.stdout.isTTY; this.peakMemory = 0; this.startTime = Date.now(); this.format = defaultFormatter; } formatter: Formatter; language: Language; stdout: Stdout; stderr: Stdout; stdin: Stdin; isTTY: boolean; emoji: boolean; noProgress: boolean; isVerbose: boolean; isSilent: boolean; nonInteractive: boolean; format: Formatter; peakMemoryInterval?: NodeJS.Timer; peakMemory: number; startTime: number; lang(key: LanguageKeys, ...args: Array): string { const msg = languages[this.language][key] || languages.en[key]; if (!msg) { throw new ReferenceError(`No message defined for language key ${key}`); } // stringify args const stringifiedArgs = stringifyLangArgs(args); // replace $0 placeholders with args return msg.replace(/\$(\d+)/g, (str, i: number) => { return stringifiedArgs[i]; }); } /** * `stringifyLangArgs` run `JSON.stringify` on strings too causing * them to appear quoted. This marks them as "raw" and prevents * the quoting and escaping */ rawText(str: string): {inspect(): string} { return { inspect(): string { return str; }, }; } verbose(msg: string) { if (this.isVerbose) { this._verbose(msg); } } verboseInspect(val: any) { if (this.isVerbose) { this._verboseInspect(val); } } _verbose(msg: string) {} _verboseInspect(val: any) {} _getStandardInput(): Stdin { let standardInput; // Accessing stdin in a win32 headless process (e.g., Visual Studio) may throw an exception. try { standardInput = process.stdin; } catch (e) { console.warn(e.message); delete process.stdin; // @ts-ignore process.stdin = new EventEmitter(); standardInput = process.stdin; } return standardInput; } initPeakMemoryCounter() { this.checkPeakMemory(); this.peakMemoryInterval = setInterval(() => { this.checkPeakMemory(); }, 1000); // $FlowFixMe: Node's setInterval returns a Timeout, not a Number this.peakMemoryInterval.unref(); } checkPeakMemory() { const {heapTotal} = process.memoryUsage(); if (heapTotal > this.peakMemory) { this.peakMemory = heapTotal; } } close() { if (this.peakMemoryInterval) { clearInterval(this.peakMemoryInterval); this.peakMemoryInterval = null; } } getTotalTime(): number { return Date.now() - this.startTime; } // TODO list(key: string, items: Array, hints?: Object) {} // Outputs basic tree structure to console tree(key: string, obj: Trees, {force = false}: {force?: boolean} = {}) {} // called whenever we begin a step in the CLI. step(current: number, total: number, message: string, emoji?: string) {} // a error message has been triggered. this however does not always meant an abrupt // program end. error(message: string) {} // an info message has been triggered. this provides things like stats and diagnostics. info(message: string) {} // a warning message has been triggered. warn(message: string) {} // a success message has been triggered. success(message: string) {} // a simple log message // TODO: rethink the {force} parameter. In the meantime, please don't use it (cf comments in #4143). log(message: string, {force = false}: {force?: boolean} = {}) {} // a shell command has been executed command(command: string) {} // inspect and pretty-print any value inspect(value: any) {} // the screen shown at the very start of the CLI header(pkg: Package) {} // the screen shown at the very end of the CLI footer(showPeakMemory: boolean) {} // a table structure table(head: Array, body: Array>) {} // render an activity spinner and return a function that will trigger an update activity(): ReporterSpinner { return { tick(name: string) {}, end() {}, }; } // activitySet(total: number, workers: number): ReporterSpinnerSet { return { spinners: Array(workers).fill({ clear() {}, setPrefix() {}, tick() {}, end() {}, }), end() {}, }; } // render a progress bar and return a function which when called will trigger an update progress(total: number): () => void { return function () {}; } // utility function to disable progress bar disableProgress() { this.noProgress = true; } } ================================================ FILE: src/reporters/console/console-reporter.ts ================================================ import chalk from 'chalk'; import * as readline from 'readline'; import stripAnsi from 'strip-ansi'; import {inspect} from 'util'; import {removeSuffix} from '../../util/misc.js'; import BaseReporter, {ReporterOptions} from '../base-reporter.js'; import {FormatKeys, Formatter} from '../format.js'; import {Package, ReporterSetSpinner, ReporterSpinner, ReporterSpinnerSet, Trees} from '../types.js'; import {getFormattedOutput, recurseTree, sortTrees} from './helpers/tree-helper.js'; import Progress from './progress-bar.js'; import Spinner from './spinner-progress.js'; import {clearLine} from './util.js'; const AUDIT_COL_WIDTHS = [15, 62]; const auditSeverityColors = { info: chalk.bold, low: chalk.bold, moderate: chalk.yellow, high: chalk.red, critical: chalk.bgRed, }; type Row = Array; // fixes bold on windows if (process.platform === 'win32' && !(process.env.TERM && /^xterm/i.test(process.env.TERM))) { // @ts-ignore chalk.bold._styles[0].close += '\u001b[m'; } export default class ConsoleReporter extends BaseReporter { _lastCategorySize: number; _progressBar?: Progress; _spinners: Set; constructor(opts: ReporterOptions) { super(opts); this._lastCategorySize = 0; this._spinners = new Set(); this.format = (chalk as any) as Formatter; this.format.stripColor = stripAnsi; this.isSilent = !!opts.isSilent; } _prependEmoji(msg: string, emoji?: string): string { if (this.emoji && emoji && this.isTTY) { msg = `${emoji} ${msg}`; } return msg; } _logCategory(category: string, color: FormatKeys, msg: string) { this._lastCategorySize = category.length; this._log(`${this.format[color](category)} ${msg}`); } _verbose(msg: string) { this._logCategory('verbose', 'grey', `${process.uptime()} ${msg}`); } _verboseInspect(obj: any) { this.inspect(obj); } close() { for (const spinner of this._spinners) { spinner.stop(); } this._spinners.clear(); this.stopProgress(); super.close(); } table(head: Array, body: Array) { // head = head.map((field: string): string => this.format.underline(field)); // const rows = [head].concat(body); // get column widths const cols: Array = []; for (let i = 0; i < head.length; i++) { const widths = rows.map((row: Row): number => this.format.stripColor(row[i]).length); cols[i] = Math.max(...widths); } // const builtRows = rows.map((row: Row): string => { for (let i = 0; i < row.length; i++) { const field = row[i]; const padding = cols[i] - this.format.stripColor(field).length; row[i] = field + ' '.repeat(padding); } return row.join(' '); }); this.log(builtRows.join('\n')); } step(current: number, total: number, msg: string, emoji?: string) { msg = this._prependEmoji(msg, emoji); if (msg.endsWith('?')) { msg = `${removeSuffix(msg, '?')}...?`; } else { msg += '...'; } this.log(`${this.format.dim(`[${current}/${total}]`)} ${msg}`); } inspect(value: any) { if (typeof value !== 'number' && typeof value !== 'string') { value = inspect(value, { breakLength: 0, colors: this.isTTY, depth: null, maxArrayLength: null, }); } this.log(String(value), {force: true}); } list(key: string, items: Array, hints?: Object) { const gutterWidth = (this._lastCategorySize || 2) - 1; if (hints) { for (const item of items) { this._log(`${' '.repeat(gutterWidth)}- ${this.format.bold(item)}`); this._log(` ${' '.repeat(gutterWidth)} ${hints[item]}`); } } else { for (const item of items) { this._log(`${' '.repeat(gutterWidth)}- ${item}`); } } } header(pkg: Package) { this.log(this.format.bold(`${pkg.name} v${pkg.version}`)); } footer(showPeakMemory?: boolean) { this.stopProgress(); const totalTime = (this.getTotalTime() / 1000).toFixed(2); let msg = `Done in ${totalTime}s.`; if (showPeakMemory) { const peakMemory = (this.peakMemory / 1024 / 1024).toFixed(2); msg += ` Peak memory usage ${peakMemory}MB.`; } this.log(this._prependEmoji(msg, '✨')); } log(msg: string, {force = false}: {force?: boolean} = {}) { this._lastCategorySize = 0; this._log(msg, {force}); } _log(msg: string, {force = false}: {force?: boolean} = {}) { if (this.isSilent && !force) { return; } clearLine(this.stdout); this.stdout.write(`${msg}\n`); } success(msg: string) { this._logCategory('success', 'green', msg); } error(msg: string) { clearLine(this.stderr); this.stderr.write(`${this.format.red('error')} ${msg}\n`); } info(msg: string) { this._logCategory('info', 'blue', msg); } command(command: string) { this.log(this.format.dim(`$ ${command}`)); } warn(msg: string) { clearLine(this.stderr); this.stderr.write(`${this.format.yellow('warning')} ${msg}\n`); } // handles basic tree output to console tree(key: string, trees: Trees, {force = false}: {force?: boolean} = {}) { this.stopProgress(); // if (this.isSilent && !force) { return; } const output = ({name, children, hint, color}, titlePrefix, childrenPrefix) => { const formatter = this.format; const out = getFormattedOutput({ prefix: titlePrefix, hint, color, name, formatter, }); this.stdout.write(out); if (children && children.length) { recurseTree(sortTrees(children), childrenPrefix, output); } }; recurseTree(sortTrees(trees), '', output); } activitySet(total: number, workers: number): ReporterSpinnerSet { if (!this.isTTY || this.noProgress) { return super.activitySet(total, workers); } const spinners: Array = []; const reporterSpinners = this._spinners; for (let i = 1; i < workers; i++) { this.log(''); } for (let i = 0; i < workers; i++) { const spinner = new Spinner(this.stderr, i); reporterSpinners.add(spinner); spinner.start(); let prefix: string | null = null; let current = 0; const updatePrefix = () => { spinner.setPrefix(`${this.format.dim(`[${current === 0 ? '-' : current}/${total}]`)} `); }; const clear = () => { prefix = null; current = 0; updatePrefix(); spinner.setText('waiting...'); }; clear(); spinners.unshift({ clear, setPrefix(_current: number, _prefix: string) { current = _current; prefix = _prefix; spinner.setText(prefix); updatePrefix(); }, tick(msg: string) { if (prefix) { msg = `${prefix}: ${msg}`; } spinner.setText(msg); }, end() { spinner.stop(); reporterSpinners.delete(spinner); }, }); } return { spinners, end: () => { for (const spinner of spinners) { spinner.end(); } readline.moveCursor(this.stdout, 0, -workers + 1); }, }; } activity(): ReporterSpinner { if (!this.isTTY) { return { tick() {}, end() {}, }; } const reporterSpinners = this._spinners; const spinner = new Spinner(this.stderr); spinner.start(); reporterSpinners.add(spinner); return { tick(name: string) { spinner.setText(name); }, end() { spinner.stop(); reporterSpinners.delete(spinner); }, }; } progress(count: number): () => void { if (this.noProgress || count <= 0) { return function () { // noop }; } if (!this.isTTY) { return function () { // TODO what should the behaviour here be? we could buffer progress messages maybe }; } // Clear any potentially old progress bars this.stopProgress(); const bar = (this._progressBar = new Progress(count, this.stderr, (progress: Progress) => { if (progress === this._progressBar) { this._progressBar = null; } })); bar.render(); return function () { bar.tick(); }; } stopProgress() { if (this._progressBar) { this._progressBar.stop(); } } } ================================================ FILE: src/reporters/console/helpers/tree-helper.ts ================================================ // types import {Trees} from '../../types.js'; export type FormattedOutput = { prefix: string; hint: any; color: string; name: string; formatter: any; }; // public export function sortTrees(trees: Trees): Trees { return trees.sort(function (tree1, tree2): number { return tree1.name.localeCompare(tree2.name); }); } export function recurseTree(tree: Trees, prefix: string, recurseFunc: Function) { const treeLen = tree.length; const treeEnd = treeLen - 1; for (let i = 0; i < treeLen; i++) { const atEnd = i === treeEnd; recurseFunc(tree[i], prefix + getLastIndentChar(atEnd), prefix + getNextIndentChar(atEnd)); } } export function getFormattedOutput(fmt: FormattedOutput): string { const item = formatColor(fmt.color, fmt.name, fmt.formatter); const suffix = getSuffix(fmt.hint, fmt.formatter); return `${fmt.prefix}─ ${item}${suffix}\n`; } function getNextIndentChar(end: boolean): string { return end ? ' ' : '│ '; } function getLastIndentChar(end: boolean): string { return end ? '└' : '├'; } function getSuffix(hint: any, formatter: any): string { return hint ? ` (${formatter.grey(hint)})` : ''; } function formatColor(color: string, strToFormat: string, formatter: any): string { return color ? formatter[color](strToFormat) : strToFormat; } ================================================ FILE: src/reporters/console/progress-bar.ts ================================================ import {Stdout} from '../types.js'; import {clearLine, toStartOfLine} from './util.js'; export default class ProgressBar { constructor(total: number, stdout: Stdout = process.stderr, callback?: (progressBar: ProgressBar) => void) { this.stdout = stdout; this.total = total; this.chars = ProgressBar.bars[0]; this.delay = 60; this.curr = 0; this._callback = callback; clearLine(stdout); } stdout: Stdout; curr: number; total: number; width: number; chars: [string, string]; delay: number; id?: NodeJS.Timeout; _callback?: (progressBar: ProgressBar) => void; static bars: [string, string][] = [['#', '-']]; tick() { if (this.curr >= this.total) { return; } this.curr++; // schedule render if (!this.id) { this.id = setTimeout((): void => this.render(), this.delay); } } cancelTick() { if (this.id) { clearTimeout(this.id); this.id = null; } } stop() { // "stop" by setting current to end so `tick` becomes noop this.curr = this.total; this.cancelTick(); clearLine(this.stdout); if (this._callback) { this._callback(this); } } render() { // clear throttle this.cancelTick(); let ratio = this.curr / this.total; ratio = Math.min(Math.max(ratio, 0), 1); // progress without bar let bar = ` ${this.curr}/${this.total}`; // calculate size of actual bar // $FlowFixMe: investigate process.stderr.columns flow error // @ts-ignore const availableSpace = Math.max(0, this.stdout.columns - bar.length - 3); const width = Math.min(this.total, availableSpace); const completeLength = Math.round(width * ratio); const complete = this.chars[0].repeat(completeLength); const incomplete = this.chars[1].repeat(width - completeLength); bar = `[${complete}${incomplete}]${bar}`; toStartOfLine(this.stdout); this.stdout.write(bar); } } ================================================ FILE: src/reporters/console/spinner-progress.ts ================================================ import {Stdout} from '../types.js'; import {writeOnNthLine, clearNthLine} from './util.js'; export default class Spinner { constructor(stdout: Stdout = process.stderr, lineNumber: number = 0) { this.current = 0; this.prefix = ''; this.lineNumber = lineNumber; this.stdout = stdout; this.delay = 60; this.chars = Spinner.spinners[28].split(''); this.text = ''; this.id = null; } stdout: Stdout; prefix: string; current: number; lineNumber: number; delay: number; chars: Array; text: string; id?: NodeJS.Timeout; static spinners: Array = [ '|/-\\', '⠂-–—–-', '◐◓◑◒', '◴◷◶◵', '◰◳◲◱', '▖▘▝▗', '■□▪▫', '▌▀▐▄', '▉▊▋▌▍▎▏▎▍▌▋▊▉', '▁▃▄▅▆▇█▇▆▅▄▃', '←↖↑↗→↘↓↙', '┤┘┴└├┌┬┐', '◢◣◤◥', '.oO°Oo.', '.oO@*', '🌍🌎🌏', '◡◡ ⊙⊙ ◠◠', '☱☲☴', '⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏', '⠋⠙⠚⠞⠖⠦⠴⠲⠳⠓', '⠄⠆⠇⠋⠙⠸⠰⠠⠰⠸⠙⠋⠇⠆', '⠋⠙⠚⠒⠂⠂⠒⠲⠴⠦⠖⠒⠐⠐⠒⠓⠋', '⠁⠉⠙⠚⠒⠂⠂⠒⠲⠴⠤⠄⠄⠤⠴⠲⠒⠂⠂⠒⠚⠙⠉⠁', '⠈⠉⠋⠓⠒⠐⠐⠒⠖⠦⠤⠠⠠⠤⠦⠖⠒⠐⠐⠒⠓⠋⠉⠈', '⠁⠁⠉⠙⠚⠒⠂⠂⠒⠲⠴⠤⠄⠄⠤⠠⠠⠤⠦⠖⠒⠐⠐⠒⠓⠋⠉⠈⠈', '⢄⢂⢁⡁⡈⡐⡠', '⢹⢺⢼⣸⣇⡧⡗⡏', '⣾⣽⣻⢿⡿⣟⣯⣷', '⠁⠂⠄⡀⢀⠠⠐⠈', ]; setPrefix(prefix: string) { this.prefix = prefix; } setText(text: string) { this.text = text; } start() { this.current = 0; this.render(); } render() { if (this.id) { clearTimeout(this.id); } // build line ensuring we don't wrap to the next line let msg = `${this.prefix}${this.chars[this.current]} ${this.text}`; // @ts-ignore const columns = typeof this.stdout.columns === 'number' ? this.stdout.columns : 100; msg = msg.slice(0, columns); writeOnNthLine(this.stdout, this.lineNumber, msg); this.current = ++this.current % this.chars.length; this.id = setTimeout((): void => this.render(), this.delay); } stop() { if (this.id) { clearTimeout(this.id); this.id = null; } clearNthLine(this.stdout, this.lineNumber); } } ================================================ FILE: src/reporters/console/util.ts ================================================ import * as tty from 'tty'; import {Stdout} from '../types.js'; import * as readline from 'readline'; import chalk from 'chalk'; const CLEAR_WHOLE_LINE = 0; const CLEAR_RIGHT_OF_CURSOR = 1; export function clearLine(stdout: Stdout) { if (!chalk.supportsColor) { if (stdout instanceof tty.WriteStream) { if (stdout.columns > 0) { stdout.write(`\r${' '.repeat(stdout.columns - 1)}`); } stdout.write(`\r`); } return; } readline.clearLine(stdout, CLEAR_WHOLE_LINE); readline.cursorTo(stdout, 0); } export function toStartOfLine(stdout: Stdout) { if (!chalk.supportsColor) { stdout.write('\r'); return; } readline.cursorTo(stdout, 0); } export function writeOnNthLine(stdout: Stdout, n: number, msg: string) { if (!chalk.supportsColor) { return; } if (n == 0) { readline.cursorTo(stdout, 0); stdout.write(msg); readline.clearLine(stdout, CLEAR_RIGHT_OF_CURSOR); return; } readline.cursorTo(stdout, 0); readline.moveCursor(stdout, 0, -n); stdout.write(msg); readline.clearLine(stdout, CLEAR_RIGHT_OF_CURSOR); readline.cursorTo(stdout, 0); readline.moveCursor(stdout, 0, n); } export function clearNthLine(stdout: Stdout, n: number) { if (!chalk.supportsColor) { return; } if (n == 0) { clearLine(stdout); return; } readline.cursorTo(stdout, 0); readline.moveCursor(stdout, 0, -n); readline.clearLine(stdout, CLEAR_WHOLE_LINE); readline.moveCursor(stdout, 0, n); } ================================================ FILE: src/reporters/format.ts ================================================ function formatFunction(...strs: Array): string { return strs.join(' '); } export const defaultFormatter = { bold: formatFunction, dim: formatFunction, italic: formatFunction, underline: formatFunction, inverse: formatFunction, strikethrough: formatFunction, black: formatFunction, red: formatFunction, green: formatFunction, yellow: formatFunction, blue: formatFunction, magenta: formatFunction, cyan: formatFunction, white: formatFunction, gray: formatFunction, grey: formatFunction, stripColor: formatFunction, }; type FormatFunction = (...strs: Array) => string; export type FormatKeys = keyof typeof defaultFormatter; export type Formatter = { bold: FormatFunction; dim: FormatFunction; italic: FormatFunction; underline: FormatFunction; inverse: FormatFunction; strikethrough: FormatFunction; black: FormatFunction; red: FormatFunction; green: FormatFunction; yellow: FormatFunction; blue: FormatFunction; magenta: FormatFunction; cyan: FormatFunction; white: FormatFunction; gray: FormatFunction; grey: FormatFunction; stripColor: FormatFunction; }; ================================================ FILE: src/reporters/index.ts ================================================ export {default as ConsoleReporter} from './console/console-reporter'; export {default as JSONReporter} from './json-reporter'; export {default as NoopReporter} from './noop-reporter'; export {default as Reporter} from './base-reporter'; ================================================ FILE: src/reporters/json-reporter.ts ================================================ import {ReporterSpinnerSet, Trees, ReporterSpinner} from './types.js'; import BaseReporter from './base-reporter.js'; export default class JSONReporter extends BaseReporter { constructor(opts?: Object) { super(opts); this._activityId = 0; this._progressId = 0; } _activityId: number; _progressId: number; _dump(type: string, data: any, error?: boolean) { let stdout = this.stdout; if (error) { stdout = this.stderr; } stdout.write(`${JSON.stringify({type, data})}\n`); } _verbose(msg: string) { this._dump('verbose', msg); } list(type: string, items: Array, hints?: Object) { this._dump('list', {type, items, hints}); } tree(type: string, trees: Trees) { this._dump('tree', {type, trees}); } step(current: number, total: number, message: string) { this._dump('step', {message, current, total}); } inspect(value: any) { this._dump('inspect', value); } footer(showPeakMemory: boolean) { this._dump('finished', this.getTotalTime()); } log(msg: string) { this._dump('log', msg); } command(msg: string) { this._dump('command', msg); } table(head: Array, body: Array>) { this._dump('table', {head, body}); } success(msg: string) { this._dump('success', msg); } error(msg: string) { this._dump('error', msg, true); } warn(msg: string) { this._dump('warning', msg, true); } info(msg: string) { this._dump('info', msg); } activitySet(total: number, workers: number): ReporterSpinnerSet { if (!this.isTTY || this.noProgress) { return super.activitySet(total, workers); } const id = this._activityId++; this._dump('activitySetStart', {id, total, workers}); const spinners = []; for (let i = 0; i < workers; i++) { let current = 0; let header = ''; spinners.push({ clear() {}, setPrefix(_current: number, _header: string) { current = _current; header = _header; }, tick: (msg) => { this._dump('activitySetTick', { id, header, current, worker: i, message: msg, }); }, end() {}, }); } return { spinners, end: () => { this._dump('activitySetEnd', {id}); }, }; } activity(): ReporterSpinner { return this._activity({}); } _activity(data: Object): ReporterSpinner { if (!this.isTTY || this.noProgress) { return { tick() {}, end() {}, }; } const id = this._activityId++; this._dump('activityStart', {id, ...data}); return { tick: (name: string) => { this._dump('activityTick', {id, name}); }, end: () => { this._dump('activityEnd', {id}); }, }; } progress(total: number): () => void { if (this.noProgress) { return function () { // noop }; } const id = this._progressId++; let current = 0; this._dump('progressStart', {id, total}); return () => { current++; this._dump('progressTick', {id, current}); if (current === total) { this._dump('progressFinish', {id}); } }; } } ================================================ FILE: src/reporters/lang/en.ts ================================================ const messages = { upToDate: 'Already up-to-date.', folderInSync: 'Folder in sync.', nothingToInstall: 'Nothing to install.', resolvingPackages: 'Resolving packages', checkingManifest: 'Validating package.json', fetchingPackages: 'Fetching packages', linkingDependencies: 'Linking dependencies', rebuildingPackages: 'Rebuilding all packages', buildingFreshPackages: 'Building fresh packages', cleaningModules: 'Cleaning modules', bumpingVersion: 'Bumping version', savingHar: 'Saving HAR file: $0', answer: 'Answer?', usage: 'Usage', installCommandRenamed: '`install` has been replaced with `add` to add new dependencies. Run $0 instead.', globalFlagRemoved: '`--global` has been deprecated. Please run $0 instead.', waitingInstance: 'Waiting for the other pika instance to finish (pid $0, inside $1)', waitingNamedInstance: 'Waiting for the other pika instance to finish ($0)', offlineRetrying: 'There appears to be trouble with your network connection. Retrying...', internalServerErrorRetrying: 'There appears to be trouble with the npm registry (returned $1). Retrying...', clearedCache: 'Cleared cache.', couldntClearPackageFromCache: "Couldn't clear package $0 from cache", clearedPackageFromCache: 'Cleared package $0 from cache', packWroteTarball: 'Wrote tarball to $0.', helpExamples: ' Examples:\n$0\n', helpCommands: ' Commands:\n$0\n', helpCommandsMore: ' Run `$0` for more information on specific commands.', helpLearnMore: ' Visit $0 to learn more about Pika.\n', manifestPotentialTypo: 'Potential typo $0, did you mean $1?', manifestBuiltinModule: '$0 is also the name of a node core module', manifestNameDot: "Name can't start with a dot", manifestNameIllegalChars: 'Name contains illegal characters', manifestNameBlacklisted: 'Name is blacklisted', manifestLicenseInvalid: 'License should be a valid SPDX license expression', manifestLicenseNone: 'No license field', manifestStringExpected: '$0 is not a string', manifestDependencyCollision: '$0 has dependency $1 with range $2 that collides with a dependency in $3 of the same name with version $4', manifestDirectoryNotFound: 'Unable to read $0 directory of module $1', verboseFileCopy: 'Copying $0 to $1.', verboseFileLink: 'Creating hardlink at $0 to $1.', verboseFileSymlink: 'Creating symlink at $0 to $1.', verboseFileSkip: 'Skipping copying of file $0 as the file at $1 is the same size ($2) and mtime ($3).', verboseFileSkipSymlink: 'Skipping copying of $0 as the file at $1 is the same symlink ($2).', verboseFileSkipHardlink: 'Skipping copying of $0 as the file at $1 is the same hardlink ($2).', verboseFileRemoveExtraneous: 'Removing extraneous file $0.', verboseFilePhantomExtraneous: "File $0 would be marked as extraneous but has been removed as it's listed as a phantom file.", verboseFileSkipArtifact: 'Skipping copying of $0 as the file is marked as a built artifact and subject to change.', verboseFileFolder: 'Creating directory $0.', verboseRequestStart: 'Performing $0 request to $1.', verboseRequestFinish: 'Request $0 finished with status code $1.', configSet: 'Set $0 to $1.', configDelete: 'Deleted $0.', configNpm: 'npm config', configPika: 'pika config', couldntFindPackagejson: "Couldn't find a package.json file in $0", couldntFindMatch: "Couldn't find match for $0 in $1 for $2.", couldntFindPackageInCache: "Couldn't find any versions for $0 that matches $1 in our cache (possible versions are $2). This is usually caused by a missing entry in the lockfile, running Pika without the --offline flag may help fix this issue.", couldntFindVersionThatMatchesRange: "Couldn't find any versions for $0 that matches $1", chooseVersionFromList: 'Please choose a version of $0 from this list:', moduleNotInManifest: "This module isn't specified in a package.json file.", moduleAlreadyInManifest: '$0 is already in $1. Please remove existing entry first before adding it to $2.', unknownFolderOrTarball: "Passed folder/tarball doesn't exist,", unknownPackage: "Couldn't find package $0.", unknownPackageName: "Couldn't find package name.", unknownUser: "Couldn't find user $0.", unknownRegistryResolver: 'Unknown registry resolver $0', userNotAnOwner: "User $0 isn't an owner of this package.", invalidVersionArgument: 'Use the $0 flag to create a new version.', invalidVersion: 'Invalid version supplied.', requiredVersionInRange: 'Required version in range.', packageNotFoundRegistry: "Couldn't find package $0 on the $1 registry.", requiredPackageNotFoundRegistry: "Couldn't find package $0 required by $1 on the $2 registry.", doesntExist: "Package $1 refers to a non-existing file '$0'.", missingRequiredPackageKey: `Package $0 doesn't have a $1.`, invalidAccess: 'Invalid argument for access, expected public or restricted.', invalidCommand: 'Invalid subcommand. Try $0', invalidGistFragment: 'Invalid gist fragment $0.', invalidHostedGitFragment: 'Invalid hosted git fragment $0.', invalidFragment: 'Invalid fragment $0.', invalidPackageName: 'Invalid package name.', invalidPackageVersion: "Can't add $0: invalid package version $1.", couldntFindManifestIn: "Couldn't find manifest in $0.", shrinkwrapWarning: 'npm-shrinkwrap.json found. This will not be updated or respected. See https://yarnpkg.com/en/docs/migrating-from-npm for more information.', npmLockfileWarning: 'package-lock.json found. Your project contains lock files generated by tools other than Pika. It is advised not to mix package managers in order to avoid resolution inconsistencies caused by unsynchronized lock files. To clear this warning, remove package-lock.json.', lockfileOutdated: 'Outdated lockfile. Please run `pika install` and try again.', lockfileMerged: 'Merge conflict detected in pika.lock and successfully merged.', lockfileConflict: 'A merge conflict was found in pika.lock but it could not be successfully merged, regenerating pika.lock from scratch.', ignoredScripts: 'Ignored scripts due to flag.', missingAddDependencies: 'Missing list of packages to add to your project.', yesWarning: 'The yes flag has been set. This will automatically answer yes to all questions, which may have security implications.', networkWarning: "You don't appear to have an internet connection. Try the --offline flag to use the cache for registry queries.", flatGlobalError: 'The package $0 requires a flat dependency graph. Add `"flat": true` to your package.json and try again.', noName: `Package doesn't have a name.`, noVersion: `Package doesn't have a version.`, answerRequired: 'An answer is required.', missingWhyDependency: 'Missing package name, folder or path to file to identify why a package has been installed', bugReport: 'If you think this is a bug, please open a bug report with the information provided in $0.', unexpectedError: 'An unexpected error occurred: $0.', jsonError: 'Error parsing JSON at $0, $1.', noPermission: 'Cannot create $0 due to insufficient permissions.', noGlobalFolder: 'Cannot find a suitable global folder. Tried these: $0', allDependenciesUpToDate: 'All of your dependencies are up to date.', legendColorsForVersionUpdates: 'Color legend : \n $0 : Major Update backward-incompatible updates \n $1 : Minor Update backward-compatible features \n $2 : Patch Update backward-compatible bug fixes', frozenLockfileError: 'Your lockfile needs to be updated, but pika was run with `--frozen-lockfile`.', fileWriteError: 'Could not write file $0: $1', fileDeleteError: 'Could not delete file $0: $1', multiplePackagesCantUnpackInSameDestination: 'Pattern $0 is trying to unpack in the same destination $1 as pattern $2. This could result in non-deterministic behavior, skipping.', incorrectLockfileEntry: 'Lockfile has incorrect entry for $0. Ignoring it.', invalidResolutionName: 'Resolution field $0 does not end with a valid package name and will be ignored', invalidResolutionVersion: 'Resolution field $0 has an invalid version entry and may be ignored', incompatibleResolutionVersion: 'Resolution field $0 is incompatible with requested version $1', pikaOutdated: "Your current version of Pika is out of date. The latest version is $0, while you're on $1.", pikaOutdatedInstaller: 'To upgrade, download the latest installer at $0.', pikaOutdatedCommand: 'To upgrade, run the following command:', tooManyArguments: 'Too many arguments, maximum of $0.', tooFewArguments: 'Not enough arguments, expected at least $0.', noArguments: "This command doesn't require any arguments.", ownerRemoving: 'Removing owner $0 from package $1.', ownerRemoved: 'Owner removed.', ownerRemoveError: "Couldn't remove owner.", ownerGetting: 'Getting owners for package $0', ownerGettingFailed: "Couldn't get list of owners.", ownerAlready: 'This user is already an owner of this package.', ownerAdded: 'Added owner.', ownerAdding: 'Adding owner $0 to package $1', ownerAddingFailed: "Couldn't add owner.", ownerNone: 'No owners.', teamCreating: 'Creating team', teamRemoving: 'Removing team', teamAddingUser: 'Adding user to team', teamRemovingUser: 'Removing user from team', teamListing: 'Listing teams', distFailed: `⚠️ Distribution "$0" failed to build: $1 $2`, distExiting: ` Exiting...`, distContinuing: ` Continuing...`, cleaning: 'Cleaning modules', cleanCreatingFile: 'Creating $0', cleanCreatedFile: 'Created $0. Please review the contents of this file then run "pika autoclean --force" to perform a clean.', cleanAlreadyExists: '$0 already exists. To revert to the default file, delete $0 then rerun this command.', cleanRequiresForce: 'This command required the "--force" flag to perform the clean. This is a destructive operation. Files specified in $0 will be deleted.', cleanDoesNotExist: '$0 does not exist. Autoclean will delete files specified by $0. Run "autoclean --init" to create $0 with the default entries.', binLinkCollision: "There's already a linked binary called $0 in your global Pika bin. Could not link this package's $0 bin entry.", linkCollision: "There's already a package called $0 registered. This command has had no effect. If this command was run in another folder with the same name, the other folder is still linked. Please run pika unlink in the other folder if you want to register this folder.", linkMissing: 'No registered package found called $0.', linkRegistered: 'Registered $0.', linkRegisteredMessage: 'You can now run `pika link $0` in the projects where you want to use this package and it will be used instead.', linkUnregistered: 'Unregistered $0.', linkUnregisteredMessage: 'You can now run `pika unlink $0` in the projects where you no longer want to use this package.', linkUsing: 'Using linked package for $0.', linkDisusing: 'Removed linked package $0.', linkDisusingMessage: 'You will need to run `pika` to re-install the package that was linked.', linkTargetMissing: 'The target of linked package $0 is missing. Removing link.', createInvalidBin: 'Invalid bin entry found in package $0.', createMissingPackage: 'Package not found - this is probably an internal error, and should be reported at https://github.com/yarnpkg/yarn/issues.', workspacesAddRootCheck: 'Running this command will add the dependency to the workspace root rather than the workspace itself, which might not be what you want - if you really meant it, make it explicit by running this command again with the -W flag (or --ignore-workspace-root-check).', workspacesRemoveRootCheck: 'Running this command will remove the dependency from the workspace root rather than the workspace itself, which might not be what you want - if you really meant it, make it explicit by running this command again with the -W flag (or --ignore-workspace-root-check).', workspacesFocusRootCheck: 'This command can only be run inside an individual workspace.', workspacesRequirePrivateProjects: 'Workspaces can only be enabled in private projects.', workspacesSettingMustBeArray: 'The workspaces field in package.json must be an array.', workspacesDisabled: 'Your project root defines workspaces but the feature is disabled in your Pika config. Please check "workspaces-experimental" in your .pikarc file.', workspacesNohoistRequirePrivatePackages: 'nohoist config is ignored in $0 because it is not a private package. If you think nohoist should be allowed in public packages, please submit an issue for your use case.', workspacesNohoistDisabled: `$0 defines nohoist but the feature is disabled in your Pika config ("workspaces-nohoist-experimental" in .pikarc file)`, workspaceRootNotFound: "Cannot find the root of your workspace - are you sure you're currently in a workspace?", workspaceMissingWorkspace: 'Missing workspace name.', workspaceMissingCommand: 'Missing command name.', workspaceUnknownWorkspace: 'Unknown workspace $0.', workspaceVersionMandatory: 'Missing version in workspace at $0, ignoring.', workspaceNameMandatory: 'Missing name in workspace at $0, ignoring.', workspaceNameDuplicate: 'There are more than one workspace with name $0', cacheFolderSkipped: 'Skipping preferred cache folder $0 because it is not writable.', cacheFolderMissing: "Pika hasn't been able to find a cache folder it can use. Please use the explicit --cache-folder option to tell it what location to use, or make one of the preferred locations writable.", cacheFolderSelected: 'Selected the next writable cache folder in the list, will be $0.', execMissingCommand: 'Missing command name.', noScriptsAvailable: 'There are no scripts specified inside package.json.', noBinAvailable: 'There are no binary scripts available.', dashDashDeprecation: `From Pika 1.0 onwards, scripts don't require "--" for options to be forwarded. In a future version, any explicit "--" will be forwarded as-is to the scripts.`, commandNotSpecified: 'No command specified.', binCommands: 'Commands available from binary scripts: ', possibleCommands: 'Project commands', commandQuestion: 'Which command would you like to run?', commandFailedWithCode: 'Command failed with exit code $0.', commandFailedWithSignal: 'Command failed with signal $0.', packageRequiresNodeGyp: 'This package requires node-gyp, which is not currently installed. Pika will attempt to automatically install it. If this fails, you can run "pika global add node-gyp" to manually install it.', nodeGypAutoInstallFailed: 'Failed to auto-install node-gyp. Please run "pika global add node-gyp" manually. Error: $0', foundIncompatible: 'Found incompatible module', incompatibleEngine: 'The engine $0 is incompatible with this module. Expected version $1. Got $2', incompatibleCPU: 'The CPU architecture $0 is incompatible with this module.', incompatibleOS: 'The platform $0 is incompatible with this module.', invalidEngine: 'The engine $0 appears to be invalid.', optionalCompatibilityExcluded: '$0 is an optional dependency and failed compatibility check. Excluding it from installation.', optionalModuleFail: 'This module is OPTIONAL, you can safely ignore this error', optionalModuleScriptFail: 'Error running install script for optional dependency: $0', optionalModuleCleanupFail: 'Could not cleanup build artifacts from failed install: $0', unmetPeer: '$0 has unmet peer dependency $1.', incorrectPeer: '$0 has incorrect peer dependency $1.', selectedPeer: 'Selecting $1 at level $2 as the peer dependency of $0.', missingBundledDependency: '$0 is missing a bundled dependency $1. This should be reported to the package maintainer.', savedNewDependency: 'Saved 1 new dependency.', savedNewDependencies: 'Saved $0 new dependencies.', directDependencies: 'Direct dependencies', allDependencies: 'All dependencies', foundWarnings: 'Found $0 warnings.', foundErrors: 'Found $0 errors.', savedLockfile: 'Saved lockfile.', noRequiredLockfile: 'No lockfile in this directory. Run `pika install` to generate one.', noLockfileFound: 'No lockfile found.', invalidSemver: 'Invalid semver version', newVersion: 'New version', currentVersion: 'Current version', noVersionOnPublish: 'Proceeding with current version', manualVersionResolution: 'Unable to find a suitable version for $0, please choose one by typing one of the numbers below:', manualVersionResolutionOption: '$0 which resolved to $1', createdTag: 'Created tag.', createdTagFail: "Couldn't add tag.", deletedTag: 'Deleted tag.', deletedTagFail: "Couldn't delete tag.", gettingTags: 'Getting tags', deletingTags: 'Deleting tag', creatingTag: 'Creating tag $0 = $1', whyStart: 'Why do we have the module $0?', whyFinding: 'Finding dependency', whyCalculating: 'Calculating file sizes', whyUnknownMatch: "We couldn't find a match!", whyInitGraph: 'Initialising dependency graph', whyWhoKnows: "We don't know why this module exists", whyDiskSizeWithout: 'Disk size without dependencies: $0', whyDiskSizeUnique: 'Disk size with unique dependencies: $0', whyDiskSizeTransitive: 'Disk size with transitive dependencies: $0', whySharedDependencies: 'Number of shared dependencies: $0', whyHoistedTo: `Has been hoisted to $0`, whyHoistedFromSimple: `This module exists because it's hoisted from $0.`, whyNotHoistedSimple: `This module exists here because it's in the nohoist list $0.`, whyDependedOnSimple: `This module exists because $0 depends on it.`, whySpecifiedSimple: `This module exists because it's specified in $0.`, whyReasons: 'Reasons this module exists', whyHoistedFrom: 'Hoisted from $0', whyNotHoisted: `in the nohoist list $0`, whyDependedOn: '$0 depends on it', whySpecified: `Specified in $0`, whyMatch: `\r=> Found $0`, uninstalledPackages: 'Uninstalled packages.', uninstallRegenerate: 'Regenerating lockfile and installing missing dependencies', cleanRemovedFiles: 'Removed $0 files', cleanSavedSize: 'Saved $0 MB.', configFileFound: 'Found configuration file $0.', configPossibleFile: 'Checking for configuration file $0.', npmUsername: 'npm username', npmPassword: 'npm password', npmEmail: 'npm email', npmOneTimePassword: 'npm one-time password', loggingIn: 'Logging in', loggedIn: 'Logged in.', notRevokingEnvToken: 'Not revoking login token, specified via environment variable.', notRevokingConfigToken: 'Not revoking login token, specified via config file.', noTokenToRevoke: 'No login token to revoke.', revokingToken: 'Revoking token', revokedToken: 'Revoked login token.', loginAsPublic: 'Logging in as public', incorrectCredentials: 'Incorrect username or password.', incorrectOneTimePassword: 'Incorrect one-time password.', twoFactorAuthenticationEnabled: 'Two factor authentication enabled.', clearedCredentials: 'Cleared login credentials.', publishFail: "Couldn't publish package: $0", publishPrivate: 'Package marked as private, not publishing.', published: 'Published.', publishing: 'Publishing', nonInteractiveNoVersionSpecified: 'You must specify a new version with --new-version when running with --non-interactive.', nonInteractiveNoToken: "No token found and can't prompt for login when running with --non-interactive.", infoFail: 'Received invalid response from npm.', malformedRegistryResponse: 'Received malformed response from registry for $0. The registry may be down.', registryNoVersions: 'No valid versions found for $0. The package may be unpublished.', cantRequestOffline: "Can't make a request in offline mode ($0)", requestManagerNotSetupHAR: 'RequestManager was not setup to capture HAR files', requestError: 'Request $0 returned a $1', requestFailed: 'Request failed $0', tarballNotInNetworkOrCache: '$0: Tarball is not in network and can not be located in cache ($1)', fetchBadHashWithPath: "Integrity check failed for $0 (computed integrity doesn't match our records, got $2)", fetchBadIntegrityAlgorithm: 'Integrity checked failed for $0 (none of the specified algorithms are supported)', fetchErrorCorrupt: '$0. Mirror tarball appears to be corrupt. You can resolve this by running:\n\n rm -rf $1\n pika install', errorExtractingTarball: 'Extracting tar content of $1 failed, the file appears to be corrupt: $0', updateInstalling: 'Installing $0...', hostedGitResolveError: 'Error connecting to repository. Please, check the url.', unknownFetcherFor: 'Unknown fetcher for $0', downloadGitWithoutCommit: 'Downloading the git repo $0 over plain git without a commit hash', downloadHTTPWithoutCommit: 'Downloading the git repo $0 over HTTP without a commit hash', unplugDisabled: "Packages can only be unplugged when Plug'n'Play is enabled.", plugnplayWindowsSupport: "Plug'n'Play on Windows doesn't support the cache and project to be kept on separate drives", packageInstalledWithBinaries: 'Installed $0 with binaries:', packageHasBinaries: '$0 has binaries:', packageHasNoBinaries: '$0 has no binaries', packageBinaryNotFound: "Couldn't find a binary named $0", couldBeDeduped: '$0 could be deduped from $1 to $2', lockfileNotContainPattern: 'Lockfile does not contain pattern: $0', integrityCheckFailed: 'Integrity check failed', noIntegrityFile: "Couldn't find an integrity file", integrityFailedExpectedIsNotAJSON: 'Integrity check: integrity file is not a json', integrityCheckLinkedModulesDontMatch: "Integrity check: Linked modules don't match", integrityFlagsDontMatch: "Integrity check: Flags don't match", integrityLockfilesDontMatch: "Integrity check: Lock files don't match", integrityFailedFilesMissing: 'Integrity check: Files are missing', integrityPatternsDontMatch: "Integrity check: Top level patterns don't match", integrityModulesFoldersMissing: 'Integrity check: Some module folders are missing', integritySystemParamsDontMatch: "Integrity check: System parameters don't match", packageNotInstalled: '$0 not installed', optionalDepNotInstalled: 'Optional dependency $0 not installed', packageWrongVersion: '$0 is wrong version: expected $1, got $2', packageDontSatisfy: "$0 doesn't satisfy found match of $1", lockfileExists: 'Lockfile already exists, not migrating.', pikaManifestExists: 'pika.package.json manifest already exists, not migrating.', noManifestExists: 'No package.json manifest found. Run `pika init` to generate a new pika.package.json manifest.', skippingImport: 'Skipping import of $0 for $1', importFailed: 'Import of $0 for $1 failed, resolving normally.', importResolveFailed: 'Import of $0 failed starting in $1', importResolvedRangeMatch: 'Using version $0 of $1 instead of $2 for $3', importSourceFilesCorrupted: 'Failed to import from package-lock.json, source file(s) corrupted', importPackageLock: 'found npm package-lock.json, converting to pika.lock', importYarnLock: 'found yarn.lock, converting to pika.lock', importNodeModules: 'creating pika.lock from local node_modules folder', packageContainsPikaAsGlobal: 'Installing Pika via Pika will result in you having two separate versions of Pika installed at the same time, which is not recommended. To update Pika please follow https://yarnpkg.com/en/docs/install .', watchStarting: `Starting up`, watchRunning: `Ready! Watching source tree for changes`, watchRebuild: `Rebuilding...`, watchError: `Build error!`, noValidationErrors: `0 Validation Errors found.`, validationErrors: `$0 Validation Error(s) found. Resolve before publishing.`, scopeNotValid: 'The specified scope is not valid.', deprecatedCommand: '$0 is deprecated. Please use $1.', deprecatedListArgs: 'Filtering by arguments is deprecated. Please use the pattern option instead.', implicitFileDeprecated: 'Using the "file:" protocol implicitly is deprecated. Please either prepend the protocol or prepend the path $0 with "./".', unsupportedNodeVersion: 'You are using Node $0 which is not supported and may encounter bugs or unexpected behavior. Pika supports the following semver range: $1', verboseUpgradeBecauseRequested: 'Considering upgrade of $0 to $1 because it was directly requested.', verboseUpgradeBecauseOutdated: 'Considering upgrade of $0 to $1 because a newer version exists in the registry.', verboseUpgradeNotUnlocking: 'Not unlocking $0 in the lockfile because it is a new or direct dependency.', verboseUpgradeUnlocking: 'Unlocking $0 in the lockfile.', folderMissing: "Directory $0 doesn't exist", mutexPortBusy: 'Cannot use the network mutex on port $0. It is probably used by another app.', auditRunning: 'Auditing packages', auditSummary: '$0 vulnerabilities found - Packages audited: $1', auditSummarySeverity: 'Severity:', auditCritical: '$0 Critical', auditHigh: '$0 High', auditModerate: '$0 Moderate', auditLow: '$0 Low', auditInfo: '$0 Info', auditResolveCommand: '# Run $0 to resolve $1 $2', auditSemverMajorChange: 'SEMVER WARNING: Recommended action is a potentially breaking change', auditManualReview: 'Manual Review\nSome vulnerabilities require your attention to resolve\n\nVisit https://go.npm.me/audit-guide for additional guidance', auditRunAuditForDetails: 'Security audit found potential problems. Run "pika audit" for additional details.', auditOffline: 'Skipping audit. Security audit cannot be performed in offline mode.', }; export type LanguageKeys = keyof typeof messages; export default messages; ================================================ FILE: src/reporters/lang/index.ts ================================================ import en from './en.js'; export {en}; ================================================ FILE: src/reporters/noop-reporter.ts ================================================ import BaseReporter from './base-reporter.js'; import {LanguageKeys} from './lang/en.js'; import {Package, ReporterSpinner, ReporterSpinnerSet, Trees} from './types.js'; export default class NoopReporter extends BaseReporter { lang(key: LanguageKeys, ...args: Array): string { return 'do nothing'; } verbose(msg: string) {} verboseInspect(val: any) {} initPeakMemoryCounter() {} checkPeakMemory() {} close() {} getTotalTime(): number { return 0; } list(key: string, items: Array, hints?: Object) {} tree(key: string, obj: Trees) {} step(current: number, total: number, message: string, emoji?: string) {} error(message: string) {} info(message: string) {} warn(message: string) {} success(message: string) {} log(message: string) {} command(command: string) {} inspect(value: any) {} header(pkg: Package) {} footer(showPeakMemory: boolean) {} table(head: Array, body: Array>) {} activity(): ReporterSpinner { return { tick(name: string) {}, end() {}, }; } activitySet(total: number, workers: number): ReporterSpinnerSet { return { spinners: Array(workers).fill({ clear() {}, setPrefix() {}, tick() {}, end() {}, }), end() {}, }; } progress(total: number): () => void { return function () {}; } disableProgress() { this.noProgress = true; } } ================================================ FILE: src/reporters/types.ts ================================================ import {Writable, Readable} from 'stream'; import {WriteStream, ReadStream} from 'fs'; export type Stdout = Writable | WriteStream; export type Stdin = Readable | ReadStream; export type Package = { name: string; version: string; }; export type Tree = { name: string; children?: Trees; hint?: string; hidden?: boolean; color?: string; }; export type Trees = Array; export type ReporterSpinner = { tick: (name: string) => void; end: () => void; }; export type ReporterSpinnerSet = { spinners: Array; end: () => void; }; export type ReporterSetSpinner = { clear: () => void; setPrefix: (current: number, prefix: string) => void; tick: (msg: string) => void; end: () => void; }; ================================================ FILE: src/types.ts ================================================ import {Reporter} from './reporters/index.js'; import Config from './config.js'; export type CLIFunction = (config: Config, reporter: Reporter, flags: Object, args: Array) => CLIFunctionReturn; type _CLIFunctionReturn = boolean; export type CLIFunctionReturn = _CLIFunctionReturn | Promise<_CLIFunctionReturn>; // person object, the exploded version of a `maintainers`/`authors` field export type PersonObject = { email?: string; name?: string; url?: string; }; // `dependencies` field in package info type Dependencies = { [key: string]: string; }; // package.json export type Manifest = { name: string; version: string; description?: string; keywords?: string[]; sideEffects?: boolean; private?: boolean; distributions?: any; author?: { name?: string; email?: string; url?: string; }; homepage?: string; flat?: boolean; license?: string; licenseText?: string; noticeText?: string; readme?: string; readmeFilename?: string; repository?: { type: 'git'; url: string; }; bugs?: { url: string; }; // the package reference that dist?: { tarball: string; shasum: string; }; directories?: { man: string; bin: string; }; man?: Array; bin?: { [name: string]: string; }; scripts?: { [name: string]: string; }; engines?: { [engineName: string]: string; }; os?: Array; cpu?: Array; dependencies?: Dependencies; devDependencies?: Dependencies; peerDependencies?: Dependencies; optionalDependencies?: Dependencies; bundleDependencies?: Array; bundledDependencies?: Array; installConfig?: { pnp?: boolean; }; deprecated?: string; files?: Array; main?: string; // This flag is true when we add a new package with `pika add `. // We need to preserve the flag because we print a list of new packages in // the end of the add command fresh?: boolean; prebuiltVariants?: {[filename: string]: string}; }; // Used by outdated and upgrade-interactive export type Dependency = { name: string; current: string; wanted: string; latest: string; url: string; hint?: string; range: string; upgradeTo: string; workspaceName: string; workspaceLoc: string; }; ================================================ FILE: src/util/babel-plugin-import-rewrite.ts ================================================ // @flow import * as nodeFs from 'fs'; import * as nodePath from 'path'; import * as url from 'url'; import chalk from 'chalk'; import {validateDynamicImportArguments} from './babel-validate-specifier.js'; const BareIdentifierFormat = /^((?:@[^\/]+\/)?[^\/]+)(\/.*)?$/; function log(symbol: string, fileName: string, errors: string | Array) { if (!Array.isArray(errors)) { errors = [errors]; } console.log(`${symbol} `, chalk.bold(fileName)); for (const error of errors) { console.log(` ${chalk.dim('≫')} ${error}`); } } export default function transform({template, types: t}): any { function rewriteImport(specifier, {opts, file}) { const {deps, addExtensions} = opts; try { url.parse(specifier); } catch (err) { return; } // URL w/o protocol if (specifier.substr(0, 2) === '//') { return; // Leave it alone } // Local path if (['.', '/'].indexOf(specifier.charAt(0)) >= 0) { if (addExtensions) { const extname = nodePath.extname(specifier); if (extname === '.js') { return; } if (extname) { console.warn('Unexpected file extension:', specifier); return; } const resolvedPath = nodePath.resolve(nodePath.dirname(file.opts.filename), specifier); try { const stat = nodeFs.lstatSync(resolvedPath); if (stat.isDirectory()) { return specifier + '/index'; } } catch (err) { // do nothing } return specifier + '.js'; } return; } // A 'bare' identifier const match = BareIdentifierFormat.exec(specifier); if (deps && match) { const packageName = match[1]; // const file = match[2] || ''; return deps[packageName]; } } return { visitor: { 'ImportDeclaration|ExportNamedDeclaration|ExportAllDeclaration'(path, {opts, file}) { if (!path.node.source) { return; } const rewrittenSpecifier = rewriteImport(path.node.source.value, {opts, file}); if (rewrittenSpecifier) { path.node.source.value = rewrittenSpecifier; } }, Import(path, {opts, file}) { const errors = validateDynamicImportArguments(path); if (errors.size > 0) { return; } const [importPath] = path.parent.arguments; const rewrittenSpecifier = rewriteImport(importPath.value, {opts, file}); if (rewrittenSpecifier) { importPath.value = rewrittenSpecifier; } }, }, }; } ================================================ FILE: src/util/babel-validate-specifier.ts ================================================ // @flow import chalk from 'chalk'; function getLineCol(node: any): string { const loc = node.loc.start; return chalk.dim(`[${loc.line}:${loc.column}]`); } export function validateDynamicImportArguments(path): Set { if (path.parent.arguments.length !== 1) { return new Set([ `${getLineCol(path.node)} "\`import()\` only accepts 1 argument, but got ${path.parent.arguments.length}`, ]); } const [argNode] = path.parent.arguments; if (argNode.type !== 'StringLiteral') { return new Set([ `${getLineCol( path.node, )} Pika expects strings as \`import()\` arguments. Treating this as an absolute file path.`, ]); } return new Set(); } ================================================ FILE: src/util/blocking-queue.ts ================================================ import map from './map.js'; export default class BlockingQueue { constructor(alias: string, maxConcurrency: number = Infinity) { this.concurrencyQueue = []; this.maxConcurrency = maxConcurrency; this.runningCount = 0; this.warnedStuck = false; this.alias = alias; this.first = true; this.running = map() || {}; this.queue = map() || {}; this.stuckTick = this.stuckTick.bind(this); } concurrencyQueue: Array<() => void>; warnedStuck: boolean; maxConcurrency: number; runningCount: number; stuckTimer?: NodeJS.Timeout; alias: string; first: boolean; queue: { [key: string]: Array<{ factory: () => Promise; resolve: (val: any) => void; reject: Function; }>; }; running: { [key: string]: boolean; }; stillActive() { if (this.stuckTimer) { clearTimeout(this.stuckTimer); } this.stuckTimer = setTimeout(this.stuckTick, 5000); // We need to check the existence of unref because of https://github.com/facebook/jest/issues/4559 // $FlowFixMe: Node's setInterval returns a Timeout, not a Number this.stuckTimer.unref && this.stuckTimer.unref(); } stuckTick() { if (this.runningCount === 1) { this.warnedStuck = true; console.log( `The ${JSON.stringify(this.alias)} blocking queue may be stuck. 5 seconds ` + `without any activity with 1 worker: ${Object.keys(this.running)[0]}`, ); } } push(key: string, factory: () => Promise): Promise { if (this.first) { this.first = false; } else { this.stillActive(); } return new Promise((resolve, reject) => { // we're already running so push ourselves to the queue const queue = (this.queue[key] = this.queue[key] || []); queue.push({factory, resolve, reject}); if (!this.running[key]) { this.shift(key); } }); } shift(key: string) { if (this.running[key]) { delete this.running[key]; this.runningCount--; if (this.stuckTimer) { clearTimeout(this.stuckTimer); this.stuckTimer = null; } if (this.warnedStuck) { this.warnedStuck = false; console.log(`${JSON.stringify(this.alias)} blocking queue finally resolved. Nothing to worry about.`); } } const queue = this.queue[key]; if (!queue) { return; } const {resolve, reject, factory} = queue.shift(); if (!queue.length) { delete this.queue[key]; } const next = () => { this.shift(key); this.shiftConcurrencyQueue(); }; const run = () => { this.running[key] = true; this.runningCount++; factory() .then(function (val): null { resolve(val); next(); return null; }) .catch(function (err) { reject(err); next(); }); }; this.maybePushConcurrencyQueue(run); } maybePushConcurrencyQueue(run: () => void) { if (this.runningCount < this.maxConcurrency) { run(); } else { this.concurrencyQueue.push(run); } } shiftConcurrencyQueue() { if (this.runningCount < this.maxConcurrency) { const fn = this.concurrencyQueue.shift(); if (fn) { fn(); } } } } ================================================ FILE: src/util/child.ts ================================================ /* global child_process$spawnOpts */ import * as constants from '../constants.js'; import BlockingQueue from './blocking-queue.js'; import {ProcessSpawnError, ProcessTermError} from '../errors.js'; import {promisify} from './promise.js'; import {exec as _exec, spawn as _spawn, ChildProcess, SpawnOptions} from 'child_process'; export const queue = new BlockingQueue('child', constants.CHILD_CONCURRENCY); // TODO: this uid check is kinda whack let uid = 0; export const exec = promisify(_exec); const spawnedProcesses = {}; export function forwardSignalToSpawnedProcesses(signal: string) { for (const key of Object.keys(spawnedProcesses)) { spawnedProcesses[key].kill(signal); } } type ProcessFn = ( proc: ChildProcess, update: (chunk: string) => void, reject: (err: any) => void, done: () => void, ) => void; export function spawn( program: string, args: Array, opts: SpawnOptions & {detached?: boolean; process?: ProcessFn} = {}, onData?: (chunk: Buffer | string) => void, ): Promise { const key = opts.cwd || String(++uid); return queue.push( key, (): Promise => new Promise((resolve, reject) => { const proc = _spawn(program, args, opts); spawnedProcesses[key] = proc; let processingDone = false; let processClosed = false; let err = null; let stdout = ''; proc.on('error', (err: any) => { if (err.code === 'ENOENT') { reject(new ProcessSpawnError(`Couldn't find the binary ${program}`, err.code, program)); } else { reject(err); } }); function updateStdout(chunk: string) { stdout += chunk; if (onData) { onData(chunk); } } function finish() { delete spawnedProcesses[key]; if (err) { reject(err); } else { resolve(stdout.trim()); } } if (typeof opts.process === 'function') { opts.process(proc, updateStdout, reject, function () { if (processClosed) { finish(); } else { processingDone = true; } }); } else { if (proc.stderr) { proc.stderr.on('data', updateStdout); } if (proc.stdout) { proc.stdout.on('data', updateStdout); } processingDone = true; } proc.on('close', (code: number, signal: string) => { if (signal || code >= 1) { err = new ProcessTermError( [ 'Command failed.', signal ? `Exit signal: ${signal}` : `Exit code: ${code}`, `Command: ${program}`, `Arguments: ${args.join(' ')}`, `Directory: ${opts.cwd || process.cwd()}`, `Output:\n${stdout.trim()}`, ].join('\n'), ); err.EXIT_SIGNAL = signal; err.EXIT_CODE = code; } if (processingDone || err) { finish(); } else { processClosed = true; } }); }), ); } ================================================ FILE: src/util/conversion.ts ================================================ const FALSY_STRINGS = new Set(['0', 'false']); export function boolify(val: string | number | boolean): boolean { return !FALSY_STRINGS.has(val.toString().toLowerCase()); } export function boolifyWithDefault(val: string | number | boolean, defaultResult: boolean): boolean { return val === '' || val === null || val === undefined ? defaultResult : boolify(val); } ================================================ FILE: src/util/execute-lifecycle-script.ts ================================================ import {StdioOptions} from 'child_process'; import Config from '../config.js'; import {MessageError} from '@pika/types'; import {ProcessTermError} from '../errors.js'; import * as child from './child.js'; import {fixCmdWinSlashes} from './fix-cmd-win-slashes.js'; // import path from 'path'; export type LifecycleReturn = Promise<{ cwd: string; command: string; stdout: string; }>; // export const IGNORE_MANIFEST_KEYS: Set = new Set(['readme', 'notice', 'licenseText']); // // We treat these configs as internal, thus not expose them to process.env. // // This helps us avoid some gyp issues when building native modules. // // See https://github.com/yarnpkg/yarn/issues/2286. // const IGNORE_CONFIG_KEYS = ['lastUpdateCheck']; // async function getPnpParameters(config: Config): Promise> { // if (await fs.exists(`${config.lockfileFolder}/${constants.PNP_FILENAME}`)) { // return ['-r', `${config.lockfileFolder}/${constants.PNP_FILENAME}`]; // } else { // return []; // } // } // let wrappersFolder = null; // export async function getWrappersFolder(config: Config): Promise { // if (wrappersFolder) { // return wrappersFolder; // } // wrappersFolder = await fs.makeTempDir(); // await makePortableProxyScript(process.execPath, wrappersFolder, { // proxyBasename: 'node', // prependArguments: [...(await getPnpParameters(config))], // }); // await makePortableProxyScript(process.execPath, wrappersFolder, { // proxyBasename: 'pika', // prependArguments: [process.argv[1]], // }); // return wrappersFolder; // } // const INVALID_CHAR_REGEX = /\W/g; export async function makeEnv(): Promise<{[key: string]: string}> { // stage: string, // cwd: string, // config: Config, const env = { NODE: process.execPath, INIT_CWD: process.cwd(), // This lets `process.env.NODE` to override our `process.execPath`. // This is a bit confusing but it is how `npm` was designed so we // try to be compatible with that. ...process.env, }; return env; } // // Merge in the `env` object specified in .pikarc // const customEnv = config.getOption('env'); // if (customEnv && typeof customEnv === 'object') { // Object.assign(env, customEnv); // } // env.npm_lifecycle_event = stage; // env.npm_node_execpath = env.NODE; // env.npm_execpath = env.npm_execpath || (process.mainModule && process.mainModule.filename); // // Set the env to production for npm compat if production mode. // // https://github.com/npm/npm/blob/30d75e738b9cb7a6a3f9b50e971adcbe63458ed3/lib/utils/lifecycle.js#L336 // if (config.production) { // env.NODE_ENV = 'production'; // } // // Note: npm_config_argv environment variable contains output of nopt - command-line // // parser used by npm. Since we use other parser, we just roughly emulate it's output. (See: #684) // env.npm_config_argv = JSON.stringify({ // remain: [], // cooked: config.commandName === 'run' ? [config.commandName, stage] : [config.commandName], // original: process.argv.slice(2), // }); // const manifest = await config.maybeReadManifest(cwd); // if (manifest) { // if (manifest.scripts && Object.prototype.hasOwnProperty.call(manifest.scripts, stage)) { // env.npm_lifecycle_script = manifest.scripts[stage]; // } // // add npm_package_* // const queue = [['', manifest]]; // while (queue.length) { // const [key, val] = queue.pop(); // if (typeof val === 'object') { // for (const subKey in val) { // const fullKey = [key, subKey].filter(Boolean).join('_'); // if (fullKey && fullKey[0] !== '_' && !IGNORE_MANIFEST_KEYS.has(fullKey)) { // queue.push([fullKey, val[subKey]]); // } // } // } else { // let cleanVal = String(val); // if (cleanVal.indexOf('\n') >= 0) { // cleanVal = JSON.stringify(cleanVal); // } // //replacing invalid chars with underscore // const cleanKey = key.replace(INVALID_CHAR_REGEX, '_'); // env[`npm_package_${cleanKey}`] = cleanVal; // } // } // } // // add npm_config_* and npm_package_config_* from pika config // const keys: Set = new Set([ // ...Object.keys(config.registries.pika.config), // ...Object.keys(config.registries.npm.config), // ]); // const cleaned = Array.from(keys) // .filter(key => !key.match(/:_/) && IGNORE_CONFIG_KEYS.indexOf(key) === -1) // .map(key => { // let val = config.getOption(key); // if (!val) { // val = ''; // } else if (typeof val === 'number') { // val = '' + val; // } else if (typeof val !== 'string') { // val = JSON.stringify(val); // } // if (val.indexOf('\n') >= 0) { // val = JSON.stringify(val); // } // return [key, val]; // }); // // add npm_config_* // for (const [key, val] of cleaned) { // const cleanKey = key.replace(/^_+/, ''); // const envKey = `npm_config_${cleanKey}`.replace(INVALID_CHAR_REGEX, '_'); // env[envKey] = val; // } // // add npm_package_config_* // if (manifest && manifest.name) { // const packageConfigPrefix = `${manifest.name}:`; // for (const [key, val] of cleaned) { // if (key.indexOf(packageConfigPrefix) !== 0) { // continue; // } // const cleanKey = key.replace(/^_+/, '').replace(packageConfigPrefix, ''); // const envKey = `npm_package_config_${cleanKey}`.replace(INVALID_CHAR_REGEX, '_'); // env[envKey] = val; // } // } // // split up the path // const envPath = env[constants.ENV_PATH_KEY]; // const pathParts = envPath ? envPath.split(path.delimiter) : []; // // Include the directory that contains node so that we can guarantee that the scripts // // will always run with the exact same Node release than the one use to run Pika // const execBin = path.dirname(process.execPath); // if (pathParts.indexOf(execBin) === -1) { // pathParts.unshift(execBin); // } // // Include node-gyp version that was bundled with the current Node.js version, // // if available. // pathParts.unshift(path.join(path.dirname(process.execPath), 'node_modules', 'npm', 'bin', 'node-gyp-bin')); // pathParts.unshift( // path.join(path.dirname(process.execPath), '..', 'lib', 'node_modules', 'npm', 'bin', 'node-gyp-bin'), // ); // // Include node-gyp version from homebrew managed npm, if available. // pathParts.unshift( // path.join(path.dirname(process.execPath), '..', 'libexec', 'lib', 'node_modules', 'npm', 'bin', 'node-gyp-bin'), // ); // // Add global bin folder if it is not present already, as some packages depend // // on a globally-installed version of node-gyp. // const globalBin = await getGlobalBinFolder(config, {}); // if (pathParts.indexOf(globalBin) === -1) { // pathParts.unshift(globalBin); // } // // Add node_modules .bin folders to the PATH // for (const registry of Object.keys(registries)) { // const binFolder = path.join(config.registries[registry].folder, '.bin'); // if (config.workspacesEnabled && config.workspaceRootFolder) { // pathParts.unshift(path.join(config.workspaceRootFolder, binFolder)); // } // pathParts.unshift(path.join(config.linkFolder, binFolder)); // pathParts.unshift(path.join(cwd, binFolder)); // if (config.modulesFolder) { // pathParts.unshift(path.join(config.modulesFolder, '.bin')); // } // } // if (await fs.exists(`${config.lockfileFolder}/${constants.PNP_FILENAME}`)) { // // TODO: Fix. import()? Do we even like that it does this? // throw new Error("pnp temporarily not supported"); // const pnpApi = {}; //dynamicRequire(`${config.lockfileFolder}/${constants.PNP_FILENAME}`); // const packageLocator = pnpApi.findPackageLocator(`${config.cwd}/`); // const packageInformation = pnpApi.getPackageInformation(packageLocator); // for (const [name, reference] of packageInformation.packageDependencies.entries()) { // const dependencyInformation = pnpApi.getPackageInformation({name, reference}); // if (!dependencyInformation || !dependencyInformation.packageLocation) { // continue; // } // pathParts.unshift(`${dependencyInformation.packageLocation}/.bin`); // } // } // pathParts.unshift(await getWrappersFolder(config)); // // join path back together // env[constants.ENV_PATH_KEY] = pathParts.join(path.delimiter); // return env; // } export async function executeLifecycleScript({ // config, cwd, cmd, args, isInteractive, onProgress, customShell, }: { // config: Config; cwd: string; args: string[]; cmd: string; isInteractive?: boolean; onProgress?: (chunk: Buffer | string) => void; customShell?: string; }): LifecycleReturn { const env = await makeEnv(); // await checkForGypIfNeeded(config, cmd, env[constants.ENV_PATH_KEY].split(path.delimiter)); if (process.platform === 'win32' && (!customShell || customShell === 'cmd')) { // handle windows run scripts starting with a relative path cmd = fixCmdWinSlashes(cmd); } // By default (non-interactive), pipe everything to the terminal and run child process detached // as long as it's not Windows (since windows does not have /dev/tty) let stdio: StdioOptions = ['ignore', 'pipe', 'pipe']; let detached = process.platform !== 'win32'; if (isInteractive) { stdio = 'inherit'; detached = false; } const shell = customShell || true; const stdout = await child.spawn(cmd, args, {cwd, env, stdio, detached, shell}, onProgress); return {cwd, command: cmd, stdout}; } export default executeLifecycleScript; // let checkGypPromise: Promise = null; // // /** // // * Special case: Some packages depend on node-gyp, but don't specify this in // // * their package.json dependencies. They assume that node-gyp is available // // * globally. We need to detect this case and show an error message. // // */ // function checkForGypIfNeeded(config: Config, cmd: string, paths: Array): Promise { // if (cmd.substr(0, cmd.indexOf(' ')) !== 'node-gyp') { // return Promise.resolve(); // } // // Ensure this only runs once, rather than multiple times in parallel. // if (!checkGypPromise) { // checkGypPromise = _checkForGyp(config, paths); // } // return checkGypPromise; // } // async function _checkForGyp(config: Config, paths: Array): Promise { // const {reporter} = config; // // Check every directory in the PATH // const allChecks = await Promise.all(paths.map(dir => fs.exists(path.join(dir, 'node-gyp')))); // if (allChecks.some(Boolean)) { // // node-gyp is available somewhere // return; // } // reporter.info(reporter.lang('packageRequiresNodeGyp')); // } // export async function execFromDistributions(config: Config, cwd: string, dist: string, step: string): Promise { // const pkg = await config.maybeReadManifest(cwd); // if (!pkg || !pkg.distributions || !pkg.distributions[dist] || typeof pkg.distributions[dist][step] !== 'string') { // return false; // } // const cmd: ?string = pkg.distributions[dist][step]; // await execCommand({stage: 'build', config, cmd, cwd, isInteractive: true}); // return true; // } // export async function execFromManifest(config: Config, commandName: string, cwd: string): Promise { // const pkg = await config.maybeReadManifest(cwd); // if (!pkg || !pkg.scripts) { // return; // } // const cmd: ?string = pkg.scripts[commandName]; // if (cmd) { // await execCommand({stage: commandName, config, cmd, cwd, isInteractive: true}); // } // } // export async function execCommand({ // stage, // config, // cmd, // cwd, // isInteractive, // customShell, // }: { // stage: string; // config: Config; // cmd: string; // cwd: string; // isInteractive: boolean; // customShell?: string; // }): Promise { // const {reporter} = config; // try { // reporter.command(cmd); // await executeLifecycleScript({config, cwd, cmd, isInteractive, customShell}); // return Promise.resolve(); // } catch (err) { // if (err instanceof ProcessTermError) { // throw new MessageError( // err.EXIT_SIGNAL // ? reporter.lang('commandFailedWithSignal', err.EXIT_SIGNAL) // : reporter.lang('commandFailedWithCode', err.EXIT_CODE), // ); // } else { // throw err; // } // } // } ================================================ FILE: src/util/fix-cmd-win-slashes.ts ================================================ export function fixCmdWinSlashes(cmd: string): string { function findQuotes(quoteSymbol: string): {from: number; to: number}[] { const quotes = []; const addQuote = (_, index) => { quotes.push({from: index, to: index + _.length}); return _; }; const regEx = new RegExp(quoteSymbol + '.*' + quoteSymbol); cmd.replace(regEx, addQuote); return quotes; } const quotes = findQuotes('"').concat(findQuotes("'")); function isInsideQuotes(index: number): boolean { return quotes.reduce((result, quote) => { return result || (quote.from <= index && index <= quote.to); }, false); } const cmdPrePattern = '((?:^|&&|&|\\|\\||\\|)\\s*)'; const cmdPattern = '(".*?"|\'.*?\'|\\S*)'; const regExp = new RegExp(`${cmdPrePattern}${cmdPattern}`, 'g'); return cmd.replace(regExp, (whole, pre, cmd, index) => { if ((pre[0] === '&' || pre[0] === '|') && isInsideQuotes(index)) { return whole; } return pre + cmd.replace(/\//g, '\\'); }); } ================================================ FILE: src/util/fs-normalized.ts ================================================ // // // This module serves as a wrapper for file operations that are inconsistant across node and OS versions. // import fs from 'fs'; // import {promisify} from './promise.js'; // import {constants} from './fs.js'; // export type CopyFileAction = { // src: string, // dest: string, // atime: Date, // mtime: Date, // mode: number, // }; // let disableTimestampCorrection: boolean; // OS dependent. will be detected on first file copy. // const readFileBuffer = promisify(fs.readFile); // const close: (fd: number) => Promise = promisify(fs.close); // const lstat: (path: string) => Promise = promisify(fs.lstat); // const open: (path: string, flags: string | number, mode: number) => Promise = promisify(fs.open); // const futimes: (fd: number, atime: number, mtime: number) => Promise = promisify(fs.futimes); // const write: ( // fd: number, // buffer: Buffer, // offset?: number, // length?: number, // position?: number, // ) => Promise = promisify(fs.write); // /** // * Unlinks the destination to force a recreation. This is needed on case-insensitive file systems // * to force the correct naming when the filename has changed only in character-casing. (Jest -> jest). // */ // export const copyFile = async function(data: CopyFileAction, cleanup: () => any): Promise { // // $FlowFixMe: Flow doesn't currently support COPYFILE_FICLONE // const ficloneFlag = (constants as any).COPYFILE_FICLONE || 0; // try { // await unlink(data.dest); // await copyFilePoly(data.src, data.dest, ficloneFlag, data); // } finally { // if (cleanup) { // cleanup(); // } // } // }; // // Node 8.5.0 introduced `fs.copyFile` which is much faster, so use that when available. // // Otherwise we fall back to reading and writing files as buffers. // const copyFilePoly: (src: string, dest: string, flags: number, data: CopyFileAction) => Promise = ( // src, // dest, // flags, // data, // ) => { // if (fs.copyFile) { // return new Promise((resolve, reject) => // fs.copyFile(src, dest, flags, err => { // if (err) { // reject(err); // } else { // fixTimes(undefined, dest, data).then(() => resolve()).catch(ex => reject(ex)); // } // }), // ); // } else { // return copyWithBuffer(src, dest, flags, data); // } // }; // const copyWithBuffer: (src: string, dest: string, flags: number, data: CopyFileAction) => Promise = async ( // src, // dest, // flags, // data, // ) => { // // Use open -> write -> futimes -> close sequence to avoid opening the file twice: // // one with writeFile and one with utimes // const fd = await open(dest, 'w', data.mode); // try { // const buffer = await readFileBuffer(src); // await write(fd, buffer, 0, buffer.length); // await fixTimes(fd, dest, data); // } finally { // await close(fd); // } // }; // // We want to preserve file timestamps when copying a file, since pika uses them to decide if a file has // // changed compared to the cache. // // There are some OS specific cases here: // // * On linux, fs.copyFile does not preserve timestamps, but does on OSX and Win. // // * On windows, you must open a file with write permissions to call `fs.futimes`. // // * On OSX you can open with read permissions and still call `fs.futimes`. // async function fixTimes(fd: number | undefined, dest: string, data: CopyFileAction): Promise { // const doOpen = fd === undefined; // let openfd: number = fd ? fd : -1; // if (disableTimestampCorrection === undefined) { // // if timestamps match already, no correction is needed. // // the need to correct timestamps varies based on OS and node versions. // const destStat = await lstat(dest); // disableTimestampCorrection = fileDatesEqual(destStat.mtime, data.mtime); // } // if (disableTimestampCorrection) { // return; // } // if (doOpen) { // try { // openfd = await open(dest, 'a', data.mode); // } catch (er) { // // file is likely read-only // try { // openfd = await open(dest, 'r', data.mode); // } catch (err) { // // We can't even open this file for reading. // return; // } // } // } // try { // if (openfd) { // await futimes(openfd, data.atime, data.mtime); // } // } catch (er) { // // If `futimes` throws an exception, we probably have a case of a read-only file on Windows. // // In this case we can just return. The incorrect timestamp will just cause that file to be recopied // // on subsequent installs, which will effect pika performance but not break anything. // } finally { // if (doOpen && openfd) { // await close(openfd); // } // } // } // // Compare file timestamps. // // Some versions of Node on windows zero the milliseconds when utime is used. // export const fileDatesEqual = (a: Date, b: Date) => { // const aTime = a.getTime(); // const bTime = b.getTime(); // if (process.platform !== 'win32') { // return aTime === bTime; // } // // See https://github.com/nodejs/node/pull/12607 // // Submillisecond times from stat and utimes are truncated on Windows, // // causing a file with mtime 8.0079998 and 8.0081144 to become 8.007 and 8.008 // // and making it impossible to update these files to their correct timestamps. // if (Math.abs(aTime - bTime) <= 1) { // return true; // } // const aTimeSec = Math.floor(aTime / 1000); // const bTimeSec = Math.floor(bTime / 1000); // // See https://github.com/nodejs/node/issues/2069 // // Some versions of Node on windows zero the milliseconds when utime is used // // So if any of the time has a milliseconds part of zero we suspect that the // // bug is present and compare only seconds. // if (aTime - aTimeSec * 1000 === 0 || bTime - bTimeSec * 1000 === 0) { // return aTimeSec === bTimeSec; // } // return aTime === bTime; // }; ================================================ FILE: src/util/fs.ts ================================================ import {promisify} from 'util'; import _rimraf from 'rimraf'; import _mkdirp from 'mkdirp'; import _glob from 'glob'; export const unlink: (path: string) => Promise = promisify(_rimraf); export const glob: (path: string, options?: Object) => Promise> = promisify(_glob); export const mkdirp: (path: string) => Promise = promisify(_mkdirp); // // import {ReadStream} from 'fs'; // import Reporter from '../reporters/base-reporter.js'; // import {CopyFileAction} from './fs-normalized.js'; import * as os from 'os'; import * as path from 'path'; // import BlockingQueue from './blocking-queue.js'; // import * as promise from './promise.js'; import map from './map.js'; // import {copyFile, fileDatesEqual, unlink} from './fs-normalized.js'; // export const constants = // typeof fs.constants !== 'undefined' // ? fs.constants // : { // R_OK: fs.R_OK, // W_OK: fs.W_OK, // X_OK: fs.X_OK, // }; // export const lockQueue = new BlockingQueue('fs lock'); import * as fs from 'fs'; import * as util from 'util'; export const open = util.promisify(fs.open); export const writeFile = util.promisify(fs.writeFile); export const readlink = util.promisify(fs.readlink); export const realpath = util.promisify(fs.realpath); export const readdir = util.promisify(fs.readdir); export const rename = util.promisify(fs.rename); export const access = util.promisify(fs.access); export const stat = util.promisify(fs.stat); export const exists = util.promisify(fs.exists); export const lstat = util.promisify(fs.lstat); export const chmod = util.promisify(fs.chmod); export const link = util.promisify(fs.link); export const copyFile = util.promisify(fs.copyFile); const readFileBuffer = util.promisify(fs.readFile); export const readFile = (path: string) => { return util.promisify(fs.readFile)(path, {encoding: 'utf-8'}); }; // export {unlink}; // // fs.copyFile uses the native file copying instructions on the system, performing much better // // than any JS-based solution and consumes fewer resources. Repeated testing to fine tune the // // concurrency level revealed 128 as the sweet spot on a quad-core, 16 CPU Intel system with SSD. // const CONCURRENT_QUEUE_ITEMS = fs.copyFile ? 128 : 4; // const fsSymlink: (target: string, path: string, type?: 'dir' | 'file' | 'junction') => Promise = promisify( // fs.symlink, // ); // import invariant from 'invariant'; import stripBOM from 'strip-bom'; // const noop = () => {}; // export type CopyQueueItem = { // src: string, // dest: string, // type?: string, // onFresh?: () => void, // onDone?: () => void, // }; // type CopyQueue = Array; // type LinkFileAction = { // src: string, // dest: string, // removeDest: boolean, // }; // type CopySymlinkAction = { // dest: string, // linkname: string, // }; // type CopyActions = { // file: Array, // symlink: Array, // link: Array, // }; // type CopyOptions = { // onProgress: (dest: string) => void, // onStart: (num: number) => void, // possibleExtraneous: Set, // ignoreBasenames: Array, // artifactFiles: Array, // }; // type FailedFolderQuery = { // error: Error, // folder: string, // }; // type FolderQueryResult = { // skipped: Array, // folder?: string, // }; // async function buildActionsForCopy( // queue: CopyQueue, // events: CopyOptions, // possibleExtraneous: Set, // reporter: Reporter, // ): Promise { // const artifactFiles: Set = new Set(events.artifactFiles || []); // const files: Set = new Set(); // // initialise events // for (const item of queue) { // const onDone = item.onDone; // item.onDone = () => { // events.onProgress(item.dest); // if (onDone) { // onDone(); // } // }; // } // events.onStart(queue.length); // // start building actions // const actions: CopyActions = { // file: [], // symlink: [], // link: [], // }; // // custom concurrency logic as we're always executing stacks of CONCURRENT_QUEUE_ITEMS queue items // // at a time due to the requirement to push items onto the queue // while (queue.length) { // const items = queue.splice(0, CONCURRENT_QUEUE_ITEMS); // await Promise.all(items.map(build)); // } // // simulate the existence of some files to prevent considering them extraneous // for (const file of artifactFiles) { // if (possibleExtraneous.has(file)) { // reporter.verbose(reporter.lang('verboseFilePhantomExtraneous', file)); // possibleExtraneous.delete(file); // } // } // for (const loc of possibleExtraneous) { // if (files.has(loc.toLowerCase())) { // possibleExtraneous.delete(loc); // } // } // return actions; // // // async function build(data: CopyQueueItem): Promise { // const {src, dest, type} = data; // const onFresh = data.onFresh || noop; // const onDone = data.onDone || noop; // // TODO https://github.com/yarnpkg/yarn/issues/3751 // // related to bundled dependencies handling // if (files.has(dest.toLowerCase())) { // reporter.verbose(`The case-insensitive file ${dest} shouldn't be copied twice in one bulk copy`); // } else { // files.add(dest.toLowerCase()); // } // if (type === 'symlink') { // await mkdirp(path.dirname(dest)); // onFresh(); // actions.symlink.push({ // dest, // linkname: src, // }); // onDone(); // return; // } // if (events.ignoreBasenames.indexOf(path.basename(src)) >= 0) { // // ignored file // return; // } // const srcStat = await lstat(src); // let srcFiles; // if (srcStat.isDirectory()) { // srcFiles = await readdir(src); // } // let destStat; // try { // // try accessing the destination // destStat = await lstat(dest); // } catch (e) { // // proceed if destination doesn't exist, otherwise error // if (e.code !== 'ENOENT') { // throw e; // } // } // // if destination exists // if (destStat) { // const bothSymlinks = srcStat.isSymbolicLink() && destStat.isSymbolicLink(); // const bothFolders = srcStat.isDirectory() && destStat.isDirectory(); // const bothFiles = srcStat.isFile() && destStat.isFile(); // // EINVAL access errors sometimes happen which shouldn't because node shouldn't be giving // // us modes that aren't valid. investigate this, it's generally safe to proceed. // /* if (srcStat.mode !== destStat.mode) { // try { // await access(dest, srcStat.mode); // } catch (err) {} // } */ // if (bothFiles && artifactFiles.has(dest)) { // // this file gets changed during build, likely by a custom install script. Don't bother checking it. // onDone(); // reporter.verbose(reporter.lang('verboseFileSkipArtifact', src)); // return; // } // if (bothFiles && srcStat.size === destStat.size && fileDatesEqual(srcStat.mtime, destStat.mtime)) { // // we can safely assume this is the same file // onDone(); // reporter.verbose(reporter.lang('verboseFileSkip', src, dest, srcStat.size, +srcStat.mtime)); // return; // } // if (bothSymlinks) { // const srcReallink = await readlink(src); // if (srcReallink === (await readlink(dest))) { // // if both symlinks are the same then we can continue on // onDone(); // reporter.verbose(reporter.lang('verboseFileSkipSymlink', src, dest, srcReallink)); // return; // } // } // if (bothFolders) { // // mark files that aren't in this folder as possibly extraneous // const destFiles = await readdir(dest); // invariant(srcFiles, 'src files not initialised'); // for (const file of destFiles) { // if (srcFiles.indexOf(file) < 0) { // const loc = path.join(dest, file); // possibleExtraneous.add(loc); // if ((await lstat(loc)).isDirectory()) { // for (const file of await readdir(loc)) { // possibleExtraneous.add(path.join(loc, file)); // } // } // } // } // } // } // if (destStat && destStat.isSymbolicLink()) { // await unlink(dest); // destStat = null; // } // if (srcStat.isSymbolicLink()) { // onFresh(); // const linkname = await readlink(src); // actions.symlink.push({ // dest, // linkname, // }); // onDone(); // } else if (srcStat.isDirectory()) { // if (!destStat) { // reporter.verbose(reporter.lang('verboseFileFolder', dest)); // await mkdirp(dest); // } // const destParts = dest.split(path.sep); // while (destParts.length) { // files.add(destParts.join(path.sep).toLowerCase()); // destParts.pop(); // } // // push all files to queue // invariant(srcFiles, 'src files not initialised'); // let remaining = srcFiles.length; // if (!remaining) { // onDone(); // } // for (const file of srcFiles) { // queue.push({ // dest: path.join(dest, file), // onFresh, // onDone: () => { // if (--remaining === 0) { // onDone(); // } // }, // src: path.join(src, file), // }); // } // } else if (srcStat.isFile()) { // onFresh(); // actions.file.push({ // src, // dest, // atime: srcStat.atime, // mtime: srcStat.mtime, // mode: srcStat.mode, // }); // onDone(); // } else { // throw new Error(`unsure how to copy this: ${src}`); // } // } // } // async function buildActionsForHardlink( // queue: CopyQueue, // events: CopyOptions, // possibleExtraneous: Set, // reporter: Reporter, // ): Promise { // const artifactFiles: Set = new Set(events.artifactFiles || []); // const files: Set = new Set(); // // initialise events // for (const item of queue) { // const onDone = item.onDone || noop; // item.onDone = () => { // events.onProgress(item.dest); // onDone(); // }; // } // events.onStart(queue.length); // // start building actions // const actions: CopyActions = { // file: [], // symlink: [], // link: [], // }; // // custom concurrency logic as we're always executing stacks of CONCURRENT_QUEUE_ITEMS queue items // // at a time due to the requirement to push items onto the queue // while (queue.length) { // const items = queue.splice(0, CONCURRENT_QUEUE_ITEMS); // await Promise.all(items.map(build)); // } // // simulate the existence of some files to prevent considering them extraneous // for (const file of artifactFiles) { // if (possibleExtraneous.has(file)) { // reporter.verbose(reporter.lang('verboseFilePhantomExtraneous', file)); // possibleExtraneous.delete(file); // } // } // for (const loc of possibleExtraneous) { // if (files.has(loc.toLowerCase())) { // possibleExtraneous.delete(loc); // } // } // return actions; // // // async function build(data: CopyQueueItem): Promise { // const {src, dest} = data; // const onFresh = data.onFresh || noop; // const onDone = data.onDone || noop; // if (files.has(dest.toLowerCase())) { // // Fixes issue https://github.com/yarnpkg/yarn/issues/2734 // // When bulk hardlinking we have A -> B structure that we want to hardlink to A1 -> B1, // // package-linker passes that modules A1 and B1 need to be hardlinked, // // the recursive linking algorithm of A1 ends up scheduling files in B1 to be linked twice which will case // // an exception. // onDone(); // return; // } // files.add(dest.toLowerCase()); // if (events.ignoreBasenames.indexOf(path.basename(src)) >= 0) { // // ignored file // return; // } // const srcStat = await lstat(src); // let srcFiles; // if (srcStat.isDirectory()) { // srcFiles = await readdir(src); // } // const destExists = await exists(dest); // if (destExists) { // const destStat = await lstat(dest); // const bothSymlinks = srcStat.isSymbolicLink() && destStat.isSymbolicLink(); // const bothFolders = srcStat.isDirectory() && destStat.isDirectory(); // const bothFiles = srcStat.isFile() && destStat.isFile(); // if (srcStat.mode !== destStat.mode) { // try { // await access(dest, srcStat.mode); // } catch (err) { // // EINVAL access errors sometimes happen which shouldn't because node shouldn't be giving // // us modes that aren't valid. investigate this, it's generally safe to proceed. // reporter.verbose(err); // } // } // if (bothFiles && artifactFiles.has(dest)) { // // this file gets changed during build, likely by a custom install script. Don't bother checking it. // onDone(); // reporter.verbose(reporter.lang('verboseFileSkipArtifact', src)); // return; // } // // correct hardlink // if (bothFiles && srcStat.ino !== null && srcStat.ino === destStat.ino) { // onDone(); // reporter.verbose(reporter.lang('verboseFileSkip', src, dest, srcStat.ino)); // return; // } // if (bothSymlinks) { // const srcReallink = await readlink(src); // if (srcReallink === (await readlink(dest))) { // // if both symlinks are the same then we can continue on // onDone(); // reporter.verbose(reporter.lang('verboseFileSkipSymlink', src, dest, srcReallink)); // return; // } // } // if (bothFolders) { // // mark files that aren't in this folder as possibly extraneous // const destFiles = await readdir(dest); // invariant(srcFiles, 'src files not initialised'); // for (const file of destFiles) { // if (srcFiles.indexOf(file) < 0) { // const loc = path.join(dest, file); // possibleExtraneous.add(loc); // if ((await lstat(loc)).isDirectory()) { // for (const file of await readdir(loc)) { // possibleExtraneous.add(path.join(loc, file)); // } // } // } // } // } // } // if (srcStat.isSymbolicLink()) { // onFresh(); // const linkname = await readlink(src); // actions.symlink.push({ // dest, // linkname, // }); // onDone(); // } else if (srcStat.isDirectory()) { // reporter.verbose(reporter.lang('verboseFileFolder', dest)); // await mkdirp(dest); // const destParts = dest.split(path.sep); // while (destParts.length) { // files.add(destParts.join(path.sep).toLowerCase()); // destParts.pop(); // } // // push all files to queue // invariant(srcFiles, 'src files not initialised'); // let remaining = srcFiles.length; // if (!remaining) { // onDone(); // } // for (const file of srcFiles) { // queue.push({ // onFresh, // src: path.join(src, file), // dest: path.join(dest, file), // onDone: () => { // if (--remaining === 0) { // onDone(); // } // }, // }); // } // } else if (srcStat.isFile()) { // onFresh(); // actions.link.push({ // src, // dest, // removeDest: destExists, // }); // onDone(); // } else { // throw new Error(`unsure how to copy this: ${src}`); // } // } // } // export function copy(src: string, dest: string, reporter: Reporter): Promise { // return copyBulk([{src, dest}], reporter); // } // export async function copyBulk( // queue: CopyQueue, // reporter: Reporter, // _events?: { // onProgress?: (dest: string) => void, // onStart?: (num: number) => void, // possibleExtraneous: Set, // ignoreBasenames?: Array, // artifactFiles?: Array, // }, // ): Promise { // const events: CopyOptions = { // onStart: (_events && _events.onStart) || noop, // onProgress: (_events && _events.onProgress) || noop, // possibleExtraneous: _events ? _events.possibleExtraneous : new Set(), // ignoreBasenames: (_events && _events.ignoreBasenames) || [], // artifactFiles: (_events && _events.artifactFiles) || [], // }; // const actions: CopyActions = await buildActionsForCopy(queue, events, events.possibleExtraneous, reporter); // events.onStart(actions.file.length + actions.symlink.length + actions.link.length); // const fileActions: Array = actions.file; // const currentlyWriting: Map> = new Map(); // await promise.queue( // fileActions, // async (data: CopyFileAction): Promise => { // let writePromise; // while ((writePromise = currentlyWriting.get(data.dest))) { // await writePromise; // } // reporter.verbose(reporter.lang('verboseFileCopy', data.src, data.dest)); // const copier = copyFile(data, () => currentlyWriting.delete(data.dest)); // currentlyWriting.set(data.dest, copier); // events.onProgress(data.dest); // return copier; // }, // CONCURRENT_QUEUE_ITEMS, // ); // // we need to copy symlinks last as they could reference files we were copying // const symlinkActions: Array = actions.symlink; // await promise.queue(symlinkActions, (data): Promise => { // const linkname = path.resolve(path.dirname(data.dest), data.linkname); // reporter.verbose(reporter.lang('verboseFileSymlink', data.dest, linkname)); // return symlink(linkname, data.dest); // }); // } // export async function hardlinkBulk( // queue: CopyQueue, // reporter: Reporter, // _events?: { // onProgress?: (dest: string) => void, // onStart?: (num: number) => void, // possibleExtraneous: Set, // artifactFiles?: Array, // }, // ): Promise { // const events: CopyOptions = { // onStart: (_events && _events.onStart) || noop, // onProgress: (_events && _events.onProgress) || noop, // possibleExtraneous: _events ? _events.possibleExtraneous : new Set(), // artifactFiles: (_events && _events.artifactFiles) || [], // ignoreBasenames: [], // }; // const actions: CopyActions = await buildActionsForHardlink(queue, events, events.possibleExtraneous, reporter); // events.onStart(actions.file.length + actions.symlink.length + actions.link.length); // const fileActions: Array = actions.link; // await promise.queue( // fileActions, // async (data): Promise => { // reporter.verbose(reporter.lang('verboseFileLink', data.src, data.dest)); // if (data.removeDest) { // await unlink(data.dest); // } // await link(data.src, data.dest); // }, // CONCURRENT_QUEUE_ITEMS, // ); // // we need to copy symlinks last as they could reference files we were copying // const symlinkActions: Array = actions.symlink; // await promise.queue(symlinkActions, (data): Promise => { // const linkname = path.resolve(path.dirname(data.dest), data.linkname); // reporter.verbose(reporter.lang('verboseFileSymlink', data.dest, linkname)); // return symlink(linkname, data.dest); // }); // } // function _readFile(loc: string, encoding: string): Promise { // return new Promise((resolve, reject) => { // fs.readFile(loc, encoding, function(err, content) { // if (err) { // reject(err); // } else { // resolve(content); // } // }); // }); // } // export function readFile(loc: string): Promise { // return _readFile(loc, 'utf8').then(normalizeOS); // } // export function readFileRaw(loc: string): Promise { // return _readFile(loc, 'binary'); // } // export async function readFileAny(files: Array): Promise { // for (const file of files) { // if (await exists(file)) { // return readFile(file); // } // } // return null; // } export async function readJson(loc: string): Promise { return (await readJsonAndFile(loc)).object; } export async function readJsonAndFile( loc: string, ): Promise<{ object: Object; content: string; }> { const file = await readFile(loc); try { return { object: map(JSON.parse(stripBOM(file))), content: file, }; } catch (err) { err.message = `${loc}: ${err.message}`; throw err; } } // export async function find(filename: string, dir: string): Promise { // const parts = dir.split(path.sep); // while (parts.length) { // const loc = parts.concat(filename).join(path.sep); // if (await exists(loc)) { // return loc; // } else { // parts.pop(); // } // } // return false; // } // export async function symlink(src: string, dest: string): Promise { // if (process.platform !== 'win32') { // // use relative paths otherwise which will be retained if the directory is moved // src = path.relative(path.dirname(dest), src); // // When path.relative returns an empty string for the current directory, we should instead use // // '.', which is a valid fs.symlink target. // src = src || '.'; // } // try { // const stats = await lstat(dest); // if (stats.isSymbolicLink()) { // const resolved = dest; // if (resolved === src) { // return; // } // } // } catch (err) { // if (err.code !== 'ENOENT') { // throw err; // } // } // // We use rimraf for unlink which never throws an ENOENT on missing target // await unlink(dest); // if (process.platform === 'win32') { // // use directory junctions if possible on win32, this requires absolute paths // await fsSymlink(src, dest, 'junction'); // } else { // await fsSymlink(src, dest); // } // } export type WalkFiles = Array<{ relative: string; absolute: string; basename: string; mtime: number; }>; export async function walk( dir: string, relativeDir?: string, ignoreBasenames: Set = new Set(), ): Promise { let files = []; let filenames = await readdir(dir); if (ignoreBasenames.size) { filenames = filenames.filter((name) => !ignoreBasenames.has(name)); } for (const name of filenames) { const relative = relativeDir ? path.join(relativeDir, name) : name; const loc = path.join(dir, name); const stat = await lstat(loc); files.push({ relative, basename: name, absolute: loc, mtime: +stat.mtime, }); if (stat.isDirectory()) { files = files.concat(await walk(loc, relative, ignoreBasenames)); } } return files; } // export async function getFileSizeOnDisk(loc: string): Promise { // const stat = await lstat(loc); // const {size, blksize: blockSize} = stat; // return Math.ceil(size / blockSize) * blockSize; // } // export function normalizeOS(body: string): string { // return body.replace(/\r\n/g, '\n'); // } const cr = '\r'.charCodeAt(0); const lf = '\n'.charCodeAt(0); async function getEolFromFile(path: string): Promise { if (!(await exists(path))) { return undefined; } const buffer = await readFileBuffer(path); for (let i = 0; i < buffer.length; ++i) { if (buffer[i] === cr) { return '\r\n'; } if (buffer[i] === lf) { return '\n'; } } return undefined; } export async function writeFilePreservingEol(path: string, data: string): Promise { const eol = (await getEolFromFile(path)) || os.EOL; if (eol !== '\n') { data = data.replace(/\n/g, eol); } await writeFile(path, data); } // export async function hardlinksWork(dir: string): Promise { // const filename = 'test-file' + Math.random(); // const file = path.join(dir, filename); // const fileLink = path.join(dir, filename + '-link'); // try { // await writeFile(file, 'test'); // await link(file, fileLink); // } catch (err) { // return false; // } finally { // await unlink(file); // await unlink(fileLink); // } // return true; // } // // not a strict polyfill for Node's fs.mkdtemp // export async function makeTempDir(prefix?: string): Promise { // const dir = path.join(os.tmpdir(), `pika-${prefix || ''}-${Date.now()}-${Math.random()}`); // await unlink(dir); // await mkdirp(dir); // return dir; // } // export async function readFirstAvailableStream(paths: Iterable): Promise { // for (const path of paths) { // try { // const fd = await open(path, 'r'); // return fs.createReadStream(path, {fd}); // } catch (err) { // // Try the next one // } // } // return null; // } // export async function getFirstSuitableFolder( // paths: Iterable, // mode: number = constants.W_OK | constants.X_OK, // eslint-disable-line no-bitwise // ): Promise { // const result: FolderQueryResult = { // skipped: [], // folder: null, // }; // for (const folder of paths) { // try { // await mkdirp(folder); // await access(folder, mode); // result.folder = folder; // return result; // } catch (error) { // result.skipped.push({ // error, // folder, // }); // } // } // return result; // } ================================================ FILE: src/util/map.ts ================================================ export default function nullify(obj?: T): T { if (Array.isArray(obj)) { for (const item of obj) { nullify(item); } } else if ((obj !== null && typeof obj === 'object') || typeof obj === 'function') { Object.setPrototypeOf(obj, null); // for..in can only be applied to 'object', not 'function' if (typeof obj === 'object') { for (const key in obj) { nullify(obj[key]); } } } return obj; } ================================================ FILE: src/util/misc.ts ================================================ /* @flow */ export function sortAlpha(a: string, b: string): number { // sort alphabetically in a deterministic way const shortLen = Math.min(a.length, b.length); for (let i = 0; i < shortLen; i++) { const aChar = a.charCodeAt(i); const bChar = b.charCodeAt(i); if (aChar !== bChar) { return aChar - bChar; } } return a.length - b.length; } export function sortOptionsByFlags(a: any, b: any): number { const aOpt = a.flags.replace(/-/g, ''); const bOpt = b.flags.replace(/-/g, ''); return sortAlpha(aOpt, bOpt); } export function entries(obj: {[key: string]: T}): Array<[string, T]> { const entries = []; if (obj) { for (const key in obj) { entries.push([key, obj[key]]); } } return entries; } export function removePrefix(pattern: string, prefix: string): string { if (pattern.startsWith(prefix)) { pattern = pattern.slice(prefix.length); } return pattern; } export function removeSuffix(pattern: string, suffix: string): string { if (pattern.endsWith(suffix)) { return pattern.slice(0, -suffix.length); } return pattern; } export function addSuffix(pattern: string, suffix: string): string { if (!pattern.endsWith(suffix)) { return pattern + suffix; } return pattern; } export function hyphenate(str: string): string { return str.replace(/[A-Z]/g, (match) => { return '-' + match.charAt(0).toLowerCase(); }); } export function compareSortedArrays(array1: Array, array2: Array): boolean { if (array1.length !== array2.length) { return false; } for (let i = 0, len = array1.length; i < len; i++) { if (array1[i] !== array2[i]) { return false; } } return true; } export function sleep(ms: number): Promise { return new Promise((resolve) => { setTimeout(resolve, ms); }); } ================================================ FILE: src/util/normalize-manifest/fix.ts ================================================ import {MANIFEST_FIELDS} from '../../constants.js'; import {Reporter} from '../../reporters/index.js'; import {isValidLicense} from './util.js'; import {normalizePerson, extractDescription} from './util.js'; import inferLicense from './infer-license.js'; import * as fs from '../fs.js'; import semver from 'semver'; import * as path from 'path'; import * as nodeUrl from 'url'; const LICENSE_RENAMES = { 'MIT/X11': 'MIT', X11: 'MIT', }; type Dict = { [key: string]: T; }; type WarnFunction = (msg: string) => void; export default (async function ( info: Dict, moduleLoc: string, reporter: Reporter, warn: WarnFunction, ): Promise { const files = await fs.readdir(moduleLoc); // clean info.version if (typeof info.version === 'string') { info.version = semver.clean(info.version) || info.version; } // if name or version aren't set then set them to empty strings info.name = info.name || ''; info.version = info.version || ''; // if the man field is a string then coerce it to an array if (typeof info.man === 'string') { info.man = [info.man]; } // if the keywords field is a string then split it on any whitespace if (typeof info.keywords === 'string') { info.keywords = info.keywords.split(/\s+/g); } // if there's no contributors field but an authors field then expand it if (!info.contributors && files.indexOf('AUTHORS') >= 0) { const authorsFilepath = path.join(moduleLoc, 'AUTHORS'); const authorsFilestats = await fs.stat(authorsFilepath); if (authorsFilestats.isFile()) { let authors = await fs.readFile(authorsFilepath); info.contributors = authors .split(/\r?\n/g) // split on lines .map((line): string => line.replace(/^\s*#.*$/, '').trim()) // remove comments .filter((line): boolean => !!line); // remove empty lines; } } // expand people fields to objects if (typeof info.author === 'string' || typeof info.author === 'object') { info.author = normalizePerson(info.author); } if (Array.isArray(info.contributors)) { info.contributors = info.contributors.map(normalizePerson); } if (Array.isArray(info.maintainers)) { info.maintainers = info.maintainers.map(normalizePerson); } // if there's no readme field then load the README file from the cwd if (!info.readme) { const readmeCandidates = files .filter((filename): boolean => { const lower = filename.toLowerCase(); return lower === 'readme' || lower.indexOf('readme.') === 0; }) .sort((filename1, filename2): number => { // favor files with extensions return filename2.indexOf('.') - filename1.indexOf('.'); }); for (const readmeFilename of readmeCandidates) { const readmeFilepath = path.join(moduleLoc, readmeFilename); const readmeFileStats = await fs.stat(readmeFilepath); if (readmeFileStats.isFile()) { info.readmeFilename = readmeFilename; info.readme = await fs.readFile(readmeFilepath); break; } } } // if there's no description then take the first paragraph from the readme if (!info.description && info.readme) { const desc = extractDescription(info.readme); if (desc) { info.description = desc; } } // support array of engine keys if (Array.isArray(info.engines)) { const engines = {}; for (const str of info.engines) { if (typeof str === 'string') { const [name, ...patternParts] = str.trim().split(/ +/g); engines[name] = patternParts.join(' '); } } info.engines = engines; } // allow bugs to be specified as a string, expand it to an object with a single url prop if (typeof info.bugs === 'string') { info.bugs = {url: info.bugs}; } // normalize homepage url to http if (typeof info.homepage === 'string') { const parts = nodeUrl.parse(info.homepage); parts.protocol = parts.protocol || 'http:'; if (parts.pathname && !parts.hostname) { parts.hostname = parts.pathname; parts.pathname = ''; } info.homepage = nodeUrl.format(parts); } // if the `bin` field is as string then expand it to an object with a single property // based on the original `bin` field and `name field` // { name: "foo", bin: "cli.js" } -> { name: "foo", bin: { foo: "cli.js" } } if (typeof info.name === 'string' && typeof info.bin === 'string' && info.bin.length > 0) { // Remove scoped package name for consistency with NPM's bin field fixing behaviour const name = info.name.replace(/^@[^\/]+\//, ''); info.bin = {[name]: info.bin}; } // bundleDependencies is an alias for bundledDependencies if (info.bundledDependencies) { info.bundleDependencies = info.bundledDependencies; delete info.bundledDependencies; } let scripts: {[key: string]: string}; // dummy script object to shove file inferred scripts onto if (info.scripts && typeof info.scripts === 'object') { scripts = info.scripts; } else { scripts = {}; } // if there's a server.js file and no start script then set it to `node server.js` if (!scripts.start && files.indexOf('server.js') >= 0) { scripts.start = 'node server'; } // if there's a binding.gyp file and no install script then set it to `node-gyp rebuild` if (!scripts.install && files.indexOf('binding.gyp') >= 0) { scripts.install = 'node-gyp rebuild'; } // set scripts if we've polluted the empty object if (Object.keys(scripts).length) { info.scripts = scripts; } const dirs = info.directories; if (dirs && typeof dirs === 'object') { const binDir = dirs.bin; if (!info.bin && binDir && typeof binDir === 'string') { const bin = (info.bin = {}); const fullBinDir = path.join(moduleLoc, binDir); if (await fs.exists(fullBinDir)) { for (const scriptName of await fs.readdir(fullBinDir)) { if (scriptName[0] === '.') { continue; } bin[scriptName] = path.join('.', binDir, scriptName); } } else { warn(reporter.lang('manifestDirectoryNotFound', binDir, info.name)); } } const manDir = dirs.man; if (!info.man && typeof manDir === 'string') { const man = (info.man = []); const fullManDir = path.join(moduleLoc, manDir); if (await fs.exists(fullManDir)) { for (const filename of await fs.readdir(fullManDir)) { if (/^(.*?)\.[0-9]$/.test(filename)) { man.push(path.join('.', manDir, filename)); } } } else { warn(reporter.lang('manifestDirectoryNotFound', manDir, info.name)); } } } delete info.directories; // normalize licenses field const licenses = info.licenses; if (Array.isArray(licenses) && !info.license) { let licenseTypes = []; for (let license of licenses) { if (license && typeof license === 'object') { license = license.type; } if (typeof license === 'string') { licenseTypes.push(license); } } licenseTypes = licenseTypes.filter(isValidLicense); if (licenseTypes.length === 1) { info.license = licenseTypes[0]; } else if (licenseTypes.length) { info.license = `(${licenseTypes.join(' OR ')})`; } } const license = info.license; // normalize license if (license && typeof license === 'object') { info.license = license.type; } // get license file const licenseFile = files.find((filename): boolean => { const lower = filename.toLowerCase(); return ( lower === 'license' || lower.startsWith('license.') || lower === 'unlicense' || lower.startsWith('unlicense.') ); }); if (licenseFile) { const licenseFilepath = path.join(moduleLoc, licenseFile); const licenseFileStats = await fs.stat(licenseFilepath); if (licenseFileStats.isFile()) { const licenseContent = await fs.readFile(licenseFilepath); const inferredLicense = inferLicense(licenseContent); info.licenseText = licenseContent; const license = info.license; if (typeof license === 'string') { if (inferredLicense && isValidLicense(inferredLicense) && !isValidLicense(license)) { // some packages don't specify their license version but we can infer it based on their license file const basicLicense = license.toLowerCase().replace(/(-like|\*)$/g, ''); const expandedLicense = inferredLicense.toLowerCase(); if (expandedLicense.startsWith(basicLicense)) { // TODO consider doing something to notify the user info.license = inferredLicense; } } } else if (inferredLicense) { // if there's no license then infer it based on the license file info.license = inferredLicense; } else { // valid expression to refer to a license in a file info.license = `SEE LICENSE IN ${licenseFile}`; } } } if (typeof info.license === 'string') { // sometimes licenses are known by different names, reduce them info.license = LICENSE_RENAMES[info.license] || info.license; } else if (typeof info.readme === 'string') { // the license might be at the bottom of the README const inferredLicense = inferLicense(info.readme); if (inferredLicense) { info.license = inferredLicense; } } // get notice file const noticeFile = files.find((filename): boolean => { const lower = filename.toLowerCase(); return lower === 'notice' || lower.startsWith('notice.'); }); if (noticeFile) { const noticeFilepath = path.join(moduleLoc, noticeFile); const noticeFileStats = await fs.stat(noticeFilepath); if (noticeFileStats.isFile()) { info.noticeText = await fs.readFile(noticeFilepath); } } for (const dependencyType of MANIFEST_FIELDS) { const dependencyList = info[dependencyType]; if (dependencyList && typeof dependencyList === 'object') { delete dependencyList['//']; for (const name in dependencyList) { dependencyList[name] = dependencyList[name] || ''; } } } }); ================================================ FILE: src/util/normalize-manifest/for-publish.ts ================================================ import {Manifest} from '../../types'; import Config from '../../config'; export async function generatePublishManifest( manifest: any, config: Config, _dists?: Array<[Function, any]>, ): Promise { const { name, version, description, keywords, homepage, bugs, bin, license, authors, contributors, man, sideEffects, repository, dependencies, peerDependencies, devDependencies, bundledDependencies, optionalDependencies, engines, enginesStrict, private: priv, publishConfig, } = manifest; const newManifest = { name, description, version, license, bin, files: ['dist-*/', 'bin/'], pika: true, sideEffects: sideEffects || false, keywords, homepage, bugs, authors, contributors, man, repository, dependencies: dependencies || {}, peerDependencies, devDependencies, bundledDependencies, optionalDependencies, engines, enginesStrict, private: priv, publishConfig, }; const dists = _dists || (await config.getDistributions()); for (const [runner, options] of dists) { if (runner.manifest) { await runner.manifest(newManifest, { cwd: config.cwd, isFull: true, manifest, options, }); } } newManifest.pika = true; return newManifest; } export function generatePrettyManifest(manifest) { return JSON.stringify( { ...manifest, dependencies: Object.keys(manifest.dependencies).length === 0 ? {} : '{ ... }', }, null, 2, ); } ================================================ FILE: src/util/normalize-manifest/index.ts ================================================ import {Manifest} from '../../types.js'; import Config from '../../config.js'; import validate from './validate.js'; import fix from './fix.js'; import * as path from 'path'; export default (async function (info: any, moduleLoc: string, config: Config, isRoot: boolean): Promise { // Append dependencies // if (depInfo) { // info.dependencies = depInfo.main; // info.devDependencies = depInfo.dev; // } // create human readable name const {name, version} = info; let human: string | undefined; if (typeof name === 'string') { human = name; } if (human && typeof version === 'string' && version) { human += `@${version}`; } if (isRoot && info._loc) { human = path.relative(config.cwd, info._loc); } function warn(msg: string) { if (human) { msg = `${human}: ${msg}`; } config.reporter.warn(msg); } await fix(info, moduleLoc, config.reporter, warn); try { validate(info, isRoot, config.reporter, warn); } catch (err) { if (human) { err.message = `${human}: ${err.message}`; } throw err; } return info; }); ================================================ FILE: src/util/normalize-manifest/infer-license.ts ================================================ import LICENSES from './licenses.js'; function clean(str: string): string { return str .replace(/[^A-Za-z\s]/g, ' ') .replace(/[\s]+/g, ' ') .trim() .toLowerCase(); } const REGEXES: {[key: string]: Array} = { Apache: [/Apache License\b/], BSD: [/BSD\b/], ISC: [/The ISC License/, /ISC\b/], MIT: [/MIT\b/], Unlicense: [/http:\/\/unlicense.org\//], WTFPL: [/DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE/, /WTFPL\b/], }; export default function inferLicense(license: string): string | null { // check if we have any explicit licenses const cleanLicense = clean(license); for (const licenseName in LICENSES) { const testLicense = LICENSES[licenseName]; if (cleanLicense.search(testLicense) >= 0) { return licenseName; } } // infer based on some keywords for (const licenseName in REGEXES) { for (const regex of REGEXES[licenseName]) { if (license.search(regex) >= 0) { return `${licenseName}*`; } } } return null; } ================================================ FILE: src/util/normalize-manifest/licenses.ts ================================================ export default { 'Apache-2.0': new RegExp( '(licensed under the apache license version the license you may not use this file except in compliance with the license you may obtain a copy of the license at http www apache org licenses license unless required by applicable law or agreed to in writing software distributed under the license is distributed on an as is basis without warranties or conditions of any kind either express or implied see the license for the specific language governing permissions and limitations under the license$|apache license version january http www apache org licenses terms and conditions for use reproduction and distribution definitions license shall mean the terms and conditions for use reproduction and distribution as defined by sections through of this document licensor shall mean the copyright owner or entity authorized by the copyright owner that is granting the license legal entity shall mean the union of the acting entity and all other entities that control are controlled by or are under common control with that entity for the purposes of this definition control means i the power direct or indirect to cause the direction or management of such entity whether by contract or otherwise or ii ownership of fifty percent or more of the outstanding shares or iii beneficial ownership of such entity you or your shall mean an individual or legal entity exercising permissions granted by this license source form shall mean the preferred form for making modifications including but not limited to software source code documentation source and configuration files object form shall mean any form resulting from mechanical transformation or translation of a source form including but not limited to compiled object code generated documentation and conversions to other media types work shall mean the work of authorship whether in source or object form made available under the license as indicated by a copyright notice that is included in or attached to the work an example is provided in the appendix below derivative works shall mean any work whether in source or object form that is based on or derived from the work and for which the editorial revisions annotations elaborations or other modifications represent as a whole an original work of authorship for the purposes of this license derivative works shall not include works that remain separable from or merely link or bind by name to the interfaces of the work and derivative works thereof contribution shall mean any work of authorship including the original version of the work and any modifications or additions to that work or derivative works thereof that is intentionally submitted to licensor for inclusion in the work by the copyright owner or by an individual or legal entity authorized to submit on behalf of the copyright owner for the purposes of this definition submitted means any form of electronic verbal or written communication sent to the licensor or its representatives including but not limited to communication on electronic mailing lists source code control systems and issue tracking systems that are managed by or on behalf of the licensor for the purpose of discussing and improving the work but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as not a contribution contributor shall mean licensor and any individual or legal entity on behalf of whom a contribution has been received by licensor and subsequently incorporated within the work grant of copyright license subject to the terms and conditions of this license each contributor hereby grants to you a perpetual worldwide non exclusive no charge royalty free irrevocable copyright license to reproduce prepare derivative works of publicly display publicly perform sublicense and distribute the work and such derivative works in source or object form grant of patent license subject to the terms and conditions of this license each contributor hereby grants to you a perpetual worldwide non exclusive no charge royalty free irrevocable except as stated in this section patent license to make have made use offer to sell sell import and otherwise transfer the work where such license applies only to those patent claims licensable by such contributor that are necessarily infringed by their contribution s alone or by combination of their contribution s with the work to which such contribution s was submitted if you institute patent litigation against any entity including a cross claim or counterclaim in a lawsuit alleging that the work or a contribution incorporated within the work constitutes direct or contributory patent infringement then any patent licenses granted to you under this license for that work shall terminate as of the date such litigation is filed redistribution you may reproduce and distribute copies of the work or derivative works thereof in any medium with or without modifications and in source or object form provided that you meet the following conditions a you must give any other recipients of the work or derivative works a copy of this license and b you must cause any modified files to carry prominent notices stating that you changed the files and c you must retain in the source form of any derivative works that you distribute all copyright patent trademark and attribution notices from the source form of the work excluding those notices that do not pertain to any part of the derivative works and d if the work includes a notice text file as part of its distribution then any derivative works that you distribute must include a readable copy of the attribution notices contained within such notice file excluding those notices that do not pertain to any part of the derivative works in at least one of the following places within a notice text file distributed as part of the derivative works within the source form or documentation if provided along with the derivative works or within a display generated by the derivative works if and wherever such third party notices normally appear the contents of the notice file are for informational purposes only and do not modify the license you may add your own attribution notices within derivative works that you distribute alongside or as an addendum to the notice text from the work provided that such additional attribution notices cannot be construed as modifying the license you may add your own copyright statement to your modifications and may provide additional or different license terms and conditions for use reproduction or distribution of your modifications or for any such derivative works as a whole provided your use reproduction and distribution of the work otherwise complies with the conditions stated in this license submission of contributions unless you explicitly state otherwise any contribution intentionally submitted for inclusion in the work by you to the licensor shall be under the terms and conditions of this license without any additional terms or conditions notwithstanding the above nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with licensor regarding such contributions trademarks this license does not grant permission to use the trade names trademarks service marks or product names of the licensor except as required for reasonable and customary use in describing the origin of the work and reproducing the content of the notice file disclaimer of warranty unless required by applicable law or agreed to in writing licensor provides the work and each contributor provides its contributions on an as is basis without warranties or conditions of any kind either express or implied including without limitation any warranties or conditions of title non infringement merchantability or fitness for a particular purpose you are solely responsible for determining the appropriateness of using or redistributing the work and assume any risks associated with your exercise of permissions under this license limitation of liability in no event and under no legal theory whether in tort including negligence contract or otherwise unless required by applicable law such as deliberate and grossly negligent acts or agreed to in writing shall any contributor be liable to you for damages including any direct indirect special incidental or consequential damages of any character arising as a result of this license or out of the use or inability to use the work including but not limited to damages for loss of goodwill work stoppage computer failure or malfunction or any and all other commercial damages or losses even if such contributor has been advised of the possibility of such damages accepting warranty or additional liability while redistributing the work or derivative works thereof you may choose to offer and charge a fee for acceptance of support warranty indemnity or other liability obligations and or rights consistent with this license however in accepting such obligations you may act only on your own behalf and on your sole responsibility not on behalf of any other contributor and only if you agree to indemnify defend and hold each contributor harmless for any liability incurred by or claims asserted against such contributor by reason of your accepting any such warranty or additional liability end of terms and conditions$)', 'g', ), 'BSD-2-Clause': new RegExp( '(redistribution and use in source and binary forms with or without modification are permitted provided that the following conditions are met redistributions of source code must retain the above copyright notice this list of conditions and the following disclaimer redistributions in binary form must reproduce the above copyright notice this list of conditions and the following disclaimer in the documentation and or other materials provided with the distribution this(.*?| )is provided by the copyright holders and contributors as is and any express or implied warranties including but not limited to the implied warranties of merchantability and fitness for a particular purpose are disclaimed in no event shall(.*?| )be liable for any direct indirect incidental special exemplary or consequential damages including but not limited to procurement of substitute goods or services loss of use data or profits or business interruption however caused and on any theory of liability whether in contract strict liability or tort including negligence or otherwise arising in any way out of the use of this(.*?| )even if advised of the possibility of such damage$|redistribution and use in source and binary forms with or without modification are permitted provided that the following conditions are met redistributions of source code must retain the above copyright notice this list of conditions and the following disclaimer redistributions in binary form must reproduce the above copyright notice this list of conditions and the following disclaimer in the documentation and or other materials provided with the distribution this software is provided by the copyright holders and contributors as is and any express or implied warranties including but not limited to the implied warranties of merchantability and fitness for a particular purpose are disclaimed in no event shall(.*?| )be liable for any direct indirect incidental special exemplary or consequential damages including but not limited to procurement of substitute goods or services loss of use data or profits or business interruption however caused and on any theory of liability whether in contract strict liability or tort including negligence or otherwise arising in any way out of the use of this software even if advised of the possibility of such damage$)', 'g', ), 'BSD-3-Clause': new RegExp( '(redistribution and use in source and binary forms with or without modification are permitted provided that the following conditions are met redistributions of source code must retain the above copyright notice this list of conditions and the following disclaimer redistributions in binary form must reproduce the above copyright notice this list of conditions and the following disclaimer in the documentation and or other materials provided with the distribution neither the name of(.*?| )nor the names of the contributors may be used to endorse or promote products derived from this software without specific prior written permission this software is provided by the copyright holders and contributors as is and any express or implied warranties including but not limited to the implied warranties of merchantability and fitness for a particular purpose are disclaimed in no event shall(.*?| )be liable for any direct indirect incidental special exemplary or consequential damages including but not limited to procurement of substitute goods or services loss of use data or profits or business interruption however caused and on any theory of liability whether in contract strict liability or tort including negligence or otherwise arising in any way out of the use of this software even if advised of the possibility of such damage$|(redistribution and use in source and binary forms with or without modification are permitted provided that the following conditions are met redistributions of source code must retain the above copyright notice this list of conditions and the following disclaimer redistributions in binary form must reproduce the above copyright notice this list of conditions and the following disclaimer in the documentation and or other materials provided with the distribution the names of any contributors may not be used to endorse or promote products derived from this software without specific prior written permission this software is provided by the copyright holders and contributors as is and any express or implied warranties including but not limited to the implied warranties of merchantability and fitness for a particular purpose are disclaimed in no event shall the copyright holders and contributors be liable for any direct indirect incidental special exemplary or consequential damages including but not limited to procurement of substitute goods or services loss of use data or profits or business interruption however caused and on any theory of liability whether in contract strict liability or tort including negligence or otherwise arising in any way out of the use of this software even if advised of the possibility of such damage$|redistribution and use in source and binary forms with or without modification are permitted provided that the following conditions are met redistributions of source code must retain the above copyright notice this list of conditions and the following disclaimer redistributions in binary form must reproduce the above copyright notice this list of conditions and the following disclaimer in the documentation and or other materials provided with the distribution neither the name(.*?| )nor the names of(.*?| )contributors may be used to endorse or promote products derived from this software without specific prior written permission this software is provided by(.*?| )as is and any express or implied warranties including but not limited to the implied warranties of merchantability and fitness for a particular purpose are disclaimed in no event shall(.*?| )be liable for any direct indirect incidental special exemplary or consequential damages including but not limited to procurement of substitute goods or services loss of use data or profits or business interruption however caused and on any theory of liability whether in contract strict liability or tort including negligence or otherwise arising in any way out of the use of this software even if advised of the possibility of such damage$))', 'g', ), MIT: new RegExp( '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$', 'g', ), Unlicense: new RegExp( 'this is free and unencumbered software released into the public domain anyone is free to copy modify publish use compile sell or distribute this software either in source code form or as a compiled binary for any purpose commercial or non commercial and by any means in jurisdictions that recognize copyright laws the author or authors of this software dedicate any and all copyright interest in the software to the public domain we make this dedication for the benefit of the public at large and to the detriment of our heirs and successors we intend this dedication to be an overt act of relinquishment in perpetuity of all present and future rights to this software under copyright law 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 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 for more information please refer to wildcard$', 'g', ), }; ================================================ FILE: src/util/normalize-manifest/typos.ts ================================================ export default { autohr: 'author', autor: 'author', contributers: 'contributors', depdenencies: 'dependencies', dependancies: 'dependencies', dependecies: 'dependencies', depends: 'dependencies', 'dev-dependencies': 'devDependencies', devDependences: 'devDependencies', devDepenencies: 'devDependencies', devEependencies: 'devDependencies', devdependencies: 'devDependencies', hampage: 'homepage', hompage: 'homepage', prefereGlobal: 'preferGlobal', publicationConfig: 'publishConfig', repo: 'repository', repostitory: 'repository', script: 'scripts', }; ================================================ FILE: src/util/normalize-manifest/util.ts ================================================ import {PersonObject} from '../../types.js'; import validateLicense from 'validate-npm-package-license'; export function isValidLicense(license: string): boolean { return !!license && validateLicense(license).validForNewPackages; } export function stringifyPerson(person: any): any { if (!person || typeof person !== 'object') { return person; } const parts = []; if (person.name) { parts.push(person.name); } const email = person.email || person.mail; if (typeof email === 'string') { parts.push(`<${email}>`); } const url = person.url || person.web; if (typeof url === 'string') { parts.push(`(${url})`); } return parts.join(' '); } export function parsePerson(person: any): PersonObject { if (typeof person !== 'string') { return person; } // format: name (url) const obj: PersonObject = {}; let name = person.match(/^([^\(<]+)/); if (name && name[0].trim()) { obj.name = name[0].trim(); } const email = person.match(/<([^>]+)>/); if (email) { obj.email = email[1]; } const url = person.match(/\(([^\)]+)\)/); if (url) { obj.url = url[1]; } return obj; } export function normalizePerson(person: any): any | PersonObject { return parsePerson(stringifyPerson(person)); } export function extractDescription(readme: any): string { if (typeof readme !== 'string' || readme === '') { return undefined; } // split into lines const lines = readme .trim() .split('\n') .map((line): string => line.trim()); // find the start of the first paragraph, ignore headings let start = 0; for (; start < lines.length; start++) { const line = lines[start]; if (line && line.match(/^(#|$)/)) { // line isn't empty and isn't a heading so this is the start of a paragraph start++; break; } } // skip newlines from the header to the first line while (start < lines.length && !lines[start]) { start++; } // continue to the first non empty line let end = start; while (end < lines.length && lines[end]) { end++; } return lines.slice(start, end).join(' '); } ================================================ FILE: src/util/normalize-manifest/validate.ts ================================================ import {Reporter} from '../../reporters/index.js'; import {MessageError} from '@pika/types'; import typos from './typos.js'; import isBuiltinModule from 'is-builtin-module'; const strings = ['name', 'version']; const dependencyKeys = [ // npm registry will include optionalDependencies in dependencies and we'll want to dedupe them from the // other fields first 'optionalDependencies', // it's seemingly common to include a dependency in dependencies and devDependencies of the same name but // different ranges, this can cause a lot of issues with our determinism and the behaviour of npm is // currently unspecified. 'dependencies', 'devDependencies', ]; function isValidName(name: string): boolean { return !name.match(/[\/@\s\+%:]/) && encodeURIComponent(name) === name; } function isValidScopedName(name: string): boolean { if (name[0] !== '@') { return false; } const parts = name.slice(1).split('/'); return parts.length === 2 && isValidName(parts[0]) && isValidName(parts[1]); } export function isValidPackageName(name: string): boolean { return isValidName(name) || isValidScopedName(name); } type WarnFunction = (msg: string) => void; export default function (info: any, isRoot: boolean, reporter: Reporter, warn: WarnFunction) { if (isRoot) { for (const key in typos) { if (key in info) { warn(reporter.lang('manifestPotentialTypo', key, typos[key])); } } } // validate name const {name} = info; if (typeof name === 'string') { if (isRoot && isBuiltinModule(name)) { warn(reporter.lang('manifestBuiltinModule', name)); } // cannot start with a dot if (name[0] === '.') { throw new MessageError(reporter.lang('manifestNameDot')); } // cannot contain the following characters if (!isValidPackageName(name)) { throw new MessageError(reporter.lang('manifestNameIllegalChars')); } // cannot equal node_modules or favicon.ico const lower = name.toLowerCase(); if (lower === 'node_modules' || lower === 'favicon.ico') { throw new MessageError(reporter.lang('manifestNameBlacklisted')); } } // Only care if you are trying to publish to npm. // // validate license // if (isRoot && !info.private) { // if (typeof info.license === 'string') { // const license = info.license.replace(/\*$/g, ''); // if (!isValidLicense(license)) { // warn(reporter.lang('manifestLicenseInvalid')); // } // } else { // warn(reporter.lang('manifestLicenseNone')); // } // } // validate strings for (const key of strings) { const val = info[key]; if (val && typeof val !== 'string') { throw new MessageError(reporter.lang('manifestStringExpected', key)); } } cleanDependencies(info, isRoot, reporter, warn); } export function cleanDependencies(info: Object, isRoot: boolean, reporter: Reporter, warn: WarnFunction) { // get dependency objects const depTypes = []; for (const type of dependencyKeys) { const deps = info[type]; if (!deps || typeof deps !== 'object') { continue; } depTypes.push([type, deps]); } // aggregate all non-trivial deps (not '' or '*') const nonTrivialDeps: Map = new Map(); for (const [type, deps] of depTypes) { for (const name of Object.keys(deps)) { const version = deps[name]; if (!nonTrivialDeps.has(name) && version && version !== '*') { nonTrivialDeps.set(name, {type, version}); } } } // overwrite first dep of package with non-trivial version, remove the rest const setDeps: Set = new Set(); for (const [type, deps] of depTypes) { for (const name of Object.keys(deps)) { let version = deps[name]; const dep = nonTrivialDeps.get(name); if (dep) { if (version && version !== '*' && version !== dep.version && isRoot) { // only throw a warning when at the root warn(reporter.lang('manifestDependencyCollision', dep.type, name, dep.version, type, version)); } version = dep.version; } if (setDeps.has(name)) { delete deps[name]; } else { deps[name] = version; setDeps.add(name); } } } } ================================================ FILE: src/util/promise.ts ================================================ export function wait(delay: number): Promise { return new Promise((resolve) => { setTimeout(resolve, delay); }); } export function promisify(fn: Function, firstData?: boolean): (...args: Array) => Promise { return function (...args): Promise { return new Promise(function (resolve, reject) { args.push(function (err, ...result) { let res = result; if (result.length <= 1) { res = result[0]; } if (firstData) { res = err; err = null; } if (err) { reject(err); } else { resolve(res); } }); fn.apply(null, args); }); }; } export function queue( arr: Array, promiseProducer: (result: U) => Promise, concurrency: number = Infinity, ): Promise> { concurrency = Math.min(concurrency, arr.length); // clone arr = arr.slice(); const results = []; let total = arr.length; if (!total) { return Promise.resolve(results); } return new Promise((resolve, reject) => { for (let i = 0; i < concurrency; i++) { next(); } function next() { const item = arr.shift(); const promise = promiseProducer(item); promise.then(function (result) { results.push(result); total--; if (total === 0) { resolve(results); } else { if (arr.length) { next(); } } }, reject); } }); } ================================================ FILE: src/util/signal-handler.ts ================================================ import {forwardSignalToSpawnedProcesses} from './child.js'; function forwardSignalAndExit(signal: string) { forwardSignalToSpawnedProcesses(signal); // We want to exit immediately here since `SIGTERM` means that // If we lose stdout messages due to abrupt exit, shoot the messenger? process.exit(1); // eslint-disable-line no-process-exit } export default function handleSignals() { process.on('SIGTERM', () => { forwardSignalAndExit('SIGTERM'); }); } ================================================ FILE: tsconfig.json ================================================ { "compilerOptions": { "target": "ES2020", "module": "esnext", "moduleResolution": "node", "esModuleInterop": true }, "include": ["src/**/*"], "exclude": ["node_modules"] }