@@ -24,14 +24,19 @@ export interface MessageDateTimePart extends MessageExpressionPart {
2424 parts : Intl . DateTimeFormatPart [ ] ;
2525}
2626
27- const localeOptions = [
28- 'calendar' ,
29- 'localeMatcher' ,
30- 'hour12' ,
31- 'hourCycle' ,
32- 'numberingSystem' ,
33- 'timeZone'
34- ] ;
27+ const styleOptions = new Set ( [ 'dateStyle' , 'timeStyle' ] ) ;
28+ const fieldOptions = new Set ( [
29+ 'weekday' ,
30+ 'era' ,
31+ 'year' ,
32+ 'month' ,
33+ 'day' ,
34+ 'hour' ,
35+ 'minute' ,
36+ 'second' ,
37+ 'fractionalSecondDigits' ,
38+ 'timeZoneName'
39+ ] ) ;
3540
3641/**
3742 * `datetime` accepts a Date, number or string as its input
@@ -46,6 +51,8 @@ export const datetime = (
4651 input ?: unknown
4752) : MessageDateTime =>
4853 dateTimeImplementation ( ctx , input , res => {
54+ let hasStyle = false ;
55+ let hasFields = false ;
4956 for ( const [ name , value ] of Object . entries ( options ) ) {
5057 if ( value === undefined ) continue ;
5158 try {
@@ -54,23 +61,27 @@ export const datetime = (
5461 break ;
5562 case 'fractionalSecondDigits' :
5663 res [ name ] = asPositiveInteger ( value ) ;
64+ hasFields = true ;
5765 break ;
5866 case 'hour12' :
5967 res [ name ] = asBoolean ( value ) ;
6068 break ;
6169 default :
6270 res [ name ] = asString ( value ) ;
71+ if ( ! hasStyle && styleOptions . has ( name ) ) hasStyle = true ;
72+ if ( ! hasFields && fieldOptions . has ( name ) ) hasFields = true ;
6373 }
6474 } catch {
65- const msg = `Value ${ value } is not valid for :datetime option ${ name } ` ;
75+ const msg = `Value ${ value } is not valid for :datetime ${ name } option ` ;
6676 ctx . onError ( new MessageResolutionError ( 'bad-option' , msg , ctx . source ) ) ;
6777 }
6878 }
69-
70- // Set defaults if localeMatcher is the only option
71- if ( Object . keys ( res ) . length <= 1 ) {
79+ if ( ! hasStyle && ! hasFields ) {
7280 res . dateStyle = 'medium' ;
7381 res . timeStyle = 'short' ;
82+ } else if ( hasStyle && hasFields ) {
83+ const msg = 'Style and field options cannot be both set for :datetime' ;
84+ throw new MessageResolutionError ( 'bad-option' , msg , ctx . source ) ;
7485 }
7586 } ) ;
7687
@@ -86,16 +97,30 @@ export const date = (
8697 input ?: unknown
8798) : MessageDateTime =>
8899 dateTimeImplementation ( ctx , input , res => {
89- const ds = options . style ?? res . dateStyle ?? 'medium' ;
90100 for ( const name of Object . keys ( res ) ) {
91- if ( ! localeOptions . includes ( name ) ) delete res [ name ] ;
101+ if ( styleOptions . has ( name ) || fieldOptions . has ( name ) ) delete res [ name ] ;
92102 }
93- try {
94- res . dateStyle = asString ( ds ) ;
95- } catch {
96- const msg = `Value ${ ds } is not valid for :date style option` ;
97- throw new MessageResolutionError ( 'bad-option' , msg , ctx . source ) ;
103+ for ( const [ name , value ] of Object . entries ( options ) ) {
104+ if ( value === undefined ) continue ;
105+ try {
106+ switch ( name ) {
107+ case 'style' :
108+ res . dateStyle = asString ( value ) ;
109+ break ;
110+ case 'hour12' :
111+ res [ name ] = asBoolean ( value ) ;
112+ break ;
113+ case 'calendar' :
114+ case 'numberingSystem' :
115+ case 'timeZone' :
116+ res [ name ] = asString ( value ) ;
117+ }
118+ } catch {
119+ const msg = `Value ${ value } is not valid for :date ${ name } option` ;
120+ ctx . onError ( new MessageResolutionError ( 'bad-option' , msg , ctx . source ) ) ;
121+ }
98122 }
123+ res . dateStyle ??= 'medium' ;
99124 } ) ;
100125
101126/**
@@ -110,16 +135,30 @@ export const time = (
110135 input ?: unknown
111136) : MessageDateTime =>
112137 dateTimeImplementation ( ctx , input , res => {
113- const ts = options . style ?? res . timeStyle ?? 'short' ;
114138 for ( const name of Object . keys ( res ) ) {
115- if ( ! localeOptions . includes ( name ) ) delete res [ name ] ;
139+ if ( styleOptions . has ( name ) || fieldOptions . has ( name ) ) delete res [ name ] ;
116140 }
117- try {
118- res . timeStyle = asString ( ts ) ;
119- } catch {
120- const msg = `Value ${ ts } is not valid for :time style option` ;
121- throw new MessageResolutionError ( 'bad-option' , msg , ctx . source ) ;
141+ for ( const [ name , value ] of Object . entries ( options ) ) {
142+ if ( value === undefined ) continue ;
143+ try {
144+ switch ( name ) {
145+ case 'style' :
146+ res . timeStyle = asString ( value ) ;
147+ break ;
148+ case 'hour12' :
149+ res [ name ] = asBoolean ( value ) ;
150+ break ;
151+ case 'calendar' :
152+ case 'numberingSystem' :
153+ case 'timeZone' :
154+ res [ name ] = asString ( value ) ;
155+ }
156+ } catch {
157+ const msg = `Value ${ value } is not valid for :time ${ name } option` ;
158+ ctx . onError ( new MessageResolutionError ( 'bad-option' , msg , ctx . source ) ) ;
159+ }
122160 }
161+ res . timeStyle ??= 'short' ;
123162 } ) ;
124163
125164function dateTimeImplementation (
0 commit comments