Last active
December 6, 2020 10:55
-
-
Save jart/0fbfb3a17ce1163882e317b598b31b8a to your computer and use it in GitHub Desktop.
NPM Dependency Calculator
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# NPM Dependency Calculator | |
# | |
# Author: Justine Tunney <jart@google.com> | |
# Last Updated: 2016-09-22 | |
# | |
# This is a .bashrc addition that lets you inspect the transitive closure of | |
# dependencies for an NPM package. It does not require NPM or node.js to be | |
# installed on your system. It takes into consideration the fact that NPM | |
# does not resolve diamond dependencies. It goes super fast. | |
# | |
# This tool is useful because NPM packages have a ridiculous number of | |
# dependencies. It's not uncommon for a modern web app written with Node | |
# tooling to have thousands of dependencies. And they're all written by | |
# random people on the Internet. Even if these people had best intentions, | |
# NPM doesn't support two-factor authentication, checksums, or signatures. | |
# It only started using HTTPS a few months ago. | |
# | |
# Take for instance Express, which is a commonly used web framework in the | |
# Node.js community. It markets itself as the "Fast, unopinionated, | |
# minimalist web framework" but it actually has 42 dependencies: | |
# | |
# $ npm-transitive-deps express | wc -l | |
# 43 | |
# | |
# If we were considering using Express for our project, we would also need | |
# to know what licenses all these dependencies have: | |
# | |
# $ npm-transitive-licenses express | |
# bsd-3-clause | |
# isc | |
# mit | |
npm-info() { | |
local usage="Usage: ${FUNCNAME} NAME [VERSION]" | |
local name="${1:?${usage}}" | |
local version="${2:-latest}" | |
local cachedir="${HOME}/.npm-json" | |
local cache="" | |
if [[ "${name}" =~ ^@ ]]; then | |
# TODO(jart): How do we fetch these weird scoped packages? | |
echo "{}" | |
return | |
fi | |
if [[ -e "${cachedir}/${name}-${version}.json" ]]; then | |
cat "${cachedir}/${name}-${version}.json" | |
else | |
mkdir -p "${cachedir}/tmp" || return 1 | |
local tmp | |
tmp="$(mktemp ${cachedir}/tmp/${FUNCNAME}.XXXXXXXXXX)" || return 1 | |
printf "\e[35mfetching https://registry.npmjs.org/%s/%s\e[0m\n" "${name}" "${version}" >&2 | |
curl -s "https://registry.npmjs.org/${name}/${version}" \ | |
| json-pretty >"${tmp}" | |
if [[ "${PIPESTATUS[0]}" -ne 0 || "${PIPESTATUS[1]}" -ne 0 ]]; then | |
rm -f "${tmp}" | |
return 1 | |
else | |
local real_version | |
real_version="$(json-get version <"${tmp}")" || return 1 | |
cat "${tmp}" | |
mv -f "${tmp}" "${cachedir}/${name}-${real_version}.json" | |
if [[ "${version}" != "${real_version}" ]]; then | |
ln -sf "${name}-${real_version}.json" \ | |
"${cachedir}/${name}-${version}.json" | |
fi | |
fi | |
fi | |
} | |
npm-transitive-deps() { | |
local usage="Usage: ${FUNCNAME} NAME [VERSION]" | |
local name="${1:?${usage}}" | |
local version="${2:-latest}" | |
version="$(npm-info "${name}" "${version}" | json-get version)" || return 1 | |
( | |
echo "${name} ${version}" | |
while read iname iversion a b c; do | |
npm-transitive-deps "${iname}" "${iversion}${a}${b}${c}" & | |
done < <(npm-info "${name}" "${version}" \ | |
| json-get dependencies \ | |
| json-keyvalues) | |
wait | |
) | sort -u | |
} | |
npm-transitive-licenses() { | |
local usage="Usage: ${FUNCNAME} NAME [VERSION]" | |
local name="${1:?${usage}}" | |
local version="${2:-latest}" | |
( | |
while read name version; do | |
npm-info "${name}" "${version}" \ | |
| json-get license \ | |
| tr \ A-Z _a-z | |
done < <(npm-transitive-deps "${name}" "${version}") | |
) | sort -u | |
} | |
npm-transitive-maintainers() { | |
local usage="Usage: ${FUNCNAME} NAME [VERSION]" | |
local name="${1:?${usage}}" | |
local version="${2:-latest}" | |
( | |
while read name version; do | |
npm-info "${name}" "${version}" \ | |
| json-get maintainers \ | |
| tr \ A-Z _a-z | |
done < <(npm-transitive-deps "${name}" "${version}") | |
) | sort -u | |
} | |
typescript-dependencies() { | |
( | |
npm-transitive-deps clang-format '^1.0.45' & | |
npm-transitive-deps typescript '^2.0.0' & | |
wait | |
) | sort -u | |
} | |
tensorboard-dependencies() { | |
( | |
npm-transitive-deps browserify '^13.1.0' & | |
npm-transitive-deps gulp '~3.9.0' & | |
npm-transitive-deps gulp-bower '0.0.13' & | |
npm-transitive-deps gulp-clean-compiled-typescript '~1.0.1' & | |
npm-transitive-deps gulp-cli '^1.1.0' & | |
npm-transitive-deps gulp-concat '^2.6.0' & | |
npm-transitive-deps gulp-filter '~3.0.1' & | |
npm-transitive-deps gulp-header '~1.7.1' & | |
npm-transitive-deps gulp-rename '~1.2.2' & | |
npm-transitive-deps gulp-replace '~0.5.4' & | |
npm-transitive-deps gulp-server-livereload '~1.5.4' & | |
npm-transitive-deps gulp-tslint '~4.2.2' & | |
npm-transitive-deps gulp-typescript '~2.10.0' & | |
npm-transitive-deps gulp-util '~3.0.7' & | |
npm-transitive-deps gulp-vulcanize '~6.1.0' & | |
npm-transitive-deps merge2 '~0.3.6' & | |
npm-transitive-deps minimist '~1.2.0' & | |
npm-transitive-deps tsify '^0.14.8' & | |
npm-transitive-deps tslint '^3.2.1' & | |
npm-transitive-deps typescript '^2.0.0' & | |
npm-transitive-deps typings '~1.0.4' & | |
npm-transitive-deps vinyl-source-stream '^1.1.0' & | |
npm-transitive-deps vulcanize '^1.14.0' & | |
npm-transitive-deps web-component-tester '4.2.2' & | |
wait | |
) | sort -u | |
} | |
json-get() { | |
local usage="Usage: ${FUNCNAME} KEY" | |
local key="${1:?${usage}}" | |
python -c " | |
import json, sys | |
try: | |
blob = json.load(sys.stdin) | |
if blob and isinstance(blob, dict) and '${key}' in blob: | |
x = blob['${key}'] | |
if isinstance(x, list) or isinstance(x, dict): | |
json.dump(x, sys.stdout) | |
else: | |
print x | |
except ValueError: | |
pass" | |
} | |
json-keys() { | |
python -c " | |
import json, sys | |
try: | |
blob = json.load(sys.stdin) | |
if blob and isinstance(blob, dict): | |
print '\n'.join(blob.keys()) | |
except ValueError: | |
pass" | |
} | |
json-keyvalues() { | |
python -c " | |
import json, sys | |
try: | |
blob = json.load(sys.stdin) | |
if blob and isinstance(blob, dict): | |
for k, v in blob.items(): | |
print k, v | |
except ValueError: | |
pass" | |
} | |
json-pretty() { | |
python -c ' | |
import json, sys | |
try: | |
json.dump(json.load(sys.stdin), sys.stdout, indent=2) | |
except ValueError: | |
pass' | |
} |
Theo de Raadt is trying to leverage the safety and security of the OpenBSD community by WIN32'ing binary interfaces. https://lwn.net/Articles/806776/ Go see what they're doing since that's a better place to probably get what you want.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
How can I use this? I'm new to linux.