diff --git a/example/index.ts b/example/index.ts index 9d228684a..00624abbc 100644 --- a/example/index.ts +++ b/example/index.ts @@ -4,46 +4,4 @@ import { Value, ValuePointer } from '@sinclair/typebox/value' import { Parse, StaticParseAsType } from '@sinclair/typebox/syntax' import { Type, TypeGuard, Kind, Static, TSchema } from '@sinclair/typebox' -// ----------------------------------------------------------- -// Create: Type -// ----------------------------------------------------------- - -const T = Type.Object({ - x: Type.Number(), - y: Type.Number(), - z: Type.Number(), -}) - -type T = Static - -console.log(T) - -// ----------------------------------------------------------- -// Parse: Type -// ----------------------------------------------------------- - -const S = Parse({ T }, `{ x: T, y: T, z: T }`) - -type S = Static - -// ----------------------------------------------------------- -// Create: Value -// ----------------------------------------------------------- - -const V = Value.Create(T) - -console.log(V) - -// ----------------------------------------------------------- -// Compile: Type -// ----------------------------------------------------------- - -const C = TypeCompiler.Compile(T) - -console.log(C.Code()) - -// ----------------------------------------------------------- -// Check: Value -// ----------------------------------------------------------- - -console.log(C.Check(V)) +const A = Type.String({ format: 'ipv4' }) diff --git a/src/format/date-time.ts b/src/format/date-time.ts new file mode 100644 index 000000000..2244dd9be --- /dev/null +++ b/src/format/date-time.ts @@ -0,0 +1,37 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox/format + +The MIT License (MIT) + +Copyright (c) 2017-2024 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +import { FormatRegistry } from '../type/index' + +const pattern = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})([+-]\d{2}:\d{2}|Z)$/ + +export function IsDateTime(value: string): boolean { + return pattern.test(value) && new globalThis.Date(value) instanceof globalThis.Date +} + +FormatRegistry.Set('date-time', IsDateTime) diff --git a/src/format/date.ts b/src/format/date.ts new file mode 100644 index 000000000..99b3d49d0 --- /dev/null +++ b/src/format/date.ts @@ -0,0 +1,36 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox/format + +The MIT License (MIT) + +Copyright (c) 2017-2024 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +import { FormatRegistry } from '../type/index' + +const pattern = /^(?:19|20)\d\d-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])$/ + +export function IsDate(value: string): boolean { + return pattern.test(value) +} +FormatRegistry.Set('date', IsDate) diff --git a/src/format/duration.ts b/src/format/duration.ts new file mode 100644 index 000000000..cae4f08c6 --- /dev/null +++ b/src/format/duration.ts @@ -0,0 +1,37 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox/format + +The MIT License (MIT) + +Copyright (c) 2017-2024 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +import { FormatRegistry } from '../type/index' + +const pattern = /^P(?:(\d+Y)?(\d+M)?(\d+D)?(T(\d+H)?(\d+M)?(\d+S)?)?)$/ + +export function IsDuration(value: string): boolean { + return pattern.test(value) +} + +FormatRegistry.Set('duration', IsDuration) diff --git a/src/format/email.ts b/src/format/email.ts new file mode 100644 index 000000000..65f1ca013 --- /dev/null +++ b/src/format/email.ts @@ -0,0 +1,39 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox/format + +The MIT License (MIT) + +Copyright (c) 2017-2024 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +import { FormatRegistry } from '../type/index' + +const username = "a-z0-9&#%$!'/=_~^*+?`|{}-" +const charset = 'a-z0-9' +const pattern = new RegExp(`^[${username}]+(?:\\.[${username}]+)*@(?:[${charset}](?:[${charset}-]*[${charset}])?\\.)+[${charset}](?:[${charset}-]*[${charset}])?$`, 'i') + +export function IsEmail(value: string): boolean { + return pattern.test(value) +} + +FormatRegistry.Set('email', IsEmail) diff --git a/src/format/hostname.ts b/src/format/hostname.ts new file mode 100644 index 000000000..0315914cb --- /dev/null +++ b/src/format/hostname.ts @@ -0,0 +1,37 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox/format + +The MIT License (MIT) + +Copyright (c) 2017-2024 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +import { FormatRegistry } from '../type/index' + +const pattern = /^(?!:\/\/)([a-zA-Z0-9-_]+\.)*[a-zA-Z0-9][a-zA-Z0-9-_]{0,61}[a-zA-Z0-9]\.[a-zA-Z]{2,}$/ + +export function IsHostname(value: string): boolean { + return pattern.test(value) +} + +FormatRegistry.Set('hostname', IsHostname) diff --git a/src/format/idn-email.ts b/src/format/idn-email.ts new file mode 100644 index 000000000..d56e2d692 --- /dev/null +++ b/src/format/idn-email.ts @@ -0,0 +1,38 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox/format + +The MIT License (MIT) + +Copyright (c) 2017-2024 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +import { FormatRegistry } from '../type/index' + +const username = "a-z0-9\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF&#%$!'/=_~^*+?`|{}-" +const charset = 'a-z0-9\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF' +const pattern = new RegExp(`^[${username}]+(?:\\.[${username}]+)*@(?:[${charset}](?:[${charset}-]*[${charset}])?\\.)+[${charset}](?:[${charset}-]*[${charset}])?$`, 'i') + +export function IsIdnEmail(value: string): boolean { + return pattern.test(value) +} +FormatRegistry.Set('idn-email', IsIdnEmail) diff --git a/src/format/idn-hostname.ts b/src/format/idn-hostname.ts new file mode 100644 index 000000000..39dce4392 --- /dev/null +++ b/src/format/idn-hostname.ts @@ -0,0 +1,37 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox/format + +The MIT License (MIT) + +Copyright (c) 2017-2024 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +import { FormatRegistry } from '../type/index' + +const pattern = /^(?!:\/\/)([a-zA-Z0-9\u00A1-\uFFFF-_]+\.)*[a-zA-Z0-9\u00A1-\uFFFF][a-zA-Z0-9\u00A1-\uFFFF-_]{0,61}[a-zA-Z0-9\u00A1-\uFFFF]\.[a-zA-Z\u00A1-\uFFFF]{2,}$/u + +export function IsIdnHostname(value: string): boolean { + return pattern.test(value) +} + +FormatRegistry.Set('idn-hostname', IsIdnHostname) diff --git a/src/format/index.ts b/src/format/index.ts new file mode 100644 index 000000000..00675c8c9 --- /dev/null +++ b/src/format/index.ts @@ -0,0 +1,46 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox/format + +The MIT License (MIT) + +Copyright (c) 2017-2024 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +export * from './date-time' +export * from './date' +export * from './duration' +export * from './email' +export * from './hostname' +export * from './idn-email' +export * from './idn-hostname' +export * from './ipv4' +export * from './ipv6' +export * from './iri' +export * from './iri-reference' +export * from './json-pointer' +export * from './regex' +export * from './time' +export * from './uri-reference' +export * from './uri-template' +export * from './uri' +export * from './uuid' diff --git a/src/format/ipv4.ts b/src/format/ipv4.ts new file mode 100644 index 000000000..23c8bd7ad --- /dev/null +++ b/src/format/ipv4.ts @@ -0,0 +1,36 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox/format + +The MIT License (MIT) + +Copyright (c) 2017-2024 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +import { FormatRegistry } from '../type/index' + +const pattern = /^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/ + +export function IsIpv4(value: string): boolean { + return pattern.test(value) +} +FormatRegistry.Set('ipv4', IsIpv4) diff --git a/src/format/ipv6.ts b/src/format/ipv6.ts new file mode 100644 index 000000000..07597054e --- /dev/null +++ b/src/format/ipv6.ts @@ -0,0 +1,36 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox/format + +The MIT License (MIT) + +Copyright (c) 2017-2024 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +import { FormatRegistry } from '../type/index' + +const pattern = /^(?:[a-fA-F0-9]{1,4}:){7}[a-fA-F0-9]{1,4}$/ + +export function IsIpv6(value: string): boolean { + return pattern.test(value) +} +FormatRegistry.Set('ipv6', IsIpv6) diff --git a/src/format/iri-reference.ts b/src/format/iri-reference.ts new file mode 100644 index 000000000..1906ab307 --- /dev/null +++ b/src/format/iri-reference.ts @@ -0,0 +1,36 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox/format + +The MIT License (MIT) + +Copyright (c) 2017-2024 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +import { FormatRegistry } from '../type/index' + +const pattern = /^(https?|ftp|file|mailto|data|irc|tel|urn|ws|wss):[^\s/$.?#].[^\s]*$/i + +export function IsIriReference(value: string): boolean { + return pattern.test(value) +} +FormatRegistry.Set('iri-reference', IsIriReference) diff --git a/src/format/iri.ts b/src/format/iri.ts new file mode 100644 index 000000000..05825d7c6 --- /dev/null +++ b/src/format/iri.ts @@ -0,0 +1,36 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox/format + +The MIT License (MIT) + +Copyright (c) 2017-2024 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +import { FormatRegistry } from '../type/index' + +const pattern = /^[a-zA-Z][a-zA-Z0-9+.-]*:[^\s]*$/ + +export function IsIri(value: string): boolean { + return pattern.test(value) +} +FormatRegistry.Set('iri', IsIri) diff --git a/src/format/json-pointer.ts b/src/format/json-pointer.ts new file mode 100644 index 000000000..6f4888d78 --- /dev/null +++ b/src/format/json-pointer.ts @@ -0,0 +1,37 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox/format + +The MIT License (MIT) + +Copyright (c) 2017-2024 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +import { FormatRegistry } from '../type/index' + +const pattern = /^(\/([^~]|~0|~1)*)*$/ + +export function IsJsonPointer(value: string): boolean { + return pattern.test(value) +} + +FormatRegistry.Set('json-pointer', IsJsonPointer) diff --git a/src/format/regex.ts b/src/format/regex.ts new file mode 100644 index 000000000..6e5b4d28b --- /dev/null +++ b/src/format/regex.ts @@ -0,0 +1,40 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox/format + +The MIT License (MIT) + +Copyright (c) 2017-2024 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +import { FormatRegistry } from '../type/index' + +export function IsRegEx(value: string): boolean { + try { + new RegExp(value) + return true + } catch { + return false + } +} + +FormatRegistry.Set('regex', IsRegEx) diff --git a/src/format/time.ts b/src/format/time.ts new file mode 100644 index 000000000..88b0eff56 --- /dev/null +++ b/src/format/time.ts @@ -0,0 +1,37 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox/format + +The MIT License (MIT) + +Copyright (c) 2017-2024 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +import { FormatRegistry } from '../type/index' + +const pattern = /^([01]?\d|2[0-3]):([0-5]?\d):([0-5]?\d)([+-](?:0[0-9]|1[0-3]):[0-5][0-9]|Z)$/ + +export function IsTime(value: string): boolean { + return pattern.test(value) +} + +FormatRegistry.Set('time', IsTime) diff --git a/src/format/uri-reference.ts b/src/format/uri-reference.ts new file mode 100644 index 000000000..05d797587 --- /dev/null +++ b/src/format/uri-reference.ts @@ -0,0 +1,36 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox/format + +The MIT License (MIT) + +Copyright (c) 2017-2024 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +import { FormatRegistry } from '../type/index' + +const pattern = /^(https?|ftp|file|mailto|data|irc|tel|urn|ws|wss):[^\s/$.?#].[^\s]*$/i + +export function IsUriReference(value: string): boolean { + return pattern.test(value) +} +FormatRegistry.Set('uri-reference', IsUriReference) diff --git a/src/format/uri-template.ts b/src/format/uri-template.ts new file mode 100644 index 000000000..1dbf6a40e --- /dev/null +++ b/src/format/uri-template.ts @@ -0,0 +1,36 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox/format + +The MIT License (MIT) + +Copyright (c) 2017-2024 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +import { FormatRegistry } from '../type/index' + +const pattern = /^(https?|ftp|file|mailto|data|irc|tel|urn|ws|wss):\/\/[^\s/$.?#].[^\s]*$/i + +export function UriTemplate(value: string): boolean { + return pattern.test(value) +} +FormatRegistry.Set('uri-template', UriTemplate) diff --git a/src/format/uri.ts b/src/format/uri.ts new file mode 100644 index 000000000..faf56ed85 --- /dev/null +++ b/src/format/uri.ts @@ -0,0 +1,36 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox/format + +The MIT License (MIT) + +Copyright (c) 2017-2024 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +import { FormatRegistry } from '../type/index' + +const pattern = /^(https?|ftp):\/\/[^\s/$.?#].[^\s]*$/i + +export function IsUri(value: string): boolean { + return pattern.test(value) +} +FormatRegistry.Set('uri', IsUri) diff --git a/src/format/uuid.ts b/src/format/uuid.ts new file mode 100644 index 000000000..48162cfa8 --- /dev/null +++ b/src/format/uuid.ts @@ -0,0 +1,36 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox/format + +The MIT License (MIT) + +Copyright (c) 2017-2024 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +import { FormatRegistry } from '../type/index' + +const pattern = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i + +export function IsUuid(value: string): boolean { + return pattern.test(value) +} +FormatRegistry.Set('uuid', IsUuid) diff --git a/src/index.ts b/src/index.ts index 90525bd71..85249cb04 100644 --- a/src/index.ts +++ b/src/index.ts @@ -26,6 +26,11 @@ THE SOFTWARE. ---------------------------------------------------------------------------*/ +// ------------------------------------------------------------------ +// Formats +// ------------------------------------------------------------------ +export * from './format/index' + // ------------------------------------------------------------------ // Infrastructure // ------------------------------------------------------------------ diff --git a/src/system/system.ts b/src/system/system.ts index 98b3647c6..7ba30d6bc 100644 --- a/src/system/system.ts +++ b/src/system/system.ts @@ -29,21 +29,7 @@ THE SOFTWARE. import { TypeRegistry, FormatRegistry } from '../type/registry/index' import { Unsafe, type TUnsafe } from '../type/unsafe/index' import { Kind } from '../type/symbols/index' -import { TypeBoxError } from '../type/error/index' -// ------------------------------------------------------------------ -// Errors -// ------------------------------------------------------------------ -export class TypeSystemDuplicateTypeKind extends TypeBoxError { - constructor(kind: string) { - super(`Duplicate type kind '${kind}' detected`) - } -} -export class TypeSystemDuplicateFormat extends TypeBoxError { - constructor(kind: string) { - super(`Duplicate string format '${kind}' detected`) - } -} // ------------------------------------------------------------------ // TypeSystem // ------------------------------------------------------------------ @@ -53,13 +39,11 @@ export type TypeFactoryFunction> = export namespace TypeSystem { /** Creates a new type */ export function Type>(kind: string, check: (options: Options, value: unknown) => boolean): TypeFactoryFunction { - if (TypeRegistry.Has(kind)) throw new TypeSystemDuplicateTypeKind(kind) TypeRegistry.Set(kind, check) return (options: Partial = {}) => Unsafe({ ...options, [Kind]: kind }) } /** Creates a new string format */ export function Format(format: F, check: (value: string) => boolean): F { - if (FormatRegistry.Has(format)) throw new TypeSystemDuplicateFormat(format) FormatRegistry.Set(format, check) return format } diff --git a/src/type/string/string.ts b/src/type/string/string.ts index c1d6061b9..a4cabe845 100644 --- a/src/type/string/string.ts +++ b/src/type/string/string.ts @@ -31,27 +31,27 @@ import { TSchema, SchemaOptions } from '../schema/index' import { Kind } from '../symbols/index' // ------------------------------------------------------------------ -// TString +// StringFormatOption // ------------------------------------------------------------------ export type StringFormatOption = | 'date-time' - | 'time' | 'date' + | 'duration' | 'email' - | 'idn-email' | 'hostname' + | 'idn-email' | 'idn-hostname' | 'ipv4' | 'ipv6' - | 'uri' - | 'uri-reference' - | 'iri' - | 'uuid' | 'iri-reference' - | 'uri-template' + | 'iri' | 'json-pointer' - | 'relative-json-pointer' | 'regex' + | 'time' + | 'uri-reference' + | 'uri-template' + | 'uri' + | 'uuid' | ({} & string) // prettier-ignore export type StringContentEncodingOption = @@ -75,12 +75,14 @@ export interface StringOptions extends SchemaOptions { /** The content media type for this string */ contentMediaType?: string } +// ------------------------------------------------------------------ +// TString +// ------------------------------------------------------------------ export interface TString extends TSchema, StringOptions { [Kind]: 'String' static: string type: 'string' } - /** `[Json]` Creates a String type */ export function String(options?: StringOptions): TString { return CreateType({ [Kind]: 'String', type: 'string' }, options) as never diff --git a/task/build/package/build.ts b/task/build/package/build.ts index 0e05ede91..c25ec1675 100644 --- a/task/build/package/build.ts +++ b/task/build/package/build.ts @@ -32,7 +32,7 @@ import { createPackageJson } from './create-package-json' /** Builds package.json and redirect directories */ export async function build(target: string) { console.log('building...package.json') - const submodules = ['compiler', 'errors', 'syntax', 'system', 'type', 'value'] + const submodules = ['compiler', 'errors', 'format', 'syntax', 'system', 'type', 'value'] await createPackageJsonRedirect(target, submodules) await createPackageJson(target, submodules) } diff --git a/test/runtime/format/date-time.ts b/test/runtime/format/date-time.ts new file mode 100644 index 000000000..ffcefdcae --- /dev/null +++ b/test/runtime/format/date-time.ts @@ -0,0 +1,20 @@ +import { Assert } from '../assert/index' +import * as Format from '@sinclair/typebox/format' + +describe('format/IsDateTime', () => { + it('Should validate DateTime 1', () => { + Assert.IsFalse(Format.IsDateTime('not-a-iso-date-time')) + }) + it('Should validate DateTime 2', () => { + Assert.IsTrue(Format.IsDateTime('2023-10-01T12:00:00Z')) + }) + it('Should validate DateTime 3', () => { + Assert.IsTrue(Format.IsDateTime('2023-10-01T12:00:00+01:00')) + }) + it('Should validate DateTime 4', () => { + Assert.IsFalse(Format.IsDateTime('2023-10-01')) + }) + it('Should validate DateTime 5', () => { + Assert.IsFalse(Format.IsDateTime('2023-10-01T12:00:00')) + }) +}) diff --git a/test/runtime/format/date.ts b/test/runtime/format/date.ts new file mode 100644 index 000000000..8d3bfd48a --- /dev/null +++ b/test/runtime/format/date.ts @@ -0,0 +1,35 @@ +import { Assert } from '../assert/index' +import * as Format from '@sinclair/typebox/format' + +describe('format/IsDate', () => { + it('Should validate Date 1', () => { + Assert.IsFalse(Format.IsDate('not-a-date')) + }) + it('Should validate Date 2', () => { + Assert.IsTrue(Format.IsDate('2024-10-10')) + }) + it('Should validate Date 3', () => { + Assert.IsFalse(Format.IsDate('2024-13-10')) + }) + it('Should validate Date 4', () => { + Assert.IsFalse(Format.IsDate('2024-10-32')) + }) + it('Should validate Date 5', () => { + Assert.IsTrue(Format.IsDate('2024-02-29')) + }) + it('Should validate Date 6', () => { + Assert.IsTrue(Format.IsDate('2020-02-29')) + }) + it('Should validate Date 7', () => { + Assert.IsFalse(Format.IsDate('2024-00-10')) + }) + it('Should validate Date 8', () => { + Assert.IsFalse(Format.IsDate('2024-10-00')) + }) + it('Should validate Date 9', () => { + Assert.IsFalse(Format.IsDate('2024-10-1')) + }) + it('Should validate Date 10', () => { + Assert.IsFalse(Format.IsDate('23-10-10')) + }) +}) diff --git a/test/runtime/format/duration.ts b/test/runtime/format/duration.ts new file mode 100644 index 000000000..92e965906 --- /dev/null +++ b/test/runtime/format/duration.ts @@ -0,0 +1,20 @@ +import { Assert } from '../assert/index' +import * as Format from '@sinclair/typebox/format' + +describe('format/IsDuration', () => { + it('Should validate Duration 1', () => { + Assert.IsFalse(Format.IsDate('not-a-duration')) + }) + it('Should validate Duration 2', () => { + Assert.IsTrue(Format.IsDuration('P1Y2M3DT4H5M6S')) + }) + it('Should validate Duration 3', () => { + Assert.IsTrue(Format.IsDuration('PT4H5M6S')) + }) + it('Should validate Duration 4', () => { + Assert.IsFalse(Format.IsDuration('P-1Y2M3DT4H5M6S')) + }) + it('Should validate Duration 5', () => { + Assert.IsFalse(Format.IsDuration('P1Y2M3DT4H5M6')) + }) +}) diff --git a/test/runtime/format/email.ts b/test/runtime/format/email.ts new file mode 100644 index 000000000..dbdc785b7 --- /dev/null +++ b/test/runtime/format/email.ts @@ -0,0 +1,80 @@ +import { Assert } from '../assert/index' +import * as Format from '@sinclair/typebox/format' + +describe('format/IsEmail', () => { + it('Should validate Email 1', () => { + Assert.IsFalse(Format.IsDate('not-a-email')) + }) + it('Should validate Email 2', () => { + Assert.IsTrue(Format.IsEmail('test@example.com')) + }) + it('Should validate Email 3', () => { + Assert.IsFalse(Format.IsEmail('test@.com')) + }) + it('Should validate Email 4', () => { + Assert.IsFalse(Format.IsEmail('test@com')) + }) + it('Should validate Email 5', () => { + Assert.IsFalse(Format.IsEmail('test@com.')) + }) + it('Should validate Email 6', () => { + Assert.IsTrue(Format.IsEmail('user.name+tag+sorting@example.com')) + }) + it('Should validate Email 7', () => { + Assert.IsTrue(Format.IsEmail('user.name@example.co.uk')) + }) + it('Should validate Email 8', () => { + Assert.IsFalse(Format.IsEmail('user.name@.example.com')) + }) + it('Should validate Email 9', () => { + Assert.IsFalse(Format.IsEmail('user.name@example..com')) + }) + it('Should validate Email 10', () => { + Assert.IsTrue(Format.IsEmail('user_name@example.com')) + }) + it('Should validate Email 11', () => { + Assert.IsFalse(Format.IsEmail('user@name@example.com')) + }) + it('Should validate Email 12', () => { + Assert.IsTrue(Format.IsEmail('user-name@example.com')) + }) + it('Should validate Email 13', () => { + Assert.IsFalse(Format.IsEmail('user@name@example.com')) + }) + it('Should validate Email 14', () => { + Assert.IsTrue(Format.IsEmail('user.name@example.com')) + }) + it('Should validate Email 15', () => { + Assert.IsFalse(Format.IsEmail('user.name@.example.com')) + }) + it('Should validate Email 16', () => { + Assert.IsTrue(Format.IsEmail('user.name@example.com')) + }) + it('Should validate Email 17', () => { + Assert.IsFalse(Format.IsEmail('user.name@example..com')) + }) + it('Should validate Email 18', () => { + Assert.IsTrue(Format.IsEmail('user.name@example.com')) + }) + it('Should validate Email 19', () => { + Assert.IsFalse(Format.IsEmail('user.name@.example.com')) + }) + it('Should validate Email 20', () => { + Assert.IsTrue(Format.IsEmail('user.name@example.com')) + }) + it('Should validate Email 21', () => { + Assert.IsFalse(Format.IsEmail('user.name@example..com')) + }) + it('Should validate Email 22', () => { + Assert.IsTrue(Format.IsEmail('user.name@example.com')) + }) + it('Should validate Email 23', () => { + Assert.IsFalse(Format.IsEmail('user.name@.example.com')) + }) + it('Should validate Email 24', () => { + Assert.IsTrue(Format.IsEmail('user.name@example.com')) + }) + it('Should validate Email 25', () => { + Assert.IsFalse(Format.IsEmail('user.name@example..com')) + }) +}) diff --git a/test/runtime/format/idn-email.ts b/test/runtime/format/idn-email.ts new file mode 100644 index 000000000..9faced1dd --- /dev/null +++ b/test/runtime/format/idn-email.ts @@ -0,0 +1,95 @@ +import { Assert } from '../assert/index' +import * as Format from '@sinclair/typebox/format' + +describe('format/IsIdnEmail', () => { + it('Should validate IdnEmail 1', () => { + Assert.IsFalse(Format.IsDate('not-a-email')) + }) + it('Should validate IdnEmail 2', () => { + Assert.IsTrue(Format.IsIdnEmail('test@example.com')) + }) + it('Should validate IdnEmail 3', () => { + Assert.IsFalse(Format.IsIdnEmail('test@.com')) + }) + it('Should validate IdnEmail 4', () => { + Assert.IsFalse(Format.IsIdnEmail('test@com')) + }) + it('Should validate IdnEmail 5', () => { + Assert.IsFalse(Format.IsIdnEmail('test@com.')) + }) + it('Should validate IdnEmail 6', () => { + Assert.IsTrue(Format.IsIdnEmail('user.name+tag+sorting@example.com')) + }) + it('Should validate IdnEmail 7', () => { + Assert.IsTrue(Format.IsIdnEmail('user.name@example.co.uk')) + }) + it('Should validate IdnEmail 8', () => { + Assert.IsFalse(Format.IsIdnEmail('user.name@.example.com')) + }) + it('Should validate IdnEmail 9', () => { + Assert.IsFalse(Format.IsIdnEmail('user.name@example..com')) + }) + it('Should validate IdnEmail 10', () => { + Assert.IsTrue(Format.IsIdnEmail('user_name@example.com')) + }) + it('Should validate IdnEmail 11', () => { + Assert.IsFalse(Format.IsIdnEmail('user@name@example.com')) + }) + it('Should validate IdnEmail 12', () => { + Assert.IsTrue(Format.IsIdnEmail('user-name@example.com')) + }) + it('Should validate IdnEmail 13', () => { + Assert.IsFalse(Format.IsIdnEmail('user@name@example.com')) + }) + it('Should validate IdnEmail 14', () => { + Assert.IsTrue(Format.IsIdnEmail('user.name@example.com')) + }) + it('Should validate IdnEmail 15', () => { + Assert.IsFalse(Format.IsIdnEmail('user.name@.example.com')) + }) + it('Should validate IdnEmail 16', () => { + Assert.IsTrue(Format.IsIdnEmail('user.name@example.com')) + }) + it('Should validate IdnEmail 17', () => { + Assert.IsFalse(Format.IsIdnEmail('user.name@example..com')) + }) + it('Should validate IdnEmail 18', () => { + Assert.IsTrue(Format.IsIdnEmail('user.name@example.com')) + }) + it('Should validate IdnEmail 19', () => { + Assert.IsFalse(Format.IsIdnEmail('user.name@.example.com')) + }) + it('Should validate IdnEmail 20', () => { + Assert.IsTrue(Format.IsIdnEmail('user.name@example.com')) + }) + it('Should validate IdnEmail 21', () => { + Assert.IsFalse(Format.IsIdnEmail('user.name@example..com')) + }) + it('Should validate IdnEmail 22', () => { + Assert.IsTrue(Format.IsIdnEmail('user.name@example.com')) + }) + it('Should validate IdnEmail 23', () => { + Assert.IsFalse(Format.IsIdnEmail('user.name@.example.com')) + }) + it('Should validate IdnEmail 24', () => { + Assert.IsTrue(Format.IsIdnEmail('user.name@example.com')) + }) + it('Should validate IdnEmail 25', () => { + Assert.IsFalse(Format.IsIdnEmail('user.name@example..com')) + }) + it('Should validate IdnEmail 26', () => { + Assert.IsTrue(Format.IsIdnEmail('用户@domain.com')) + }) + it('Should validate IdnEmail 27', () => { + Assert.IsTrue(Format.IsIdnEmail('अजय@डाटा.भारत')) + }) + it('Should validate IdnEmail 28', () => { + Assert.IsTrue(Format.IsIdnEmail('квіточка@пошта.укр')) + }) + it('Should validate IdnEmail 29', () => { + Assert.IsTrue(Format.IsIdnEmail('θσερ@εχαμπλε.ψομ')) + }) + it('Should validate IdnEmail 30', () => { + Assert.IsTrue(Format.IsIdnEmail('Dörte@Sörensen.example.com')) + }) +}) diff --git a/test/runtime/format/index.ts b/test/runtime/format/index.ts new file mode 100644 index 000000000..ab47d1591 --- /dev/null +++ b/test/runtime/format/index.ts @@ -0,0 +1,5 @@ +import './date-time' +import './date' +import './duration' +import './email' +import './idn-email' diff --git a/test/runtime/index.ts b/test/runtime/index.ts index ec19724e0..d0dfbb517 100644 --- a/test/runtime/index.ts +++ b/test/runtime/index.ts @@ -8,6 +8,7 @@ TypeSystemPolicy.InstanceMode = 'freeze' import './compiler/index' import './compiler-ajv/index' import './errors/index' +import './format/index' import './syntax/index' import './system/index' import './type/index' diff --git a/test/runtime/system/type/format.ts b/test/runtime/system/type/format.ts index bac7c9160..9b0419139 100644 --- a/test/runtime/system/type/format.ts +++ b/test/runtime/system/type/format.ts @@ -11,9 +11,4 @@ describe('system/TypeSystem/Format', () => { Fail(T, 'bar') FormatRegistry.Delete('Foo') }) - it('Should throw if registering the same type twice', () => { - TypeSystem.Format('Foo', () => true) - Assert.Throws(() => TypeSystem.Format('Foo', () => true)) - FormatRegistry.Delete('Foo') - }) }) diff --git a/test/runtime/system/type/type.ts b/test/runtime/system/type/type.ts index 86288f595..5e4d617bb 100644 --- a/test/runtime/system/type/type.ts +++ b/test/runtime/system/type/type.ts @@ -14,9 +14,4 @@ describe('system/TypeSystem/Type', () => { Fail(T, 'bar') TypeRegistry.Delete('Foo') }) - it('Should throw if registering the same type twice', () => { - TypeSystem.Type('Foo', () => true) - Assert.Throws(() => TypeSystem.Type('Foo', () => true)) - TypeRegistry.Delete('Foo') - }) }) diff --git a/tsconfig.json b/tsconfig.json index 34a4b8f21..9f8ce7396 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -8,6 +8,7 @@ "paths": { "@sinclair/typebox/compiler": ["src/compiler/index.ts"], "@sinclair/typebox/errors": ["src/errors/index.ts"], + "@sinclair/typebox/format": ["src/format/index.ts"], "@sinclair/typebox/syntax": ["src/syntax/index.ts"], "@sinclair/typebox/system": ["src/system/index.ts"], "@sinclair/typebox/type": ["src/type/index.ts"],