Skip to content

Commit

Permalink
Make non-empty strings compatible with Effect
Browse files Browse the repository at this point in the history
Refs #1941, #1834
  • Loading branch information
thewilkybarkid committed Sep 19, 2024
1 parent 4971a3d commit 7e6fb76
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 0 deletions.
1 change: 1 addition & 0 deletions src/types/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export * as Pseudonym from './pseudonym.js'
export * as NonEmptyString from './string.js'
6 changes: 6 additions & 0 deletions src/types/string.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { Schema } from '@effect/schema'
import type { Eq } from 'fp-ts/lib/Eq.js'
import type { Ord } from 'fp-ts/lib/Ord.js'
import { pipe } from 'fp-ts/lib/function.js'
Expand All @@ -9,6 +10,11 @@ export type NonEmptyString = string & NonEmptyStringBrand

export const NonEmptyStringC = C.fromDecoder(pipe(D.string, D.refine(isNonEmptyString, 'NonEmptyString')))

export const NonEmptyStringSchema: Schema.Schema<NonEmptyString, string> = pipe(
Schema.String,
Schema.filter(isNonEmptyString, { message: () => 'string is empty' }),
)

export function isNonEmptyString(value: string): value is NonEmptyString {
return value.trim().length > 0
}
Expand Down
30 changes: 30 additions & 0 deletions test/types/string.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { ArrayFormatter, Schema } from '@effect/schema'
import { test } from '@fast-check/jest'
import { describe, expect } from '@jest/globals'
import { Either } from 'effect'
import * as D from 'io-ts/lib/Decoder.js'
import * as _ from '../../src/types/string.js'
import * as fc from '../fc.js'
Expand Down Expand Up @@ -32,6 +34,34 @@ describe('NonEmptyStringC', () => {
})
})

describe('NonEmptyStringSchema', () => {
describe('decode', () => {
test.prop([fc.string({ unit: fc.alphanumeric(), minLength: 1 })])('with a non-empty string', string => {
const actual = Schema.decodeSync(_.NonEmptyStringSchema)(string)

expect(actual).toStrictEqual(string)
})

test.prop([fc.string({ unit: fc.invisibleCharacter() })])('with an empty string', string => {
const actual = Either.mapLeft(Schema.decodeEither(_.NonEmptyStringSchema)(string), ArrayFormatter.formatErrorSync)

expect(actual).toStrictEqual(Either.left([expect.objectContaining({ message: 'string is empty' })]))
})

test.prop([fc.anything().filter(value => typeof value !== 'string')])('with a non-string', value => {
const actual = Schema.decodeUnknownEither(_.NonEmptyStringSchema)(value)

expect(actual).toStrictEqual(Either.left(expect.anything()))
})
})

test.prop([fc.pseudonym()])('encode', pseudonym => {
const actual = Schema.encodeSync(_.NonEmptyStringSchema)(pseudonym)

expect(actual).toStrictEqual(pseudonym)
})
})

describe('isNonEmptyString', () => {
describe('decode', () => {
test.prop([fc.string({ unit: fc.alphanumeric(), minLength: 1 })])('with a non-empty string', string => {
Expand Down

0 comments on commit 7e6fb76

Please sign in to comment.