gpt4 book ai didi

node.js - 从 semver 版本中确定 NPM 服务器上存在的依赖项的最大匹配版本

转载 作者:行者123 更新时间:2023-12-04 09:25:39 26 4
gpt4 key购买 nike

我正在编写一个有助于固定依赖关系的 Node 脚本。
如何从 semver 版本中确定 NPM 服务器上存在的包的最大实现版本?
例如,我们有一个依赖“foo”,它在 package.json 中指定为 ~1.2.3 .
在 NPM 上,有发布版本 1.2.5 ,这是与 ~1.2.3 兼容的最新发布版本.
我需要编写一个将“foo”和~1.2.3作为输入的脚本,然后在服务器查询后,返回 1.2.5 .像这样的东西:

await fetchRealizedVersion('foo', '~1.2.3'); // resolves to 1.2.5
我知道我可以这样做 yarn upgrade然后解析锁定文件,但我正在寻找一种更直接的方法来完成此操作。
希望有一个包可以将其归结为 API 调用,但在谷歌搜索后我没有找到任何东西。

最佳答案

"Hopefully there is a package that boils this down to an API call,"


简短回答:不幸的是,没有,据我所知,目前不存在一个包。
编辑:有 get-latest-version 您可能想尝试的包:

Basic usage:

const getLatestVersion = require('get-latest-version')

getLatestVersion('some-other-module', {range: '^1.0.0'})
.then((version) => console.log(version)) // highest version matching ^1.0.0 range
.catch((err) => console.error(err))


或者,考虑使用/编写自定义 node.js 模块来执行以下步骤:
  • 任何一个:
  • 掏出npm view命令检索给定包的 NPM 注册表中可用的所有版本:例如:
    npm view <pkg> versions --json
  • 或者,直接制作 https向公众请求npm registryhttps://registry.npmjs.org检索给定包的所有可用版本。

  • 解析返回的 JSON 并将其与 semver 范围(例如 ~1.2.3 )一起传递给 node-semver包的maxSatisfying()方法。maxSatisfying()方法在 docs 中描述作为:

    maxSatisfying(versions, range): Return the highest version in the list that satisfies the range, or null if none of them do.



  • 自定义模块(A): get-latest-version.js 中提供的自定义示例模块(下)基本上执行上述步骤。在这个例子中,我们使用 npm view命令。
    获取最新版本.js
    'use strict';

    //------------------------------------------------------------------------------
    // Requirements
    //------------------------------------------------------------------------------

    const { exec } = require('child_process');
    const { maxSatisfying } = require('semver');

    //------------------------------------------------------------------------------
    // Data
    //------------------------------------------------------------------------------

    const errorBadge = '\x1b[31;40mERR!\x1b[0m';

    //------------------------------------------------------------------------------
    // Helpers
    //------------------------------------------------------------------------------

    /**
    * Captures the data written to stdout from a given shell command.
    *
    * @param {String} command The shell command to execute.
    * @return {Promise<string>} A Promise object whose fulfillment value holds the
    * data written to stdout. When rejected an error message is returned.
    * @private
    */
    function shellExec(command) {
    return new Promise((resolve, reject) => {
    exec(command, (error, stdout, stderr) => {
    if (error) {
    reject(new Error(`Failed executing command: '${command}'`));
    return;
    }
    resolve(stdout.trim());
    });
    });
    }

    //------------------------------------------------------------------------------
    // Public Interface
    //------------------------------------------------------------------------------

    module.exports = {

    /**
    * Retrieves the latest version that matches the given range for a package.
    *
    * @async
    * @param {String} pkg The package name.
    * @param {String} range The semver range.
    * @returns {Promise<string>} A Promise object that when fulfilled returns the
    * latest version that matches. When rejected an error message is returned.
    */
    async fetchRealizedVersion(pkg, range) {
    try {
    const response = await shellExec(`npm view ${pkg} versions --json`);
    const versions = JSON.parse(response);

    return maxSatisfying(versions, range);

    } catch ({ message: errorMssg }) {
    throw Error([
    `${errorBadge} ${errorMssg}`,
    `${errorBadge} '${pkg}' is probably not in the npm registry.`
    ].join('\n'));
    }
    }

    };

    用法:
    以下 index.js演示使用上述模块。
    index.js
    'use strict';

    const { fetchRealizedVersion } = require('./get-latest-version.js');

    (async function() {
    try {
    const latest = await fetchRealizedVersion('eslint', '~5.15.0');
    console.log(latest); // --> 5.15.3
    } catch ({ message: errMssg }) {
    console.error(errMssg);
    }
    })();
    如您所见,在该示例中,我们获得了 eslint 的最新发布版本。与 semver 波浪号范围兼容的软件包 ~5.15.0 .
    满足 ~5.15.0 的最新/最大版本打印到控制台:
    $ node ./index.js
    5.15.3

    注:您可以随时使用在线 semver calculator 仔细检查结果。它实际上使用了 node-semver包裹。
    另一个用法示例:
    以下 index.js演示使用上述模块获取多个包和不同范围的最新/最大版本。
    index.js
    'use strict';

    const { fetchRealizedVersion } = require('./get-latest-version.js');

    const criteria = [
    {
    pkg: 'eslint',
    range: '^4.9.0'
    },
    {
    pkg: 'eslint',
    range: '~5.0.0'
    },
    {
    pkg: 'lighthouse',
    range: '~1.0.0'
    },
    {
    pkg: 'lighthouse',
    range: '^1.0.4'
    },
    {
    pkg: 'yarn',
    range: '~1.3.0'
    },
    {
    pkg: 'yarn',
    range: '^1.3.0'
    },
    {
    pkg: 'yarn',
    range: '^20.3.0'
    },
    {
    pkg: 'quuxbarfoo',
    range: '~1.3.0'
    }
    ];


    (async function () {

    // Each request is sent and read in parallel.
    const promises = criteria.map(async ({ pkg, range }) => {
    try {
    return await fetchRealizedVersion(pkg, range);
    } catch ({ message: errMssg }) {
    return errMssg;
    }
    });

    // Log each 'latest' semver in sequence.
    for (const latest of promises) {
    console.log(await latest);
    }
    })();
    最后一个示例的结果如下:
    $ node ./index.js
    4.19.1
    5.0.1
    1.0.6
    1.6.5
    1.3.2
    1.22.4
    null
    ERR! Failed executing command: 'npm view quuxbarfoo versions --json'
    ERR! 'quuxbarfoo' is probably not in the npm registry.


    附加说明: shellExec get-latest-version.js 中的辅助函数目前 promise child_process模块的 exec() 脱壳 npm view的方法命令。但是,由于 node.js 版本 12,内置的 util.promisify 提供另一种方式来 promise exec()方法(如 exec 的文档中所示),因此您可能更喜欢这样做。

    自定义模块(B):
    如果您想避免使用 npm view命令,您可以考虑直接向 https://registry.npmjs.org 发出请求端点(与 npm view 命令发送 https GET 请求的端点相同)。 get-latest-version.js的修改版(下)基本上使用了内置 https.get 的 promise 版本.
    用法与前面“用法”部分中演示的相同。
    获取最新版本.js
    'use strict';

    //------------------------------------------------------------------------------
    // Requirements
    //------------------------------------------------------------------------------

    const https = require('https');
    const { maxSatisfying } = require('semver');

    //------------------------------------------------------------------------------
    // Data
    //------------------------------------------------------------------------------

    const endPoint = 'https://registry.npmjs.org';
    const errorBadge = '\x1b[31;40mERR!\x1b[0m';

    //------------------------------------------------------------------------------
    // Helpers
    //------------------------------------------------------------------------------

    /**
    * Requests JSON for a given package from the npm registry.
    *
    * @param {String} pkg The package name.
    * @return {Promise<json>} A Promise object that when fulfilled returns the JSON
    * metadata for the specific package. When rejected an error message is returned.
    * @private
    */
    function fetchPackageInfo(pkg) {

    return new Promise((resolve, reject) => {

    https.get(`${endPoint}/${pkg}/`, response => {

    const { statusCode, headers: { 'content-type': contentType } } = response;

    if (statusCode !== 200) {
    reject(new Error(`Request to ${endPoint} failed. ${statusCode}`));
    return;
    }

    if (!/^application\/json/.test(contentType)) {
    reject(new Error(`Expected application/json but received ${contentType}`));
    return;
    }

    let data = '';

    response.on('data', chunk => {
    data += chunk;
    });

    response.on('end', () => {
    resolve(data);
    });

    }).on('error', error => {
    reject(new Error(`Cannot find ${endPoint}`));
    });
    });
    }

    //------------------------------------------------------------------------------
    // Public Interface
    //------------------------------------------------------------------------------

    module.exports = {

    /**
    * Retrieves the latest version that matches the given range for a package.
    *
    * @async
    * @param {String} pkg The package name.
    * @param {String} range The semver range.
    * @returns {Promise<string>} A Promise object that when fulfilled returns the
    * latest version that matches. When rejected an error message is returned.
    */
    async fetchRealizedVersion(pkg, range) {
    try {
    const response = await fetchPackageInfo(pkg);
    const { versions: allVersionInfo } = JSON.parse(response);

    // The response includes all metadata for all versions of a package.
    // Let's create an Array holding just the `version` info.
    const versions = [];
    Object.keys(allVersionInfo).forEach(key => {
    versions.push(allVersionInfo[key].version)
    });

    return maxSatisfying(versions, range);

    } catch ({ message: errorMssg }) {
    throw Error([
    `${errorBadge} ${errorMssg}`,
    `${errorBadge} '${pkg}' is probably not in the npm registry.`
    ].join('\n'));
    }
    }

    };

    备注 node-semver的版本示例自定义模块 (A & B) 中使用的不是当前最新版本(即 7.3.2 )。版本 ^5.7.1而是使用了 - 这与 npm cli 使用的版本相同工具。

    关于node.js - 从 semver 版本中确定 NPM 服务器上存在的依赖项的最大匹配版本,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63022138/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com