【问题标题】:Enumerate all installed packages from source in current javascript project从当前 javascript 项目中的源代码枚举所有已安装的包
【发布时间】:2020-10-15 19:34:12
【问题描述】:

我正在尝试找到一种方法从源代码递归枚举当前 javascript 项目中的所有包。

我想做的是相当于npm listyarn list,但来自源代码。

我想避免的:

  • 直接自己解析/导入package.json,然后分析每个package.json的依赖关系
  • 产生一个进程npm listyarn list 并解析它的输出

我对此类库所做的每一次搜索都会在诸如npm listyarn list 等交互式解决方案的结果中被污染。

【问题讨论】:

    标签: javascript node.js package


    【解决方案1】:

    这是我最终做的:

    • 使用yarn-logical-treenpm-logical-tree 包,并根据yarn.lockpackage-lock.json 的存在使用正确的包
    • 解析结果树
    const fs = require('fs')
    const path = require('path')
    const fsPromises = fs.promises
    const lockfile = require('@yarnpkg/lockfile')
    const yarnLogicalTree = require('yarn-logical-tree')
    const npmLogicalTree = require('npm-logical-tree')
    
    /**
     * Return true of a file exists and is readable
     * @param {string} filename 
     */
    const fileExists = async (filename) => {
        try {
            await fsPromises.access(filename, fs.constants.R_OK)
            return true
        } catch (error) {
            return false
        }
    }
    
    /**
     * Find the project directory associated to the directory passed as argument (by searching for package.json in all directories from this one to the root one)
     * @param {string} dir 
     */
    const findProject = async (dir) => {
        let parsedDir = null
        dir = await fsPromises.realpath(dir)
        let found = false
        do {
            parsedDir = path.parse(dir)
            const packageFile = path.join(dir, 'package.json')
            if (await fileExists(packageFile)) {
                return dir
            }
            dir = parsedDir.dir
        } while ((!found) && parsedDir && parsedDir.base !== '')
        return null
    }
    
    /**
     * Get a package tree (by searching for a 'yarn.lock' or a 'package-lock.json')
     * @param {string} dir The directory where to look for a node project
     */
    const getTree = async (dir) => {
        const project = await findProject(dir)
        const packageFilename = path.join(project, 'package.json')
        const yarnFilename = path.join(project, 'yarn.lock')
        const npmFilename = path.join(project, 'package-lock.json')
        const packageContent = await fsPromises.readFile(packageFilename, 'utf-8')
        if (await fileExists(yarnFilename)) {
            const yarnLockContent = await fsPromises.readFile(yarnFilename, 'utf-8')
    
            const package = JSON.parse(packageContent)
            const yarnLock = lockfile.parse(yarnLockContent)
            return yarnLogicalTree(package, yarnLock.object)
        } else if (await fileExists(npmFilename)) {
            const npmLockContent = await fsPromises.readFile(npmFilename, 'utf-8')
    
            const packageParsed = JSON.parse(packageContent)
            const npmLock = JSON.parse(npmLockContent)
            return npmLogicalTree(packageParsed, npmLock)
        }
        return null
    }
    
    /**
     * Find all direct or indirect dependencies from a project tree
     * @param {LogicalTree} tree The tree to parse
     * @param {Object.<string, {name: string, version: string}>} deps The deps structure to update
     * @returns {Object.<string, {name: string, version: string}>}
     */
    
    const searchTree = async (tree, deps = {}) => {
        const { name, version, dependencies } = tree
        const id = `${name}@${version}`
        if (!deps[id]) {
            deps[id] = { name, version }
            for (let subTreeName of dependencies.keys()) {
                const subTree = dependencies.get(subTreeName)
                await searchTree(subTree, deps)
            }
        }
        return deps
    }
    

    然后,我是这样使用它的:

    const start = async () => {
        let dir = '.'
        const project = await findProject(dir)
        const tree = await getTree(project)
        const deps = await searchTree(tree)
        for (let id of Object.keys(deps).sort()) {
            const { name, version } = deps[id]
            console.log(`${name} (${version})`)
        }
    }
    
    start()
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-06-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-02-16
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多