• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (c) 2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License")
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16const content = require('./content')
17const data = require('./data')
18const { DEVICE_LEVEL } = require('../lite/lite-enum')
19const card = process.env.DEVICE_LEVEL === DEVICE_LEVEL.CARD
20const REG_CARD_ARRAY = /(\['.+?'\])|(\[".+?"\])/g
21const connectContent = `+ decodeURI('${encodeURI('')}') +`;
22
23/**
24 * Check if there is data binding.
25 * @param {Object} initValue Hml text token information.
26 * @param {Object} functionFlag Hml text token information.
27 * @return {String} Compiled data binding
28 */
29function transExp(initValue, functionFlag, isValue, out, nodeLoc) {
30  let value = initValue.toString().trim()
31  const hasExpFlag = isExp(value)
32  if (hasExpFlag) {
33    value = parseExp(value, functionFlag, isValue, out, nodeLoc)
34  }
35  return value
36}
37/**
38 * parse data binding.
39 * @param {Object} value Hml text token information.
40 * @param {Object} functionFlag Hml text token information.
41 * @return {String} Compiled data binding
42 */
43function parseExp(value, functionFlag, isValue, out, nodeLoc) {
44  const textArray = data.parseText(value)
45  const explist = []
46  for (let i = 0; i < textArray.length; i++) {
47    const exp = textArray[i]
48    let transValue
49    if (exp.tag) {
50      if (card) {
51        checkCard(exp.value, out, nodeLoc)
52      }
53      transValue = card ? `{{${transCardArray(exp.value)}}}` : content.parseExpression(exp.value)
54        if (textArray.length !== 1 && !card) {
55          transValue = `(${transValue})`
56        }
57    } else {
58      transValue = card ? exp.value : `decodeURI('${encodeURI(exp.value).replace(/\'/g, '%27')}')`
59    }
60    explist.push(transValue)
61  }
62  if (card && checkCardVersionLimit() && isValue) {
63    if (explist.length > 1) {
64      out.log.push({
65        line: nodeLoc.line || 1,
66        column: nodeLoc.col || 1,
67        reason: 'ERROR: Variable concatenation is not supported currently.',
68      })
69    }
70  }
71  let func = explist.join(card ? '' : connectContent);
72  if (functionFlag !== false && !card) {
73    func = eval('(function () {return ' + func + '})')
74  }
75  func = card && textArray.length > 1 ? '$f(' + func + ')' : func
76
77  return func
78}
79
80/**
81 * Check if there is data binding in the list.
82 * @param {String} initValue Hml text token information.
83 * @return {String} Compiled data binding in list
84 */
85function transExpForList(initValue) {
86  let value = initValue.toString().trim()
87  const hasExpListFlag = containExp(value)
88  if (hasExpListFlag) {
89    value = parseExpList(value)
90  }
91  return value
92}
93/**
94 * parse data binding in list.
95 * @param {String} value Hml text token information.
96 * @return {String} Compiled data binding in list
97 */
98function parseExpList(value) {
99  const exprMatch = value.match(/{{{([\s\S]+?)}}}|{{([\s\S]+?)}}/g)
100  const exprArray = value.replace(/{{{([\s\S]+?)}}}|{{([\s\S]+?)}}/g, '&e').split(/\s+/)
101  let n = 0
102  const result = []
103  exprArray.forEach((item)=>{
104    if (item.indexOf('&e') >= 0) {
105      while (item.indexOf('&e') >= 0) {
106        item = item.replace('&e', exprMatch[n++])
107      }
108      const textArray = data.parseText(item)
109      const exprlist = []
110      if (textArray) {
111        textArray.forEach(function(text) {
112          const transValue = text.tag ?
113            card ? `{{${text.value}}}` : content.parseExpression(text.value) :
114            card ? text.value : `'${text.value}'`
115          exprlist.push(transValue)
116        })
117        result.push(exprlist.join('+'))
118      }
119    } else {
120      const value = card ? item : `'${item}'`
121      result.push(value)
122    }
123  })
124
125  return card ? result : "(function () {return [" + result.join(", ") + "]})"
126}
127
128/**
129 * Regexp determine whether there is data binding.
130 * @param {String} value expression value.
131 * @return {Boolean} Test results
132 */
133function isExp(value) {
134  const REGEXP_DATABIND = /{{{([\s\S]+?)}}}|{{([\s\S]+?)}}/
135  return REGEXP_DATABIND.test(value)
136}
137
138/**
139 * Global regexp determine whether there is data binding.
140 * @param {String} value expression value.
141 * @return {Boolean} Test results
142 */
143function containExp(value) {
144  const REGEXP_DATABIND_ALL = /{{{([\s\S]+?)}}}|{{([\s\S]+?)}}/g
145  return REGEXP_DATABIND_ALL.test(value)
146}
147
148/**
149 * Replace value on match.
150 * @param {String} value expression value.
151 * @return {String} The result after replacement
152 */
153function removeAllExpFix(value) {
154  const REGEXP_PRE_DATABIND = /\{\{\{?|\}\}\}?/g
155  return containExp(value) ? value.replace(REGEXP_PRE_DATABIND, '') : value
156}
157
158/**
159 * Change array format in card
160 * @param {String} value Array in card
161 * @return {String} The card array format
162 */
163function transCardArray(value) {
164  value = value.replace(REG_CARD_ARRAY, item => {
165    return `.${item.slice(2, -2)}.`
166  })
167  if (value.charAt(value.length - 1) === '.') {
168    value = value.slice(0, -1)
169  }
170  return value
171}
172
173function checkCard(value, out, nodeLoc) {
174  if (!checkApi(value) && !checkIdxAndItem(value)) {
175    if (checkCardVersionLimit() && !checkVariable(value)){
176      out.log.push({
177        line: nodeLoc.line || 1,
178        column: nodeLoc.col || 1,
179        reason: `ERROR: Version 5: The expression '${value}' is not supported. Only single variables are supported.`
180      })
181    } else if (!checkCardVersionLimit() && !checkExpression(value)) {
182      out.log.push({
183        line: nodeLoc.line || 1,
184        column: nodeLoc.col || 1,
185        reason: `ERROR: Version 6 and above: The expression '${value}' is not supported. Only the binocular expression, ` +
186          `OR expression, AND expression and NOT expression are supported.`
187      })
188    }
189  }
190}
191
192function checkCardVersionLimit() {
193  return parseInt(process.env.PLATFORM_VERSION.replace('Version', '')) < 6
194}
195
196function checkApi(value) {
197  return /^\$(tc|t|r)/m.test(value)
198}
199
200function checkExpression(value) {
201  return checkVariable(value) || checkOR(value) || checkAND(value) || checkNOT(value) || checkBinocular(value)
202}
203
204function checkIdxAndItem(value) {
205  return value === '$idx' || value === '$item'
206}
207
208function checkVariable(value) {
209  return /^[a-zA-Z\$_][a-zA-Z\d_\.\[\]'"`\s]*$/.test(value)
210}
211
212function checkOR(value) {
213  return /^[a-zA-Z\$_][a-zA-Z\d_\.\[\]'"`\s]*\|\|[a-zA-Z\$_\s][a-zA-Z\d_\.\[\]'"`\s]*$/m.test(value)
214}
215
216function checkAND(value) {
217  return /^[a-zA-Z\$_][a-zA-Z\d_\.\[\]'"`\s]*&&[a-zA-Z\$_\s][a-zA-Z\d_\.\[\]'"`\s]*$/m.test(value)
218}
219
220function checkNOT(value) {
221  return /^![a-zA-Z\$_][a-zA-Z\d_\.\[\]'"`\s]*$/m.test(value)
222}
223
224function checkBinocular(value) {
225  return /^[a-zA-Z\$_][a-zA-Z\d_\.\[\]'"`\s]*\?[a-zA-Z\$_\s][a-zA-Z\d_\.\[\]'"`\s]*:[a-zA-Z\$_\s][a-zA-Z\d_\.\[\]'"`\s]*$/m.test(value)
226}
227
228transExp.checkApi = checkApi
229transExp.checkExpression = checkExpression
230transExp.checkIdxAndItem = checkIdxAndItem
231transExp.checkVariable = checkVariable
232transExp.checkAND = checkAND
233transExp.checkOR = checkOR
234transExp.checkNOT = checkNOT
235transExp.isExp = isExp
236transExp.containExp = containExp
237transExp.removeAllExpFix = removeAllExpFix
238transExp.transExpForList = transExpForList
239transExp.transCardArray = transCardArray
240module.exports = transExp
241