npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@megic/easy-dev

v1.0.0

Published

一个专注 OpenAPI-only 的命令行工具: - 以 OpenAPI 作为唯一真源(Single Source of Truth) - 版本快照直接保存 OpenAPI 文件到 `versions/<semver>/` - 直接从两个 OpenAPI 文件生成数据库增量 SQL(Postgres) - 可选:保留解析到 JSON 的能力,但默认流程不依赖 JSON 元数据

Readme

easy-dev CLI (edev)

一个专注 OpenAPI-only 的命令行工具:

  • 以 OpenAPI 作为唯一真源(Single Source of Truth)
  • 版本快照直接保存 OpenAPI 文件到 versions/<semver>/
  • 直接从两个 OpenAPI 文件生成数据库增量 SQL(Postgres)
  • 可选:保留解析到 JSON 的能力,但默认流程不依赖 JSON 元数据

快速开始(OpenAPI-only 默认流程)

要求:Node.js >= 18

npm run build
npm link # 将 edev 命令链接到全局

# 保存 OpenAPI 到版本目录(推荐)
edev version create -v 0.1.1 -m "保存 JSON 快照" --openapi example/openapi.ns.json

# 直接从两个 OpenAPI 文件对比并生成 SQL(不落 JSON)
edev db diff --from-openapi example/openapi-old.json --to-openapi example/openapi.ns.json -d postgres -o migrations/openapi_old_to_new.sql

# 从 latest 版本的 OpenAPI 对比到新 OpenAPI
edev db diff --from-latest --to-openapi example/openapi.ns.json -d postgres -o migrations/latest_to_new.sql

# 指定某个版本作为旧版(versions/<v>/openapi.*)
edev db diff --from-version 0.1.1 --to-openapi example/openapi.ns.json -d postgres -o migrations/0.1.1_to_new.sql

# 从 Git tag/commit 读取旧版 OpenAPI 并对比当前 OpenAPI
edev db diff --from-git v0.1.1 --to-openapi example/openapi.ns.json -d postgres -o migrations/git_v0.1.1_to_new.sql

以上命令均默认优先使用 OpenAPI;仅当未找到 OpenAPI 时才回退到 JSON 物理模型(例如 --from versions/0.1.1/physical.json--to meta/physical.json)。

说明:--from-git <ref> 将尝试从 <ref> 提交下的以下路径中定位 OpenAPI(依次):versions/*/openapi.json(选择最高版本)、example/openapi.jsonopenapi.json,并写入缓存临时文件用于解析。

发布与安装

发布到 npm

  1. 确保 package.json 中的 name 是唯一的(建议使用 scope 包,如 @your-username/easy-dev)。
  2. 登录 npm:
    npm login
  3. 构建并发布:
    # 自动运行 build 脚本
    npm publish --access public

全局安装

用户可以通过以下命令全局安装:

npm install -g easy-dev
# 或者如果是 scope 包
npm install -g @your-username/easy-dev

安装后即可在任意目录下使用 edev 命令。

OpenAPI 扩展约定

  • 物理模型标记:在 components.schemas.* 中使用 x-physical: truex-db.table: "表名" 标记为物理模型实体
  • 列属性扩展:
    • x-primary-key: true 设置主键列
    • x-unique: true 设置唯一约束
    • nullable: true/falsedefault 作为列属性
    • description: string 列描述(用于 Postgres 的 COMMENT ON COLUMN
  • 表描述:表的 description: string 用于 Postgres 的 COMMENT ON TABLE
  • 额外 SQL:
    • x-db.sql: string[] 支持宏替换:{{table}} -> 实际表名(启用命名空间后如 app_members
    • 列级内联片段:在列上使用 x-db.sql: string | string[](例如 DEFAULT now())将直接附加到列定义
    • 建议写成幂等语句(IF NOT EXISTS)以适配重复执行场景
  • 列类型覆盖:
    • 使用 x-db.sqlType(或 x-db: { sqlType })指定列 SQL 类型(如 JSONBTEXT[]TIMESTAMPTZ
    • 未指定时 object/array 默认映射为 TEXT;指定后按给定类型输出(不校验兼容性)
    • 迁移提示(Postgres):从 TEXT/VARCHAR 转为 JSON/JSONB 时,自动加入 USING 强制转换;请确保现有数据可解析为合法 JSON
  • 命名空间行为:
    • 启用 --namespace 时,x-db.table 自动加上下划线前缀(如 app_members);schemas 名称前缀为 <目录名><分隔符> 并自动重写 $ref
  • 示例:参见 example/modules/*/openapi.json 与合并后的 example/openapi.ns.json

目录约定

  • versions/<semver>/:版本快照(openapi.json
  • CHANGELOG.md:版本记录
  • migrations/:diff 输出的 SQL 文件
  • meta/:可选的 JSON 快照(如果需要)

可选功能(非默认)

  • 解析 OpenAPI 为 JSON 元数据快照:
    edev parse -i example/openapi.ns.json -o meta -d postgres
  • 基于 JSON 快照的数据库增量(历史 versions/<v>/physical.json 到当前 meta/physical.json):
    edev db diff -d postgres -o migrations/0.1.0_to_current.sql

注意

  • 当前 diff 主要支持表创建/删除、列新增/删除、列类型/可空/默认值/唯一约束变更;更复杂约束(复合主键、外键、索引等)可后续扩展。
  • OpenAPI-only 模式下,你可以完全跳过 JSON 快照与元数据版本化,直接以 OpenAPI 文件作为版本基线与对比来源。

合并模块为总 OpenAPI(JSON)

  • 说明:遍历子目录中的 openapi.json,合并为一个总的 OpenAPI JSON;按子目录名为每个接口添加 tags 分组。
  • 用法:
    edev openapi merge -d example/modules -o example/openapi.json -t "Example Modules" -v 0.1.0
  • 参数:
    • --dir <modulesDir> 模块目录(子目录中包含 openapi.json
    • --out <file> 输出的合并后 JSON 文件路径
    • --title <text> 顶部 info.title(默认 Merged API
    • --version <ver> 顶部 info.version(默认 0.1.0
    • --namespace 启用命名空间:paths 前缀加子目录名,schemas 加子目录名前缀
    • --ns-sep <sep> 命名空间分隔符(默认 .,例如 system.User
  • 示例(启用命名空间):
    edev openapi merge -d example/modules -o example/openapi.ns.json --namespace
  • 合并策略:
    • paths:合并各模块的路由与操作;每个操作的 tags 自动追加子目录名;启用命名空间时将路径前缀为 /<目录名>
    • components.schemascomponents.securitySchemes:简单合并(同名覆盖,最后出现的生效);启用命名空间时 schemas 名称前缀为 <目录名><分隔符> 并自动重写文档中的 $ref
    • x-db.table:启用命名空间时自动加上下划线前缀(如 app_memberssystem_users

合并模块初始化脚本 (init.sql)

  • 说明:扫描模块目录下的所有子目录,寻找 init.sql 文件,将其合并为一个总的初始化 SQL 脚本。
  • 特性:
    • 自动移除各模块 init.sql 中的事务控制语句 (BEGIN/COMMIT/ROLLBACK),避免嵌套事务错误。
    • 在最终生成的 SQL 文件外层包裹统一的事务 (BEGIN; ... COMMIT;)。
    • 按模块目录名称排序合并顺序。
  • 用法:
    edev merge-init-sql --dir example/modules --out example/full_init.sql
  • 参数:
    • --dir <dir> 模块根目录(包含多个子模块目录)
    • --out <file> 输出的合并后 SQL 文件路径

生成完整 SQL(建表 + 额外 SQL + 描述)

  • 目的:从单一 OpenAPI 直接生成完整物理建表与扩展 SQL,且支持宏替换。
  • 命令:
    edev db generate --from-openapi example/openapi.ns.json --out example/full.sql --dialect postgres
  • 行为:
    • 生成 CREATE TABLE 语句(根据 x-physical/x-db.table 与列定义)
    • 生成 Postgres 的 COMMENT ON TABLECOMMENT ON COLUMN 语句(来自 description
    • 读取 x-db.sql: string[] 并执行宏替换:{{table}} -> 实际表名(命名空间后,如 app_members
    • 输出按顺序拼接:建表 -> 注释 -> 额外 SQL
  • 示例(在模块 OpenAPI 中声明额外 SQL,并使用宏):
    {
      "components": {
        "schemas": {
          "Member": {
            "x-physical": true,
            "description": "会员表",
            "x-db": { "table": "members", "sql": [
              "CREATE UNIQUE INDEX IF NOT EXISTS uq_app_members_email ON {{table}} (email)"
            ]},
            "type": "object",
            "required": ["id", "email"],
            "properties": {
              "id": { "type": "string", "x-primary-key": true, "description": "主键ID" },
              "email": { "type": "string", "x-unique": true, "description": "邮箱" },
              "nickname": { "type": "string", "description": "昵称" },
              "createdAt": { "type": "string", "format": "date-time", "description": "创建时间" }
            }
          }
        }
      }
    }
  • 说明:
    • 描述注释目前支持 Postgres(--dialect postgres),其他方言可后续按需补充。
    • 建议将额外 SQL写成幂等语句(IF NOT EXISTS)。

对比现有数据库并生成差异 SQL(Postgres)

  • 目的:将 OpenAPI 物理模型与线上 Postgres 实际表结构进行对比,输出迁移 SQL。
  • 命令:
    edev db diff-db --from-openapi example/openapi.ns.json --url postgres://user:pass@host:5432/db --out migrations/diff_from_db.sql
  • 行为:
    • 新增表:生成 CREATE TABLE,追加 Postgres 的 COMMENT ON TABLE/COMMENT ON COLUMN,并拼接 x-db.sql(支持 {{table}} 宏)
    • 既有表:生成列/可空/默认值/唯一约束/自增等差异的 ALTER TABLE 语句(不重复追加 x-db.sql
    • 输出顺序(新增表部分):建表 -> 注释 -> 额外 SQL
  • 说明:
    • 描述注释目前支持 Postgres(diff-db),其他方言后续按需补充
    • 建议将额外 SQL 写成幂等语句(IF NOT EXISTS)以适配重复执行场景
    • 生成 CREATE TABLE 语句(根据 x-physical/x-db.table 与列定义)
    • 生成 Postgres 的 COMMENT ON TABLECOMMENT ON COLUMN 语句(来自 description
    • 读取 x-db.sql: string[] 并执行宏替换:{{table}} -> 实际表名(命名空间后,如 app_members
    • 输出按顺序拼接:建表 -> 注释 -> 额外 SQL
  • 示例(在模块 OpenAPI 中声明额外 SQL,并使用宏):
    {
      "components": {
        "schemas": {
          "Member": {
            "x-physical": true,
            "description": "会员表",
            "x-db": { "table": "members", "sql": [
              "CREATE UNIQUE INDEX IF NOT EXISTS uq_app_members_email ON {{table}} (email)"
            ]},
            "type": "object",
            "required": ["id", "email"],
            "properties": {
              "id": { "type": "string", "x-primary-key": true, "description": "主键ID" },
              "email": { "type": "string", "x-unique": true, "description": "邮箱" },
              "nickname": { "type": "string", "description": "昵称" },
              "createdAt": { "type": "string", "format": "date-time", "description": "创建时间" }
            }
          }
        }
      }
    }
  • 说明:
    • 描述注释目前支持 Postgres(--dialect postgres),其他方言可后续按需补充。
    • 建议将额外 SQL写成幂等语句(IF NOT EXISTS)。

执行 SQL 文件

  • 命令:edev db exec --url postgres://user:pass@host:5432/db --file path/to.sql
  • 行为:一次性执行整份 SQL;不自动开启事务;遇到错误会停止并返回非零退出码。
  • 多语句:按分号 ; 分隔。请确保每条语句以 ; 结尾(生成器会自动补上)。
  • 示例:
    • 执行生成的完整建表与注释:edev db exec --url postgres://user:pass@host:5432/db --file example/full.sql
    • 执行差异迁移:edev db exec --url postgres://user:pass@host:5432/db --file migrations/diff_from_db.sql
  • 提示:
    • 若 SQL 中包含 Postgres 专属语句(如 COMMENT ONINHERITS),请使用 --dialect postgres 生成。
    • 生产库前建议在测试库验证;必要时将关键步骤包裹在手动事务(BEGIN; ... COMMIT;)中。

数据库管理(Postgres 模板与测试库)

提供了一组命令用于 CI/CD 流程中快速创建、克隆和清理测试数据库。支持并发安全检测、强制覆盖以及标准化 JSON 日志输出。

命令概览

  • 创建模板库:将现有数据库(source)克隆为模板库(template),并标记为模板(禁止连接)。
  • 克隆测试库:基于模板库(template)快速克隆出新的测试库(target)。
  • 删除数据库:清理不再需要的数据库。

连接参数

支持两种连接方式(二选一):

  1. --url:完整的连接字符串,例如 postgres://user:pass@host:5432/db?sslmode=require
  2. 分解参数:
    • --host <host> (必填)
    • --user <user> (必填)
    • --password <pass> (可选)
    • --port <port> (可选,默认 5432)
    • --sslmode <mode> (可选,支持 disable|allow|prefer|require|verify-ca|verify-full)

1. 创建模板库 (create-template)

# 使用 URL
edev db create-template --source-db my_source --template-db my_template --url postgres://u:p@localhost:5432/postgres --force

# 使用分解参数
edev db create-template --source-db my_source --template-db my_template --host localhost --user postgres --password secret --force
  • --source-db:源数据库名(必须存在)。
  • --template-db:目标模板数据库名。
  • --force:如果模板库已存在,强制删除重建;如果源库有连接,强制终止连接。

2. 克隆测试库 (clone-template)

edev db clone-template --template-db my_template --target-db test_db_123 --host localhost --user postgres --force
  • --template-db:模板数据库名(必须存在)。
  • --target-db:新数据库名。
  • --force:如果目标库已存在,强制删除重建。

3. 删除数据库 (drop-db)

edev db drop-db --target-db test_db_123 --host localhost --user postgres --if-exists --force
  • --target-db:要删除的数据库名。
  • --if-exists:如果数据库不存在,不报错(返回成功)。
  • --force:如果数据库有连接,强制终止连接并删除。

CI/CD 集成 (JSON 日志与错误码)

所有数据库管理命令的标准输出(stdout/stderr)均为 JSON 格式(单行),便于机器解析。

  • 格式{"ts": "...", "level": "info|error", "code": "...", "message": "...", "data": {...}}
  • 错误码 (code)
    • OK: 成功
    • DB_NOT_FOUND: 数据库不存在
    • DB_ALREADY_EXISTS: 数据库已存在(且未指定 force)
    • DB_IN_USE: 数据库正被占用(且未指定 force)
    • PG_CONNECT_FAILED: 连接失败(密码/网络等)
    • INVALID_ARGS: 参数错误
  • 退出码:进程退出码与错误类型对应(0=成功, 1=常规错误, 2=参数错误 等)。
  • 项目结构
    • src/:CLI 源码(db/diff.tsdb/types.tsopenapi.tsindex.ts 等)
    • example/:示例输出与合并后的 OpenAPI(openapi.jsonopenapi.ns.jsonfull.sql
    • example/modules/:模块化 OpenAPI(如 app/openapi.jsonsystem/openapi.json
    • migrations/:通过 diff 命令生成的迁移 SQL
    • versions/:OpenAPI 版本快照(推荐保留)

    对齐 example/full.sql

    • 使用合并后的 OpenAPI 生成完整 SQL:
      • edev db generate --from-openapi example/openapi.ns.json --dialect postgres -o example/full.sql
    • full.sql 示例包含:
      • 建表(app_memberssystem_users)与主键
      • 唯一索引与普通索引(可在模块 OpenAPI 的 x-db.sql 中声明,支持 {{table}} 宏)
      • 表与列注释(Postgres)
      • 其他额外 SQL(如分区/继承等 Postgres 特性)建议放入 x-db.sql

类型变更注意事项(Postgres)

  • TEXT/VARCHAR 变更到 INTEGER 时,Postgres 不会自动转换,需要显式 USING
    • 生成的语句将包含:ALTER TABLE "tbl" ALTER COLUMN "id" TYPE INTEGER USING NULLIF(TRIM("id"), '')::INTEGER;
    • 若存在非数字内容(例如 abc),上述转换仍会失败。请先清洗数据或分步迁移:
      • 增加新整型列、回填合法数据、调整主键/外键、再移除旧列;或在事务内批量更新非数字为 NULL/占位。
  • 变更到自增(IDENTITY)建议在类型稳定后再追加:
    • ALTER TABLE "tbl" ALTER COLUMN "id" ADD GENERATED BY DEFAULT AS IDENTITY;

(已合并至上文“OpenAPI 扩展约定”)