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

@tq1086/jaf-cli

v0.4.9

Published

JAF - JSON API Format: A simple CLI for executing HTTP requests with variable management

Downloads

699

Readme

JAF - JSON API Flow CLI

版本: 0.4.4

JAF (JSON API Flow) 是一种轻量级脚本语言,用于快速测试 JSON API。支持变量、路径级联、登录态管理和响应断言。

设计原则:

  • 理解、生成优先于执行
  • 只支持 JSON,无其他格式
  • 线性执行,无循环条件
  • 人类可读,LLM 友好
  • 够用即可,避免过度设计
  • Fast-fail 策略,简化错误处理

功能特性

  • 简单语法: 易读的 JAF 格式,用于定义 HTTP 请求
  • 变量管理: 支持环境变量、脚本变量和响应捕获
  • 内置变量: UUID、时间戳和随机数生成
  • 变量替换: 在 URL、请求头和请求体中自动替换变量
  • 路径级联: 支持基础 URL 的智能 URL 路径处理
  • 类型转换: 对捕获的变量进行自动类型转换
  • Session 管理: 支持登录态管理和头部注入
  • 响应断言: 支持断言检查和期望验证
  • 响应记录: 将响应保存到输出文件
  • 彩色输出: 清晰的彩色终端输出,便于调试

安装

npm i @tq1086/jaf-cli

使用方法

# 运行 JAF 脚本(同时输出到文件和控制台)
jaf example.jaf

# 指定输出目录
jaf example.jaf -o ./output

# 抑制控制台输出,只写入文件
jaf example.jaf --no-stdout

# 将输出内容复制到剪贴板
jaf example.jaf --clipboard

# 显示详细信息(每个步骤的详细输出)
jaf example.jaf --verbose

# 组合使用:只输出到文件和剪贴板
jaf example.jaf --no-stdout --clipboard

# 显示帮助信息
jaf --help

# 显示版本信息
jaf --version

命令行选项

  • --verbose: 打印每个步骤的详细信息,包括:

    • Tokenizing 阶段详情
    • Parsing 阶段详情(指令和请求数量)
    • 变量替换前后对比
    • 请求和响应的详细信息
    • 带彩色输出的不同级别信息
  • --no-stdout: 抑制控制台输出,但仍输出文件路径和摘要信息

    • --verbose 选项兼容
    • 不影响文件输出功能
  • --clipboard: 将输出内容复制到剪贴板

    • 支持 Windows、macOS、Linux 平台
    • Linux 需要 xclip 或 xsel
    • 提供清晰的错误提示和降级处理

JAF 语法

基础语法

#!      变量定义、默认值、路径前缀、session(单行)
#@      请求配置与断言(单行,可累积)
#>      记录实际收到的响应(单行,可累积,只读)
{}      HTTP 请求(JSON,可多行)
#       行内注释(单行)

指令

设置基础 URL(路径级联)

#!base = https://api.example.com

设置基础 URL 后,可以使用:

  • 完整 URL: https://other.com/path(原样使用)
  • 协议相对: //api.example.com/path(使用基础 URL 的协议)
  • 绝对路径: /users(替换基础 URL 的路径)
  • 相对路径: users(追加到基础 URL 的路径)

定义脚本变量

#!var USER_ID = 123
#!var API_KEY = "secret-key"
#!var USER_NAME = "张三"

使用环境变量

#!env API_KEY
#!env API_KEY ?= default-value

设置默认请求参数

#!default {"method": "POST", "headers": {"Content-Type": "application/json"}}

Session 管理

#!session {"headers": {"Authorization": "Bearer @{token}"}}
#!session begin
# ... 带有 session 请求头的请求 ...
#!session end

请求配置与断言(#@)

#@ timeout 5000                    # 设置超时
#@ capture $.token auth_token     # 捕获响应路径到变量
#@ capture $.expires exp:number   # 带类型转换
#@ expect status ok                # 期望精确值
#@ expect code <number>            # 期望类型
#@ assert $status == 200           # 断言条件
#@ ignore error                    # 忽略错误

响应记录(#>)

#> record $.body             # 记录完整响应体
#> record $.status           # 记录状态码
#> record $header.Content-Type  # 记录响应头
#> record $.items[0]         # 记录数组元素

请求

# GET 请求
{"method": "GET", "uri": "/users"}

# 带请求体的 POST 请求
{"method": "POST", "uri": "/users", "headers": {"Content-Type": "application/json"}, "body": {"name": "John"}}

# PUT 请求
{"method": "PUT", "uri": "/users/@{USER_ID}", "headers": {"Content-Type": "application/json"}, "body": {"name": "Updated"}}

# DELETE 请求
{"method": "DELETE", "uri": "/users/@{USER_ID}"}

变量引用

  • 环境变量: ${ENV_VAR}${ENV_VAR?=default}
  • 脚本变量: @{scriptVar}(在路径中自动进行 URL 编码)
  • 捕获变量: @{capturedVar}

内置变量

  • @{_uuid_}: 生成随机 UUID
  • @{_timestamp_}: 当前 Unix 时间戳(秒)
  • @{_timestamp_ms_}: 当前 Unix 时间戳(毫秒)
  • @{_iso_timestamp_}: ISO 8601 格式时间戳(如 2024-01-15T10:30:00.000Z)
  • @{_random_}: 0 到 1 之间的随机数
  • @{_random_}: 0 到 1 之间的随机数

注意: 内置变量是只读的,不能被用户定义的变量覆盖。

URL 编码

路径中的变量会自动进行 URL 编码:

#!var USER_NAME = "张三"
{"method": "GET", "uri": "/users/@{USER_NAME}"}
# URL 变为: /users/%E5%BC%A0%E4%B8%89

示例

基本 API 测试

#!base = https://jsonplaceholder.typicode.com
#!var USER_ID = 1

# 获取所有用户
{"method": "GET", "uri": "/users"}

# 获取特定用户并捕获数据
{"method": "GET", "uri": "/users/@{USER_ID}"}
#@ capture $.id user_id
#@ capture $.name user_name
#@ capture $.email user_email

# 使用捕获的用户 ID 创建帖子
{"method": "POST", "uri": "/posts", "headers": {"Content-Type": "application/json"}, "body": {"title": "Test", "userId": @{user_id}}}

路径级联

#!base = https://api.example.com/v1

# 完整 URL(忽略基础 URL)
{"method": "GET", "uri": "https://other.com/data"}

# 协议相对(使用基础 URL 的协议)
{"method": "GET", "uri": "//api2.example.com/users"}

# 绝对路径(替换基础 URL 的路径)
{"method": "GET", "uri": "/users"}

# 相对路径(追加到基础 URL 的路径)
{"method": "GET", "uri": "posts"}
# 结果: https://api.example.com/v1/posts

Session 管理

#!base = https://api.example.com
#!var USERNAME = "test"
#!var PASSWORD = "secret"

# 登录并捕获 token
{"method": "POST", "uri": "/login", "headers": {"Content-Type": "application/json"}, "body": {"username": @{USERNAME}, "password": @{PASSWORD}}}
#@ capture $.token auth_token

# 定义 session 头部(多行累积)
#!session {"headers": {"Authorization": "Bearer @{auth_token}"}}

# 开始 session(此时才展开变量)
#!session begin

# session 中的所有请求都包含授权请求头
{"method": "GET", "uri": "/profile"}
{"method": "GET", "uri": "/settings"}

# 结束 session(移除授权请求头)
#!session end

类型转换与断言

#!base = https://api.example.com

# 捕获各种类型
{"method": "GET", "uri": "/user/@{USER_ID}"}
#@ capture $.id user_id:number
#@ capture $.name user_name:string
#@ capture $.isActive active:boolean
#@ capture $.roles roles:array
#@ capture $.metadata meta:object

# 断言检查
#@ assert $status == 200
#@ assert $.id > 0
#@ expect id <string>
#@ expect name "test"

# 使用捕获的变量
{"method": "POST", "uri": "/users/@{user_id}/update", "headers": {"Content-Type": "application/json"}, "body": {"name": @{user_name}, "active": @{active}}}

输出

响应保存到以下格式的文件中:<origin>.output.<yyyymmdd>.<seq>.jaf.txt

输出文件包含:

  • 原始 JAF 文件的全部内容
  • 在每个请求的下一行添加 #> 输出记录实际响应

示例输出:

{"method": "GET", "uri": "/users"}
#> {"id":1,"name":"Leanne Graham"}

{"method": "GET", "uri": "/users/1"}
#> {"id":1,"name":"Leanne Graham","email":"[email protected]"}

{"method": "POST", "uri": "/posts", "body": {"title": "Test"}}
#> {"id":101,"title":"Test","userId":1}

开发

# 安装依赖
pnpm install

# 运行测试
pnpm test

# 运行测试并生成覆盖率报告
pnpm test:coverage

# 构建
pnpm build

# 监视模式(开发)
pnpm dev

# 代码检查
pnpm lint

# 修复代码检查问题
pnpm lint:fix

# 格式化代码
pnpm format

# 类型检查
pnpm type-check

项目结构

src/
├── cli/           # CLI 入口
├── executor/      # HTTP 请求执行
├── formatter/     # 输出格式化
├── parser/        # JAF 语法解析器
├── runtime/       # Session 管理
├── tokenizer/     # JAF 语法词法分析器
├── types/         # TypeScript 类型定义
├── validator/     # 断言和 Schema 验证
└── variables/     # 变量管理

常见问题

Q: 如何处理身份验证?

A: 使用环境变量或捕获的 token:

#!env API_KEY
#!default {"headers": {"Authorization": "Bearer ${API_KEY}"}}

Q: 可以在请求头中使用变量吗?

A: 可以,变量在请求头和请求体中都有效:

{"method": "GET", "uri": "/users", "headers": {"X-User-ID": @{USER_ID}}}

Q: 如果捕获失败会发生什么?

A: 默认情况下,捕获失败会停止执行。可以使用 #@ ignore error 来忽略错误:

#@ ignore error
#@ capture $.optional_field field

Q: 如何测试非 JSON 响应?

A: JAF 只支持 JSON 响应,非 JSON 响应会报错停止执行。

Q: 变量替换是如何工作的?

A: 变量替换是文本级别的。变量值会被转换为字符串并直接插入到文本中。用户需要确保替换后的结果是合法的 JSON。

示例:

#!var NUM = 42
{"method": "POST", "uri": "/data", "body": {"value": @{NUM}}}
# 结果: {"method": "POST", "uri": "/data", "body": {"value": 42}}

注意事项:

  • 变量值会被转换为字符串后插入
  • 如果变量包含特殊字符,可能会导致 JSON 格式错误
  • 使用类型转换确保变量值正确
  • 内置变量是只读的,不能被覆盖

Q: 如何使用 --verbose 选项调试?

A: 使用 --verbose 选项查看每个步骤的详细信息:

jaf example.jaf --verbose

这将显示:

  • Tokenizing 和 Parsing 阶段的详细信息
  • 变量替换前后对比
  • 请求和响应的完整内容
  • 带彩色输出的调试信息

Q: --no-stdout 选项有什么用?

A: --no-stdout 选项抑制控制台输出,但仍输出文件路径和摘要:

jaf example.jaf --no-stdout

适用于:

  • 自动化脚本中只关心文件输出
  • 减少控制台输出干扰
  • --verbose 选项兼容(verbose 信息仍会显示)

Q: 如何在 Linux 上使用 --clipboard 选项?

A: Linux 需要安装 xclip 或 xsel:

# Ubuntu/Debian
sudo apt-get install xclip

# Fedora/RHEL
sudo dnf install xclip

# Arch
sudo pacman -S xclip

安装后即可使用:

jaf example.jaf --clipboard

Q: JAF 支持哪些变量类型?

A: JAF 只支持 primitive 类型(string/number/boolean/null),不支持 object/array。

Q: 如何隐藏 C 堆栈错误?

A: 在 PowerShell 中使用 2>$null 重定向 stderr:

jaf example.jaf 2>$null

这将隐藏来自 libuv 的 C 堆栈错误信息。

规范文档

详细的 JAF 语言规范请参考 jaf.md

更新日志

v0.4.1 (2026-02-19)

改进:

  • 添加 --verbose 选项,支持详细日志输出
  • 在请求信息中显示实际发送的完整 URL(host 和 path)
  • 优化输出文件名格式:<original>.output.<yyyymmdd>.<seq>.jaf.txt(序号自动递增,3位数字)
  • 移除 example.jaf.txt,使用 examples/ 目录中的示例文件
  • 更新 .gitignore,忽略所有测试和临时文件
  • 所有日志消息改为中文输出

v0.4.0 (2026-02-19)

重大更新:

  • 完全重构语法以符合 jaf.md 规范
  • 修改 #@ 指令语法:
    • #@ capture PATH VAR#@ capture PATH VAR:TYPE
    • #@ expect FIELD VALUE#@ expect FIELD <TYPE>
    • #@ assert CONDITION
    • #@ ignore error(两个词)
  • 修改 #> 指令语法:
    • #> record PATH(只记录,不参与逻辑控制)
  • 移除旧的 #> capture/expect 语法
  • 更新 token 类型和 AST 类型定义
  • 更新 tokenizer 和 parser 以支持新语法

改进:

  • Output file 现在包含原始 jaf 文件的全部内容
  • 在请求下一行添加 #> 输出记录实际响应
  • 更新 .gitignore 忽略所有临时和测试文件
  • 更新 README 文档以反映最新语法

修复:

  • 修复 parser 没有正确传递 tokens 的问题
  • 修复 default method 没有被正确应用的问题
  • 修复 formatter 没有初始化 outputLines 的问题

v0.3.0 (2026-02-19)

新增功能:

  • 新增 @{_iso_timestamp_} 内置变量,生成 ISO 8601 格式时间戳
  • 改进错误提示,包含行号定位和修复建议
  • 完善 --verbose 选项,打印每个步骤的详细信息
  • 完善 --no-stdout 选项,抑制控制台输出但仍显示关键信息
  • 完善 --clipboard 选项,改进跨平台支持和错误提示

改进:

  • 添加内置变量只读保护
  • 改进变量替换错误提示
  • 添加变量替换最佳实践文档
  • 改进语法错误提示,包含彩色输出

修复:

  • 修复变量替换规则文档说明

v0.2.0 (2025-12-15)

新增功能:

  • 支持 Session 管理
  • 支持变量类型转换
  • 支持可选字段捕获
  • 改进错误处理

改进:

  • 优化性能
  • 改进日志输出

v0.1.0 (2025-12-01)

初始发布:

  • 基础 JAF 语言支持
  • 变量管理
  • HTTP 请求执行
  • 响应断言

许可证

MIT

Q: 如何在 Linux 上使用 --clipboard 选项?

A: Linux 需要安装 xclip 或 xsel:

# Ubuntu/Debian
sudo apt-get install xclip

# Fedora/RHEL
sudo dnf install xclip

# Arch
sudo pacman -S xclip

安装后即可使用:

jaf example.jaf --clipboard

Q: 如何隐藏 C 堆栈错误信息?

A: 在 Windows 上,有时会看到来自 libuv 的 C 堆栈错误信息(如 "Assertion failed: !(handle->flags & UV_HANDLE_CLOSING)")。这些是 Node.js 内部错误,不影响 JAF 的功能。

要隐藏这些错误,在 PowerShell 中使用 2>$null 重定向:

jaf example.jaf --verbose 2>$null

这将:

  • 隐藏 C 堆栈错误信息
  • 保留所有正常的 JAF 输出
  • 不影响任何功能

更新日志

v0.4.5 (2026-02-19)

重要修复:

  • 修复 Fast-Fail 机制:当请求失败且没有 #@ ignore error 时,正确抛出异常停止执行
  • 修复 #@ ignore error 指令支持:现在可以正确忽略单个请求的错误并继续执行后续请求
  • 修复绝对路径处理:将以 / 开头的路径正确追加到 base URL 路径,而不是替换
  • 修复 CLI URL 显示逻辑:确保 CLI 显示的 URL 与实际发送的 URL 一致
  • 改进错误处理:即使在 fast-fail 情况下也会生成输出文件,保留部分执行结果

架构改进:

  • 重构预请求指令(#@)处理:现在指令与特定请求关联,而不是全局指令
  • 改进 tokenizer:收集请求之前的 #@ 指令并关联到请求
  • 改进 parser:正确解析请求关联的预请求指令
  • 改进 CLI:在执行请求前正确处理预请求指令(如 #@ ignore error

规范对齐:

  • 绝对路径处理现在完全符合 jaf.md 规范:/usershttp://api.com/v1/users
  • 相对路径处理:usershttp://api.com/v1/users
  • 完整 URL:https://other.com/api → 原样使用
  • 协议相对://cdn.com/file → 使用 base URL 的协议

v0.4.4 (2026-02-19)

修复:

  • 修复 verbose 输出中显示 undefined 方法的问题
  • 当请求未指定 method 时,正确显示默认方法或 GET

v0.4.3 (2026-02-19)

功能改进:

  • 优化输出文件命名:序号不再使用前导零(如 1, 2, 3 而不是 001, 002, 003)
  • 输出文件序号自动递增:每次运行时检查已存在的文件,自动使用下一个可用的序号
  • 输出文件只使用 LF 换行符,确保跨平台兼容性
  • 移除控制台输出中的 output file 内容显示,只显示文件路径和摘要
  • 修复默认方法未正确应用的问题
  • 修复 tokenizer 将未定义 method 设置为空字符串的问题

修复:

  • 修复输出文件路径问题,确保只在输出目录中创建文件
  • 修复错误处理中的模板字符串问题

v0.4.2 (2026-02-19)

安全改进:

  • 新增敏感变量屏蔽功能:当输出环境变量或脚本变量时,如果变量名包含 "key"(不区分大小写),自动屏蔽变量值
  • 屏蔽规则:短值(≤8字符)显示首尾字符,长值(>8字符)显示前4位和后4位

修复:

  • 修复输出文件路径问题,确保只在输出目录中创建文件
  • 修复错误处理中的模板字符串问题

v0.4.1 (2026-02-19)

新增功能:

  • 新增 @{_iso_timestamp_} 内置变量,生成 ISO 8601 格式时间戳
  • 改进错误提示,包含行号定位和修复建议
  • 将请求字段从 path 改为 uri 以符合 jaf.md 规范
  • 完善 --verbose 选项,打印每个步骤的详细信息
  • 完善 --no-stdout 选项,抑制控制台输出但仍显示关键信息
  • 完善 --clipboard 选项,改进跨平台支持和错误提示

改进:

  • 添加内置变量只读保护
  • 改进变量替换错误提示
  • 添加变量替换最佳实践文档
  • 改进语法错误提示,包含彩色输出

修复:

  • 修复变量替换规则文档说明

文档:

  • 更新 README.md,包含所有新功能说明
  • 添加变量替换最佳实践章节
  • 添加常见问题解答

许可证

MIT