diff options
author | Ruy Adorno <ruyadorno@hotmail.com> | 2020-05-08 23:54:48 +0300 |
---|---|---|
committer | Ruy Adorno <ruyadorno@hotmail.com> | 2020-06-12 20:55:38 +0300 |
commit | a16f172d1a9299965bb52ba7162caa48fefca95e (patch) | |
tree | 05ad2a7d612d3209a191885ec9e1d8e25eaf5c1f /node_modules/libnpmfund | |
parent | d7397ba6f5d66c02a23787f00196ce8d410e7c1c (diff) |
chore: arborist fund cmd refactor
- npm fund cmd:
- no longer depends on `lib/install` modules
- now it uses arborist tree and inventory to retrieve funding data
- refactor to use same exports patterns to new commands
- changed human output to reinstate representation of nested deps
- install:
- no longer breaks on missing audit report
- refactored `reify-output` to use `libnpmfund` module
- added tests for utils.reify-output fund summary
- moved logic from `lib/utils/funding.js` into a new `libnpmfund` pkg
PR-URL: https://github.com/npm/cli/pull/1311
Credit: @ruyadorno
Close: #1311
Reviewed-by: @darcyclarke
Diffstat (limited to 'node_modules/libnpmfund')
-rw-r--r-- | node_modules/libnpmfund/CHANGELOG.md | 6 | ||||
-rw-r--r-- | node_modules/libnpmfund/LICENSE | 15 | ||||
-rw-r--r-- | node_modules/libnpmfund/README.md | 129 | ||||
-rw-r--r-- | node_modules/libnpmfund/index.js | 183 | ||||
-rw-r--r-- | node_modules/libnpmfund/package.json | 87 |
5 files changed, 420 insertions, 0 deletions
diff --git a/node_modules/libnpmfund/CHANGELOG.md b/node_modules/libnpmfund/CHANGELOG.md new file mode 100644 index 000000000..b890b58e1 --- /dev/null +++ b/node_modules/libnpmfund/CHANGELOG.md @@ -0,0 +1,6 @@ +# Changelog + +## 0.0.0-pre.0 + +- Initial pre-release. + diff --git a/node_modules/libnpmfund/LICENSE b/node_modules/libnpmfund/LICENSE new file mode 100644 index 000000000..dedcd7d2f --- /dev/null +++ b/node_modules/libnpmfund/LICENSE @@ -0,0 +1,15 @@ +The ISC License + +Copyright (c) npm Inc. + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR +IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/node_modules/libnpmfund/README.md b/node_modules/libnpmfund/README.md new file mode 100644 index 000000000..c373a9ceb --- /dev/null +++ b/node_modules/libnpmfund/README.md @@ -0,0 +1,129 @@ +# libnpmfund + +[![npm version](https://img.shields.io/npm/v/libnpmfund.svg)](https://npm.im/libnpmfund) +[![license](https://img.shields.io/npm/l/libnpmfund.svg)](https://npm.im/libnpmfund) +[![GitHub Actions](https://github.com/npm/libnpmfund/workflows/node-ci/badge.svg)](https://github.com/npm/libnpmfund/actions?query=workflow%3Anode-ci) +[![Coverage Status](https://coveralls.io/repos/github/npm/libnpmfund/badge.svg?branch=master)](https://coveralls.io/github/npm/libnpmfund?branch=master) + +[`libnpmfund`](https://github.com/npm/libnpmfund) is a Node.js library for +retrieving **funding** information for packages installed using +[`arborist`](https://github.com/npm/arborist). + +## Table of Contents + +* [Example](#example) +* [Install](#install) +* [Contributing](#contributing) +* [API](#api) +* [LICENSE](#license) + +## Example + +```js +const { read } = require('libnpmfund') + +const fundingInfo = await read() +console.log( + JSON.stringify(fundingInfo, null, 2) +) +// => { + length: 2, + name: 'foo', + version: '1.0.0', + funding: { url: 'https://example.com' }, + dependencies: { + bar: { + version: '1.0.0', + funding: { url: 'http://collective.example.com' } + } + } +} +``` + +## Install + +`$ npm install libnpmfund` + +### Contributing + +The npm team enthusiastically welcomes contributions and project participation! +There's a bunch of things you can do if you want to contribute! The +[Contributor Guide](https://github.com/npm/cli/blob/latest/CONTRIBUTING.md) +outlines the process for community interaction and contribution. Please don't +hesitate to jump in if you'd like to, or even ask us questions if something +isn't clear. + +All participants and maintainers in this project are expected to follow the +[npm Code of Conduct](https://www.npmjs.com/policies/conduct), and just +generally be excellent to each other. + +Please refer to the [Changelog](CHANGELOG.md) for project history details, too. + +Happy hacking! + +### API + +##### <a name="fund.read"></a> `> fund.read([opts]) -> Promise<Object>` + +Reads **funding** info from a npm install and returns a promise for a +tree object that only contains packages in which funding info is defined. + +Options: + +- `countOnly`: Uses the tree-traversal logic from **npm fund** but skips over +any obj definition and just returns an obj containing `{ length }` - useful for +things such as printing a `6 packages are looking for funding` msg. +- `path`: Location to current working directory + +##### <a name="fund.readTree"></a> `> fund.readTree(tree, [opts]) -> Promise<Object>` + +Reads **funding** info from a given install tree and returns a tree object +that only contains packages in which funding info is defined. + +- `tree`: An [`arborist`](https://github.com/npm/arborist) tree to be used, e.g: + +```js +const Arborist = require('@npmcli/arborist') +const { readTree } = require('libnpmfund') + +const arb = new Arborist({ path: process.cwd() }) +const tree = await arb.loadActual() + +return readTree(tree, { countOnly: false }) +``` + +Options: + +- `countOnly`: Uses the tree-traversal logic from **npm fund** but skips over +any obj definition and just returns an obj containing `{ length }` - useful for +things such as printing a `6 packages are looking for funding` msg. + +##### <a name="fund.normalizeFunding"></a> `> fund.normalizeFunding(funding) -> Object` + +From a `funding` `<object|string|array>`, retrieves normalized funding objects +containing a `url` property. + +e.g: + +```js +normalizeFunding('http://example.com') +// => { + url: 'http://example.com' +} +``` + +##### <a name="fund.isValidFunding"></a> `> fund.isValidFunding(funding) -> Boolean` + +Returns `<true>` if `funding` is a valid funding object, e.g: + +```js +isValidFunding({ foo: 'not a valid funding obj' }) +// => false + +isValidFunding('http://example.com') +// => true +``` + +## LICENSE + +[ISC](./LICENSE) diff --git a/node_modules/libnpmfund/index.js b/node_modules/libnpmfund/index.js new file mode 100644 index 000000000..58aba028e --- /dev/null +++ b/node_modules/libnpmfund/index.js @@ -0,0 +1,183 @@ +'use strict' + +const URL = require('url').URL +const Arborist = require('@npmcli/arborist') + +// supports object funding and string shorthand, or an array of these +// if original was an array, returns an array; else returns the lone item +function normalizeFunding (funding) { + const normalizeItem = item => + typeof item === 'string' ? { url: item } : item + const sources = [].concat(funding || []).map(normalizeItem) + return Array.isArray(funding) ? sources : sources[0] +} + +// Is the value of a `funding` property of a `package.json` +// a valid type+url for `npm fund` to display? +function isValidFunding (funding) { + if (!funding) return false + + if (Array.isArray(funding)) { + return funding.every(f => !Array.isArray(f) && isValidFunding(f)) + } + + try { + var parsed = new URL(funding.url || funding) + } catch (error) { + return false + } + + if ( + parsed.protocol !== 'https:' && + parsed.protocol !== 'http:' + ) return false + + return Boolean(parsed.host) +} + +const empty = () => Object.create(null) + +function readTree (tree, opts) { + let packageWithFundingCount = 0 + const seen = new Set() + const { countOnly } = opts || {} + const _trailingDependencies = Symbol('trailingDependencies') + + function tracked (name, version) { + const key = String(name) + String(version) + if (seen.has(key)) { + return true + } + seen.add(key) + } + + function retrieveDependencies (dependencies) { + const trailing = dependencies[_trailingDependencies] + + if (trailing) { + return Object.assign( + empty(), + dependencies, + trailing + ) + } + + return dependencies + } + + function hasDependencies (dependencies) { + return dependencies && ( + Object.keys(dependencies).length || + dependencies[_trailingDependencies] + ) + } + + function attachFundingInfo (target, funding) { + if (funding && isValidFunding(funding)) { + target.funding = normalizeFunding(funding) + packageWithFundingCount++ + } + } + + function getFundingDependencies (tree) { + const edges = tree && tree.edgesOut && tree.edgesOut.values() + if (!edges) return empty() + + const directDepsWithFunding = Array.from(edges).map(edge => { + if (!edge || !edge.to) return empty() + + const node = edge.to.target || edge.to + if (!node.package) return empty() + + const { name, funding, version } = node.package + + // avoids duplicated items within the funding tree + if (tracked(name, version)) return empty() + + const fundingItem = {} + + if (version) { + fundingItem.version = version + } + + attachFundingInfo(fundingItem, funding) + + return { + node, + fundingItem + } + }) + + return directDepsWithFunding.reduce( + (res, { node, fundingItem }, i) => { + if (!fundingItem || + fundingItem.length === 0 || + !node) return res + + // recurse + const transitiveDependencies = node.edgesOut && + node.edgesOut.size > 0 && + getFundingDependencies(node) + + // if we're only counting items there's no need + // to add all the data to the resulting object + if (countOnly) return null + + if (hasDependencies(transitiveDependencies)) { + fundingItem.dependencies = + retrieveDependencies(transitiveDependencies) + } + + if (isValidFunding(fundingItem.funding)) { + res[node.package.name] = fundingItem + } else if (hasDependencies(fundingItem.dependencies)) { + res[_trailingDependencies] = + Object.assign( + empty(), + res[_trailingDependencies], + fundingItem.dependencies + ) + } + + return res + }, countOnly ? null : empty()) + } + + const treeDependencies = getFundingDependencies(tree) + const result = { + length: packageWithFundingCount + } + + if (!countOnly) { + const name = + (tree && tree.package && tree.package.name) || + (tree && tree.name) + result.name = name || (tree && tree.path) + + if (tree && tree.package && tree.package.version) { + result.version = tree.package.version + } + + if (tree && tree.package && tree.package.funding) { + result.funding = normalizeFunding(tree.package.funding) + } + + result.dependencies = retrieveDependencies(treeDependencies) + } + + return result +} + +async function read (opts) { + const arb = new Arborist(opts) + const tree = await arb.loadActual() + + return readTree(tree, opts) +} + +module.exports = { + read, + readTree, + normalizeFunding, + isValidFunding +} diff --git a/node_modules/libnpmfund/package.json b/node_modules/libnpmfund/package.json new file mode 100644 index 000000000..dc48e96ca --- /dev/null +++ b/node_modules/libnpmfund/package.json @@ -0,0 +1,87 @@ +{ + "_from": "libnpmfund@latest", + "_id": "libnpmfund@0.0.0-pre.2", + "_inBundle": false, + "_integrity": "sha512-wVOjSwimVZguGMZp7Tx/XMln2CDVj8WZyxTZfED5iOCudEqAVAtnElQTbDCip1CN97uFhVugUao1WjV4bvRHjg==", + "_location": "/libnpmfund", + "_phantomChildren": {}, + "_requested": { + "type": "tag", + "registry": true, + "raw": "libnpmfund@latest", + "name": "libnpmfund", + "escapedName": "libnpmfund", + "rawSpec": "latest", + "saveSpec": null, + "fetchSpec": "latest" + }, + "_requiredBy": [ + "#USER", + "/" + ], + "_resolved": "https://registry.npmjs.org/libnpmfund/-/libnpmfund-0.0.0-pre.2.tgz", + "_shasum": "437aea7f4bb62d3d4aa99eada6fd7f59f2007eb2", + "_spec": "libnpmfund@latest", + "_where": "/Users/ruyadorno/Documents/workspace/cli", + "author": { + "name": "npm Inc.", + "email": "support@npmjs.com" + }, + "bugs": { + "url": "https://github.com/npm/libnpmfund/issues" + }, + "bundleDependencies": false, + "contributors": [ + { + "name": "Ruy Adorno", + "url": "https://ruyadorno.com" + } + ], + "dependencies": { + "@npmcli/arborist": "0.0.0-pre.20" + }, + "deprecated": false, + "description": "Programmatic API for npm fund", + "devDependencies": { + "require-inject": "^1.4.4", + "standard": "^14.3.4", + "tap": "^14.10.7" + }, + "files": [ + "index.js" + ], + "homepage": "https://github.com/npm/libnpmfund#readme", + "keywords": [ + "npm", + "npmcli", + "libnpm", + "cli", + "git", + "fund", + "gitfund" + ], + "license": "ISC", + "name": "libnpmfund", + "repository": { + "type": "git", + "url": "git+https://github.com/npm/libnpmfund.git" + }, + "scripts": { + "lint": "standard", + "postversion": "npm publish", + "prepublishOnly": "git push origin --follow-tags", + "pretest": "npm run lint", + "preversion": "npm test", + "snap": "tap", + "test": "tap" + }, + "standard": { + "ignore": [ + "/tap-snapshots/" + ] + }, + "tap": { + "check-coverage": true + }, + "version": "0.0.0-pre.2" +} |