ytn — 包使用指南
ytn(whY Try Not)提供便携、可编译为 JavaScript 的 TypeScript 包,用于模式验证、SQL 生成和 CLI 路由。所有包均为纯 ESM、严格 TypeScript,并尽可能实现零外部依赖。
包概览
| 包名 | npm | 安装命令 | 适用场景 |
|---|
@ytrynot/dna | @ytrynot/dna | npm install @ytrynot/dna | 需要类似 Zod 的模式验证,且支持可序列化字节码或独立编译验证器 |
@ytrynot/schvalid | @ytrynot/schvalid | npm install @ytrynot/schvalid | 拥有 JSON Schema 2020-12 并希望实现超快速验证 |
@ytrynot/qb | @ytrynot/qb | npm install @ytrynot/qb | 需要通过流畅 API 或 Zod/DNA 模式构建 SQLite SQL 字符串 |
@ytrynot/cli | @ytrynot/cli | npm install @ytrynot/cli | 需要具有 DNA 验证、自动帮助和 AOT 编译的 CLI 路由器 |
@ytrynot/dna — 模式构建器 + DNA 运行时
安装
npm install @ytrynot/dna
定义模式(类似 Zod 的流畅 API)
import { dna } from "@ytrynot/dna";
const user = dna.object({
name: dna.string().min(2),
email: dna.string().email(),
age: dna.number().int().min(0).optional(),
role: dna.enum(["admin", "user"]).default("user"),
});
type User = dna.infer<typeof user>;
验证 / 解析
user.validate({ name: "John", email: "[email protected]" });
const result = user.safeParse({ name: "J", email: "bad" });
const data = user.parse({ name: "John", email: "[email protected]" });
编译为独立 JS(无需运行时)
import { dna, validator, parser } from "@ytrynot/dna";
const schema = dna.object({ name: dna.string().min(2), age: dna.number() });
const bytecode = schema.toDna();
const validate = validator(bytecode);
validate({ name: "John", age: 30 });
const parse = parser(bytecode);
parse({ name: "John", age: 30 });
对象模式
dna.object({ name: dna.string() })
dna.strictObject({ name: dna.string() })
dna.looseObject({ name: dna.string() })
常用模式类型
dna.string().min(1).max(100).email().uuid().url().regex(/^[a-z]+$/)
dna.number().int().positive().negative().min(0).max(100).multipleOf(2)
dna.boolean()
dna.date()
dna.bigint()
dna.literal("active")
dna.enum(["a", "b", "c"])
dna.array(dna.string()).min(1).max(10).nonempty()
dna.object({ ... })
dna.tuple([dna.string(), dna.number()])
dna.union([dna.string(), dna.number()])
dna.discriminatedUnion("type", [shapeA, shapeB])
dna.record(dna.string(), dna.boolean())
dna.map(dna.string(), dna.string())
dna.set(dna.string())
dna.optional()
dna.nullable()
dna.default("fallback")
dna.catch("fallback")
dna.preprocess((v) => Number(v), dna.number())
dna.coerce.number().parse("123")
dna.instanceof(UserClass)
dna.templateLiteral(["https://", dna.string(), ".", dna.enum(["com", "net"])])
dna.function().input([dna.string()]).output(dna.number()).implement((s) => s.length)
dna.lazy(() => dna.object({ children: dna.array(recursiveSchema) }))
dna.brand<"MyBrand">()
细化规则
dna.string().refine((s) => s.length > 3, "太短");
dna.array(dna.string()).superRefine((val, ctx) => {
if (val.length > 10) ctx.addIssue({ code: "too_big", maximum: 10, message: "太多" });
});
转换 + 管道
const schema = dna.string().transform((s) => s.length).pipe(dna.number());
schema.parse("hello");
递归
const TreeSchema: DnaLazy<Tree> = dna.lazy(() =>
dna.object({ value: dna.number(), children: dna.array(TreeSchema) })
);
const NodeSchema = dna.object({
value: dna.number(),
get children() { return dna.array(NodeSchema); },
});
元数据
const field = dna.string().meta({ title: "邮箱", description: "用户邮箱" });
const field2 = dna.string().describe("用户全名");
进一步阅读
- README — 完整 API、入口点、CLI Union、外部依赖
- 配方库 — 15+ 可复制粘贴的配方(对象模式、递归、管道、细化规则、强制转换、模板字面量、函数模式、映射/集合、默认值、品牌化、元数据)
- 技术文档 — DNA 操作码、架构、代码生成内部
- Zod 对比 — DNA 与 Zod 功能对比
- 外部依赖 — 用于转换的外部机制
- 序列化 — DNA 序列化格式
- 操作码模式 — 操作码使用模式
@ytrynot/schvalid — JSON Schema 到 DNA 编译器
安装
npm install @ytrynot/schvalid
将 JSON Schema 转换为 DNA 并验证
import { jschemaToDna, validator, parser } from "@ytrynot/schvalid";
const jsonSchema = {
type: "object",
properties: {
name: { type: "string", minLength: 3 },
age: { type: "number", minimum: 0 },
},
required: ["name"],
};
const dna = jschemaToDna(jsonSchema);
const validate = validator(dna);
validate({ name: "John", age: 30 });
validate({ name: "Jo" });
const parse = parser(dna);
parse({ name: "John", age: 30 });
parse({ name: "Jo" });
编译一次,多次验证(构建器 API)
import { schvalid } from "@ytrynot/schvalid";
const compiler = schvalid("validation");
const validate = compiler.compile(jsonSchema);
validate({ name: "John", age: 30 });
schvalid("validation");
schvalid("parser");
schvalid("fast");
schvalid("all");
支持的 JSON Schema 2020-12 特性
- 类型:string、number、integer、boolean、null、object、array
- 约束:properties、required、items、additionalProperties、minItems、maxItems、minLength、maxLength、minimum、maximum、exclusiveMinimum、exclusiveMaximum、multipleOf、pattern、format、const、enum
- 逻辑:anyOf、allOf、oneOf、if/then/else、not
- OpenAPI 3.1:discriminator
- 引用:仅支持内部
$ref(不支持外部 URI)
局限性
- 不支持外部
$ref(HTTP URI、URN、外部文件)
- 不支持自定义格式(仅支持标准格式:email、uuid、uri 等)
- 不支持异步验证、
$data、类型强制转换、默认值注入
进一步阅读
@ytrynot/qb — SQLite 查询构建器
安装
npm install @ytrynot/qb
npm install zod
npm install @ytrynot/dna
流畅 DML 查询
import { QueryBuilder as QB } from "@ytrynot/qb";
const sql = QB.table("users", "u")
.select(["u.id", "u.name", "u.email"])
.where(["u.active"])
.orderBy("u.created_at", "DESC")
.limit(10)
.toSQL();
从 Zod 模式定义表
import { z } from "zod";
import { QueryBuilder as QB } from "@ytrynot/qb";
const UserSchema = z.object({
id: z.string().uuid().meta({ pk: true }),
email: z.string().email().meta({ unique: true }),
name: z.string(),
age: z.number().int(),
created_at: z.date().optional(),
});
const users = QB.defTable("users", UserSchema);
users.createTable;
users.getById;
users.insert;
users.update;
users.delete;
users.upsert;
从 DNA 模式定义表
import { dna } from "@ytrynot/dna";
import { QueryBuilder as QB } from "@ytrynot/qb";
const UserSchema = dna.object({
id: dna.string().uuid().meta({ pk: true }),
email: dna.string().email().meta({ unique: true }),
name: dna.string(),
age: dna.int(),
created_at: dna.date().optional(),
});
const users = QB.defTable("users", UserSchema);
通过 .req / .q 自定义查询
users.req.select("id", "name").where("id").toSQL();
users.req.upsert("email", "name").toSQL();
使用驱动程序执行
import { DatabaseSync } from "node:sqlite";
const db = new DatabaseSync("app.db");
db.exec(QB.enableForeignKeys());
db.exec(users.createTable);
const stmt = db.prepare(users.insert);
stmt.run({ id: crypto.randomUUID(), email: "[email protected]", name: "Alice", age: 30, created_at: null });
DDL 元数据键
| 键 | 效果 |
|---|
pk: true | PRIMARY KEY |
pkauto: true | PRIMARY KEY AUTOINCREMENT |
unique: true | UNIQUE |
default: value | DEFAULT value |
fk: { table, column } | REFERENCES table(column) |
进一步阅读
- 快速入门 — 完整教程,端到端 CRUD
- 查询指南 — SELECT、INSERT、UPDATE、DELETE、UPSERT、WHERE、JOIN、排序、限制、分页、文本搜索、GROUP BY
- DDL 指南 — 所有模式源、元数据键、外键、索引、复合主键
- 高级指南 — EXISTS、CASE WHEN、子查询、窗口函数、PragmaBuilder
- 功能参考 — 完整方法清单,SQLite 版本矩阵
@ytrynot/cli — DNA 验证的 CLI 路由器
安装
npm install @ytrynot/cli
将路由定义为 DNA 模式
import { dna } from "@ytrynot/dna";
import { createContract, execute } from "@ytrynot/cli";
const buildRoute = dna.object({
cmd: dna.literal("build"),
files: dna.array(dna.string()).optional().meta({ description: "要构建的文件" }),
}).meta({ cli: { routeId: "build" }, description: "构建项目" });
const deployRoute = dna.object({
cmd: dna.literal("deploy"),
target: dna.string().optional().meta({ description: "部署目标" }),
}).meta({ cli: { routeId: "deploy" }, description: "部署项目" });
const contract = createContract({
name: "mycli",
description: "一个演示 CLI",
targets: [buildRoute, deployRoute],
cli: { positionals: ["cmd", "files"] },
});
运行(第一层 — 同步路由 + 验证)
const result = execute(contract, ["build", "a.ts", "b.ts"]);
execute(contract, ["deploy", "--target", "prod"]);
execute(contract, ["unknown"]);
完整 CLI(处理函数 + 格式化器 + process.exit)
import { executeContract, cliFactory, fullCli } from "@ytrynot/cli";
import type { ts } from "@ytrynot/cli";
const handlers: ts.Handlers = {
build: (payload) => ({ success: true, data: `构建了 ${payload.files?.length ?? 0} 个文件` }),
deploy: (payload) => ({ success: true, data: `部署到 ${payload.target ?? "default"}` }),
};
const formatter: ts.FormatterFn = (result) => {
if (result.success) return { exit: 0, message: String(result.data ?? "") };
return { exit: 1, message: `错误:${result.error}` };
};
const run = fullCli(cliFactory(executeContract(contract, handlers), formatter));
await run();
添加 --help / --version
const helpRoute = dna.looseObject({ cmd: dna.literal("help") })