UNPKG

dpdm-fast

Version:

Analyze circular dependencies in your JavaScript/TypeScript projects with Rust.

251 lines 8.65 kB
"use strict"; /*! * Copyright 2019 acrazing <joking.young@gmail.com>. All rights reserved. * @since 2019-07-17 18:45:32 */ Object.defineProperty(exports, "__esModule", { value: true }); exports.simpleResolver = exports.defaultOptions = void 0; exports.normalizeOptions = normalizeOptions; exports.appendSuffix = appendSuffix; exports.shortenTree = shortenTree; exports.parseCircular = parseCircular; exports.parseDependents = parseDependents; exports.parseWarnings = parseWarnings; exports.prettyTree = prettyTree; exports.prettyCircular = prettyCircular; exports.prettyWarning = prettyWarning; exports.isEmpty = isEmpty; const tslib_1 = require("tslib"); const chalk_1 = tslib_1.__importDefault(require("chalk")); const fs_extra_1 = tslib_1.__importDefault(require("fs-extra")); const module_1 = require("module"); const path_1 = tslib_1.__importDefault(require("path")); const consts_1 = require("./consts"); const allBuiltins = new Set(module_1.builtinModules); exports.defaultOptions = { context: process.cwd(), extensions: ['', '.ts', '.tsx', '.mjs', '.js', '.jsx', '.json'], js: ['.ts', '.tsx', '.mjs', '.js', '.jsx'], include: /.*/, exclude: /node_modules/, tsconfig: void 0, transform: false, skipDynamicImports: false, onProgress: () => void 0, }; function normalizeOptions(options) { const newOptions = Object.assign(Object.assign({}, exports.defaultOptions), options); if (newOptions.extensions.indexOf('') < 0) { newOptions.extensions.unshift(''); } newOptions.context = path_1.default.resolve(newOptions.context); if (options.tsconfig === void 0) { try { const tsconfig = path_1.default.join(newOptions.context, 'tsconfig.json'); const stat = fs_extra_1.default.statSync(tsconfig); if (stat.isFile()) { options.tsconfig = tsconfig; } } catch (_a) { } } else { let stat; try { stat = fs_extra_1.default.statSync(options.tsconfig); } catch (_b) { } if (!stat || !stat.isFile()) { throw new Error(`specified tsconfig "${options.tsconfig}" is not a file`); } options.tsconfig = path_1.default.join(process.cwd(), options.tsconfig); } return newOptions; } function appendSuffix(request, extensions) { return tslib_1.__awaiter(this, void 0, void 0, function* () { for (const ext of extensions) { try { const stat = yield fs_extra_1.default.stat(request + ext); if (stat.isFile()) { return request + ext; } } catch (_a) { } } try { const stat = yield fs_extra_1.default.stat(request); if (stat.isDirectory()) { return appendSuffix(path_1.default.join(request, 'index'), extensions); } } catch (_b) { } return null; }); } const simpleResolver = (context, request, extensions) => tslib_1.__awaiter(void 0, void 0, void 0, function* () { if (path_1.default.isAbsolute(request)) { return appendSuffix(request, extensions); } if (request.charAt(0) === '.') { return appendSuffix(path_1.default.join(context, request), extensions); } // is package const nodePath = { paths: [context] }; try { const pkgPath = require.resolve(path_1.default.join(request, 'package.json'), nodePath); const pkgJson = yield fs_extra_1.default.readJSON(pkgPath); const id = path_1.default.join(path_1.default.dirname(pkgPath), pkgJson.module || pkgJson.main); return appendSuffix(id, extensions); } catch (_a) { } try { return require.resolve(request, nodePath); } catch (_b) { } return null; }); exports.simpleResolver = simpleResolver; function shortenTree(context, tree) { const output = {}; for (const key in tree) { const shortKey = path_1.default.relative(context, key); output[shortKey] = tree[key] ? tree[key].map((item) => (Object.assign(Object.assign({}, item), { issuer: shortKey, id: item.id === null ? null : path_1.default.relative(context, item.id) }))) : null; } return output; } function parseCircular(tree, skipDynamicImports = false) { const circulars = []; tree = Object.assign({}, tree); function visit(id, used) { const index = used.indexOf(id); if (index > -1) { circulars.push(used.slice(index)); } else if (tree[id]) { used.push(id); const deps = tree[id]; delete tree[id]; deps && deps.forEach((dep) => { if (dep.id && (!skipDynamicImports || dep.kind !== consts_1.DependencyKind.DynamicImport)) { visit(dep.id, used.slice()); } }); } } for (const id in tree) { visit(id, []); } return circulars; } function parseDependents(tree) { const output = {}; for (const key in tree) { const deps = tree[key]; if (deps) { deps.forEach((dep) => { if (dep.id) { (output[dep.id] = output[dep.id] || []).push(key); } }); } } for (const key in output) { output[key].sort(); } return output; } function parseWarnings(tree, dependents = parseDependents(tree)) { const warnings = []; const builtin = new Set(); for (const key in tree) { const deps = tree[key]; if (!builtin.has(key) && allBuiltins.has(key)) { builtin.add(key); } if (!deps) { const parents = dependents[key] || []; const total = parents.length; warnings.push(`skip ${JSON.stringify(key)}, issuers: ${parents .slice(0, 2) .map((id) => JSON.stringify(id)) .join(', ')}${total > 2 ? ` (${total - 2} more...)` : ''}`); } else { for (const dep of deps) { if (!dep.id) { warnings.push(`miss ${JSON.stringify(dep.request)} in ${JSON.stringify(dep.issuer)}`); } } } } if (builtin.size > 0) { warnings.push('node ' + Array.from(builtin, (item) => JSON.stringify(item)).join(', ')); } return warnings.sort(); } function prettyTree(tree, entries, prefix = ' ') { const lines = []; let id = 0; const idMap = {}; const digits = Math.ceil(Math.log10(Object.keys(tree).length)); function visit(item, prefix, hasMore) { const isNew = idMap[item] === void 0; const iid = (idMap[item] = idMap[item] || id++); let line = chalk_1.default.gray(prefix + '- ' + iid.toString().padStart(digits, '0') + ') '); const deps = tree[item]; if (allBuiltins.has(item)) { lines.push(line + chalk_1.default.blue(item)); return; } else if (!isNew) { lines.push(line + chalk_1.default.gray(item)); return; } else if (!deps) { lines.push(line + chalk_1.default.yellow(item)); return; } lines.push(line + item); prefix += hasMore ? '· ' : ' '; for (let i = 0; i < deps.length; i++) { visit(deps[i].id || deps[i].request, prefix, i < deps.length - 1); } } for (let i = 0; i < entries.length; i++) { visit(entries[i], prefix, i < entries.length - 1); } return lines.join('\n'); } function prettyCircular(circulars, prefix = ' ') { const digits = Math.ceil(Math.log10(circulars.length)); return circulars .map((line, index) => { return (chalk_1.default.gray(`${prefix}${(index + 1).toString().padStart(digits, '0')}) `) + line.map((item) => chalk_1.default.red(item)).join(chalk_1.default.gray(' -> '))); }) .join('\n'); } function prettyWarning(warnings, prefix = ' ') { const digits = Math.ceil(Math.log10(warnings.length)); return warnings .map((line, index) => { return (chalk_1.default.gray(`${prefix}${(index + 1).toString().padStart(digits, '0')}) `) + chalk_1.default.yellow(line)); }) .join('\n'); } function isEmpty(v) { if (v == null) { return true; } for (const k in v) { if (v.hasOwnProperty(k)) { return false; } } return true; } //# sourceMappingURL=utils.js.map