Project Icon

npm-check-updates

自动化项目依赖升级工具

npm-check-updates是一个用于自动更新package.json依赖的开源工具。它可检测并升级依赖包到最新版本,同时保持原有的语义化版本规则。支持npm、yarn、pnpm等包管理器,提供命令行和模块化使用选项。该工具默认配置合理,且高度可定制,有助于开发者轻松维护项目依赖的最新状态。

npm-check-updates

npm版本 构建状态

npm-check-updates 将你的 package.json 依赖项升级到最新版本,忽略指定的版本。

  • 保持现有的语义化版本策略,例如将 "react": "^17.0.2" 升级到 "react": "^18.3.1"
  • 仅修改 package.json 文件。运行 npm install 来更新已安装的包和 package-lock.json。
  • 默认设置合理,但高度可定制
  • 兼容 npm、yarn、pnpm、deno 和 bun
  • 支持命令行和模块使用
示例输出

$${\color{red}红色}$$ 主版本升级(包括所有主版本号为零的版本
$${\color{cyan}青色}$$ 次版本升级
$${\color{green}绿色}$$ 补丁版本升级

安装

全局安装以使用 npm-check-updates 或更短的 ncu

npm install -g npm-check-updates

或使用 npx 运行(仅支持长格式):

npx npm-check-updates

使用方法

检查所有项目依赖的最新版本:

$ ncu
正在检查 package.json
[====================] 5/5 100%

 eslint             7.32.0  →    8.0.0
 prettier           ^2.7.1  →   ^3.0.0
 svelte            ^3.48.0  →  ^3.51.0
 typescript         >3.0.0  →   >4.0.0
 untildify          <4.0.0  →   ^4.0.0
 webpack               4.x  →      5.x

运行 ncu -u 以升级 package.json

升级项目的 package 文件:

确保你的 package 文件已经进行版本控制,且所有更改都已提交。这将覆盖你的 package 文件。

$ ncu -u
正在升级 package.json
[====================] 1/1 100%

 express           4.12.x  →   4.13.x

运行 npm install 以安装新版本。

$ npm install      # 更新已安装的包和 package-lock.json

检查全局包:

ncu -g

交互模式

在交互模式下选择要更新的包:

ncu --interactive
ncu -i

ncu --interactive

结合 --format group 使用,体验更佳:

ncu --interactive --format group

筛选包

使用 --filter 选项或添加额外的命令行参数来筛选包:

# 仅升级 mocha
ncu mocha
ncu -f mocha
ncu --filter mocha

# 仅升级 chalk、mocha 和 react
ncu chalk mocha react
ncu chalk, mocha, react
ncu -f "chalk mocha react"

使用通配符或正则表达式进行筛选:

# 升级以 "react-" 开头的包
ncu react-*
ncu "/^react-.*$/"

使用 --reject 选项或在筛选器前加 ! 来排除特定包。支持字符串、通配符、全局模式、逗号或空格分隔的列表和正则表达式:

# 升级除 nodemon 之外的所有包
ncu \!nodemon
ncu -x nodemon
ncu --reject nodemon

# 升级不以 "react-" 开头的包
ncu \!react-*
ncu '/^(?!react-).*$/' # mac/linux
ncu "/^(?!react-).*$/" # windows

高级筛选器:filterfilterResultsfilterVersion

如何确定依赖项更新

  • 直接依赖项会更新到最新的稳定版本:
    • 2.0.12.2.0
    • 1.21.3
    • 0.1.01.0.1
  • 范围操作符会保留,版本号会更新:
    • ^1.2.0^2.0.0
    • 1.x2.x
    • >0.2.0>0.3.0
  • "小于"会被替换为通配符:
    • <2.0.0^3.0.0
    • 1.0.0 < 2.0.0^3.0.0
  • "任意版本"会被保留:
    • **
  • 默认情况下会忽略预发布版本。
    • 使用 --pre 来包含预发布版本(如 alphabetabuild1235
  • 选择升级到的级别:
    • 使用 --target semver,根据指定的 semver 版本范围更新:
      • ^1.1.0^1.9.99
    • 使用 --target minor,严格更新补丁和次要版本(包括主版本号为零的版本):
      • 0.1.00.2.1
    • 使用 --target patch,严格更新补丁版本(包括主版本号为零的版本):
      • 0.1.00.1.2
    • 使用 --target @next,更新到发布在 next 标签上的版本:
      • 0.1.0 -> 0.1.1-next.1

选项

选项按以下优先级合并:

  1. 命令行选项
  2. 本地配置文件
  3. 项目配置文件
  4. 用户配置文件

不需要参数的选项可以通过在前面加上 --no- 来取消,例如 --no-peer

--cache将版本缓存到本地缓存文件。默认的 --cacheFile 是 ~/.ncu-cache.json,默认的 --cacheExpiration 是 10 分钟。
--cacheClear清除默认缓存,或由 --cacheFile 指定的缓存文件。
--cacheExpiration <分钟>缓存过期时间(分钟)。仅与 --cache 一起使用。(默认值:10)
--cacheFile <路径>缓存文件的文件路径。仅与 --cache 一起使用。(默认值:"~/.ncu-cache.json")
--color强制在终端中使用彩色输出。
--concurrency <n>向注册表发送 HTTP 请求的最大并发数。(默认值:8)
--configFileName <s>配置文件名。(默认值:.ncurc.{json,yml,js,cjs})
--configFilePath <路径>.ncurc 配置文件的目录。(默认值:packageFile 所在目录)
--cwd <路径>npm 将在其中执行的工作目录。
--deep在当前工作目录中递归运行。等同于 (--packageFile '**/package.json')。
--dep <值>仅检查一个或多个依赖项部分:dev、optional、peer、prod 或 packageManager(用逗号分隔)。(默认值:["prod","dev","optional","packageManager"])
--deprecated包含已弃用的包。使用 --no-deprecated 可排除已弃用的包(会使用更多带宽)。(默认值:true)
-d, --doctor迭代安装升级并运行测试以识别破坏性升级。需要 -u 才能执行。
--doctorInstall <命令>指定在 doctor 模式下使用的安装脚本。(默认值:npm install 或您的包管理器的等效命令)
--doctorTest <命令>指定在 doctor 模式下使用的测试脚本。(默认值:npm test
--enginesNode仅包含满足包文件中指定的 engines.node 的包。
-e, --errorLevel <n>设置错误级别。1:如果没有错误发生,以错误代码 0 退出。2:如果没有包需要更新,以错误代码 0 退出(对持续集成有用)。(默认值:1)
-f, --filter <p>仅包含匹配给定字符串、通配符、glob、逗号或空格分隔列表、/正则表达式/或谓词函数的包名。
filterResults <fn>根据用户提供的函数过滤升级。
--filterVersion <p>使用逗号或空格分隔列表、/正则表达式/或谓词函数过滤包版本。
--format <值>修改输出格式或显示附加信息。指定一个或多个逗号分隔的值:group、ownerChanged、repo、time、lines。(默认值:[])
-g, --global检查全局包而不是当前项目中的包。
groupFunction <fn>使用 --format group 时,自定义包如何分组。
--install <值>控制自动安装行为:always、never、prompt。(默认值:"prompt")
-i, --interactive为每个依赖项启用交互式提示;除非设置了 json 选项之一,否则隐含 -u
-j, --jsonAll输出新的包文件,而不是人类可读的消息。
--jsonDeps类似 jsonAll,但只列出新包数据的 dependenciesdevDependenciesoptionalDependencies 等。
--jsonUpgraded以 json 格式输出已升级的依赖项。
-l, --loglevel <n>日志记录量:silent、error、minimal、warn、info、verbose、silly。(默认值:"warn")
--mergeConfig将嵌套配置与根配置文件合并,用于 --deep--packageFile 选项。(默认值:false)
-m, --minimal
根据语义化版本(semver),不要升级已经满足版本范围的较新版本。 --packageData <值> 包文件数据(您也可以使用标准输入)。 --packageFile <路径|通配符> 包文件位置。(默认:./package.json) -p, --packageManager <s> npm、yarn、pnpm、deno、bun、staticRegistry(默认:npm)。 --peer 检查已安装包的对等依赖,并筛选出兼容版本的更新。 --pre <n> 包含预发布版本,例如 -alpha.0、-beta.5、-rc.2。当 --target 设为 newest 或 greatest 时,或当前版本是预发布版本时,自动设置为 1。(默认:0) --prefix <路径> npm 的当前工作目录。 -r, --registry <uri> 指定查找包版本时使用的注册表。 --registryType <类型> 指定 --registry 是指完整的 npm 注册表还是简单的 JSON 文件或 URL:npm、json。(默认:npm) -x, --reject <p> 排除匹配给定字符串、通配符、glob、逗号或空格分隔列表、/正则表达式/或谓词函数的包。 --rejectVersion <p> 使用逗号或空格分隔列表、/正则表达式/或谓词函数排除 package.json 版本。 --removeRange 从最终包版本中删除版本范围。 --retry <n> 重试获取包信息失败请求的次数。(默认:3) --root 除了指定的工作空间外,还对根项目运行更新。仅允许与 --workspace--workspaces 一起使用。(默认:true) -s, --silent 不输出任何内容。等同于 --loglevel silent。 --stdin 从标准输入读取 package.json。 -t, --target <值> 确定要升级到的版本:latest、newest、greatest、minor、patch、semver、@[tag] 或 [函数]。(默认:latest) --timeout <毫秒> 全局超时时间(毫秒)。(默认:无全局超时,每个 npm-registry-fetch 30 秒) -u, --upgrade 用升级后的版本覆写包文件,而不仅仅输出到控制台。 --verbose 记录额外信息以进行调试。等同于 --loglevel verbose。 -w, --workspace <s> 在一个或多个指定的工作空间上运行。添加 --root 也可以升级根项目。(默认:[]) -ws, --workspaces 在所有工作空间上运行。添加 --root 也可以升级根项目。

高级选项

一些选项具有高级用法,或允许通过在 .ncurc.js 文件中指定函数来设置每个包的值。

运行 ncu --help [选项] 可查看特定选项的高级帮助,或参见以下内容:

doctor

用法:

ncu --doctor -u
ncu --no-doctor
ncu -du

迭代安装升级并运行您项目的测试,以识别破坏性升级。回滚破坏性升级并用可用升级更新 package.json。

需要 -u 来执行(修改您的 package 文件、lock 文件和 node_modules)

更具体地说:

  1. 运行 npm installnpm test 以确保测试当前通过。
  2. 运行 ncu -u 乐观地升级所有依赖项。
  3. 如果测试通过,太好了!
  4. 如果测试失败,恢复 package 文件和 lock 文件。
  5. 对每个依赖项,安装升级并运行测试。
  6. 打印出带有测试错误的破坏性升级。
  7. 将可用升级保存到 package.json。

其他选项:

--doctorInstall指定自定义安装脚本(默认:`npm install` 或 `yarn`)
--doctorTest指定自定义测试脚本(默认:`npm test`)

示例:

$ ncu --doctor -u
在升级前运行测试
npm install
npm run test
升级所有依赖项并重新运行测试
ncu -u
npm install
npm run test
测试失败
识别破坏性依赖项
npm install
npm install --no-save react@16.0.0
npm run test
  ✓ react 15.0.0 → 16.0.0
npm install --no-save react-redux@7.0.0
npm run test
  ✗ react-redux 6.0.0 → 7.0.0

/projects/myproject/test.js:13
  throw new Error('Test failed!')
  ^

npm install --no-save react-dnd@11.1.3
npm run test
  ✓ react-dnd 10.0.0 → 11.1.3
保存部分升级的 package.json

filter

用法:

ncu --filter [p]
ncu -f [p]

仅包含匹配给定字符串、通配符、glob、逗号或空格分隔列表、/正则表达式/或谓词函数的包名。只有包含的包会使用 --peer 进行检查。

--filter 在获取新版本之前运行,而 --filterResults 则在之后运行。

谓词函数仅在 .ncurc.js 中或将 npm-check-updates 作为模块导入时可用,不能在命令行中使用。

/**
  @param name     依赖项的名称。
  @param semver   已升级版本的解析 Semver 数组。
    (参见:https://git.coolaj86.com/coolaj86/semver-utils.js#semverutils-parse-semverstring)
  @returns        如果应包含该包则返回 true,如果应排除则返回 false。
*/
filterFunction: (name, semver) => {
  if (name.startsWith('@myorg/')) {
    return false
  }
  return true
}

filterResults

基于用户提供的函数过滤升级。

filterResults 在获取新版本之后运行,而 filterrejectfilterVersionrejectVersion 则在之前运行。这允许您基于版本变化(例如主版本变更)使用 filterResults 过滤升级。

仅在 .ncurc.js 中或将 npm-check-updates 作为模块导入时可用。

/** 过滤掉非主要版本更新。
  @param {string} packageName        依赖项的名称。
  @param {string} current            当前版本声明(可能是一个范围)。
  @param {SemVer[]} currentSemver    语义版本格式的当前版本声明(可能是一个范围)。
  @param {string} upgraded           升级后的版本。
  @param {SemVer} upgradedSemver     语义版本格式的升级后版本。
  @returns {boolean}                 如果应保留升级则返回 true,否则将被忽略。
*/
filterResults: (packageName, { current, currentSemver, upgraded, upgradedSemver }) => {
  const currentMajor = parseInt(currentSemver[0]?.major, 10)
  const upgradedMajor = parseInt(upgradedSemver?.major, 10)
  if (currentMajor && upgradedMajor) {
    return currentMajor < upgradedMajor
  }
  return true
}

有关 SemVer 类型定义,请参见:https://git.coolaj86.com/coolaj86/semver-utils.js#semverutils-parse-semverstring

filterVersion

用法:

ncu --filterVersion [p]

仅包含匹配给定字符串、通配符、glob、逗号或空格分隔列表、/正则表达式/或谓词函数的版本。

谓词函数仅在 .ncurc.js 中或将 npm-check-updates 作为模块导入时可用,不能在命令行中使用。此函数是 filter 选项函数的别名。

/**
  @param name     依赖项的名称。
  @param semver   已升级版本的解析 Semver 数组。
    (参见:https://git.coolaj86.com/coolaj86/semver-utils.js#semverutils-parse-semverstring)
  @returns        如果应包含该包则返回 true,如果应排除则返回 false。
*/
filterVersionFunction: (name, semver) => {
  if (name.startsWith('@myorg/') && parseInt(semver[0]?.major) > 5) {
    return false
  }
  return true
}

format

用法:

ncu --format [值]

修改输出格式或显示附加信息。指定一个或多个逗号分隔的值。

group按主要、次要、补丁和主版本零更新对包进行分组。
ownerChanged显示包所有者是否已更改。
repo推断并显示包的源代码仓库链接。需要安装包。
time显示每个升级的发布时间。
lines在单独的行上打印 name@version。适用于通过管道传输到 npm install。

groupFunction

使用 --format group 时自定义包如何分组。

仅在 .ncurc.js 中或将 npm-check-updates 作为模块导入时可用,不能在命令行中使用。

/**
  @param name             依赖项的名称。
  @param defaultGroup     默认使用的预定义分组名称。
  @param currentSpec      package.json 中的当前版本范围。
  @param upgradedSpec     将写入 package.json 的升级后版本范围。
  @param upgradedVersion  注册表返回的升级后版本号。
  @returns                预定义分组名称('major' | 'minor' | 'patch' | 'majorVersionZero' | 'none')或自定义字符串以创建自己的分组。
*/
groupFunction: (name, defaultGroup, currentSpec, upgradedSpec, upgradedVersion) => {
  if (name === 'typescript' && defaultGroup === 'minor') {
    return 'major'
  }
  if (name.startsWith('@myorg/')) {
    return 'My Org'
  }
  return defaultGroup
}

install

用法:

ncu --install [值]

默认: prompt

控制自动安装行为。

always升级后自动运行包管理器的安装命令。
never不安装且不提示。
prompt升级后显示消息建议安装,但不执行安装。在交互模式下,提示是否安装。(默认)

packageManager

用法:

ncu --packageManager [s]
ncu -p [s]

指定查找版本时使用的包管理器。

npm系统安装的 npm。默认。
yarn系统安装的 yarn。如果存在 yarn.lock 文件则自动使用。
pnpm系统安装的 pnpm。如果存在 pnpm-lock.yaml 文件则自动使用。
bun系统安装的 bun。如果存在 bun.lockb 文件则自动使用。

peer

用法:

ncu --peer
ncu --no-peer

检查已安装包的对等依赖,并将更新过滤为兼容版本。

示例:

以下示例演示了 --peer 的工作原理,以及它如何使用升级模块的对等依赖。

ncu-test-peer-update 包发布了两个版本:

  • 1.0.0 的对等依赖为 "ncu-test-return-version": "1.0.x"
  • 1.1.0 的对等依赖为 "ncu-test-return-version": "1.1.x"

我们的测试应用具有以下依赖项:

"ncu-test-peer-update": "1.0.0",
"ncu-test-return-version": "1.0.0"

这些包的最新版本是:

"ncu-test-peer-update": "1.1.0",
"ncu-test-return-version": "2.0.0"

使用 --peer:

ncu 将包升级到仍然遵守对等依赖约束的最高版本:

ncu-test-peer-update     1.0.0  →  1.1.0
ncu-test-return-version  1.0.0  →  1.1.0

不使用 --peer:

作为对比:不使用 --peer 选项时,ncu 将建议最新版本,忽略对等依赖:

ncu-test-peer-update     1.0.0  →  1.1.0
ncu-test-return-version  1.0.0  →  2.0.0

registryType

用法:

ncu --registryType [类型]

指定 --registry 是指完整的 npm 注册表还是简单的 JSON 文件。

npm默认 npm 注册表
json从文件或简单 JSON 注册表的 URL 检查版本。必须包含 `--registry` 选项。

示例:

// 本地文件
$ ncu --registryType json --registry ./registry.json

// URL
$ ncu --registryType json --registry https://api.mydomain/registry.json

// 当注册表以 .json 结尾时,可以省略 --registryType
$ ncu --registry ./registry.json
$ ncu --registry https://api.mydomain/registry.json

registry.json:

{
  "prettier": "2.7.1",
  "typescript": "4.7.4"
}

reject

用法:

ncu --reject [p]
ncu -x [p]

--filter 的反向操作。排除与给定字符串、通配符、glob、逗号或空格分隔列表、/正则表达式/或谓词函数匹配的包名。这也会将它们从 --peer 检查中排除。

--reject 在获取新版本之前运行,而 --filterResults 在之后运行。

谓词函数仅在 .ncurc.js 中或将 npm-check-updates 作为模块导入时可用,在命令行中不可用。

/**
  @param name     依赖项的名称。
  @param semver   升级版本的解析 Semver 数组。
    (参见: https://git.coolaj86.com/coolaj86/semver-utils.js#semverutils-parse-semverstring)
  @returns        如果包应被排除则返回 true,如果应包含则返回 false。
*/
rejectFunction: (name, semver) => {
  if (name.startsWith('@myorg/')) {
    return true
  }
  return false
}

rejectVersion

用法:

ncu --rejectVersion [p]

--filterVersion 的反向操作。排除与给定字符串、通配符、glob、逗号或空格分隔列表、/正则表达式/或谓词函数匹配的版本。

谓词函数仅在 .ncurc.js 中或将 npm-check-updates 作为模块导入时可用,在命令行中不可用。此函数是 reject 选项函数的别名。

/**
  @param name     依赖项的名称。
  @param semver   升级版本的解析 Semver 数组。
    (参见: https://git.coolaj86.com/coolaj86/semver-utils.js#semverutils-parse-semverstring)
  @returns        如果包应被排除则返回 true,如果应包含则返回 false。
*/
rejectVersionFunction: (name, semver) => {
  if (name.startsWith('@myorg/') && parseInt(semver[0]?.major) > 5) {
    return true
  }
  return false
}

target

用法:

ncu --target [值]
ncu -t [值]

确定要升级到的版本。(默认: "latest")

greatest升级到已发布的最高版本号,不考虑发布日期或标签。包括预发布版本。
latest升级到包的"latest"git标签所指向的版本。除非指定--pre,否则不包括预发布版本。
minor升级到最高的次要版本,但不升级主要版本。
newest升级到发布日期最近的版本,即使存在其他更高的版本号。包括预发布版本。
patch升级到最高的补丁版本,但不升级次要或主要版本。
semver升级到package.json中指定的语义化版本范围内的最高版本。
@[tag]升级到发布到特定标签的版本,例如'next'或'beta'。

你还可以在.ncurc.js文件中指定自定义函数,或在将npm-check-updates作为模块导入时指定:

/** 将主版本为零的升级到下一个次要版本,其他版本升级到最新版本。
  @param name     依赖项的名称。
  @param semver   升级版本的解析后的Semver对象。
    (参见:https://git.coolaj86.com/coolaj86/semver-utils.js#semverutils-parse-semverstring)
  @returns        上表中指定的有效目标值之一。
*/
target: (name, semver) => {
  if (parseInt(semver[0]?.major) === '0') return 'minor'
  return 'latest'
}

配置文件

使用.ncurc.{json,yml,js,cjs}文件来指定配置信息。 你可以使用--configFileName和--configFilePath命令行选项来指定文件名和路径。

例如,.ncurc.json:

{
  "upgrade": true,
  "filter": "svelte",
  "reject": ["@types/estree", "ts-node"]
}

如果你使用json或yaml编写.ncurc配置文件,你可以将JSON Schema添加到IDE设置中以获得自动完成功能。

例如,对于VS Code:

  "json.schemas": [
    {
      "fileMatch": [
        ".ncurc",
        ".ncurc.json",
      ],
      "url": "https://raw.githubusercontent.com/raineorshine/npm-check-updates/main/src/types/RunOptions.json"
    }
  ],
  "yaml.schemas": {
    "https://raw.githubusercontent.com/raineorshine/npm-check-updates/main/src/types/RunOptions.json": [
        ".ncurc.yml",
    ]
  },

模块/程序化使用

npm-check-updates可以作为模块导入:

import ncu from 'npm-check-updates'

const upgraded = await ncu.run({
  // 传递任何cli选项
  packageFile: '../package.json',
  upgrade: true,
  // 默认值:
  // jsonUpgraded: true,
  // silent: true,
})

console.log(upgraded) // { "mypackage": "^2.0.0", ... }

贡献

我们欢迎并感谢贡献。我会回应所有的PR,并可以就如何进行修改提供指导。有关贡献提示,请参阅CONTRIBUTING.md。

遇到问题?

提交一个issue。请先搜索现有的issues。

项目侧边栏1项目侧边栏2
推荐项目
Project Cover

豆包MarsCode

豆包 MarsCode 是一款革命性的编程助手,通过AI技术提供代码补全、单测生成、代码解释和智能问答等功能,支持100+编程语言,与主流编辑器无缝集成,显著提升开发效率和代码质量。

Project Cover

AI写歌

Suno AI是一个革命性的AI音乐创作平台,能在短短30秒内帮助用户创作出一首完整的歌曲。无论是寻找创作灵感还是需要快速制作音乐,Suno AI都是音乐爱好者和专业人士的理想选择。

Project Cover

有言AI

有言平台提供一站式AIGC视频创作解决方案,通过智能技术简化视频制作流程。无论是企业宣传还是个人分享,有言都能帮助用户快速、轻松地制作出专业级别的视频内容。

Project Cover

Kimi

Kimi AI助手提供多语言对话支持,能够阅读和理解用户上传的文件内容,解析网页信息,并结合搜索结果为用户提供详尽的答案。无论是日常咨询还是专业问题,Kimi都能以友好、专业的方式提供帮助。

Project Cover

阿里绘蛙

绘蛙是阿里巴巴集团推出的革命性AI电商营销平台。利用尖端人工智能技术,为商家提供一键生成商品图和营销文案的服务,显著提升内容创作效率和营销效果。适用于淘宝、天猫等电商平台,让商品第一时间被种草。

Project Cover

吐司

探索Tensor.Art平台的独特AI模型,免费访问各种图像生成与AI训练工具,从Stable Diffusion等基础模型开始,轻松实现创新图像生成。体验前沿的AI技术,推动个人和企业的创新发展。

Project Cover

SubCat字幕猫

SubCat字幕猫APP是一款创新的视频播放器,它将改变您观看视频的方式!SubCat结合了先进的人工智能技术,为您提供即时视频字幕翻译,无论是本地视频还是网络流媒体,让您轻松享受各种语言的内容。

Project Cover

美间AI

美间AI创意设计平台,利用前沿AI技术,为设计师和营销人员提供一站式设计解决方案。从智能海报到3D效果图,再到文案生成,美间让创意设计更简单、更高效。

Project Cover

AIWritePaper论文写作

AIWritePaper论文写作是一站式AI论文写作辅助工具,简化了选题、文献检索至论文撰写的整个过程。通过简单设定,平台可快速生成高质量论文大纲和全文,配合图表、参考文献等一应俱全,同时提供开题报告和答辩PPT等增值服务,保障数据安全,有效提升写作效率和论文质量。

投诉举报邮箱: service@vectorlightyear.com
@2024 懂AI·鲁ICP备2024100362号-6·鲁公网安备37021002001498号