[normal][docs] update docs, readme and CHANGELOG.
This commit is contained in:
parent
d023489c51
commit
d7eac2d86f
121
CHANGELOG.md
121
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**
|
||||
|
|
|
|||
145
README.mbt.md
145
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 { ... }
|
||||
|
|
|
|||
145
README_zh.mbt.md
145
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 { ... }
|
||||
|
|
|
|||
51
docs/API.md
51
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)` |
|
||||
|
||||
|
|
|
|||
27
docs/CLI.md
27
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)`
|
||||
|
|
|
|||
37
docs/INFO.md
37
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
|
||||
|
|
|
|||
|
|
@ -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)` |
|
||||
|
||||
|
|
|
|||
|
|
@ -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)`
|
||||
|
|
|
|||
|
|
@ -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)`,通过包装器正确链接规则
|
||||
|
|
|
|||
Loading…
Reference in New Issue