11import { NodeTypes } from '@intlify/message-compiler'
2+ import { hasOwn , isNumber } from '@intlify/shared'
23
34import type {
4- Node ,
5- TextNode ,
6- LiteralNode ,
5+ LinkedModifierNode ,
6+ LinkedNode ,
77 ListNode ,
88 MessageNode ,
99 NamedNode ,
10- LinkedNode ,
11- LinkedKeyNode ,
12- LinkedModifierNode ,
10+ Node ,
1311 PluralNode ,
1412 ResourceNode
1513} from '@intlify/message-compiler'
1614import type {
1715 MessageContext ,
1816 MessageFunction ,
19- MessageType ,
20- MessageFunctionReturn
17+ MessageFunctionReturn ,
18+ MessageType
2119} from './runtime'
2220
2321export function format < Message = string > (
@@ -28,14 +26,18 @@ export function format<Message = string>(
2826 return msg
2927}
3028
31- function formatParts < Message = string > (
29+ export function formatParts < Message = string > (
3230 ctx : MessageContext < Message > ,
3331 ast : ResourceNode
3432) : MessageFunctionReturn < Message > {
35- const body = ast . b || ast . body
36- if ( ( body . t || body . type ) === NodeTypes . Plural ) {
33+ const body = resolveBody ( ast )
34+ if ( body == null ) {
35+ throw createUnhandleNodeError ( NodeTypes . Resource )
36+ }
37+ const type = resolveType ( body )
38+ if ( type === NodeTypes . Plural ) {
3739 const plural = body as PluralNode
38- const cases = plural . c || plural . cases
40+ const cases = resolveCases ( plural )
3941 return ctx . plural (
4042 cases . reduce (
4143 ( messages , c ) =>
@@ -51,64 +53,170 @@ function formatParts<Message = string>(
5153 }
5254}
5355
54- function formatMessageParts < Message = string > (
56+ const PROPS_BODY = [ 'b' , 'body' ]
57+
58+ function resolveBody ( node : ResourceNode ) {
59+ return resolveProps < MessageNode | PluralNode > ( node , PROPS_BODY )
60+ }
61+
62+ const PROPS_CASES = [ 'c' , 'cases' ]
63+
64+ function resolveCases ( node : PluralNode ) {
65+ return resolveProps < PluralNode [ 'cases' ] , PluralNode [ 'cases' ] > (
66+ node ,
67+ PROPS_CASES ,
68+ [ ]
69+ )
70+ }
71+
72+ export function formatMessageParts < Message = string > (
5573 ctx : MessageContext < Message > ,
5674 node : MessageNode
5775) : MessageFunctionReturn < Message > {
58- const _static = node . s || node . static
59- if ( _static ) {
76+ const static_ = resolveStatic ( node )
77+ if ( static_ != null ) {
6078 return ctx . type === 'text'
61- ? ( _static as MessageFunctionReturn < Message > )
62- : ctx . normalize ( [ _static ] as MessageType < Message > [ ] )
79+ ? ( static_ as MessageFunctionReturn < Message > )
80+ : ctx . normalize ( [ static_ ] as MessageType < Message > [ ] )
6381 } else {
64- const messages = ( node . i || node . items ) . reduce (
82+ const messages = resolveItems ( node ) . reduce (
6583 ( acm , c ) => [ ...acm , formatMessagePart ( ctx , c ) ] ,
6684 [ ] as MessageType < Message > [ ]
6785 )
6886 return ctx . normalize ( messages ) as MessageFunctionReturn < Message >
6987 }
7088}
7189
72- function formatMessagePart < Message = string > (
90+ const PROPS_STATIC = [ 's' , 'static' ]
91+
92+ function resolveStatic ( node : MessageNode ) {
93+ return resolveProps ( node , PROPS_STATIC )
94+ }
95+
96+ const PROPS_ITEMS = [ 'i' , 'items' ]
97+
98+ function resolveItems ( node : MessageNode ) {
99+ return resolveProps < MessageNode [ 'items' ] , MessageNode [ 'items' ] > (
100+ node ,
101+ PROPS_ITEMS ,
102+ [ ]
103+ )
104+ }
105+
106+ type NodeValue < Message > = {
107+ v ?: MessageType < Message >
108+ value ?: MessageType < Message >
109+ }
110+
111+ export function formatMessagePart < Message = string > (
73112 ctx : MessageContext < Message > ,
74113 node : Node
75114) : MessageType < Message > {
76- const type = node . t || node . type
115+ const type = resolveType ( node )
77116 switch ( type ) {
78117 case NodeTypes . Text : {
79- const text = node as TextNode
80- return ( text . v || text . value ) as MessageType < Message >
118+ return resolveValue < Message > ( node as NodeValue < Message > , type )
81119 }
82120 case NodeTypes . Literal : {
83- const literal = node as LiteralNode
84- return ( literal . v || literal . value ) as MessageType < Message >
121+ return resolveValue < Message > ( node as NodeValue < Message > , type )
85122 }
86123 case NodeTypes . Named : {
87124 const named = node as NamedNode
88- return ctx . interpolate ( ctx . named ( named . k || named . key ) )
125+ if ( hasOwn ( named , 'k' ) && named . k ) {
126+ return ctx . interpolate ( ctx . named ( named . k ) )
127+ }
128+ if ( hasOwn ( named , 'key' ) && named . key ) {
129+ return ctx . interpolate ( ctx . named ( named . key ) )
130+ }
131+ throw createUnhandleNodeError ( type )
89132 }
90133 case NodeTypes . List : {
91134 const list = node as ListNode
92- return ctx . interpolate ( ctx . list ( list . i != null ? list . i : list . index ) )
135+ if ( hasOwn ( list , 'i' ) && isNumber ( list . i ) ) {
136+ return ctx . interpolate ( ctx . list ( list . i ) )
137+ }
138+ if ( hasOwn ( list , 'index' ) && isNumber ( list . index ) ) {
139+ return ctx . interpolate ( ctx . list ( list . index ) )
140+ }
141+ throw createUnhandleNodeError ( type )
93142 }
94143 case NodeTypes . Linked : {
95144 const linked = node as LinkedNode
96- const modifier = linked . m || linked . modifier
145+ const modifier = resolveLinkedModifier ( linked )
146+ const key = resolveLinkedKey ( linked )
97147 return ctx . linked (
98- formatMessagePart ( ctx , linked . k || linked . key ) as string ,
148+ formatMessagePart ( ctx , key ! ) as string ,
99149 modifier ? ( formatMessagePart ( ctx , modifier ) as string ) : undefined ,
100150 ctx . type
101151 )
102152 }
103153 case NodeTypes . LinkedKey : {
104- const linkedKey = node as LinkedKeyNode
105- return ( linkedKey . v || linkedKey . value ) as MessageType < Message >
154+ return resolveValue < Message > ( node as NodeValue < Message > , type )
106155 }
107156 case NodeTypes . LinkedModifier : {
108- const linkedModifier = node as LinkedModifierNode
109- return ( linkedModifier . v || linkedModifier . value ) as MessageType < Message >
157+ return resolveValue < Message > ( node as NodeValue < Message > , type )
110158 }
111159 default :
112- throw new Error ( `unhandled node type on format message part: ${ type } ` )
160+ throw new Error ( `unhandled node on format message part: ${ type } ` )
161+ }
162+ }
163+
164+ const PROPS_TYPE = [ 't' , 'type' ]
165+
166+ export function resolveType ( node : Node ) {
167+ return resolveProps < NodeTypes > ( node , PROPS_TYPE )
168+ }
169+
170+ const PROPS_VALUE = [ 'v' , 'value' ]
171+
172+ function resolveValue < Message = string > (
173+ node : { v ?: MessageType < Message > ; value ?: MessageType < Message > } ,
174+ type : NodeTypes
175+ ) : MessageType < Message > {
176+ const resolved = resolveProps < Message > (
177+ node as Node ,
178+ PROPS_VALUE
179+ ) as MessageType < Message >
180+ if ( resolved ) {
181+ return resolved
182+ } else {
183+ throw createUnhandleNodeError ( type )
184+ }
185+ }
186+
187+ const PROPS_MODIFIER = [ 'm' , 'modifier' ]
188+
189+ function resolveLinkedModifier ( node : LinkedNode ) {
190+ return resolveProps < LinkedModifierNode > ( node , PROPS_MODIFIER )
191+ }
192+
193+ const PROPS_KEY = [ 'k' , 'key' ]
194+
195+ function resolveLinkedKey ( node : LinkedNode ) {
196+ const resolved = resolveProps < LinkedNode [ 'key' ] > ( node , PROPS_KEY )
197+ if ( resolved ) {
198+ return resolved
199+ } else {
200+ throw createUnhandleNodeError ( NodeTypes . Linked )
113201 }
114202}
203+
204+ function resolveProps < T = string , Default = undefined > (
205+ node : Node ,
206+ props : string [ ] ,
207+ defaultValue ?: Default
208+ ) : T | Default {
209+ for ( let i = 0 ; i < props . length ; i ++ ) {
210+ const prop = props [ i ]
211+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
212+ if ( hasOwn ( node , prop ) && ( node as any ) [ prop ] != null ) {
213+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
214+ return ( node as any ) [ prop ] as T
215+ }
216+ }
217+ return defaultValue as Default
218+ }
219+
220+ function createUnhandleNodeError ( type : NodeTypes ) {
221+ return new Error ( `unhandled node type: ${ type } ` )
222+ }
0 commit comments