1
1
import { NodeTypes } from '@intlify/message-compiler'
2
+ import { hasOwn , isNumber } from '@intlify/shared'
2
3
3
4
import type {
4
- Node ,
5
- TextNode ,
6
- LiteralNode ,
5
+ LinkedModifierNode ,
6
+ LinkedNode ,
7
7
ListNode ,
8
8
MessageNode ,
9
9
NamedNode ,
10
- LinkedNode ,
11
- LinkedKeyNode ,
12
- LinkedModifierNode ,
10
+ Node ,
13
11
PluralNode ,
14
12
ResourceNode
15
13
} from '@intlify/message-compiler'
16
14
import type {
17
15
MessageContext ,
18
16
MessageFunction ,
19
- MessageType ,
20
- MessageFunctionReturn
17
+ MessageFunctionReturn ,
18
+ MessageType
21
19
} from './runtime'
22
20
23
21
export function format < Message = string > (
@@ -28,14 +26,18 @@ export function format<Message = string>(
28
26
return msg
29
27
}
30
28
31
- function formatParts < Message = string > (
29
+ export function formatParts < Message = string > (
32
30
ctx : MessageContext < Message > ,
33
31
ast : ResourceNode
34
32
) : 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 ) {
37
39
const plural = body as PluralNode
38
- const cases = plural . c || plural . cases
40
+ const cases = resolveCases ( plural )
39
41
return ctx . plural (
40
42
cases . reduce (
41
43
( messages , c ) =>
@@ -51,64 +53,170 @@ function formatParts<Message = string>(
51
53
}
52
54
}
53
55
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 > (
55
73
ctx : MessageContext < Message > ,
56
74
node : MessageNode
57
75
) : MessageFunctionReturn < Message > {
58
- const _static = node . s || node . static
59
- if ( _static ) {
76
+ const static_ = resolveStatic ( node )
77
+ if ( static_ != null ) {
60
78
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 > [ ] )
63
81
} else {
64
- const messages = ( node . i || node . items ) . reduce (
82
+ const messages = resolveItems ( node ) . reduce (
65
83
( acm , c ) => [ ...acm , formatMessagePart ( ctx , c ) ] ,
66
84
[ ] as MessageType < Message > [ ]
67
85
)
68
86
return ctx . normalize ( messages ) as MessageFunctionReturn < Message >
69
87
}
70
88
}
71
89
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 > (
73
112
ctx : MessageContext < Message > ,
74
113
node : Node
75
114
) : MessageType < Message > {
76
- const type = node . t || node . type
115
+ const type = resolveType ( node )
77
116
switch ( type ) {
78
117
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 )
81
119
}
82
120
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 )
85
122
}
86
123
case NodeTypes . Named : {
87
124
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 )
89
132
}
90
133
case NodeTypes . List : {
91
134
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 )
93
142
}
94
143
case NodeTypes . Linked : {
95
144
const linked = node as LinkedNode
96
- const modifier = linked . m || linked . modifier
145
+ const modifier = resolveLinkedModifier ( linked )
146
+ const key = resolveLinkedKey ( linked )
97
147
return ctx . linked (
98
- formatMessagePart ( ctx , linked . k || linked . key ) as string ,
148
+ formatMessagePart ( ctx , key ! ) as string ,
99
149
modifier ? ( formatMessagePart ( ctx , modifier ) as string ) : undefined ,
100
150
ctx . type
101
151
)
102
152
}
103
153
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 )
106
155
}
107
156
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 )
110
158
}
111
159
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 )
113
201
}
114
202
}
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