Socket
Socket
Sign inDemoInstall

envinfo

Package Overview
Dependencies
0
Maintainers
1
Versions
88
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 4.4.2 to 5.0.0

__tests__/envinfo.test.js

2

.eslintrc.js
module.exports = {
env: {
node: true,
es6: true,
jest: true,
},

@@ -5,0 +7,0 @@ extends: ['airbnb-base/legacy', 'prettier'],

11

package.json
{
"name": "envinfo",
"version": "4.4.2",
"version": "5.0.0",
"description": "Info about your dev environment for debugging purposes",

@@ -19,3 +19,4 @@ "repository": "https://github.com/tabrindle/envinfo",

"format": "prettier --write 'src/**/*.js'",
"test": "npm run lint && prettier -l 'src/**/*.js'",
"test": "jest && npm run lint && npm run check:format",
"check:format": "prettier -l 'src/**/*.js'",
"preversion": "yarn webpack && git add ."

@@ -36,2 +37,3 @@ },

"clipboardy": "^1.2.2",
"eslint": "^4.10.0",
"eslint-config-airbnb-base": "^12.1.0",

@@ -41,4 +43,4 @@ "eslint-config-prettier": "^2.7.0",

"eslint-plugin-prettier": "^2.3.1",
"eslint": "^4.10.0",
"glob": "^7.1.2",
"jest": "^22.4.3",
"minimist": "^1.2.0",

@@ -50,3 +52,4 @@ "object.entries": "^1.0.4",

"uglifyjs-webpack-plugin": "^1.2.1",
"webpack": "^3.11.0",
"webpack": "^4.5.0",
"webpack-cli": "^2.0.14",
"which": "^1.2.14",

@@ -53,0 +56,0 @@ "yamlify-object": "^0.4.5"

@@ -9,2 +9,15 @@ <p align="center">

## The problem
- It works on my computer
- "command not found"
- what version of "command" are you running?
- what version of "different command" are you running?
- do you have "insert obscure android sdk version"?
- every github issue reporting template ever:
**Please mention other relevant information such as the browser version, Node.js version, Operating System and programming language.**
## This solution
- Gather all of this information in one spot, quickly, and painlessly.
## Installation

@@ -108,3 +121,3 @@

```
returns:
```

@@ -159,47 +172,21 @@ {

* --clipboard - Optionally copy directly to your clipboard with `envinfo --clipboard`. This feature uses [Clipboardy](https://www.npmjs.com/package/clipboardy)
* --npmPackages - Optionally return packages from your package.json: takes either boolean or comma delimited string in CLI or array via API
`envinfo --npmPackages minimist,which`
```sh
npmPackages:
minimist:
wanted: ^1.2.0
installed: 1.2.0
which:
wanted: ^1.2.14
installed: 1.3.0
```
--system Print general system info such as OS, CPU, Memory and Shell
--browsers Get version numbers of installed web browsers
--SDKs Get platforms, build tools and SDKs of iOS and Android
--IDEs Get version numbers of installed IDEs
--languages Get version numbers of installed languages such as Java, Python, PHP, etc
--binaries Get version numbers of node, npm, watchman, etc
--npmPackages Get version numbers of locally installed npm packages - glob, string, or comma delimited list
--npmGlobalPackages Get version numbers of globally installed npm packages
* --npmGlobalPackages - print your npm global packages versions
--duplicates Mark duplicate npm packages inside parentheses eg. (2.1.4)
--fullTree Traverse entire node_modules dependency tree, not just top level
`envinfo --npmGlobalPackages`
```sh
npmGlobalPackages:
exp: 48.0.2
npm: 5.6.0
react-native-cli: 2.0.1
--markdown Print output in markdown format
--json Print output in JSON format
--console Print to console (defaults to on for CLI usage, off for programmatic usage)
--clipboard Copy output to your system clipboard (uses clipboardy)
```
* --duplicates - will search given packages for duplicates, display in parentheses
```sh
Packages:
minimist: ^1.2.0 => 1.2.0 (1.2.0, 0.0.8)
```
* --fullTree - will traverse and print the entire flattened dependency tree (optionally also with --duplicates)
```sh
Packages:
...
minimatch: 3.0.4
minimist: ^1.2.0 => 1.2.0 (1.2.0, 0.0.8)
mkdirp: 0.5.1
...
```
## Integration

@@ -210,4 +197,5 @@

* [React Native](https://github.com/facebook/react-native) (`react-native info`)
* [create-react-app](https://github.com/facebook/create-react-app) (`create-react-app --info`)
* [Exponent Development CLI](https://github.com/expo/exp) (`exp diagnostics`)
* [Create React App](https://github.com/facebook/create-react-app) (`create-react-app --info`)
* [Expo](https://github.com/expo/exp) (`exp diagnostics`)
* [Webpack](https://github.com/webpack/webpack-cli) (`webpack-cli info`)
* [Solidarity](https://github.com/infinitered/solidarity) (`solidarity report`)

@@ -224,1 +212,10 @@

This project came out of a [PR](https://github.com/facebook/react-native/pull/14428) to the React Native CLI tool - issues are reported frequently without important environment information, like Node/npm versions.
## Alternatives
- type `$ command -v` until you smash your computer
- [screenfetch](https://github.com/KittyKatt/screenFetch) - fetch system and terminal information, and display a pretty ascii logo
- [Solidarity](https://github.com/infinitered/solidarity) - a project based environment checker
- write your own
## License
MIT

@@ -5,3 +5,2 @@ 'use strict';

const helpers = require('./helpers');
const helperMap = require('./map');
const formatters = require('./formatters');

@@ -18,45 +17,3 @@ const presets = require('./presets');

// a map of all the capabilities of envinfo - used as a default input
const capabilities = {
System: ['OS', 'CPU', 'Free Memory', 'Total Memory', 'Shell'],
Binaries: ['Node', 'Yarn', 'npm', 'Watchman'],
Virtualization: ['Docker', 'Parallels', 'Virtualbox', 'VMware Fusion'],
SDKs: ['iOS', 'Android'],
IDEs: ['Android Studio', 'Atom', 'VSCode', 'Sublime Text', 'Xcode'],
Languages: ['Bash', 'Go', 'Elixir', 'PHP', 'Python', 'Ruby'],
Browsers: [
'Chrome',
'Chrome Canary',
'Firefox',
'Firefox Developer Edition',
'Firefox Nightly',
'Safari',
'Safari Technology Preview',
],
npmPackages: null,
npmGlobalPackages: true,
};
function main(props, options) {
// set props to passed in props or default all capabilities
const defaults = Object.keys(props).length > 0 ? props : capabilities;
options = options || {};
// get data by iterating and calling helper functions
const data = Object.entries(defaults).reduce((acc, prop) => {
const category = prop[0];
const value = prop[1];
// create an object of all the resolved helper values
return Object.assign(acc, {
[category]: helperMap[category]
? helperMap[category](value, options) // if there is a category level helper
: value.reduce((cat, name) => {
const fn = helperMap[name.toLowerCase().replace(/\s/g, '_')];
return Object.assign(cat, {
[name]: fn ? fn() : 'Unknown',
});
}, {}),
});
}, {});
function format(data, options) {
// set the default formatter (yaml is default, similar to old table)

@@ -69,6 +26,6 @@ const formatter = (() => {

if (options.console) return console.log(formatter(data, { console: true })); // eslint-disable-line no-console
// call the formatter with console option off first to return, or pipe to clipboard
const formatted = formatter(data, { console: false });
if (options.console) console.log(formatter(data, { console: true })); // eslint-disable-line no-console
if (options.clipboard) copypasta.writeSync(formatted);

@@ -79,2 +36,55 @@

function main(props, options) {
options = options || {};
// set props to passed in props or default to presets.defaults
const defaults = Object.keys(props).length > 0 ? props : presets.defaults;
// collect a list of promises of helper functions
const promises = Object.entries(defaults).reduce((acc, entries) => {
const category = entries[0];
const value = entries[1];
const categoryFn = helpers[`get${category}`];
// check to see if a category level function exists
if (categoryFn) {
if (value) acc.push(categoryFn(value, options));
// if the value on the category is falsy, don't run it
return acc;
}
// map over a categories helper functions, call and add to the stack
acc = acc.concat(
(value || []).map(v => {
const helperFn = helpers[`get${v.replace(/\s/g, '')}Info`];
return helperFn ? helperFn() : Promise.resolve(['Unknown']);
})
);
return acc;
}, []);
// once all tasks are done, map all the data back to the shape of the original config obj
return Promise.all(promises).then(data => {
// reduce promise results to object for addressability.
const dataObj = data.reduce((acc, dataValue) => {
if (dataValue && dataValue[0]) Object.assign(acc, { [dataValue[0]]: dataValue });
return acc;
}, {});
// use defaults object for mapping
const reduced = Object.entries(presets.defaults).reduce((acc, entries) => {
const category = entries[0];
const values = entries[1];
if (dataObj[category]) return Object.assign(acc, { [category]: dataObj[category][1] });
return Object.assign(acc, {
[category]: (values || []).reduce((helperAcc, v) => {
if (dataObj[v]) {
dataObj[v].shift();
if (dataObj[v].length === 1) return Object.assign(helperAcc, { [v]: dataObj[v][0] });
return Object.assign(helperAcc, {
[v]: { version: dataObj[v][0], path: dataObj[v][1] },
});
}
return helperAcc;
}, {}),
});
}, {});
return format(reduced, options);
});
}
// Example usage:

@@ -84,6 +94,18 @@ // $ envinfo --system --npmPackages

// if all option is passed, do not pass go, do not collect 200 dollars, go straight to main
if (options.all) return main(Object.assign({}, capabilities, { npmPackages: true }), options);
if (options.all)
return main(
Object.assign({}, presets.defaults, { npmPackages: true, npmGlobalPackages: true }),
options
);
// if raw, parse the row options and skip to main
if (options.raw) return main(JSON.parse(options.raw), options);
// generic function to make sure passed option exists in capability list
// if helper flag, run just that helper then log the results
if (options.helper) {
const helper =
helpers[`get${options.helper}`] ||
helpers[`get${options.helper}Info`] ||
helpers[options.helper];
return helper ? helper().then(console.log) : console.error('Not Found');
}
// generic function to make sure passed option exists in presets.defaults list
// TODO: This will eventually be replaced with a better fuzzy finder.

@@ -93,6 +115,6 @@ const matches = (list, opt) => list.toLowerCase().includes(opt.toLowerCase());

const categories = Object.keys(options).filter(o =>
Object.keys(capabilities).some(c => matches(c, o))
Object.keys(presets.defaults).some(c => matches(c, o))
);
// build the props object for filtering capabilities
const props = Object.entries(capabilities).reduce((acc, entry) => {
// build the props object for filtering presets.defaults
const props = Object.entries(presets.defaults).reduce((acc, entry) => {
if (categories.some(c => matches(c, entry[0]))) {

@@ -103,3 +125,2 @@ return Object.assign(acc, { [entry[0]]: entry[1] || options[entry[0]] });

}, {});
// if there is a preset, merge that with the parsed props and options

@@ -106,0 +127,0 @@ if (options.preset) {

@@ -37,5 +37,5 @@ const yamlify = require('yamlify-object');

function formatPackages(data) {
return Object.assign(
data,
Object.entries(data.packages || {}).reduce((acc, entry) => {
if (!data.npmPackages) return data;
return Object.assign(data, {
npmPackages: Object.entries(data.npmPackages || {}).reduce((acc, entry) => {
const key = entry[0];

@@ -51,4 +51,4 @@ const value = entry[1];

});
}, {})
);
}, {}),
});
}

@@ -81,2 +81,27 @@

function serializeVersionsAndPaths(data) {
return Object.entries(data).reduce(
(Dacc, Dentry) =>
Object.assign(
Dacc,
{
[Dentry[0]]: Object.entries(Dentry[1]).reduce((acc, entry) => {
const key = entry[0];
const value = entry[1];
if (value.version) {
return Object.assign(acc, {
[key]: [value.version, value.path].filter(Boolean).join(' - '),
});
}
return Object.assign(acc, {
[key]: [value][0],
});
}, {}),
},
{}
),
{}
);
}
function yaml(data) {

@@ -118,5 +143,6 @@ return yamlify(data, {

return utils.pipe([
clean,
formatPackages,
serializeArrays,
clean,
serializeVersionsAndPaths,
yaml,

@@ -128,3 +154,10 @@ options.console ? formatHeaders : utils.noop,

function formatToMarkdown(data) {
return utils.pipe([formatPackages, serializeArrays, clean, yaml, markdown])(data);
return utils.pipe([
clean,
formatPackages,
serializeArrays,
serializeVersionsAndPaths,
yaml,
markdown,
])(data);
}

@@ -135,3 +168,3 @@

data = utils.pipe([json])(data);
data = utils.pipe([clean, json])(data);
data = options.console ? `\n${data}\n` : data;

@@ -138,0 +171,0 @@

@@ -5,409 +5,381 @@ const childProcess = require('child_process');

const path = require('path');
const which = require('which');
const packages = require('./packages');
const utils = require('./utils');
var browserBundleIdentifiers = {
Chrome: 'com.google.Chrome',
'Chrome Canary': 'com.google.Chrome.canary',
Firefox: 'org.mozilla.firefox',
'Firefox Developer Edition': 'org.mozilla.firefoxdeveloperedition',
'Firefox Nightly': 'org.mozilla.nightly',
Safari: 'com.apple.Safari',
'Safari Technology Preview': 'com.apple.SafariTechnologyPreview',
};
function findDarwinApplication(id) {
var appPath;
try {
appPath = utils.run('mdfind "kMDItemCFBundleIdentifier=="' + id + '""').replace(/(\s)/g, '\\ ');
} catch (error) {
appPath = null;
}
return appPath;
}
function generatePlistBuddyCommand(appPath, options) {
var optionsArray = (options || ['CFBundleShortVersionString']).map(function optionsMap(option) {
return '-c Print:' + option;
});
return ['/usr/libexec/PlistBuddy']
.concat(optionsArray)
.concat([appPath])
.join(' ');
}
function getDarwinApplicationVersion(bundleIdentifier) {
var version;
if (process.platform === 'darwin') {
try {
version = utils.run(
generatePlistBuddyCommand(
path.join(findDarwinApplication(bundleIdentifier), 'Contents', 'Info.plist'),
['CFBundleShortVersionString']
)
);
} catch (error) {
version = 'Not Found';
module.exports = Object.assign({}, utils, packages, {
getiOSSDKInfo: () => {
var iOSSDKVersions;
if (process.platform === 'darwin') {
iOSSDKVersions = utils
.run('xcodebuild -showsdks')
.then(sdks => sdks.match(/[\w]+\s[\d|.]+/g))
.then(utils.uniq)
.catch(() => 'Unknown');
} else {
iOSSDKVersions = 'N/A';
}
return version;
}
return 'N/A';
}
return iOSSDKVersions.then(platforms => ['iOS SDK', { Platforms: platforms }]);
},
function getAlliOSSDKs() {
var iOSSDKVersions;
getAndroidSDKInfo: () => {
var buildTools = [];
var androidAPIs = [];
return utils
.run(
process.env.ANDROID_HOME ? '$ANDROID_HOME/tools/bin/sdkmanager --list' : 'sdkmanager --list'
)
.then(output => {
const installed = output.split('Available')[0];
const getBuildVersions = /build-tools;([\d|.]+)[\S\s]/g;
const getAPIVersions = /platforms;android-(\d+)[\S\s]/g;
let matcher;
// eslint-disable-next-line
while ((matcher = getBuildVersions.exec(installed))) {
buildTools.push(matcher[1]);
}
// eslint-disable-next-line
while ((matcher = getAPIVersions.exec(installed))) {
androidAPIs.push(matcher[1]);
}
return [
'Android SDK',
{
'Build Tools': buildTools,
'API Levels': androidAPIs,
},
];
})
.catch(() => ({
buildTools: ['Unknown'],
androidAPIs: ['Unknown'],
}));
},
if (process.platform === 'darwin') {
try {
var output = utils.run('xcodebuild -showsdks');
iOSSDKVersions = output.match(/[\w]+\s[\d|.]+/g);
} catch (e) {
iOSSDKVersions = 'Unknown';
}
} else {
return 'N/A';
}
return {
Platforms: utils.uniq(iOSSDKVersions),
};
}
function getAllAndroidSDKs() {
var buildTools = [];
var androidAPIs = [];
try {
// try to use preferred install path
var command = process.env.ANDROID_HOME ? '$ANDROID_HOME/tools/bin/sdkmanager' : 'sdkmanager';
var installed = utils.run(command + ' --list').split('Available')[0];
var getBuildVersions = /build-tools;([\d|.]+)[\S\s]/g;
var getAPIVersions = /platforms;android-(\d+)[\S\s]/g;
var matcher;
// eslint-disable-next-line
while ((matcher = getBuildVersions.exec(installed))) {
buildTools.push(matcher[1]);
}
// eslint-disable-next-line
while ((matcher = getAPIVersions.exec(installed))) {
androidAPIs.push(matcher[1]);
}
} catch (err) {
buildTools = ['Unknown'];
androidAPIs = ['Unknown'];
}
return {
'Build Tools': buildTools,
'API Levels': androidAPIs,
};
}
function getAndroidStudioVersion() {
var androidStudioVersion = 'Not Found';
if (process.platform === 'darwin') {
try {
getAndroidStudioInfo: () => {
let androidStudioVersion;
if (process.platform === 'darwin') {
androidStudioVersion = utils
.run(
generatePlistBuddyCommand('/Applications/Android\\ Studio.app/Contents/Info.plist', [
'CFBundleShortVersionString',
'CFBundleVersion',
])
utils.generatePlistBuddyCommand(
path.join('/', 'Applications', 'Android\\ Studio.app', 'Contents', 'Info.plist'),
['CFBundleShortVersionString', 'CFBundleVersion']
)
)
.split('\n')
.join(' ');
} catch (err) {
androidStudioVersion = 'Not Found';
.then(version => version.split('\n').join(' '));
} else if (process.platform === 'linux') {
androidStudioVersion = Promise.all([
utils
.run('cat /opt/android-studio/bin/studio.sh | grep "$Home/.AndroidStudio" | head -1')
.then(utils.findVersion),
utils.run('cat /opt/android-studio/build.txt'),
]).then(tasks => {
const linuxVersion = tasks[0];
const linuxBuildNumber = tasks[1];
return `${linuxVersion} ${linuxBuildNumber}`;
});
} else if (process.platform.startsWith('win')) {
androidStudioVersion = Promise.all([
utils
.run(
'wmic datafile where name="C:\\\\Program Files\\\\Android\\\\Android Studio\\\\bin\\\\studio.exe" get Version'
)
.then(version => version.replace(/(\r\n|\n|\r)/gm, '')),
utils
.run('type "C:\\\\Program Files\\\\Android\\\\Android Studio\\\\build.txt"')
.then(version => version.replace(/(\r\n|\n|\r)/gm, '')),
]).then(tasks => {
const windowsVersion = tasks[0];
const windowsBuildNumber = tasks[1];
return `${windowsVersion} ${windowsBuildNumber}`;
});
}
} else if (process.platform === 'linux') {
return Promise.all(['Android Studio', androidStudioVersion || 'Not Found']);
},
getAtomInfo: () => {
utils.log('trace', 'getAtomInfo');
return Promise.all(['Atom', utils.getDarwinApplicationVersion('com.github.atom'), 'N/A']);
},
getCPUInfo: () => {
utils.log('trace', 'getCPUInfo');
let info;
try {
var linuxBuildNumber = utils.run('cat /opt/android-studio/build.txt');
var linuxVersion = utils
.run('cat /opt/android-studio/bin/studio.sh | grep "$Home/.AndroidStudio" | head -1')
.match(/\d\.\d/)[0];
androidStudioVersion = `${linuxVersion} ${linuxBuildNumber}`;
info = os.arch() + ' ' + os.cpus()[0].model;
} catch (err) {
androidStudioVersion = 'Not Found';
info = 'Unknown';
}
} else if (process.platform.startsWith('win')) {
try {
var windowsVersion = utils
.run(
'wmic datafile where name="C:\\\\Program Files\\\\Android\\\\Android Studio\\\\bin\\\\studio.exe" get Version'
)
.replace(/(\r\n|\n|\r)/gm, '');
var windowsBuildNumber = utils
.run('type "C:\\\\Program Files\\\\Android\\\\Android Studio\\\\build.txt"')
.replace(/(\r\n|\n|\r)/gm, '');
androidStudioVersion = `${windowsVersion} ${windowsBuildNumber}`;
} catch (err) {
androidStudioVersion = 'Not Found';
}
}
return androidStudioVersion;
}
return Promise.all(['CPU', info]);
},
function getAtomVersion() {
return utils.customGenericVersionFunction(() => getDarwinApplicationVersion('com.github.atom'));
}
getBashInfo: () => {
utils.log('trace', 'getBashInfo');
return Promise.all([
'Bash',
utils.run('bash --version').then(utils.findVersion),
utils.which('bash'),
]);
},
function getCPUInfo() {
return utils.customGenericVersionFunction(() => os.arch() + ' ' + os.cpus()[0].model, 'Unknown');
}
getPHPInfo: () => {
utils.log('trace', 'getPHPInfo');
return Promise.all(['PHP', utils.run('php -v').then(utils.findVersion), utils.which('php')]);
},
function getBashVersion() {
var bashVersion;
var bashPath;
try {
bashPath = which.sync('bash');
bashVersion = utils.run(`${bashPath} --version`).match(utils.versionRegex)[0];
} catch (error) {
bashVersion = 'Not Found';
}
return bashVersion;
}
getParallelsInfo: () => {
utils.log('trace', 'getParallelsInfo');
return Promise.all([
'Parallels',
utils.run('prlctl --version').then(utils.findVersion),
utils.which('prlctl'),
]);
},
function getPhpVersion() {
return utils.customGenericVersionFunction(() => utils.run('php -v').split(' ', 2)[1]);
}
getDockerInfo: () => {
utils.log('trace', 'getDockerInfo');
return Promise.all([
'Docker',
utils.run('docker --version').then(utils.findVersion),
utils.which('docker'),
]);
},
function getParallelsVersion() {
return utils.customGenericVersionFunction(
() => utils.run('prlctl --version').match(/[version]+\s([\d|.]+)/)[1]
);
}
getElixirInfo: () => {
utils.log('trace', 'getElixirInfo');
return Promise.all([
'Elixir',
utils.run('elixir --version').then(version => version.match(/[Elixir]+\s([\d+.[\d+|.]+)/)[1]),
utils.which('elixir'),
]);
},
function getDockerVersion() {
return utils.customGenericVersionFunction(() =>
utils.run('docker --version').replace('Docker version ', '')
);
}
getMemoryInfo: () => {
utils.log('trace', 'getMemoryInfo');
return Promise.all([
'Memory',
`${utils.toReadableBytes(os.freemem())} / ${utils.toReadableBytes(os.totalmem())}`,
]);
},
function getElixirVersion() {
return utils.customGenericVersionFunction(
() => /[Elixir]+\s([\d|.]+)/g.exec(utils.run('elixir --version'))[1]
);
}
getSublimeTextInfo: () => {
utils.log('trace', 'getSublimeTextInfo');
return Promise.all([
'Sublime Text',
utils.run('subl --version').then(version => utils.findVersion(version, /\d+/)),
utils.which('subl'),
]);
},
function getFreeMemory() {
return utils.toReadableBytes(os.freemem());
}
getHomeBrewInfo: () => {
utils.log('trace', 'getHomeBrewInfo');
var homeBrewVersion;
if (process.platform === 'darwin') {
homeBrewVersion = Promise.all([
'Homebrew',
utils.run('brew --version').then(utils.findVersion),
utils.which('brew'),
]);
} else homeBrewVersion = Promise.resolve('N/A');
return homeBrewVersion;
},
function getTotalMemory() {
return utils.toReadableBytes(os.totalmem());
}
getGoInfo: () => {
utils.log('trace', 'getGoInfo');
return Promise.all(['Go', utils.run('go version').then(utils.findVersion), utils.which('go')]);
},
function getSublimeTextVersion() {
return utils.customGenericVersionFunction(() => getDarwinApplicationVersion('com.sublimetext.3'));
}
getRubyInfo: () => {
utils.log('trace', 'getRubyInfo');
return Promise.all(['Ruby', utils.run('ruby -v').then(utils.findVersion), utils.which('ruby')]);
},
function getHomeBrewVersion() {
var homeBrewVersion;
if (process.platform === 'darwin') {
try {
homeBrewVersion = utils
.run('brew --version')
.replace('Homebrew ', '')
.split('\n', 1)
.join();
} catch (error) {
homeBrewVersion = 'Not Found';
}
} else homeBrewVersion = 'N/A';
return homeBrewVersion;
}
getNodeInfo: () => {
utils.log('trace', 'getNodeInfo');
return Promise.all([
'Node',
utils.run('node -v').then(v => v.replace('v', '')),
utils.which('node').then(utils.condensePath),
]);
},
function getGoVersion() {
return utils.customGenericVersionFunction(() =>
utils
.run('go version')
.replace('go version go', '')
.split(' ', 1)
.join()
);
}
getnpmInfo: () => {
utils.log('trace', 'getnpmInfo');
return Promise.all(['npm', utils.run('npm -v'), utils.which('npm').then(utils.condensePath)]);
},
function getRubyVersion() {
return utils.customGenericVersionFunction(() =>
utils
.run('ruby --version')
.replace('ruby ', '')
.split(' ', 1)
.join()
);
}
getShellInfo: () => {
utils.log('trace', 'getShellInfo');
return Promise.all([
'Shell',
utils.run(`${process.env.SHELL} --version`).then(utils.findVersion),
utils.which(process.env.SHELL),
]);
},
function getNodeVersion() {
return utils.customGenericVersionFunction(() => utils.run('node --version').replace('v', ''));
}
getOSInfo: () => {
utils.log('trace', 'getOSInfo');
return (process.platform === 'darwin'
? utils.run('sw_vers -productVersion ')
: Promise.resolve()
).then(version => {
let info = osName(os.platform(), os.release());
if (version) info += ` ${version}`;
return ['OS', info];
});
},
function getNpmVersion() {
return utils.customGenericVersionFunction(() => utils.run('npm -v'));
}
getWatchmanInfo: () => {
utils.log('trace', 'getWatchmanInfo');
return Promise.all([
'Watchman',
utils.which('watchman').then(watchmanPath => utils.run(watchmanPath + ' -v')),
utils.which('watchman'),
]);
},
function getShell(shellBinary) {
shellBinary = shellBinary || process.env.SHELL;
getVSCodeInfo: () => {
utils.log('trace', 'getVSCodeInfo');
return Promise.all([
'VSCode',
utils.run('code --version').then(utils.findVersion),
utils.which('code'),
]);
},
const shellVersion = utils.customGenericVersionFunction(
() => utils.run(`${shellBinary} --version`).match(utils.versionRegex)[0]
);
getVirtualBoxInfo: () => {
utils.log('trace', 'getVirtualBoxInfo');
return Promise.all([
'VirtualBox',
utils.run('vboxmanage --version').then(utils.findVersion),
utils.which('vboxmanage'),
]);
},
return (shellBinary && shellVersion && `${shellBinary} - ${shellVersion}`) || `¯\\_(ツ)_/¯`;
}
getVMwareFusionInfo: () => {
utils.log('trace', 'getVMwareFusionInfo');
return Promise.all([
'VMWare Fusion',
utils.getDarwinApplicationVersion('com.vmware.fusion'),
'N/A',
]);
},
function getOperatingSystemInfo() {
var operatingSystemInfo;
try {
operatingSystemInfo = osName(os.platform(), os.release());
getPythonInfo: () => {
utils.log('trace', 'getPythonInfo');
let pythonVersion;
let pythonPath;
try {
pythonPath = utils.runSync('which python');
pythonVersion = childProcess
.execFileSync(pythonPath, ['-c', 'import platform; print(platform.python_version());'])
.toString()
.replace(/(\r\n|\n|\r)/gm, '');
} catch (error) {
pythonVersion = 'Not Found';
}
return Promise.resolve(['Python', pythonVersion, pythonPath]);
},
getXcodeInfo: () => {
utils.log('trace', 'getXcodeInfo');
if (process.platform === 'darwin') {
operatingSystemInfo = operatingSystemInfo + ' ' + utils.run('sw_vers -productVersion ');
return Promise.all([
'Xcode',
utils
.which('xcodebuild')
.then(xcodePath => utils.run(xcodePath + ' -version'))
.then(version => `${utils.findVersion(version)} - ${version.split('Build version ')[1]}`),
utils.which('xcodebuild'),
]);
}
} catch (err) {
operatingSystemInfo += ' Unknown Version';
}
return operatingSystemInfo;
}
return Promise.resolve(['Xcode', 'N/A']);
},
function getWatchmanVersion() {
return utils.customGenericVersionFunction(
() => which.sync('watchman') && utils.run(which.sync('watchman') + ' --version')
);
}
getYarnInfo: () => {
utils.log('trace', 'getYarnInfo');
return Promise.all([
'Yarn',
utils.run('yarn -v'),
utils.which('yarn').then(utils.condensePath),
]);
},
function getVSCodeVersion() {
return utils.customGenericVersionFunction(() =>
utils
.run('code --version')
.split('\n', 1)
.join('')
);
}
getChromeInfo: () => {
utils.log('trace', 'getChromeInfo');
let chromeVersion;
if (process.platform === 'linux') {
try {
chromeVersion = utils.runSync('google-chrome --version').replace(/^.* ([^ ]*)/g, '$1');
} catch (err) {
chromeVersion = 'Not Found';
}
} else {
chromeVersion = utils.getDarwinApplicationVersion(utils.browserBundleIdentifiers.Chrome);
}
return Promise.all(['Chrome', chromeVersion, 'N/A']);
},
function getVirtualBoxVersion() {
return utils.customGenericVersionFunction(() => utils.run('vboxmanage --version'));
}
getChromeCanaryInfo: () => {
utils.log('trace', 'getChromeCanaryInfo');
const chromeCanaryVersion = utils.getDarwinApplicationVersion(
utils.browserBundleIdentifiers['Chrome Canary']
);
return Promise.all(['Chrome Canary', chromeCanaryVersion, 'N/A']);
},
function getVMwareVersion() {
return utils.customGenericVersionFunction(() => getDarwinApplicationVersion('com.vmware.fusion'));
}
getFirefoxDeveloperEditionInfo: () => {
utils.log('trace', 'getFirefoxDeveloperEditionInfo');
const firefoxDeveloperEdition = utils.getDarwinApplicationVersion(
utils.browserBundleIdentifiers['Firefox Developer Edition']
);
return Promise.all(['Firefox Developer Edition', firefoxDeveloperEdition, 'N/A']);
},
function getPythonVersion() {
var pythonVersion;
var pythonPath;
try {
pythonPath = utils.run('which python');
pythonVersion = childProcess
.execFileSync(pythonPath, ['-c', 'import platform; print(platform.python_version());'])
.toString()
.replace(/(\r\n|\n|\r)/gm, '');
} catch (error) {
pythonVersion = 'Not Found';
}
return pythonVersion;
}
getSafariTechnologyPreviewInfo: () => {
utils.log('trace', 'getSafariTechnologyPreviewInfo');
const safariTechnologyPreview = utils.getDarwinApplicationVersion(
utils.browserBundleIdentifiers['Safari Technology Preview']
);
return Promise.all(['Safari Technology Preview', safariTechnologyPreview, 'N/A']);
},
function getXcodeVersion() {
var xcodeVersion;
if (process.platform === 'darwin') {
var xcodePath = which.sync('xcodebuild');
try {
xcodeVersion =
xcodePath &&
utils
.run(xcodePath + ' -version')
.split('\n')
.join(' ');
} catch (err) {
xcodeVersion = 'Not Found';
}
} else {
xcodeVersion = 'N/A';
}
return xcodeVersion;
}
getSafariInfo: () => {
utils.log('trace', 'getSafariInfo');
const safariVersion = utils.getDarwinApplicationVersion(utils.browserBundleIdentifiers.Safari);
return Promise.all(['Safari', safariVersion, 'N/A']);
},
function getYarnVersion() {
return utils.customGenericVersionFunction(() => utils.run('yarn --version'));
}
function getChromeVersion() {
var chromeVersion;
if (process.platform === 'linux') {
try {
chromeVersion = utils.run('google-chrome --version').replace(/^.* ([^ ]*)/g, '$1');
} catch (err) {
chromeVersion = 'Not Found';
getFirefoxInfo: () => {
utils.log('trace', 'getFirefoxInfo');
var firefoxVersion;
if (process.platform === 'linux') {
try {
firefoxVersion = utils.runSync('firefox --version').replace(/^.* ([^ ]*)/g, '$1');
} catch (err) {
firefoxVersion = 'Not Found';
}
} else {
firefoxVersion = utils.getDarwinApplicationVersion(utils.browserBundleIdentifiers.Firefox);
}
} else {
chromeVersion = getDarwinApplicationVersion(browserBundleIdentifiers.Chrome);
}
return chromeVersion;
}
return Promise.all(['Firefox', firefoxVersion, 'N/A']);
},
function getFirefoxVersion() {
var firefoxVersion;
if (process.platform === 'linux') {
try {
firefoxVersion = utils.run('firefox --version').replace(/^.* ([^ ]*)/g, '$1');
} catch (err) {
firefoxVersion = 'Not Found';
getFirefoxNightlyInfo: () => {
utils.log('trace', 'getFirefoxNightlyInfo');
var firefoxNightlyVersion;
if (process.platform === 'linux') {
try {
firefoxNightlyVersion = utils
.runSync('firefox-trunk --version')
.replace(/^.* ([^ ]*)/g, '$1');
} catch (err) {
firefoxNightlyVersion = 'Not Found';
}
} else {
firefoxNightlyVersion = utils.getDarwinApplicationVersion(
utils.browserBundleIdentifiers['Firefox Nightly']
);
}
} else {
firefoxVersion = getDarwinApplicationVersion(browserBundleIdentifiers.Firefox);
}
return firefoxVersion;
}
function getFirefoxNightlyVersion() {
var firefoxNightlyVersion;
if (process.platform === 'linux') {
try {
firefoxNightlyVersion = utils.run('firefox-trunk --version').replace(/^.* ([^ ]*)/g, '$1');
} catch (err) {
firefoxNightlyVersion = 'Not Found';
}
} else {
firefoxNightlyVersion = getDarwinApplicationVersion(
browserBundleIdentifiers['Firefox Nightly']
);
}
return firefoxNightlyVersion;
}
module.exports = Object.assign(packages, {
browserBundleIdentifiers: browserBundleIdentifiers,
findDarwinApplication: findDarwinApplication,
generatePlistBuddyCommand: generatePlistBuddyCommand,
getAllAndroidSDKs: getAllAndroidSDKs,
getAlliOSSDKs: getAlliOSSDKs,
getAndroidStudioVersion: getAndroidStudioVersion,
getAtomVersion: getAtomVersion,
getBashVersion: getBashVersion,
getCPUInfo: getCPUInfo,
getDarwinApplicationVersion: getDarwinApplicationVersion,
getDockerVersion: getDockerVersion,
getElixirVersion: getElixirVersion,
getFreeMemory: getFreeMemory,
getGoVersion: getGoVersion,
getHomeBrewVersion: getHomeBrewVersion,
getNodeVersion: getNodeVersion,
getNpmVersion: getNpmVersion,
getOperatingSystemInfo: getOperatingSystemInfo,
getPhpVersion: getPhpVersion,
getParallelsVersion: getParallelsVersion,
getPythonVersion: getPythonVersion,
getRubyVersion: getRubyVersion,
getShell: getShell,
getSublimeTextVersion: getSublimeTextVersion,
getTotalMemory: getTotalMemory,
getVirtualBoxVersion: getVirtualBoxVersion,
getVMwareVersion: getVMwareVersion,
getVSCodeVersion: getVSCodeVersion,
getWatchmanVersion: getWatchmanVersion,
getXcodeVersion: getXcodeVersion,
getYarnVersion: getYarnVersion,
getChromeVersion: getChromeVersion,
getFirefoxVersion: getFirefoxVersion,
getFirefoxNightlyVersion: getFirefoxNightlyVersion,
return Promise.all(['Firefox Nightly', firefoxNightlyVersion, 'N/A']);
},
});
const glob = require('glob');
const path = require('path');
const utils = require('./utils');
function getAllPackageJsonPaths(packageGlob) {
if (packageGlob) return glob.sync(`node_modules/${packageGlob}/package.json`);
return glob.sync('node_modules/**/package.json');
}
function getPackageDuplicates(dependency, allPackageJsonPaths) {
const duplicates = allPackageJsonPaths
// filter by which dependency we are looking for
.filter(packagePath => {
return packagePath.includes(`/${dependency.name}/package.json`);
})
// map over each occurrence of that dependency in the tree
.map(packageJsonPath => {
var packageJson = utils.getPackageJsonByPath(packageJsonPath);
if (packageJson) return packageJson.version;
return false;
})
.filter(Boolean)
// remove duplicates
.reduce((p, c) => {
if (!p.includes(c)) p.push(c);
return p;
}, []);
// if there is more than one version found, push the duplicates
if (duplicates.length > 1) dependency.duplicates = duplicates;
return dependency;
}
function getPackageVersion(packageName) {
var name = packageName.trim();
var dependencyPackageJson = utils.getPackageJsonByName(name);
var installed = dependencyPackageJson ? dependencyPackageJson.version : 'Not Found';
return installed;
}
function packageReducer(list, dependency) {
const value = dependency.duplicates
? {
[dependency.name]: {
wanted: dependency.wanted,
installed: getPackageVersion(dependency.name),
duplicates: dependency.duplicates,
},
}
: {
[dependency.name]: {
wanted: dependency.wanted,
installed: getPackageVersion(dependency.name),
},
};
return Object.assign(list, value);
}
function getPackageFullTree(allPackageJsonPaths) {
return allPackageJsonPaths
.map(filePath => {
var packageJson = utils.getPackageJsonByPath(filePath);
return {
name: packageJson.name,
installed: packageJson.version,
};
})
.reduce((acc, val) => {
return Object.assign(acc, {
[val.name]: acc[val.name] ? acc[val.name].concat([val.installed]) : [val.installed],
});
}, {});
}
function mapTopLevelDependencies(dependency) {
return {
name: dependency[0],
wanted: dependency[1],
};
}
function mapFullPackageTree(dependency) {
return {
name: dependency[0],
installed: dependency[1],
};
}
function assignWantedVersion(dependency, topLevelDependencies) {
const idx = Object.keys(topLevelDependencies).indexOf(dependency.name);
if (idx > -1) {
return Object.assign(dependency, {
wanted: Object.values(topLevelDependencies)[idx],
});
}
return dependency;
}
function getPackageInfo(packages, options) {
function getnpmPackages(packages, options) {
utils.log('trace', 'getnpmPackages');
if (!options) options = {};
let packageGlob = null;
let tld = null;

@@ -119,98 +26,142 @@ if (typeof packages === 'string') {

}
// get the package.json files from the full tree for either option
const allPackageJsonPaths =
(packageGlob || options.duplicates || options.fullTree) && getAllPackageJsonPaths();
// get the globbed packages if the packageGlob is truthy
const globbedPackageJsonPaths = packageGlob && getAllPackageJsonPaths(packageGlob);
// load top level package.json for the dependencies
const packageJson = utils.getPackageJsonByPath('package.json') || {};
const topLevelDependencies = Object.assign(
{},
packageJson.devDependencies || {},
packageJson.dependencies || {}
);
const topLevelPackageNames = Object.keys(topLevelDependencies);
// filter the globbed paths by whats actually in your root package.json
const globbedTopLevelDependencies = (globbedPackageJsonPaths || []).filter(p => {
return topLevelPackageNames.includes(p.match(/(?:node_modules)\/(.+)\/(?:.*)/)[1]);
});
if (packageGlob) {
// --npmPackages "eslint-*" (--duplicates) (--fullTree)
// matches packages against given glob, optionally adding duplicates, or crawling the fullTree
return utils.sortObject(
Object.entries(
options.fullTree
? getPackageFullTree(globbedPackageJsonPaths)
: getPackageFullTree(globbedTopLevelDependencies)
return Promise.all([
'npmPackages',
utils
.getPackageJsonByPath('package.json')
.then(packageJson =>
Object.assign({}, packageJson.devDependencies || {}, packageJson.dependencies || {})
)
.map(options.fullTree ? mapFullPackageTree : mapTopLevelDependencies)
.map(d => assignWantedVersion(d, topLevelDependencies))
.map(d => (options.duplicates ? getPackageDuplicates(d, allPackageJsonPaths) : d))
.reduce(packageReducer, {})
);
}
if (Array.isArray(packages)) {
// --npmPackages minimist,which (--duplicates)
// only specified top level packages (with duplicates) with wanted and installed
return utils.sortObject(
Object.entries(topLevelDependencies)
.map(mapTopLevelDependencies)
.filter(d => packages.includes(d.name))
.map(d => (options.duplicates ? getPackageDuplicates(d, allPackageJsonPaths) : d))
.reduce(packageReducer, {})
);
}
if (typeof packages === 'boolean') {
// --npmPackages (--duplicates) (--fullTree)
// print all packages (with duplicates) with wanted and installed, optionally crawling full tree
return utils.sortObject(
Object.entries(
options.fullTree ? getPackageFullTree(allPackageJsonPaths) : topLevelDependencies
// determine which paths to get
.then(packageJsonDependencies => {
tld = packageJsonDependencies;
if (options.fullTree || options.duplicates || packageGlob) {
return utils.getAllPackageJsonPaths(packageGlob);
}
return Promise.resolve(
Object.keys(packageJsonDependencies || []).map(dep =>
path.join('node_modules', dep, 'package.json')
)
);
})
// filter by glob or selection
.then(packageJsonPaths => {
if ((packageGlob || typeof packages === 'boolean') && !options.fullTree) {
return Promise.resolve(
(packageJsonPaths || []).filter(p =>
Object.keys(tld || []).includes(p.split('/').slice(-2)[0])
)
);
}
if (Array.isArray(packages)) {
return Promise.resolve(
(packageJsonPaths || []).filter(p => packages.includes(p.split('/').slice(-2)[0]))
);
}
return Promise.resolve(packageJsonPaths);
})
.then(paths =>
Promise.all([
paths,
Promise.all(paths.map(filePath => utils.getPackageJsonByPath(filePath))),
])
)
.map(options.fullTree ? mapFullPackageTree : mapTopLevelDependencies)
.map(d => assignWantedVersion(d, topLevelDependencies))
.map(d => (options.duplicates ? getPackageDuplicates(d, allPackageJsonPaths) : d))
.reduce(packageReducer, {})
);
}
// conglomerate the data
.then(result => {
const paths = result[0];
const files = result[1];
return {};
return files.reduce((acc, d, idx) => {
// if the file is a test stub, or doesn't have a name, ignore it.
if (!d || !d.name) return acc;
// create object if its not already created
if (!acc[d.name]) acc[d.name] = {};
// set duplicates if flag set, if version not already there, && !== installed
if (options.duplicates) {
if (acc[d.name].installed && acc[d.name].installed !== d.version) {
utils.uniq(
(acc[d.name].duplicates = (acc[d.name].duplicates || []).concat(d.version))
);
}
}
// set the installed version, if its installed top level
if ((paths[idx].match(/node_modules/g) || []).length === 1)
acc[d.name].installed = d.version;
// if it is a top level dependency, get the wanted version
if (tld[d.name]) acc[d.name].wanted = tld[d.name];
return acc;
}, {});
})
.then(versions => utils.sortObject(versions)),
]);
}
function getNpmGlobalPackages(packages) {
function getnpmGlobalPackages(packages) {
utils.log('trace', 'getnpmGlobalPackages', packages);
let packageGlob = null;
if (typeof packages === 'string') {
packages = packages.split(',');
if (
// detect characters that are not allowed in npm names, but are in globs
// wont work if the exactly once glob @ is used by itself, because of npm namespacing
packages.includes('*') ||
packages.includes('?') ||
packages.includes('+') ||
packages.includes('!')
) {
packageGlob = packages;
} else {
packages = packages.split(',');
}
} else if (!Array.isArray(packages)) {
packages = true;
}
var npmGlobalPackages;
try {
npmGlobalPackages = utils.run('npm list -g --depth=0 --json');
npmGlobalPackages = JSON.parse(npmGlobalPackages);
} catch (error) {
if (error.stdout) npmGlobalPackages = JSON.parse(error.stdout.toString());
if (!npmGlobalPackages) return 'Not Found';
}
npmGlobalPackages = Object.entries(npmGlobalPackages.dependencies).reduce((acc, dep) => {
const name = dep[0];
const info = dep[1];
if (!Array.isArray(packages) || packages.some(p => p.toLowerCase() === name.toLowerCase()))
return Object.assign(acc, {
[name]: info.version,
});
return acc;
}, {});
return npmGlobalPackages;
return Promise.all([
'npmGlobalPackages',
utils
// get the location of the npm global node_modules
.run('npm get prefix --global')
// glob all of the package.json files in that directory
.then(
prefix =>
new Promise((resolve, reject) =>
glob(
// sub packageGlob in to only get globbed packages if not null
path.join(prefix, 'lib', 'node_modules', packageGlob || '*', 'package.json'),
(err, files) => {
if (!err) resolve(files);
reject(err);
}
)
)
)
.then(globResults =>
Promise.all(
globResults
// filter out package paths not in list provided in options
.filter(
globbedPath =>
typeof packages === 'boolean' ||
packageGlob !== null ||
packages.includes(globbedPath.split('/').slice(-2)[0])
)
// get all the package.json by path, return promises
.map(packageJson => utils.getPackageJsonByFullPath(packageJson))
)
)
// accumulate all the package info in one object.
.then(allPackages =>
allPackages.reduce(
(acc, json) => (json ? Object.assign(acc, { [json.name]: json.version }) : acc),
{}
)
),
]);
}
module.exports = {
getPackageInfo: getPackageInfo,
getNpmGlobalPackages: getNpmGlobalPackages,
getnpmPackages: getnpmPackages,
getnpmGlobalPackages: getnpmGlobalPackages,
};
module.exports = {
defaults: {
System: ['OS', 'CPU', 'Memory', 'Shell', 'derp'],
Binaries: ['Node', 'Yarn', 'npm', 'Watchman'],
Virtualization: ['Docker', 'Parallels', 'VirtualBox', 'VMware Fusion'],
SDKs: ['iOS SDK', 'Android SDK'],
IDEs: ['Android Studio', 'Atom', 'VSCode', 'Sublime Text', 'Xcode'],
Languages: ['Bash', 'Go', 'Elixir', 'PHP', 'Python', 'Ruby'],
Browsers: [
'Chrome',
'Chrome Canary',
'Firefox',
'Firefox Developer Edition',
'Firefox Nightly',
'Safari',
'Safari Technology Preview',
],
npmPackages: null,
npmGlobalPackages: null,
},
jest: {

@@ -3,0 +22,0 @@ System: ['OS', 'CPU'],

@@ -1,102 +0,181 @@

var path = require('path');
var fs = require('fs');
var childProcess = require('child_process');
const path = require('path');
const fs = require('fs');
const childProcess = require('child_process');
const libWhich = require('which');
const glob = require('glob');
function run(cmd) {
return (
childProcess
.execSync(cmd, {
const run = cmd => {
return new Promise(resolve => {
childProcess.exec(
cmd,
{
stdio: [0, 'pipe', 'ignore'],
})
.toString() || ''
).trim();
}
},
(err, out) => {
resolve((err ? '' : out.toString() || '').trim());
}
);
});
};
function customGenericVersionFunction(fn, msg) {
if (msg === undefined) msg = 'Not Found';
var version;
try {
version = fn();
} catch (error) {
version = msg;
}
return version;
}
const log = function log(level) {
const args = Object.values(Array.prototype.slice.call(arguments).slice(1)).join(', ');
if ((process.env.ENVINFO_DEBUG || '').toLowerCase() === level) console.log(level, args);
};
function uniq(arr) {
return Array.from(new Set(arr)); // eslint-disable-line no-undef
}
const fileExists = filePath => {
return new Promise(resolve => {
fs.stat(filePath, err => (err ? resolve(null) : resolve(filePath)));
});
};
function toReadableBytes(bytes) {
const i = Math.floor(Math.log(bytes) / Math.log(1024));
return (
(!bytes && '0 Bytes') ||
(bytes / Math.pow(1024, i)).toFixed(2) + ' ' + ['B', 'KB', 'MB', 'GB', 'TB', 'PB'][i]
const readFile = filePath => {
return new Promise(fileResolved => {
if (!filePath) fileResolved(null);
fs.readFile(filePath, 'utf8', (err, file) => (file ? fileResolved(file) : fileResolved(null)));
});
};
const requireJson = filePath => {
return fileExists(filePath)
.then(readFile)
.then(file => (file ? JSON.parse(file) : null));
};
const versionRegex = /\d+\.[\d+|.]+/;
const findDarwinApplication = id => {
return run('mdfind "kMDItemCFBundleIdentifier=="' + id + '""').then(v =>
v.replace(/(\s)/g, '\\ ')
);
}
};
function omit(obj, props) {
return Object.keys(obj)
.filter(key => props.indexOf(key) < 0)
.reduce((acc, key) => Object.assign(acc, { [key]: obj[key] }), {});
}
const generatePlistBuddyCommand = (appPath, options) => {
var optionsArray = (options || ['CFBundleShortVersionString']).map(function optionsMap(option) {
return '-c Print:' + option;
});
return ['/usr/libexec/PlistBuddy']
.concat(optionsArray)
.concat([appPath])
.join(' ');
};
function pick(obj, props) {
return Object.keys(obj)
.filter(key => props.indexOf(key) >= 0)
.reduce((acc, key) => Object.assign(acc, { [key]: obj[key] }), {});
}
module.exports = {
run: run,
log: log,
fileExists: fileExists,
readFile: readFile,
requireJson: requireJson,
versionRegex: versionRegex,
findDarwinApplication: findDarwinApplication,
generatePlistBuddyCommand: generatePlistBuddyCommand,
const isObject = val => typeof val === 'object' && !Array.isArray(val);
const pipe = fns => x => fns.reduce((v, f) => f(v), x);
isObject: val => typeof val === 'object' && !Array.isArray(val),
noop: d => d,
pipe: fns => x => fns.reduce((v, f) => f(v), x),
function requireJson(filePath) {
var packageJson;
if (fs.existsSync(filePath)) {
try {
packageJson = JSON.parse(fs.readFileSync(filePath, 'utf8'));
} catch (e) {
return null;
browserBundleIdentifiers: {
Chrome: 'com.google.Chrome',
'Chrome Canary': 'com.google.Chrome.canary',
Firefox: 'org.mozilla.firefox',
'Firefox Developer Edition': 'org.mozilla.firefoxdeveloperedition',
'Firefox Nightly': 'org.mozilla.nightly',
Safari: 'com.apple.Safari',
'Safari Technology Preview': 'com.apple.SafariTechnologyPreview',
},
runSync: cmd => {
return (
childProcess
.execSync(cmd, {
stdio: [0, 'pipe', 'ignore'],
})
.toString() || ''
).trim();
},
which: binary => {
return new Promise(resolve => libWhich(binary, (err, binaryPath) => resolve(binaryPath)));
},
getDarwinApplicationVersion: bundleIdentifier => {
var version;
if (process.platform !== 'darwin') {
version = 'N/A';
} else {
version = findDarwinApplication(bundleIdentifier).then(appPath =>
run(
generatePlistBuddyCommand(path.join(appPath, 'Contents', 'Info.plist'), [
'CFBundleShortVersionString',
])
)
);
}
return packageJson;
}
return null;
}
return Promise.resolve(version);
},
function getPackageJsonByName(dep) {
return this.requireJson(path.join(process.cwd(), 'node_modules', dep, 'package.json'));
}
uniq: arr => {
return Array.from(new Set(arr)); // eslint-disable-line no-undef
},
function getPackageJsonByPath(filePath) {
return this.requireJson(path.join(process.cwd(), filePath));
}
toReadableBytes: bytes => {
const i = Math.floor(Math.log(bytes) / Math.log(1024));
return (
(!bytes && '0 Bytes') ||
(bytes / Math.pow(1024, i)).toFixed(2) + ' ' + ['B', 'KB', 'MB', 'GB', 'TB', 'PB'][i]
);
},
const noop = d => d;
omit: (obj, props) => {
return Object.keys(obj)
.filter(key => props.indexOf(key) < 0)
.reduce((acc, key) => Object.assign(acc, { [key]: obj[key] }), {});
},
function sortObject(obj) {
return Object.keys(obj)
.sort()
.reduce((acc, val) => {
acc[val] = obj[val];
return acc;
}, {});
}
pick: (obj, props) => {
return Object.keys(obj)
.filter(key => props.indexOf(key) >= 0)
.reduce((acc, key) => Object.assign(acc, { [key]: obj[key] }), {});
},
const versionRegex = /\d+\.[\d+|\.]+/;
getPackageJsonByName: name => {
return requireJson(path.join(process.cwd(), 'node_modules', name, 'package.json'));
},
module.exports = {
customGenericVersionFunction: customGenericVersionFunction,
getPackageJsonByName: getPackageJsonByName,
getPackageJsonByPath: getPackageJsonByPath,
isObject: isObject,
noop: noop,
omit: omit,
pick: pick,
pipe: pipe,
requireJson: requireJson,
run: run,
sortObject: sortObject,
toReadableBytes: toReadableBytes,
uniq: uniq,
versionRegex: versionRegex,
getPackageJsonByPath: filePath => {
return requireJson(path.join(process.cwd(), filePath));
},
getPackageJsonByFullPath: fullPath => {
log('trace', 'getPackageJsonByFullPath', fullPath);
return requireJson(fullPath);
},
getAllPackageJsonPaths: packageGlob => {
log('trace', 'getAllPackageJsonPaths', packageGlob);
return new Promise(resolve => {
const cb = (err, res) => resolve(res || []);
if (packageGlob) return glob(path.join('node_modules', packageGlob, 'package.json'), cb);
return glob(path.join('node_modules', '**', 'package.json'), cb);
});
},
sortObject: obj => {
return Object.keys(obj)
.sort()
.reduce((acc, val) => {
acc[val] = obj[val];
return acc;
}, {});
},
findVersion: (versionString, regex) => {
const matcher = regex || versionRegex;
const matched = versionString.match(matcher);
return matched ? matched[0] : versionString;
},
condensePath: pathString => {
return pathString.replace(process.env.HOME, '~');
},
};

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Packages

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc