Skip to content

Commit 5584592

Browse files
authored
Version 1.0.41 (#1416)
* Repair: Support Sub Schema Refine Recovery * ChangeLog * Version
1 parent 29dce4b commit 5584592

5 files changed

Lines changed: 69 additions & 13 deletions

File tree

changelog/1.0.0.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
---
44

55
### Version Updates
6+
- [Revision 1.0.41](https://github.com/sinclairzx81/typebox/pull/1416)
7+
- Support Sub Schema Value Recovery on Repair
68
- [Revision 1.0.40](https://github.com/sinclairzx81/typebox/pull/1415)
79
- Support Top Level Value Recovery on Repair
810
- [Revision 1.0.39](https://github.com/sinclairzx81/typebox/pull/1411)

src/value/repair/from-type.ts

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ THE SOFTWARE.
3030

3131
import { Guard, GlobalsGuard } from '../../guard/index.ts'
3232
import * as T from '../../type/index.ts'
33+
import { Check } from '../check/index.ts'
34+
import { Create } from '../create/index.ts'
3335

3436
import { FromArray } from './from-array.ts'
3537
import { FromBase } from './from-base.ts'
@@ -73,15 +75,35 @@ function AssertRepairableType(context: T.TProperties, type: T.TSchema, value: un
7375
}
7476
}
7577
// ------------------------------------------------------------------
78+
// FinalizeRepair
79+
//
80+
// When a type includes the ~refine modifier, a post-repair validation
81+
// check must be performed to ensure the repaired value satisfies the
82+
// refine constraint. This logic is implemented as part of FromType to
83+
// ensure the post-refine validation check is handled outside of
84+
// sub-schema constraint checking (i.e., at the top level).
85+
//
86+
// ------------------------------------------------------------------
87+
function FinalizeRepair(context: T.TProperties, type: T.TSchema, repaired: unknown): unknown {
88+
return T.IsRefine(type)
89+
? Check(context, type, repaired)
90+
? repaired
91+
: Create(context, type)
92+
: repaired
93+
}
94+
// ------------------------------------------------------------------
7695
// FromType
7796
// ------------------------------------------------------------------
7897
export function FromType(context: T.TProperties, type: T.TSchema, value: unknown): unknown {
79-
// Intercept Base
80-
if (T.IsBase(type)) return FromBase(context, type, value)
81-
// Standard Repair
98+
// Base Repair
99+
if (T.IsBase(type)) {
100+
const repaired = FromBase(context, type, value)
101+
return FinalizeRepair(context, type, repaired)
102+
}
103+
// Schema Repair
82104
AssertRepairableValue(context, type, value)
83105
AssertRepairableType(context, type, value)
84-
return (
106+
const repaired = (
85107
T.IsArray(type) ? FromArray(context, type, value) :
86108
T.IsEnum(type) ? FromEnum(context, type, value) :
87109
T.IsIntersect(type) ? FromIntersect(context, type, value) :
@@ -93,4 +115,5 @@ export function FromType(context: T.TProperties, type: T.TSchema, value: unknown
93115
T.IsUnion(type) ? FromUnion(context, type, value) :
94116
FromUnknown(context, type, value)
95117
)
118+
return FinalizeRepair(context, type, repaired)
96119
}

src/value/repair/repair.ts

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,6 @@ import { Arguments } from '../../system/arguments/index.ts'
3232
import type { TProperties, TSchema, Static } from '../../type/index.ts'
3333
import { FromType } from './from-type.ts'
3434
import { Assert } from '../assert/index.ts'
35-
import { Check } from '../check/index.ts'
36-
import { Create } from '../create/index.ts'
3735

3836
/**
3937
* Repairs a value to match the provided type. This function is intended for data migration
@@ -70,7 +68,6 @@ export function Repair(...args: unknown[]): unknown {
7068
2: (type, value) => [{}, type, value],
7169
})
7270
const repaired = FromType(context, type, value)
73-
const checked = Check(context, type, repaired) ? repaired : Create(context, type)
74-
Assert(context, type, checked) // ensure correct
75-
return checked
71+
Assert(context, type, repaired)
72+
return repaired
7673
}

tasks.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { Range } from './task/range/index.ts'
88
import { Metrics } from './task/metrics/index.ts'
99
import { Task } from 'tasksmith'
1010

11-
const Version = '1.0.40'
11+
const Version = '1.0.41'
1212

1313
// ------------------------------------------------------------------
1414
// Build

test/typebox/runtime/value/repair/~refine.ts

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ Test('Should Refine 1', () => {
1313
greater: Type.Integer({ default: 10 }),
1414
smaller: Type.Integer({ default: 5 })
1515
}),
16-
(data) => data.greater > data.smaller
16+
(value) => value.greater > value.smaller
1717
)
1818
const R = Value.Repair(T, { greater: 3, smaller: 7 })
1919
Assert.IsEqual(R, {
@@ -32,7 +32,7 @@ Test('Should Refine 2', () => {
3232
smaller: 5
3333
}
3434
}),
35-
(data) => data.greater > data.smaller
35+
(value) => value.greater > value.smaller
3636
)
3737
const R = Value.Repair(T, { greater: 3, smaller: 7 })
3838
Assert.IsEqual(R, {
@@ -51,11 +51,45 @@ Test('Should Refine 3', () => {
5151
smaller: 50
5252
}
5353
}),
54-
(data) => data.greater > data.smaller
54+
(value) => value.greater > value.smaller
5555
)
5656
const R = Value.Repair(T, { greater: 3, smaller: 7 })
5757
Assert.IsEqual(R, {
5858
greater: 100,
5959
smaller: 50
6060
})
6161
})
62+
// ------------------------------------------------------------------
63+
// Coverage (Fall through case for when post refine-checks pass)
64+
// ------------------------------------------------------------------
65+
Test('Should Refine 4', () => {
66+
const T = Type.Refine(
67+
Type.Object({
68+
greater: Type.Integer({ default: 10 }),
69+
smaller: Type.Integer({ default: 5 })
70+
}),
71+
(value) => value.greater > value.smaller
72+
)
73+
const R = Value.Repair(T, { greater: 10, smaller: 5 })
74+
Assert.IsEqual(R, {
75+
greater: 10,
76+
smaller: 5
77+
})
78+
})
79+
// ------------------------------------------------------------------
80+
// https://github.com/sinclairzx81/typebox/issues/1414#issuecomment-3420056090
81+
// ------------------------------------------------------------------
82+
Test('Should Refine 5', () => {
83+
const T = Type.Object({
84+
bounds: Type.Refine(
85+
Type.Object({
86+
max: Type.Integer({ default: 10 }),
87+
min: Type.Integer({ default: 5 })
88+
}),
89+
(value) => value.max > value.min
90+
),
91+
otherData: Type.String({ default: '' })
92+
})
93+
const R = Value.Repair(T, { bounds: { max: 10, min: 15 }, otherData: 'keep this' })
94+
Assert.IsEqual(R, { bounds: { max: 10, min: 5 }, otherData: 'keep this' })
95+
})

0 commit comments

Comments
 (0)