UNPKG

157 kBJavaScriptView Raw
1'use strict';
2
3Object.defineProperty(exports, '__esModule', { value: true });
4
5function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
6
7var path = require('path');
8var commander$1 = require('commander');
9var fs = require('fs');
10var invariant = _interopDefault(require('invariant'));
11var loudRejection = _interopDefault(require('loud-rejection'));
12var semver = _interopDefault(require('semver'));
13var chalk = _interopDefault(require('chalk'));
14var inquirer = require('inquirer');
15var read = _interopDefault(require('read'));
16var readline = require('readline');
17var stripAnsi = _interopDefault(require('strip-ansi'));
18var tty = require('tty');
19var util = require('util');
20require('camelcase');
21var isCI = require('is-ci');
22var os = require('os');
23var events = require('events');
24var _rimraf = _interopDefault(require('rimraf'));
25var _mkdirp = _interopDefault(require('mkdirp'));
26var _glob = _interopDefault(require('glob'));
27var stripBOM = _interopDefault(require('strip-bom'));
28var types = require('@pika/types');
29var child_process = require('child_process');
30var isBuiltinModule = _interopDefault(require('is-builtin-module'));
31var validateLicense = _interopDefault(require('validate-npm-package-license'));
32var nodeUrl = require('url');
33var detectIndent = _interopDefault(require('detect-indent'));
34var importFrom = _interopDefault(require('import-from'));
35var uri2path = _interopDefault(require('file-uri-to-path'));
36
37/* @flow */
38function sortAlpha(a, b) {
39 // sort alphabetically in a deterministic way
40 const shortLen = Math.min(a.length, b.length);
41
42 for (let i = 0; i < shortLen; i++) {
43 const aChar = a.charCodeAt(i);
44 const bChar = b.charCodeAt(i);
45
46 if (aChar !== bChar) {
47 return aChar - bChar;
48 }
49 }
50
51 return a.length - b.length;
52}
53function sortOptionsByFlags(a, b) {
54 const aOpt = a.flags.replace(/-/g, '');
55 const bOpt = b.flags.replace(/-/g, '');
56 return sortAlpha(aOpt, bOpt);
57}
58function removeSuffix(pattern, suffix) {
59 if (pattern.endsWith(suffix)) {
60 return pattern.slice(0, -suffix.length);
61 }
62
63 return pattern;
64}
65
66function formatFunction(...strs) {
67 return strs.join(' ');
68}
69
70const defaultFormatter = {
71 bold: formatFunction,
72 dim: formatFunction,
73 italic: formatFunction,
74 underline: formatFunction,
75 inverse: formatFunction,
76 strikethrough: formatFunction,
77 black: formatFunction,
78 red: formatFunction,
79 green: formatFunction,
80 yellow: formatFunction,
81 blue: formatFunction,
82 magenta: formatFunction,
83 cyan: formatFunction,
84 white: formatFunction,
85 gray: formatFunction,
86 grey: formatFunction,
87 stripColor: formatFunction
88};
89
90const messages = {
91 upToDate: 'Already up-to-date.',
92 folderInSync: 'Folder in sync.',
93 nothingToInstall: 'Nothing to install.',
94 resolvingPackages: 'Resolving packages',
95 checkingManifest: 'Validating package.json',
96 fetchingPackages: 'Fetching packages',
97 linkingDependencies: 'Linking dependencies',
98 rebuildingPackages: 'Rebuilding all packages',
99 buildingFreshPackages: 'Building fresh packages',
100 cleaningModules: 'Cleaning modules',
101 bumpingVersion: 'Bumping version',
102 savingHar: 'Saving HAR file: $0',
103 answer: 'Answer?',
104 usage: 'Usage',
105 installCommandRenamed: '`install` has been replaced with `add` to add new dependencies. Run $0 instead.',
106 globalFlagRemoved: '`--global` has been deprecated. Please run $0 instead.',
107 waitingInstance: 'Waiting for the other pika instance to finish (pid $0, inside $1)',
108 waitingNamedInstance: 'Waiting for the other pika instance to finish ($0)',
109 offlineRetrying: 'There appears to be trouble with your network connection. Retrying...',
110 internalServerErrorRetrying: 'There appears to be trouble with the npm registry (returned $1). Retrying...',
111 clearedCache: 'Cleared cache.',
112 couldntClearPackageFromCache: "Couldn't clear package $0 from cache",
113 clearedPackageFromCache: 'Cleared package $0 from cache',
114 packWroteTarball: 'Wrote tarball to $0.',
115 helpExamples: ' Examples:\n$0\n',
116 helpCommands: ' Commands:\n$0\n',
117 helpCommandsMore: ' Run `$0` for more information on specific commands.',
118 helpLearnMore: ' Visit $0 to learn more about Pika.\n',
119 manifestPotentialTypo: 'Potential typo $0, did you mean $1?',
120 manifestBuiltinModule: '$0 is also the name of a node core module',
121 manifestNameDot: "Name can't start with a dot",
122 manifestNameIllegalChars: 'Name contains illegal characters',
123 manifestNameBlacklisted: 'Name is blacklisted',
124 manifestLicenseInvalid: 'License should be a valid SPDX license expression',
125 manifestLicenseNone: 'No license field',
126 manifestStringExpected: '$0 is not a string',
127 manifestDependencyCollision: '$0 has dependency $1 with range $2 that collides with a dependency in $3 of the same name with version $4',
128 manifestDirectoryNotFound: 'Unable to read $0 directory of module $1',
129 verboseFileCopy: 'Copying $0 to $1.',
130 verboseFileLink: 'Creating hardlink at $0 to $1.',
131 verboseFileSymlink: 'Creating symlink at $0 to $1.',
132 verboseFileSkip: 'Skipping copying of file $0 as the file at $1 is the same size ($2) and mtime ($3).',
133 verboseFileSkipSymlink: 'Skipping copying of $0 as the file at $1 is the same symlink ($2).',
134 verboseFileSkipHardlink: 'Skipping copying of $0 as the file at $1 is the same hardlink ($2).',
135 verboseFileRemoveExtraneous: 'Removing extraneous file $0.',
136 verboseFilePhantomExtraneous: "File $0 would be marked as extraneous but has been removed as it's listed as a phantom file.",
137 verboseFileSkipArtifact: 'Skipping copying of $0 as the file is marked as a built artifact and subject to change.',
138 verboseFileFolder: 'Creating directory $0.',
139 verboseRequestStart: 'Performing $0 request to $1.',
140 verboseRequestFinish: 'Request $0 finished with status code $1.',
141 configSet: 'Set $0 to $1.',
142 configDelete: 'Deleted $0.',
143 configNpm: 'npm config',
144 configPika: 'pika config',
145 couldntFindPackagejson: "Couldn't find a package.json file in $0",
146 couldntFindMatch: "Couldn't find match for $0 in $1 for $2.",
147 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.",
148 couldntFindVersionThatMatchesRange: "Couldn't find any versions for $0 that matches $1",
149 chooseVersionFromList: 'Please choose a version of $0 from this list:',
150 moduleNotInManifest: "This module isn't specified in a package.json file.",
151 moduleAlreadyInManifest: '$0 is already in $1. Please remove existing entry first before adding it to $2.',
152 unknownFolderOrTarball: "Passed folder/tarball doesn't exist,",
153 unknownPackage: "Couldn't find package $0.",
154 unknownPackageName: "Couldn't find package name.",
155 unknownUser: "Couldn't find user $0.",
156 unknownRegistryResolver: 'Unknown registry resolver $0',
157 userNotAnOwner: "User $0 isn't an owner of this package.",
158 invalidVersionArgument: 'Use the $0 flag to create a new version.',
159 invalidVersion: 'Invalid version supplied.',
160 requiredVersionInRange: 'Required version in range.',
161 packageNotFoundRegistry: "Couldn't find package $0 on the $1 registry.",
162 requiredPackageNotFoundRegistry: "Couldn't find package $0 required by $1 on the $2 registry.",
163 doesntExist: "Package $1 refers to a non-existing file '$0'.",
164 missingRequiredPackageKey: `Package $0 doesn't have a $1.`,
165 invalidAccess: 'Invalid argument for access, expected public or restricted.',
166 invalidCommand: 'Invalid subcommand. Try $0',
167 invalidGistFragment: 'Invalid gist fragment $0.',
168 invalidHostedGitFragment: 'Invalid hosted git fragment $0.',
169 invalidFragment: 'Invalid fragment $0.',
170 invalidPackageName: 'Invalid package name.',
171 invalidPackageVersion: "Can't add $0: invalid package version $1.",
172 couldntFindManifestIn: "Couldn't find manifest in $0.",
173 shrinkwrapWarning: 'npm-shrinkwrap.json found. This will not be updated or respected. See https://yarnpkg.com/en/docs/migrating-from-npm for more information.',
174 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.',
175 lockfileOutdated: 'Outdated lockfile. Please run `pika install` and try again.',
176 lockfileMerged: 'Merge conflict detected in pika.lock and successfully merged.',
177 lockfileConflict: 'A merge conflict was found in pika.lock but it could not be successfully merged, regenerating pika.lock from scratch.',
178 ignoredScripts: 'Ignored scripts due to flag.',
179 missingAddDependencies: 'Missing list of packages to add to your project.',
180 yesWarning: 'The yes flag has been set. This will automatically answer yes to all questions, which may have security implications.',
181 networkWarning: "You don't appear to have an internet connection. Try the --offline flag to use the cache for registry queries.",
182 flatGlobalError: 'The package $0 requires a flat dependency graph. Add `"flat": true` to your package.json and try again.',
183 noName: `Package doesn't have a name.`,
184 noVersion: `Package doesn't have a version.`,
185 answerRequired: 'An answer is required.',
186 missingWhyDependency: 'Missing package name, folder or path to file to identify why a package has been installed',
187 bugReport: 'If you think this is a bug, please open a bug report with the information provided in $0.',
188 unexpectedError: 'An unexpected error occurred: $0.',
189 jsonError: 'Error parsing JSON at $0, $1.',
190 noPermission: 'Cannot create $0 due to insufficient permissions.',
191 noGlobalFolder: 'Cannot find a suitable global folder. Tried these: $0',
192 allDependenciesUpToDate: 'All of your dependencies are up to date.',
193 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',
194 frozenLockfileError: 'Your lockfile needs to be updated, but pika was run with `--frozen-lockfile`.',
195 fileWriteError: 'Could not write file $0: $1',
196 fileDeleteError: 'Could not delete file $0: $1',
197 multiplePackagesCantUnpackInSameDestination: 'Pattern $0 is trying to unpack in the same destination $1 as pattern $2. This could result in non-deterministic behavior, skipping.',
198 incorrectLockfileEntry: 'Lockfile has incorrect entry for $0. Ignoring it.',
199 invalidResolutionName: 'Resolution field $0 does not end with a valid package name and will be ignored',
200 invalidResolutionVersion: 'Resolution field $0 has an invalid version entry and may be ignored',
201 incompatibleResolutionVersion: 'Resolution field $0 is incompatible with requested version $1',
202 pikaOutdated: "Your current version of Pika is out of date. The latest version is $0, while you're on $1.",
203 pikaOutdatedInstaller: 'To upgrade, download the latest installer at $0.',
204 pikaOutdatedCommand: 'To upgrade, run the following command:',
205 tooManyArguments: 'Too many arguments, maximum of $0.',
206 tooFewArguments: 'Not enough arguments, expected at least $0.',
207 noArguments: "This command doesn't require any arguments.",
208 ownerRemoving: 'Removing owner $0 from package $1.',
209 ownerRemoved: 'Owner removed.',
210 ownerRemoveError: "Couldn't remove owner.",
211 ownerGetting: 'Getting owners for package $0',
212 ownerGettingFailed: "Couldn't get list of owners.",
213 ownerAlready: 'This user is already an owner of this package.',
214 ownerAdded: 'Added owner.',
215 ownerAdding: 'Adding owner $0 to package $1',
216 ownerAddingFailed: "Couldn't add owner.",
217 ownerNone: 'No owners.',
218 teamCreating: 'Creating team',
219 teamRemoving: 'Removing team',
220 teamAddingUser: 'Adding user to team',
221 teamRemovingUser: 'Removing user from team',
222 teamListing: 'Listing teams',
223 distFailed: `⚠️ Distribution "$0" failed to build: $1 $2`,
224 distExiting: ` Exiting...`,
225 distContinuing: ` Continuing...`,
226 cleaning: 'Cleaning modules',
227 cleanCreatingFile: 'Creating $0',
228 cleanCreatedFile: 'Created $0. Please review the contents of this file then run "pika autoclean --force" to perform a clean.',
229 cleanAlreadyExists: '$0 already exists. To revert to the default file, delete $0 then rerun this command.',
230 cleanRequiresForce: 'This command required the "--force" flag to perform the clean. This is a destructive operation. Files specified in $0 will be deleted.',
231 cleanDoesNotExist: '$0 does not exist. Autoclean will delete files specified by $0. Run "autoclean --init" to create $0 with the default entries.',
232 binLinkCollision: "There's already a linked binary called $0 in your global Pika bin. Could not link this package's $0 bin entry.",
233 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.",
234 linkMissing: 'No registered package found called $0.',
235 linkRegistered: 'Registered $0.',
236 linkRegisteredMessage: 'You can now run `pika link $0` in the projects where you want to use this package and it will be used instead.',
237 linkUnregistered: 'Unregistered $0.',
238 linkUnregisteredMessage: 'You can now run `pika unlink $0` in the projects where you no longer want to use this package.',
239 linkUsing: 'Using linked package for $0.',
240 linkDisusing: 'Removed linked package $0.',
241 linkDisusingMessage: 'You will need to run `pika` to re-install the package that was linked.',
242 linkTargetMissing: 'The target of linked package $0 is missing. Removing link.',
243 createInvalidBin: 'Invalid bin entry found in package $0.',
244 createMissingPackage: 'Package not found - this is probably an internal error, and should be reported at https://github.com/yarnpkg/yarn/issues.',
245 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).',
246 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).',
247 workspacesFocusRootCheck: 'This command can only be run inside an individual workspace.',
248 workspacesRequirePrivateProjects: 'Workspaces can only be enabled in private projects.',
249 workspacesSettingMustBeArray: 'The workspaces field in package.json must be an array.',
250 workspacesDisabled: 'Your project root defines workspaces but the feature is disabled in your Pika config. Please check "workspaces-experimental" in your .pikarc file.',
251 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.',
252 workspacesNohoistDisabled: `$0 defines nohoist but the feature is disabled in your Pika config ("workspaces-nohoist-experimental" in .pikarc file)`,
253 workspaceRootNotFound: "Cannot find the root of your workspace - are you sure you're currently in a workspace?",
254 workspaceMissingWorkspace: 'Missing workspace name.',
255 workspaceMissingCommand: 'Missing command name.',
256 workspaceUnknownWorkspace: 'Unknown workspace $0.',
257 workspaceVersionMandatory: 'Missing version in workspace at $0, ignoring.',
258 workspaceNameMandatory: 'Missing name in workspace at $0, ignoring.',
259 workspaceNameDuplicate: 'There are more than one workspace with name $0',
260 cacheFolderSkipped: 'Skipping preferred cache folder $0 because it is not writable.',
261 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.",
262 cacheFolderSelected: 'Selected the next writable cache folder in the list, will be $0.',
263 execMissingCommand: 'Missing command name.',
264 noScriptsAvailable: 'There are no scripts specified inside package.json.',
265 noBinAvailable: 'There are no binary scripts available.',
266 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.`,
267 commandNotSpecified: 'No command specified.',
268 binCommands: 'Commands available from binary scripts: ',
269 possibleCommands: 'Project commands',
270 commandQuestion: 'Which command would you like to run?',
271 commandFailedWithCode: 'Command failed with exit code $0.',
272 commandFailedWithSignal: 'Command failed with signal $0.',
273 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.',
274 nodeGypAutoInstallFailed: 'Failed to auto-install node-gyp. Please run "pika global add node-gyp" manually. Error: $0',
275 foundIncompatible: 'Found incompatible module',
276 incompatibleEngine: 'The engine $0 is incompatible with this module. Expected version $1. Got $2',
277 incompatibleCPU: 'The CPU architecture $0 is incompatible with this module.',
278 incompatibleOS: 'The platform $0 is incompatible with this module.',
279 invalidEngine: 'The engine $0 appears to be invalid.',
280 optionalCompatibilityExcluded: '$0 is an optional dependency and failed compatibility check. Excluding it from installation.',
281 optionalModuleFail: 'This module is OPTIONAL, you can safely ignore this error',
282 optionalModuleScriptFail: 'Error running install script for optional dependency: $0',
283 optionalModuleCleanupFail: 'Could not cleanup build artifacts from failed install: $0',
284 unmetPeer: '$0 has unmet peer dependency $1.',
285 incorrectPeer: '$0 has incorrect peer dependency $1.',
286 selectedPeer: 'Selecting $1 at level $2 as the peer dependency of $0.',
287 missingBundledDependency: '$0 is missing a bundled dependency $1. This should be reported to the package maintainer.',
288 savedNewDependency: 'Saved 1 new dependency.',
289 savedNewDependencies: 'Saved $0 new dependencies.',
290 directDependencies: 'Direct dependencies',
291 allDependencies: 'All dependencies',
292 foundWarnings: 'Found $0 warnings.',
293 foundErrors: 'Found $0 errors.',
294 savedLockfile: 'Saved lockfile.',
295 noRequiredLockfile: 'No lockfile in this directory. Run `pika install` to generate one.',
296 noLockfileFound: 'No lockfile found.',
297 invalidSemver: 'Invalid semver version',
298 newVersion: 'New version',
299 currentVersion: 'Current version',
300 noVersionOnPublish: 'Proceeding with current version',
301 manualVersionResolution: 'Unable to find a suitable version for $0, please choose one by typing one of the numbers below:',
302 manualVersionResolutionOption: '$0 which resolved to $1',
303 createdTag: 'Created tag.',
304 createdTagFail: "Couldn't add tag.",
305 deletedTag: 'Deleted tag.',
306 deletedTagFail: "Couldn't delete tag.",
307 gettingTags: 'Getting tags',
308 deletingTags: 'Deleting tag',
309 creatingTag: 'Creating tag $0 = $1',
310 whyStart: 'Why do we have the module $0?',
311 whyFinding: 'Finding dependency',
312 whyCalculating: 'Calculating file sizes',
313 whyUnknownMatch: "We couldn't find a match!",
314 whyInitGraph: 'Initialising dependency graph',
315 whyWhoKnows: "We don't know why this module exists",
316 whyDiskSizeWithout: 'Disk size without dependencies: $0',
317 whyDiskSizeUnique: 'Disk size with unique dependencies: $0',
318 whyDiskSizeTransitive: 'Disk size with transitive dependencies: $0',
319 whySharedDependencies: 'Number of shared dependencies: $0',
320 whyHoistedTo: `Has been hoisted to $0`,
321 whyHoistedFromSimple: `This module exists because it's hoisted from $0.`,
322 whyNotHoistedSimple: `This module exists here because it's in the nohoist list $0.`,
323 whyDependedOnSimple: `This module exists because $0 depends on it.`,
324 whySpecifiedSimple: `This module exists because it's specified in $0.`,
325 whyReasons: 'Reasons this module exists',
326 whyHoistedFrom: 'Hoisted from $0',
327 whyNotHoisted: `in the nohoist list $0`,
328 whyDependedOn: '$0 depends on it',
329 whySpecified: `Specified in $0`,
330 whyMatch: `\r=> Found $0`,
331 uninstalledPackages: 'Uninstalled packages.',
332 uninstallRegenerate: 'Regenerating lockfile and installing missing dependencies',
333 cleanRemovedFiles: 'Removed $0 files',
334 cleanSavedSize: 'Saved $0 MB.',
335 configFileFound: 'Found configuration file $0.',
336 configPossibleFile: 'Checking for configuration file $0.',
337 npmUsername: 'npm username',
338 npmPassword: 'npm password',
339 npmEmail: 'npm email',
340 npmOneTimePassword: 'npm one-time password',
341 loggingIn: 'Logging in',
342 loggedIn: 'Logged in.',
343 notRevokingEnvToken: 'Not revoking login token, specified via environment variable.',
344 notRevokingConfigToken: 'Not revoking login token, specified via config file.',
345 noTokenToRevoke: 'No login token to revoke.',
346 revokingToken: 'Revoking token',
347 revokedToken: 'Revoked login token.',
348 loginAsPublic: 'Logging in as public',
349 incorrectCredentials: 'Incorrect username or password.',
350 incorrectOneTimePassword: 'Incorrect one-time password.',
351 twoFactorAuthenticationEnabled: 'Two factor authentication enabled.',
352 clearedCredentials: 'Cleared login credentials.',
353 publishFail: "Couldn't publish package: $0",
354 publishPrivate: 'Package marked as private, not publishing.',
355 published: 'Published.',
356 publishing: 'Publishing',
357 nonInteractiveNoVersionSpecified: 'You must specify a new version with --new-version when running with --non-interactive.',
358 nonInteractiveNoToken: "No token found and can't prompt for login when running with --non-interactive.",
359 infoFail: 'Received invalid response from npm.',
360 malformedRegistryResponse: 'Received malformed response from registry for $0. The registry may be down.',
361 registryNoVersions: 'No valid versions found for $0. The package may be unpublished.',
362 cantRequestOffline: "Can't make a request in offline mode ($0)",
363 requestManagerNotSetupHAR: 'RequestManager was not setup to capture HAR files',
364 requestError: 'Request $0 returned a $1',
365 requestFailed: 'Request failed $0',
366 tarballNotInNetworkOrCache: '$0: Tarball is not in network and can not be located in cache ($1)',
367 fetchBadHashWithPath: "Integrity check failed for $0 (computed integrity doesn't match our records, got $2)",
368 fetchBadIntegrityAlgorithm: 'Integrity checked failed for $0 (none of the specified algorithms are supported)',
369 fetchErrorCorrupt: '$0. Mirror tarball appears to be corrupt. You can resolve this by running:\n\n rm -rf $1\n pika install',
370 errorExtractingTarball: 'Extracting tar content of $1 failed, the file appears to be corrupt: $0',
371 updateInstalling: 'Installing $0...',
372 hostedGitResolveError: 'Error connecting to repository. Please, check the url.',
373 unknownFetcherFor: 'Unknown fetcher for $0',
374 downloadGitWithoutCommit: 'Downloading the git repo $0 over plain git without a commit hash',
375 downloadHTTPWithoutCommit: 'Downloading the git repo $0 over HTTP without a commit hash',
376 unplugDisabled: "Packages can only be unplugged when Plug'n'Play is enabled.",
377 plugnplayWindowsSupport: "Plug'n'Play on Windows doesn't support the cache and project to be kept on separate drives",
378 packageInstalledWithBinaries: 'Installed $0 with binaries:',
379 packageHasBinaries: '$0 has binaries:',
380 packageHasNoBinaries: '$0 has no binaries',
381 packageBinaryNotFound: "Couldn't find a binary named $0",
382 couldBeDeduped: '$0 could be deduped from $1 to $2',
383 lockfileNotContainPattern: 'Lockfile does not contain pattern: $0',
384 integrityCheckFailed: 'Integrity check failed',
385 noIntegrityFile: "Couldn't find an integrity file",
386 integrityFailedExpectedIsNotAJSON: 'Integrity check: integrity file is not a json',
387 integrityCheckLinkedModulesDontMatch: "Integrity check: Linked modules don't match",
388 integrityFlagsDontMatch: "Integrity check: Flags don't match",
389 integrityLockfilesDontMatch: "Integrity check: Lock files don't match",
390 integrityFailedFilesMissing: 'Integrity check: Files are missing',
391 integrityPatternsDontMatch: "Integrity check: Top level patterns don't match",
392 integrityModulesFoldersMissing: 'Integrity check: Some module folders are missing',
393 integritySystemParamsDontMatch: "Integrity check: System parameters don't match",
394 packageNotInstalled: '$0 not installed',
395 optionalDepNotInstalled: 'Optional dependency $0 not installed',
396 packageWrongVersion: '$0 is wrong version: expected $1, got $2',
397 packageDontSatisfy: "$0 doesn't satisfy found match of $1",
398 lockfileExists: 'Lockfile already exists, not migrating.',
399 pikaManifestExists: 'pika.package.json manifest already exists, not migrating.',
400 noManifestExists: 'No package.json manifest found. Run `pika init` to generate a new pika.package.json manifest.',
401 skippingImport: 'Skipping import of $0 for $1',
402 importFailed: 'Import of $0 for $1 failed, resolving normally.',
403 importResolveFailed: 'Import of $0 failed starting in $1',
404 importResolvedRangeMatch: 'Using version $0 of $1 instead of $2 for $3',
405 importSourceFilesCorrupted: 'Failed to import from package-lock.json, source file(s) corrupted',
406 importPackageLock: 'found npm package-lock.json, converting to pika.lock',
407 importYarnLock: 'found yarn.lock, converting to pika.lock',
408 importNodeModules: 'creating pika.lock from local node_modules folder',
409 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 .',
410 watchStarting: `Starting up`,
411 watchRunning: `Ready! Watching source tree for changes`,
412 watchRebuild: `Rebuilding...`,
413 watchError: `Build error!`,
414 noValidationErrors: `0 Validation Errors found.`,
415 validationErrors: `$0 Validation Error(s) found. Resolve before publishing.`,
416 scopeNotValid: 'The specified scope is not valid.',
417 deprecatedCommand: '$0 is deprecated. Please use $1.',
418 deprecatedListArgs: 'Filtering by arguments is deprecated. Please use the pattern option instead.',
419 implicitFileDeprecated: 'Using the "file:" protocol implicitly is deprecated. Please either prepend the protocol or prepend the path $0 with "./".',
420 unsupportedNodeVersion: 'You are using Node $0 which is not supported and may encounter bugs or unexpected behavior. Pika supports the following semver range: $1',
421 verboseUpgradeBecauseRequested: 'Considering upgrade of $0 to $1 because it was directly requested.',
422 verboseUpgradeBecauseOutdated: 'Considering upgrade of $0 to $1 because a newer version exists in the registry.',
423 verboseUpgradeNotUnlocking: 'Not unlocking $0 in the lockfile because it is a new or direct dependency.',
424 verboseUpgradeUnlocking: 'Unlocking $0 in the lockfile.',
425 folderMissing: "Directory $0 doesn't exist",
426 mutexPortBusy: 'Cannot use the network mutex on port $0. It is probably used by another app.',
427 auditRunning: 'Auditing packages',
428 auditSummary: '$0 vulnerabilities found - Packages audited: $1',
429 auditSummarySeverity: 'Severity:',
430 auditCritical: '$0 Critical',
431 auditHigh: '$0 High',
432 auditModerate: '$0 Moderate',
433 auditLow: '$0 Low',
434 auditInfo: '$0 Info',
435 auditResolveCommand: '# Run $0 to resolve $1 $2',
436 auditSemverMajorChange: 'SEMVER WARNING: Recommended action is a potentially breaking change',
437 auditManualReview: 'Manual Review\nSome vulnerabilities require your attention to resolve\n\nVisit https://go.npm.me/audit-guide for additional guidance',
438 auditRunAuditForDetails: 'Security audit found potential problems. Run "pika audit" for additional details.',
439 auditOffline: 'Skipping audit. Security audit cannot be performed in offline mode.'
440};
441
442
443
444var languages = /*#__PURE__*/Object.freeze({
445 en: messages
446});
447
448function stringifyLangArgs(args) {
449 return args.map(function (val) {
450 if (val != null && val.inspect) {
451 return val.inspect();
452 } else {
453 try {
454 const str = JSON.stringify(val) || val + ''; // should match all literal line breaks and
455 // "u001b" that follow an odd number of backslashes and convert them to ESC
456 // we do this because the JSON.stringify process has escaped these characters
457
458 return str.replace(/((?:^|[^\\])(?:\\{2})*)\\u001[bB]/g, '$1\u001b').replace(/[\\]r[\\]n|([\\])?[\\]n/g, (match, precededBacklash) => {
459 // precededBacklash not null when "\n" is preceded by a backlash ("\\n")
460 // match will be "\\n" and we don't replace it with os.EOL
461 return precededBacklash ? match : os.EOL;
462 });
463 } catch (e) {
464 return util.inspect(val);
465 }
466 }
467 });
468}
469class BaseReporter {
470 constructor(opts = {}) {
471 const lang = 'en';
472 this.language = lang;
473 this.stdout = opts.stdout || process.stdout;
474 this.stderr = opts.stderr || process.stderr;
475 this.stdin = opts.stdin || this._getStandardInput();
476 this.emoji = !!opts.emoji;
477 this.nonInteractive = !!opts.nonInteractive;
478 this.noProgress = !!opts.noProgress || isCI;
479 this.isVerbose = !!opts.verbose; // @ts-ignore
480
481 this.isTTY = this.stdout.isTTY;
482 this.peakMemory = 0;
483 this.startTime = Date.now();
484 this.format = defaultFormatter;
485 }
486
487 lang(key, ...args) {
488 const msg = languages[this.language][key] || messages[key];
489
490 if (!msg) {
491 throw new ReferenceError(`No message defined for language key ${key}`);
492 } // stringify args
493
494
495 const stringifiedArgs = stringifyLangArgs(args); // replace $0 placeholders with args
496
497 return msg.replace(/\$(\d+)/g, (str, i) => {
498 return stringifiedArgs[i];
499 });
500 }
501 /**
502 * `stringifyLangArgs` run `JSON.stringify` on strings too causing
503 * them to appear quoted. This marks them as "raw" and prevents
504 * the quoting and escaping
505 */
506
507
508 rawText(str) {
509 return {
510 inspect() {
511 return str;
512 }
513
514 };
515 }
516
517 verbose(msg) {
518 if (this.isVerbose) {
519 this._verbose(msg);
520 }
521 }
522
523 verboseInspect(val) {
524 if (this.isVerbose) {
525 this._verboseInspect(val);
526 }
527 }
528
529 _verbose(msg) {}
530
531 _verboseInspect(val) {}
532
533 _getStandardInput() {
534 let standardInput; // Accessing stdin in a win32 headless process (e.g., Visual Studio) may throw an exception.
535
536 try {
537 standardInput = process.stdin;
538 } catch (e) {
539 console.warn(e.message);
540 delete process.stdin; // @ts-ignore
541
542 process.stdin = new events.EventEmitter();
543 standardInput = process.stdin;
544 }
545
546 return standardInput;
547 }
548
549 initPeakMemoryCounter() {
550 this.checkPeakMemory();
551 this.peakMemoryInterval = setInterval(() => {
552 this.checkPeakMemory();
553 }, 1000); // $FlowFixMe: Node's setInterval returns a Timeout, not a Number
554
555 this.peakMemoryInterval.unref();
556 }
557
558 checkPeakMemory() {
559 const {
560 heapTotal
561 } = process.memoryUsage();
562
563 if (heapTotal > this.peakMemory) {
564 this.peakMemory = heapTotal;
565 }
566 }
567
568 close() {
569 if (this.peakMemoryInterval) {
570 clearInterval(this.peakMemoryInterval);
571 this.peakMemoryInterval = null;
572 }
573 }
574
575 getTotalTime() {
576 return Date.now() - this.startTime;
577 } // TODO
578
579
580 list(key, items, hints) {} // Outputs basic tree structure to console
581
582
583 tree(key, obj, {
584 force = false
585 } = {}) {} // called whenever we begin a step in the CLI.
586
587
588 step(current, total, message, emoji) {} // a error message has been triggered. this however does not always meant an abrupt
589 // program end.
590
591
592 error(message) {} // an info message has been triggered. this provides things like stats and diagnostics.
593
594
595 info(message) {} // a warning message has been triggered.
596
597
598 warn(message) {} // a success message has been triggered.
599
600
601 success(message) {} // a simple log message
602 // TODO: rethink the {force} parameter. In the meantime, please don't use it (cf comments in #4143).
603
604
605 log(message, {
606 force = false
607 } = {}) {} // a shell command has been executed
608
609
610 command(command) {} // inspect and pretty-print any value
611
612
613 inspect(value) {} // the screen shown at the very start of the CLI
614
615
616 header(command, pkg) {} // the screen shown at the very end of the CLI
617
618
619 footer(showPeakMemory) {} // a table structure
620
621
622 table(head, body) {} // render an activity spinner and return a function that will trigger an update
623
624
625 activity() {
626 return {
627 tick(name) {},
628
629 end() {}
630
631 };
632 } //
633
634
635 activitySet(total, workers) {
636 return {
637 spinners: Array(workers).fill({
638 clear() {},
639
640 setPrefix() {},
641
642 tick() {},
643
644 end() {}
645
646 }),
647
648 end() {}
649
650 };
651 } //
652
653
654 question(question, options = {}) {
655 return Promise.reject(new Error('Not implemented'));
656 } //
657
658
659 async questionAffirm(question) {
660 const condition = true; // trick eslint
661
662 if (this.nonInteractive) {
663 return true;
664 }
665
666 while (condition) {
667 let answer = await this.question(question);
668 answer = answer.toLowerCase();
669
670 if (answer === 'y' || answer === 'yes') {
671 return true;
672 }
673
674 if (answer === 'n' || answer === 'no') {
675 return false;
676 }
677
678 this.error('Invalid answer for question');
679 }
680
681 return false;
682 } // prompt the user to select an option from an array
683
684
685 select(header, question, options) {
686 return Promise.reject(new Error('Not implemented'));
687 } // render a progress bar and return a function which when called will trigger an update
688
689
690 progress(total) {
691 return function () {};
692 } // utility function to disable progress bar
693
694
695 disableProgress() {
696 this.noProgress = true;
697 } //
698
699
700 prompt(message, choices, options = {}) {
701 return Promise.reject(new Error('Not implemented'));
702 }
703
704}
705
706// public
707function sortTrees(trees) {
708 return trees.sort(function (tree1, tree2) {
709 return tree1.name.localeCompare(tree2.name);
710 });
711}
712function recurseTree(tree, prefix, recurseFunc) {
713 const treeLen = tree.length;
714 const treeEnd = treeLen - 1;
715
716 for (let i = 0; i < treeLen; i++) {
717 const atEnd = i === treeEnd;
718 recurseFunc(tree[i], prefix + getLastIndentChar(atEnd), prefix + getNextIndentChar(atEnd));
719 }
720}
721function getFormattedOutput(fmt) {
722 const item = formatColor(fmt.color, fmt.name, fmt.formatter);
723 const suffix = getSuffix(fmt.hint, fmt.formatter);
724 return `${fmt.prefix}${item}${suffix}\n`;
725}
726
727function getNextIndentChar(end) {
728 return end ? ' ' : '│ ';
729}
730
731function getLastIndentChar(end) {
732 return end ? '└' : '├';
733}
734
735function getSuffix(hint, formatter) {
736 return hint ? ` (${formatter.grey(hint)})` : '';
737}
738
739function formatColor(color, strToFormat, formatter) {
740 return color ? formatter[color](strToFormat) : strToFormat;
741}
742
743const CLEAR_WHOLE_LINE = 0;
744const CLEAR_RIGHT_OF_CURSOR = 1;
745function clearLine(stdout) {
746 if (!chalk.supportsColor) {
747 if (stdout instanceof tty.WriteStream) {
748 if (stdout.columns > 0) {
749 stdout.write(`\r${' '.repeat(stdout.columns - 1)}`);
750 }
751
752 stdout.write(`\r`);
753 }
754
755 return;
756 }
757
758 readline.clearLine(stdout, CLEAR_WHOLE_LINE);
759 readline.cursorTo(stdout, 0);
760}
761function toStartOfLine(stdout) {
762 if (!chalk.supportsColor) {
763 stdout.write('\r');
764 return;
765 }
766
767 readline.cursorTo(stdout, 0);
768}
769function writeOnNthLine(stdout, n, msg) {
770 if (!chalk.supportsColor) {
771 return;
772 }
773
774 if (n == 0) {
775 readline.cursorTo(stdout, 0);
776 stdout.write(msg);
777 readline.clearLine(stdout, CLEAR_RIGHT_OF_CURSOR);
778 return;
779 }
780
781 readline.cursorTo(stdout, 0);
782 readline.moveCursor(stdout, 0, -n);
783 stdout.write(msg);
784 readline.clearLine(stdout, CLEAR_RIGHT_OF_CURSOR);
785 readline.cursorTo(stdout, 0);
786 readline.moveCursor(stdout, 0, n);
787}
788function clearNthLine(stdout, n) {
789 if (!chalk.supportsColor) {
790 return;
791 }
792
793 if (n == 0) {
794 clearLine(stdout);
795 return;
796 }
797
798 readline.cursorTo(stdout, 0);
799 readline.moveCursor(stdout, 0, -n);
800 readline.clearLine(stdout, CLEAR_WHOLE_LINE);
801 readline.moveCursor(stdout, 0, n);
802}
803
804class ProgressBar {
805 constructor(total, stdout = process.stderr, callback) {
806 this.stdout = stdout;
807 this.total = total;
808 this.chars = ProgressBar.bars[0];
809 this.delay = 60;
810 this.curr = 0;
811 this._callback = callback;
812 clearLine(stdout);
813 }
814
815 tick() {
816 if (this.curr >= this.total) {
817 return;
818 }
819
820 this.curr++; // schedule render
821
822 if (!this.id) {
823 this.id = setTimeout(() => this.render(), this.delay);
824 }
825 }
826
827 cancelTick() {
828 if (this.id) {
829 clearTimeout(this.id);
830 this.id = null;
831 }
832 }
833
834 stop() {
835 // "stop" by setting current to end so `tick` becomes noop
836 this.curr = this.total;
837 this.cancelTick();
838 clearLine(this.stdout);
839
840 if (this._callback) {
841 this._callback(this);
842 }
843 }
844
845 render() {
846 // clear throttle
847 this.cancelTick();
848 let ratio = this.curr / this.total;
849 ratio = Math.min(Math.max(ratio, 0), 1); // progress without bar
850
851 let bar = ` ${this.curr}/${this.total}`; // calculate size of actual bar
852 // $FlowFixMe: investigate process.stderr.columns flow error
853 // @ts-ignore
854
855 const availableSpace = Math.max(0, this.stdout.columns - bar.length - 3);
856 const width = Math.min(this.total, availableSpace);
857 const completeLength = Math.round(width * ratio);
858 const complete = this.chars[0].repeat(completeLength);
859 const incomplete = this.chars[1].repeat(width - completeLength);
860 bar = `[${complete}${incomplete}]${bar}`;
861 toStartOfLine(this.stdout);
862 this.stdout.write(bar);
863 }
864
865}
866ProgressBar.bars = [['#', '-']];
867
868class Spinner {
869 constructor(stdout = process.stderr, lineNumber = 0) {
870 this.current = 0;
871 this.prefix = '';
872 this.lineNumber = lineNumber;
873 this.stdout = stdout;
874 this.delay = 60;
875 this.chars = Spinner.spinners[28].split('');
876 this.text = '';
877 this.id = null;
878 }
879
880 setPrefix(prefix) {
881 this.prefix = prefix;
882 }
883
884 setText(text) {
885 this.text = text;
886 }
887
888 start() {
889 this.current = 0;
890 this.render();
891 }
892
893 render() {
894 if (this.id) {
895 clearTimeout(this.id);
896 } // build line ensuring we don't wrap to the next line
897
898
899 let msg = `${this.prefix}${this.chars[this.current]} ${this.text}`; // @ts-ignore
900
901 const columns = typeof this.stdout.columns === 'number' ? this.stdout.columns : 100;
902 msg = msg.slice(0, columns);
903 writeOnNthLine(this.stdout, this.lineNumber, msg);
904 this.current = ++this.current % this.chars.length;
905 this.id = setTimeout(() => this.render(), this.delay);
906 }
907
908 stop() {
909 if (this.id) {
910 clearTimeout(this.id);
911 this.id = null;
912 }
913
914 clearNthLine(this.stdout, this.lineNumber);
915 }
916
917}
918Spinner.spinners = ['|/-\\', '⠂-–—–-', '◐◓◑◒', '◴◷◶◵', '◰◳◲◱', '▖▘▝▗', '■□▪▫', '▌▀▐▄', '▉▊▋▌▍▎▏▎▍▌▋▊▉', '▁▃▄▅▆▇█▇▆▅▄▃', '←↖↑↗→↘↓↙', '┤┘┴└├┌┬┐', '◢◣◤◥', '.oO°Oo.', '.oO@*', '🌍🌎🌏', '◡◡ ⊙⊙ ◠◠', '☱☲☴', '⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏', '⠋⠙⠚⠞⠖⠦⠴⠲⠳⠓', '⠄⠆⠇⠋⠙⠸⠰⠠⠰⠸⠙⠋⠇⠆', '⠋⠙⠚⠒⠂⠂⠒⠲⠴⠦⠖⠒⠐⠐⠒⠓⠋', '⠁⠉⠙⠚⠒⠂⠂⠒⠲⠴⠤⠄⠄⠤⠴⠲⠒⠂⠂⠒⠚⠙⠉⠁', '⠈⠉⠋⠓⠒⠐⠐⠒⠖⠦⠤⠠⠠⠤⠦⠖⠒⠐⠐⠒⠓⠋⠉⠈', '⠁⠁⠉⠙⠚⠒⠂⠂⠒⠲⠴⠤⠄⠄⠤⠠⠠⠤⠦⠖⠒⠐⠐⠒⠓⠋⠉⠈⠈', '⢄⢂⢁⡁⡈⡐⡠', '⢹⢺⢼⣸⣇⡧⡗⡏', '⣾⣽⣻⢿⡿⣟⣯⣷', '⠁⠂⠄⡀⢀⠠⠐⠈'];
919
920const auditSeverityColors = {
921 info: chalk.bold,
922 low: chalk.bold,
923 moderate: chalk.yellow,
924 high: chalk.red,
925 critical: chalk.bgRed
926}; // fixes bold on windows
927
928if (process.platform === 'win32' && !(process.env.TERM && /^xterm/i.test(process.env.TERM))) {
929 // @ts-ignore
930 chalk.bold._styles[0].close += '\u001b[m';
931}
932
933class ConsoleReporter extends BaseReporter {
934 constructor(opts) {
935 super(opts);
936 this._lastCategorySize = 0;
937 this._spinners = new Set();
938 this.format = chalk;
939 this.format.stripColor = stripAnsi;
940 this.isSilent = !!opts.isSilent;
941 }
942
943 _prependEmoji(msg, emoji) {
944 if (this.emoji && emoji && this.isTTY) {
945 msg = `${emoji} ${msg}`;
946 }
947
948 return msg;
949 }
950
951 _logCategory(category, color, msg) {
952 this._lastCategorySize = category.length;
953
954 this._log(`${this.format[color](category)} ${msg}`);
955 }
956
957 _verbose(msg) {
958 this._logCategory('verbose', 'grey', `${process.uptime()} ${msg}`);
959 }
960
961 _verboseInspect(obj) {
962 this.inspect(obj);
963 }
964
965 close() {
966 for (const spinner of this._spinners) {
967 spinner.stop();
968 }
969
970 this._spinners.clear();
971
972 this.stopProgress();
973 super.close();
974 }
975
976 table(head, body) {
977 //
978 head = head.map(field => this.format.underline(field)); //
979
980 const rows = [head].concat(body); // get column widths
981
982 const cols = [];
983
984 for (let i = 0; i < head.length; i++) {
985 const widths = rows.map(row => this.format.stripColor(row[i]).length);
986 cols[i] = Math.max(...widths);
987 } //
988
989
990 const builtRows = rows.map(row => {
991 for (let i = 0; i < row.length; i++) {
992 const field = row[i];
993 const padding = cols[i] - this.format.stripColor(field).length;
994 row[i] = field + ' '.repeat(padding);
995 }
996
997 return row.join(' ');
998 });
999 this.log(builtRows.join('\n'));
1000 }
1001
1002 step(current, total, msg, emoji) {
1003 msg = this._prependEmoji(msg, emoji);
1004
1005 if (msg.endsWith('?')) {
1006 msg = `${removeSuffix(msg, '?')}...?`;
1007 } else {
1008 msg += '...';
1009 }
1010
1011 this.log(`${this.format.dim(`[${current}/${total}]`)} ${msg}`);
1012 }
1013
1014 inspect(value) {
1015 if (typeof value !== 'number' && typeof value !== 'string') {
1016 value = util.inspect(value, {
1017 breakLength: 0,
1018 colors: this.isTTY,
1019 depth: null,
1020 maxArrayLength: null
1021 });
1022 }
1023
1024 this.log(String(value), {
1025 force: true
1026 });
1027 }
1028
1029 list(key, items, hints) {
1030 const gutterWidth = (this._lastCategorySize || 2) - 1;
1031
1032 if (hints) {
1033 for (const item of items) {
1034 this._log(`${' '.repeat(gutterWidth)}- ${this.format.bold(item)}`);
1035
1036 this._log(` ${' '.repeat(gutterWidth)} ${hints[item]}`);
1037 }
1038 } else {
1039 for (const item of items) {
1040 this._log(`${' '.repeat(gutterWidth)}- ${item}`);
1041 }
1042 }
1043 }
1044
1045 header(command, pkg) {
1046 this.log(this.format.bold(`${pkg.name} ${command} v${pkg.version}`));
1047 }
1048
1049 footer(showPeakMemory) {
1050 this.stopProgress();
1051 const totalTime = (this.getTotalTime() / 1000).toFixed(2);
1052 let msg = `Done in ${totalTime}s.`;
1053
1054 if (showPeakMemory) {
1055 const peakMemory = (this.peakMemory / 1024 / 1024).toFixed(2);
1056 msg += ` Peak memory usage ${peakMemory}MB.`;
1057 }
1058
1059 this.log(this._prependEmoji(msg, '✨'));
1060 }
1061
1062 log(msg, {
1063 force = false
1064 } = {}) {
1065 this._lastCategorySize = 0;
1066
1067 this._log(msg, {
1068 force
1069 });
1070 }
1071
1072 _log(msg, {
1073 force = false
1074 } = {}) {
1075 if (this.isSilent && !force) {
1076 return;
1077 }
1078
1079 clearLine(this.stdout);
1080 this.stdout.write(`${msg}\n`);
1081 }
1082
1083 success(msg) {
1084 this._logCategory('success', 'green', msg);
1085 }
1086
1087 error(msg) {
1088 clearLine(this.stderr);
1089 this.stderr.write(`${this.format.red('error')} ${msg}\n`);
1090 }
1091
1092 info(msg) {
1093 this._logCategory('info', 'blue', msg);
1094 }
1095
1096 command(command) {
1097 this.log(this.format.dim(`$ ${command}`));
1098 }
1099
1100 warn(msg) {
1101 clearLine(this.stderr);
1102 this.stderr.write(`${this.format.yellow('warning')} ${msg}\n`);
1103 }
1104
1105 question(question, options = {}) {
1106 if (!process.stdout.isTTY) {
1107 return Promise.reject(new Error("Can't answer a question unless a user TTY"));
1108 }
1109
1110 return new Promise((resolve, reject) => {
1111 read({
1112 prompt: `${this.format.dim('question')} ${question}: `,
1113 silent: !!options.password,
1114 output: this.stdout,
1115 input: this.stdin
1116 }, (err, answer) => {
1117 if (err) {
1118 if (err.message === 'canceled') {
1119 process.exitCode = 1;
1120 }
1121
1122 reject(err);
1123 } else {
1124 if (!answer && options.required) {
1125 this.error(this.lang('answerRequired'));
1126 resolve(this.question(question, options));
1127 } else {
1128 resolve(answer);
1129 }
1130 }
1131 });
1132 });
1133 } // handles basic tree output to console
1134
1135
1136 tree(key, trees, {
1137 force = false
1138 } = {}) {
1139 this.stopProgress(); //
1140
1141 if (this.isSilent && !force) {
1142 return;
1143 }
1144
1145 const output = ({
1146 name,
1147 children,
1148 hint,
1149 color
1150 }, titlePrefix, childrenPrefix) => {
1151 const formatter = this.format;
1152 const out = getFormattedOutput({
1153 prefix: titlePrefix,
1154 hint,
1155 color,
1156 name,
1157 formatter
1158 });
1159 this.stdout.write(out);
1160
1161 if (children && children.length) {
1162 recurseTree(sortTrees(children), childrenPrefix, output);
1163 }
1164 };
1165
1166 recurseTree(sortTrees(trees), '', output);
1167 }
1168
1169 activitySet(total, workers) {
1170 if (!this.isTTY || this.noProgress) {
1171 return super.activitySet(total, workers);
1172 }
1173
1174 const spinners = [];
1175 const reporterSpinners = this._spinners;
1176
1177 for (let i = 1; i < workers; i++) {
1178 this.log('');
1179 }
1180
1181 for (let i = 0; i < workers; i++) {
1182 const spinner = new Spinner(this.stderr, i);
1183 reporterSpinners.add(spinner);
1184 spinner.start();
1185 let prefix = null;
1186 let current = 0;
1187
1188 const updatePrefix = () => {
1189 spinner.setPrefix(`${this.format.dim(`[${current === 0 ? '-' : current}/${total}]`)} `);
1190 };
1191
1192 const clear = () => {
1193 prefix = null;
1194 current = 0;
1195 updatePrefix();
1196 spinner.setText('waiting...');
1197 };
1198
1199 clear();
1200 spinners.unshift({
1201 clear,
1202
1203 setPrefix(_current, _prefix) {
1204 current = _current;
1205 prefix = _prefix;
1206 spinner.setText(prefix);
1207 updatePrefix();
1208 },
1209
1210 tick(msg) {
1211 if (prefix) {
1212 msg = `${prefix}: ${msg}`;
1213 }
1214
1215 spinner.setText(msg);
1216 },
1217
1218 end() {
1219 spinner.stop();
1220 reporterSpinners.delete(spinner);
1221 }
1222
1223 });
1224 }
1225
1226 return {
1227 spinners,
1228 end: () => {
1229 for (const spinner of spinners) {
1230 spinner.end();
1231 }
1232
1233 readline.moveCursor(this.stdout, 0, -workers + 1);
1234 }
1235 };
1236 }
1237
1238 activity() {
1239 if (!this.isTTY) {
1240 return {
1241 tick() {},
1242
1243 end() {}
1244
1245 };
1246 }
1247
1248 const reporterSpinners = this._spinners;
1249 const spinner = new Spinner(this.stderr);
1250 spinner.start();
1251 reporterSpinners.add(spinner);
1252 return {
1253 tick(name) {
1254 spinner.setText(name);
1255 },
1256
1257 end() {
1258 spinner.stop();
1259 reporterSpinners.delete(spinner);
1260 }
1261
1262 };
1263 }
1264
1265 select(header, question, options) {
1266 if (!this.isTTY) {
1267 return Promise.reject(new Error("Can't answer a question unless a user TTY"));
1268 }
1269
1270 const rl = readline.createInterface({
1271 input: this.stdin,
1272 output: this.stdout,
1273 terminal: true
1274 });
1275 const questions = options.map(opt => opt.name);
1276 const answers = options.map(opt => opt.value);
1277
1278 function toIndex(input) {
1279 const index = answers.indexOf(input);
1280
1281 if (index >= 0) {
1282 return index;
1283 } else {
1284 return +input;
1285 }
1286 }
1287
1288 return new Promise(resolve => {
1289 this.info(header);
1290
1291 for (let i = 0; i < questions.length; i++) {
1292 this.log(` ${this.format.dim(`${i + 1})`)} ${questions[i]}`);
1293 }
1294
1295 const ask = () => {
1296 rl.question(`${question}: `, input => {
1297 let index = toIndex(input);
1298
1299 if (isNaN(index)) {
1300 this.log('Not a number');
1301 ask();
1302 return;
1303 }
1304
1305 if (index <= 0 || index > options.length) {
1306 this.log('Outside answer range');
1307 ask();
1308 return;
1309 } // get index
1310
1311
1312 index--;
1313 rl.close();
1314 resolve(answers[index]);
1315 });
1316 };
1317
1318 ask();
1319 });
1320 }
1321
1322 progress(count) {
1323 if (this.noProgress || count <= 0) {
1324 return function () {// noop
1325 };
1326 }
1327
1328 if (!this.isTTY) {
1329 return function () {// TODO what should the behaviour here be? we could buffer progress messages maybe
1330 };
1331 } // Clear any potentially old progress bars
1332
1333
1334 this.stopProgress();
1335 const bar = this._progressBar = new ProgressBar(count, this.stderr, progress => {
1336 if (progress === this._progressBar) {
1337 this._progressBar = null;
1338 }
1339 });
1340 bar.render();
1341 return function () {
1342 bar.tick();
1343 };
1344 }
1345
1346 stopProgress() {
1347 if (this._progressBar) {
1348 this._progressBar.stop();
1349 }
1350 }
1351
1352 async prompt(message, choices, options = {}) {
1353 if (!process.stdout.isTTY) {
1354 return Promise.reject(new Error("Can't answer a question unless a user TTY"));
1355 }
1356
1357 let pageSize;
1358
1359 if (process.stdout instanceof tty.WriteStream) {
1360 pageSize = process.stdout.rows - 2;
1361 }
1362
1363 const rl = readline.createInterface({
1364 input: this.stdin,
1365 output: this.stdout,
1366 terminal: true
1367 }); // $FlowFixMe: Need to update the type of Inquirer
1368
1369 const prompt = inquirer.createPromptModule({
1370 input: this.stdin,
1371 output: this.stdout
1372 });
1373 const {
1374 name = 'prompt',
1375 type = 'input',
1376 validate
1377 } = options;
1378 const answers = await prompt([{
1379 name,
1380 type,
1381 message,
1382 choices,
1383 pageSize,
1384 validate,
1385 default: options.default
1386 }]);
1387 rl.close();
1388 return answers[name];
1389 }
1390
1391}
1392
1393function _defineProperty(obj, key, value) {
1394 if (key in obj) {
1395 Object.defineProperty(obj, key, {
1396 value: value,
1397 enumerable: true,
1398 configurable: true,
1399 writable: true
1400 });
1401 } else {
1402 obj[key] = value;
1403 }
1404
1405 return obj;
1406}
1407
1408function _objectSpread(target) {
1409 for (var i = 1; i < arguments.length; i++) {
1410 var source = arguments[i] != null ? arguments[i] : {};
1411 var ownKeys = Object.keys(source);
1412
1413 if (typeof Object.getOwnPropertySymbols === 'function') {
1414 ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) {
1415 return Object.getOwnPropertyDescriptor(source, sym).enumerable;
1416 }));
1417 }
1418
1419 ownKeys.forEach(function (key) {
1420 _defineProperty(target, key, source[key]);
1421 });
1422 }
1423
1424 return target;
1425}
1426
1427class JSONReporter extends BaseReporter {
1428 constructor(opts) {
1429 super(opts);
1430 this._activityId = 0;
1431 this._progressId = 0;
1432 }
1433
1434 _dump(type, data, error) {
1435 let stdout = this.stdout;
1436
1437 if (error) {
1438 stdout = this.stderr;
1439 }
1440
1441 stdout.write(`${JSON.stringify({
1442 type,
1443 data
1444 })}\n`);
1445 }
1446
1447 _verbose(msg) {
1448 this._dump('verbose', msg);
1449 }
1450
1451 list(type, items, hints) {
1452 this._dump('list', {
1453 type,
1454 items,
1455 hints
1456 });
1457 }
1458
1459 tree(type, trees) {
1460 this._dump('tree', {
1461 type,
1462 trees
1463 });
1464 }
1465
1466 step(current, total, message) {
1467 this._dump('step', {
1468 message,
1469 current,
1470 total
1471 });
1472 }
1473
1474 inspect(value) {
1475 this._dump('inspect', value);
1476 }
1477
1478 footer(showPeakMemory) {
1479 this._dump('finished', this.getTotalTime());
1480 }
1481
1482 log(msg) {
1483 this._dump('log', msg);
1484 }
1485
1486 command(msg) {
1487 this._dump('command', msg);
1488 }
1489
1490 table(head, body) {
1491 this._dump('table', {
1492 head,
1493 body
1494 });
1495 }
1496
1497 success(msg) {
1498 this._dump('success', msg);
1499 }
1500
1501 error(msg) {
1502 this._dump('error', msg, true);
1503 }
1504
1505 warn(msg) {
1506 this._dump('warning', msg, true);
1507 }
1508
1509 info(msg) {
1510 this._dump('info', msg);
1511 }
1512
1513 activitySet(total, workers) {
1514 if (!this.isTTY || this.noProgress) {
1515 return super.activitySet(total, workers);
1516 }
1517
1518 const id = this._activityId++;
1519
1520 this._dump('activitySetStart', {
1521 id,
1522 total,
1523 workers
1524 });
1525
1526 const spinners = [];
1527
1528 for (let i = 0; i < workers; i++) {
1529 let current = 0;
1530 let header = '';
1531 spinners.push({
1532 clear() {},
1533
1534 setPrefix(_current, _header) {
1535 current = _current;
1536 header = _header;
1537 },
1538
1539 tick: msg => {
1540 this._dump('activitySetTick', {
1541 id,
1542 header,
1543 current,
1544 worker: i,
1545 message: msg
1546 });
1547 },
1548
1549 end() {}
1550
1551 });
1552 }
1553
1554 return {
1555 spinners,
1556 end: () => {
1557 this._dump('activitySetEnd', {
1558 id
1559 });
1560 }
1561 };
1562 }
1563
1564 activity() {
1565 return this._activity({});
1566 }
1567
1568 _activity(data) {
1569 if (!this.isTTY || this.noProgress) {
1570 return {
1571 tick() {},
1572
1573 end() {}
1574
1575 };
1576 }
1577
1578 const id = this._activityId++;
1579
1580 this._dump('activityStart', _objectSpread({
1581 id
1582 }, data));
1583
1584 return {
1585 tick: name => {
1586 this._dump('activityTick', {
1587 id,
1588 name
1589 });
1590 },
1591 end: () => {
1592 this._dump('activityEnd', {
1593 id
1594 });
1595 }
1596 };
1597 }
1598
1599 progress(total) {
1600 if (this.noProgress) {
1601 return function () {// noop
1602 };
1603 }
1604
1605 const id = this._progressId++;
1606 let current = 0;
1607
1608 this._dump('progressStart', {
1609 id,
1610 total
1611 });
1612
1613 return () => {
1614 current++;
1615
1616 this._dump('progressTick', {
1617 id,
1618 current
1619 });
1620
1621 if (current === total) {
1622 this._dump('progressFinish', {
1623 id
1624 });
1625 }
1626 };
1627 }
1628
1629}
1630
1631// import os from 'os';
1632// import * as path from 'path';
1633// import userHome from './util/user-home-dir.js';
1634// import {getCacheDir, getConfigDir, getDataDir} from './util/user-dirs.js';
1635const DEPENDENCY_TYPES = ['devDependencies', 'dependencies', 'legacyDependencies']; // export const OWNED_DEPENDENCY_TYPES = ['devDependencies', 'dependencies', 'legacyDependencies'];
1636
1637const RESOLUTIONS = 'resolutions';
1638const MANIFEST_FIELDS = [RESOLUTIONS, ...DEPENDENCY_TYPES];
1639const SUPPORTED_NODE_VERSIONS = '>=8.5.0'; // export const PIKA_REGISTRY = 'https://registry.npmjs.org';
1640// export const NPM_REGISTRY_RE = /https?:\/\/registry\.npmjs\.org/g;
1641// export const PIKA_DOCS = 'https://yarnpkg.com/en/docs/cli/';
1642// export const PIKA_INSTALLER_SH = 'https://yarnpkg.com/install.sh';
1643// export const PIKA_INSTALLER_MSI = 'https://yarnpkg.com/latest.msi';
1644// export const SELF_UPDATE_VERSION_URL = 'https://www.pikapkg.com/downloads/latest-version';
1645// // cache version, bump whenever we make backwards incompatible changes
1646// export const CACHE_VERSION = 3;
1647// // lockfile version, bump whenever we make backwards incompatible changes
1648// export const LOCKFILE_VERSION = 1;
1649// // max amount of network requests to perform concurrently
1650// export const NETWORK_CONCURRENCY = 8;
1651// // HTTP timeout used when downloading packages
1652// export const NETWORK_TIMEOUT = 30 * 1000; // in milliseconds
1653// // max amount of child processes to execute concurrently
1654
1655const CHILD_CONCURRENCY = 5; // export const REQUIRED_PACKAGE_KEYS = ['name', 'version', '_uid'];
1656const NODE_PACKAGE_JSON = 'package.json'; // export const PNP_FILENAME = '.pnp';
1657// export const POSIX_GLOBAL_PREFIX = `${process.env.DESTDIR || ''}/usr/local`;
1658// export const FALLBACK_GLOBAL_PREFIX = path.join(userHome, '.pika');
1659// export const META_FOLDER = '.pika-meta';
1660// export const INTEGRITY_FILENAME = '.pika-integrity';
1661// export const LOCKFILE_FILENAME = 'pika.lock';
1662// export const LEGACY_LOCKFILE_FILENAME = 'yarn.lock';
1663// export const METADATA_FILENAME = '.pika-metadata.json';
1664// export const TARBALL_FILENAME = '.pika-tarball.tgz';
1665// export const CLEAN_FILENAME = '.pikaclean';
1666// export const NPM_LOCK_FILENAME = 'package-lock.json';
1667// export const NPM_SHRINKWRAP_FILENAME = 'npm-shrinkwrap.json';
1668
1669const DEFAULT_INDENT = ' '; // export const SINGLE_INSTANCE_PORT = 31997;
1670// export const SINGLE_INSTANCE_FILENAME = '.pika-single-instance';
1671
1672const ENV_PATH_KEY = getPathKey(process.platform, process.env);
1673function getPathKey(platform, env) {
1674 let pathKey = 'PATH'; // windows calls its path "Path" usually, but this is not guaranteed.
1675
1676 if (platform === 'win32') {
1677 pathKey = 'Path';
1678
1679 for (const key in env) {
1680 if (key.toLowerCase() === 'path') {
1681 pathKey = key;
1682 }
1683 }
1684 }
1685
1686 return pathKey;
1687} // export const VERSION_COLOR_SCHEME: {[key: string]: VersionColor} = {
1688// major: 'red',
1689// premajor: 'red',
1690// minor: 'yellow',
1691// preminor: 'yellow',
1692// patch: 'green',
1693// prepatch: 'green',
1694// prerelease: 'red',
1695// unchanged: 'white',
1696// unknown: 'red',
1697// };
1698// export type VersionColor = 'red' | 'yellow' | 'green' | 'white';
1699// export type RequestHint = 'dev' | 'optional' | 'resolution' | 'workspaces';
1700
1701function nullify(obj) {
1702 if (Array.isArray(obj)) {
1703 for (const item of obj) {
1704 nullify(item);
1705 }
1706 } else if (obj !== null && typeof obj === 'object' || typeof obj === 'function') {
1707 Object.setPrototypeOf(obj, null); // for..in can only be applied to 'object', not 'function'
1708
1709 if (typeof obj === 'object') {
1710 for (const key in obj) {
1711 nullify(obj[key]);
1712 }
1713 }
1714 }
1715
1716 return obj;
1717}
1718
1719const unlink = util.promisify(_rimraf);
1720const glob = util.promisify(_glob);
1721const mkdirp = util.promisify(_mkdirp); //
1722const open = util.promisify(fs.open);
1723const writeFile = util.promisify(fs.writeFile);
1724const readlink = util.promisify(fs.readlink);
1725const realpath = util.promisify(fs.realpath);
1726const readdir = util.promisify(fs.readdir);
1727const rename = util.promisify(fs.rename);
1728const access = util.promisify(fs.access);
1729const stat = util.promisify(fs.stat);
1730const exists = util.promisify(fs.exists);
1731const lstat = util.promisify(fs.lstat);
1732const chmod = util.promisify(fs.chmod);
1733const link = util.promisify(fs.link);
1734const copyFile = util.promisify(fs.copyFile);
1735const readFileBuffer = util.promisify(fs.readFile);
1736const readFile = path => {
1737 return util.promisify(fs.readFile)(path, {
1738 encoding: 'utf-8'
1739 });
1740}; // export {unlink};
1741// export type CopyQueueItem = {
1742// src: string,
1743// dest: string,
1744// type?: string,
1745// onFresh?: () => void,
1746// onDone?: () => void,
1747// };
1748// type CopyQueue = Array<CopyQueueItem>;
1749// type LinkFileAction = {
1750// src: string,
1751// dest: string,
1752// removeDest: boolean,
1753// };
1754// type CopySymlinkAction = {
1755// dest: string,
1756// linkname: string,
1757// };
1758// type CopyActions = {
1759// file: Array<CopyFileAction>,
1760// symlink: Array<CopySymlinkAction>,
1761// link: Array<LinkFileAction>,
1762// };
1763// type CopyOptions = {
1764// onProgress: (dest: string) => void,
1765// onStart: (num: number) => void,
1766// possibleExtraneous: Set<string>,
1767// ignoreBasenames: Array<string>,
1768// artifactFiles: Array<string>,
1769// };
1770// type FailedFolderQuery = {
1771// error: Error,
1772// folder: string,
1773// };
1774// type FolderQueryResult = {
1775// skipped: Array<FailedFolderQuery>,
1776// folder?: string,
1777// };
1778// async function buildActionsForCopy(
1779// queue: CopyQueue,
1780// events: CopyOptions,
1781// possibleExtraneous: Set<string>,
1782// reporter: Reporter,
1783// ): Promise<CopyActions> {
1784// const artifactFiles: Set<string> = new Set(events.artifactFiles || []);
1785// const files: Set<string> = new Set();
1786// // initialise events
1787// for (const item of queue) {
1788// const onDone = item.onDone;
1789// item.onDone = () => {
1790// events.onProgress(item.dest);
1791// if (onDone) {
1792// onDone();
1793// }
1794// };
1795// }
1796// events.onStart(queue.length);
1797// // start building actions
1798// const actions: CopyActions = {
1799// file: [],
1800// symlink: [],
1801// link: [],
1802// };
1803// // custom concurrency logic as we're always executing stacks of CONCURRENT_QUEUE_ITEMS queue items
1804// // at a time due to the requirement to push items onto the queue
1805// while (queue.length) {
1806// const items = queue.splice(0, CONCURRENT_QUEUE_ITEMS);
1807// await Promise.all(items.map(build));
1808// }
1809// // simulate the existence of some files to prevent considering them extraneous
1810// for (const file of artifactFiles) {
1811// if (possibleExtraneous.has(file)) {
1812// reporter.verbose(reporter.lang('verboseFilePhantomExtraneous', file));
1813// possibleExtraneous.delete(file);
1814// }
1815// }
1816// for (const loc of possibleExtraneous) {
1817// if (files.has(loc.toLowerCase())) {
1818// possibleExtraneous.delete(loc);
1819// }
1820// }
1821// return actions;
1822// //
1823// async function build(data: CopyQueueItem): Promise<void> {
1824// const {src, dest, type} = data;
1825// const onFresh = data.onFresh || noop;
1826// const onDone = data.onDone || noop;
1827// // TODO https://github.com/yarnpkg/yarn/issues/3751
1828// // related to bundled dependencies handling
1829// if (files.has(dest.toLowerCase())) {
1830// reporter.verbose(`The case-insensitive file ${dest} shouldn't be copied twice in one bulk copy`);
1831// } else {
1832// files.add(dest.toLowerCase());
1833// }
1834// if (type === 'symlink') {
1835// await mkdirp(path.dirname(dest));
1836// onFresh();
1837// actions.symlink.push({
1838// dest,
1839// linkname: src,
1840// });
1841// onDone();
1842// return;
1843// }
1844// if (events.ignoreBasenames.indexOf(path.basename(src)) >= 0) {
1845// // ignored file
1846// return;
1847// }
1848// const srcStat = await lstat(src);
1849// let srcFiles;
1850// if (srcStat.isDirectory()) {
1851// srcFiles = await readdir(src);
1852// }
1853// let destStat;
1854// try {
1855// // try accessing the destination
1856// destStat = await lstat(dest);
1857// } catch (e) {
1858// // proceed if destination doesn't exist, otherwise error
1859// if (e.code !== 'ENOENT') {
1860// throw e;
1861// }
1862// }
1863// // if destination exists
1864// if (destStat) {
1865// const bothSymlinks = srcStat.isSymbolicLink() && destStat.isSymbolicLink();
1866// const bothFolders = srcStat.isDirectory() && destStat.isDirectory();
1867// const bothFiles = srcStat.isFile() && destStat.isFile();
1868// // EINVAL access errors sometimes happen which shouldn't because node shouldn't be giving
1869// // us modes that aren't valid. investigate this, it's generally safe to proceed.
1870// /* if (srcStat.mode !== destStat.mode) {
1871// try {
1872// await access(dest, srcStat.mode);
1873// } catch (err) {}
1874// } */
1875// if (bothFiles && artifactFiles.has(dest)) {
1876// // this file gets changed during build, likely by a custom install script. Don't bother checking it.
1877// onDone();
1878// reporter.verbose(reporter.lang('verboseFileSkipArtifact', src));
1879// return;
1880// }
1881// if (bothFiles && srcStat.size === destStat.size && fileDatesEqual(srcStat.mtime, destStat.mtime)) {
1882// // we can safely assume this is the same file
1883// onDone();
1884// reporter.verbose(reporter.lang('verboseFileSkip', src, dest, srcStat.size, +srcStat.mtime));
1885// return;
1886// }
1887// if (bothSymlinks) {
1888// const srcReallink = await readlink(src);
1889// if (srcReallink === (await readlink(dest))) {
1890// // if both symlinks are the same then we can continue on
1891// onDone();
1892// reporter.verbose(reporter.lang('verboseFileSkipSymlink', src, dest, srcReallink));
1893// return;
1894// }
1895// }
1896// if (bothFolders) {
1897// // mark files that aren't in this folder as possibly extraneous
1898// const destFiles = await readdir(dest);
1899// invariant(srcFiles, 'src files not initialised');
1900// for (const file of destFiles) {
1901// if (srcFiles.indexOf(file) < 0) {
1902// const loc = path.join(dest, file);
1903// possibleExtraneous.add(loc);
1904// if ((await lstat(loc)).isDirectory()) {
1905// for (const file of await readdir(loc)) {
1906// possibleExtraneous.add(path.join(loc, file));
1907// }
1908// }
1909// }
1910// }
1911// }
1912// }
1913// if (destStat && destStat.isSymbolicLink()) {
1914// await unlink(dest);
1915// destStat = null;
1916// }
1917// if (srcStat.isSymbolicLink()) {
1918// onFresh();
1919// const linkname = await readlink(src);
1920// actions.symlink.push({
1921// dest,
1922// linkname,
1923// });
1924// onDone();
1925// } else if (srcStat.isDirectory()) {
1926// if (!destStat) {
1927// reporter.verbose(reporter.lang('verboseFileFolder', dest));
1928// await mkdirp(dest);
1929// }
1930// const destParts = dest.split(path.sep);
1931// while (destParts.length) {
1932// files.add(destParts.join(path.sep).toLowerCase());
1933// destParts.pop();
1934// }
1935// // push all files to queue
1936// invariant(srcFiles, 'src files not initialised');
1937// let remaining = srcFiles.length;
1938// if (!remaining) {
1939// onDone();
1940// }
1941// for (const file of srcFiles) {
1942// queue.push({
1943// dest: path.join(dest, file),
1944// onFresh,
1945// onDone: () => {
1946// if (--remaining === 0) {
1947// onDone();
1948// }
1949// },
1950// src: path.join(src, file),
1951// });
1952// }
1953// } else if (srcStat.isFile()) {
1954// onFresh();
1955// actions.file.push({
1956// src,
1957// dest,
1958// atime: srcStat.atime,
1959// mtime: srcStat.mtime,
1960// mode: srcStat.mode,
1961// });
1962// onDone();
1963// } else {
1964// throw new Error(`unsure how to copy this: ${src}`);
1965// }
1966// }
1967// }
1968// async function buildActionsForHardlink(
1969// queue: CopyQueue,
1970// events: CopyOptions,
1971// possibleExtraneous: Set<string>,
1972// reporter: Reporter,
1973// ): Promise<CopyActions> {
1974// const artifactFiles: Set<string> = new Set(events.artifactFiles || []);
1975// const files: Set<string> = new Set();
1976// // initialise events
1977// for (const item of queue) {
1978// const onDone = item.onDone || noop;
1979// item.onDone = () => {
1980// events.onProgress(item.dest);
1981// onDone();
1982// };
1983// }
1984// events.onStart(queue.length);
1985// // start building actions
1986// const actions: CopyActions = {
1987// file: [],
1988// symlink: [],
1989// link: [],
1990// };
1991// // custom concurrency logic as we're always executing stacks of CONCURRENT_QUEUE_ITEMS queue items
1992// // at a time due to the requirement to push items onto the queue
1993// while (queue.length) {
1994// const items = queue.splice(0, CONCURRENT_QUEUE_ITEMS);
1995// await Promise.all(items.map(build));
1996// }
1997// // simulate the existence of some files to prevent considering them extraneous
1998// for (const file of artifactFiles) {
1999// if (possibleExtraneous.has(file)) {
2000// reporter.verbose(reporter.lang('verboseFilePhantomExtraneous', file));
2001// possibleExtraneous.delete(file);
2002// }
2003// }
2004// for (const loc of possibleExtraneous) {
2005// if (files.has(loc.toLowerCase())) {
2006// possibleExtraneous.delete(loc);
2007// }
2008// }
2009// return actions;
2010// //
2011// async function build(data: CopyQueueItem): Promise<void> {
2012// const {src, dest} = data;
2013// const onFresh = data.onFresh || noop;
2014// const onDone = data.onDone || noop;
2015// if (files.has(dest.toLowerCase())) {
2016// // Fixes issue https://github.com/yarnpkg/yarn/issues/2734
2017// // When bulk hardlinking we have A -> B structure that we want to hardlink to A1 -> B1,
2018// // package-linker passes that modules A1 and B1 need to be hardlinked,
2019// // the recursive linking algorithm of A1 ends up scheduling files in B1 to be linked twice which will case
2020// // an exception.
2021// onDone();
2022// return;
2023// }
2024// files.add(dest.toLowerCase());
2025// if (events.ignoreBasenames.indexOf(path.basename(src)) >= 0) {
2026// // ignored file
2027// return;
2028// }
2029// const srcStat = await lstat(src);
2030// let srcFiles;
2031// if (srcStat.isDirectory()) {
2032// srcFiles = await readdir(src);
2033// }
2034// const destExists = await exists(dest);
2035// if (destExists) {
2036// const destStat = await lstat(dest);
2037// const bothSymlinks = srcStat.isSymbolicLink() && destStat.isSymbolicLink();
2038// const bothFolders = srcStat.isDirectory() && destStat.isDirectory();
2039// const bothFiles = srcStat.isFile() && destStat.isFile();
2040// if (srcStat.mode !== destStat.mode) {
2041// try {
2042// await access(dest, srcStat.mode);
2043// } catch (err) {
2044// // EINVAL access errors sometimes happen which shouldn't because node shouldn't be giving
2045// // us modes that aren't valid. investigate this, it's generally safe to proceed.
2046// reporter.verbose(err);
2047// }
2048// }
2049// if (bothFiles && artifactFiles.has(dest)) {
2050// // this file gets changed during build, likely by a custom install script. Don't bother checking it.
2051// onDone();
2052// reporter.verbose(reporter.lang('verboseFileSkipArtifact', src));
2053// return;
2054// }
2055// // correct hardlink
2056// if (bothFiles && srcStat.ino !== null && srcStat.ino === destStat.ino) {
2057// onDone();
2058// reporter.verbose(reporter.lang('verboseFileSkip', src, dest, srcStat.ino));
2059// return;
2060// }
2061// if (bothSymlinks) {
2062// const srcReallink = await readlink(src);
2063// if (srcReallink === (await readlink(dest))) {
2064// // if both symlinks are the same then we can continue on
2065// onDone();
2066// reporter.verbose(reporter.lang('verboseFileSkipSymlink', src, dest, srcReallink));
2067// return;
2068// }
2069// }
2070// if (bothFolders) {
2071// // mark files that aren't in this folder as possibly extraneous
2072// const destFiles = await readdir(dest);
2073// invariant(srcFiles, 'src files not initialised');
2074// for (const file of destFiles) {
2075// if (srcFiles.indexOf(file) < 0) {
2076// const loc = path.join(dest, file);
2077// possibleExtraneous.add(loc);
2078// if ((await lstat(loc)).isDirectory()) {
2079// for (const file of await readdir(loc)) {
2080// possibleExtraneous.add(path.join(loc, file));
2081// }
2082// }
2083// }
2084// }
2085// }
2086// }
2087// if (srcStat.isSymbolicLink()) {
2088// onFresh();
2089// const linkname = await readlink(src);
2090// actions.symlink.push({
2091// dest,
2092// linkname,
2093// });
2094// onDone();
2095// } else if (srcStat.isDirectory()) {
2096// reporter.verbose(reporter.lang('verboseFileFolder', dest));
2097// await mkdirp(dest);
2098// const destParts = dest.split(path.sep);
2099// while (destParts.length) {
2100// files.add(destParts.join(path.sep).toLowerCase());
2101// destParts.pop();
2102// }
2103// // push all files to queue
2104// invariant(srcFiles, 'src files not initialised');
2105// let remaining = srcFiles.length;
2106// if (!remaining) {
2107// onDone();
2108// }
2109// for (const file of srcFiles) {
2110// queue.push({
2111// onFresh,
2112// src: path.join(src, file),
2113// dest: path.join(dest, file),
2114// onDone: () => {
2115// if (--remaining === 0) {
2116// onDone();
2117// }
2118// },
2119// });
2120// }
2121// } else if (srcStat.isFile()) {
2122// onFresh();
2123// actions.link.push({
2124// src,
2125// dest,
2126// removeDest: destExists,
2127// });
2128// onDone();
2129// } else {
2130// throw new Error(`unsure how to copy this: ${src}`);
2131// }
2132// }
2133// }
2134// export function copy(src: string, dest: string, reporter: Reporter): Promise<void> {
2135// return copyBulk([{src, dest}], reporter);
2136// }
2137// export async function copyBulk(
2138// queue: CopyQueue,
2139// reporter: Reporter,
2140// _events?: {
2141// onProgress?: (dest: string) => void,
2142// onStart?: (num: number) => void,
2143// possibleExtraneous: Set<string>,
2144// ignoreBasenames?: Array<string>,
2145// artifactFiles?: Array<string>,
2146// },
2147// ): Promise<void> {
2148// const events: CopyOptions = {
2149// onStart: (_events && _events.onStart) || noop,
2150// onProgress: (_events && _events.onProgress) || noop,
2151// possibleExtraneous: _events ? _events.possibleExtraneous : new Set(),
2152// ignoreBasenames: (_events && _events.ignoreBasenames) || [],
2153// artifactFiles: (_events && _events.artifactFiles) || [],
2154// };
2155// const actions: CopyActions = await buildActionsForCopy(queue, events, events.possibleExtraneous, reporter);
2156// events.onStart(actions.file.length + actions.symlink.length + actions.link.length);
2157// const fileActions: Array<CopyFileAction> = actions.file;
2158// const currentlyWriting: Map<string, Promise<void>> = new Map();
2159// await promise.queue(
2160// fileActions,
2161// async (data: CopyFileAction): Promise<void> => {
2162// let writePromise;
2163// while ((writePromise = currentlyWriting.get(data.dest))) {
2164// await writePromise;
2165// }
2166// reporter.verbose(reporter.lang('verboseFileCopy', data.src, data.dest));
2167// const copier = copyFile(data, () => currentlyWriting.delete(data.dest));
2168// currentlyWriting.set(data.dest, copier);
2169// events.onProgress(data.dest);
2170// return copier;
2171// },
2172// CONCURRENT_QUEUE_ITEMS,
2173// );
2174// // we need to copy symlinks last as they could reference files we were copying
2175// const symlinkActions: Array<CopySymlinkAction> = actions.symlink;
2176// await promise.queue(symlinkActions, (data): Promise<void> => {
2177// const linkname = path.resolve(path.dirname(data.dest), data.linkname);
2178// reporter.verbose(reporter.lang('verboseFileSymlink', data.dest, linkname));
2179// return symlink(linkname, data.dest);
2180// });
2181// }
2182// export async function hardlinkBulk(
2183// queue: CopyQueue,
2184// reporter: Reporter,
2185// _events?: {
2186// onProgress?: (dest: string) => void,
2187// onStart?: (num: number) => void,
2188// possibleExtraneous: Set<string>,
2189// artifactFiles?: Array<string>,
2190// },
2191// ): Promise<void> {
2192// const events: CopyOptions = {
2193// onStart: (_events && _events.onStart) || noop,
2194// onProgress: (_events && _events.onProgress) || noop,
2195// possibleExtraneous: _events ? _events.possibleExtraneous : new Set(),
2196// artifactFiles: (_events && _events.artifactFiles) || [],
2197// ignoreBasenames: [],
2198// };
2199// const actions: CopyActions = await buildActionsForHardlink(queue, events, events.possibleExtraneous, reporter);
2200// events.onStart(actions.file.length + actions.symlink.length + actions.link.length);
2201// const fileActions: Array<LinkFileAction> = actions.link;
2202// await promise.queue(
2203// fileActions,
2204// async (data): Promise<void> => {
2205// reporter.verbose(reporter.lang('verboseFileLink', data.src, data.dest));
2206// if (data.removeDest) {
2207// await unlink(data.dest);
2208// }
2209// await link(data.src, data.dest);
2210// },
2211// CONCURRENT_QUEUE_ITEMS,
2212// );
2213// // we need to copy symlinks last as they could reference files we were copying
2214// const symlinkActions: Array<CopySymlinkAction> = actions.symlink;
2215// await promise.queue(symlinkActions, (data): Promise<void> => {
2216// const linkname = path.resolve(path.dirname(data.dest), data.linkname);
2217// reporter.verbose(reporter.lang('verboseFileSymlink', data.dest, linkname));
2218// return symlink(linkname, data.dest);
2219// });
2220// }
2221// function _readFile(loc: string, encoding: string): Promise<any> {
2222// return new Promise((resolve, reject) => {
2223// fs.readFile(loc, encoding, function(err, content) {
2224// if (err) {
2225// reject(err);
2226// } else {
2227// resolve(content);
2228// }
2229// });
2230// });
2231// }
2232// export function readFile(loc: string): Promise<string> {
2233// return _readFile(loc, 'utf8').then(normalizeOS);
2234// }
2235// export function readFileRaw(loc: string): Promise<Buffer> {
2236// return _readFile(loc, 'binary');
2237// }
2238// export async function readFileAny(files: Array<string>): Promise<string | null> {
2239// for (const file of files) {
2240// if (await exists(file)) {
2241// return readFile(file);
2242// }
2243// }
2244// return null;
2245// }
2246
2247async function readJson(loc) {
2248 return (await readJsonAndFile(loc)).object;
2249}
2250async function readJsonAndFile(loc) {
2251 const file = await readFile(loc);
2252
2253 try {
2254 return {
2255 object: nullify(JSON.parse(stripBOM(file))),
2256 content: file
2257 };
2258 } catch (err) {
2259 err.message = `${loc}: ${err.message}`;
2260 throw err;
2261 }
2262}
2263// const stat = await lstat(loc);
2264// const {size, blksize: blockSize} = stat;
2265// return Math.ceil(size / blockSize) * blockSize;
2266// }
2267// export function normalizeOS(body: string): string {
2268// return body.replace(/\r\n/g, '\n');
2269// }
2270
2271const cr = '\r'.charCodeAt(0);
2272const lf = '\n'.charCodeAt(0);
2273
2274async function getEolFromFile(path) {
2275 if (!(await exists(path))) {
2276 return undefined;
2277 }
2278
2279 const buffer = await readFileBuffer(path);
2280
2281 for (let i = 0; i < buffer.length; ++i) {
2282 if (buffer[i] === cr) {
2283 return '\r\n';
2284 }
2285
2286 if (buffer[i] === lf) {
2287 return '\n';
2288 }
2289 }
2290
2291 return undefined;
2292}
2293
2294async function writeFilePreservingEol(path, data) {
2295 const eol = (await getEolFromFile(path)) || os.EOL;
2296
2297 if (eol !== '\n') {
2298 data = data.replace(/\n/g, eol);
2299 }
2300
2301 await writeFile(path, data);
2302} // export async function hardlinksWork(dir: string): Promise<boolean> {
2303// const filename = 'test-file' + Math.random();
2304// const file = path.join(dir, filename);
2305// const fileLink = path.join(dir, filename + '-link');
2306// try {
2307// await writeFile(file, 'test');
2308// await link(file, fileLink);
2309// } catch (err) {
2310// return false;
2311// } finally {
2312// await unlink(file);
2313// await unlink(fileLink);
2314// }
2315// return true;
2316// }
2317// // not a strict polyfill for Node's fs.mkdtemp
2318// export async function makeTempDir(prefix?: string): Promise<string> {
2319// const dir = path.join(os.tmpdir(), `pika-${prefix || ''}-${Date.now()}-${Math.random()}`);
2320// await unlink(dir);
2321// await mkdirp(dir);
2322// return dir;
2323// }
2324// export async function readFirstAvailableStream(paths: Iterable<string>): Promise<?ReadStream> {
2325// for (const path of paths) {
2326// try {
2327// const fd = await open(path, 'r');
2328// return fs.createReadStream(path, {fd});
2329// } catch (err) {
2330// // Try the next one
2331// }
2332// }
2333// return null;
2334// }
2335// export async function getFirstSuitableFolder(
2336// paths: Iterable<string>,
2337// mode: number = constants.W_OK | constants.X_OK, // eslint-disable-line no-bitwise
2338// ): Promise<FolderQueryResult> {
2339// const result: FolderQueryResult = {
2340// skipped: [],
2341// folder: null,
2342// };
2343// for (const folder of paths) {
2344// try {
2345// await mkdirp(folder);
2346// await access(folder, mode);
2347// result.folder = folder;
2348// return result;
2349// } catch (error) {
2350// result.skipped.push({
2351// error,
2352// folder,
2353// });
2354// }
2355// }
2356// return result;
2357// }
2358
2359async function generatePublishManifest(manifest, config, _dists) {
2360 const {
2361 name,
2362 version,
2363 description,
2364 keywords,
2365 homepage,
2366 bugs,
2367 bin,
2368 license,
2369 authors,
2370 contributors,
2371 man,
2372 sideEffects,
2373 repository,
2374 dependencies,
2375 peerDependencies,
2376 devDependencies,
2377 bundledDependencies,
2378 optionalDependencies,
2379 engines,
2380 enginesStrict,
2381 private: priv,
2382 publishConfig
2383 } = manifest;
2384 const newManifest = {
2385 name,
2386 description,
2387 version,
2388 license,
2389 bin,
2390 files: ['dist-*/', 'bin/'],
2391 pika: true,
2392 sideEffects: sideEffects || false,
2393 keywords,
2394 homepage,
2395 bugs,
2396 authors,
2397 contributors,
2398 man,
2399 repository,
2400 dependencies: dependencies || {},
2401 peerDependencies,
2402 devDependencies,
2403 bundledDependencies,
2404 optionalDependencies,
2405 engines,
2406 enginesStrict,
2407 private: priv,
2408 publishConfig
2409 };
2410 const dists = _dists || (await config.getDistributions());
2411
2412 for (const [runner, options] of dists) {
2413 if (runner.manifest) {
2414 await runner.manifest(newManifest, {
2415 cwd: config.cwd,
2416 isFull: true,
2417 manifest,
2418 options
2419 });
2420 }
2421 }
2422
2423 newManifest.pika = true;
2424 return newManifest;
2425}
2426function generatePrettyManifest(manifest) {
2427 return JSON.stringify(_objectSpread({}, manifest, {
2428 dependencies: Object.keys(manifest.dependencies).length === 0 ? {} : '{ ... }'
2429 }), null, 2);
2430}
2431
2432function setFlags(commander) {
2433 commander.description('Prepares your package out directory (pkg/) for publishing.');
2434 commander.usage('build [flags]');
2435 commander.option('-O, --out <path>', 'Where to write to');
2436 commander.option('--force', 'Whether to ignore failed build plugins and continue through errors.');
2437 commander.option('-P, --publish', 'Whether to include publish-only builds like unpkg & types.');
2438}
2439function hasWrapper(commander, args) {
2440 return true;
2441}
2442class Build {
2443 constructor(flags, config, reporter) {
2444 this.flags = flags;
2445 this.config = config;
2446 this.reporter = reporter;
2447 this.totalNum = 0;
2448 this.out = path.resolve(config.cwd, flags.out || 'pkg/');
2449
2450 if (this.out === this.config.cwd) {
2451 throw new Error('On publish, you cannot write to cwd because a package.json is created');
2452 }
2453 }
2454
2455 async cleanup() {
2456 const {
2457 out
2458 } = this;
2459 await unlink(path.join(out, '*'));
2460 }
2461
2462 async init(isFull) {
2463 const {
2464 config,
2465 out,
2466 reporter,
2467 flags
2468 } = this;
2469 const {
2470 cwd
2471 } = config;
2472 const outPretty = path.relative(cwd, out) + path.sep;
2473 const manifest = await config.manifest;
2474 const distRunners = await config.getDistributions();
2475 const builderConfig = {
2476 out,
2477 cwd,
2478 reporter: {
2479 info: msg => reporter.log(chalk.dim(` » ${msg}`)),
2480 warning: msg => reporter.log(chalk.yellow(` » ${msg}`)),
2481 success: msg => reporter.log(chalk.green(` » ${msg}`)),
2482 created: (filename, entrypoint) => reporter.log(` 📝 ${chalk.green(path.relative(cwd, filename))} ${entrypoint ? chalk.dim(`[${entrypoint}]`) : ''}`)
2483 },
2484 isFull,
2485 manifest,
2486 src: {
2487 loc: path.join(out, 'dist-src'),
2488 entrypoint: path.join(out, 'dist-src', 'index.js'),
2489 // TODO: Deprecated, remove
2490 options: {},
2491 // TODO: Deprecated, remove
2492 files: await (async () => {
2493 const ignoreSet = new Set([]);
2494 ignoreSet.add('**/*/README.md');
2495 const files = await glob(`src/**/*`, {
2496 cwd,
2497 nodir: true,
2498 absolute: true,
2499 ignore: Array.from(ignoreSet).map(g => path.join('src', g))
2500 });
2501 return files.filter(fileAbs => !fileAbs.endsWith('.d.ts'));
2502 })()
2503 }
2504 };
2505 const steps = [];
2506 steps.push(async (curr, total) => {
2507 this.reporter.step(curr, total, 'Validating source');
2508
2509 for (const [runner, options] of distRunners) {
2510 if (runner.validate) {
2511 const result = await runner.validate(_objectSpread({}, builderConfig, {
2512 options
2513 }));
2514
2515 if (result instanceof Error) {
2516 throw result;
2517 }
2518 }
2519 }
2520 });
2521 steps.push(async (curr, total) => {
2522 this.reporter.step(curr, total, `Preparing pipeline`);
2523 await this.cleanup();
2524 reporter.log(` ❇️ ${chalk.green(outPretty)}`);
2525
2526 for (const [runner, options] of distRunners) {
2527 await (runner.beforeBuild && runner.beforeBuild(_objectSpread({}, builderConfig, {
2528 options
2529 })));
2530 }
2531 });
2532
2533 if (distRunners.length === 0) {
2534 steps.push(async (curr, total) => {
2535 this.reporter.step(curr, total, `Pipeline is empty! See ${chalk.underline('https://github.com/pikapkg/pack')} for help getting started`);
2536 });
2537 }
2538
2539 for (const [runner, options] of distRunners) {
2540 steps.push(async (curr, total) => {
2541 this.reporter.step(curr, total, `Running ${chalk.bold(runner.name)}`); // return Promise.resolve(
2542
2543 try {
2544 await (runner.beforeJob && runner.beforeJob(_objectSpread({}, builderConfig, {
2545 options
2546 })));
2547 await (runner.build && runner.build(_objectSpread({}, builderConfig, {
2548 options
2549 })));
2550 await (runner.afterJob && runner.afterJob(_objectSpread({}, builderConfig, {
2551 options
2552 })));
2553 } catch (err) {
2554 if (flags.force) {
2555 console.log(' ❗️ ', chalk.red(err.message), chalk.dim('--force, continuing...'));
2556 } else {
2557 throw err;
2558 }
2559 } // ).catch(err => {
2560 // log(chalk.red(err.message));
2561 // reporter.log(
2562 // reporter.lang("distFailed", runner.name, err.code, err.message),
2563 // { force: true }
2564 // );
2565 // if (err.forceExit === true) {
2566 // reporter.log(reporter.lang("distExiting"));
2567 // throw err;
2568 // return;
2569 // }
2570 // reporter.log(reporter.lang("distContinuing"));
2571 // });
2572
2573 });
2574 }
2575
2576 steps.push(async (curr, total) => {
2577 this.reporter.step(curr, total, `Finalizing package`);
2578
2579 for (const [runner, options] of distRunners) {
2580 await (runner.afterBuild && runner.afterBuild(_objectSpread({}, builderConfig, {
2581 options
2582 })));
2583 }
2584
2585 if (await exists(path.join(cwd, 'CHANGELOG'))) {
2586 copyFile(path.join(cwd, 'CHANGELOG'), path.join(out, 'CHANGELOG'));
2587 reporter.log(chalk.dim(` » copying CHANGELOG...`));
2588 } else if (await exists(path.join(cwd, 'CHANGELOG.md'))) {
2589 copyFile(path.join(cwd, 'CHANGELOG.md'), path.join(out, 'CHANGELOG.md'));
2590 reporter.log(chalk.dim(` » copying CHANGELOG.md...`));
2591 }
2592
2593 if (await exists(path.join(cwd, 'LICENSE'))) {
2594 copyFile(path.join(cwd, 'LICENSE'), path.join(out, 'LICENSE'));
2595 reporter.log(chalk.dim(` » copying LICENSE...`));
2596 } else if (await exists(path.join(cwd, 'LICENSE.md'))) {
2597 copyFile(path.join(cwd, 'LICENSE.md'), path.join(out, 'LICENSE.md'));
2598 reporter.log(chalk.dim(` » copying LICENSE.md...`));
2599 }
2600
2601 if (await exists(path.join(cwd, 'README'))) {
2602 copyFile(path.join(cwd, 'README'), path.join(out, 'README'));
2603 reporter.log(chalk.dim(` » copying README...`));
2604 } else if (await exists(path.join(cwd, 'README.md'))) {
2605 copyFile(path.join(cwd, 'README.md'), path.join(out, 'README.md'));
2606 reporter.log(chalk.dim(` » copying README.md...`));
2607 }
2608
2609 const publishManifest = await generatePublishManifest(config._manifest, config, distRunners);
2610
2611 if (out === cwd) {
2612 reporter.log(`NEW MANIFEST:\n\n`);
2613 reporter.log(generatePrettyManifest(publishManifest));
2614 reporter.log(`\n\n`);
2615 } else {
2616 await writeFilePreservingEol(path.join(out, 'package.json'), JSON.stringify(publishManifest, null, DEFAULT_INDENT) + '\n');
2617 reporter.log(` 📝 ` + chalk.green(outPretty + 'package.json'));
2618 }
2619
2620 reporter.log(` 📦 ` + chalk.green(outPretty));
2621 });
2622 let currentStep = 0;
2623
2624 for (const step of steps) {
2625 await step(++currentStep, steps.length);
2626 }
2627 }
2628
2629}
2630async function run(config, reporter, flags, args) {
2631 const isProduction = flags.publish;
2632 const builder = new Build(flags, config, reporter);
2633 await builder.init(isProduction);
2634}
2635
2636var build = /*#__PURE__*/Object.freeze({
2637 setFlags: setFlags,
2638 hasWrapper: hasWrapper,
2639 Build: Build,
2640 run: run
2641});
2642
2643class BlockingQueue {
2644 constructor(alias, maxConcurrency = Infinity) {
2645 this.concurrencyQueue = [];
2646 this.maxConcurrency = maxConcurrency;
2647 this.runningCount = 0;
2648 this.warnedStuck = false;
2649 this.alias = alias;
2650 this.first = true;
2651 this.running = nullify() || {};
2652 this.queue = nullify() || {};
2653 this.stuckTick = this.stuckTick.bind(this);
2654 }
2655
2656 stillActive() {
2657 if (this.stuckTimer) {
2658 clearTimeout(this.stuckTimer);
2659 }
2660
2661 this.stuckTimer = setTimeout(this.stuckTick, 5000); // We need to check the existence of unref because of https://github.com/facebook/jest/issues/4559
2662 // $FlowFixMe: Node's setInterval returns a Timeout, not a Number
2663
2664 this.stuckTimer.unref && this.stuckTimer.unref();
2665 }
2666
2667 stuckTick() {
2668 if (this.runningCount === 1) {
2669 this.warnedStuck = true;
2670 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]}`);
2671 }
2672 }
2673
2674 push(key, factory) {
2675 if (this.first) {
2676 this.first = false;
2677 } else {
2678 this.stillActive();
2679 }
2680
2681 return new Promise((resolve, reject) => {
2682 // we're already running so push ourselves to the queue
2683 const queue = this.queue[key] = this.queue[key] || [];
2684 queue.push({
2685 factory,
2686 resolve,
2687 reject
2688 });
2689
2690 if (!this.running[key]) {
2691 this.shift(key);
2692 }
2693 });
2694 }
2695
2696 shift(key) {
2697 if (this.running[key]) {
2698 delete this.running[key];
2699 this.runningCount--;
2700
2701 if (this.stuckTimer) {
2702 clearTimeout(this.stuckTimer);
2703 this.stuckTimer = null;
2704 }
2705
2706 if (this.warnedStuck) {
2707 this.warnedStuck = false;
2708 console.log(`${JSON.stringify(this.alias)} blocking queue finally resolved. Nothing to worry about.`);
2709 }
2710 }
2711
2712 const queue = this.queue[key];
2713
2714 if (!queue) {
2715 return;
2716 }
2717
2718 const {
2719 resolve,
2720 reject,
2721 factory
2722 } = queue.shift();
2723
2724 if (!queue.length) {
2725 delete this.queue[key];
2726 }
2727
2728 const next = () => {
2729 this.shift(key);
2730 this.shiftConcurrencyQueue();
2731 };
2732
2733 const run = () => {
2734 this.running[key] = true;
2735 this.runningCount++;
2736 factory().then(function (val) {
2737 resolve(val);
2738 next();
2739 return null;
2740 }).catch(function (err) {
2741 reject(err);
2742 next();
2743 });
2744 };
2745
2746 this.maybePushConcurrencyQueue(run);
2747 }
2748
2749 maybePushConcurrencyQueue(run) {
2750 if (this.runningCount < this.maxConcurrency) {
2751 run();
2752 } else {
2753 this.concurrencyQueue.push(run);
2754 }
2755 }
2756
2757 shiftConcurrencyQueue() {
2758 if (this.runningCount < this.maxConcurrency) {
2759 const fn = this.concurrencyQueue.shift();
2760
2761 if (fn) {
2762 fn();
2763 }
2764 }
2765 }
2766
2767}
2768
2769class ProcessSpawnError extends types.MessageError {
2770 constructor(msg, code, process) {
2771 super(msg);
2772 this.code = code;
2773 this.process = process;
2774 }
2775
2776}
2777class ProcessTermError extends types.MessageError {}
2778
2779/* global child_process$spawnOpts */
2780const queue = new BlockingQueue('child', CHILD_CONCURRENCY); // TODO: this uid check is kinda whack
2781
2782let uid = 0;
2783const spawnedProcesses = {};
2784function forwardSignalToSpawnedProcesses(signal) {
2785 for (const key of Object.keys(spawnedProcesses)) {
2786 spawnedProcesses[key].kill(signal);
2787 }
2788}
2789function spawn(program, args, opts = {}, onData) {
2790 const key = opts.cwd || String(++uid);
2791 return queue.push(key, () => new Promise((resolve, reject) => {
2792 const proc = child_process.spawn(program, args, opts);
2793
2794 spawnedProcesses[key] = proc;
2795 let processingDone = false;
2796 let processClosed = false;
2797 let err = null;
2798 let stdout = '';
2799 proc.on('error', err => {
2800 if (err.code === 'ENOENT') {
2801 reject(new ProcessSpawnError(`Couldn't find the binary ${program}`, err.code, program));
2802 } else {
2803 reject(err);
2804 }
2805 });
2806
2807 function updateStdout(chunk) {
2808 stdout += chunk;
2809
2810 if (onData) {
2811 onData(chunk);
2812 }
2813 }
2814
2815 function finish() {
2816 delete spawnedProcesses[key];
2817
2818 if (err) {
2819 reject(err);
2820 } else {
2821 resolve(stdout.trim());
2822 }
2823 }
2824
2825 if (typeof opts.process === 'function') {
2826 opts.process(proc, updateStdout, reject, function () {
2827 if (processClosed) {
2828 finish();
2829 } else {
2830 processingDone = true;
2831 }
2832 });
2833 } else {
2834 if (proc.stderr) {
2835 proc.stderr.on('data', updateStdout);
2836 }
2837
2838 if (proc.stdout) {
2839 proc.stdout.on('data', updateStdout);
2840 }
2841
2842 processingDone = true;
2843 }
2844
2845 proc.on('close', (code, signal) => {
2846 if (signal || code >= 1) {
2847 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'));
2848 err.EXIT_SIGNAL = signal;
2849 err.EXIT_CODE = code;
2850 }
2851
2852 if (processingDone || err) {
2853 finish();
2854 } else {
2855 processClosed = true;
2856 }
2857 });
2858 }));
2859}
2860
2861function fixCmdWinSlashes(cmd) {
2862 function findQuotes(quoteSymbol) {
2863 const quotes = [];
2864
2865 const addQuote = (_, index) => {
2866 quotes.push({
2867 from: index,
2868 to: index + _.length
2869 });
2870 return _;
2871 };
2872
2873 const regEx = new RegExp(quoteSymbol + '.*' + quoteSymbol);
2874 cmd.replace(regEx, addQuote);
2875 return quotes;
2876 }
2877
2878 const quotes = findQuotes('"').concat(findQuotes("'"));
2879
2880 function isInsideQuotes(index) {
2881 return quotes.reduce((result, quote) => {
2882 return result || quote.from <= index && index <= quote.to;
2883 }, false);
2884 }
2885
2886 const cmdPrePattern = '((?:^|&&|&|\\|\\||\\|)\\s*)';
2887 const cmdPattern = '(".*?"|\'.*?\'|\\S*)';
2888 const regExp = new RegExp(`${cmdPrePattern}${cmdPattern}`, 'g');
2889 return cmd.replace(regExp, (whole, pre, cmd, index) => {
2890 if ((pre[0] === '&' || pre[0] === '|') && isInsideQuotes(index)) {
2891 return whole;
2892 }
2893
2894 return pre + cmd.replace(/\//g, '\\');
2895 });
2896}
2897
2898// // We treat these configs as internal, thus not expose them to process.env.
2899// // This helps us avoid some gyp issues when building native modules.
2900// // See https://github.com/yarnpkg/yarn/issues/2286.
2901// const IGNORE_CONFIG_KEYS = ['lastUpdateCheck'];
2902// async function getPnpParameters(config: Config): Promise<Array<string>> {
2903// if (await fs.exists(`${config.lockfileFolder}/${constants.PNP_FILENAME}`)) {
2904// return ['-r', `${config.lockfileFolder}/${constants.PNP_FILENAME}`];
2905// } else {
2906// return [];
2907// }
2908// }
2909// let wrappersFolder = null;
2910// export async function getWrappersFolder(config: Config): Promise<string> {
2911// if (wrappersFolder) {
2912// return wrappersFolder;
2913// }
2914// wrappersFolder = await fs.makeTempDir();
2915// await makePortableProxyScript(process.execPath, wrappersFolder, {
2916// proxyBasename: 'node',
2917// prependArguments: [...(await getPnpParameters(config))],
2918// });
2919// await makePortableProxyScript(process.execPath, wrappersFolder, {
2920// proxyBasename: 'pika',
2921// prependArguments: [process.argv[1]],
2922// });
2923// return wrappersFolder;
2924// }
2925// const INVALID_CHAR_REGEX = /\W/g;
2926
2927async function makeEnv() {
2928 // stage: string,
2929 // cwd: string,
2930 // config: Config,
2931 const env = _objectSpread({
2932 NODE: process.execPath,
2933 INIT_CWD: process.cwd()
2934 }, process.env);
2935
2936 return env;
2937} // // Merge in the `env` object specified in .pikarc
2938// const customEnv = config.getOption('env');
2939// if (customEnv && typeof customEnv === 'object') {
2940// Object.assign(env, customEnv);
2941// }
2942// env.npm_lifecycle_event = stage;
2943// env.npm_node_execpath = env.NODE;
2944// env.npm_execpath = env.npm_execpath || (process.mainModule && process.mainModule.filename);
2945// // Set the env to production for npm compat if production mode.
2946// // https://github.com/npm/npm/blob/30d75e738b9cb7a6a3f9b50e971adcbe63458ed3/lib/utils/lifecycle.js#L336
2947// if (config.production) {
2948// env.NODE_ENV = 'production';
2949// }
2950// // Note: npm_config_argv environment variable contains output of nopt - command-line
2951// // parser used by npm. Since we use other parser, we just roughly emulate it's output. (See: #684)
2952// env.npm_config_argv = JSON.stringify({
2953// remain: [],
2954// cooked: config.commandName === 'run' ? [config.commandName, stage] : [config.commandName],
2955// original: process.argv.slice(2),
2956// });
2957// const manifest = await config.maybeReadManifest(cwd);
2958// if (manifest) {
2959// if (manifest.scripts && Object.prototype.hasOwnProperty.call(manifest.scripts, stage)) {
2960// env.npm_lifecycle_script = manifest.scripts[stage];
2961// }
2962// // add npm_package_*
2963// const queue = [['', manifest]];
2964// while (queue.length) {
2965// const [key, val] = queue.pop();
2966// if (typeof val === 'object') {
2967// for (const subKey in val) {
2968// const fullKey = [key, subKey].filter(Boolean).join('_');
2969// if (fullKey && fullKey[0] !== '_' && !IGNORE_MANIFEST_KEYS.has(fullKey)) {
2970// queue.push([fullKey, val[subKey]]);
2971// }
2972// }
2973// } else {
2974// let cleanVal = String(val);
2975// if (cleanVal.indexOf('\n') >= 0) {
2976// cleanVal = JSON.stringify(cleanVal);
2977// }
2978// //replacing invalid chars with underscore
2979// const cleanKey = key.replace(INVALID_CHAR_REGEX, '_');
2980// env[`npm_package_${cleanKey}`] = cleanVal;
2981// }
2982// }
2983// }
2984// // add npm_config_* and npm_package_config_* from pika config
2985// const keys: Set<string> = new Set([
2986// ...Object.keys(config.registries.pika.config),
2987// ...Object.keys(config.registries.npm.config),
2988// ]);
2989// const cleaned = Array.from(keys)
2990// .filter(key => !key.match(/:_/) && IGNORE_CONFIG_KEYS.indexOf(key) === -1)
2991// .map(key => {
2992// let val = config.getOption(key);
2993// if (!val) {
2994// val = '';
2995// } else if (typeof val === 'number') {
2996// val = '' + val;
2997// } else if (typeof val !== 'string') {
2998// val = JSON.stringify(val);
2999// }
3000// if (val.indexOf('\n') >= 0) {
3001// val = JSON.stringify(val);
3002// }
3003// return [key, val];
3004// });
3005// // add npm_config_*
3006// for (const [key, val] of cleaned) {
3007// const cleanKey = key.replace(/^_+/, '');
3008// const envKey = `npm_config_${cleanKey}`.replace(INVALID_CHAR_REGEX, '_');
3009// env[envKey] = val;
3010// }
3011// // add npm_package_config_*
3012// if (manifest && manifest.name) {
3013// const packageConfigPrefix = `${manifest.name}:`;
3014// for (const [key, val] of cleaned) {
3015// if (key.indexOf(packageConfigPrefix) !== 0) {
3016// continue;
3017// }
3018// const cleanKey = key.replace(/^_+/, '').replace(packageConfigPrefix, '');
3019// const envKey = `npm_package_config_${cleanKey}`.replace(INVALID_CHAR_REGEX, '_');
3020// env[envKey] = val;
3021// }
3022// }
3023// // split up the path
3024// const envPath = env[constants.ENV_PATH_KEY];
3025// const pathParts = envPath ? envPath.split(path.delimiter) : [];
3026// // Include the directory that contains node so that we can guarantee that the scripts
3027// // will always run with the exact same Node release than the one use to run Pika
3028// const execBin = path.dirname(process.execPath);
3029// if (pathParts.indexOf(execBin) === -1) {
3030// pathParts.unshift(execBin);
3031// }
3032// // Include node-gyp version that was bundled with the current Node.js version,
3033// // if available.
3034// pathParts.unshift(path.join(path.dirname(process.execPath), 'node_modules', 'npm', 'bin', 'node-gyp-bin'));
3035// pathParts.unshift(
3036// path.join(path.dirname(process.execPath), '..', 'lib', 'node_modules', 'npm', 'bin', 'node-gyp-bin'),
3037// );
3038// // Include node-gyp version from homebrew managed npm, if available.
3039// pathParts.unshift(
3040// path.join(path.dirname(process.execPath), '..', 'libexec', 'lib', 'node_modules', 'npm', 'bin', 'node-gyp-bin'),
3041// );
3042// // Add global bin folder if it is not present already, as some packages depend
3043// // on a globally-installed version of node-gyp.
3044// const globalBin = await getGlobalBinFolder(config, {});
3045// if (pathParts.indexOf(globalBin) === -1) {
3046// pathParts.unshift(globalBin);
3047// }
3048// // Add node_modules .bin folders to the PATH
3049// for (const registry of Object.keys(registries)) {
3050// const binFolder = path.join(config.registries[registry].folder, '.bin');
3051// if (config.workspacesEnabled && config.workspaceRootFolder) {
3052// pathParts.unshift(path.join(config.workspaceRootFolder, binFolder));
3053// }
3054// pathParts.unshift(path.join(config.linkFolder, binFolder));
3055// pathParts.unshift(path.join(cwd, binFolder));
3056// if (config.modulesFolder) {
3057// pathParts.unshift(path.join(config.modulesFolder, '.bin'));
3058// }
3059// }
3060// if (await fs.exists(`${config.lockfileFolder}/${constants.PNP_FILENAME}`)) {
3061// // TODO: Fix. import()? Do we even like that it does this?
3062// throw new Error("pnp temporarily not supported");
3063// const pnpApi = {}; //dynamicRequire(`${config.lockfileFolder}/${constants.PNP_FILENAME}`);
3064// const packageLocator = pnpApi.findPackageLocator(`${config.cwd}/`);
3065// const packageInformation = pnpApi.getPackageInformation(packageLocator);
3066// for (const [name, reference] of packageInformation.packageDependencies.entries()) {
3067// const dependencyInformation = pnpApi.getPackageInformation({name, reference});
3068// if (!dependencyInformation || !dependencyInformation.packageLocation) {
3069// continue;
3070// }
3071// pathParts.unshift(`${dependencyInformation.packageLocation}/.bin`);
3072// }
3073// }
3074// pathParts.unshift(await getWrappersFolder(config));
3075// // join path back together
3076// env[constants.ENV_PATH_KEY] = pathParts.join(path.delimiter);
3077// return env;
3078// }
3079
3080async function executeLifecycleScript({
3081 // config,
3082 cwd,
3083 cmd,
3084 args,
3085 isInteractive,
3086 onProgress,
3087 customShell
3088}) {
3089 const env = await makeEnv(); // await checkForGypIfNeeded(config, cmd, env[constants.ENV_PATH_KEY].split(path.delimiter));
3090
3091 if (process.platform === 'win32' && (!customShell || customShell === 'cmd')) {
3092 // handle windows run scripts starting with a relative path
3093 cmd = fixCmdWinSlashes(cmd);
3094 } // By default (non-interactive), pipe everything to the terminal and run child process detached
3095 // as long as it's not Windows (since windows does not have /dev/tty)
3096
3097
3098 let stdio = ['ignore', 'pipe', 'pipe'];
3099 let detached = process.platform !== 'win32';
3100
3101 if (isInteractive) {
3102 stdio = 'inherit';
3103 detached = false;
3104 }
3105
3106 const shell = customShell || true;
3107 const stdout = await spawn(cmd, args, {
3108 cwd,
3109 env,
3110 stdio,
3111 detached,
3112 shell
3113 }, onProgress);
3114 return {
3115 cwd,
3116 command: cmd,
3117 stdout
3118 };
3119}
3120// // /**
3121// // * Special case: Some packages depend on node-gyp, but don't specify this in
3122// // * their package.json dependencies. They assume that node-gyp is available
3123// // * globally. We need to detect this case and show an error message.
3124// // */
3125// function checkForGypIfNeeded(config: Config, cmd: string, paths: Array<string>): Promise<void> {
3126// if (cmd.substr(0, cmd.indexOf(' ')) !== 'node-gyp') {
3127// return Promise.resolve();
3128// }
3129// // Ensure this only runs once, rather than multiple times in parallel.
3130// if (!checkGypPromise) {
3131// checkGypPromise = _checkForGyp(config, paths);
3132// }
3133// return checkGypPromise;
3134// }
3135// async function _checkForGyp(config: Config, paths: Array<string>): Promise<void> {
3136// const {reporter} = config;
3137// // Check every directory in the PATH
3138// const allChecks = await Promise.all(paths.map(dir => fs.exists(path.join(dir, 'node-gyp'))));
3139// if (allChecks.some(Boolean)) {
3140// // node-gyp is available somewhere
3141// return;
3142// }
3143// reporter.info(reporter.lang('packageRequiresNodeGyp'));
3144// }
3145// export async function execFromDistributions(config: Config, cwd: string, dist: string, step: string): Promise<void> {
3146// const pkg = await config.maybeReadManifest(cwd);
3147// if (!pkg || !pkg.distributions || !pkg.distributions[dist] || typeof pkg.distributions[dist][step] !== 'string') {
3148// return false;
3149// }
3150// const cmd: ?string = pkg.distributions[dist][step];
3151// await execCommand({stage: 'build', config, cmd, cwd, isInteractive: true});
3152// return true;
3153// }
3154// export async function execFromManifest(config: Config, commandName: string, cwd: string): Promise<void> {
3155// const pkg = await config.maybeReadManifest(cwd);
3156// if (!pkg || !pkg.scripts) {
3157// return;
3158// }
3159// const cmd: ?string = pkg.scripts[commandName];
3160// if (cmd) {
3161// await execCommand({stage: commandName, config, cmd, cwd, isInteractive: true});
3162// }
3163// }
3164// export async function execCommand({
3165// stage,
3166// config,
3167// cmd,
3168// cwd,
3169// isInteractive,
3170// customShell,
3171// }: {
3172// stage: string;
3173// config: Config;
3174// cmd: string;
3175// cwd: string;
3176// isInteractive: boolean;
3177// customShell?: string;
3178// }): Promise<void> {
3179// const {reporter} = config;
3180// try {
3181// reporter.command(cmd);
3182// await executeLifecycleScript({config, cwd, cmd, isInteractive, customShell});
3183// return Promise.resolve();
3184// } catch (err) {
3185// if (err instanceof ProcessTermError) {
3186// throw new MessageError(
3187// err.EXIT_SIGNAL
3188// ? reporter.lang('commandFailedWithSignal', err.EXIT_SIGNAL)
3189// : reporter.lang('commandFailedWithCode', err.EXIT_CODE),
3190// );
3191// } else {
3192// throw err;
3193// }
3194// }
3195// }
3196
3197function setFlags$1(commander) {
3198 commander.description('Publish');
3199 commander.usage('publish [version] [...flags]');
3200 commander.option('--any-branch', 'Allow publishing from any branch');
3201 commander.option('--no-cleanup', 'Skips cleanup of node_modules');
3202 commander.option('--yolo', 'Skips cleanup and testing');
3203 commander.option('--no-publish', 'Skips publishing');
3204 commander.option('--tag', ' Publish under a given dist-tag');
3205 commander.option('--no-yarn', " Don't use Yarn");
3206 commander.option('--contents', 'Subdirectory to publish', 'pkg/');
3207 commander.option('--no-release-draft', 'Skips opening a GitHub release draft');
3208 commander.option('--otp <code>', 'Publish with an OTP code');
3209}
3210function hasWrapper$1() {
3211 return false;
3212}
3213async function run$1(config, reporter, flags, args) {
3214 const contentsArg = flags.contents ? [] : ['--contents', flags.out || flags.contents || 'pkg/'];
3215 const manifest = await config.loadPackageManifest();
3216
3217 if (!manifest.scripts.version) {
3218 reporter.warn(`${chalk.bold('missing "version" script:')} You'll want to create a fresh build after bumping the master package.json version.`);
3219
3220 if (manifest.scripts.build) {
3221 config._manifest.scripts.version = 'npm run build';
3222 } else {
3223 config._manifest.scripts.version = 'npx @pika/pack build';
3224 }
3225
3226 reporter.log(`Adding the following "version" lifecycle script to your package.json... ` + chalk.bold(`"${config._manifest.scripts.version}"`));
3227 await config.savePackageManifest(config._manifest);
3228 reporter.log(`Please review & commit this change before publishing.`);
3229 return;
3230 } // TODO: Check that the "version" hook runs build or @pika/pack
3231
3232
3233 try {
3234 await executeLifecycleScript({
3235 cwd: config.cwd,
3236 cmd: 'npx',
3237 args: ['np', ...contentsArg, ...flags.originalArgs],
3238 isInteractive: true
3239 });
3240 } catch (err) {
3241 // swallow err, np will properly log it to the console
3242 return;
3243 }
3244
3245 const newManifest = await config.loadPackageManifest();
3246 console.log(`If published publicly, you can see it at: ${chalk.underline(`https://unpkg.com/${newManifest.name}@${newManifest.version}/`)}`);
3247}
3248
3249var publish = /*#__PURE__*/Object.freeze({
3250 setFlags: setFlags$1,
3251 hasWrapper: hasWrapper$1,
3252 run: run$1
3253});
3254
3255const commands = {
3256 build,
3257 publish
3258};
3259
3260/* @flow */
3261function hasWrapper$2(flags, args) {
3262 return false;
3263}
3264function setFlags$2(commander) {
3265 commander.description('Displays help information.');
3266}
3267function run$2(config, reporter, commander, args) {
3268 if (args.length) {
3269 const commandName = args.shift();
3270
3271 if (Object.prototype.hasOwnProperty.call(commands, commandName)) {
3272 const command = commands[commandName];
3273
3274 if (command) {
3275 command.setFlags(commander);
3276 const examples = (command && command.examples || []).map(example => ` $ pika ${example}`);
3277
3278 if (examples.length) {
3279 commander.on('--help', () => {
3280 reporter.log(reporter.lang('helpExamples', reporter.rawText(examples.join('\n'))));
3281 });
3282 } // eslint-disable-next-line pika-internal/warn-language
3283 // commander.on('--help', () => reporter.log(' ' + getDocsInfo(commandName) + '\n'));
3284
3285
3286 commander.help();
3287 return Promise.resolve();
3288 }
3289 }
3290 }
3291
3292 commander.options.sort(sortOptionsByFlags);
3293 commander.help();
3294 return Promise.resolve();
3295}
3296
3297var helpCommand = /*#__PURE__*/Object.freeze({
3298 hasWrapper: hasWrapper$2,
3299 setFlags: setFlags$2,
3300 run: run$2
3301});
3302
3303var typos = {
3304 autohr: 'author',
3305 autor: 'author',
3306 contributers: 'contributors',
3307 depdenencies: 'dependencies',
3308 dependancies: 'dependencies',
3309 dependecies: 'dependencies',
3310 depends: 'dependencies',
3311 'dev-dependencies': 'devDependencies',
3312 devDependences: 'devDependencies',
3313 devDepenencies: 'devDependencies',
3314 devEependencies: 'devDependencies',
3315 devdependencies: 'devDependencies',
3316 hampage: 'homepage',
3317 hompage: 'homepage',
3318 prefereGlobal: 'preferGlobal',
3319 publicationConfig: 'publishConfig',
3320 repo: 'repository',
3321 repostitory: 'repository',
3322 script: 'scripts'
3323};
3324
3325const strings = ['name', 'version'];
3326const dependencyKeys = [// npm registry will include optionalDependencies in dependencies and we'll want to dedupe them from the
3327// other fields first
3328'optionalDependencies', // it's seemingly common to include a dependency in dependencies and devDependencies of the same name but
3329// different ranges, this can cause a lot of issues with our determinism and the behaviour of npm is
3330// currently unspecified.
3331'dependencies', 'devDependencies'];
3332
3333function isValidName(name) {
3334 return !name.match(/[\/@\s\+%:]/) && encodeURIComponent(name) === name;
3335}
3336
3337function isValidScopedName(name) {
3338 if (name[0] !== '@') {
3339 return false;
3340 }
3341
3342 const parts = name.slice(1).split('/');
3343 return parts.length === 2 && isValidName(parts[0]) && isValidName(parts[1]);
3344}
3345
3346function isValidPackageName(name) {
3347 return isValidName(name) || isValidScopedName(name);
3348}
3349function validate (info, isRoot, reporter, warn) {
3350 if (isRoot) {
3351 for (const key in typos) {
3352 if (key in info) {
3353 warn(reporter.lang('manifestPotentialTypo', key, typos[key]));
3354 }
3355 }
3356 } // validate name
3357
3358
3359 const {
3360 name
3361 } = info;
3362
3363 if (typeof name === 'string') {
3364 if (isRoot && isBuiltinModule(name)) {
3365 warn(reporter.lang('manifestBuiltinModule', name));
3366 } // cannot start with a dot
3367
3368
3369 if (name[0] === '.') {
3370 throw new types.MessageError(reporter.lang('manifestNameDot'));
3371 } // cannot contain the following characters
3372
3373
3374 if (!isValidPackageName(name)) {
3375 throw new types.MessageError(reporter.lang('manifestNameIllegalChars'));
3376 } // cannot equal node_modules or favicon.ico
3377
3378
3379 const lower = name.toLowerCase();
3380
3381 if (lower === 'node_modules' || lower === 'favicon.ico') {
3382 throw new types.MessageError(reporter.lang('manifestNameBlacklisted'));
3383 }
3384 } // Only care if you are trying to publish to npm.
3385 // // validate license
3386 // if (isRoot && !info.private) {
3387 // if (typeof info.license === 'string') {
3388 // const license = info.license.replace(/\*$/g, '');
3389 // if (!isValidLicense(license)) {
3390 // warn(reporter.lang('manifestLicenseInvalid'));
3391 // }
3392 // } else {
3393 // warn(reporter.lang('manifestLicenseNone'));
3394 // }
3395 // }
3396 // validate strings
3397
3398
3399 for (const key of strings) {
3400 const val = info[key];
3401
3402 if (val && typeof val !== 'string') {
3403 throw new types.MessageError(reporter.lang('manifestStringExpected', key));
3404 }
3405 }
3406
3407 cleanDependencies(info, isRoot, reporter, warn);
3408}
3409function cleanDependencies(info, isRoot, reporter, warn) {
3410 // get dependency objects
3411 const depTypes = [];
3412
3413 for (const type of dependencyKeys) {
3414 const deps = info[type];
3415
3416 if (!deps || typeof deps !== 'object') {
3417 continue;
3418 }
3419
3420 depTypes.push([type, deps]);
3421 } // aggregate all non-trivial deps (not '' or '*')
3422
3423
3424 const nonTrivialDeps = new Map();
3425
3426 for (const [type, deps] of depTypes) {
3427 for (const name of Object.keys(deps)) {
3428 const version = deps[name];
3429
3430 if (!nonTrivialDeps.has(name) && version && version !== '*') {
3431 nonTrivialDeps.set(name, {
3432 type,
3433 version
3434 });
3435 }
3436 }
3437 } // overwrite first dep of package with non-trivial version, remove the rest
3438
3439
3440 const setDeps = new Set();
3441
3442 for (const [type, deps] of depTypes) {
3443 for (const name of Object.keys(deps)) {
3444 let version = deps[name];
3445 const dep = nonTrivialDeps.get(name);
3446
3447 if (dep) {
3448 if (version && version !== '*' && version !== dep.version && isRoot) {
3449 // only throw a warning when at the root
3450 warn(reporter.lang('manifestDependencyCollision', dep.type, name, dep.version, type, version));
3451 }
3452
3453 version = dep.version;
3454 }
3455
3456 if (setDeps.has(name)) {
3457 delete deps[name];
3458 } else {
3459 deps[name] = version;
3460 setDeps.add(name);
3461 }
3462 }
3463 }
3464}
3465
3466function isValidLicense(license) {
3467 return !!license && validateLicense(license).validForNewPackages;
3468}
3469function stringifyPerson(person) {
3470 if (!person || typeof person !== 'object') {
3471 return person;
3472 }
3473
3474 const parts = [];
3475
3476 if (person.name) {
3477 parts.push(person.name);
3478 }
3479
3480 const email = person.email || person.mail;
3481
3482 if (typeof email === 'string') {
3483 parts.push(`<${email}>`);
3484 }
3485
3486 const url = person.url || person.web;
3487
3488 if (typeof url === 'string') {
3489 parts.push(`(${url})`);
3490 }
3491
3492 return parts.join(' ');
3493}
3494function parsePerson(person) {
3495 if (typeof person !== 'string') {
3496 return person;
3497 } // format: name (url) <email>
3498
3499
3500 const obj = {};
3501 let name = person.match(/^([^\(<]+)/);
3502
3503 if (name && name[0].trim()) {
3504 obj.name = name[0].trim();
3505 }
3506
3507 const email = person.match(/<([^>]+)>/);
3508
3509 if (email) {
3510 obj.email = email[1];
3511 }
3512
3513 const url = person.match(/\(([^\)]+)\)/);
3514
3515 if (url) {
3516 obj.url = url[1];
3517 }
3518
3519 return obj;
3520}
3521function normalizePerson(person) {
3522 return parsePerson(stringifyPerson(person));
3523}
3524function extractDescription(readme) {
3525 if (typeof readme !== 'string' || readme === '') {
3526 return undefined;
3527 } // split into lines
3528
3529
3530 const lines = readme.trim().split('\n').map(line => line.trim()); // find the start of the first paragraph, ignore headings
3531
3532 let start = 0;
3533
3534 for (; start < lines.length; start++) {
3535 const line = lines[start];
3536
3537 if (line && line.match(/^(#|$)/)) {
3538 // line isn't empty and isn't a heading so this is the start of a paragraph
3539 start++;
3540 break;
3541 }
3542 } // skip newlines from the header to the first line
3543
3544
3545 while (start < lines.length && !lines[start]) {
3546 start++;
3547 } // continue to the first non empty line
3548
3549
3550 let end = start;
3551
3552 while (end < lines.length && lines[end]) {
3553 end++;
3554 }
3555
3556 return lines.slice(start, end).join(' ');
3557}
3558
3559var LICENSES = {
3560 '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'),
3561 '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'),
3562 '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'),
3563 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'),
3564 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')
3565};
3566
3567function clean(str) {
3568 return str.replace(/[^A-Za-z\s]/g, ' ').replace(/[\s]+/g, ' ').trim().toLowerCase();
3569}
3570
3571const REGEXES = {
3572 Apache: [/Apache License\b/],
3573 BSD: [/BSD\b/],
3574 ISC: [/The ISC License/, /ISC\b/],
3575 MIT: [/MIT\b/],
3576 Unlicense: [/http:\/\/unlicense.org\//],
3577 WTFPL: [/DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE/, /WTFPL\b/]
3578};
3579function inferLicense(license) {
3580 // check if we have any explicit licenses
3581 const cleanLicense = clean(license);
3582
3583 for (const licenseName in LICENSES) {
3584 const testLicense = LICENSES[licenseName];
3585
3586 if (cleanLicense.search(testLicense) >= 0) {
3587 return licenseName;
3588 }
3589 } // infer based on some keywords
3590
3591
3592 for (const licenseName in REGEXES) {
3593 for (const regex of REGEXES[licenseName]) {
3594 if (license.search(regex) >= 0) {
3595 return `${licenseName}*`;
3596 }
3597 }
3598 }
3599
3600 return null;
3601}
3602
3603const LICENSE_RENAMES = {
3604 'MIT/X11': 'MIT',
3605 X11: 'MIT'
3606};
3607var fix = (async function (info, moduleLoc, reporter, warn) {
3608 const files = await readdir(moduleLoc); // clean info.version
3609
3610 if (typeof info.version === 'string') {
3611 info.version = semver.clean(info.version) || info.version;
3612 } // if name or version aren't set then set them to empty strings
3613
3614
3615 info.name = info.name || '';
3616 info.version = info.version || ''; // if the man field is a string then coerce it to an array
3617
3618 if (typeof info.man === 'string') {
3619 info.man = [info.man];
3620 } // if the keywords field is a string then split it on any whitespace
3621
3622
3623 if (typeof info.keywords === 'string') {
3624 info.keywords = info.keywords.split(/\s+/g);
3625 } // if there's no contributors field but an authors field then expand it
3626
3627
3628 if (!info.contributors && files.indexOf('AUTHORS') >= 0) {
3629 const authorsFilepath = path.join(moduleLoc, 'AUTHORS');
3630 const authorsFilestats = await stat(authorsFilepath);
3631
3632 if (authorsFilestats.isFile()) {
3633 let authors = await readFile(authorsFilepath);
3634 info.contributors = authors.split(/\r?\n/g) // split on lines
3635 .map(line => line.replace(/^\s*#.*$/, '').trim()) // remove comments
3636 .filter(line => !!line); // remove empty lines;
3637 }
3638 } // expand people fields to objects
3639
3640
3641 if (typeof info.author === 'string' || typeof info.author === 'object') {
3642 info.author = normalizePerson(info.author);
3643 }
3644
3645 if (Array.isArray(info.contributors)) {
3646 info.contributors = info.contributors.map(normalizePerson);
3647 }
3648
3649 if (Array.isArray(info.maintainers)) {
3650 info.maintainers = info.maintainers.map(normalizePerson);
3651 } // if there's no readme field then load the README file from the cwd
3652
3653
3654 if (!info.readme) {
3655 const readmeCandidates = files.filter(filename => {
3656 const lower = filename.toLowerCase();
3657 return lower === 'readme' || lower.indexOf('readme.') === 0;
3658 }).sort((filename1, filename2) => {
3659 // favor files with extensions
3660 return filename2.indexOf('.') - filename1.indexOf('.');
3661 });
3662
3663 for (const readmeFilename of readmeCandidates) {
3664 const readmeFilepath = path.join(moduleLoc, readmeFilename);
3665 const readmeFileStats = await stat(readmeFilepath);
3666
3667 if (readmeFileStats.isFile()) {
3668 info.readmeFilename = readmeFilename;
3669 info.readme = await readFile(readmeFilepath);
3670 break;
3671 }
3672 }
3673 } // if there's no description then take the first paragraph from the readme
3674
3675
3676 if (!info.description && info.readme) {
3677 const desc = extractDescription(info.readme);
3678
3679 if (desc) {
3680 info.description = desc;
3681 }
3682 } // support array of engine keys
3683
3684
3685 if (Array.isArray(info.engines)) {
3686 const engines = {};
3687
3688 for (const str of info.engines) {
3689 if (typeof str === 'string') {
3690 const [name, ...patternParts] = str.trim().split(/ +/g);
3691 engines[name] = patternParts.join(' ');
3692 }
3693 }
3694
3695 info.engines = engines;
3696 } // allow bugs to be specified as a string, expand it to an object with a single url prop
3697
3698
3699 if (typeof info.bugs === 'string') {
3700 info.bugs = {
3701 url: info.bugs
3702 };
3703 } // normalize homepage url to http
3704
3705
3706 if (typeof info.homepage === 'string') {
3707 const parts = nodeUrl.parse(info.homepage);
3708 parts.protocol = parts.protocol || 'http:';
3709
3710 if (parts.pathname && !parts.hostname) {
3711 parts.hostname = parts.pathname;
3712 parts.pathname = '';
3713 }
3714
3715 info.homepage = nodeUrl.format(parts);
3716 } // if the `bin` field is as string then expand it to an object with a single property
3717 // based on the original `bin` field and `name field`
3718 // { name: "foo", bin: "cli.js" } -> { name: "foo", bin: { foo: "cli.js" } }
3719
3720
3721 if (typeof info.name === 'string' && typeof info.bin === 'string' && info.bin.length > 0) {
3722 // Remove scoped package name for consistency with NPM's bin field fixing behaviour
3723 const name = info.name.replace(/^@[^\/]+\//, '');
3724 info.bin = {
3725 [name]: info.bin
3726 };
3727 } // bundleDependencies is an alias for bundledDependencies
3728
3729
3730 if (info.bundledDependencies) {
3731 info.bundleDependencies = info.bundledDependencies;
3732 delete info.bundledDependencies;
3733 }
3734
3735 let scripts; // dummy script object to shove file inferred scripts onto
3736
3737 if (info.scripts && typeof info.scripts === 'object') {
3738 scripts = info.scripts;
3739 } else {
3740 scripts = {};
3741 } // if there's a server.js file and no start script then set it to `node server.js`
3742
3743
3744 if (!scripts.start && files.indexOf('server.js') >= 0) {
3745 scripts.start = 'node server';
3746 } // if there's a binding.gyp file and no install script then set it to `node-gyp rebuild`
3747
3748
3749 if (!scripts.install && files.indexOf('binding.gyp') >= 0) {
3750 scripts.install = 'node-gyp rebuild';
3751 } // set scripts if we've polluted the empty object
3752
3753
3754 if (Object.keys(scripts).length) {
3755 info.scripts = scripts;
3756 }
3757
3758 const dirs = info.directories;
3759
3760 if (dirs && typeof dirs === 'object') {
3761 const binDir = dirs.bin;
3762
3763 if (!info.bin && binDir && typeof binDir === 'string') {
3764 const bin = info.bin = {};
3765 const fullBinDir = path.join(moduleLoc, binDir);
3766
3767 if (await exists(fullBinDir)) {
3768 for (const scriptName of await readdir(fullBinDir)) {
3769 if (scriptName[0] === '.') {
3770 continue;
3771 }
3772
3773 bin[scriptName] = path.join('.', binDir, scriptName);
3774 }
3775 } else {
3776 warn(reporter.lang('manifestDirectoryNotFound', binDir, info.name));
3777 }
3778 }
3779
3780 const manDir = dirs.man;
3781
3782 if (!info.man && typeof manDir === 'string') {
3783 const man = info.man = [];
3784 const fullManDir = path.join(moduleLoc, manDir);
3785
3786 if (await exists(fullManDir)) {
3787 for (const filename of await readdir(fullManDir)) {
3788 if (/^(.*?)\.[0-9]$/.test(filename)) {
3789 man.push(path.join('.', manDir, filename));
3790 }
3791 }
3792 } else {
3793 warn(reporter.lang('manifestDirectoryNotFound', manDir, info.name));
3794 }
3795 }
3796 }
3797
3798 delete info.directories; // normalize licenses field
3799
3800 const licenses = info.licenses;
3801
3802 if (Array.isArray(licenses) && !info.license) {
3803 let licenseTypes = [];
3804
3805 for (let license of licenses) {
3806 if (license && typeof license === 'object') {
3807 license = license.type;
3808 }
3809
3810 if (typeof license === 'string') {
3811 licenseTypes.push(license);
3812 }
3813 }
3814
3815 licenseTypes = licenseTypes.filter(isValidLicense);
3816
3817 if (licenseTypes.length === 1) {
3818 info.license = licenseTypes[0];
3819 } else if (licenseTypes.length) {
3820 info.license = `(${licenseTypes.join(' OR ')})`;
3821 }
3822 }
3823
3824 const license = info.license; // normalize license
3825
3826 if (license && typeof license === 'object') {
3827 info.license = license.type;
3828 } // get license file
3829
3830
3831 const licenseFile = files.find(filename => {
3832 const lower = filename.toLowerCase();
3833 return lower === 'license' || lower.startsWith('license.') || lower === 'unlicense' || lower.startsWith('unlicense.');
3834 });
3835
3836 if (licenseFile) {
3837 const licenseFilepath = path.join(moduleLoc, licenseFile);
3838 const licenseFileStats = await stat(licenseFilepath);
3839
3840 if (licenseFileStats.isFile()) {
3841 const licenseContent = await readFile(licenseFilepath);
3842 const inferredLicense = inferLicense(licenseContent);
3843 info.licenseText = licenseContent;
3844 const license = info.license;
3845
3846 if (typeof license === 'string') {
3847 if (inferredLicense && isValidLicense(inferredLicense) && !isValidLicense(license)) {
3848 // some packages don't specify their license version but we can infer it based on their license file
3849 const basicLicense = license.toLowerCase().replace(/(-like|\*)$/g, '');
3850 const expandedLicense = inferredLicense.toLowerCase();
3851
3852 if (expandedLicense.startsWith(basicLicense)) {
3853 // TODO consider doing something to notify the user
3854 info.license = inferredLicense;
3855 }
3856 }
3857 } else if (inferredLicense) {
3858 // if there's no license then infer it based on the license file
3859 info.license = inferredLicense;
3860 } else {
3861 // valid expression to refer to a license in a file
3862 info.license = `SEE LICENSE IN ${licenseFile}`;
3863 }
3864 }
3865 }
3866
3867 if (typeof info.license === 'string') {
3868 // sometimes licenses are known by different names, reduce them
3869 info.license = LICENSE_RENAMES[info.license] || info.license;
3870 } else if (typeof info.readme === 'string') {
3871 // the license might be at the bottom of the README
3872 const inferredLicense = inferLicense(info.readme);
3873
3874 if (inferredLicense) {
3875 info.license = inferredLicense;
3876 }
3877 } // get notice file
3878
3879
3880 const noticeFile = files.find(filename => {
3881 const lower = filename.toLowerCase();
3882 return lower === 'notice' || lower.startsWith('notice.');
3883 });
3884
3885 if (noticeFile) {
3886 const noticeFilepath = path.join(moduleLoc, noticeFile);
3887 const noticeFileStats = await stat(noticeFilepath);
3888
3889 if (noticeFileStats.isFile()) {
3890 info.noticeText = await readFile(noticeFilepath);
3891 }
3892 }
3893
3894 for (const dependencyType of MANIFEST_FIELDS) {
3895 const dependencyList = info[dependencyType];
3896
3897 if (dependencyList && typeof dependencyList === 'object') {
3898 delete dependencyList['//'];
3899
3900 for (const name in dependencyList) {
3901 dependencyList[name] = dependencyList[name] || '';
3902 }
3903 }
3904 }
3905});
3906
3907var normalizeManifest = (async function (info, moduleLoc, config, isRoot) {
3908 // Append dependencies
3909 // if (depInfo) {
3910 // info.dependencies = depInfo.main;
3911 // info.devDependencies = depInfo.dev;
3912 // }
3913 // create human readable name
3914 const {
3915 name,
3916 version
3917 } = info;
3918 let human;
3919
3920 if (typeof name === 'string') {
3921 human = name;
3922 }
3923
3924 if (human && typeof version === 'string' && version) {
3925 human += `@${version}`;
3926 }
3927
3928 if (isRoot && info._loc) {
3929 human = path.relative(config.cwd, info._loc);
3930 }
3931
3932 function warn(msg) {
3933 if (human) {
3934 msg = `${human}: ${msg}`;
3935 }
3936
3937 config.reporter.warn(msg);
3938 }
3939
3940 await fix(info, moduleLoc, config.reporter, warn);
3941
3942 try {
3943 validate(info, isRoot, config.reporter, warn);
3944 } catch (err) {
3945 if (human) {
3946 err.message = `${human}: ${err.message}`;
3947 }
3948
3949 throw err;
3950 }
3951
3952 return info;
3953});
3954
3955class Config {
3956 constructor(reporter, cwd, flags) {
3957 this.reporter = reporter; // Ensure the cwd is always an absolute path.
3958
3959 this.cwd = path.resolve(cwd || process.cwd());
3960 this.flags = flags;
3961 }
3962
3963 async loadPackageManifest() {
3964 const loc = path.join(this.cwd, NODE_PACKAGE_JSON);
3965
3966 if (await exists(loc)) {
3967 const info = await this.readJson(loc, readJsonAndFile);
3968 this._manifest = _objectSpread({}, info.object);
3969 this.manifestIndent = detectIndent(info.content).indent || undefined;
3970 this.manifest = await normalizeManifest(info.object, this.cwd, this, true);
3971 return this.manifest;
3972 } else {
3973 return null;
3974 }
3975 }
3976
3977 readJson(loc, factory = readJson) {
3978 try {
3979 return factory(loc);
3980 } catch (err) {
3981 if (err instanceof SyntaxError) {
3982 throw new types.MessageError(this.reporter.lang('jsonError', loc, err.message));
3983 } else {
3984 throw err;
3985 }
3986 }
3987 }
3988
3989 async savePackageManifest(newManifestData) {
3990 const loc = path.join(this.cwd, NODE_PACKAGE_JSON);
3991
3992 const manifest = _objectSpread({}, this._manifest, newManifestData);
3993
3994 await writeFilePreservingEol(loc, JSON.stringify(manifest, null, this.manifestIndent || DEFAULT_INDENT) + '\n');
3995 return this.loadPackageManifest();
3996 }
3997
3998 async getDistributions() {
3999 const raw = this.manifest[`@pika/pack`] || {};
4000 const override = this.flags.pipeline && JSON.parse(this.flags.pipeline);
4001 const cwd = this.cwd;
4002
4003 function cleanRawDistObject(rawVal) {
4004 if (Array.isArray(rawVal)) {
4005 let importStr = rawVal[0].startsWith('./') || rawVal[0].startsWith('../') ? path.join(cwd, rawVal[0]) : rawVal[0];
4006 return [_objectSpread({}, importFrom(cwd, importStr), {
4007 name: rawVal[0]
4008 }), rawVal[1] || {}];
4009 }
4010
4011 if (typeof rawVal === 'string') {
4012 return [{
4013 build: ({
4014 cwd
4015 }) => {
4016 return executeLifecycleScript({
4017 // config: this,
4018 args: [],
4019 cwd,
4020 cmd: rawVal,
4021 isInteractive: false
4022 });
4023 }
4024 }, {}];
4025 }
4026
4027 if (!rawVal) {
4028 throw new Error('Cannot be false');
4029 }
4030
4031 return false;
4032 }
4033
4034 const pipeline = override || raw.pipeline || [];
4035 return pipeline.map(cleanRawDistObject).filter(Boolean);
4036 }
4037
4038}
4039
4040function forwardSignalAndExit(signal) {
4041 forwardSignalToSpawnedProcesses(signal); // We want to exit immediately here since `SIGTERM` means that
4042 // If we lose stdout messages due to abrupt exit, shoot the messenger?
4043
4044 process.exit(1); // eslint-disable-line no-process-exit
4045}
4046
4047function handleSignals() {
4048 process.on('SIGTERM', () => {
4049 forwardSignalAndExit('SIGTERM');
4050 });
4051}
4052
4053const FALSY_STRINGS = new Set(['0', 'false']);
4054function boolify(val) {
4055 return !FALSY_STRINGS.has(val.toString().toLowerCase());
4056}
4057function boolifyWithDefault(val, defaultResult) {
4058 return val === '' || val === null || val === undefined ? defaultResult : boolify(val);
4059}
4060
4061const commander = new commander$1.Command(); // @ts-ignore
4062
4063const 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)));
4064
4065function getVersion() {
4066 const packageJsonContent = fs.readFileSync(path.resolve(currentFilename, '../../package.json'), {
4067 encoding: 'utf-8'
4068 });
4069 const {
4070 version
4071 } = nullify(JSON.parse(stripBOM(packageJsonContent)));
4072 return version;
4073}
4074
4075function findProjectRoot(base) {
4076 let prev = null;
4077 let dir = base;
4078
4079 do {
4080 if (fs.existsSync(path.join(dir, NODE_PACKAGE_JSON))) {
4081 return dir;
4082 }
4083
4084 prev = dir;
4085 dir = path.dirname(dir);
4086 } while (dir !== prev);
4087
4088 return base;
4089}
4090
4091async function main({
4092 startArgs,
4093 args,
4094 endArgs
4095}) {
4096 const version = getVersion();
4097 loudRejection();
4098 handleSignals(); // set global options
4099
4100 commander.version(version, '-v, --version');
4101 commander.usage('[command] [flags]');
4102 commander.option('--verbose', 'output verbose messages on internal operations');
4103 commander.option('--json', 'format Pika log messages as lines of JSON (see jsonlines.org)'); // commander.option('--force', 'install and build packages even if they were built before, overwrite lockfile');
4104 // commander.option('--prod, --production [prod]', '', boolify);
4105
4106 commander.option('--emoji [bool]', 'enable emoji in output', boolify, process.platform === 'darwin' || process.env.TERM_PROGRAM === 'Hyper' || process.env.TERM_PROGRAM === 'HyperTerm');
4107 commander.option('-s, --silent', 'skip Pika console logs, other types of logs (script output) will be printed');
4108 commander.option('--cwd <cwd>', 'working directory to use', process.cwd());
4109 commander.option('--no-progress', 'disable progress bar');
4110 commander.option('--no-node-version-check', 'do not warn when using a potentially unsupported Node version');
4111 commander.option('--pipeline <pipeline>', 'the build pipeline to run'); // if -v is the first command, then always exit after returning the version
4112
4113 if (args[0] === '-v') {
4114 console.log(version.trim());
4115 process.exitCode = 0;
4116 return;
4117 } // get command name
4118
4119
4120 const firstNonFlagIndex = args.findIndex((arg, idx, arr) => {
4121 const isOption = arg.startsWith('-');
4122 const prev = idx > 0 && arr[idx - 1];
4123 const prevOption = prev && prev.startsWith('-') && commander.optionFor(prev);
4124 const boundToPrevOption = prevOption && (prevOption.optional || prevOption.required);
4125 return !isOption && !boundToPrevOption;
4126 });
4127 let preCommandArgs;
4128 let commandName = '';
4129
4130 if (firstNonFlagIndex > -1) {
4131 preCommandArgs = args.slice(0, firstNonFlagIndex);
4132 commandName = args[firstNonFlagIndex];
4133 args = args.slice(firstNonFlagIndex + 1);
4134 } else {
4135 preCommandArgs = args;
4136 args = [];
4137 }
4138
4139 let isKnownCommand = Object.prototype.hasOwnProperty.call(commands, commandName);
4140
4141 const isHelp = arg => arg === '--help' || arg === '-h';
4142
4143 const helpInPre = preCommandArgs.findIndex(isHelp);
4144 const helpInArgs = args.findIndex(isHelp);
4145
4146 const setHelpMode = () => {
4147 if (isKnownCommand) {
4148 args.unshift(commandName);
4149 }
4150
4151 commandName = 'help';
4152 isKnownCommand = true;
4153 };
4154
4155 if (helpInPre > -1) {
4156 preCommandArgs.splice(helpInPre);
4157 setHelpMode();
4158 } else if (isKnownCommand && helpInArgs === 0) {
4159 args.splice(helpInArgs);
4160 setHelpMode();
4161 }
4162
4163 if (!commandName) {
4164 commandName = 'help';
4165 isKnownCommand = true;
4166 }
4167
4168 if (!isKnownCommand) {
4169 // if command is not recognized, then set default to `run`
4170 args.unshift(commandName);
4171 commandName = 'help';
4172 }
4173
4174 const command = commandName === 'help' ? helpCommand : commands[commandName];
4175 commander.originalArgs = args;
4176 args = [...preCommandArgs, ...args];
4177 command.setFlags(commander);
4178 commander.parse([...startArgs, // we use this for https://github.com/tj/commander.js/issues/346, otherwise
4179 // it will strip some args that match with any options
4180 'this-arg-will-get-stripped-later', ...args]);
4181 commander.args = commander.args.concat(endArgs.slice(1)); // we strip cmd
4182
4183 console.assert(commander.args.length >= 1);
4184 console.assert(commander.args[0] === 'this-arg-will-get-stripped-later');
4185 commander.args.shift(); //
4186
4187 const Reporter = commander.json ? JSONReporter : ConsoleReporter;
4188 const reporter = new Reporter({
4189 emoji: process.stdout.isTTY && commander.emoji,
4190 verbose: commander.verbose,
4191 noProgress: !commander.progress,
4192 isSilent: boolifyWithDefault(process.env.PIKA_SILENT, false) || commander.silent,
4193 nonInteractive: commander.nonInteractive
4194 });
4195
4196 const exit = (exitCode = 0) => {
4197 if (exitCode === 0) {
4198 clearErrorReport();
4199 }
4200
4201 process.exitCode = exitCode;
4202 reporter.close();
4203 };
4204
4205 reporter.initPeakMemoryCounter();
4206 const outputWrapperEnabled = boolifyWithDefault(process.env.PIKA_WRAP_OUTPUT, true);
4207 const shouldWrapOutput = outputWrapperEnabled && !commander.json && command.hasWrapper(commander, commander.args); // if (shouldWrapOutput) {
4208
4209 reporter.header(commandName, {
4210 name: '@pika/pack',
4211 version
4212 }); // }
4213
4214 if (commander.nodeVersionCheck && !semver.satisfies(process.versions.node, SUPPORTED_NODE_VERSIONS)) {
4215 reporter.warn(reporter.lang('unsupportedNodeVersion', process.versions.node, SUPPORTED_NODE_VERSIONS));
4216 }
4217
4218 if (command.noArguments && commander.args.length) {
4219 reporter.error(reporter.lang('noArguments')); // reporter.info(command.getDocsInfo);
4220
4221 exit(1);
4222 return;
4223 } //
4224 // if (commander.yes) {
4225 // reporter.warn(reporter.lang('yesWarning'));
4226 // }
4227 //
4228
4229
4230 const run = () => {
4231 invariant(command, 'missing command'); // if (warnAboutRunDashDash) {
4232 // reporter.warn(reporter.lang('dashDashDeprecation'));
4233 // }
4234
4235 return command.run(config, reporter, commander, commander.args).then(exitCode => {
4236 if (shouldWrapOutput) {
4237 reporter.footer(false);
4238 }
4239
4240 return exitCode;
4241 });
4242 };
4243
4244 function onUnexpectedError(err) {
4245 function indent(str) {
4246 return '\n ' + str.trim().split('\n').join('\n ');
4247 }
4248
4249 const log = [];
4250 log.push(`Arguments: ${indent(process.argv.join(' '))}`);
4251 log.push(`PATH: ${indent(process.env.PATH || 'undefined')}`);
4252 log.push(`Pika version: ${indent(version)}`);
4253 log.push(`Node version: ${indent(process.versions.node)}`);
4254 log.push(`Platform: ${indent(process.platform + ' ' + process.arch)}`);
4255 log.push(`Trace: ${indent(err.stack)}`);
4256 const errorReportLoc = writeErrorReport(log);
4257 reporter.error(reporter.lang('unexpectedError', err.message));
4258
4259 if (errorReportLoc) {
4260 reporter.info(reporter.lang('bugReport', errorReportLoc));
4261 }
4262 }
4263
4264 function writeErrorReport(log) {
4265 const errorReportLoc = path.join(config.cwd, 'pika-error.log');
4266
4267 try {
4268 fs.writeFileSync(errorReportLoc, log.join('\n\n') + '\n');
4269 } catch (err) {
4270 reporter.error(reporter.lang('fileWriteError', errorReportLoc, err.message));
4271 return undefined;
4272 }
4273
4274 return errorReportLoc;
4275 }
4276
4277 function clearErrorReport() {
4278 const errorReportLoc = path.join(config.cwd, 'pika-error.log');
4279
4280 if (fs.existsSync(errorReportLoc)) {
4281 try {
4282 fs.unlinkSync(errorReportLoc);
4283 } catch (err) {
4284 reporter.error(reporter.lang('fileDeleteError', errorReportLoc, err.message));
4285 return undefined;
4286 }
4287 }
4288
4289 return errorReportLoc;
4290 }
4291
4292 const cwd = command.shouldRunInCurrentCwd ? commander.cwd : findProjectRoot(commander.cwd);
4293 const config = new Config(reporter, cwd, commander);
4294 await config.loadPackageManifest();
4295
4296 try {
4297 // option "no-progress" stored in pika config
4298 const noProgressConfig = false; //config.registries.pika.getOption('no-progress');
4299
4300 if (noProgressConfig) {
4301 reporter.disableProgress();
4302 } // verbose logs outputs process.uptime() with this line we can sync uptime to absolute time on the computer
4303
4304
4305 reporter.verbose(`current time: ${new Date().toISOString()}`);
4306 return run().then(exit);
4307 } catch (err) {
4308 reporter.verbose(err.stack);
4309
4310 if (err instanceof types.MessageError) {
4311 reporter.error(err.message);
4312 } else {
4313 onUnexpectedError(err);
4314 } // if (command.getDocsInfo) {
4315 // reporter.info(command.getDocsInfo);
4316 // }
4317
4318
4319 return exit(1);
4320 }
4321}
4322
4323async function start() {
4324 // ignore all arguments after a --
4325 const doubleDashIndex = process.argv.findIndex(element => element === '--');
4326 const startArgs = process.argv.slice(0, 2);
4327 const args = process.argv.slice(2, doubleDashIndex === -1 ? process.argv.length : doubleDashIndex);
4328 const endArgs = doubleDashIndex === -1 ? [] : process.argv.slice(doubleDashIndex);
4329 await main({
4330 startArgs,
4331 args,
4332 endArgs
4333 });
4334}
4335
4336const autoRun = false;
4337
4338exports.autoRun = autoRun;
4339exports.default = start;
4340exports.main = main;