feat(schema): implement Phase 2 StringSchema and NumberSchema#13
feat(schema): implement Phase 2 StringSchema and NumberSchema#13viniciusdacal merged 2 commits intomainfrom
Conversation
StringSchema: type validation, min/max/length, regex, startsWith/endsWith/includes, uppercase/lowercase validation, trim/toLowerCase/toUpperCase/normalize transforms, per-rule custom error messages, JSON Schema output. NumberSchema: type validation (rejects NaN), gte/gt/lte/lt bounds, int, positive/ negative/nonnegative/nonpositive, multipleOf/step, finite, per-rule custom error messages, JSON Schema output with integer type support. 18 TDD cycles, 43 tests passing. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
viniciusdacal
left a comment
There was a problem hiding this comment.
Code Review — PR #13: Phase 2 StringSchema and NumberSchema
Strengths
- Strict TDD followed — 18 red-green-refactor cycles, 43 tests
- Immutable chaining pattern consistent with Phase 1 base class
- Transforms (trim, toLowerCase, toUpperCase, normalize) correctly applied before validation
- JSON Schema output correctly maps constraints (minLength, maxLength, pattern, minimum, exclusiveMinimum, etc.)
NumberSchema.int()correctly maps to{ type: "integer" }in JSON Schema
Issues & Suggestions
1. _clone() boilerplate is growing — string.ts, number.ts
Both schemas have 15+ fields to copy in _clone(). This is correct and safe, but as more constraint methods are added it becomes a maintenance burden. Consider a shared helper or Object.assign pattern in a future refactor phase (e.g., Phase 4 when wrapper schemas introduce more cloning).
2. gt() and lt() don't support custom error messages — number.ts
.gte() and .lte() accept an optional message param, but .gt() and .lt() don't. This is inconsistent — consider adding the same optional message param for parity.
3. StringSchema.regex() error message is just "Invalid" — string.ts:51
Other constraints have descriptive messages, but regex failure says "Invalid". Consider including the pattern: Invalid: must match ${pattern}.
4. Missing DateSchema.toISOString() transform from plan — noted for Phase 3 scope
The plan mentions .toISOString() as a transform on DateSchema. This wasn't included in Phase 2 (which is correct since DateSchema is Phase 3), but it's also missing from Phase 3. Worth tracking.
5. length() doesn't support custom error messages — string.ts
.min() and .max() accept custom messages but .length() does not. Minor inconsistency.
Test Coverage
- Good coverage of happy/unhappy paths for all constraints
- Tests verify both
parse()throwing andsafeParse()returning errors - Custom error message tests included for min/max on both schemas
- JSON Schema output tested with combined constraints
Summary
Clean, well-tested implementation. The main suggestions are minor consistency improvements (custom messages on all constraint methods, better regex error message). Nothing blocking.
…mprove regex message Address PR #13 review feedback: consistent custom message support across all constraint methods and descriptive regex failure messages. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat(schema): implement Phase 2 StringSchema and NumberSchema StringSchema: type validation, min/max/length, regex, startsWith/endsWith/includes, uppercase/lowercase validation, trim/toLowerCase/toUpperCase/normalize transforms, per-rule custom error messages, JSON Schema output. NumberSchema: type validation (rejects NaN), gte/gt/lte/lt bounds, int, positive/ negative/nonnegative/nonpositive, multipleOf/step, finite, per-rule custom error messages, JSON Schema output with integer type support. 18 TDD cycles, 43 tests passing. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix(schema): add custom error messages to gt(), lt(), length(), and improve regex message Address PR #13 review feedback: consistent custom message support across all constraint methods and descriptive regex failure messages. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Summary
StringSchemaandNumberSchemafor@vertz/schemavia strict TDD (18 red-green-refactor cycles)StringSchema
.min(),.max(),.length(),.regex(),.startsWith(),.endsWith(),.includes().uppercase(),.lowercase().trim(),.toLowerCase(),.toUpperCase(),.normalize().min(5, 'Too short').toJSONSchema()—{ type, minLength, maxLength, pattern }NumberSchema
.gte()/.min(),.gt(),.lte()/.max(),.lt().int(),.positive(),.negative(),.nonnegative(),.nonpositive(),.finite().multipleOf()/.step().toJSONSchema()—{ type (number|integer), minimum, exclusiveMinimum, maximum, exclusiveMaximum, multipleOf }Test plan
npx vitest run— 43 tests passingindex.tsupdated🤖 Generated with Claude Code