From 1481bf62689ef6607b8e5d72fd16c3df38af506e Mon Sep 17 00:00:00 2001 From: Siem Lasseel Date: Wed, 6 Sep 2023 11:29:59 +0200 Subject: [PATCH] feat: use node module resolution to find packages --- dist/index.js | 17 ++++++++--------- dist/packageUtils.js | 25 +++++++++++++++++-------- dist/util.js | 11 ++++++----- dist/whitelist.js | 14 -------------- package.json | 2 +- src/index.ts | 11 +++++------ src/packageUtils.ts | 32 +++++++++++++++++++++++++++----- src/util.ts | 11 ++++++----- 8 files changed, 70 insertions(+), 53 deletions(-) delete mode 100644 dist/whitelist.js diff --git a/dist/index.js b/dist/index.js index f5eda60..02060e1 100644 --- a/dist/index.js +++ b/dist/index.js @@ -1,22 +1,21 @@ #! /usr/bin/env node "use strict"; -var _fs = _interopRequireDefault(require("fs")); +var _promises = _interopRequireDefault(require("fs/promises")); var _path = _interopRequireDefault(require("path")); -var _util = require("util"); var _licenseUtils = require("./licenseUtils"); -var _util2 = require("./util"); +var _util = require("./util"); var _packageUtils = require("./packageUtils"); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } async function readFromLicenseFile(basePath) { - const matches = await (0, _util.promisify)(_fs.default.readdir)(basePath); + const matches = await _promises.default.readdir(basePath); const validLicenseFiles = matches.filter(match => match.toUpperCase().startsWith('LICENSE')); if (validLicenseFiles.length < 1) { console.log(`No valid license files found in ${basePath}`); return null; } const licenseFile = _path.default.join(basePath, validLicenseFiles[0]); - const contents = (await (0, _util.promisify)(_fs.default.readFile)(licenseFile)).toString(); + const contents = (await _promises.default.readFile(licenseFile)).toString(); const file = licenseFile.split('node_modules/')[1]; return { file, @@ -46,7 +45,7 @@ async function getPackageDetails(dep) { }; } (async () => { - const flags = (0, _util2.parseCLIFlags)(process.argv); + const flags = (0, _util.parseCLIFlags)(process.argv); let [dependencies, devDependencies] = await (0, _packageUtils.getDependencies)(Boolean(flags.includeDev)); if (devDependencies !== null) { dependencies = [...dependencies, ...devDependencies]; @@ -54,7 +53,7 @@ async function getPackageDetails(dep) { if (flags.exclude) { if (Array.isArray(flags.exclude) && flags.exclude.length > 1) { // Get a diff between excluded and current if multiple provided - dependencies = (0, _util2.diff)(dependencies, flags.exclude); + dependencies = (0, _util.diff)(dependencies, flags.exclude); } else if (typeof flags.exclude === 'string') { // If only one dependency provided, exclude it from current dependencies dependencies = dependencies.filter(dep => dep !== flags.exclude); @@ -66,12 +65,12 @@ async function getPackageDetails(dep) { if (flags.export) { if (typeof flags.export === 'string') { const filename = _path.default.join(process.cwd(), flags.export); - (0, _util.promisify)(_fs.default.writeFile)(filename, `${JSON.stringify(resolvedDeps, null, 2)}\n`); + _promises.default.writeFile(filename, `${JSON.stringify(resolvedDeps, null, 2)}\n`); console.log(`Licenses exported to ${filename}`); } else if (typeof flags.export === 'boolean') { // Export to default licenses.json if no exported file name provided const filename = _path.default.join(process.cwd(), 'licenses.json'); - (0, _util.promisify)(_fs.default.writeFile)(filename, `${JSON.stringify(resolvedDeps, null, 2)}\n`); + _promises.default.writeFile(filename, `${JSON.stringify(resolvedDeps, null, 2)}\n`); console.log(`Licenses exported to ${filename}`); } } else { diff --git a/dist/packageUtils.js b/dist/packageUtils.js index 2f6d5b8..0095de3 100644 --- a/dist/packageUtils.js +++ b/dist/packageUtils.js @@ -36,15 +36,24 @@ async function getDependencies(includeDev) { } /** - * Returns descriptor (basepath and package.json content) for a package + * Returns descriptor (basePath and package.json content) for a package + * Emulating node js module resolution (see: https://medium.com/outbrain-engineering/node-js-module-resolution-af46715784ef) */ -async function getPackageDescriptor(dep) { - const basePath = _path.default.join(process.cwd(), 'node_modules', dep); - const pkg = await (0, _util.readJSONFile)(_path.default.join(basePath, 'package.json')); - return { - basePath, - pkg - }; +async function getPackageDescriptor(dep, basePath = process.cwd(), basePathTries = []) { + try { + const pkg = await (0, _util.readJSONFile)(_path.default.join(basePath, 'node_modules', dep, 'package.json'), false); + return { + pkg, + basePath: _path.default.join(basePath, 'node_modules', dep) + }; + } catch (error) { + basePathTries = [...basePathTries, _path.default.join(basePath, 'node_modules', dep)]; + if (basePath === '/') { + console.error(`Could not find package: '${dep}', tried: \n\t${basePathTries.join('\n\t')}`); + return process.exit(1); + } + return getPackageDescriptor(dep, _path.default.join(basePath, '..'), basePathTries); + } } /** diff --git a/dist/util.js b/dist/util.js index ed8fe80..7308ea3 100644 --- a/dist/util.js +++ b/dist/util.js @@ -6,8 +6,7 @@ Object.defineProperty(exports, "__esModule", { exports.diff = diff; exports.parseCLIFlags = parseCLIFlags; exports.readJSONFile = readJSONFile; -var _fs = _interopRequireDefault(require("fs")); -var _util = require("util"); +var _promises = _interopRequireDefault(require("fs/promises")); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } /** * Creates a nice object of flags from Node's process.argv @@ -40,12 +39,14 @@ function diff(a, b) { /** * Safely read a file and parse it as JSON */ -async function readJSONFile(filePath) { +async function readJSONFile(filePath, outputFail = true) { try { - const fileBuffer = await (0, _util.promisify)(_fs.default.readFile)(filePath); + const fileBuffer = await _promises.default.readFile(filePath); return JSON.parse(fileBuffer.toString()); } catch (error) { - console.error('Could not read JSON file:', error); + if (outputFail) { + console.error('Could not read JSON file:', error); + } throw error; } } \ No newline at end of file diff --git a/dist/whitelist.js b/dist/whitelist.js deleted file mode 100644 index 35f268f..0000000 --- a/dist/whitelist.js +++ /dev/null @@ -1,14 +0,0 @@ -"use strict"; - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.isValidLicense = isValidLicense; -exports.licenseSnippets = void 0; -const validLicense = ['MIT', 'BSD', 'Apache License', 'Creative Commons', 'GPL', 'Apache-2.0', 'BSD-3-Clause', "ISC"]; -const licenseSnippets = ['MIT License', 'The GNU General Public License is a free, copyleft license for software and other kinds of works.']; -exports.licenseSnippets = licenseSnippets; - -function isValidLicense(license) { - return validLicense.some(i => i === license); -} \ No newline at end of file diff --git a/package.json b/package.json index 618aa12..9003797 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@inthepocket/npm-license-scraper", - "version": "2.3.1", + "version": "2.3.2", "description": "Dead simple license scraper and validator with zero dependencies.", "main": "dist/index.js", "bin": { diff --git a/src/index.ts b/src/index.ts index 66e97b0..6f86583 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,8 +1,7 @@ #! /usr/bin/env node -import fs from 'fs'; +import fs from 'fs/promises'; import path from 'path'; -import { promisify } from 'util'; import { isValidLicense } from './licenseUtils'; import { parseCLIFlags, diff } from './util'; @@ -10,7 +9,7 @@ import { getPackageDescriptor, getPackageInfo, getDependencies } from './package async function readFromLicenseFile(basePath: string) { - const matches = await promisify(fs.readdir)(basePath); + const matches = await fs.readdir(basePath); const validLicenseFiles = matches.filter(match => match.toUpperCase().startsWith('LICENSE')); if (validLicenseFiles.length < 1) { @@ -19,7 +18,7 @@ async function readFromLicenseFile(basePath: string) { } const licenseFile = path.join(basePath, validLicenseFiles[0]); - const contents = (await promisify(fs.readFile)(licenseFile)).toString(); + const contents = (await fs.readFile(licenseFile)).toString(); const file = licenseFile.split('node_modules/')[1]; @@ -77,12 +76,12 @@ async function getPackageDetails(dep: string) { if (flags.export) { if (typeof flags.export === 'string') { const filename = path.join(process.cwd(), flags.export); - promisify(fs.writeFile)(filename, `${JSON.stringify(resolvedDeps, null, 2)}\n`); + fs.writeFile(filename, `${JSON.stringify(resolvedDeps, null, 2)}\n`); console.log(`Licenses exported to ${filename}`); } else if (typeof flags.export === 'boolean') { // Export to default licenses.json if no exported file name provided const filename = path.join(process.cwd(), 'licenses.json'); - promisify(fs.writeFile)(filename, `${JSON.stringify(resolvedDeps, null, 2)}\n`); + fs.writeFile(filename, `${JSON.stringify(resolvedDeps, null, 2)}\n`); console.log(`Licenses exported to ${filename}`); } } else { diff --git a/src/packageUtils.ts b/src/packageUtils.ts index 4cdd2c0..c9220e2 100644 --- a/src/packageUtils.ts +++ b/src/packageUtils.ts @@ -36,12 +36,34 @@ export async function getDependencies( } /** - * Returns descriptor (basepath and package.json content) for a package + * Returns descriptor (basePath and package.json content) for a package + * Emulating node js module resolution (see: https://medium.com/outbrain-engineering/node-js-module-resolution-af46715784ef) */ -export async function getPackageDescriptor(dep: string) { - const basePath = path.join(process.cwd(), 'node_modules', dep); - const pkg = await readJSONFile(path.join(basePath, 'package.json')); - return { basePath, pkg }; +export async function getPackageDescriptor( + dep: string, + basePath = process.cwd(), + basePathTries: string[] = [] + ): Promise<{ + basePath: string; + pkg: any; +}> { + try { + const pkg = await readJSONFile(path.join(basePath, 'node_modules', dep, 'package.json'), false); + + return { + pkg, + basePath: path.join(basePath, 'node_modules', dep), + }; + } catch (error) { + basePathTries = [...basePathTries, path.join(basePath, 'node_modules', dep)]; + + if (basePath === '/') { + console.error(`Could not find package: '${dep}', tried: \n\t${basePathTries.join('\n\t')}`); + return process.exit(1); + } + + return getPackageDescriptor(dep, path.join(basePath, '..'), basePathTries); + } } /** diff --git a/src/util.ts b/src/util.ts index 8d36762..e14299a 100644 --- a/src/util.ts +++ b/src/util.ts @@ -1,5 +1,4 @@ -import fs from 'fs'; -import { promisify } from "util"; +import fs from 'fs/promises'; /** * Creates a nice object of flags from Node's process.argv @@ -36,12 +35,14 @@ export function diff(a: any[], b: any[]) { /** * Safely read a file and parse it as JSON */ -export async function readJSONFile(filePath: string) { +export async function readJSONFile(filePath: string, outputFail = true) { try { - const fileBuffer = await promisify(fs.readFile)(filePath); + const fileBuffer = await fs.readFile(filePath); return JSON.parse(fileBuffer.toString()); } catch (error) { - console.error('Could not read JSON file:', error); + if (outputFail) { + console.error('Could not read JSON file:', error); + } throw error; } }