1- import { describe , expect , it } from "vitest" ;
1+ import { describe , expect , expectTypeOf , it } from "vitest" ;
22import { ValidationError } from "./error" ;
33import { v } from "./index" ;
44import {
55 asType ,
66 attrsOf ,
7+ isNoInput ,
8+ isNoOutput ,
79 omitFields ,
810 parseFields ,
911 rejectFields ,
12+ type SchemaInputOf ,
13+ type SchemaOutputOf ,
1014 validate ,
1115 withAttrs ,
1216} from "./schema" ;
@@ -16,10 +20,10 @@ describe("schema $attrs", () => {
1620 const base = v . string ( ) ;
1721 const once = withAttrs ( base , "db" , { unique : true } ) ;
1822 const twice = withAttrs ( once , "db" , { index : true } ) ;
19- const both = withAttrs ( twice , "http" , { serverOnly : true } ) ;
23+ const both = withAttrs ( twice , "http" , { tag : true } ) ;
2024
2125 expect ( attrsOf ( twice , "db" ) ) . toEqual ( { unique : true , index : true } ) ;
22- expect ( attrsOf ( both , "http" ) ) . toEqual ( { serverOnly : true } ) ;
26+ expect ( attrsOf ( both , "http" ) ) . toEqual ( { tag : true } ) ;
2327 expect ( attrsOf ( both ) ?. db ) . toEqual ( { unique : true , index : true } ) ;
2428 // Original untouched.
2529 expect ( attrsOf ( base ) ) . toBeUndefined ( ) ;
@@ -44,11 +48,11 @@ describe("schema $attrs", () => {
4448 default : null ,
4549 schema : v . object ( { id : v . string ( ) } ) ,
4650 } ) ;
47- const marked = withAttrs ( user , "http" , { serverOnly : true } ) ;
51+ const marked = withAttrs ( user , "http" , { tag : true } ) ;
4852 expect ( marked . $var ) . toBe ( true ) ;
4953 expect ( marked . name ) . toBe ( "attr_user" ) ;
5054 expect ( typeof marked . customize ) . toBe ( "function" ) ;
51- expect ( attrsOf ( marked , "http" ) ) . toEqual ( { serverOnly : true } ) ;
55+ expect ( attrsOf ( marked , "http" ) ) . toEqual ( { tag : true } ) ;
5256 // Field schema on the var is untouched.
5357 expect ( attrsOf ( marked . schema ) ) . toBeUndefined ( ) ;
5458 } ) ;
@@ -58,27 +62,85 @@ describe("schema $attrs", () => {
5862 default : null ,
5963 schema : v . object ( { id : v . string ( ) } ) ,
6064 } ) ;
61- const marked = withAttrs ( user , "http" , { serverOnly : true } ) ;
65+ const marked = withAttrs ( user , "http" , { tag : true } ) ;
6266 const widened = marked . customize ( {
6367 schema : ( c ) => c . add ( { role : c . string ( ) } ) ,
6468 } ) ;
6569 expect ( widened . $var ) . toBe ( true ) ;
66- expect ( attrsOf ( widened , "http" ) ) . toEqual ( { serverOnly : true } ) ;
70+ expect ( attrsOf ( widened , "http" ) ) . toEqual ( { tag : true } ) ;
6771 expect (
6872 ( widened . schema as { shape : Record < string , unknown > } ) . shape . role ,
6973 ) . toBeDefined ( ) ;
7074 } ) ;
7175} ) ;
7276
77+ describe ( "v.noInput / v.noOutput and schema views" , ( ) => {
78+ const user = v . var ( "attr_views_user" , {
79+ schema : v . object ( {
80+ id : v . noInput ( v . string ( ) ) ,
81+ email : v . string ( ) ,
82+ passwordHash : v . noOutput ( v . string ( ) ) ,
83+ } ) ,
84+ } ) ;
85+
86+ it ( "marks $attrs.v" , ( ) => {
87+ expect ( attrsOf ( v . noInput ( v . string ( ) ) , "v" ) ) . toEqual ( { noInput : true } ) ;
88+ expect ( attrsOf ( v . noOutput ( v . string ( ) ) , "v" ) ) . toEqual ( { noOutput : true } ) ;
89+ expect ( isNoInput ( v . noInput ( v . string ( ) ) ) ) . toBe ( true ) ;
90+ expect ( isNoOutput ( v . noOutput ( v . string ( ) ) ) ) . toBe ( true ) ;
91+ } ) ;
92+
93+ it ( "var.input and var.output project nested fields" , ( ) => {
94+ const inputShape = asType ( user . input . schema ) . shape as Record <
95+ string ,
96+ unknown
97+ > ;
98+ const outputShape = asType ( user . output . schema ) . shape as Record <
99+ string ,
100+ unknown
101+ > ;
102+ expect ( Object . keys ( inputShape ) . sort ( ) ) . toEqual ( [ "email" , "passwordHash" ] ) ;
103+ expect ( Object . keys ( outputShape ) . sort ( ) ) . toEqual ( [ "email" , "id" ] ) ;
104+ } ) ;
105+
106+ it ( "type .input / .output match omitFields" , ( ) => {
107+ const schema = v . object ( {
108+ id : v . noInput ( v . string ( ) ) ,
109+ email : v . string ( ) ,
110+ secret : v . noOutput ( v . string ( ) ) ,
111+ } ) ;
112+ expect ( Object . keys ( asType ( schema . input ) . shape as object ) . sort ( ) ) . toEqual ( [
113+ "email" ,
114+ "secret" ,
115+ ] ) ;
116+ expect ( Object . keys ( asType ( schema . output ) . shape as object ) . sort ( ) ) . toEqual ( [
117+ "email" ,
118+ "id" ,
119+ ] ) ;
120+ } ) ;
121+
122+ it ( "SchemaInputOf / SchemaOutputOf drop gated keys" , ( ) => {
123+ type Row = {
124+ id : ReturnType < typeof v . noInput < ReturnType < typeof v . string > > > ;
125+ email : ReturnType < typeof v . string > ;
126+ passwordHash : ReturnType < typeof v . noOutput < ReturnType < typeof v . string > > > ;
127+ } ;
128+ expectTypeOf < keyof SchemaInputOf < Row > > ( ) . toEqualTypeOf <
129+ "email" | "passwordHash"
130+ > ( ) ;
131+ expectTypeOf < keyof SchemaOutputOf < Row > > ( ) . toEqualTypeOf < "id" | "email" > ( ) ;
132+ } ) ;
133+ } ) ;
134+
73135describe ( "omitFields / rejectFields / parseFields" , ( ) => {
74136 const dropMarked = ( schema : unknown ) =>
75- attrsOf ( schema , "http " ) ?. readonly === true ;
137+ attrsOf ( schema , "v " ) ?. noInput === true ;
76138 const shape = v . object ( {
77139 id : v . string ( ) ,
78- role : withAttrs ( v . string ( ) , "http" , { readonly : true } ) ,
140+ role : v . noInput ( v . string ( ) ) ,
79141 meta : v . object ( {
80142 note : v . string ( ) ,
81- secret : withAttrs ( v . string ( ) , "http" , { readonly : true } ) ,
143+ secret : v . noInput ( v . string ( ) ) ,
82144 } ) ,
83145 } ) ;
84146
0 commit comments