UNPKG

3.56 kBJavaScriptView Raw
1// @flow
2'use strict'
3
4/**
5 * This function runs through the message looking for tokens. When it finds a
6 * token matching a wrapper, it will replace the token with the wrapper, keeping
7 * any children intact.
8 */
9module.exports = function formatChildren (
10 applyChildren/*: (string, any, ?mixed[]) => any */,
11 message/*: string */,
12 wrappers/*: Object */
13) {
14 if (process.env.NODE_ENV !== 'production' && typeof console === 'object') {
15 console.warn(
16 'Warning: formatChildren() is deprecated. Use formatMessage.rich() instead.\n' +
17 'https://github.com/format-message/format-message/tree/master/packages/format-message' +
18 '#formatmessagerichpattern-args-locales'
19 )
20 }
21 wrappers = wrappers || []
22
23 // at least one word character (letter, digit, or _) surrounded by < >
24 const wrappingToken = /<(\w+)>/g
25
26 // at least one word character (letter, digit, or _) surrounded by < />
27 const selfClosingToken = /<(\w+)\/>/g
28
29 const results = []
30 let match, token, i, split, result
31
32 // check that wrapping tokens are properly nested
33 const tokens = []
34 while ((match = wrappingToken.exec(message)) !== null) {
35 const key = match[1]
36 token = {
37 key: key,
38 start: match.index,
39 end: message.indexOf('</' + key + '>')
40 }
41
42 tokens.forEach(function (t) {
43 // a token is properly nested if its start tag is within another tokens
44 // start and end tag and if its end tag is inside the other tokens end tag
45 if (token.start > t.start && token.start < t.end && token.end > t.end) {
46 throw new Error('Wrapping tags not properly nested in "' + message + '"')
47 }
48 })
49
50 tokens.push(token)
51 }
52
53 // replace wrapper tokens
54 for (i = tokens.length - 1; i >= 0; --i) {
55 token = tokens[i]
56
57 if (wrappers[token.key]) {
58 // get the text in between the token
59 const start = message.lastIndexOf('<' + token.key + '>')
60 const end = message.lastIndexOf('</' + token.key + '>')
61 const value = message.substring(start + token.key.length + 2, end)
62
63 const children = []
64
65 // add all children between the token, replacing any self closing tokens
66 // (which will be the odd index of the split)
67 split = value.split(selfClosingToken)
68 for (let j = 0; j < split.length; ++j) {
69 result = split[j]
70
71 if (j % 2 === 1 && wrappers[result]) {
72 children.push(wrappers[result])
73 } else if (result) {
74 children.push(result)
75 }
76 }
77
78 // replace the wrapper token with a self closing token in the message to
79 // signify the replacement has been done. this also will allow a parent
80 // token to add this token as a child
81 wrappers['__' + i + '__'] = applyChildren(token.key, wrappers[token.key], children)
82
83 const left = message.substring(0, start)
84 const right = message.substring(end + token.key.length + 3)
85 message = left + '<__' + i + '__/>' + right
86 }
87 }
88
89 // replace self closing tokens
90 split = message.split(selfClosingToken)
91 for (i = 0; i < split.length; ++i) {
92 result = split[i]
93
94 if (i % 2 === 1 && wrappers[result]) {
95 // don't call applyChildren to a wrapped tag replacement as it was already done
96 if (result.indexOf('__') === 0 && result.lastIndexOf('__') === result.length - 2) {
97 results.push(wrappers[result])
98 } else {
99 results.push(applyChildren(result, wrappers[result], null))
100 }
101 } else if (result) {
102 results.push(result)
103 }
104 }
105
106 return results.length === 1 ? results[0] : results
107}