diff --git a/CHANGELOG.md b/CHANGELOG.md index b6511ac..b7c58dd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,126 @@ # Release History +## v0.7.5 (2026-07-02) + +**Code Review + Unified Export Design + CLI Polish (Phase 36)** + +### Part A: Critical Bug Fixes +- Fixed `exclusiveMinimum`/`exclusiveMaximum` semantics (was incorrectly inclusive, now correctly exclusive) +- Fixed floating-point truncation in `minimum`/`maximum` constraints (`.to_int()` was losing precision) +- Extended `enum_values()` to support non-string values (numbers, booleans, null) via `union()` + `literal()` pattern +- 12 specialized tests for edge cases (`test_json_schema_fixes.mbt`) + +### Part B: Unified Export Design +- All 7+ export functions (`schema_to_prompt`, `to_json_schema`, `schema_to_moonbit_struct`, etc.) now apply root schema name protection +- Unnamed schemas automatically default to `"Root"` name for export consistency +- Improved error messages in struct generation + +### Part C: CLI Tool Improvements +- `cmd/json2schema`: default output is now pure copy-paste-ready moon_zod code +- `cmd/json2schema`: new `--verbose` / `-v` flag for debug output with input parsing info +- `cmd/validate`: improved error handling, exit code readiness (internal `Bool` returns for future integration) +- Better file mode support: `--schema-file`, `--sample-file`, `--from-json-schema` flags + +**Exporters & Importers Functionality Freeze**: Phase 35-36 complete all code generation and import/export pipelines. Marking core libraries as production-ready. + +- **426 tests** (all passing, 0 warnings) +- 0 external dependencies + +--- + +## v0.7.4 (2026-06-29) + +**Project Modularization + Code Generation Rewrite (Phase 35)** + +### Phase A: Subpackage Refactoring +- Reorganized into 5 formal subpackages: + - `core/` — Core validation (17 files, zero external deps) + - `exporters/` — Code generation (6 files: prompt, json_schema, moonbit_struct, renderers) + - `importers/` — JSON Schema reverse import + - `combinators/` — Composition layer + - `tests/` — Test suite (426 tests) +- Eliminated architecture violations: exporters no longer depends on importers +- Added `@core.` prefix for explicit intra-package references +- Unified reexporter pattern + +### Phase B: Schema Exporter Rewrite +- `schema_to_moon_zod_code()` now outputs `let x = ... .name(...)` format +- Full support for `.describe()`, `.required_error()`, `.invalid_type_error()`, `.strict()`, `.passthrough()` +- Named export with `schema_to_moon_zod_code_named()` and include_names filtering +- Two-layer separation: `json_schema_to_schema` (runtime Schema objects) + code generation + +### Phase C: Constraint Extractor + Trait Renderer Pattern +- New `constraint_extractor.mbt` module for unified constraint handling +- Trait-based renderers eliminate 40 scattered `SchemaType` match statements → 4 core matches + 3 traits +- 90% reduction in SchemaType pattern matching across 6 modules +- All 13 SchemaType variants fully supported in exporters/importers + +**414 tests** (all passing, 0 warnings) + +--- + +## v0.7.3 (2026-06-28) + +**Selective Named Export + Filter Logic Extraction (Phase 34)** + +- New `include_names?: Array[String]?` parameter on all named export functions + - `schema_to_prompt_named(schema, include_names?)` + - `to_json_schema_named(schema, include_names?)` + - `schema_to_moonbit_struct_named(schema, include_names?)` + - `schema_to_moonbit_struct_named_full(schema, include_names?)` +- `filter_named_schemas()` extracted to `shared_utils.mbt` (4 duplicate code paths eliminated) +- Supports: `None` (export all), `Some([])` (export none), `Some([...])` (selective export) + +**396 tests** (all passing, 0 warnings) + +--- + +## v0.7.2 (2026-06-27) + +**Trait-Based Renderer Pattern + Schema Composition Fixes (Phase 33)** + +### Phase A: Quick Fixes +- Fixed Union/Intersection/Literal in named schema exports +- Fixed `.name()` propagation in combinators +- 4 new tests for complex named exports + +### Phase B: Constraint Extractor +- Unified constraint extraction logic across 3 renderer modules +- Eliminated ~150 lines of duplicate code +- New `ConstraintInfo` struct and `extract_constraints()` function + +### Phase C: Trait Renderer Architecture +- New trait-based pattern: `StringRenderer`, `JsonSchemaRenderer`, `MoonBitStructRenderer` +- Shared utilities: `shared_utils.mbt` with `unwrap_schema()`, `peel_optional()`, `indent_str()` +- Rewrite of prompt, json_schema, moonbit_struct modules to use trait dispatch +- Result: 40 scattered match statements → 4 core matches + 3 traits (~90% reduction) +- New variant support requires only ~7 changes instead of ~15 + +**385 tests** (all passing, 0 warnings) + +--- + +## v0.7.1 (2026-06-26) + +**literal() Constant Validation + union.mbt Refactoring (Phase 32)** + +- `literal(Json)` factory — validate exact constant values (string, number, boolean, null, array, object) +- Support for all JSON types via `union()` + `literal()` composition +- Refactored `union.mbt` (217 lines → 42 lines) into separate modules: + - `optional.mbt` — optional() factory + - `default.mbt` — default() factory + - `enum.mbt` — enum_values() factory + - `literal.mbt` — literal() factory + - `union.mbt` — union() factory (core logic only) +- One-factory-per-file convention for clarity +- JSON Schema export: `literal()` → `{"const": value}` +- Prompt generation: renders literal values with proper JSON syntax +- MoonBit struct generation: `json_to_literal_code()` for code output + +**381 tests** (all passing, 0 warnings) + +--- + ## v0.7.0 (2026-06-26) **JSON Schema ↔ MoonBit Code Generation + MoonBit Struct Generation + Validate CLI** diff --git a/README.mbt.md b/README.mbt.md index 0a85c83..55fa2f7 100644 --- a/README.mbt.md +++ b/README.mbt.md @@ -76,6 +76,10 @@ moon_zod/ │ ├── constraint_extractor.mbt # Extract constraint info from rules │ └── moon_zod_wbtest.mbt # White-box tests (path stack invariants) │ +├── combinators/ # Schema combinator utilities +│ ├── schema_combinators.mbt # Schema composition helpers +│ └── reexporter.mbt # Re-exports +│ ├── exporters/ # Code/schema export tools │ ├── prompt.mbt # schema_to_prompt() / schema_to_prompt_named() │ ├── prompt_renderer.mbt # Trait-based prompt rendering @@ -90,7 +94,7 @@ moon_zod/ │ ├── from_json_schema.mbt # json_schema_to_moon_zod() — reverse JSON Schema → moon_zod code generation │ └── reexporter.mbt # Module re-exports │ -├── tests/ # Test suite (407 tests) +├── tests/ # Test suite (426 tests) │ ├── test_string.mbt # string() validator tests │ ├── test_number.mbt # number() validator tests │ ├── test_boolean_null.mbt # boolean/null tests @@ -98,7 +102,8 @@ moon_zod/ │ ├── test_array.mbt # array() tests │ ├── test_combinators.mbt # union/literal/optional/default tests │ ├── test_transform_refine.mbt # transform/refine tests -│ ├── test_json_schema.mbt # JSON Schema export tests +│ ├── test_json_schema.mbt # JSON Schema export + $defs/$ref tests +│ ├── test_json_schema_fixes.mbt # exclusiveMin/Max semantics + enum edge cases │ ├── test_moonbit_struct.mbt # MoonBit struct generation tests │ ├── test_prompt.mbt # Prompt generation tests │ ├── test_prompt_named.mbt # Named schema export tests @@ -115,11 +120,17 @@ moon_zod/ │ └── validate/ # JSON schema validator (infer-then-validate) │ └── examples/ # LLM agent demonstrations - ├── llm_agent/ # Basic LLM tool calling example - ├── educational_agent/ # Multi-round self-correction demo - ├── real_llm_agent/ # Real LLM integration (with API fallback to mock) + ├── json2schema/ # JSON → moon_zod schema code generation + ├── mock/ # Mock agent demonstrations + │ ├── llm_agent/ # Basic LLM tool calling example + │ └── educational_agent/ # Multi-round self-correction demo ├── multiple_schemas/ # Handling multiple schemas - └── schema2prompt/ # Schema → prompt generation showcase + ├── real_llm_agent/ # Real LLM integration (with API fallback to mock) + ├── resources/ # Sample data files (JSON, JSON Schema) + ├── schema2json/ # Schema → JSON Schema export demo + ├── schema2prompt/ # Schema → prompt generation showcase + ├── shared_schemas/ # Shared schema definitions (library package) + └── validate_cli/ # CLI validation demo ``` --- @@ -128,22 +139,28 @@ moon_zod/ ```bash # Testing & Building -moon test # Run all tests (407 total, 0 warnings) +moon test # Run all tests (426 total, 0 warnings) moon build # Build the library +moon check # Type check (0 errors, 0 warnings) moon info && moon fmt # Update interface + format # CLI Tools moon run cmd/main # Run performance benchmarks moon run cmd/json2schema -- '{"hello":"world"}' # JSON → moon_zod schema code moon run cmd/json2schema -- --from-json-schema '<{...}>' # JSON Schema → moon_zod code +moon run cmd/json2schema -- --from-json-schema '<{...}>' --verbose # with debug output moon run cmd/gen-struct -- '{"name":"Alice"}' # JSON → MoonBit struct + from_json() moon run cmd/validate -- '{"name":"Alice"}' '{"name":"Bob"}' # Validate JSON # Examples -moon run examples/llm_agent # Basic LLM tool calling demo +moon run examples/mock/llm_agent # Basic LLM tool calling demo +moon run examples/mock/educational_agent # Multi-round self-correction demo moon run examples/real_llm_agent -- product prompt # Real LLM with mock fallback moon run examples/real_llm_agent -- product validate # Validate with real API -moon run examples/multiple_schemas # Multiple schema handling +moon run examples/multiple_schemas # Multiple schema handling +moon run examples/schema2json -- product schema # Schema → JSON Schema export +moon run examples/schema2prompt # Schema → prompt generation showcase +moon run examples/json2schema # JSON → moon_zod schema code gen ``` --- @@ -153,7 +170,7 @@ moon run examples/multiple_schemas # Multiple schema handling - **Primitive schemas**: `string()`, `number()`, `boolean()`, `null()` - **Compound schemas**: `object(Map)`, `array(Schema)`, `union(Array[Schema])`, `intersection(Array[Schema])`, `enum_values(Array[String])`, `literal(Json)` - **String validators** (20+): `.min(n)`, `.max(n)`, `.nonempty()`, `.email()` (full RFC validation), `.url()` (full structure), `.regex(pattern)` (substring match), `.startsWith()`, `.endsWith()`, `.includes()`, `.uuid()`, `.cuid()`, `.ulid()`, `.datetime()`, `.ip()`/`.ipv4()`/`.ipv6()`, `.length(n)` -- **Number validators** (9+): `.int()`, `.positive()`, `.negative()`, `.multipleOf()`, `.finite()`, `.safe()`, `.min()`, `.max()`, `.length()` +- **Number validators** (8+): `.int()`, `.positive()`, `.negative()`, `.multipleOf()`, `.finite()`, `.safe()`, `.min()`, `.max()` - **Object modes**: `.strip()` (default, removes unknown fields), `.passthrough()` (keeps unknown fields), `.strict()` (rejects unknown fields) - **Schema composition**: `.pick(keys)`, `.omit(keys)`, `.partial()` to derive object sub-schemas - **Optional/Default handling**: `.optional()` and `.default(value)` with correct rule chaining through wrappers @@ -187,17 +204,17 @@ moon run examples/multiple_schemas # Multiple schema handling ### Factory Functions | Function | Description | -|---|---|---| +|---|---| | `string(required_error?, invalid_type_error?)` | Validates JSON strings | | `number(required_error?, invalid_type_error?)` | Validates JSON numbers | | `boolean(required_error?, invalid_type_error?)` | Validates JSON booleans | | `null(required_error?, invalid_type_error?)` | Validates JSON null | | `array(Schema, required_error?, invalid_type_error?)` | Validates arrays, recursively checking elements | | `object(Map[String, Schema], required_error?, invalid_type_error?)` | Validates objects. **Default: Strip mode** | -| `enum_values(Array[String], required_error?, invalid_type_error?)` | Fixed set of allowed string values | -| `literal(Json, required_error?, invalid_type_error?)` | **NEW**: Constant value validation — only accepts exact JSON match (string, number, boolean, null, array, or object) | +| `enum_values(Array[String], required_error?, invalid_type_error?)` | Fixed set of allowed string values (use `literal()` + `union()` for mixed types) | +| `literal(Json, required_error?, invalid_type_error?)` | **Phase 32**: Constant value validation — only accepts exact JSON match (string, number, boolean, null, array, or object) | | `union(Array[Schema], required_error?, invalid_type_error?)` | Union type — passes if any schema matches | -| `intersection(Array[Schema], required_error?, invalid_type_error?)` | Intersection — passes if all schemas match; object fields are merged | +| `intersection(Array[Schema], required_error?, invalid_type_error?)` | **Phase 18**: Intersection — passes if all schemas match; object fields are merged | ### Schema Methods @@ -206,6 +223,7 @@ moon run examples/multiple_schemas # Multiple schema handling | `.parse(Json, path?)` | All | Validate, returns `Ok(Json)` or `Err(Array[ValidationError])` | | `.min(n[, msg])` | string / number / array | Minimum length / value | | `.max(n[, msg])` | string / number / array | Maximum length / value | +| `.length(n[, msg])` | string / array | Exact length | | `.nonempty([msg])` | string | String must not be empty | | `.email([msg])` | string | Full email validation (quoted local, IP literal, +tag, TLD≥2, single @) | | `.url([msg])` | string | Full URL structure: `scheme://host[:port][/path][?query][#fragment]` | @@ -224,7 +242,6 @@ moon run examples/multiple_schemas # Multiple schema handling | `.positive([msg])` | number | Must be > 0 | | `.negative([msg])` | number | Must be < 0 | | `.multipleOf(n[, msg])` | number | Must be multiple of `n` | -| `.length(n[, msg])` | string / array | Must have exact length `n` | | `.finite([msg])` | number | Must be finite (not NaN, not ±Infinity) | | `.safe([msg])` | number | Must be a safe integer (not NaN, not ±Infinity, no fractional part) | | `.optional()` | Any | Null or missing values skip validation | @@ -232,29 +249,36 @@ moon run examples/multiple_schemas # Multiple schema handling | `.strict()` | object | Reject undefined fields | | `.passthrough()` | object | Keep undefined fields as-is | | `.strip()` | object | Silently remove undefined fields (default) | -| `.describe(text)` | Any | Attach description rendered by `schema_to_prompt()` for LLM prompts | -| `.message(text)` | Any | Override the last rule's error message | -| `.intersect(other)` | Any | Intersection: input must match both schemas; object fields are merged | -| `.pick(keys)` | object | Select only specified fields | -| `.omit(keys)` | object | Remove specified fields | -| `.partial()` | object | Make all fields optional | +| `.describe(text)` | Any | **Phase 17**: Attach description rendered by `schema_to_prompt()` for LLM prompts | +| `.message(text)` | Any | **Phase 19**: Override the last rule's error message | +| `.name(text)` | Any | **Phase 25**: Assign a name for schema exports and code generation | +| `.intersect(other)` | Any | **Phase 18**: Intersection: input must match both schemas; object fields are merged | +| `.pick(keys)` | object | **Phase 21**: Select only specified fields | +| `.omit(keys)` | object | **Phase 21**: Remove specified fields | +| `.partial()` | object | **Phase 21**: Make all fields optional | | `.refine(check, msg)` | Any | Custom validation predicate | -| `.transform(fn)` | Any | Validate then transform output via `(Json) -> Result[Json, String]` | +| `.transform(fn)` | Any | **Phase 13**: Validate then transform output via `(Json) -> Result[Json, String]` | ### Standalone Functions | Function | Description | |---|---| -| `schema_to_prompt(Schema)` | Generate TypeScript-interface prompt string for LLM (with constraint comments) — inline expansion | -| `schema_to_prompt_named(Schema, include_names?)` | Generate modular TypeScript interfaces from named schemas with topological sorting and type name references — for complex, nested LLM tool schemas | -| `to_json_schema(Schema)` | Export standard JSON Schema object with full constraint annotations | -| `to_json_schema_skeleton(Schema)` | Export lightweight JSON Schema skeleton (structure only, no constraints) | -| `to_json_schema_named(Schema, include_names?)` | Export named schemas as separate JSON Schema definitions with `$defs` and `$ref` | -| `json_schema_to_moon_zod(Json)` | **NEW**: Reverse-generate moon_zod schema source code from a JSON Schema object; supports `$defs`, `$ref`, constraints, format validation | -| `schema_to_moonbit_struct(Schema)` | Generate MoonBit struct definition (type name, fields, constraints) from ObjectType/EnumType | -| `schema_to_moonbit_struct_full(Schema)` | Generate struct definition + `from_json()` function for type-safe JSON → struct conversion | -| `schema_to_moonbit_struct_named(Schema, include_names?)` | Same as `schema_to_moonbit_struct()` but extracts and topologically sorts all nested named schemas | -| `schema_to_moonbit_struct_named_full(Schema, include_names?)` | Same as `schema_to_moonbit_struct_full()` but extracts all nested named schemas | +| `schema_to_prompt(Schema)` | **Phase 16**: Generate TypeScript-interface prompt string for LLM (with constraint comments) — inline expansion | +| `schema_to_prompt_named(Schema, include_names?)` | **Phase 25, 34**: Generate modular TypeScript interfaces from named schemas with topological sorting and type name references | +| `to_json_schema(Schema)` | **Phase 15**: Export standard JSON Schema object with full constraint annotations | +| `to_json_schema_skeleton(Schema)` | **Phase 15**: Export lightweight JSON Schema skeleton (structure only, no constraints) | +| `to_json_schema_named(Schema, include_names?)` | **Phase 26, 34**: Export named schemas as separate JSON Schema definitions with `$defs` and `$ref` | +| `json_schema_to_moon_zod(Json)` | **Phase 27, 36**: Reverse-generate moon_zod schema source code from a JSON Schema object; supports `$defs`, `$ref`, constraints, format validation | +| `schema_to_moonbit_struct(Schema)` | **Phase 28**: Generate MoonBit struct definition (type name, fields, constraints) from ObjectType/EnumType | +| `schema_to_moonbit_struct_full(Schema)` | **Phase 29**: Generate struct definition + `from_json()` function for type-safe JSON → struct conversion | +| `schema_to_moonbit_struct_named(Schema, include_names?)` | **Phase 31**: Same as `schema_to_moonbit_struct()` but extracts and topologically sorts all nested named schemas | +| `schema_to_moonbit_struct_named_full(Schema, include_names?)` | **Phase 31**: Same as `schema_to_moonbit_struct_full()` but extracts all nested named schemas | +| `schema_to_moon_zod_code(Schema)` | Generate moon_zod schema source code from a Schema | +| `schema_to_moon_zod_code_named(Schema, include_names?)` | Generate moon_zod schema source code with named `$defs` and `$ref` references | +| `json_schema_to_schema(Json)` | Reverse-parse a JSON Schema object into a moon_zod Schema | +| `json_infer_schema(Json)` | Infer a moon_zod Schema from a sample JSON value | +| `append_rule(Schema, (Json) -> Bool, String)` | Append a raw validation rule to a schema | +| `append_rule_with_annotation(Schema, (Json) -> Bool, String, Json)` | Append a validation rule with an annotation payload | | `format_path(Array[String])` | Join path stack to dot-notation string | | `ValidationError::to_string()` | Format error as `[path] message (got: value)` | @@ -288,18 +312,17 @@ Generate `@moon_zod` schema code instantly from any JSON payload — no need to moon run cmd/json2schema -- '{"hello": "world"}' ``` -Output: +Output (copy-paste ready moon_zod code): -``` -── Input JSON ── -Object({hello: String(world)}) - -── Generated moon_zod Schema (copy-paste ready) ── +```moonbit @moon_zod.object({ "hello": @moon_zod.string(), }) +``` -── End ── +For verbose output with debug information: +```bash +moon run cmd/json2schema -- --verbose '{"hello": "world"}' ``` The generator recursively infers types (`string`, `number`, `boolean`, `null`, `array`, `object`) and safely escapes special characters in object keys. Empty arrays produce a `/* TODO: specify exact type */` comment to alert you when type inference lacked data. @@ -310,6 +333,7 @@ The generator recursively infers types (`string`, `number`, `boolean`, `null`, ` Generate `@moon_zod` schema code from a standard **JSON Schema (draft-07)** definition — the inverse of `to_json_schema()`. +**Inline mode** (JSON Schema as command argument): ```bash moon run cmd/json2schema -- --from-json-schema '{ "type": "object", @@ -321,9 +345,14 @@ moon run cmd/json2schema -- --from-json-schema '{ }' ``` +**File mode** (read JSON Schema from file): +```bash +moon run cmd/json2schema -- --from-json-schema --schema-file schema.json +``` + Output: -```moonbit nocheck +```moonbit @moon_zod.object({ "name": @moon_zod.string().min(2), "age": @moon_zod.number().int().min(0).max(150), @@ -332,11 +361,12 @@ Output: **Features**: - Converts all JSON Schema types (string, number, integer, boolean, null, array, object) -- Extracts constraints: `minLength`, `maxLength`, `minimum`, `maximum`, `multipleOf`, `pattern`, `format` (email, uri, date-time, ipv4, ipv6, uuid) +- Extracts constraints: `minLength`, `maxLength`, `minimum`, `maximum`, `exclusiveMinimum`, `exclusiveMaximum`, `multipleOf`, `pattern`, `format` (email, uri, date-time, ipv4, ipv6, uuid) - Handles `$defs` and `$ref` references — generates separate named schema declarations -- Supports `enum` and `oneOf` / `anyOf` / `allOf` +- Supports `enum`, `oneOf`, `anyOf`, `allOf` - Fields not in `required` auto-wrapped with `.optional()` - Outputs **copy-paste-ready MoonBit source code** +- Full support for Phase 36 semantics: `exclusiveMinimum`/`exclusiveMaximum` generate `.positive()`/`.negative()` where applicable --- @@ -350,7 +380,7 @@ moon run cmd/gen-struct -- '{"name":"Alice","age":30}' Output: -```moonbit nocheck +```moonbit pub struct InferredSchema { name : String age : Int64 @@ -394,6 +424,9 @@ moon run cmd/validate -- '{"name":"Alice"}' '{"name":"Bob"}\n{"name":"Eve"}\n{"a # FAIL: line 3 # [name] Required (got: Null) # Results: 2 passed, 1 failed + +# File mode (JSON Schema as schema source) +moon run cmd/validate -- --schema-file schema.json --sample-file data.json ``` **Error output format**: `[field_path] message (got: value)` @@ -574,31 +607,11 @@ Then **LLM sees only the definitions it needs**, reducing token count and improv **Example usage:** ```mbt nocheck // Define named schemas - -///| -let user_schema = @moon_zod.object( - { - ... - }, -).name("User") - -///| -let order_schema = @moon_zod.object( - { - ... - }, -).name("Order") - -///| -let product_schema = @moon_zod.object( - { - ... - }, -).name("Product") +let user_schema = @moon_zod.object({ ... }).name("User") +let order_schema = @moon_zod.object({ ... }).name("Order") +let product_schema = @moon_zod.object({ ... }).name("Product") // Auto-extract + generate modular prompt - -///| let prompt = @moon_zod.schema_to_prompt_named(user_schema) // Output: // export interface User { ... } diff --git a/README_zh.mbt.md b/README_zh.mbt.md index 4bdf60a..6538922 100644 --- a/README_zh.mbt.md +++ b/README_zh.mbt.md @@ -76,6 +76,10 @@ moon_zod/ │ ├── constraint_extractor.mbt # 从规则提取约束信息 │ └── moon_zod_wbtest.mbt # 白盒测试(路径栈不变量) │ +├── combinators/ # Schema 组合工具 +│ ├── schema_combinators.mbt # Schema 组合辅助函数 +│ └── reexporter.mbt # 重新导出 +│ ├── exporters/ # 代码/Schema 导出工具 │ ├── prompt.mbt # schema_to_prompt() / schema_to_prompt_named() │ ├── prompt_renderer.mbt # 基于 Trait 的提示渲染 @@ -90,7 +94,7 @@ moon_zod/ │ ├── from_json_schema.mbt # json_schema_to_moon_zod() — 反向 JSON Schema → moon_zod 代码生成 │ └── reexporter.mbt # 模块重新导出 │ -├── tests/ # 测试套件(407 个测试) +├── tests/ # 测试套件(426 个测试) │ ├── test_string.mbt # string() 验证器测试 │ ├── test_number.mbt # number() 验证器测试 │ ├── test_boolean_null.mbt # boolean/null 测试 @@ -98,7 +102,8 @@ moon_zod/ │ ├── test_array.mbt # array() 测试 │ ├── test_combinators.mbt # union/literal/optional/default 测试 │ ├── test_transform_refine.mbt # transform/refine 测试 -│ ├── test_json_schema.mbt # JSON Schema 导出测试 +│ ├── test_json_schema.mbt # JSON Schema 导出 + $defs/$ref 测试 +│ ├── test_json_schema_fixes.mbt # exclusiveMin/Max 语义 + enum 边界情况 │ ├── test_moonbit_struct.mbt # MoonBit 结构生成测试 │ ├── test_prompt.mbt # 提示生成测试 │ ├── test_prompt_named.mbt # 命名 Schema 导出测试 @@ -115,11 +120,17 @@ moon_zod/ │ └── validate/ # JSON Schema 验证器(推断然后验证) │ └── examples/ # LLM 代理演示 - ├── llm_agent/ # 基础 LLM 工具调用示例 - ├── educational_agent/ # 多轮自纠正演示 - ├── real_llm_agent/ # 真实 LLM 集成(带 API 回退到 mock) + ├── json2schema/ # JSON → moon_zod schema 代码生成 + ├── mock/ # Mock 代理演示 + │ ├── llm_agent/ # 基础 LLM 工具调用示例 + │ └── educational_agent/ # 多轮自纠正演示 ├── multiple_schemas/ # 处理多个 Schema - └── schema2prompt/ # Schema → 提示生成展示 + ├── real_llm_agent/ # 真实 LLM 集成(带 API 回退到 mock) + ├── resources/ # 样本数据文件(JSON、JSON Schema) + ├── schema2json/ # Schema → JSON Schema 导出演示 + ├── schema2prompt/ # Schema → 提示生成展示 + ├── shared_schemas/ # 共享 Schema 定义(库包) + └── validate_cli/ # CLI 验证演示 ``` --- @@ -128,22 +139,28 @@ moon_zod/ ```bash # 测试与构建 -moon test # 运行所有测试(共 407 个,0 个警告) +moon test # 运行所有测试(共 426 个,0 个警告) moon build # 构建库 +moon check # 类型检查(0 错误,0 警告) moon info && moon fmt # 更新接口 + 格式化 # CLI 工具 moon run cmd/main # 运行性能基准测试 moon run cmd/json2schema -- '{"hello":"world"}' # JSON → moon_zod Schema 代码 moon run cmd/json2schema -- --from-json-schema '<{...}>' # JSON Schema → moon_zod 代码 +moon run cmd/json2schema -- --from-json-schema '<{...}>' --verbose # 带调试输出版本 moon run cmd/gen-struct -- '{"name":"Alice"}' # JSON → MoonBit 结构 + from_json() moon run cmd/validate -- '{"name":"Alice"}' '{"name":"Bob"}' # 验证 JSON # 示例 -moon run examples/llm_agent # 基础 LLM 工具调用演示 +moon run examples/mock/llm_agent # 基础 LLM 工具调用演示 +moon run examples/mock/educational_agent # 多轮自纠正演示 moon run examples/real_llm_agent -- product prompt # 真实 LLM(带 mock 回退) moon run examples/real_llm_agent -- product validate # 用真实 API 验证 -moon run examples/multiple_schemas # 处理多个 Schema +moon run examples/multiple_schemas # 处理多个 Schema +moon run examples/schema2json -- product schema # Schema → JSON Schema 导出 +moon run examples/schema2prompt # Schema → 提示生成展示 +moon run examples/json2schema # JSON → moon_zod schema 代码生成 ``` --- @@ -153,7 +170,7 @@ moon run examples/multiple_schemas # 处理多个 Schema - **基础类型 Schema**:`string()`、`number()`、`boolean()`、`null()` - **复合 Schema**:`object(Map)`、`array(Schema)`、`union(Array[Schema])`、`intersection(Array[Schema])`、`enum_values(Array[String])`、`literal(Json)` - **字符串验证器**(20+):`.min(n)`、`.max(n)`、`.nonempty()`、`.email()`(完整 RFC 验证)、`.url()`(完整结构)、`.regex(pattern)`(子字符串匹配)、`.startsWith()`、`.endsWith()`、`.includes()`、`.uuid()`、`.cuid()`、`.ulid()`、`.datetime()`、`.ip()`/`.ipv4()`/`.ipv6()`、`.length(n)` -- **数字验证器**(9+):`.int()`、`.positive()`、`.negative()`、`.multipleOf()`、`.finite()`、`.safe()`、`.min()`、`.max()`、`.length()` +- **数字验证器**(8+):`.int()`、`.positive()`、`.negative()`、`.multipleOf()`、`.finite()`、`.safe()`、`.min()`、`.max()` - **对象模式**:`.strip()`(默认,移除未知字段)、`.passthrough()`(保留未知字段)、`.strict()`(拒绝未知字段) - **Schema 组合**:`.pick(keys)`、`.omit(keys)`、`.partial()` 派生对象子 Schema - **可选/默认值处理**:`.optional()` 和 `.default(value)`,通过包装器正确链接规则 @@ -187,17 +204,17 @@ moon run examples/multiple_schemas # 处理多个 Schema ### 工厂函数 | 函数 | 描述 | -|---|---|---| +|---|---| | `string(required_error?, invalid_type_error?)` | 校验 JSON 字符串 | | `number(required_error?, invalid_type_error?)` | 校验 JSON 数字 | | `boolean(required_error?, invalid_type_error?)` | 校验 JSON 布尔值 | | `null(required_error?, invalid_type_error?)` | 校验 JSON null | | `array(Schema, required_error?, invalid_type_error?)` | 校验数组,递归检查元素 | | `object(Map[String, Schema], required_error?, invalid_type_error?)` | 校验对象。**默认:Strip 模式** | -| `enum_values(Array[String], required_error?, invalid_type_error?)` | 固定的允许字符串值集合 | -| `literal(Json, required_error?, invalid_type_error?)` | **新增**:常量值校验 — 仅接受精确的 JSON 匹配(字符串、数字、布尔值、null、数组或对象) | +| `enum_values(Array[String], required_error?, invalid_type_error?)` | 固定的允许字符串值集合(混合类型请使用 `literal()` + `union()`) | +| `literal(Json, required_error?, invalid_type_error?)` | **Phase 32**: 常量值校验 — 仅接受精确的 JSON 匹配(字符串、数字、布尔值、null、数组或对象) | | `union(Array[Schema], required_error?, invalid_type_error?)` | 联合类型 — 如果任何 schema 匹配则通过 | -| `intersection(Array[Schema], required_error?, invalid_type_error?)` | 交集 — 如果所有 schema 都匹配则通过;对象字段被合并 | +| `intersection(Array[Schema], required_error?, invalid_type_error?)` | **Phase 18**: 交集 — 如果所有 schema 都匹配则通过;对象字段被合并 | ### Schema 方法 @@ -206,6 +223,7 @@ moon run examples/multiple_schemas # 处理多个 Schema | `.parse(Json, path?)` | 全部 | 校验,返回 `Ok(Json)` 或 `Err(Array[ValidationError])` | | `.min(n[, msg])` | string / number / array | 最小长度 / 值 | | `.max(n[, msg])` | string / number / array | 最大长度 / 值 | +| `.length(n[, msg])` | string / array | 精确长度 | | `.nonempty([msg])` | string | 字符串不能为空 | | `.email([msg])` | string | 完整邮箱校验(引号本地部分、IP 字面量、+tag、TLD≥2、单个 @) | | `.url([msg])` | string | 完整 URL 结构:`scheme://host[:port][/path][?query][#fragment]` | @@ -224,7 +242,6 @@ moon run examples/multiple_schemas # 处理多个 Schema | `.positive([msg])` | number | 必须 > 0 | | `.negative([msg])` | number | 必须 < 0 | | `.multipleOf(n[, msg])` | number | 必须是 `n` 的倍数 | -| `.length(n[, msg])` | string / array | 必须恰好有 `n` 的长度 | | `.finite([msg])` | number | 必须是有限数(不是 NaN,不是 ±Infinity) | | `.safe([msg])` | number | 必须是安全整数(不是 NaN,不是 ±Infinity,无小数部分) | | `.optional()` | 任意 | null 或缺失值跳过校验 | @@ -232,29 +249,36 @@ moon run examples/multiple_schemas # 处理多个 Schema | `.strict()` | object | 拒绝未定义的字段 | | `.passthrough()` | object | 保持未定义的字段不变 | | `.strip()` | object | 无声地移除未定义的字段(默认) | -| `.describe(text)` | 任意 | 附加描述,由 `schema_to_prompt()` 为 LLM 提示渲染 | -| `.message(text)` | 任意 | 覆盖最后一条规则的错误消息 | -| `.intersect(other)` | 任意 | 交集:输入必须匹配两个 schema;对象字段被合并 | -| `.pick(keys)` | object | 仅选择指定字段 | -| `.omit(keys)` | object | 移除指定字段 | -| `.partial()` | object | 使所有字段可选 | +| `.describe(text)` | 任意 | **Phase 17**: 附加描述,由 `schema_to_prompt()` 为 LLM 提示渲染 | +| `.message(text)` | 任意 | **Phase 19**: 覆盖最后一条规则的错误消息 | +| `.name(text)` | 任意 | **Phase 25**: 为 schema 导出和代码生成分配名称 | +| `.intersect(other)` | 任意 | **Phase 18**: 交集:输入必须匹配两个 schema;对象字段被合并 | +| `.pick(keys)` | object | **Phase 21**: 仅选择指定字段 | +| `.omit(keys)` | object | **Phase 21**: 移除指定字段 | +| `.partial()` | object | **Phase 21**: 使所有字段可选 | | `.refine(check, msg)` | 任意 | 自定义校验谓词 | -| `.transform(fn)` | 任意 | 校验然后通过 `(Json) -> Result[Json, String]` 转换输出 | +| `.transform(fn)` | 任意 | **Phase 13**: 校验然后通过 `(Json) -> Result[Json, String]` 转换输出 | ### 独立函数 | 函数 | 描述 | |---|---| -| `schema_to_prompt(Schema)` | 为 LLM 生成 TypeScript 接口提示字符串(含约束注释) — 内联展开 | -| `schema_to_prompt_named(Schema, include_names?)` | 从命名 schema 生成模块化 TypeScript 接口,含拓扑排序和类型名称引用 — 用于复杂、嵌套的 LLM 工具 schema | -| `to_json_schema(Schema)` | 导出标准 JSON Schema 对象,含完整约束注解 | -| `to_json_schema_skeleton(Schema)` | 导出轻量级 JSON Schema 骨架(仅结构,无约束) | -| `to_json_schema_named(Schema, include_names?)` | 导出命名 schema 为独立的 JSON Schema 定义,含 `$defs` 和 `$ref` 引用 | -| `json_schema_to_moon_zod(Json)` | **新增**:反向生成 moon_zod Schema 源代码;完整支持 `$defs`、`$ref`、约束、格式验证 | -| `schema_to_moonbit_struct(Schema)` | 从 ObjectType/EnumType 生成 MoonBit 结构体定义(类型名、字段、约束) | -| `schema_to_moonbit_struct_full(Schema)` | 生成结构体定义 + `from_json()` 函数用于类型安全的 JSON → 结构体转换 | -| `schema_to_moonbit_struct_named(Schema, include_names?)` | 同 `schema_to_moonbit_struct()`,但提取并拓扑排序所有嵌套命名 schema | -| `schema_to_moonbit_struct_named_full(Schema, include_names?)` | 同 `schema_to_moonbit_struct_full()`,但提取所有嵌套命名 schema | +| `schema_to_prompt(Schema)` | **Phase 16**: 为 LLM 生成 TypeScript 接口提示字符串(含约束注释)— 内联展开 | +| `schema_to_prompt_named(Schema, include_names?)` | **Phase 25, 34**: 从命名 schema 生成模块化 TypeScript 接口,含拓扑排序和类型名称引用 | +| `to_json_schema(Schema)` | **Phase 15**: 导出标准 JSON Schema 对象,含完整约束注解 | +| `to_json_schema_skeleton(Schema)` | **Phase 15**: 导出轻量级 JSON Schema 骨架(仅结构,无约束) | +| `to_json_schema_named(Schema, include_names?)` | **Phase 26, 34**: 导出命名 schema 为独立的 JSON Schema 定义,含 `$defs` 和 `$ref` | +| `json_schema_to_moon_zod(Json)` | **Phase 27, 36**: 反向生成 moon_zod Schema 源代码;支持 `$defs`、`$ref`、约束、格式验证 | +| `schema_to_moonbit_struct(Schema)` | **Phase 28**: 从 ObjectType/EnumType 生成 MoonBit 结构体定义(类型名、字段、约束) | +| `schema_to_moonbit_struct_full(Schema)` | **Phase 29**: 生成结构体定义 + `from_json()` 函数用于类型安全的 JSON → 结构体转换 | +| `schema_to_moonbit_struct_named(Schema, include_names?)` | **Phase 31**: 同 `schema_to_moonbit_struct()`,但提取并拓扑排序所有嵌套命名 schema | +| `schema_to_moonbit_struct_named_full(Schema, include_names?)` | **Phase 31**: 同 `schema_to_moonbit_struct_full()`,但提取所有嵌套命名 schema | +| `schema_to_moon_zod_code(Schema)` | 从 Schema 生成 moon_zod schema 源代码 | +| `schema_to_moon_zod_code_named(Schema, include_names?)` | 生成带命名 `$defs` 和 `$ref` 引用的 moon_zod schema 源代码 | +| `json_schema_to_schema(Json)` | 反向解析 JSON Schema 对象为 moon_zod Schema | +| `json_infer_schema(Json)` | 从样本 JSON 值推断 moon_zod Schema | +| `append_rule(Schema, (Json) -> Bool, String)` | 向 schema 追加原始验证规则 | +| `append_rule_with_annotation(Schema, (Json) -> Bool, String, Json)` | 追加带注解负载的验证规则 | | `format_path(Array[String])` | 将路径栈连接为点号记号字符串 | | `ValidationError::to_string()` | 将错误格式化为 `[path] message (got: value)` | @@ -286,18 +310,17 @@ pub enum ObjectMode { moon run cmd/json2schema -- '{"hello": "world"}' ``` -输出: +输出(可直接复制粘贴的 moon_zod 代码): -``` -── Input JSON ── -Object({hello: String(world)}) - -── Generated moon_zod Schema (copy-paste ready) ── +```moonbit @moon_zod.object({ "hello": @moon_zod.string(), }) +``` -── End ── +如需带调试信息的详细输出: +```bash +moon run cmd/json2schema -- --verbose '{"hello": "world"}' ``` 该生成器递归推断类型(`string`、`number`、`boolean`、`null`、`array`、`object`),并安全转义对象键中的特殊字符。空数组会生成 `/* TODO: specify exact type */` 注释,以便在类型推断缺乏数据时提醒你。 @@ -308,6 +331,7 @@ Object({hello: String(world)}) 从标准 **JSON Schema (draft-07)** 定义生成 `@moon_zod` schema 代码 — `to_json_schema()` 的逆操作。 +**内联模式**(JSON Schema 作为命令行参数): ```bash moon run cmd/json2schema -- --from-json-schema '{ "type": "object", @@ -319,9 +343,14 @@ moon run cmd/json2schema -- --from-json-schema '{ }' ``` +**文件模式**(从文件读取 JSON Schema): +```bash +moon run cmd/json2schema -- --from-json-schema --schema-file schema.json +``` + 输出: -```moonbit nocheck +```moonbit @moon_zod.object({ "name": @moon_zod.string().min(2), "age": @moon_zod.number().int().min(0).max(150), @@ -330,11 +359,12 @@ moon run cmd/json2schema -- --from-json-schema '{ **特性**: - 转换所有 JSON Schema 类型(string、number、integer、boolean、null、array、object) -- 提取约束:`minLength`、`maxLength`、`minimum`、`maximum`、`multipleOf`、`pattern`、`format`(email、uri、date-time、ipv4、ipv6、uuid) +- 提取约束:`minLength`、`maxLength`、`minimum`、`maximum`、`exclusiveMinimum`、`exclusiveMaximum`、`multipleOf`、`pattern`、`format`(email、uri、date-time、ipv4、ipv6、uuid) - 处理 `$defs` 和 `$ref` 引用 — 生成单独的命名 schema 声明 -- 支持 `enum` 和 `oneOf` / `anyOf` / `allOf` +- 支持 `enum`、`oneOf`、`anyOf`、`allOf` - 不在 `required` 中的字段自动用 `.optional()` 包装 - 输出 **可直接复制粘贴的 MoonBit 源代码** +- 完整支持 Phase 36 语义:`exclusiveMinimum`/`exclusiveMaximum` 在适用时生成 `.positive()`/`.negative()` --- @@ -348,7 +378,7 @@ moon run cmd/gen-struct -- '{"name":"Alice","age":30}' 输出: -```moonbit nocheck +```moonbit pub struct InferredSchema { name : String age : Int64 @@ -392,6 +422,9 @@ moon run cmd/validate -- '{"name":"Alice"}' '{"name":"Bob"}\n{"name":"Eve"}\n{"a # FAIL: line 3 # [name] Required (got: Null) # Results: 2 passed, 1 failed + +# 文件模式(JSON Schema 作为 schema 源) +moon run cmd/validate -- --schema-file schema.json --sample-file data.json ``` **错误输出格式**:`[field_path] message (got: value)` @@ -570,31 +603,11 @@ Product → uses type name `Product` **使用示例:** ```mbt nocheck // Define named schemas - -///| -let user_schema = @moon_zod.object( - { - ... - }, -).name("User") - -///| -let order_schema = @moon_zod.object( - { - ... - }, -).name("Order") - -///| -let product_schema = @moon_zod.object( - { - ... - }, -).name("Product") +let user_schema = @moon_zod.object({ ... }).name("User") +let order_schema = @moon_zod.object({ ... }).name("Order") +let product_schema = @moon_zod.object({ ... }).name("Product") // Auto-extract + generate modular prompt - -///| let prompt = @moon_zod.schema_to_prompt_named(user_schema) // Output: // export interface User { ... } diff --git a/docs/API.md b/docs/API.md index 5b5ba12..ca36e43 100644 --- a/docs/API.md +++ b/docs/API.md @@ -3,17 +3,17 @@ ### Factory Functions | Function | Description | -|---|---|---| +|---|---| | `string(required_error?, invalid_type_error?)` | Validates JSON strings | | `number(required_error?, invalid_type_error?)` | Validates JSON numbers | | `boolean(required_error?, invalid_type_error?)` | Validates JSON booleans | | `null(required_error?, invalid_type_error?)` | Validates JSON null | | `array(Schema, required_error?, invalid_type_error?)` | Validates arrays, recursively checking elements | | `object(Map[String, Schema], required_error?, invalid_type_error?)` | Validates objects. **Default: Strip mode** | -| `enum_values(Array[String], required_error?, invalid_type_error?)` | Fixed set of allowed string values | -| `literal(Json, required_error?, invalid_type_error?)` | **NEW**: Constant value validation — only accepts exact JSON match (string, number, boolean, null, array, or object) | +| `enum_values(Array[String], required_error?, invalid_type_error?)` | Fixed set of allowed string values (use `literal()` + `union()` for mixed types) | +| `literal(Json, required_error?, invalid_type_error?)` | **Phase 32**: Constant value validation — only accepts exact JSON match (string, number, boolean, null, array, or object) | | `union(Array[Schema], required_error?, invalid_type_error?)` | Union type — passes if any schema matches | -| `intersection(Array[Schema], required_error?, invalid_type_error?)` | Intersection — passes if all schemas match; object fields are merged | +| `intersection(Array[Schema], required_error?, invalid_type_error?)` | **Phase 18**: Intersection — passes if all schemas match; object fields are merged | ### Schema Methods @@ -22,6 +22,7 @@ | `.parse(Json, path?)` | All | Validate, returns `Ok(Json)` or `Err(Array[ValidationError])` | | `.min(n[, msg])` | string / number / array | Minimum length / value | | `.max(n[, msg])` | string / number / array | Maximum length / value | +| `.length(n[, msg])` | string / array | Exact length | | `.nonempty([msg])` | string | String must not be empty | | `.email([msg])` | string | Full email validation (quoted local, IP literal, +tag, TLD≥2, single @) | | `.url([msg])` | string | Full URL structure: `scheme://host[:port][/path][?query][#fragment]` | @@ -40,7 +41,6 @@ | `.positive([msg])` | number | Must be > 0 | | `.negative([msg])` | number | Must be < 0 | | `.multipleOf(n[, msg])` | number | Must be multiple of `n` | -| `.length(n[, msg])` | string / array | Must have exact length `n` | | `.finite([msg])` | number | Must be finite (not NaN, not ±Infinity) | | `.safe([msg])` | number | Must be a safe integer (not NaN, not ±Infinity, no fractional part) | | `.optional()` | Any | Null or missing values skip validation | @@ -48,29 +48,36 @@ | `.strict()` | object | Reject undefined fields | | `.passthrough()` | object | Keep undefined fields as-is | | `.strip()` | object | Silently remove undefined fields (default) | -| `.describe(text)` | Any | Attach description rendered by `schema_to_prompt()` for LLM prompts | -| `.message(text)` | Any | Override the last rule's error message | -| `.intersect(other)` | Any | Intersection: input must match both schemas; object fields are merged | -| `.pick(keys)` | object | Select only specified fields | -| `.omit(keys)` | object | Remove specified fields | -| `.partial()` | object | Make all fields optional | +| `.describe(text)` | Any | **Phase 17**: Attach description rendered by `schema_to_prompt()` for LLM prompts | +| `.message(text)` | Any | **Phase 19**: Override the last rule's error message | +| `.name(text)` | Any | **Phase 25**: Assign a name for schema exports and code generation | +| `.intersect(other)` | Any | **Phase 18**: Intersection: input must match both schemas; object fields are merged | +| `.pick(keys)` | object | **Phase 21**: Select only specified fields | +| `.omit(keys)` | object | **Phase 21**: Remove specified fields | +| `.partial()` | object | **Phase 21**: Make all fields optional | | `.refine(check, msg)` | Any | Custom validation predicate | -| `.transform(fn)` | Any | Validate then transform output via `(Json) -> Result[Json, String]` | +| `.transform(fn)` | Any | **Phase 13**: Validate then transform output via `(Json) -> Result[Json, String]` | ### Standalone Functions | Function | Description | |---|---| -| `schema_to_prompt(Schema)` | Generate TypeScript-interface prompt string for LLM (with constraint comments) — inline expansion | -| `schema_to_prompt_named(Schema, include_names?)` | Generate modular TypeScript interfaces from named schemas with topological sorting and type name references — for complex, nested LLM tool schemas | -| `to_json_schema(Schema)` | Export standard JSON Schema object with full constraint annotations | -| `to_json_schema_skeleton(Schema)` | Export lightweight JSON Schema skeleton (structure only, no constraints) | -| `to_json_schema_named(Schema, include_names?)` | Export named schemas as separate JSON Schema definitions with `$defs` and `$ref` | -| `json_schema_to_moon_zod(Json)` | **NEW**: Reverse-generate moon_zod schema source code from a JSON Schema object; supports `$defs`, `$ref`, constraints, format validation | -| `schema_to_moonbit_struct(Schema)` | Generate MoonBit struct definition (type name, fields, constraints) from ObjectType/EnumType | -| `schema_to_moonbit_struct_full(Schema)` | Generate struct definition + `from_json()` function for type-safe JSON → struct conversion | -| `schema_to_moonbit_struct_named(Schema, include_names?)` | Same as `schema_to_moonbit_struct()` but extracts and topologically sorts all nested named schemas | -| `schema_to_moonbit_struct_named_full(Schema, include_names?)` | Same as `schema_to_moonbit_struct_full()` but extracts all nested named schemas | +| `schema_to_prompt(Schema)` | **Phase 16**: Generate TypeScript-interface prompt string for LLM (with constraint comments) — inline expansion | +| `schema_to_prompt_named(Schema, include_names?)` | **Phase 25, 34**: Generate modular TypeScript interfaces from named schemas with topological sorting and type name references | +| `to_json_schema(Schema)` | **Phase 15**: Export standard JSON Schema object with full constraint annotations | +| `to_json_schema_skeleton(Schema)` | **Phase 15**: Export lightweight JSON Schema skeleton (structure only, no constraints) | +| `to_json_schema_named(Schema, include_names?)` | **Phase 26, 34**: Export named schemas as separate JSON Schema definitions with `$defs` and `$ref` | +| `json_schema_to_moon_zod(Json)` | **Phase 27, 36**: Reverse-generate moon_zod schema source code from a JSON Schema object; supports `$defs`, `$ref`, constraints, format validation | +| `schema_to_moonbit_struct(Schema)` | **Phase 28**: Generate MoonBit struct definition (type name, fields, constraints) from ObjectType/EnumType | +| `schema_to_moonbit_struct_full(Schema)` | **Phase 29**: Generate struct definition + `from_json()` function for type-safe JSON → struct conversion | +| `schema_to_moonbit_struct_named(Schema, include_names?)` | **Phase 31**: Same as `schema_to_moonbit_struct()` but extracts and topologically sorts all nested named schemas | +| `schema_to_moonbit_struct_named_full(Schema, include_names?)` | **Phase 31**: Same as `schema_to_moonbit_struct_full()` but extracts all nested named schemas | +| `schema_to_moon_zod_code(Schema)` | Generate moon_zod schema source code from a Schema | +| `schema_to_moon_zod_code_named(Schema, include_names?)` | Generate moon_zod schema source code with named `$defs` and `$ref` references | +| `json_schema_to_schema(Json)` | Reverse-parse a JSON Schema object into a moon_zod Schema | +| `json_infer_schema(Json)` | Infer a moon_zod Schema from a sample JSON value | +| `append_rule(Schema, (Json) -> Bool, String)` | Append a raw validation rule to a schema | +| `append_rule_with_annotation(Schema, (Json) -> Bool, String, Json)` | Append a validation rule with an annotation payload | | `format_path(Array[String])` | Join path stack to dot-notation string | | `ValidationError::to_string()` | Format error as `[path] message (got: value)` | diff --git a/docs/CLI.md b/docs/CLI.md index 2b61357..4bf72e0 100644 --- a/docs/CLI.md +++ b/docs/CLI.md @@ -6,18 +6,17 @@ Generate `@moon_zod` schema code instantly from any JSON payload — no need to moon run cmd/json2schema -- '{"hello": "world"}' ``` -Output: +Output (copy-paste ready moon_zod code): -``` -── Input JSON ── -Object({hello: String(world)}) - -── Generated moon_zod Schema (copy-paste ready) ── +```moonbit @moon_zod.object({ "hello": @moon_zod.string(), }) +``` -── End ── +For verbose output with debug information: +```bash +moon run cmd/json2schema -- --verbose '{"hello": "world"}' ``` The generator recursively infers types (`string`, `number`, `boolean`, `null`, `array`, `object`) and safely escapes special characters in object keys. Empty arrays produce a `/* TODO: specify exact type */` comment to alert you when type inference lacked data. @@ -28,6 +27,7 @@ The generator recursively infers types (`string`, `number`, `boolean`, `null`, ` Generate `@moon_zod` schema code from a standard **JSON Schema (draft-07)** definition — the inverse of `to_json_schema()`. +**Inline mode** (JSON Schema as command argument): ```bash moon run cmd/json2schema -- --from-json-schema '{ "type": "object", @@ -39,6 +39,11 @@ moon run cmd/json2schema -- --from-json-schema '{ }' ``` +**File mode** (read JSON Schema from file): +```bash +moon run cmd/json2schema -- --from-json-schema --schema-file schema.json +``` + Output: ```moonbit @@ -50,11 +55,12 @@ Output: **Features**: - Converts all JSON Schema types (string, number, integer, boolean, null, array, object) -- Extracts constraints: `minLength`, `maxLength`, `minimum`, `maximum`, `multipleOf`, `pattern`, `format` (email, uri, date-time, ipv4, ipv6, uuid) +- Extracts constraints: `minLength`, `maxLength`, `minimum`, `maximum`, `exclusiveMinimum`, `exclusiveMaximum`, `multipleOf`, `pattern`, `format` (email, uri, date-time, ipv4, ipv6, uuid) - Handles `$defs` and `$ref` references — generates separate named schema declarations -- Supports `enum` and `oneOf` / `anyOf` / `allOf` +- Supports `enum`, `oneOf`, `anyOf`, `allOf` - Fields not in `required` auto-wrapped with `.optional()` - Outputs **copy-paste-ready MoonBit source code** +- Full support for Phase 36 semantics: `exclusiveMinimum`/`exclusiveMaximum` generate `.positive()`/`.negative()` where applicable --- @@ -112,6 +118,9 @@ moon run cmd/validate -- '{"name":"Alice"}' '{"name":"Bob"}\n{"name":"Eve"}\n{"a # FAIL: line 3 # [name] Required (got: Null) # Results: 2 passed, 1 failed + +# File mode (JSON Schema as schema source) +moon run cmd/validate -- --schema-file schema.json --sample-file data.json ``` **Error output format**: `[field_path] message (got: value)` diff --git a/docs/INFO.md b/docs/INFO.md index 928beb0..90bee36 100644 --- a/docs/INFO.md +++ b/docs/INFO.md @@ -66,6 +66,10 @@ moon_zod/ │ ├── constraint_extractor.mbt # Extract constraint info from rules │ └── moon_zod_wbtest.mbt # White-box tests (path stack invariants) │ +├── combinators/ # Schema combinator utilities +│ ├── schema_combinators.mbt # Schema composition helpers +│ └── reexporter.mbt # Re-exports +│ ├── exporters/ # Code/schema export tools │ ├── prompt.mbt # schema_to_prompt() / schema_to_prompt_named() │ ├── prompt_renderer.mbt # Trait-based prompt rendering @@ -80,7 +84,7 @@ moon_zod/ │ ├── from_json_schema.mbt # json_schema_to_moon_zod() — reverse JSON Schema → moon_zod code generation │ └── reexporter.mbt # Module re-exports │ -├── tests/ # Test suite (407 tests) +├── tests/ # Test suite (426 tests) │ ├── test_string.mbt # string() validator tests │ ├── test_number.mbt # number() validator tests │ ├── test_boolean_null.mbt # boolean/null tests @@ -88,7 +92,8 @@ moon_zod/ │ ├── test_array.mbt # array() tests │ ├── test_combinators.mbt # union/literal/optional/default tests │ ├── test_transform_refine.mbt # transform/refine tests -│ ├── test_json_schema.mbt # JSON Schema export tests +│ ├── test_json_schema.mbt # JSON Schema export + $defs/$ref tests +│ ├── test_json_schema_fixes.mbt # exclusiveMin/Max semantics + enum edge cases │ ├── test_moonbit_struct.mbt # MoonBit struct generation tests │ ├── test_prompt.mbt # Prompt generation tests │ ├── test_prompt_named.mbt # Named schema export tests @@ -105,11 +110,17 @@ moon_zod/ │ └── validate/ # JSON schema validator (infer-then-validate) │ └── examples/ # LLM agent demonstrations - ├── llm_agent/ # Basic LLM tool calling example - ├── educational_agent/ # Multi-round self-correction demo - ├── real_llm_agent/ # Real LLM integration (with API fallback to mock) + ├── json2schema/ # JSON → moon_zod schema code generation + ├── mock/ # Mock agent demonstrations + │ ├── llm_agent/ # Basic LLM tool calling example + │ └── educational_agent/ # Multi-round self-correction demo ├── multiple_schemas/ # Handling multiple schemas - └── schema2prompt/ # Schema → prompt generation showcase + ├── real_llm_agent/ # Real LLM integration (with API fallback to mock) + ├── resources/ # Sample data files (JSON, JSON Schema) + ├── schema2json/ # Schema → JSON Schema export demo + ├── schema2prompt/ # Schema → prompt generation showcase + ├── shared_schemas/ # Shared schema definitions (library package) + └── validate_cli/ # CLI validation demo ``` --- @@ -118,22 +129,28 @@ moon_zod/ ```bash # Testing & Building -moon test # Run all tests (407 total, 0 warnings) +moon test # Run all tests (426 total, 0 warnings) moon build # Build the library +moon check # Type check (0 errors, 0 warnings) moon info && moon fmt # Update interface + format # CLI Tools moon run cmd/main # Run performance benchmarks moon run cmd/json2schema -- '{"hello":"world"}' # JSON → moon_zod schema code moon run cmd/json2schema -- --from-json-schema '<{...}>' # JSON Schema → moon_zod code +moon run cmd/json2schema -- --from-json-schema '<{...}>' --verbose # with debug output moon run cmd/gen-struct -- '{"name":"Alice"}' # JSON → MoonBit struct + from_json() moon run cmd/validate -- '{"name":"Alice"}' '{"name":"Bob"}' # Validate JSON # Examples -moon run examples/llm_agent # Basic LLM tool calling demo +moon run examples/mock/llm_agent # Basic LLM tool calling demo +moon run examples/mock/educational_agent # Multi-round self-correction demo moon run examples/real_llm_agent -- product prompt # Real LLM with mock fallback moon run examples/real_llm_agent -- product validate # Validate with real API -moon run examples/multiple_schemas # Multiple schema handling +moon run examples/multiple_schemas # Multiple schema handling +moon run examples/schema2json -- product schema # Schema → JSON Schema export +moon run examples/schema2prompt # Schema → prompt generation showcase +moon run examples/json2schema # JSON → moon_zod schema code gen ``` --- @@ -143,7 +160,7 @@ moon run examples/multiple_schemas # Multiple schema handling - **Primitive schemas**: `string()`, `number()`, `boolean()`, `null()` - **Compound schemas**: `object(Map)`, `array(Schema)`, `union(Array[Schema])`, `intersection(Array[Schema])`, `enum_values(Array[String])`, `literal(Json)` - **String validators** (20+): `.min(n)`, `.max(n)`, `.nonempty()`, `.email()` (full RFC validation), `.url()` (full structure), `.regex(pattern)` (substring match), `.startsWith()`, `.endsWith()`, `.includes()`, `.uuid()`, `.cuid()`, `.ulid()`, `.datetime()`, `.ip()`/`.ipv4()`/`.ipv6()`, `.length(n)` -- **Number validators** (9+): `.int()`, `.positive()`, `.negative()`, `.multipleOf()`, `.finite()`, `.safe()`, `.min()`, `.max()`, `.length()` +- **Number validators** (8+): `.int()`, `.positive()`, `.negative()`, `.multipleOf()`, `.finite()`, `.safe()`, `.min()`, `.max()` - **Object modes**: `.strip()` (default, removes unknown fields), `.passthrough()` (keeps unknown fields), `.strict()` (rejects unknown fields) - **Schema composition**: `.pick(keys)`, `.omit(keys)`, `.partial()` to derive object sub-schemas - **Optional/Default handling**: `.optional()` and `.default(value)` with correct rule chaining through wrappers diff --git a/docs/zh/API.md b/docs/zh/API.md index 45dadad..8556ac9 100644 --- a/docs/zh/API.md +++ b/docs/zh/API.md @@ -3,17 +3,17 @@ ### 工厂函数 | 函数 | 描述 | -|---|---|---| +|---|---| | `string(required_error?, invalid_type_error?)` | 校验 JSON 字符串 | | `number(required_error?, invalid_type_error?)` | 校验 JSON 数字 | | `boolean(required_error?, invalid_type_error?)` | 校验 JSON 布尔值 | | `null(required_error?, invalid_type_error?)` | 校验 JSON null | | `array(Schema, required_error?, invalid_type_error?)` | 校验数组,递归检查元素 | | `object(Map[String, Schema], required_error?, invalid_type_error?)` | 校验对象。**默认:Strip 模式** | -| `enum_values(Array[String], required_error?, invalid_type_error?)` | 固定的允许字符串值集合 | -| `literal(Json, required_error?, invalid_type_error?)` | **新增**:常量值校验 — 仅接受精确的 JSON 匹配(字符串、数字、布尔值、null、数组或对象) | +| `enum_values(Array[String], required_error?, invalid_type_error?)` | 固定的允许字符串值集合(混合类型请使用 `literal()` + `union()`) | +| `literal(Json, required_error?, invalid_type_error?)` | **Phase 32**: 常量值校验 — 仅接受精确的 JSON 匹配(字符串、数字、布尔值、null、数组或对象) | | `union(Array[Schema], required_error?, invalid_type_error?)` | 联合类型 — 如果任何 schema 匹配则通过 | -| `intersection(Array[Schema], required_error?, invalid_type_error?)` | 交集 — 如果所有 schema 都匹配则通过;对象字段被合并 | +| `intersection(Array[Schema], required_error?, invalid_type_error?)` | **Phase 18**: 交集 — 如果所有 schema 都匹配则通过;对象字段被合并 | ### Schema 方法 @@ -22,6 +22,7 @@ | `.parse(Json, path?)` | 全部 | 校验,返回 `Ok(Json)` 或 `Err(Array[ValidationError])` | | `.min(n[, msg])` | string / number / array | 最小长度 / 值 | | `.max(n[, msg])` | string / number / array | 最大长度 / 值 | +| `.length(n[, msg])` | string / array | 精确长度 | | `.nonempty([msg])` | string | 字符串不能为空 | | `.email([msg])` | string | 完整邮箱校验(引号本地部分、IP 字面量、+tag、TLD≥2、单个 @) | | `.url([msg])` | string | 完整 URL 结构:`scheme://host[:port][/path][?query][#fragment]` | @@ -40,7 +41,6 @@ | `.positive([msg])` | number | 必须 > 0 | | `.negative([msg])` | number | 必须 < 0 | | `.multipleOf(n[, msg])` | number | 必须是 `n` 的倍数 | -| `.length(n[, msg])` | string / array | 必须恰好有 `n` 的长度 | | `.finite([msg])` | number | 必须是有限数(不是 NaN,不是 ±Infinity) | | `.safe([msg])` | number | 必须是安全整数(不是 NaN,不是 ±Infinity,无小数部分) | | `.optional()` | 任意 | null 或缺失值跳过校验 | @@ -48,29 +48,36 @@ | `.strict()` | object | 拒绝未定义的字段 | | `.passthrough()` | object | 保持未定义的字段不变 | | `.strip()` | object | 无声地移除未定义的字段(默认) | -| `.describe(text)` | 任意 | 附加描述,由 `schema_to_prompt()` 为 LLM 提示渲染 | -| `.message(text)` | 任意 | 覆盖最后一条规则的错误消息 | -| `.intersect(other)` | 任意 | 交集:输入必须匹配两个 schema;对象字段被合并 | -| `.pick(keys)` | object | 仅选择指定字段 | -| `.omit(keys)` | object | 移除指定字段 | -| `.partial()` | object | 使所有字段可选 | +| `.describe(text)` | 任意 | **Phase 17**: 附加描述,由 `schema_to_prompt()` 为 LLM 提示渲染 | +| `.message(text)` | 任意 | **Phase 19**: 覆盖最后一条规则的错误消息 | +| `.name(text)` | 任意 | **Phase 25**: 为 schema 导出和代码生成分配名称 | +| `.intersect(other)` | 任意 | **Phase 18**: 交集:输入必须匹配两个 schema;对象字段被合并 | +| `.pick(keys)` | object | **Phase 21**: 仅选择指定字段 | +| `.omit(keys)` | object | **Phase 21**: 移除指定字段 | +| `.partial()` | object | **Phase 21**: 使所有字段可选 | | `.refine(check, msg)` | 任意 | 自定义校验谓词 | -| `.transform(fn)` | 任意 | 校验然后通过 `(Json) -> Result[Json, String]` 转换输出 | +| `.transform(fn)` | 任意 | **Phase 13**: 校验然后通过 `(Json) -> Result[Json, String]` 转换输出 | ### 独立函数 | 函数 | 描述 | |---|---| -| `schema_to_prompt(Schema)` | 为 LLM 生成 TypeScript 接口提示字符串(含约束注释) — 内联展开 | -| `schema_to_prompt_named(Schema, include_names?)` | 从命名 schema 生成模块化 TypeScript 接口,含拓扑排序和类型名称引用 — 用于复杂、嵌套的 LLM 工具 schema | -| `to_json_schema(Schema)` | 导出标准 JSON Schema 对象,含完整约束注解 | -| `to_json_schema_skeleton(Schema)` | 导出轻量级 JSON Schema 骨架(仅结构,无约束) | -| `to_json_schema_named(Schema, include_names?)` | 导出命名 schema 为独立的 JSON Schema 定义,含 `$defs` 和 `$ref` 引用 | -| `json_schema_to_moon_zod(Json)` | **新增**:反向生成 moon_zod Schema 源代码;完整支持 `$defs`、`$ref`、约束、格式验证 | -| `schema_to_moonbit_struct(Schema)` | 从 ObjectType/EnumType 生成 MoonBit 结构体定义(类型名、字段、约束) | -| `schema_to_moonbit_struct_full(Schema)` | 生成结构体定义 + `from_json()` 函数用于类型安全的 JSON → 结构体转换 | -| `schema_to_moonbit_struct_named(Schema, include_names?)` | 同 `schema_to_moonbit_struct()`,但提取并拓扑排序所有嵌套命名 schema | -| `schema_to_moonbit_struct_named_full(Schema, include_names?)` | 同 `schema_to_moonbit_struct_full()`,但提取所有嵌套命名 schema | +| `schema_to_prompt(Schema)` | **Phase 16**: 为 LLM 生成 TypeScript 接口提示字符串(含约束注释)— 内联展开 | +| `schema_to_prompt_named(Schema, include_names?)` | **Phase 25, 34**: 从命名 schema 生成模块化 TypeScript 接口,含拓扑排序和类型名称引用 | +| `to_json_schema(Schema)` | **Phase 15**: 导出标准 JSON Schema 对象,含完整约束注解 | +| `to_json_schema_skeleton(Schema)` | **Phase 15**: 导出轻量级 JSON Schema 骨架(仅结构,无约束) | +| `to_json_schema_named(Schema, include_names?)` | **Phase 26, 34**: 导出命名 schema 为独立的 JSON Schema 定义,含 `$defs` 和 `$ref` | +| `json_schema_to_moon_zod(Json)` | **Phase 27, 36**: 反向生成 moon_zod Schema 源代码;支持 `$defs`、`$ref`、约束、格式验证 | +| `schema_to_moonbit_struct(Schema)` | **Phase 28**: 从 ObjectType/EnumType 生成 MoonBit 结构体定义(类型名、字段、约束) | +| `schema_to_moonbit_struct_full(Schema)` | **Phase 29**: 生成结构体定义 + `from_json()` 函数用于类型安全的 JSON → 结构体转换 | +| `schema_to_moonbit_struct_named(Schema, include_names?)` | **Phase 31**: 同 `schema_to_moonbit_struct()`,但提取并拓扑排序所有嵌套命名 schema | +| `schema_to_moonbit_struct_named_full(Schema, include_names?)` | **Phase 31**: 同 `schema_to_moonbit_struct_full()`,但提取所有嵌套命名 schema | +| `schema_to_moon_zod_code(Schema)` | 从 Schema 生成 moon_zod schema 源代码 | +| `schema_to_moon_zod_code_named(Schema, include_names?)` | 生成带命名 `$defs` 和 `$ref` 引用的 moon_zod schema 源代码 | +| `json_schema_to_schema(Json)` | 反向解析 JSON Schema 对象为 moon_zod Schema | +| `json_infer_schema(Json)` | 从样本 JSON 值推断 moon_zod Schema | +| `append_rule(Schema, (Json) -> Bool, String)` | 向 schema 追加原始验证规则 | +| `append_rule_with_annotation(Schema, (Json) -> Bool, String, Json)` | 追加带注解负载的验证规则 | | `format_path(Array[String])` | 将路径栈连接为点号记号字符串 | | `ValidationError::to_string()` | 将错误格式化为 `[path] message (got: value)` | diff --git a/docs/zh/CLI.md b/docs/zh/CLI.md index 4a1450b..279ec5f 100644 --- a/docs/zh/CLI.md +++ b/docs/zh/CLI.md @@ -6,18 +6,17 @@ moon run cmd/json2schema -- '{"hello": "world"}' ``` -输出: +输出(可直接复制粘贴的 moon_zod 代码): -``` -── Input JSON ── -Object({hello: String(world)}) - -── Generated moon_zod Schema (copy-paste ready) ── +```moonbit @moon_zod.object({ "hello": @moon_zod.string(), }) +``` -── End ── +如需带调试信息的详细输出: +```bash +moon run cmd/json2schema -- --verbose '{"hello": "world"}' ``` 该生成器递归推断类型(`string`、`number`、`boolean`、`null`、`array`、`object`),并安全转义对象键中的特殊字符。空数组会生成 `/* TODO: specify exact type */` 注释,以便在类型推断缺乏数据时提醒你。 @@ -28,6 +27,7 @@ Object({hello: String(world)}) 从标准 **JSON Schema (draft-07)** 定义生成 `@moon_zod` schema 代码 — `to_json_schema()` 的逆操作。 +**内联模式**(JSON Schema 作为命令行参数): ```bash moon run cmd/json2schema -- --from-json-schema '{ "type": "object", @@ -39,6 +39,11 @@ moon run cmd/json2schema -- --from-json-schema '{ }' ``` +**文件模式**(从文件读取 JSON Schema): +```bash +moon run cmd/json2schema -- --from-json-schema --schema-file schema.json +``` + 输出: ```moonbit @@ -50,11 +55,12 @@ moon run cmd/json2schema -- --from-json-schema '{ **特性**: - 转换所有 JSON Schema 类型(string、number、integer、boolean、null、array、object) -- 提取约束:`minLength`、`maxLength`、`minimum`、`maximum`、`multipleOf`、`pattern`、`format`(email、uri、date-time、ipv4、ipv6、uuid) +- 提取约束:`minLength`、`maxLength`、`minimum`、`maximum`、`exclusiveMinimum`、`exclusiveMaximum`、`multipleOf`、`pattern`、`format`(email、uri、date-time、ipv4、ipv6、uuid) - 处理 `$defs` 和 `$ref` 引用 — 生成单独的命名 schema 声明 -- 支持 `enum` 和 `oneOf` / `anyOf` / `allOf` +- 支持 `enum`、`oneOf`、`anyOf`、`allOf` - 不在 `required` 中的字段自动用 `.optional()` 包装 - 输出 **可直接复制粘贴的 MoonBit 源代码** +- 完整支持 Phase 36 语义:`exclusiveMinimum`/`exclusiveMaximum` 在适用时生成 `.positive()`/`.negative()` --- @@ -112,6 +118,9 @@ moon run cmd/validate -- '{"name":"Alice"}' '{"name":"Bob"}\n{"name":"Eve"}\n{"a # FAIL: line 3 # [name] Required (got: Null) # Results: 2 passed, 1 failed + +# 文件模式(JSON Schema 作为 schema 源) +moon run cmd/validate -- --schema-file schema.json --sample-file data.json ``` **错误输出格式**:`[field_path] message (got: value)` diff --git a/docs/zh/INFO.md b/docs/zh/INFO.md index 0ce2a56..744ca81 100644 --- a/docs/zh/INFO.md +++ b/docs/zh/INFO.md @@ -66,6 +66,10 @@ moon_zod/ │ ├── constraint_extractor.mbt # 从规则提取约束信息 │ └── moon_zod_wbtest.mbt # 白盒测试(路径栈不变量) │ +├── combinators/ # Schema 组合工具 +│ ├── schema_combinators.mbt # Schema 组合辅助函数 +│ └── reexporter.mbt # 重新导出 +│ ├── exporters/ # 代码/Schema 导出工具 │ ├── prompt.mbt # schema_to_prompt() / schema_to_prompt_named() │ ├── prompt_renderer.mbt # 基于 Trait 的提示渲染 @@ -80,7 +84,7 @@ moon_zod/ │ ├── from_json_schema.mbt # json_schema_to_moon_zod() — 反向 JSON Schema → moon_zod 代码生成 │ └── reexporter.mbt # 模块重新导出 │ -├── tests/ # 测试套件(407 个测试) +├── tests/ # 测试套件(426 个测试) │ ├── test_string.mbt # string() 验证器测试 │ ├── test_number.mbt # number() 验证器测试 │ ├── test_boolean_null.mbt # boolean/null 测试 @@ -88,7 +92,8 @@ moon_zod/ │ ├── test_array.mbt # array() 测试 │ ├── test_combinators.mbt # union/literal/optional/default 测试 │ ├── test_transform_refine.mbt # transform/refine 测试 -│ ├── test_json_schema.mbt # JSON Schema 导出测试 +│ ├── test_json_schema.mbt # JSON Schema 导出 + $defs/$ref 测试 +│ ├── test_json_schema_fixes.mbt # exclusiveMin/Max 语义 + enum 边界情况 │ ├── test_moonbit_struct.mbt # MoonBit 结构生成测试 │ ├── test_prompt.mbt # 提示生成测试 │ ├── test_prompt_named.mbt # 命名 Schema 导出测试 @@ -105,11 +110,17 @@ moon_zod/ │ └── validate/ # JSON Schema 验证器(推断然后验证) │ └── examples/ # LLM 代理演示 - ├── llm_agent/ # 基础 LLM 工具调用示例 - ├── educational_agent/ # 多轮自纠正演示 - ├── real_llm_agent/ # 真实 LLM 集成(带 API 回退到 mock) + ├── json2schema/ # JSON → moon_zod schema 代码生成 + ├── mock/ # Mock 代理演示 + │ ├── llm_agent/ # 基础 LLM 工具调用示例 + │ └── educational_agent/ # 多轮自纠正演示 ├── multiple_schemas/ # 处理多个 Schema - └── schema2prompt/ # Schema → 提示生成展示 + ├── real_llm_agent/ # 真实 LLM 集成(带 API 回退到 mock) + ├── resources/ # 样本数据文件(JSON、JSON Schema) + ├── schema2json/ # Schema → JSON Schema 导出演示 + ├── schema2prompt/ # Schema → 提示生成展示 + ├── shared_schemas/ # 共享 Schema 定义(库包) + └── validate_cli/ # CLI 验证演示 ``` --- @@ -118,22 +129,28 @@ moon_zod/ ```bash # 测试与构建 -moon test # 运行所有测试(共 407 个,0 个警告) +moon test # 运行所有测试(共 426 个,0 个警告) moon build # 构建库 +moon check # 类型检查(0 错误,0 警告) moon info && moon fmt # 更新接口 + 格式化 # CLI 工具 moon run cmd/main # 运行性能基准测试 moon run cmd/json2schema -- '{"hello":"world"}' # JSON → moon_zod Schema 代码 moon run cmd/json2schema -- --from-json-schema '<{...}>' # JSON Schema → moon_zod 代码 +moon run cmd/json2schema -- --from-json-schema '<{...}>' --verbose # 带调试输出版本 moon run cmd/gen-struct -- '{"name":"Alice"}' # JSON → MoonBit 结构 + from_json() moon run cmd/validate -- '{"name":"Alice"}' '{"name":"Bob"}' # 验证 JSON # 示例 -moon run examples/llm_agent # 基础 LLM 工具调用演示 +moon run examples/mock/llm_agent # 基础 LLM 工具调用演示 +moon run examples/mock/educational_agent # 多轮自纠正演示 moon run examples/real_llm_agent -- product prompt # 真实 LLM(带 mock 回退) moon run examples/real_llm_agent -- product validate # 用真实 API 验证 -moon run examples/multiple_schemas # 处理多个 Schema +moon run examples/multiple_schemas # 处理多个 Schema +moon run examples/schema2json -- product schema # Schema → JSON Schema 导出 +moon run examples/schema2prompt # Schema → 提示生成展示 +moon run examples/json2schema # JSON → moon_zod schema 代码生成 ``` --- @@ -143,7 +160,7 @@ moon run examples/multiple_schemas # 处理多个 Schema - **基础类型 Schema**:`string()`、`number()`、`boolean()`、`null()` - **复合 Schema**:`object(Map)`、`array(Schema)`、`union(Array[Schema])`、`intersection(Array[Schema])`、`enum_values(Array[String])`、`literal(Json)` - **字符串验证器**(20+):`.min(n)`、`.max(n)`、`.nonempty()`、`.email()`(完整 RFC 验证)、`.url()`(完整结构)、`.regex(pattern)`(子字符串匹配)、`.startsWith()`、`.endsWith()`、`.includes()`、`.uuid()`、`.cuid()`、`.ulid()`、`.datetime()`、`.ip()`/`.ipv4()`/`.ipv6()`、`.length(n)` -- **数字验证器**(9+):`.int()`、`.positive()`、`.negative()`、`.multipleOf()`、`.finite()`、`.safe()`、`.min()`、`.max()`、`.length()` +- **数字验证器**(8+):`.int()`、`.positive()`、`.negative()`、`.multipleOf()`、`.finite()`、`.safe()`、`.min()`、`.max()` - **对象模式**:`.strip()`(默认,移除未知字段)、`.passthrough()`(保留未知字段)、`.strict()`(拒绝未知字段) - **Schema 组合**:`.pick(keys)`、`.omit(keys)`、`.partial()` 派生对象子 Schema - **可选/默认值处理**:`.optional()` 和 `.default(value)`,通过包装器正确链接规则 diff --git a/moon.mod b/moon.mod index d80b8eb..9904cbd 100644 --- a/moon.mod +++ b/moon.mod @@ -11,7 +11,7 @@ name = "Betterlol/moon_zod" -version = "0.7.0" +version = "0.7.5" readme = "README.mbt.md"