Skip to content

Commit c5b8a9e

Browse files
committed
fix: brandedSchema signature
Signed-off-by: Andres Correa Casablanca <[email protected]>
1 parent ec0eec2 commit c5b8a9e

22 files changed

+171
-14
lines changed

.github/workflows/tests.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,4 +56,4 @@ jobs:
5656
run: "pnpm turbo test"
5757
- name: "(All) Run All Tasks"
5858
if: ${{ matrix.os != 'windows-latest' }}
59-
run: "pnpm turbo all"
59+
run: "pnpm turbo all:cov"

.hooks/pre-push

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,4 @@
33
set -eu
44
set -o pipefail
55

6-
pnpm turbo all
6+
pnpm turbo all:cov

@coderspirit/lambda-ioc/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
"devDependencies": {
3737
"@arethetypeswrong/cli": "^0.15.4",
3838
"@biomejs/biome": "1.8.3",
39+
"@vitest/coverage-v8": "^2.0.5",
3940
"get-tsconfig": "^4.7.6",
4041
"publint": "^0.2.9",
4142
"rollup": "^4.20.0",
Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,19 @@
11
import { defineConfig } from 'vitest/config'
22

33
export default defineConfig({
4-
test: {},
4+
test: {
5+
coverage: {
6+
provider: 'v8',
7+
include: ['src/**/*.mjs', 'src/**/*.mts'],
8+
exclude: ['src/**/tests/**/*', 'coverage/**/*'],
9+
thresholds: {
10+
statements: 92.0,
11+
branches: 90.0,
12+
functions: 100.0,
13+
lines: 92.0,
14+
},
15+
reportsDirectory: 'coverage',
16+
},
17+
include: ['src/**/tests/**/*.test.mts'],
18+
},
519
})

@coderspirit/nominal-typebox/README.md

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,3 +148,45 @@ const unionSchema = brandedUnion(
148148
[Literal('on'), Literal('off')]
149149
)
150150
```
151+
152+
### Fallback alternative
153+
154+
In case this library does not provide a specific schema factory for your type,
155+
you can rely on `brandedSchema`. Notice that if you are using it for complex
156+
schemas, it can loose some branding information from inner/nested properties.
157+
158+
```typescript
159+
import type { FastBrand } from '@coderspirit/nominal'
160+
import {
161+
brandedInteger,
162+
brandedSchema,
163+
brandedString,
164+
} from '@coderspirit/nominal-typebox'
165+
import { Record as TBRecord } from '@sinclair/typebox'
166+
167+
const personNameSchema = brandedString<'PersonName'>()
168+
const personAgeSchema = brandedInteger<'PersonAge'>()
169+
const recordSchema = brandedSchema('PeopleAges', TBRecord(
170+
personNameSchema,
171+
personAgeSchema,
172+
))
173+
const recordValidator = TypeCompiler.Compile(recordSchema)
174+
175+
const requestRecord = getRequestFromSomewhere() // unknown
176+
if (!requestValidator.Check(requestRecord)) {
177+
throw new Error('Invalid request!')
178+
}
179+
180+
// OK
181+
const recordSink: FastBrand<Record<string, number>, 'PeopleAges'> =
182+
requestRecord
183+
184+
// @ts-expect-error Type Error!
185+
const corruptedRecordSink: FastBrand<
186+
Record<string, number>, 'PeopleAges'
187+
> = { Alice: 20, Bob: 30 }
188+
189+
// IMPORTANT!: Notice that `brandedSchema` is unable to preserve the
190+
// brands of keys & values in the record. This limitation
191+
// is due to the fact that `brandedSchema` is too generic.
192+
```

@coderspirit/nominal-typebox/src/schema.mts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ export type BrandedSchema<B extends string, T extends TSchema> = Pick<
3030
}
3131

3232
export const brandedSchema = <const B extends string, S extends TSchema>(
33+
_b: B,
3334
schema: S,
3435
): BrandedSchema<B, S> => {
3536
return schema as BrandedSchema<B, S>

@coderspirit/nominal-typebox/src/tests/array.test.mts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,7 @@ import type { TaggedInteger } from '@coderspirit/nominal-inputs'
55
import { TypeCompiler } from '@sinclair/typebox/compiler'
66
import { describe, expect, it } from 'vitest'
77

8-
import { brandedArray } from '../array.mts'
9-
import { brandedInteger } from '../number.mts'
8+
import { brandedArray, brandedInteger } from '../main.mts'
109

1110
describe('brandedArray', () => {
1211
it('lets typebox to annotate arrays with a brand', () => {

@coderspirit/nominal-typebox/src/tests/number.test.mts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import type { TaggedInteger } from '@coderspirit/nominal-inputs'
55
import { TypeCompiler } from '@sinclair/typebox/compiler'
66
import { describe, expect, it } from 'vitest'
77

8-
import { brandedInteger, brandedNumber } from '../number.mts'
8+
import { brandedInteger, brandedNumber } from '../main.mts'
99

1010
describe('brandedInteger', () => {
1111
it('lets typebox to annotate a number as an integer', () => {

@coderspirit/nominal-typebox/src/tests/object.test.mts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,7 @@ import type { TaggedInteger } from '@coderspirit/nominal-inputs'
55
import { TypeCompiler } from '@sinclair/typebox/compiler'
66
import { describe, expect, it } from 'vitest'
77

8-
import { brandedInteger } from '../number.mts'
9-
import { brandedObject } from '../object.mts'
10-
import { brandedString } from '../string.mts'
8+
import { brandedInteger, brandedObject, brandedString } from '../main.mts'
119

1210
describe('brandedObject', () => {
1311
it('lets typebox to annotate objects with a brand', () => {

0 commit comments

Comments
 (0)