• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1
2var util = require('./util')
3var OHOS_THEME_PROP_GROUPS = require('../../theme/ohosStyles');
4
5// http://www.w3.org/TR/css3-color/#html4
6var BASIC_COLOR_KEYWORDS = {
7  black: '#000000',
8  silver: '#C0C0C0',
9  gray: '#808080',
10  white: '#FFFFFF',
11  maroon: '#800000',
12  red: '#FF0000',
13  purple: '#800080',
14  fuchsia: '#FF00FF',
15  green: '#008000',
16  lime: '#00FF00',
17  olive: '#808000',
18  yellow: '#FFFF00',
19  navy: '#000080',
20  blue: '#0000FF',
21  teal: '#008080',
22  aqua: '#00FFFF'
23}
24
25// http://www.w3.org/TR/css3-color/#svg-color
26var EXTENDED_COLOR_KEYWORDS = {
27  aliceblue: '#F0F8FF',
28  antiquewhite: '#FAEBD7',
29  aqua: '#00FFFF',
30  aquamarine: '#7FFFD4',
31  azure: '#F0FFFF',
32  beige: '#F5F5DC',
33  bisque: '#FFE4C4',
34  black: '#000000',
35  blanchedalmond: '#FFEBCD',
36  blue: '#0000FF',
37  blueviolet: '#8A2BE2',
38  brown: '#A52A2A',
39  burlywood: '#DEB887',
40  cadetblue: '#5F9EA0',
41  chartreuse: '#7FFF00',
42  chocolate: '#D2691E',
43  coral: '#FF7F50',
44  cornflowerblue: '#6495ED',
45  cornsilk: '#FFF8DC',
46  crimson: '#DC143C',
47  cyan: '#00FFFF',
48  darkblue: '#00008B',
49  darkcyan: '#008B8B',
50  darkgoldenrod: '#B8860B',
51  darkgray: '#A9A9A9',
52  darkgreen: '#006400',
53  darkgrey: '#A9A9A9',
54  darkkhaki: '#BDB76B',
55  darkmagenta: '#8B008B',
56  darkolivegreen: '#556B2F',
57  darkorange: '#FF8C00',
58  darkorchid: '#9932CC',
59  darkred: '#8B0000',
60  darksalmon: '#E9967A',
61  darkseagreen: '#8FBC8F',
62  darkslateblue: '#483D8B',
63  darkslategray: '#2F4F4F',
64  darkslategrey: '#2F4F4F',
65  darkturquoise: '#00CED1',
66  darkviolet: '#9400D3',
67  deeppink: '#FF1493',
68  deepskyblue: '#00BFFF',
69  dimgray: '#696969',
70  dimgrey: '#696969',
71  dodgerblue: '#1E90FF',
72  firebrick: '#B22222',
73  floralwhite: '#FFFAF0',
74  forestgreen: '#228B22',
75  fuchsia: '#FF00FF',
76  gainsboro: '#DCDCDC',
77  ghostwhite: '#F8F8FF',
78  gold: '#FFD700',
79  goldenrod: '#DAA520',
80  gray: '#808080',
81  green: '#008000',
82  greenyellow: '#ADFF2F',
83  grey: '#808080',
84  honeydew: '#F0FFF0',
85  hotpink: '#FF69B4',
86  indianred: '#CD5C5C',
87  indigo: '#4B0082',
88  ivory: '#FFFFF0',
89  khaki: '#F0E68C',
90  lavender: '#E6E6FA',
91  lavenderblush: '#FFF0F5',
92  lawngreen: '#7CFC00',
93  lemonchiffon: '#FFFACD',
94  lightblue: '#ADD8E6',
95  lightcoral: '#F08080',
96  lightcyan: '#E0FFFF',
97  lightgoldenrodyellow: '#FAFAD2',
98  lightgray: '#D3D3D3',
99  lightgreen: '#90EE90',
100  lightgrey: '#D3D3D3',
101  lightpink: '#FFB6C1',
102  lightsalmon: '#FFA07A',
103  lightseagreen: '#20B2AA',
104  lightskyblue: '#87CEFA',
105  lightslategray: '#778899',
106  lightslategrey: '#778899',
107  lightsteelblue: '#B0C4DE',
108  lightyellow: '#FFFFE0',
109  lime: '#00FF00',
110  limegreen: '#32CD32',
111  linen: '#FAF0E6',
112  magenta: '#FF00FF',
113  maroon: '#800000',
114  mediumaquamarine: '#66CDAA',
115  mediumblue: '#0000CD',
116  mediumorchid: '#BA55D3',
117  mediumpurple: '#9370DB',
118  mediumseagreen: '#3CB371',
119  mediumslateblue: '#7B68EE',
120  mediumspringgreen: '#00FA9A',
121  mediumturquoise: '#48D1CC',
122  mediumvioletred: '#C71585',
123  midnightblue: '#191970',
124  mintcream: '#F5FFFA',
125  mistyrose: '#FFE4E1',
126  moccasin: '#FFE4B5',
127  navajowhite: '#FFDEAD',
128  navy: '#000080',
129  oldlace: '#FDF5E6',
130  olive: '#808000',
131  olivedrab: '#6B8E23',
132  orange: '#FFA500',
133  orangered: '#FF4500',
134  orchid: '#DA70D6',
135  palegoldenrod: '#EEE8AA',
136  palegreen: '#98FB98',
137  paleturquoise: '#AFEEEE',
138  palevioletred: '#DB7093',
139  papayawhip: '#FFEFD5',
140  peachpuff: '#FFDAB9',
141  peru: '#CD853F',
142  pink: '#FFC0CB',
143  plum: '#DDA0DD',
144  powderblue: '#B0E0E6',
145  purple: '#800080',
146  red: '#FF0000',
147  rosybrown: '#BC8F8F',
148  royalblue: '#4169E1',
149  rebeccapurple: '#663399',
150  saddlebrown: '#8B4513',
151  salmon: '#FA8072',
152  sandybrown: '#F4A460',
153  seagreen: '#2E8B57',
154  seashell: '#FFF5EE',
155  sienna: '#A0522D',
156  silver: '#C0C0C0',
157  skyblue: '#87CEEB',
158  slateblue: '#6A5ACD',
159  slategray: '#708090',
160  slategrey: '#708090',
161  snow: '#FFFAFA',
162  springgreen: '#00FF7F',
163  steelblue: '#4682B4',
164  tan: '#D2B48C',
165  teal: '#008080',
166  thistle: '#D8BFD8',
167  tomato: '#FF6347',
168  turquoise: '#40E0D0',
169  violet: '#EE82EE',
170  wheat: '#F5DEB3',
171  white: '#FFFFFF',
172  whitesmoke: '#F5F5F5',
173  yellow: '#FFFF00',
174  yellowgreen: '#9ACD32'
175}
176
177var DEFAULT_ANIMATION = {
178    animationDuration : "0ms",
179    animationDelay : "0ms",
180    animationDirection : 'normal',
181    animationTimingFunction : 'ease',
182    animationPlayState : 'running',
183    animationIterationCount : 1,
184    animationFillMode : 'none'
185}
186
187var LENGTH_REGEXP = /^[-+]?\d*\.?\d+(\S*)$/
188var LINE_GRADIENT_ITEM_REGEXP = /^([0-9a-zA-Z-]+)\((.*)\)/
189var LINE_GRADIENT_DIRECTION_REGEXP = /^\s*(to|bottom|right|left|top)|[-+]?[0-9]*\.?[0-9]+(.*)/
190var LINE_GRADIENT_TO_DIRECTION_REGEXP = /(to|bottom|right|left|top)/
191var ANGLE_REGEXP = /^[-+]?[0-9]*\.?[0-9]+(.*)/
192var ARRAY_COLOR_STOP_REGEXP = /(rgba|rgb)\([0-9,.\spx%vpfp]+\)\s?[0-9-+px%vpfp]*|[#]?\w+\s?[0-9+-\spx%vpfp]*/gi
193var URL_REGEXP = /^url\(\s*['"]?\s*([^()]+?)\s*['"]?\s*\)$/
194var NAME_REGEXP = /^[a-zA-Z_]+[a-zA-Z0-9-]*$/
195var INT_REGEXP = /^[-+]?[0-9]+$/
196var ID_REGEXP = /^\"@id\d+\"$/
197var NORMAL_REGEXP =  /^normal$/
198var AUTO_REGEXP = /^auto$/
199var DATE_REGEXP = /(^([0-9]{3}[1-9]|[0-9]{2}[1-9][0-9]{1}|[0-9]{1}[1-9][0-9]{2}|[1-9][0-9]{3})-(((1[02]|0?[13578])-([12][0-9]|3[01]|0?[1-9]))|((11|0?[469])-(30|[12][0-9]|0?[1-9]))|(0?2-(1[0-9]|2[0-8]|0?[1-9])))$)|(^(([0-9]{2})(0[48]|[2468][048]|[13579][26])|((0[48]|[2468][048]|[13579][26])00))-(0?)2-29$)/
200var TRANSFORM_REGEXP = /[0-9a-zA-Z]+\s*\(\s*[0-9(a-zA-Z-|%)\.]+\s*(,\s*[0-9(a-zA-Z-|%)\.]+)*\)/g
201var TRANSFORM_ITEM_REGEXP = /^([0-9a-zA-Z]+)\s*\((.*)\)$/
202var FILTER_REGEXP = /^blur\(([1-9]\d*|0)(px|fp|vp)\)$/
203var FILTER_PERCENTAGE_REGEXP = /^blur\(([1-9]?\d|100)%\)$/
204var FILTER_STYLE_REGEXP = /^blur\(([1-9]?\d|100)%\)\s+[A-Za-z_]+$/
205var SUPPORT_CSS_EXPRESSION = /calc\(|var\(\-\-/
206var SUPPORT_VAR_EXPRESSION = /var\(\-\-/
207var SUPPORT_CSS_UNIT = ['px', 'pt', 'wx', 'vp', 'fp']
208var SUPPORT_CSS_TIME_UNIT = ['ms', 's']
209var SUPPORT_CSS_PERCENTAGE_UNIT = ['px', '%', 'vp', 'fp']
210var SUPPORT_CSS_GRID_UNIT = ['px', '%', 'fr', 'vp', 'fp']
211var SUPPORT_CSS_TEXT_INDENT_UNIT = ['px', 'cm', '%', 'em', 'vp', 'fp']
212var SUPPORT_CSS_ANGLE_UNIT = ["deg", "rad", "grad", "turn"]
213var logTypes = ["NOTE", "WARNING", "ERROR"]
214
215var ANYTHING_VALIDATOR = function ANYTHING_VALIDATOR(v) {
216  v = (v || '').toString().trim()
217  return { value: v }
218}
219
220/**
221 * the values below is valid
222 * - auto
223 * - number
224 * - number + 'px'|'%'|'vp'| 'fp'
225 *
226 * @param {string} v
227 * @return {function} a function to return
228 * - value: number|null
229 * - reason(k, v, result)
230 */
231var AUTO_PERCENTAGE_LENGTH_VALIDATOR = function AUTO_PERCENTAGE_LENGTH_VALIDATOR(v) {
232  v = (v || '').toString().trim()
233  if (v.match(AUTO_REGEXP)) {
234    return { value: v }
235  } else if (v.match(ID_REGEXP)) {
236    return { value: v }
237  } else if (v.match(SUPPORT_CSS_EXPRESSION)) {
238    return { value: v }
239  } else {
240    return LENGTH(v, SUPPORT_CSS_PERCENTAGE_UNIT)
241  }
242}
243
244/**
245 * the values below is valid
246 * - number
247 * - number + 'px'|'%'|'vp'| 'fp'
248 *
249 * @param {string} v
250 * @return {function} a function to return
251 * - value: number|null
252 * - reason(k, v, result)
253 */
254var PERCENTAGE_LENGTH_VALIDATOR = function PERCENTAGE_LENGTH_VALIDATOR(v) {
255  v = (v || '').toString().trim()
256  if (v.match(ID_REGEXP)) {
257    return { value: v }
258  } else if (v.match(SUPPORT_CSS_EXPRESSION)) {
259    return { value: v }
260  } else {
261    return LENGTH(v, SUPPORT_CSS_PERCENTAGE_UNIT)
262  }
263}
264
265/**
266 * the values below is valid
267 * - number
268 * - number + 'px'
269 *
270 * @param {string} v
271 * @return {function} a function to return
272 * - value: number|null
273 * - reason(k, v, result)
274 */
275var LENGTH_VALIDATOR = function LENGTH_VALIDATOR(v) {
276  v = (v || '').toString().trim()
277  if (v.match(SUPPORT_CSS_EXPRESSION)) {
278    return { value: v }
279  } else if (v.match(ID_REGEXP)) {
280    return { value: v }
281  } else {
282    return LENGTH(v, SUPPORT_CSS_UNIT)
283  }
284}
285
286var LENGTH = function LENGTH(v, SUPPORT_UNIT) {
287  v = (v || '').toString().trim()
288  var match = v.match(LENGTH_REGEXP)
289
290  if (match) {
291    var unit = match[1]
292    if (!unit) {
293      return v === '0' ? { value: parseFloat(v) + SUPPORT_UNIT[0] } :
294        {
295          value: parseFloat(v) + SUPPORT_UNIT[0],
296          reason: function(k, v) {
297            return 'WARNING: No unit is specified for the `' + util.camelCaseToHyphened(k) +
298              '` attribute. The default unit is ' + SUPPORT_UNIT[0]
299          }
300        }
301    } else if (SUPPORT_UNIT.indexOf(unit) > -1) {
302      return { value: v }
303    } else {
304      return {
305        value: parseFloat(v) + SUPPORT_UNIT[0],
306        reason: function reason(k, v, result) {
307          return 'ERROR: The `' + k + '` attribute does not support `' + unit +
308            '`. The default unit is ' + SUPPORT_UNIT[0]
309        }
310      }
311    }
312  }
313
314  if (v.indexOf('@') >= 0) {
315    let result
316    // target format "@sys.float.id_sys_length" or '@sys.float.id_sys_length'
317    let SysResourceTypeRefReg = /['"]\s*@sys\.float\.(?<resName>\w+)\s*['"]/
318    result = SysResourceTypeRefReg.exec(v)
319    if (result) {
320      const resourceName = result.groups['resName']
321      if (resourceName && OHOS_THEME_PROP_GROUPS[resourceName]) {
322        return { value: "@sys.float." + OHOS_THEME_PROP_GROUPS[resourceName] }
323      }
324    }
325    // target format "@app.float.developer_defined_length" or '@app.float.developer_defined_length'
326    let AppResourceTypeRefReg = /['"]\s*@app\.float\.(?<resName>\w+)\s*['"]/
327    result = AppResourceTypeRefReg.exec(v)
328    if (result) {
329      const resourceName = result.groups['resName']
330      if (resourceName) {
331        return { value: "@app.float." + resourceName}
332      }
333    }
334    // target format "@id_sys_length" or '@id_sys_length' or @id_sys_length
335    let ResourceRefReg = /['"]?\s*@(?<resName>\w+)\s*['"]?/
336    result = ResourceRefReg.exec(v)
337    if (result) {
338      const resourceName = result.groups['resName']
339      if (resourceName && OHOS_THEME_PROP_GROUPS[resourceName]) {
340        return { value: "@ohos_id_" + OHOS_THEME_PROP_GROUPS[resourceName] }
341      }
342    }
343  }
344
345  return {
346    value: null,
347    reason: function reason(k, v, result) {
348      return 'ERROR: The `' + util.camelCaseToHyphened(k) + '` attribute does not support the `' +
349        v + '` value (only numbers are supported).'
350    }
351  }
352}
353
354var TEXT_INDENT_VALIDATOR = function TEXT_INDENT_VALIDATOR(v) {
355  return LENGTH(v, SUPPORT_CSS_TEXT_INDENT_UNIT)
356}
357
358var TEXT_LINE_HEIGHT_VALIDATOR = function TEXT_LINE_HEIGHT_VALIDATOR(v) {
359  v = (v || '').toString().trim()
360
361  if (v.match(NORMAL_REGEXP)) {
362    return { value: v }
363  } else {
364    return LENGTH_VALIDATOR(v)
365  }
366}
367
368/**
369 * the values below is valid
370 * - number
371 * - number + 'ms'|'s'
372 *
373 * @param {string} v
374 * @return {function} a function to return
375 * - value: number|null
376 * - reason(k, v, result)
377 */
378var TIME_VALIDATOR = function TIME_VALIDATOR(v) {
379  return LENGTH(v, SUPPORT_CSS_TIME_UNIT)
380}
381
382/**
383 * the values below is valid
384 * - number {1,4}
385 * - number + 'px' {1,4}
386 *
387 * @param {string} v
388 * @return {function} a function to return
389 * - value: number|null
390 * - reason(k, v, result)
391 */
392var SHORTHAND_PERCENTAGE_LENGTH_VALIDATOR = function SHORTHAND_PERCENTAGE_LENGTH_VALIDATOR(v) {
393  v = (v || '').toString().trim()
394  let rule = PERCENTAGE_LENGTH_VALIDATOR
395  return SHORTHAND_VALIDATOR(v, rule)
396}
397
398var SHORTHAND_AUTO_PERCENTAGE_LENGTH_VALIDATOR = function SHORTHAND_AUTO_PERCENTAGE_LENGTH_VALIDATOR(v) {
399  v = (v || '').toString().trim()
400  let rule = AUTO_PERCENTAGE_LENGTH_VALIDATOR
401  return SHORTHAND_VALIDATOR(v, rule)
402}
403
404var SHORTHAND_LENGTH_VALIDATOR = function SHORTHAND_LENGTH_VALIDATOR(v) {
405  v = (v || '').toString().trim()
406  let rule = LENGTH_VALIDATOR
407  return SHORTHAND_VALIDATOR(v, rule)
408}
409
410var ARRAY_LENGTH_VALIDATOR = function ARRAY_LENGTH_VALIDATOR(v) {
411  v = (v || '').toString().trim().replace(/,/g, ' ')
412  var isArray = true
413  return SHORTHAND_VALIDATOR(v, LENGTH_VALIDATOR, isArray)
414}
415
416/**
417 * the values below is valid
418 * - hex color value (#xxxxxx or #xxx)
419 * - basic and extended color keywords in CSS spec
420 * - expression
421 *
422 * @param {string} v
423 * @return {function} a function to return
424 * - value: string|null
425 * - reason(k, v, result)
426 */
427var COLOR_VAR_VALIDATOR = function COLOR_VAR_VALIDATOR(v) {
428  v = (v || '').toString().trim()
429  if (v.match(SUPPORT_VAR_EXPRESSION)) {
430    return { value: v }
431  } else {
432    return COLOR_VALIDATOR(v)
433  }
434}
435
436/**
437 * the values below is valid
438 * - hex color value (#xxxxxx or #xxx)
439 * - basic and extended color keywords in CSS spec
440 *
441 * @param {string} v
442 * @return {function} a function to return
443 * - value: string|null
444 * - reason(k, v, result)
445 */
446var COLOR_VALIDATOR = function COLOR_VALIDATOR(v) {
447  v = (v || '').toString().trim()
448
449  if (v.indexOf('linear-gradient') >= 0) {
450    let result = {
451      values: []
452    }
453    let temp = LINEAR_GRADIENT_VALIDATOR(v)
454    if (util.isValidValue(temp.value)) {
455      let tempValue = JSON.parse(temp.value)
456      result.values.push(tempValue)
457      return { value: JSON.stringify(result) }
458    } else {
459      return temp
460    }
461  }
462
463  if (v.match(ID_REGEXP)) {
464    return { value: v }
465  }
466
467  if (v.indexOf('@') >= 0) {
468    let result
469    // target format "@sys.color.id_color_background" or '@sys.color.id_color_background'
470    let SysResourceTypeRefReg = /['"]\s*@sys\.color\.(?<resName>\w+)\s*['"]/
471    result = SysResourceTypeRefReg.exec(v)
472    if (result) {
473      const resourceName = result.groups['resName']
474      if (resourceName && OHOS_THEME_PROP_GROUPS[resourceName]) {
475        return { value: "@sys.color." + OHOS_THEME_PROP_GROUPS[resourceName] }
476      }
477    }
478    // target format "@app.color.developer_defined_color" or '@app.color.developer_defined_color'
479    let AppResourceTypeRefReg = /['"]\s*@app\.color\.(?<resName>\w+)\s*['"]/
480    result = AppResourceTypeRefReg.exec(v)
481    if (result) {
482      const resourceName = result.groups['resName']
483      if (resourceName) {
484        return { value: "@app.color." + resourceName}
485      }
486    }
487    // target format "@id_color_background" or '@id_color_background' or @id_color_background
488    let ResourceRefReg = /['"]?\s*@(?<resName>\w+)\s*['"]?/
489    result = ResourceRefReg.exec(v)
490    if (result) {
491      const resourceName = result.groups['resName']
492      if (resourceName && OHOS_THEME_PROP_GROUPS[resourceName]) {
493        return { value: "@ohos_id_" + OHOS_THEME_PROP_GROUPS[resourceName] }
494      }
495    }
496  }
497
498  if (v.match(/^#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/)) {
499    return { value: v }
500  }
501
502  if (v.match(/^#[0-9a-fA-F]{3}$/)) {
503    return {
504      value: '#' + v[1] + v[1] + v[2] + v[2] + v[3] + v[3],
505      reason: function reason(k, v, result) {
506        return 'NOTE: Attribute value `' + v + '` is automatically fixed to `' + result + '`.'
507      }
508    }
509  }
510
511  if (EXTENDED_COLOR_KEYWORDS[v]) {
512    return {
513      value: EXTENDED_COLOR_KEYWORDS[v],
514      reason: function reason(k, v, result) {
515        return 'NOTE: Attribute value `' + v + '` is automatically fixed to `' + result + '`.'
516      }
517    }
518  }
519
520  if (v === 'transparent' || v === 'none') {
521    return { value: 'rgba(0,0,0,0)' }
522  }
523
524  const returnColorReg = COLOR_REG(v)
525  if (returnColorReg.value !== null) {
526    return returnColorReg
527  }
528
529  return {
530    value: null,
531    reason: function reason(k, v, result) {
532      return 'ERROR: Value `' + v + '` is invalid for the `' + util.camelCaseToHyphened(k) + '` attribute.'
533    }
534  }
535}
536
537var COLOR_REG = function COLOR_REG(v) {
538  let arrColor, r, g, b, a
539  const RGB_REGEXP = /^rgb\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)$/gi
540  const RGBA_REGEXP = /^rgba\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d*\.?\d+)\s*\)$/gi
541  const HSL_REGEXP = /^hsl\(\s*(\d+)\s*,\s*(\d+)%\s*,\s*(\d+)%\s*\)$/gi
542  const HSLA_REGEXP = /^hsla\(\s*(\d+)\s*,\s*(\d+)%\s*,\s*(\d+)%\s*,\s*(\d*\.?\d+)\s*\)$/gi
543  if (arrColor = RGB_REGEXP.exec(v)) {
544    r = parseInt(arrColor[1])
545    g = parseInt(arrColor[2])
546    b = parseInt(arrColor[3])
547    if (r >= 0 && r <= 255 && g >= 0 && g <= 255 && b >= 0 && b <= 255) {
548      return { value: 'rgb(' + [r, g, b].join(',') + ')' }
549    }
550  }
551  if (arrColor = RGBA_REGEXP.exec(v)) {
552    r = parseInt(arrColor[1])
553    g = parseInt(arrColor[2])
554    b = parseInt(arrColor[3])
555    a = parseFloat(arrColor[4])
556    if (r >= 0 && r <= 255 && g >= 0 && g <= 255 && b >= 0 && b <= 255 && a >= 0 && a <= 1) {
557      return { value: 'rgba(' + [r, g, b, a].join(',') + ')' }
558    }
559  }
560  if (arrColor = HSL_REGEXP.exec(v)) {
561    r = arrColor[1]
562    g = arrColor[2]
563    b = arrColor[3]
564    if (r >= 0 && r <= 360 && g >= 0 && g <= 100 && b >= 0 && b <= 100) {
565      return { value: 'hsl(' + [r, g+'%', b+'%'].join(',') + ')' }
566    }
567  }
568  if (arrColor = HSLA_REGEXP.exec(v)) {
569    r = arrColor[1]
570    g = arrColor[2]
571    b = arrColor[3]
572    a = arrColor[4]
573    if (r >= 0 && r <= 360 && g >= 0 && g <= 100 && b >= 0 && b <= 100 && a >= 0 && a <= 1) {
574      return { value: 'hsla(' + [r, g+'%', b+'%', a].join(',') + ')' }
575    }
576  }
577
578  return { value: null }
579}
580
581/**
582 * the values below is valid
583 * - color {1,4}
584 *
585 * @param {string} v
586 * @return {function} a function to return
587 * - value: color|null
588 * - reason(k, v, result)
589 */
590var SHORTHAND_COLOR_VALIDATOR = function SHORTHAND_COLOR_VALIDATOR(v) {
591  v = (v || '').toString().trim()
592  v = v.replace(/\s*,\s+/g, ',')
593  return SHORTHAND_VALIDATOR(v, COLOR_VAR_VALIDATOR)
594}
595
596var ARRAY_COLOR_VALIDATOR = function ARRAY_COLOR_VALIDATOR(v) {
597  v = (v || '').toString().trim()
598  var isArray = true
599  return SHORTHAND_VALIDATOR(v.replace(/,/g, ' '), COLOR_VAR_VALIDATOR, isArray)
600}
601
602var SHORTHAND_STYLE_VALIDATOR = function SHORTHAND_STYLE_VALIDATOR(v) {
603  v = (v || '').toString().trim()
604  return SHORTHAND_VALIDATOR(v, STYLE_VALIDATOR)
605}
606
607var STYLE_VALIDATOR = function STYLE_VALIDATOR(v) {
608  const styleList = ["solid", "dashed", "dotted"]
609  v = (v || '').toString().trim()
610  if (styleList.includes(v)) {
611    return { value:v }
612  } else {
613    return {
614      value: null,
615      reason: function (k,v) {
616        return 'ERROR: The `' + util.camelCaseToHyphened(k) + '` attribute does not support value `' +
617          v + '` (the support value is `' + styleList.join('`|`') + '`).'
618      }
619    }
620  }
621}
622
623var SHORTHAND_VALIDATOR = function SHORTHAND_VALIDATOR(v, validateFunction, isArray) {
624  v = (v || '').toString().trim()
625  let value = []
626  let reason = []
627  let results = v.split(/(?<!\+|\-|\*|\/|\,)\s+(?!\+|\-|\*|\/|\,)/).map(validateFunction)
628  for (let i = 0; i < results.length; ++i) {
629    let res = results[i]
630    if (!res.value) {
631      value = null
632      reason = res.reason
633      break
634    }
635    value.push(res.value)
636    if (res.reason) {
637      reason.push(res.reason)
638    }
639  }
640
641  if (!value) {
642    return {
643      value: value,
644      reason: reason
645    }
646  }
647  else {
648    return {
649      value: isArray ? value.join(',') : value.join(' '),
650      reason: reason.length > 0 ? function (k, v, result) {
651        return reason.map(function (res) {
652          if (typeof res === 'function') {
653            return res(k, v, result)
654          }
655        }).join('\n')
656      } : null
657    }
658  }
659}
660
661var BORDER_VALIDATOR = function BORDER_VALIDATOR (value, name) {
662  value = (value || '').toString().trim();
663  let values = '';
664  const colorAttribute = value.match(/\(.*?\)/g);
665  if (colorAttribute && colorAttribute.length === 1) {
666    values = value.replace(colorAttribute[0], colorAttribute[0].replace(/\s+/g, '')).split(/\s+/);
667  } else {
668    values = value.split(/\s+/);
669  }
670  const res = []
671  let hasError = false
672  const reasons = []
673  let index = 0
674  const order = []
675  let validatorResult
676  const rules = [
677    {
678      match (item) { return LENGTH_VALIDATOR(item).value },
679      action (item) {
680        validatorResult = LENGTH_VALIDATOR(item)
681        order.push(0)
682        res.push({
683          value: validatorResult.value,
684          type: 'Width'
685        })
686      }
687    },
688    {
689      match (item) { return validate('borderStyle', item).value },
690      action (item) {
691        validatorResult = validate('borderStyle', item)
692        order.push(1)
693        res.push({
694          value: validatorResult.value,
695          type: 'Style'
696        })
697      }
698    },
699    {
700      match (item) { return COLOR_VAR_VALIDATOR(item).value },
701      action (item) {
702        validatorResult = COLOR_VAR_VALIDATOR(item)
703        order.push(2)
704        res.push({
705          value: validatorResult.value,
706          type: 'Color'
707        })
708      }
709    },
710    {
711      match () { return true },
712      action () {
713        hasError = true
714      }
715    }
716  ]
717  if (values && values.length <= 3) {
718    for (let i = 0; i < values.length; i++) {
719      const item = values[i]
720      for (let i = 0; i < rules.length; i++) {
721        if (rules[i].match(item)) {
722          rules[i].action(item)
723          break;
724        }
725      }
726      // style width color pass verification, but did not write in order, such as "1px red solid", should be error
727      let orderIndex = -1
728      order.forEach((item) => {
729        orderIndex < item ? orderIndex = item : hasError = true
730      })
731      // get all warning and note log
732      logUtil(validatorResult, name, item, reasons, index)
733    }
734    // print warning and note
735    if (!hasError) {
736      return {
737        value: res,
738        reason: reasons.length > 0 ? function (k, v) {
739          return (
740            logTypes[index] + ': There are some problems with value `' + v + '` of the `' +
741              util.camelCaseToHyphened(k) + '` attribute. \n ' + reasons.join(' \n'))
742        } : null
743      }
744    }
745  }
746  // print error
747  return {
748    value: null,
749    reason: function reason (k, v, result) {
750      return 'ERROR: The `' + util.camelCaseToHyphened(k) +
751        '` attribute does not support value `' + v +
752        '` (this value does not meet the inspection standards for the width, style, and color).'
753    }
754  }
755}
756
757function logUtil (validatorResult, name, item, reasons, index) {
758  if (validatorResult.reason) {
759    let str = validatorResult.reason(name, item, validatorResult.value)
760    const mesg = str.match(/^([A-Z]+):/)
761    // When both warning and note information are included, a high severity sign is output
762    const num = logTypes.indexOf(mesg[1])
763    if (index < num) {
764      index = num
765    }
766    str = str.replace(mesg[0], '')
767    reasons.push(str)
768  }
769}
770
771var BOX_SHADOW_VALIDATOR = function BOX_SHADOW_VALIDATOR(value, name) {
772  value = (value || '').toString().trim()
773  const values = value.split(/\s+/)
774  let validatorResult
775  const res = []
776  const order = []
777  const reasons = []
778  let index = 0
779  let ruleIndex = 0
780  let hasError = false
781  const rules = [
782    {
783      match (item) { return validate('boxShadowH', item).value },
784      action (item) {
785        validatorResult = validate('boxShadowH', item)
786        order.push(0)
787        res.push({
788          value: validatorResult.value,
789          type: 'H'
790        })
791      }
792    },
793    {
794      match (item) { return validate('boxShadowV', item).value },
795      action (item) {
796        validatorResult = validate('boxShadowV', item)
797        order.push(1)
798        res.push({
799          value: validatorResult.value,
800          type: 'V'
801        })
802      }
803    },
804    {
805      match (item) { return validate('boxShadowBlur', item).value },
806      action (item) {
807        validatorResult = validate('boxShadowBlur', item)
808        order.push(2)
809        res.push({
810          value: validatorResult.value,
811          type: 'Blur'
812        })
813      }
814    },
815    {
816      match (item) { return validate('boxShadowSpread', item).value },
817      action (item) {
818        validatorResult = validate('boxShadowSpread', item)
819        order.push(3)
820        res.push({
821          value: validatorResult.value,
822          type: 'Spread'
823        })
824      }
825    },
826    {
827      match (item) { return COLOR_VAR_VALIDATOR(item).value },
828      action (item) {
829        validatorResult = COLOR_VAR_VALIDATOR(item)
830        order.push(4)
831        res.push({
832          value: validatorResult.value,
833          type: 'Color'
834        })
835      }
836    }
837  ]
838  const length = values.length
839  const flag = (length <= 6 && length >= 2) && values[0].match(LENGTH_REGEXP) && values[1].match(LENGTH_REGEXP)
840  if (values && flag) {
841    for (let i = 0; i < values.length; i++) {
842      const item = values[i]
843      for (let j = ruleIndex; j < rules.length; j++) {
844        if (rules[j].match(item)) {
845          ruleIndex++
846          rules[j].action(item)
847          break
848        }
849      }
850      let orderIndex = -1
851      order.forEach((item) => {
852        orderIndex < item ? orderIndex = item : hasError = true
853      })
854      // get all warning and note log
855      logUtil(validatorResult, name, item, reasons, index)
856    }
857    if (!hasError) {
858      return {
859        value: res,
860        reason: reasons.length > 0 ? function (k, v) {
861          return (
862            logTypes[index] + ': There are some problems with value `' + v +
863              '` of the `' + util.camelCaseToHyphened(k) + '` attribute. \n ' + reasons.join(' \n'))
864        } : null
865      }
866    }
867  }
868  return {
869    value: null,
870    reason: function reason (k, v, result) {
871      return 'ERROR: The `' + util.camelCaseToHyphened(k) +
872        '` attribute does not support value `' + v +
873        '` (this value does not meet the inspection standards).'
874    }
875  }
876}
877
878/**
879 * only integer or float value is valid
880 *
881 * @param {string} v
882 * @return {function} a function to return
883 * - value: number|null
884 * - reason(k, v, result)
885 */
886var NUMBER_VALIDATOR = function NUMBER_VALIDATOR(v, isInt) {
887  v = (v || '').toString().trim()
888
889  if (v.match(ID_REGEXP)) {
890    return { value: v }
891  }
892
893  var match = v.match(LENGTH_REGEXP)
894
895  if (match && !match[1]) {
896    return { value: isInt === true ? parseInt(v, 10) : parseFloat(v) }
897  }
898
899  if (v.indexOf('@') >= 0) {
900    let result
901    // target format "@sys.float.id_sys_number" or '@sys.float.id_sys_number'
902    let SysResourceTypeRefReg = /['"]\s*@sys\.float\.(?<resName>\w+)\s*['"]/
903    result = SysResourceTypeRefReg.exec(v)
904    if (result) {
905      const resourceName = result.groups['resName']
906      if (resourceName && OHOS_THEME_PROP_GROUPS[resourceName]) {
907        return { value: "@sys.float." + OHOS_THEME_PROP_GROUPS[resourceName] }
908      }
909    }
910    // target format "@app.float.developer_defined_number" or '@app.float.developer_defined_number'
911    let AppResourceTypeRefReg = /['"]\s*@app\.float\.(?<resName>\w+)\s*['"]/
912    result = AppResourceTypeRefReg.exec(v)
913    if (result) {
914      const resourceName = result.groups['resName']
915      if (resourceName) {
916        return { value: "@app.float." + resourceName}
917      }
918    }
919    // target format "@id_sys_number" or '@id_sys_number' or @id_sys_number
920    let ResourceRefReg = /['"]?\s*@(?<resName>\w+)\s*['"]?/
921    result = ResourceRefReg.exec(v)
922    if (result) {
923      const resourceName = result.groups['resName']
924      if (resourceName && OHOS_THEME_PROP_GROUPS[resourceName]) {
925        return { value: "@ohos_id_" + OHOS_THEME_PROP_GROUPS[resourceName] }
926      }
927    }
928  }
929
930  return {
931    value: null,
932    reason: function reason(k, v, result) {
933      return 'ERROR: The `' + util.camelCaseToHyphened(k) +
934        '` attribute does not support value `' + v + '` (only numbers are supported).'
935    }
936  }
937}
938
939var ARRAY_NUMBER_VALIDATOR = function ARRAY_NUMBER_VALIDATOR(v) {
940  v = (v || '').toString().trim().replace(/,/g, ' ')
941  var isArray = true
942  return SHORTHAND_VALIDATOR(v, NUMBER_VALIDATOR, isArray)
943}
944
945/**
946 * only integer value is valid
947 *
948 * @param {string} v
949 * @return {function} a function to return
950 * - value: number|null
951 * - reason(k, v, result)
952 */
953var INTEGER_VALIDATOR = function INTEGER_VALIDATOR(v) {
954  return NUMBER_VALIDATOR(v, true)
955}
956
957/**
958 * transition-property: only css property is valid
959 *
960 * @param {string} v
961 * @return {function} a function to return
962 * - value: string|null
963 * - reason(k, v, result)
964 */
965var TRANSITION_PROPERTY_VALIDATOR = function TRANSITION_PROPERTY_VALIDATOR(v) {
966  v = (v || '').toString()
967  v = v.split(/\s*,\s*/).map(util.hyphenedToCamelCase).join(',')
968
969  if (v.split(/\s*,\s*/).every(p => !!validatorMap[p])) {
970    return {value: v}
971  }
972
973  return {
974    value: null,
975    reason: function reason(k, v, result) {
976      return 'ERROR: The `' + util.camelCaseToHyphened(k) + '` attribute does not support value `' +
977        v + '` (only CSS attributes support this value).'
978    }
979  }
980}
981
982/**
983 * transition-duration & transition-delay: only number of seconds or milliseconds is valid
984 *
985 * @param {string} v
986 * @return {function} a function to return
987 * - value: number|null
988 * - reason(k, v, result)
989 */
990var TRANSITION_INTERVAL_VALIDATOR = function TRANSITION_INTERVAL_VALIDATOR(v) {
991  v = (v || 0).toString()
992  var match, num, ret
993
994  if (match = v.match(/^\d*\.?\d+(ms|s)?$/)) {
995    num = parseFloat(match[0])
996    if (!match[1]) {
997      ret = {value: parseInt(num)}
998    }
999    else {
1000      if (match[1] === 's') {
1001        num *= 1000
1002      }
1003      ret = {
1004        value: parseInt(num),
1005        reason: function reason(k, v, result) {
1006          return 'NOTE: Attribute value `' + v + '` is automatically fixed to `' + result + '`.'
1007        }
1008      }
1009    }
1010    return ret
1011  }
1012
1013  return {
1014    value: null,
1015    reason: function reason(k, v, result) {
1016      return 'ERROR: The `' + util.camelCaseToHyphened(k) + '` attribute does not support value `' +
1017        v + '` (only seconds and milliseconds are supported).'
1018    }
1019  }
1020}
1021
1022/**
1023 * transition-timing-function: only linear|ease|ease-in|ease-out|ease-in-out|cubic-bezier(n,n,n,n) is valid
1024 *
1025 * @param {string} v
1026 * @return {function} a function to return
1027 * - value: linear|ease|ease-in|ease-out|ease-in-out|cubic-bezier(n,n,n,n)|null
1028 * - reason(k, v, result)
1029 */
1030var TRANSITION_TIMING_FUNCTION_VALIDATOR = function TRANSITION_TIMING_FUNCTION_VALIDATOR(v) {
1031  v = (v || '').toString()
1032
1033  if (v.match(/^linear|ease|ease-in|ease-out|ease-in-out|fast-out-slow-in|linear-out-slow-in$/) ||
1034    v.match(/^fast-out-linear-in|friction|extreme-deceleration|sharp|rhythm|smooth$/)) {
1035    return {value: v}
1036  }
1037
1038  let match, ret
1039  let NUM_REGEXP = /^[-]?\d*\.?\d+$/
1040  if (match = v.match(/^cubic-bezier\(\s*(.*)\s*,\s*(.*)\s*,\s*(.*)\s*,\s*(.*)\s*\)$/)) {
1041    /* istanbul ignore else */
1042    if (match[1].match(NUM_REGEXP) && match[2].match(NUM_REGEXP) &&
1043      match[3].match(NUM_REGEXP) && match[4].match(NUM_REGEXP)) {
1044      ret = [parseFloat(match[1]), parseFloat(match[2]), parseFloat(match[3]), parseFloat(match[4])].join(',')
1045      return {value: 'cubic-bezier(' + ret + ')'}
1046    }
1047  }
1048
1049  // check steps
1050  if (match = v.match(/^steps\(\s*([\d]*)\s*(,\s*(start|end)\s*){0,1}\)$/)) {
1051    var stepCnt = parseFloat(match[1]);
1052    if (stepCnt > 0) {
1053      if (match[3] === undefined) {
1054        ret = stepCnt;
1055      } else {
1056        ret = [stepCnt, match[3]].join(',')
1057      }
1058      return {value: 'steps(' + ret + ')'}
1059    }
1060  }
1061
1062  return {
1063    value: null,
1064    reason: function reason(k, v, result) {
1065      return 'ERROR: The `' + util.camelCaseToHyphened(k) + '` attribute does not support value `' + v +
1066             '` (supported values include `linear`, `ease`, `ease-in`, `ease-out`, `ease-in-out`,' +
1067             ' `cubic-bezier(n,n,n,n)` and `steps(n[, start|end])`).'
1068    }
1069  }
1070}
1071
1072function parseAnimationOption(key, option, style)
1073{
1074   var subResult = validate(key, option)
1075   if (subResult.value) {
1076       style[key] = subResult.value
1077       return true
1078   }
1079    return false
1080}
1081
1082function parseSimpleAnimation(style, animation) {
1083    // init default animation brief value
1084    Object.assign(style, DEFAULT_ANIMATION)
1085    let options = animation.trim().replace(/,\s+/g, ",").split(/\s+/)
1086    let durationIdx = NaN
1087    let delayIdx = NaN
1088    let directionIdx = NaN
1089    let timingIdx = NaN
1090    let playStateIdx = NaN
1091    let iterationIdx = NaN
1092    let fillModeIdx = NaN
1093    for (let idx in options) {
1094        const option = options[idx]
1095        if (isNaN(timingIdx) && parseAnimationOption('animationTimingFunction', option, style)) {
1096            timingIdx = idx
1097            continue
1098        }
1099        if (isNaN(directionIdx) && parseAnimationOption('animationDirection', option, style)) {
1100            directionIdx = idx
1101            continue
1102        }
1103        if (isNaN(playStateIdx) && parseAnimationOption('animationPlayState', option, style)) {
1104            playStateIdx = idx
1105            continue
1106        }
1107        if (isNaN(iterationIdx) && parseAnimationOption('animationIterationCount', option, style)) {
1108            iterationIdx = idx
1109            continue
1110        }
1111        if (isNaN(fillModeIdx) && parseAnimationOption('animationFillMode', option, style)) {
1112            fillModeIdx = idx
1113            continue
1114        }
1115        if (isNaN(durationIdx) && parseAnimationOption('animationDuration', option, style)) {
1116            durationIdx = idx
1117            continue
1118        }
1119        if (isNaN(delayIdx) && parseAnimationOption('animationDelay', option, style)) {
1120            delayIdx = idx
1121            continue
1122        }
1123    }
1124    delete options[durationIdx]
1125    delete options[delayIdx]
1126    delete options[directionIdx]
1127    delete options[timingIdx]
1128    delete options[playStateIdx]
1129    delete options[iterationIdx]
1130    delete options[fillModeIdx]
1131    options = options.filter(res => { return !(res === 'undefined') })
1132    if (options.length === 1) {
1133       if (!parseAnimationOption('animationName', options[0], style)) {
1134           return false
1135       }
1136       return true
1137    } else if (options.length > 1) {
1138        return false
1139    } else {
1140        // use default.
1141        return true
1142    }
1143}
1144
1145var ANIMATION_VALIDATOR = function ANIMATION_VALIDATOR(v) {
1146    var style = {}
1147    if (parseSimpleAnimation(style, v)) {
1148        return {value: style}
1149    } else {
1150        return {
1151            value: null,
1152            reason: function reason(k, v, result) {
1153                return 'ERROR: animation is invalid'
1154            }
1155        }
1156    }
1157}
1158
1159var TRANSFORM_VALIDATOR = function TRANSFORM_VALIDATOR(v) {
1160  v = (v || '').toString().trim()
1161  if (v.match(/^none$/)) {
1162    return { value: JSON.stringify({}) }
1163  }
1164  const values = []
1165  TRANSFORM_REGEXP.lastIndex = 0
1166  while (true) {
1167    let matchValue = TRANSFORM_REGEXP.exec(v)
1168    if (!matchValue) {
1169      break
1170    }
1171    values.push(v.slice(matchValue.index, TRANSFORM_REGEXP.lastIndex))
1172  }
1173  if (!values.length) {
1174    return {
1175      value: null,
1176      reason: function reason(k, v) {
1177        return 'ERROR: The `' + util.camelCaseToHyphened(k) + '` attribute does not support value `' + v + '`.'
1178      }
1179    }
1180  }
1181  let result = {}
1182  let reasonMaps = []
1183  let allLength = 0
1184  values.forEach(function(v) {
1185    let length = 0
1186    let match = v.match(TRANSFORM_ITEM_REGEXP)
1187    if (match) {
1188      let firstValue = match[1]
1189      let secondValue = match[2]
1190      let checkFuntion = transformValidatorMap[firstValue]
1191      if (typeof checkFuntion == 'function') {
1192        var checkResult = checkFuntion(secondValue)
1193        if (typeof checkResult.value == 'number' || typeof checkResult.value == 'string') {
1194          result[firstValue] = checkResult.value
1195        }
1196        let check = checkReason(checkResult, firstValue, secondValue, length)
1197        length = check.length
1198        if (check.realReason) {
1199          reasonMaps.push(check.realReason)
1200        }
1201      } else {
1202        length = 2
1203        reasonMaps.push('property `' + firstValue + '` is invalid.')
1204      }
1205    } else {
1206      length = 2
1207      reasonMaps.push('property value `' + v + '` is invalid.')
1208    }
1209    if (allLength < length) {
1210      allLength = length
1211    }
1212  })
1213  return {
1214    value: result ? JSON.stringify(result) : null,
1215    reason: reasonMaps.length > 0 ?
1216      function(k, v) {
1217        return logTypes[allLength] + ': Value `' + v + '` of the `' +
1218          util.camelCaseToHyphened(k) + '` attribute is incorrect. \n ' + reasonMaps.join(' \n ')
1219      } : null
1220  }
1221}
1222
1223var MULTIPLE_PERCENTAGE_LENGTH_VALIDATOR = function MULTIPLE_PERCENTAGE_LENGTH_VALIDATOR(v) {
1224  v = (v || '').toString().trim()
1225  return MULTIPLE_POSITION_VALIDATOR(v, PERCENTAGE_LENGTH_VALIDATOR)
1226}
1227
1228var MULTIPLE_NUMBER_VALIDATOR = function MULTIPLE_NUMBER_VALIDATOR(v) {
1229  v = (v || '').toString().trim()
1230  return MULTIPLE_POSITION_VALIDATOR(v, NUMBER_VALIDATOR)
1231}
1232
1233var MUTIPLE_ANGLE_VALIDATOR = function MUTIPLE_ANGLE_VALIDATOR(v) {
1234  v = (v || '').toString().trim()
1235  return MULTIPLE_POSITION_VALIDATOR(v, ANGLE_VALIDATOR)
1236}
1237
1238var ROTATE3D_VALIDATOR = function ROTATE3D_VALIDATOR(v) {
1239  v = (v || '').toString().trim()
1240  let values = v.split(/,/g)
1241  if (values && values.length > 0) {
1242    let resultValues = []
1243    let childResult = void 0
1244    let reasonMaps = []
1245    let length = 0
1246    if (values.length != 4) {
1247      length = 2
1248      reasonMaps.push('The number of properties is 4, value ' + values + ' is incorrect.')
1249    } else {
1250      values.forEach(function (value, index) {
1251        if (index < 3) {
1252          childResult = NUMBER_VALIDATOR(value)
1253        } else {
1254          childResult = ANGLE_VALIDATOR(value)
1255        }
1256        if (typeof childResult.value == 'number' || typeof childResult.value == 'string') {
1257          resultValues.push(childResult.value)
1258        }
1259        let check = checkReason(childResult, index.toString(), value, length)
1260        length = check.length
1261        if (check.realReason !== null) {
1262          reasonMaps.push(check.realReason)
1263        }
1264      })
1265    }
1266
1267    return {
1268      value: length < 2 ? resultValues.join(' ') : null,
1269      reason: reasonMaps.length > 0 ?
1270        function (k, v) {
1271          return logTypes[length] + ': Value `' + v + '` of the `' + util.camelCaseToHyphened(k) +
1272            '` attribute is incorrect. \n ' + reasonMaps.join(' \n ')
1273        } : null
1274    }
1275  }
1276}
1277
1278var MULTIPLE_POSITION_VALIDATOR = function MULTIPLE_POSITION_VALIDATOR(v, validateFunction) {
1279  v = (v || '').toString().trim()
1280  let values = v.split(/,/g)
1281  if (values && values.length > 0) {
1282    let resultValues = []
1283    let childResult = void 0
1284    let reasonMaps = []
1285    let length = 0
1286    if (values.length > 16) {
1287      length = 2
1288      reasonMaps.push('The maximum number of properties is 16, value ' + values + ' is incorrect.')
1289    }
1290    values.forEach(function (value, index) {
1291      childResult = validateFunction(value)
1292      if (typeof childResult.value == 'number' || typeof childResult.value == 'string') {
1293        resultValues.push(childResult.value)
1294      }
1295      let check = checkReason(childResult, index.toString(), value, length)
1296      length = check.length
1297      if (check.realReason !== null) {
1298        reasonMaps.push(check.realReason)
1299      }
1300    })
1301    return {
1302      value: length < 2 ? resultValues.join(' ') : null,
1303      reason: reasonMaps.length > 0 ?
1304        function (k, v) {
1305          return logTypes[length] + ': Value `' + v + '` of the `' + util.camelCaseToHyphened(k) +
1306            '` attribute is incorrect. \n ' + reasonMaps.join(' \n ')
1307        } : null
1308    }
1309  }
1310}
1311
1312/**
1313 * generate a function to check whether a value is in `list`
1314 * - first value: default, could be removed
1315 * - not in `list`: incorrect
1316 *
1317 * @param  {Array} list
1318 * @return {function} a function(v) which returns a function to return
1319 * - value: string|null
1320 * - reason(k, v, result)
1321 */
1322function genEnumValidator(list) {
1323  return function ENUM_VALIDATOR(v, name) {
1324    v = (v || '').toString().trim()
1325    if (v.match(ID_REGEXP)) {
1326      return {value: v}
1327    }
1328
1329    var index = list.indexOf(v)
1330    if (index > 0) {
1331      return {value: v}
1332    }
1333    if (index === 0) {
1334      return {
1335        value: v,
1336        reason: name !== 'objectFit' ?
1337          function reason(k, v, result) {
1338            return 'NOTE: Value `' + v + '` is the default value of the `' + util.camelCaseToHyphened(k) +
1339              '` attribute (the value can be removed).'
1340          } : null
1341      }
1342    }
1343    else {
1344      return {
1345        value: null,
1346        reason: function reason(k, v, result) {
1347          return 'ERROR: The `' + util.camelCaseToHyphened(k) + '` attribute does not support value `' + v +
1348            '` (the supported value is `' + list.join('`|`') + '`).'
1349        }
1350      }
1351    }
1352  }
1353}
1354
1355var MASK_VALIDATOR = function MASK_VALIDATOR(v) {
1356  if (v.indexOf('url') >= 0) {
1357      return URL_VALIDATOR(v)
1358  } else {
1359      return BACKGROUND_VALIDATOR(v)
1360  }
1361}
1362
1363var BACKGROUND_VALIDATOR = function BACKGROUND_VALIDATOR(v) {
1364  v = (v || '').toString().trim()
1365  if (v.indexOf('-gradient') > 0) {
1366    let valueMatch = v.match(/(repeating-linear|linear).*?(?=\s*(repeating|linear)|$)/g)
1367    let resultValues = {
1368      values: []
1369    }
1370    if (valueMatch && valueMatch.length) {
1371      let reasonMaps = []
1372      let length = 0
1373      valueMatch.forEach(function (realValue) {
1374        let temp, gradientValidator
1375        if(realValue.indexOf("-gradient") >= 0){
1376          temp = realValue.indexOf("repeating") >= 0 ? "repeatingLinearGradient": "linearGradient"
1377          gradientValidator = backgroundValidatorMap[temp]
1378        }
1379        if (typeof gradientValidator == 'function') {
1380          let validateResult = gradientValidator(realValue)
1381          if (util.isValidValue(validateResult.value)) {
1382            let jsonValue = JSON.parse(validateResult.value)
1383            resultValues.values.push(jsonValue)
1384          }
1385          let check = checkReason(validateResult, temp, realValue, length)
1386          length = check.length
1387          if (check.realReason !== null) {
1388            reasonMaps.push(check.realReason)
1389          }
1390        } else {
1391          length = 2
1392          reasonMaps.push("background type '" + realValue + "' is not supported.")
1393        }
1394      })
1395      return {
1396        value: length < 2 ? JSON.stringify(resultValues) : null,
1397        reason: reasonMaps.length > 0 ?
1398          function (k, v) {
1399            return logTypes[length] + ': Value `' + v + '` of the `' + util.camelCaseToHyphened(k) +
1400              '` attribute is incorrect. \n ' + reasonMaps.join(' \n ')
1401          } : null
1402      }
1403    }
1404  }
1405  return {
1406    value: null,
1407    reason: function (k, v) {
1408      return 'ERROR: The format of value `' + v + '` of the `' + util.camelCaseToHyphened(k) +
1409        '` attribute is incorrect.'
1410    }
1411  }
1412}
1413
1414var LINEAR_GRADIENT_VALIDATOR = function LINEAR_GRADIENT_VALIDATOR(v) {
1415  v = (v || "").toString().trim()
1416  let result = {
1417    type: "",
1418    directions: ["to", "bottom"],
1419    values: []
1420  }
1421  let valueMatch = v.match(LINE_GRADIENT_ITEM_REGEXP)
1422  if (valueMatch) {
1423    let tempResult = {}
1424    let reasonMaps = []
1425    let length = 0
1426    let typeName = util.hyphenedToCamelCase(valueMatch[1])
1427    result.type = typeName
1428    let matchValues = valueMatch[2].split(/,/)
1429    if (LINE_GRADIENT_DIRECTION_REGEXP.test(matchValues[0])) {
1430      let directionValidator
1431      if (LINE_GRADIENT_TO_DIRECTION_REGEXP.test(matchValues[0])) {
1432        directionValidator = backgroundValidatorMap.linearGradientDirection
1433      } else if (matchValues[0].match(ANGLE_REGEXP)) {
1434        directionValidator = backgroundValidatorMap.linearGradientAngle
1435      }
1436      if (typeof directionValidator == "function") {
1437        tempResult = directionValidator(matchValues[0])
1438        if (util.isValidValue(tempResult.value)) {
1439          result.directions = tempResult.value.split(/\s+/)
1440        }
1441        let check = checkReason(tempResult, typeName, matchValues[0], length)
1442        length = check.length
1443        if (check.realReason !== null) {
1444          reasonMaps.push(check.realReason)
1445        }
1446        matchValues.splice(0, 1)
1447      }
1448    }
1449    if (matchValues.length > 0) {
1450      let colorStopResult = {}
1451      colorStopResult = backgroundValidatorMap.linearGradientColor(matchValues)
1452      if (util.isValidValue(colorStopResult.value)) {
1453        result.values = JSON.parse(colorStopResult.value)
1454      }
1455      let check = checkReason(colorStopResult, typeName, matchValues, length)
1456        length = check.length
1457        if (check.realReason !== null) {
1458          reasonMaps.push(check.realReason)
1459        }
1460    } else {
1461      length = 2
1462      reasonMaps.push("parameter '" + v + "' missing transition colors.")
1463    }
1464    return {
1465      value: length < 2 ? JSON.stringify(result) : null,
1466      reason: reasonMaps.length > 0 ?
1467        function (k, v) {
1468          return logTypes[length] + ': Value `' + v + '` of the `' + util.camelCaseToHyphened(k) +
1469            '` attribute is incorrect. \n  ' + reasonMaps.join('\n  ')
1470        }: null
1471    }
1472  }
1473  return {
1474    value: null,
1475    reason: function (k, v) {
1476      return 'ERROR: The format of value `' + v + '` of the `' + util.camelCaseToHyphened(k) +
1477        '` attribute is incorrect.'
1478    }
1479  }
1480}
1481
1482var ARRAY_COLOR_STOP_VALIDATOR = function ARRAY_COLOR_STOP_VALIDATOR(v) {
1483  v = (v || '').toString().trim()
1484  let values = v.match(ARRAY_COLOR_STOP_REGEXP)
1485  if (values && values.length > 1) {
1486    let resultValues = []
1487    let reasonMaps = []
1488    let length = 0
1489    processValueItem(v, values, resultValues, reasonMaps, length)
1490    return {
1491      value: length < 2 ? JSON.stringify(resultValues) : null,
1492      reason: reasonMaps.length > 0 ?
1493        function (k, v) {
1494          return logTypes[length] + ': Value `' + v + '` of the `' +
1495            util.camelCaseToHyphened(k) + '` attribute is incorrect. \n  ' + reasonMaps.join('\n  ')
1496        } : null
1497    }
1498  }
1499  return {
1500    value: null,
1501    reason: function (k, v) {
1502      return 'ERROR: The format of value `' + v + '` of the `'+ util.camelCaseToHyphened(k) +
1503        '` attribute is incorrect. Please specify at least two colors.'
1504    }
1505  }
1506}
1507
1508function processValueItem(v, values, resultValues, reasonMaps, length) {
1509  values.forEach(function (value, n) {
1510    let widthMatch = value.match(/[\s]+[-+0-9]+(px|%|vp|fp)?$/)
1511    let tempValues = []
1512    if (widthMatch) {
1513      let matchResult = PERCENTAGE_LENGTH_VALIDATOR(widthMatch[0])
1514      let index = value.indexOf(widthMatch[0])
1515      value = value.substring(0, index)
1516      if (util.isValidValue(matchResult.value)) {
1517        tempValues.push(matchResult.value)
1518      }
1519      let check = checkReason(matchResult, n.toString(), widthMatch[0], length)
1520      length = check.length
1521      if (check.realReason !== null) {
1522        reasonMaps.push(check.realReason)
1523      }
1524    }
1525    if (value) {
1526      let colorResult = COLOR_VAR_VALIDATOR(value)
1527      if (util.isValidValue(colorResult.value)) {
1528        tempValues.unshift(colorResult.value)
1529      }
1530      resultValues.push(tempValues.join(' '))
1531      let check = checkReason(colorResult, n.toString(), value, length)
1532      length = check.length
1533      if (check.realReason !== null) {
1534        reasonMaps.push(check.realReason)
1535      }
1536    } else {
1537      length = 2
1538      reasonMaps.push("parameter '" + v + "' is incorrect format.")
1539    }
1540  })
1541}
1542
1543function checkReason(result, k, v, length) {
1544  let reason
1545  if (result.reason) {
1546    reason = result.reason(k, v, result.value)
1547    if (reason) {
1548      let reasonType = reason.match(/^([A-Z]+):/)
1549      let index
1550      if (reasonType) {
1551        index = logTypes.indexOf(reasonType[1])
1552        if (logTypes.indexOf(reasonType[1]) > length) {
1553          length = index
1554        }
1555        reason = reason.replace(reasonType[0], '').trim()
1556      }
1557    }
1558  }
1559  return {
1560    length: length,
1561    realReason: reason ? reason : null
1562  }
1563}
1564
1565var ANGLE_VALIDATOR = function ANGLE_VALIDATOR(v) {
1566  v = (v || '').toString().trim()
1567  let match = v.match(ANGLE_REGEXP)
1568  if (match) {
1569    let unit = match[1]
1570    if (unit) {
1571      let angle = parseFloat(v)
1572      if (unit.toLowerCase() === 'rad') {
1573        return {
1574          value: Math.round(180 * angle / Math.PI) + SUPPORT_CSS_ANGLE_UNIT[0]
1575        }
1576      } else {
1577        if (SUPPORT_CSS_ANGLE_UNIT.indexOf(unit.toLowerCase()) >= 0) {
1578          return { value: v }
1579        } else {
1580          return {
1581            value: angle + SUPPORT_CSS_ANGLE_UNIT[0],
1582            reason: function(k, v) {
1583              return 'ERROR: The `' + util.camelCaseToHyphened(k) +
1584                '` attribute does not support `' + unit + '`. It only supports `' +
1585                JSON.stringify(SUPPORT_CSS_ANGLE_UNIT) + '`.'
1586            }
1587          }
1588        }
1589      }
1590    } else {
1591      return {
1592        value: parseFloat(v) + SUPPORT_CSS_ANGLE_UNIT[0],
1593        reason: function(k, v) {
1594          return 'WARNING: No unit is specified for the value `' + v +
1595            '` of the `' + util.camelCaseToHyphened(k) + '` attribute. The default unit is `' +
1596            SUPPORT_CSS_ANGLE_UNIT[0] + '`.'
1597        }
1598      }
1599    }
1600  }
1601  return {
1602    value: null,
1603    reason: function(k, v) {
1604      return 'ERROR: The `' + util.camelCaseToHyphened(k) + '` attribute does not support value `'
1605        + v + '` (only numbers are supported).'
1606    }
1607  }
1608}
1609
1610var GRADIENT_DIRECTION_VALIDATOR = function GRADIENT_DIRECTION_VALIDATOR(v) {
1611  v = (v || "").toString().trim()
1612  let values = v.split(/\s+/)
1613  let invalid = false
1614  let scaleY = ['top','bottom']
1615  let scaleX = ['left','right']
1616  let valueOrder = []
1617
1618  values.forEach(function (value) {
1619    if (value === 'to') {
1620      valueOrder.push(0)
1621    } else if (scaleY.includes(value)) {
1622      valueOrder.push(1)
1623    } else if (scaleX.includes(value)) {
1624      valueOrder.push(2)
1625    } else {
1626      invalid = true
1627    }
1628  })
1629  if (!invalid) {
1630    if (valueOrder[0] === 0 && valueOrder.length > 1 && valueOrder.length < 4 && valueOrder[1] !== 0) {
1631      if (valueOrder[2] && valueOrder[1] + valueOrder[2] !== 3) {
1632        invalid = true
1633      }
1634    }
1635  }
1636
1637  return {
1638    value: invalid ? null : v,
1639    reason: invalid ?
1640      function (k, v) {
1641        return 'ERROR: The format of value `' + v + '` of the `' + util.camelCaseToHyphened(k) +
1642          '` attribute is incorrect.'
1643      } : null
1644  }
1645}
1646
1647var URL_VALIDATOR = function URL_VALIDATOR(v) {
1648  v = (v || "").toString().trim()
1649  if (v.match(/^none$/i)) {
1650    return { value: "none" }
1651  }
1652  if (v.indexOf('@') >= 0) {
1653    let result
1654    // target format "@sys.media.sys_background_image" or '@sys.media.sys_background_image'
1655    let SysResourceTypeRefReg = /['"]\s*@sys\.media\.(?<resName>\w+)\s*['"]/
1656    result = SysResourceTypeRefReg.exec(v)
1657    if (result) {
1658      const resourceName = result.groups['resName']
1659      if (resourceName && OHOS_THEME_PROP_GROUPS[resourceName]) {
1660        return { value: "@sys.media." + OHOS_THEME_PROP_GROUPS[resourceName] }
1661      }
1662    }
1663    // target format "@app.media.customized_background_image" or '@app.media.customized_background_image'
1664    let AppResourceTypeRefReg = /['"]\s*@app\.media\.(?<resName>\w+)\s*['"]/
1665    result = AppResourceTypeRefReg.exec(v)
1666    if (result) {
1667      const resourceName = result.groups['resName']
1668      if (resourceName) {
1669        return { value: "@app.media." + resourceName}
1670      }
1671    }
1672  }
1673
1674  let matchValues = URL_REGEXP.exec(v)
1675  if (matchValues) {
1676    if(isLiteDevice){
1677      return { value: matchValues[0] }
1678    }else{
1679      if (matchValues[1].match(/^\.\.\/|^\.\//)) {
1680        return {
1681          value: matchValues[1],
1682          isRelative: true
1683        }
1684      }
1685      else {
1686        return { value: matchValues[1] }
1687      }
1688    }
1689  }
1690  else {
1691    return {
1692      value: null,
1693      reason: function (k, v) {
1694          return 'ERROR: Value `' + v + '` of the `' + util.camelCaseToHyphened(k) +
1695            '` attribute must be none or url(...).'
1696      }
1697    }
1698  }
1699}
1700
1701var NAME_VALIDATOR = function NAME_VALIDATOR(v) {
1702  v = (v || "").toString().trim()
1703  if (v.match(NAME_REGEXP)) {
1704    return  { value: v }
1705  } else {
1706    return {
1707      value: null,
1708      reason: function(k, v) {
1709        return 'ERROR: The format of value `' + v + '` of the `' +  util.camelCaseToHyphened(k) +
1710          '` attribute is incorrect.'
1711      }
1712    }
1713  }
1714}
1715
1716var ITERATIONCOUNT_VALIDATOR = function ITERATIONCOUNT_VALIDATOR(v) {
1717  v = (v || "").toString().trim()
1718  if (v.match(INT_REGEXP)) {
1719    return {
1720      value: parseInt(v, 10)
1721    }
1722  } else if (v.match(/^infinite$/)) {
1723    return { value: -1 }
1724  } else {
1725    return {
1726      value: null,
1727      reason: function(k, v) {
1728          return 'ERROR: The format of value `' + v + '` of the `' +  util.camelCaseToHyphened(k) +
1729            '` attribute is incorrect (only integers and infinity are supported).'
1730      }
1731    }
1732  }
1733}
1734
1735var BACKGROUND_SIZE_VALIDATOR = function BACKGROUND_SIZE_VALIDATOR(v) {
1736  v = (v || "").toString().trim()
1737  let values = v.split(/\s+/)
1738  const sizeReg = /auto|contain|cover/g
1739  if (values.length === 1) {
1740    if (/^(auto|contain|cover)$/.test(v)) {
1741      return { value: v }
1742    } else {
1743      return PERCENTAGE_LENGTH_VALIDATOR(v)
1744    }
1745  }
1746  if (values.length === 2 && !sizeReg.test(v)) {
1747    return SHORTHAND_VALIDATOR(v, PERCENTAGE_LENGTH_VALIDATOR)
1748  }
1749  return {
1750    value: null,
1751    reason: function(k, v) {
1752      return 'ERROR: Value `' + v + '` of the `' +  util.camelCaseToHyphened(k) + '` attribute is incorrect.'
1753    }
1754  }
1755}
1756
1757var BACKGROUND_POSITION_VALIDATOR = function BACKGROUND_POSITION_VALIDATOR(v) {
1758  v = (v || '').toString().trim()
1759  let values = v.split(/\s+/)
1760  const positionReg = /left|right|top|bottom|center/g
1761  if (values.length === 1) {
1762    if (/^(left|right|top|bottom|center)$/.test(v)) {
1763      return { value: v }
1764    } else {
1765      return PERCENTAGE_LENGTH_VALIDATOR(v)
1766    }
1767  }
1768  if (values.length === 2) {
1769    if (!positionReg.test(v)) {
1770      return SHORTHAND_VALIDATOR(v, PERCENTAGE_LENGTH_VALIDATOR)
1771    } else {
1772      return CHECK_BACKGROUND_POSITION(v)
1773    }
1774  }
1775  return {
1776    value: null,
1777    reason: function(k, v) {
1778      return 'ERROR: Value `' + v + '` of the `' +  util.camelCaseToHyphened(k) + '` attribute is incorrect.'
1779    }
1780  }
1781}
1782
1783var CHECK_BACKGROUND_POSITION = function CHECK_BACKGROUND_POSITION(v) {
1784  let values = v.split(/\s+/)
1785  let result = []
1786  let reasons = []
1787  let directions = []
1788  values.forEach(function(value, index) {
1789    if (/^(left|right|top|bottom|center)$/.test(value)) {
1790      result.push(value)
1791      if (checkDirection(value)) {
1792        directions.push(checkDirection(value))
1793      }
1794    } else {
1795      let tempResult = PERCENTAGE_LENGTH_VALIDATOR(value)
1796      if (tempResult.value) {
1797        result.push(value)
1798        if(index === 0){
1799          directions.push('horizon')
1800        } else {
1801          directions.push('vertical')
1802        }
1803      }
1804      if (tempResult.reason) {
1805        reasons.push(tempResult.reason)
1806      }
1807    }
1808  })
1809  if (directions.length === 2 && directions[0] === directions[1]) {
1810    reasons.push(function(k, v) {
1811      return 'ERROR: Value `' + v + '` of the `' + util.camelCaseToHyphened(k) + '` attribute is incorrect.'
1812    })
1813  }
1814  return {
1815    value: result.length > 0 ? result.join(' ') : null,
1816    reason: reasons.length > 0 ?
1817      function(k, v) {
1818        return reasons.map(function(res) {
1819          if (typeof res === 'function') {
1820            return res(k, v)
1821          }
1822        }).join('\n')
1823      }: null
1824  }
1825}
1826
1827function checkDirection(v) {
1828  const scaleXReg = /^(left|right)$/
1829  const scaleYReg = /^(top|bottom)$/
1830  if (scaleXReg.test(v)) {
1831    return 'horizon'
1832  }
1833  if (scaleYReg.test(v)) {
1834    return 'vertical'
1835  }
1836  return null
1837}
1838
1839var MYLOCATION_VALIDATOR = function MYLOCATION_VALIDATOR(v) {
1840  v = (v || "").toString().trim()
1841  let values = v.match(/\((.+?)\)/g) || []
1842  let replaceValue = null
1843  if (values.length) {
1844    for (let index = 0; index < values.length; index++) {
1845      replaceValue = values[index].replace(/\s*/g, "")
1846      v = v.replace(values[index], replaceValue);
1847    }
1848  }
1849  let realValues = v.split(/\s+/)
1850  let resultValues = []
1851  let valuesOrder = []
1852  let reason = null
1853  if (realValues && realValues.length <= 3) {
1854    realValues.forEach(function(realValue) {
1855      if (typeof COLOR_VAR_VALIDATOR(realValue).value == 'string') {
1856        resultValues.push(COLOR_VAR_VALIDATOR(realValue).value)
1857        valuesOrder.push(0)
1858      } else if (typeof URL_VALIDATOR(realValue).value == 'string') {
1859        resultValues.push(URL_VALIDATOR(realValue).value)
1860        valuesOrder.push(1)
1861      } else {
1862        reason = 'value'
1863      }
1864    })
1865    let n = -1
1866    valuesOrder.forEach(function(order) {
1867      if (order >= n) {
1868        n = order
1869      } else {
1870        if (!reason) {
1871          reason = 'order'
1872        }
1873      }
1874    })
1875    if (reason) {
1876      return {
1877        value : null,
1878        reason: function(k, v) {
1879          return reason == 'value' ?
1880            'ERROR: Value `' + v + '` of the `' + util.camelCaseToHyphened(k) +
1881            '` attribute does not meet the inspection standards for the color or url.' :
1882            'ERROR: Value `' + v + '` of the `' + util.camelCaseToHyphened(k) +
1883            '` attribute must be set in order(color color url).'
1884        }
1885      }
1886    }
1887    return {
1888      value: resultValues.join(" ")
1889    }
1890  }
1891  return {
1892    value: null,
1893    reason: function(k, v) {
1894      return 'ERROR: Value `' + v + '` of the `' + util.camelCaseToHyphened(k) + '` attribute is invalid.'
1895    }
1896  }
1897}
1898
1899var TRANSFORM_ORIGIN_VALIDATOR = function TRANSFORM_ORIGIN_VALIDATOR(v) {
1900  v = (v || "").toString().trim()
1901  let values = v.split(/\s+/)
1902  const positionReg = /left|right|top|bottom|center/g
1903  if (values.length == 1) {
1904    if (/^(left|right|top|bottom|center)$/.test(v)) {
1905      return { value: v }
1906    } else {
1907      return PERCENTAGE_LENGTH_VALIDATOR(v);
1908    }
1909  }
1910  if (values.length == 2) {
1911    if (!positionReg.test(v)) {
1912      return SHORTHAND_VALIDATOR(v, PERCENTAGE_LENGTH_VALIDATOR)
1913    } else {
1914      return CHECK_TRANSFORM_ORIGIN(values)
1915    }
1916  }
1917  return {
1918    value: null,
1919    reason: function (k, v) {
1920      return 'ERROR: Value `' + v + '` of the `' + util.camelCaseToHyphened(k) +
1921        '` attribute is invalid. such as left 100px or 50% bottom.'
1922    }
1923  }
1924}
1925
1926var CHECK_TRANSFORM_ORIGIN = function CHECK_TRANSFORM_ORIGIN(values) {
1927  let result = []
1928  let reasons = []
1929  let directions = []
1930  values.forEach(function (value, index) {
1931    if (/^(left|right|top|bottom|center)$/.test(value)) {
1932      result.push(value)
1933      directions.push(checkDirection(value))
1934    } else {
1935      let tempResult = PERCENTAGE_LENGTH_VALIDATOR(value)
1936      if (tempResult.value) {
1937        result.push(value)
1938        if (index === 0) {
1939          directions.push('horizon')
1940        } else {
1941          directions.push('vertical')
1942        }
1943      }
1944      if (tempResult.reason) {
1945        reasons.push(tempResult.reason)
1946      }
1947    }
1948  })
1949  if (directions.length != 2 || directions.length === 2 &&
1950    (directions[0] === 'vertical' || directions[1] === 'horizon')) {
1951    reasons.push(function (k, v) {
1952      return 'ERROR: Value `' + v + '` of the `' + util.camelCaseToHyphened(k) + '` attribute is incorrect.'
1953    })
1954  }
1955  return {
1956    value: result.length > 0 ? result.join(' ') : null,
1957    reason: reasons.length > 0 ?
1958      function (k, v) {
1959        return reasons.map(function (res) {
1960          if (typeof res === 'function') {
1961            return res(k, v)
1962          }
1963        }).join('\n')
1964      } : null
1965  }
1966}
1967
1968var GRID_VALIDATOR = function GRID_VALIDATOR(v) {
1969  v = (v || '').toString().trim()
1970  if (v == 'auto' || v == 'auto-fill') {
1971    return { value: v }
1972  } else {
1973    return LENGTH(v, SUPPORT_CSS_GRID_UNIT)
1974  }
1975}
1976
1977var GRID_TEMPLATE_VALIDATOR = function GRID_TEMPLATE_VALIDATOR(v) {
1978  v = (v || '').toString().trim()
1979  if (v.match(/^repeat/)) {
1980    let str = []
1981    if (v.match(/auto-fill/)) {
1982      let match = v.match(/^repeat\((.+),(.+)\)/)
1983      str.push(match[1].trim(), match[2].trim())
1984      return GRID_TEMPLATE_VALIDATOR(str.join(' '))
1985    } else {
1986      let match = v.match(/^repeat\((\d+),(.+)\)/)
1987      if (match[1] && match[2]) {
1988        let n = match[1]
1989          while (n > 0) {
1990            str.push(match[2].trim())
1991            n--
1992          }
1993        return GRID_TEMPLATE_VALIDATOR(str.join(' '))
1994      }
1995      else {
1996        return {
1997          value: null,
1998          reason: function reason(k, v, result) {
1999            return 'ERROR: The `' + util.camelCaseToHyphened(k) + '` attribute does not support value `' + v + '`.'
2000          }
2001        }
2002      }
2003    }
2004  }
2005  else {
2006    let value = []
2007    let reason = []
2008    let results = v.split(/\s+/).map(GRID_VALIDATOR)
2009    for (let i = 0; i < results.length; ++i) {
2010      let res = results[i]
2011      if (!res.value) {
2012        value = null
2013        reason = res.reason
2014        break
2015      }
2016      value.push(res.value)
2017      if (res.reason) {
2018        reason.push(res.reason)
2019      }
2020    }
2021
2022    if (!value) {
2023      return {
2024        value: value,
2025        reason: reason
2026      }
2027    } else {
2028      return {
2029        value: value.join(' '),
2030        reason: reason.length > 0 ? function(k, v, result) {
2031          return reason.map(function (res) {
2032            if (typeof res === 'function') {
2033              return res(k, v, result)
2034            }
2035          }).join('\n')
2036        } : null
2037      }
2038    }
2039  }
2040}
2041
2042var DATE_VALIDATOR = function DATE_VALIDATOR(v) {
2043  v = (v || '').toString().trim()
2044  if (DATE_REGEXP.test(v)) {
2045    return { value: v }
2046  } else {
2047    return {
2048      value: null,
2049      reason:function (k, v, result) {
2050        return 'ERROR: The format of value `' + v + '` of the `' +
2051          util.camelCaseToHyphened(k) + '` attribute is incorrect.'
2052      }
2053    }
2054  }
2055}
2056
2057var FILTER_VALIDATOR = function FILTER_VALIDATOR(v) {
2058  v = (v || '').toString().trim().replace(/\s*/g, '')
2059  if (FILTER_REGEXP.test(v)) {
2060    return { value: v }
2061  } else {
2062    return {
2063      value: null,
2064      reason:function (k, v, result) {
2065        return 'ERROR: The format of value `' + v + '` of the `' +
2066          util.camelCaseToHyphened(k) + '` attribute is incorrect.'
2067      }
2068    }
2069  }
2070}
2071
2072var FILTER_PERCENTAGE_VALIDATOR = function FILTER_PERCENTAGE_VALIDATOR(v) {
2073  v = (v || '').toString().trim().replace(/\s*,\s*/g, " ")
2074  if (FILTER_PERCENTAGE_REGEXP.test(v)) {
2075    return { value: v }
2076  }
2077  if (FILTER_STYLE_REGEXP.test(v)) {
2078    const values = v.trim().split(/\s+/)
2079    if(values[1] && values.length === 2){
2080      const blurStyleValidator = genEnumValidator(['small_light', 'medium_light', 'large_light',
2081        'xlarge_light', 'small_dark', 'medium_dark', 'large_dark', 'xlarge_dark'])
2082      const blurStyleResult = blurStyleValidator(values[1])
2083      if(util.isValidValue(blurStyleResult.value)){
2084        return { value: v }
2085      }
2086      let reasonMaps = [];
2087      let length = 0;
2088      let check = checkReason(blurStyleResult, 'window-filter', values[1], length)
2089      if(check.realReason !== null) {
2090        reasonMaps.push(check.realReason)
2091      }
2092      return {
2093        value: check.length < 2 ? JSON.stringify(blurStyleResult.value) : null,
2094        reason: function(k, v) {
2095          return 'ERROR: ' + reasonMaps
2096        }
2097      }
2098    }
2099  }
2100  return {
2101    value: null,
2102    reason:function (k, v, result) {
2103      return 'ERROR: The format of value `' + v + '` of the `' + util.camelCaseToHyphened(k) +
2104        '` attribute is incorrect.'
2105    }
2106  }
2107}
2108
2109var BORDER_IMAGE_VALIDATOR = function BORDER_IMAGE_VALIDATOR(v) {
2110  var regexp = /(repeating-linear|linear).*?(?=\s*(repeating|linear)|$)/g;
2111  if (regexp.test(v)) {
2112    return BORDER_IMAGE_GRADIENT_VALIDATOR(v);
2113  } else {
2114    return BORDER_IMAGE_URL_VALIDATOR(v);
2115  }
2116}
2117
2118var BORDER_IMAGE_URL_VALIDATOR = function BORDER_IMAGE_URL_VALIDATOR(v) {
2119  let base = {
2120    values: []
2121  };
2122  let value = {
2123    url: "",
2124    repeat: ""
2125  };
2126  var URL_REGEXP_FIRST = /^url\(\s*['"]?\s*([^()]+?)\s*['"]?\s*\)(.*)/;
2127  var regexpFirst = /(stretch|round|repeat|space)$/;
2128  var URL_REGEXP_SECOND = /^(.*)(stretch|round|repeat|space)$/;
2129  let result;
2130  result = URL_REGEXP_FIRST.exec(v);
2131  if (regexpFirst.test(result[2])) {
2132    let res = URL_REGEXP_SECOND.exec(result[2]);
2133    value = BORDER_IMAGE_NOL(res[1]);
2134    value.repeat = res[2];
2135  } else {
2136    var reg = /px|%/;
2137    if (reg.test(result[2])) {
2138      value = BORDER_IMAGE_NOL(result[2]);
2139    }
2140  }
2141  value.url = result[1];
2142  base.values.push(value);
2143  return {
2144    value: JSON.stringify(base)
2145  };
2146}
2147
2148var BORDER_IMAGE_NOL = function BORDER_IMAGE_NOL(v) {
2149  let value = {
2150    url: "",
2151    repeat: ""
2152  };
2153  var reg = /px|%/;
2154  if (!reg.test(v)) {
2155    return value;
2156  }
2157  let num = v.split(/\//);
2158  switch (num.length) {
2159    case 1:
2160    value.slice = BORDER_IMAGE_SPLIT(num[0]);
2161    break;
2162    case 2:
2163    value.slice = BORDER_IMAGE_SPLIT(num[0]);
2164    value.width = BORDER_IMAGE_SPLIT(num[1]);
2165    break;
2166    case 3:
2167    value.slice = BORDER_IMAGE_SPLIT(num[0]);
2168    value.width = BORDER_IMAGE_SPLIT(num[1]);
2169    value.outset = BORDER_IMAGE_SPLIT(num[2]);
2170    break;
2171  }
2172  return value;
2173}
2174
2175var BORDER_IMAGE_SPLIT = function BORDER_IMAGE_SPLIT(v) {
2176  const NUM_REGEXP = SHORTHAND_PERCENTAGE_LENGTH_VALIDATOR(v);
2177  let result = [];
2178  const value = NUM_REGEXP.value.split(/\s/);
2179  value.forEach(element => {
2180    result.push(element);
2181  });
2182  return result;
2183}
2184
2185var BORDER_IMAGE_GRADIENT_VALIDATOR = function BORDER_IMAGE_GRADIENT_VALIDATOR(v) {
2186  v = (v || "").toString().trim()
2187  var BORDER_IMAGE_GRADIENT_ITEM_REGEXP = /^([0-9a-zA-Z-]+)\((.*)\)(.*)/;
2188  let base = {
2189    values: []
2190  }
2191  let valueMatch = v.match(BORDER_IMAGE_GRADIENT_ITEM_REGEXP)
2192  if (valueMatch) {
2193    const gradientStr = valueMatch[1].toString() + '(' + valueMatch[2].toString() + ')';
2194    const gradient = LINEAR_GRADIENT_VALIDATOR(gradientStr);
2195    let value = {};
2196    if (util.isValidValue(gradient.value)) {
2197      value = JSON.parse(gradient.value)
2198    }
2199    var reg = /px|%/;
2200    if (valueMatch[3].match(reg)) {
2201      value.slice = BORDER_IMAGE_SPLIT(valueMatch[3]);
2202    }
2203    base.values.push(value);
2204    return {
2205      value: JSON.stringify(base),
2206      reason: gradient.reason
2207    }
2208  }
2209  return {
2210    value: null,
2211    reason: function(k, v) {
2212      return 'ERROR: The format of value `' + v + '` of the `' + util.camelCaseToHyphened(k)
2213        + '` attribute is incorrect.'
2214    }
2215  }
2216}
2217
2218var Color_Picker_VALIDATOR = function Color_Picker_VALIDATOR(v) {
2219  v = (v || "").toString().trim()
2220  let num = v.split(/\//);
2221  let base = {
2222    cValues: []
2223  }
2224  num.forEach(element => {
2225    base.cValues.push(COLOR_VAR_VALIDATOR(element).value);
2226  });
2227  return {
2228    value: JSON.stringify(base)
2229  }
2230}
2231
2232var RICH_PROP_NAME_GROUPS = {
2233  boxModel: {
2234    width: PERCENTAGE_LENGTH_VALIDATOR,
2235    height: PERCENTAGE_LENGTH_VALIDATOR,
2236    overflow: genEnumValidator(['auto', 'hidden','scroll','visible']),
2237    padding: SHORTHAND_PERCENTAGE_LENGTH_VALIDATOR,
2238    paddingLeft: PERCENTAGE_LENGTH_VALIDATOR,
2239    paddingRight: PERCENTAGE_LENGTH_VALIDATOR,
2240    paddingTop: PERCENTAGE_LENGTH_VALIDATOR,
2241    paddingBottom: PERCENTAGE_LENGTH_VALIDATOR,
2242    paddingStart: PERCENTAGE_LENGTH_VALIDATOR,
2243    paddingEnd: PERCENTAGE_LENGTH_VALIDATOR,
2244    margin: SHORTHAND_AUTO_PERCENTAGE_LENGTH_VALIDATOR,
2245    marginLeft: AUTO_PERCENTAGE_LENGTH_VALIDATOR,
2246    marginRight: AUTO_PERCENTAGE_LENGTH_VALIDATOR,
2247    marginTop: AUTO_PERCENTAGE_LENGTH_VALIDATOR,
2248    marginBottom: AUTO_PERCENTAGE_LENGTH_VALIDATOR,
2249    marginStart: PERCENTAGE_LENGTH_VALIDATOR,
2250    marginEnd: PERCENTAGE_LENGTH_VALIDATOR,
2251    placeholderColor: COLOR_VAR_VALIDATOR,
2252    selectedColor: COLOR_VAR_VALIDATOR,
2253    caretColor: COLOR_VAR_VALIDATOR,
2254    strokeWidth: LENGTH_VALIDATOR,
2255    progressColor: COLOR_VAR_VALIDATOR,
2256    slideWidth: LENGTH_VALIDATOR,
2257    slideMargin: LENGTH_VALIDATOR,
2258    resizeMode: genEnumValidator(['cover', 'contain', 'stretch', 'center']),
2259    columns: NUMBER_VALIDATOR,
2260    columnSpan: NUMBER_VALIDATOR,
2261    maskColor: COLOR_VAR_VALIDATOR,
2262    mylocation: MYLOCATION_VALIDATOR,
2263    mylocationFillColor: COLOR_VAR_VALIDATOR,
2264    mylocationStrokeColor: COLOR_VAR_VALIDATOR,
2265    mylocationIconPath: URL_VALIDATOR,
2266    displayIndex: NUMBER_VALIDATOR,
2267    aspectRatio: NUMBER_VALIDATOR,
2268    minWidth: PERCENTAGE_LENGTH_VALIDATOR,
2269    minHeight: PERCENTAGE_LENGTH_VALIDATOR,
2270    maxWidth: PERCENTAGE_LENGTH_VALIDATOR,
2271    maxHeight: PERCENTAGE_LENGTH_VALIDATOR,
2272    flexWeight: NUMBER_VALIDATOR,
2273    boxShadow: BOX_SHADOW_VALIDATOR,
2274    boxShadowH: LENGTH_VALIDATOR,
2275    boxShadowV: LENGTH_VALIDATOR,
2276    boxShadowBlur: LENGTH_VALIDATOR,
2277    boxShadowSpread: LENGTH_VALIDATOR,
2278    boxShadowColor: COLOR_VAR_VALIDATOR,
2279    filter: FILTER_VALIDATOR,
2280    backdropFilter: FILTER_VALIDATOR,
2281    windowFilter: FILTER_PERCENTAGE_VALIDATOR,
2282    transitionEffect: genEnumValidator(['unfold', 'none'])
2283  },
2284  div: {
2285    gridTemplateColumns: GRID_TEMPLATE_VALIDATOR,
2286    gridTemplateRows: GRID_TEMPLATE_VALIDATOR,
2287    gridGap: LENGTH_VALIDATOR,
2288    gridColumnsGap: LENGTH_VALIDATOR,
2289    gridRowsGap: LENGTH_VALIDATOR,
2290    gridRowStart: NUMBER_VALIDATOR,
2291    gridRowEnd: NUMBER_VALIDATOR,
2292    gridColumnStart: NUMBER_VALIDATOR,
2293    gridColumnEnd: NUMBER_VALIDATOR,
2294    gridAutoFlow: genEnumValidator(['row', 'column'])
2295  },
2296  border: {
2297    border: BORDER_VALIDATOR,
2298    borderWidth: SHORTHAND_LENGTH_VALIDATOR,
2299    borderLeftWidth: LENGTH_VALIDATOR,
2300    borderTopWidth: LENGTH_VALIDATOR,
2301    borderRightWidth: LENGTH_VALIDATOR,
2302    borderBottomWidth: LENGTH_VALIDATOR,
2303    borderColor: SHORTHAND_COLOR_VALIDATOR,
2304    borderLeftColor: COLOR_VAR_VALIDATOR,
2305    borderTopColor: COLOR_VAR_VALIDATOR,
2306    borderRightColor: COLOR_VAR_VALIDATOR,
2307    borderBottomColor: COLOR_VAR_VALIDATOR,
2308    borderStyle: SHORTHAND_STYLE_VALIDATOR,
2309    borderTopStyle: STYLE_VALIDATOR,
2310    borderRightStyle: STYLE_VALIDATOR,
2311    borderBottomStyle: STYLE_VALIDATOR,
2312    borderLeftStyle: STYLE_VALIDATOR,
2313    borderRadius: SHORTHAND_LENGTH_VALIDATOR,
2314    borderBottomLeftRadius: LENGTH_VALIDATOR,
2315    borderBottomRightRadius: LENGTH_VALIDATOR,
2316    borderTopLeftRadius: LENGTH_VALIDATOR,
2317    borderTopRightRadius: LENGTH_VALIDATOR,
2318    borderLeft: BORDER_VALIDATOR,
2319    borderRight: BORDER_VALIDATOR,
2320    borderTop: BORDER_VALIDATOR,
2321    borderBottom: BORDER_VALIDATOR,
2322    borderImage: BORDER_IMAGE_VALIDATOR,
2323    borderImageSource: URL_VALIDATOR,
2324    borderImageOutset: SHORTHAND_PERCENTAGE_LENGTH_VALIDATOR,
2325    borderImageSlice: SHORTHAND_PERCENTAGE_LENGTH_VALIDATOR,
2326    borderImageWidth: SHORTHAND_PERCENTAGE_LENGTH_VALIDATOR,
2327    borderImageRepeat: genEnumValidator(['stretch', 'round', 'repeat', 'space'])
2328  },
2329  indicator: {
2330    indicatorSize: LENGTH_VALIDATOR,
2331    indicatorTop: PERCENTAGE_LENGTH_VALIDATOR,
2332    indicatorRight: PERCENTAGE_LENGTH_VALIDATOR,
2333    indicatorBottom: PERCENTAGE_LENGTH_VALIDATOR,
2334    indicatorLeft: PERCENTAGE_LENGTH_VALIDATOR,
2335    indicatorColor: COLOR_VAR_VALIDATOR,
2336    indicatorSelectedColor: COLOR_VAR_VALIDATOR
2337  },
2338  animation: {
2339    animationDuration: TIME_VALIDATOR,
2340    animationDelay: TIME_VALIDATOR,
2341    animationName: NAME_VALIDATOR,
2342    animationTimingFunction: TRANSITION_TIMING_FUNCTION_VALIDATOR,
2343    animationIterationCount: ITERATIONCOUNT_VALIDATOR,
2344    animationFillMode: genEnumValidator(['none', 'forwards', 'backwards', 'both']),
2345    animationPlayState: genEnumValidator(['running', 'paused']),
2346    animationDirection: genEnumValidator(['normal', 'reverse', 'alternate', 'alternate-reverse']),
2347    animation: ANIMATION_VALIDATOR,
2348  },
2349  flexbox: {
2350    flex: genEnumValidator(['none', 'auto', 'initial']),
2351    flexWrap: genEnumValidator(['nowrap', 'wrap']),
2352    flexGrow: NUMBER_VALIDATOR,
2353    flexShrink: NUMBER_VALIDATOR,
2354    flexBasis: LENGTH_VALIDATOR,
2355    flexDirection: genEnumValidator(['row', 'column']),
2356    justifyContent: genEnumValidator(['flex-start', 'flex-end', 'center', 'space-between',
2357      'space-around', 'space-evenly']),
2358    alignItems: genEnumValidator(['stretch', 'flex-start', 'flex-end', 'center', 'baseline']),
2359    alignContent: genEnumValidator(['stretch', 'flex-start', 'flex-end', 'center', 'space-between', 'space-around']),
2360    alignSelf: genEnumValidator(["auto", "flex-start", "flex-end", "center", "baseline", "stretch"])
2361  },
2362  position: {
2363    position: genEnumValidator(['relative', 'fixed', 'absolute']),
2364    top: PERCENTAGE_LENGTH_VALIDATOR,
2365    bottom: PERCENTAGE_LENGTH_VALIDATOR,
2366    left: PERCENTAGE_LENGTH_VALIDATOR,
2367    right: PERCENTAGE_LENGTH_VALIDATOR,
2368    zIndex: INTEGER_VALIDATOR
2369  },
2370  common: {
2371    opacity: NUMBER_VALIDATOR,
2372    background: BACKGROUND_VALIDATOR,
2373    backgroundColor: COLOR_VAR_VALIDATOR,
2374    backgroundImage: URL_VALIDATOR,
2375    backgroundRepeat: genEnumValidator(['repeat', 'no-repeat', 'repeat-x', 'repeat-y']),
2376    visibility: genEnumValidator(['visible', 'hidden']),
2377    objectFit: genEnumValidator(['cover', 'fill', 'contain', 'none', 'scale-down']),
2378    backgroundSize: BACKGROUND_SIZE_VALIDATOR,
2379    backgroundPosition: BACKGROUND_POSITION_VALIDATOR,
2380    display: genEnumValidator(['flex', 'none', 'grid']),
2381    imageFill: COLOR_VAR_VALIDATOR,
2382    maskImage: MASK_VALIDATOR,
2383    maskPosition: BACKGROUND_POSITION_VALIDATOR,
2384    maskSize: BACKGROUND_SIZE_VALIDATOR
2385  },
2386  text: {
2387    lines: INTEGER_VALIDATOR,
2388    color: COLOR_VAR_VALIDATOR,
2389    fontSize: LENGTH_VALIDATOR,
2390    fontStyle: genEnumValidator(['normal', 'italic']),
2391    fontFamily: ANYTHING_VALIDATOR,
2392    fontWeight: genEnumValidator(['normal', 'lighter', 'bold', 'bolder', "medium", "regular",
2393      '100', '200', '300', '400', '500', '600', '700', '800', '900']),
2394    textDecoration: genEnumValidator(['none', 'underline', 'line-through']),
2395    textAlign: genEnumValidator(['start', 'end', 'left', 'center', 'right']),
2396    textOverflow: genEnumValidator(['clip', 'ellipsis']),
2397    textIndent: TEXT_INDENT_VALIDATOR,
2398    lineHeight: TEXT_LINE_HEIGHT_VALIDATOR,
2399    letterSpacing: LENGTH_VALIDATOR,
2400    minLines: NUMBER_VALIDATOR,
2401    maxLines: ANYTHING_VALIDATOR,
2402    minFontSize: LENGTH_VALIDATOR,
2403    maxFontSize: LENGTH_VALIDATOR,
2404    fontSizeStep: LENGTH_VALIDATOR,
2405    preferFontSizes: ARRAY_LENGTH_VALIDATOR,
2406    adaptHeight: genEnumValidator(['true', 'false']),
2407    allowScale: genEnumValidator(['true', 'false']),
2408    fontVariant: ANYTHING_VALIDATOR,
2409    id: ANYTHING_VALIDATOR,
2410    x: PERCENTAGE_LENGTH_VALIDATOR,
2411    y: PERCENTAGE_LENGTH_VALIDATOR,
2412    dx: PERCENTAGE_LENGTH_VALIDATOR,
2413    dy: PERCENTAGE_LENGTH_VALIDATOR,
2414    rotate: NUMBER_VALIDATOR,
2415    fill: COLOR_VAR_VALIDATOR,
2416    fillOpacity: NUMBER_VALIDATOR,
2417    stroke: COLOR_VAR_VALIDATOR,
2418    strokeOpacity: NUMBER_VALIDATOR,
2419    strokeWidth: LENGTH_VALIDATOR,
2420    fontFeatureSettings: ANYTHING_VALIDATOR
2421  },
2422  calendar: {
2423    boundaryColOffset: LENGTH_VALIDATOR,
2424    boundaryRowOffset: LENGTH_VALIDATOR,
2425    colSpace: LENGTH_VALIDATOR,
2426    dailyFiveRowSpace: LENGTH_VALIDATOR,
2427    dayColor: COLOR_VAR_VALIDATOR,
2428    dayFontSize: LENGTH_VALIDATOR,
2429    dayHeight: LENGTH_VALIDATOR,
2430    dayWidth: LENGTH_VALIDATOR,
2431    focusedAreaBackgroundColor: COLOR_VAR_VALIDATOR,
2432    focusedAreaRadius: LENGTH_VALIDATOR,
2433    focusedDayColor: COLOR_VAR_VALIDATOR,
2434    focusedLunarColor: COLOR_VAR_VALIDATOR,
2435    gregorianCalendarHeight: LENGTH_VALIDATOR,
2436    lunarColor: COLOR_VAR_VALIDATOR,
2437    lunarDayFontSize: LENGTH_VALIDATOR,
2438    lunarDayYAxisOffset: LENGTH_VALIDATOR,
2439    lunarHeight: LENGTH_VALIDATOR,
2440    markLunarColor: COLOR_VAR_VALIDATOR,
2441    nonCurrentMonthDayColor: COLOR_VAR_VALIDATOR,
2442    nonCurrentMonthLunarColor: COLOR_VAR_VALIDATOR,
2443    nonCurrentMonthOffDayMarkColor: COLOR_VAR_VALIDATOR,
2444    nonCurrentMonthWorkDayMarkColor: COLOR_VAR_VALIDATOR,
2445    offDayMarkColor: COLOR_VAR_VALIDATOR,
2446    offDayMarkSize: LENGTH_VALIDATOR,
2447    scheduleMarkerRadius: LENGTH_VALIDATOR,
2448    scheduleMarkerXAxisOffset: LENGTH_VALIDATOR,
2449    scheduleMarkerYAxisOffset: LENGTH_VALIDATOR,
2450    underscoreLength: LENGTH_VALIDATOR,
2451    underscoreWidth: LENGTH_VALIDATOR,
2452    underscoreXAxisOffset: LENGTH_VALIDATOR,
2453    underscoreYAxisOffset: LENGTH_VALIDATOR,
2454    weekAndDayRowSpace: LENGTH_VALIDATOR,
2455    weekColor: COLOR_VAR_VALIDATOR,
2456    weekFontSize: LENGTH_VALIDATOR,
2457    weekHeight: LENGTH_VALIDATOR,
2458    weekWidth: LENGTH_VALIDATOR,
2459    weekendDayColor: COLOR_VAR_VALIDATOR,
2460    weekendLunarColor: COLOR_VAR_VALIDATOR,
2461    workDayMarkColor: COLOR_VAR_VALIDATOR,
2462    workDayMarkSize: LENGTH_VALIDATOR,
2463    workStateHorizontalMovingDistance: LENGTH_VALIDATOR,
2464    workStateVerticalMovingDistance: LENGTH_VALIDATOR,
2465    workStateWidth: LENGTH_VALIDATOR
2466  },
2467  rating: {
2468    starBackground: URL_VALIDATOR,
2469    starForeground: URL_VALIDATOR,
2470    starSecondary: URL_VALIDATOR,
2471    rtlFlip: genEnumValidator(['true', 'false'])
2472  },
2473  transition: {
2474    transitionProperty: TRANSITION_PROPERTY_VALIDATOR,
2475    transitionDuration: TRANSITION_INTERVAL_VALIDATOR,
2476    transitionDelay: TRANSITION_INTERVAL_VALIDATOR,
2477    transitionEnter: NAME_VALIDATOR,
2478    transitionExit: NAME_VALIDATOR,
2479    transitionDuration: TIME_VALIDATOR,
2480    transitionTimingFunction: TRANSITION_TIMING_FUNCTION_VALIDATOR
2481  },
2482  transform: {
2483    transform: TRANSFORM_VALIDATOR,
2484    transformOrigin: TRANSFORM_ORIGIN_VALIDATOR
2485  },
2486  customized: {
2487    itemSize: LENGTH_VALIDATOR,
2488    itemColor: COLOR_VAR_VALIDATOR,
2489    itemSelectedColor: COLOR_VAR_VALIDATOR,
2490    textColor: COLOR_VAR_VALIDATOR,
2491    timeColor: COLOR_VAR_VALIDATOR,
2492    textHighlightColor: COLOR_VAR_VALIDATOR
2493  },
2494  list: {
2495    itemExtent: PERCENTAGE_LENGTH_VALIDATOR,
2496    fadeColor: COLOR_VAR_VALIDATOR,
2497    dividerColor: COLOR_VAR_VALIDATOR,
2498    dividerHeight: LENGTH_VALIDATOR,
2499    dividerLength: LENGTH_VALIDATOR,
2500    dividerOrigin: LENGTH_VALIDATOR,
2501    scrollbarColor: COLOR_VALIDATOR,
2502    scrollbarWidth: LENGTH_VALIDATOR,
2503    scrollbarOffset: ARRAY_LENGTH_VALIDATOR
2504  },
2505  progress: {
2506    secondaryColor: COLOR_VAR_VALIDATOR,
2507    scaleWidth: LENGTH_VALIDATOR,
2508    scaleNumber: NUMBER_VALIDATOR,
2509    startAngle: ANGLE_VALIDATOR,
2510    totalAngle: ANGLE_VALIDATOR,
2511    centerX: LENGTH_VALIDATOR,
2512    centerY: LENGTH_VALIDATOR,
2513    radius: LENGTH_VALIDATOR,
2514    direction: genEnumValidator(['start-to-end', 'end-to-start']),
2515    sections: NAME_VALIDATOR,
2516    colors: ARRAY_COLOR_VALIDATOR,
2517    weights: ARRAY_NUMBER_VALIDATOR
2518  },
2519  navigation: {
2520    titleColor: COLOR_VAR_VALIDATOR,
2521    subtitleColor: COLOR_VAR_VALIDATOR
2522  },
2523  button: {
2524    iconWidth: LENGTH_VALIDATOR,
2525    iconHeight: LENGTH_VALIDATOR
2526  },
2527  switch: {
2528    textonColor: COLOR_VAR_VALIDATOR,
2529    textoffColor: COLOR_VAR_VALIDATOR,
2530    textPadding: LENGTH_VALIDATOR
2531  },
2532  share: {
2533    sharedTransitionEffect: genEnumValidator(['exchange', 'static']),
2534    sharedTransitionName: NAME_VALIDATOR,
2535    sharedTransitionTimingFunction: TRANSITION_TIMING_FUNCTION_VALIDATOR
2536  },
2537  image: {
2538    matchTextDirection: genEnumValidator(['false', 'true']),
2539    fitOriginalSize: genEnumValidator(['false', 'true']),
2540  },
2541  divider: {
2542    lineCap: genEnumValidator(['butt', 'square', 'round'])
2543  },
2544  picker: {
2545    columnHeight: LENGTH_VALIDATOR
2546  },
2547  pickerView: {
2548    selectedFontSize: LENGTH_VALIDATOR,
2549    selectedFontFamily: ANYTHING_VALIDATOR,
2550    focusColor: COLOR_VAR_VALIDATOR,
2551    focusFontSize: LENGTH_VALIDATOR,
2552    focusFontFamily: ANYTHING_VALIDATOR,
2553    disappearFontSize: LENGTH_VALIDATOR,
2554    disappearColor: COLOR_VAR_VALIDATOR
2555  },
2556  colorpicker: {
2557    colorPickerColor: Color_Picker_VALIDATOR
2558  },
2559  colorpickerView: {
2560    colorPickerColor: Color_Picker_VALIDATOR
2561  },
2562  slider: {
2563    blockColor: COLOR_VAR_VALIDATOR,
2564  },
2565  badge: {
2566    badgeColor: COLOR_VAR_VALIDATOR,
2567    badgeSize: LENGTH_VALIDATOR
2568  },
2569  ellipse: {
2570    fill: COLOR_VAR_VALIDATOR,
2571    fillOpacity: NUMBER_VALIDATOR,
2572    fillRule: genEnumValidator(['nonzero', 'evenodd']),
2573    opacity: NUMBER_VALIDATOR,
2574    stroke: COLOR_VAR_VALIDATOR,
2575    strokeDasharray: ANYTHING_VALIDATOR,
2576    strokeDashoffset: LENGTH_VALIDATOR,
2577    strokeLinejoin: genEnumValidator(['bevel', 'miter', 'round']),
2578    strokeLinecap: genEnumValidator(['butt', 'round', 'square']),
2579    strokeMiterlimit: NUMBER_VALIDATOR,
2580    strokeOpacity: NUMBER_VALIDATOR,
2581    strokeWidth: LENGTH_VALIDATOR,
2582    transform: TRANSFORM_VALIDATOR,
2583    id: ANYTHING_VALIDATOR,
2584    cx: PERCENTAGE_LENGTH_VALIDATOR,
2585    cy: PERCENTAGE_LENGTH_VALIDATOR,
2586    rx: PERCENTAGE_LENGTH_VALIDATOR,
2587    ry: PERCENTAGE_LENGTH_VALIDATOR
2588  },
2589  rect: {
2590    id: ANYTHING_VALIDATOR,
2591    fill: COLOR_VAR_VALIDATOR,
2592    fillOpacity: NUMBER_VALIDATOR,
2593    fillRule: genEnumValidator(['nonzero', 'evenodd']),
2594    opacity: NUMBER_VALIDATOR,
2595    strokeDasharray: ANYTHING_VALIDATOR,
2596    strokeLinejoin: genEnumValidator(['bevel', 'miter', 'round']),
2597    strokeLinecap: genEnumValidator(['butt', 'round', 'square']),
2598    strokeMiterlimit: NUMBER_VALIDATOR,
2599    strokeOpacity: NUMBER_VALIDATOR,
2600    strokeWidth: LENGTH_VALIDATOR,
2601    transform: TRANSFORM_VALIDATOR,
2602    width: PERCENTAGE_LENGTH_VALIDATOR,
2603    height: PERCENTAGE_LENGTH_VALIDATOR,
2604    x: PERCENTAGE_LENGTH_VALIDATOR,
2605    y: PERCENTAGE_LENGTH_VALIDATOR,
2606    rx: PERCENTAGE_LENGTH_VALIDATOR,
2607    ry: PERCENTAGE_LENGTH_VALIDATOR,
2608    stroke: COLOR_VAR_VALIDATOR,
2609    strokeDashoffset: LENGTH_VALIDATOR
2610  },
2611  circle: {
2612    fill: COLOR_VAR_VALIDATOR,
2613    fillOpacity: NUMBER_VALIDATOR,
2614    fillRule: genEnumValidator(['nonzero', 'evenodd']),
2615    opacity: NUMBER_VALIDATOR,
2616    stroke: COLOR_VAR_VALIDATOR,
2617    strokeDasharray: ANYTHING_VALIDATOR,
2618    strokeDashoffset: LENGTH_VALIDATOR,
2619    strokeLinejoin: genEnumValidator(['bevel', 'miter', 'round']),
2620    strokeLinecap: genEnumValidator(['butt', 'round', 'square']),
2621    strokeMiterlimit: NUMBER_VALIDATOR,
2622    strokeOpacity: NUMBER_VALIDATOR,
2623    strokeWidth: LENGTH_VALIDATOR,
2624    transform: TRANSFORM_VALIDATOR,
2625    id: ANYTHING_VALIDATOR,
2626    cx: PERCENTAGE_LENGTH_VALIDATOR,
2627    cy: PERCENTAGE_LENGTH_VALIDATOR,
2628    r: PERCENTAGE_LENGTH_VALIDATOR
2629  },
2630  path: {
2631    fillOpacity: NUMBER_VALIDATOR,
2632    fillRule: genEnumValidator(['nonzero', 'evenodd']),
2633    opacity: NUMBER_VALIDATOR,
2634    strokeDashoffset: LENGTH_VALIDATOR,
2635    strokeLinejoin: genEnumValidator(['bevel', 'miter', 'round']),
2636    strokeLinecap: genEnumValidator(['butt', 'round', 'square']),
2637    strokeMiterlimit: NUMBER_VALIDATOR,
2638    strokeOpacity: NUMBER_VALIDATOR,
2639    strokeWidth: LENGTH_VALIDATOR,
2640    transform: TRANSFORM_VALIDATOR,
2641    id: ANYTHING_VALIDATOR,
2642    d: ANYTHING_VALIDATOR,
2643    fill: COLOR_VAR_VALIDATOR,
2644    strokeDasharray: ANYTHING_VALIDATOR,
2645    stroke: COLOR_VAR_VALIDATOR
2646  },
2647  svg: {
2648    fill: COLOR_VAR_VALIDATOR,
2649    fillOpacity: NUMBER_VALIDATOR,
2650    fillRule: genEnumValidator(['nonzero', 'evenodd']),
2651    opacity: NUMBER_VALIDATOR,
2652    stroke: COLOR_VAR_VALIDATOR,
2653    strokeDasharray: ANYTHING_VALIDATOR,
2654    strokeDashoffset: LENGTH_VALIDATOR,
2655    strokeLinejoin: genEnumValidator(['bevel', 'miter', 'round']),
2656    strokeLinecap: genEnumValidator(['butt', 'round', 'square']),
2657    strokeMiterlimit: NUMBER_VALIDATOR,
2658    strokeOpacity: NUMBER_VALIDATOR,
2659    strokeWidth: LENGTH_VALIDATOR,
2660    transform: TRANSFORM_VALIDATOR,
2661    id: ANYTHING_VALIDATOR,
2662    width: PERCENTAGE_LENGTH_VALIDATOR,
2663    height: PERCENTAGE_LENGTH_VALIDATOR,
2664    x: PERCENTAGE_LENGTH_VALIDATOR,
2665    y: PERCENTAGE_LENGTH_VALIDATOR,
2666    viewbox: ANYTHING_VALIDATOR
2667  },
2668  polygon: {
2669    fill: COLOR_VAR_VALIDATOR,
2670    fillOpacity: NUMBER_VALIDATOR,
2671    opacity: NUMBER_VALIDATOR,
2672    stroke: COLOR_VAR_VALIDATOR,
2673    strokeDasharray: ANYTHING_VALIDATOR,
2674    strokeDashoffset: LENGTH_VALIDATOR,
2675    strokeLinejoin: genEnumValidator(['bevel', 'miter', 'round']),
2676    strokeLinecap: genEnumValidator(['butt', 'round', 'square']),
2677    strokeMiterlimit: NUMBER_VALIDATOR,
2678    strokeOpacity: NUMBER_VALIDATOR,
2679    strokeWidth: LENGTH_VALIDATOR,
2680    transform: TRANSFORM_VALIDATOR,
2681    id: ANYTHING_VALIDATOR,
2682    points: ANYTHING_VALIDATOR,
2683    fillRule: genEnumValidator(['nonzero', 'evenodd'])
2684  },
2685  polyline: {
2686    fill: COLOR_VAR_VALIDATOR,
2687    fillOpacity: NUMBER_VALIDATOR,
2688    opacity: NUMBER_VALIDATOR,
2689    stroke: COLOR_VAR_VALIDATOR,
2690    strokeDasharray: ANYTHING_VALIDATOR,
2691    strokeDashoffset: LENGTH_VALIDATOR,
2692    strokeLinejoin: genEnumValidator(['bevel', 'miter', 'round']),
2693    strokeLinecap: genEnumValidator(['butt', 'round', 'square']),
2694    strokeMiterlimit: NUMBER_VALIDATOR,
2695    strokeOpacity: NUMBER_VALIDATOR,
2696    strokeWidth: LENGTH_VALIDATOR,
2697    transform: TRANSFORM_VALIDATOR,
2698    id: ANYTHING_VALIDATOR,
2699    points: ANYTHING_VALIDATOR,
2700    fillRule: genEnumValidator(['nonzero', 'evenodd'])
2701  },
2702  tspan: {
2703    id: ANYTHING_VALIDATOR,
2704    x: PERCENTAGE_LENGTH_VALIDATOR,
2705    y: PERCENTAGE_LENGTH_VALIDATOR,
2706    dx: PERCENTAGE_LENGTH_VALIDATOR,
2707    dy: PERCENTAGE_LENGTH_VALIDATOR,
2708    rotate: NUMBER_VALIDATOR,
2709    fontSize: LENGTH_VALIDATOR,
2710    fill: COLOR_VAR_VALIDATOR,
2711    fillOpacity: NUMBER_VALIDATOR,
2712    stroke: COLOR_VAR_VALIDATOR,
2713    strokeOpacity: NUMBER_VALIDATOR,
2714    strokeWidth: LENGTH_VALIDATOR
2715  },
2716  textPath: {
2717    id: ANYTHING_VALIDATOR,
2718    path: ANYTHING_VALIDATOR,
2719    startOffset: PERCENTAGE_LENGTH_VALIDATOR,
2720    fontSize: LENGTH_VALIDATOR,
2721    fill: COLOR_VAR_VALIDATOR,
2722    fillOpacity: NUMBER_VALIDATOR,
2723    stroke: COLOR_VAR_VALIDATOR,
2724    strokeOpacity: NUMBER_VALIDATOR,
2725    strokeWidth: LENGTH_VALIDATOR
2726  },
2727  animate: {
2728    id: ANYTHING_VALIDATOR,
2729    attributeName: ANYTHING_VALIDATOR,
2730    begin: ANYTHING_VALIDATOR,
2731    dur: ANYTHING_VALIDATOR,
2732    end: ANYTHING_VALIDATOR,
2733    repeatCount: ANYTHING_VALIDATOR,
2734    fill: genEnumValidator(['freeze', 'remove']),
2735    calcMode: genEnumValidator(['discrete', 'linear', 'paced', 'spline']),
2736    keyTimes: ANYTHING_VALIDATOR,
2737    keySplines: ANYTHING_VALIDATOR,
2738    from: ANYTHING_VALIDATOR,
2739    to: ANYTHING_VALIDATOR,
2740    values: ANYTHING_VALIDATOR
2741  },
2742  animateMotion: {
2743    id: ANYTHING_VALIDATOR,
2744    attributeName: ANYTHING_VALIDATOR,
2745    begin: ANYTHING_VALIDATOR,
2746    dur: ANYTHING_VALIDATOR,
2747    end: ANYTHING_VALIDATOR,
2748    repeatCount: ANYTHING_VALIDATOR,
2749    fill: genEnumValidator(['freeze', 'remove']),
2750    calcMode: genEnumValidator(['discrete', 'linear', 'paced', 'spline']),
2751    keyTimes: ANYTHING_VALIDATOR,
2752    keySplines: ANYTHING_VALIDATOR,
2753    from: ANYTHING_VALIDATOR,
2754    to: ANYTHING_VALIDATOR,
2755    keyPoints: ANYTHING_VALIDATOR,
2756    path: ANYTHING_VALIDATOR,
2757    rotate: ANYTHING_VALIDATOR
2758  },
2759  animateTransform: {
2760    id: ANYTHING_VALIDATOR,
2761    attributeName: ANYTHING_VALIDATOR,
2762    begin: ANYTHING_VALIDATOR,
2763    dur: ANYTHING_VALIDATOR,
2764    end: ANYTHING_VALIDATOR,
2765    repeatCount: ANYTHING_VALIDATOR,
2766    fill: genEnumValidator(['freeze', 'remove']),
2767    calcMode: genEnumValidator(['discrete', 'linear', 'paced', 'spline']),
2768    from: ANYTHING_VALIDATOR,
2769    to: ANYTHING_VALIDATOR,
2770    type: genEnumValidator(['translate', 'scale', 'skewX', 'skewY'])
2771  },
2772  line: {
2773    fill: COLOR_VAR_VALIDATOR,
2774    fillOpacity: NUMBER_VALIDATOR,
2775    opacity: NUMBER_VALIDATOR,
2776    stroke: COLOR_VAR_VALIDATOR,
2777    strokeDasharray: ANYTHING_VALIDATOR,
2778    strokeDashoffset: LENGTH_VALIDATOR,
2779    strokeLinejoin: genEnumValidator(['bevel', 'miter', 'round']),
2780    strokeLinecap: genEnumValidator(['butt', 'round', 'square']),
2781    strokeMiterlimit: NUMBER_VALIDATOR,
2782    strokeOpacity: NUMBER_VALIDATOR,
2783    strokeWidth: LENGTH_VALIDATOR,
2784    fillRule: genEnumValidator(['nonzero', 'evenodd']),
2785    transform: TRANSFORM_VALIDATOR,
2786    id: ANYTHING_VALIDATOR,
2787    x1: PERCENTAGE_LENGTH_VALIDATOR,
2788    y1: PERCENTAGE_LENGTH_VALIDATOR,
2789    x2: PERCENTAGE_LENGTH_VALIDATOR,
2790    y2: PERCENTAGE_LENGTH_VALIDATOR
2791  }
2792}
2793
2794var LITE_PROP_NAME_GROUPS = {
2795  boxModel: {
2796    width: PERCENTAGE_LENGTH_VALIDATOR,
2797    height: PERCENTAGE_LENGTH_VALIDATOR,
2798    padding: SHORTHAND_LENGTH_VALIDATOR,
2799    paddingLeft: LENGTH_VALIDATOR,
2800    paddingRight: LENGTH_VALIDATOR,
2801    paddingTop: LENGTH_VALIDATOR,
2802    paddingBottom: LENGTH_VALIDATOR,
2803    margin:SHORTHAND_AUTO_PERCENTAGE_LENGTH_VALIDATOR,
2804    marginLeft: AUTO_PERCENTAGE_LENGTH_VALIDATOR,
2805    marginRight: AUTO_PERCENTAGE_LENGTH_VALIDATOR,
2806    marginTop: AUTO_PERCENTAGE_LENGTH_VALIDATOR,
2807    marginBottom: AUTO_PERCENTAGE_LENGTH_VALIDATOR,
2808    strokeWidth: LENGTH_VALIDATOR,
2809  },
2810  border:{
2811    borderWidth: SHORTHAND_LENGTH_VALIDATOR,
2812    borderColor: SHORTHAND_COLOR_VALIDATOR,
2813    borderRadius: LENGTH_VALIDATOR,
2814  },
2815  animation:{
2816    animationDuration: TIME_VALIDATOR,
2817    animationDelay: TIME_VALIDATOR,
2818    animationName: NAME_VALIDATOR,
2819    animationTimingFunction: genEnumValidator(['linear', 'ease-in', 'ease-out', 'ease-in-out']),
2820    animationIterationCount: ITERATIONCOUNT_VALIDATOR,
2821    animationFillMode: genEnumValidator(['none', 'forwards'])
2822  },
2823  flexbox: {
2824    flexDirection: genEnumValidator(['row', 'column']),
2825    flexWrap: genEnumValidator(['nowrap', 'wrap']),
2826    justifyContent: genEnumValidator(['flex-start', 'flex-end', 'center', 'space-between',
2827      'space-around', 'space-evenly']),
2828    alignItems: genEnumValidator(['stretch', 'flex-start', 'flex-end', 'center']),
2829  },
2830  position: {
2831    top: PERCENTAGE_LENGTH_VALIDATOR,
2832    left: PERCENTAGE_LENGTH_VALIDATOR,
2833  },
2834  common: {
2835    opacity: NUMBER_VALIDATOR,
2836    backgroundColor: COLOR_VAR_VALIDATOR,
2837    backgroundImage: URL_VALIDATOR,
2838    placeholderColor: COLOR_VAR_VALIDATOR,
2839    display: genEnumValidator(['flex', 'none']),
2840  },
2841  text: {
2842    color: COLOR_VAR_VALIDATOR,
2843    fontSize: LENGTH_VALIDATOR,
2844    fontFamily: genEnumValidator(['HYQiHei-65S']),
2845    letterSpacing: LENGTH_VALIDATOR,
2846    textAlign: genEnumValidator(['left', 'center', 'right']),
2847    textOverflow: genEnumValidator(['clip', 'ellipsis']),
2848  },
2849  slider: {
2850    selectedColor: COLOR_VAR_VALIDATOR,
2851    selectedFontSize: LENGTH_VALIDATOR,
2852    selectedFontFamily: genEnumValidator(['HYQiHei-65S']),
2853    blockColor: COLOR_VAR_VALIDATOR,
2854  },
2855  transform: {
2856    transform: TRANSFORM_VALIDATOR,
2857  },
2858  progress: {
2859    centerX: LENGTH_VALIDATOR,
2860    centerY: LENGTH_VALIDATOR,
2861    radius: LENGTH_VALIDATOR,
2862    startAngle: ANGLE_VALIDATOR,
2863    totalAngle: ANGLE_VALIDATOR
2864  }
2865}
2866
2867var CARD_PROP_NAME_GROUPS = {
2868  boxModel: {
2869    width: PERCENTAGE_LENGTH_VALIDATOR,
2870    height: PERCENTAGE_LENGTH_VALIDATOR,
2871    overflow: genEnumValidator(['auto', 'hidden','scroll','visible']),
2872    padding: SHORTHAND_PERCENTAGE_LENGTH_VALIDATOR,
2873    paddingLeft: PERCENTAGE_LENGTH_VALIDATOR,
2874    paddingRight: PERCENTAGE_LENGTH_VALIDATOR,
2875    paddingTop: PERCENTAGE_LENGTH_VALIDATOR,
2876    paddingBottom: PERCENTAGE_LENGTH_VALIDATOR,
2877    paddingStart: PERCENTAGE_LENGTH_VALIDATOR,
2878    paddingEnd: PERCENTAGE_LENGTH_VALIDATOR,
2879    margin: SHORTHAND_AUTO_PERCENTAGE_LENGTH_VALIDATOR,
2880    marginLeft: AUTO_PERCENTAGE_LENGTH_VALIDATOR,
2881    marginRight: AUTO_PERCENTAGE_LENGTH_VALIDATOR,
2882    marginTop: AUTO_PERCENTAGE_LENGTH_VALIDATOR,
2883    marginBottom: AUTO_PERCENTAGE_LENGTH_VALIDATOR,
2884    marginStart: PERCENTAGE_LENGTH_VALIDATOR,
2885    marginEnd: PERCENTAGE_LENGTH_VALIDATOR,
2886    columns: NUMBER_VALIDATOR,
2887    displayIndex: NUMBER_VALIDATOR,
2888    aspectRatio: NUMBER_VALIDATOR,
2889    minWidth: PERCENTAGE_LENGTH_VALIDATOR,
2890    minHeight: PERCENTAGE_LENGTH_VALIDATOR,
2891    maxWidth: PERCENTAGE_LENGTH_VALIDATOR,
2892    maxHeight: PERCENTAGE_LENGTH_VALIDATOR,
2893    flexWeight: NUMBER_VALIDATOR,
2894    boxShadow: BOX_SHADOW_VALIDATOR,
2895    boxShadowH: LENGTH_VALIDATOR,
2896    boxShadowV: LENGTH_VALIDATOR,
2897    boxShadowBlur: LENGTH_VALIDATOR,
2898    boxShadowSpread: LENGTH_VALIDATOR,
2899    boxShadowColor: COLOR_VAR_VALIDATOR,
2900    filter: FILTER_VALIDATOR,
2901    backdropFilter: FILTER_VALIDATOR,
2902    windowFilter: FILTER_PERCENTAGE_VALIDATOR
2903  },
2904  div: {
2905    gridTemplateColumns: GRID_TEMPLATE_VALIDATOR,
2906    gridTemplateRows: GRID_TEMPLATE_VALIDATOR,
2907    gridGap: LENGTH_VALIDATOR,
2908    gridColumnsGap: LENGTH_VALIDATOR,
2909    gridRowsGap: LENGTH_VALIDATOR,
2910    gridRowStart: NUMBER_VALIDATOR,
2911    gridRowEnd: NUMBER_VALIDATOR,
2912    gridColumnStart: NUMBER_VALIDATOR,
2913    gridColumnEnd: NUMBER_VALIDATOR
2914  },
2915  border: {
2916    border: BORDER_VALIDATOR,
2917    borderWidth: SHORTHAND_LENGTH_VALIDATOR,
2918    borderLeftWidth: LENGTH_VALIDATOR,
2919    borderTopWidth: LENGTH_VALIDATOR,
2920    borderRightWidth: LENGTH_VALIDATOR,
2921    borderBottomWidth: LENGTH_VALIDATOR,
2922    borderColor: SHORTHAND_COLOR_VALIDATOR,
2923    borderLeftColor: COLOR_VAR_VALIDATOR,
2924    borderTopColor: COLOR_VAR_VALIDATOR,
2925    borderRightColor: COLOR_VAR_VALIDATOR,
2926    borderBottomColor: COLOR_VAR_VALIDATOR,
2927    borderStyle: genEnumValidator(['solid', 'dashed', 'dotted']),
2928    borderTopStyle: genEnumValidator(['solid', 'dashed', 'dotted']),
2929    borderRightStyle: genEnumValidator(['solid', 'dashed', 'dotted']),
2930    borderBottomStyle: genEnumValidator(['solid', 'dashed', 'dotted']),
2931    borderLeftStyle: genEnumValidator(['solid', 'dashed', 'dotted']),
2932    borderRadius: LENGTH_VALIDATOR,
2933    borderBottomLeftRadius: LENGTH_VALIDATOR,
2934    borderBottomRightRadius: LENGTH_VALIDATOR,
2935    borderTopLeftRadius: LENGTH_VALIDATOR,
2936    borderTopRightRadius: LENGTH_VALIDATOR,
2937    borderLeft: BORDER_VALIDATOR,
2938    borderRight: BORDER_VALIDATOR,
2939    borderTop: BORDER_VALIDATOR,
2940    borderBottom: BORDER_VALIDATOR
2941  },
2942  flexbox: {
2943    flex: genEnumValidator(['none', 'auto', 'initial']),
2944    flexWrap: genEnumValidator(['nowrap', 'wrap']),
2945    flexGrow: NUMBER_VALIDATOR,
2946    flexShrink: NUMBER_VALIDATOR,
2947    flexBasis: LENGTH_VALIDATOR,
2948    flexDirection: genEnumValidator(['row', 'column']),
2949    justifyContent: genEnumValidator(['flex-start', 'flex-end', 'center', 'space-between',
2950      'space-around', 'space-evenly']),
2951    alignItems: genEnumValidator(['stretch', 'flex-start', 'flex-end', 'center', 'baseline']),
2952    alignContent: genEnumValidator(['stretch', 'flex-start', 'flex-end', 'center', 'space-between', 'space-around']),
2953  },
2954  position: {
2955    position: genEnumValidator(['relative', 'fixed', 'absolute']),
2956    top: PERCENTAGE_LENGTH_VALIDATOR,
2957    bottom: PERCENTAGE_LENGTH_VALIDATOR,
2958    left: PERCENTAGE_LENGTH_VALIDATOR,
2959    right: PERCENTAGE_LENGTH_VALIDATOR,
2960    zIndex: INTEGER_VALIDATOR
2961  },
2962  common: {
2963    background: BACKGROUND_VALIDATOR,
2964    backgroundColor: COLOR_VAR_VALIDATOR,
2965    backgroundImage: URL_VALIDATOR,
2966    backgroundSize: BACKGROUND_SIZE_VALIDATOR,
2967    backgroundRepeat: genEnumValidator(['repeat', 'no-repeat', 'repeat-x', 'repeat-y']),
2968    backgroundPosition: BACKGROUND_POSITION_VALIDATOR,
2969    opacity: NUMBER_VALIDATOR,
2970    appearingDuration: NUMBER_VALIDATOR,
2971    visibility: genEnumValidator(['visible', 'hidden']),
2972    display: genEnumValidator(['flex', 'none', 'grid']),
2973    imageFill: COLOR_VAR_VALIDATOR,
2974    maskImage: MASK_VALIDATOR,
2975    maskPosition: BACKGROUND_POSITION_VALIDATOR,
2976    maskSize: BACKGROUND_SIZE_VALIDATOR
2977  },
2978  text: {
2979    color: COLOR_VAR_VALIDATOR,
2980    fontSize: LENGTH_VALIDATOR,
2981    allowScale: genEnumValidator(['true', 'false']),
2982    letterSpacing: LENGTH_VALIDATOR,
2983    fontStyle: genEnumValidator(['normal', 'italic']),
2984    fontFamily: ANYTHING_VALIDATOR,
2985    fontWeight: genEnumValidator(['normal', 'lighter', 'bold', 'bolder', "medium", "regular",
2986      '100', '200', '300', '400', '500', '600', '700', '800', '900']),
2987    textDecoration: genEnumValidator(['none', 'underline', 'line-through']),
2988    textAlign: genEnumValidator(['start', 'end', 'left', 'center', 'right']),
2989    textOverflow: genEnumValidator(['clip', 'ellipsis']),
2990    textIndent: TEXT_INDENT_VALIDATOR,
2991    lineHeight: LENGTH_VALIDATOR,
2992    maxLines: ANYTHING_VALIDATOR,
2993    minFontSize: LENGTH_VALIDATOR,
2994    maxFontSize: LENGTH_VALIDATOR,
2995    fontSizeStep: LENGTH_VALIDATOR,
2996    preferFontSizes: ARRAY_LENGTH_VALIDATOR,
2997    adaptHeight: genEnumValidator(['true', 'false'])
2998  },
2999  progress: {
3000    secondaryColor: COLOR_VAR_VALIDATOR,
3001    scaleWidth: LENGTH_VALIDATOR,
3002    scaleNumber: NUMBER_VALIDATOR,
3003    startAngle: ANGLE_VALIDATOR,
3004    totalAngle: ANGLE_VALIDATOR,
3005    centerX: LENGTH_VALIDATOR,
3006    centerY: LENGTH_VALIDATOR,
3007    radius: LENGTH_VALIDATOR,
3008    direction: genEnumValidator(['start-to-end', 'end-to-start']),
3009    sections: NAME_VALIDATOR,
3010    colors: ARRAY_COLOR_VALIDATOR,
3011    weights: ARRAY_NUMBER_VALIDATOR
3012  },
3013  chart: {
3014    strokeWidth: LENGTH_VALIDATOR,
3015  },
3016  button: {
3017    textColor: COLOR_VAR_VALIDATOR,
3018    iconWidth: LENGTH_VALIDATOR,
3019    iconHeight: LENGTH_VALIDATOR
3020  },
3021  image: {
3022    objectFit: genEnumValidator(['cover', 'fill', 'contain', 'none', 'scale-down']),
3023    matchTextDirection: genEnumValidator(['false', 'true']),
3024    fitOriginalSize: genEnumValidator(['false', 'true']),
3025  },
3026  list: {
3027    itemExtent: PERCENTAGE_LENGTH_VALIDATOR,
3028    fadeColor: COLOR_VAR_VALIDATOR,
3029    dividerColor: COLOR_VAR_VALIDATOR,
3030    dividerHeight: LENGTH_VALIDATOR,
3031    dividerLength: LENGTH_VALIDATOR,
3032    dividerOrigin: LENGTH_VALIDATOR,
3033    scrollbarColor: COLOR_VALIDATOR,
3034    scrollbarWidth: LENGTH_VALIDATOR,
3035    scrollbarOffset: ARRAY_LENGTH_VALIDATOR
3036  }
3037}
3038
3039var backgroundValidatorMap = {
3040  linearGradient: LINEAR_GRADIENT_VALIDATOR,
3041  repeatingLinearGradient: LINEAR_GRADIENT_VALIDATOR,
3042  linearGradientColor: ARRAY_COLOR_STOP_VALIDATOR,
3043  linearGradientAngle: ANGLE_VALIDATOR,
3044  linearGradientDirection: GRADIENT_DIRECTION_VALIDATOR
3045}
3046
3047var transformValidatorMap = {
3048  translate: MULTIPLE_PERCENTAGE_LENGTH_VALIDATOR,
3049  translate3d: MULTIPLE_PERCENTAGE_LENGTH_VALIDATOR,
3050  translateX: PERCENTAGE_LENGTH_VALIDATOR,
3051  translateY: PERCENTAGE_LENGTH_VALIDATOR,
3052  translateZ: PERCENTAGE_LENGTH_VALIDATOR,
3053  scale: MULTIPLE_NUMBER_VALIDATOR,
3054  scale3d: MULTIPLE_NUMBER_VALIDATOR,
3055  scaleX: NUMBER_VALIDATOR,
3056  scaleY: NUMBER_VALIDATOR,
3057  scaleZ: NUMBER_VALIDATOR,
3058  rotate: MUTIPLE_ANGLE_VALIDATOR,
3059  rotate3d: ROTATE3D_VALIDATOR,
3060  rotateX: ANGLE_VALIDATOR,
3061  rotateY: ANGLE_VALIDATOR,
3062  rotateZ: ANGLE_VALIDATOR,
3063  skew: MUTIPLE_ANGLE_VALIDATOR,
3064  skewX: ANGLE_VALIDATOR,
3065  skewY: ANGLE_VALIDATOR,
3066  matrix: MULTIPLE_NUMBER_VALIDATOR,
3067  matrix3d: MULTIPLE_NUMBER_VALIDATOR,
3068  perspective: PERCENTAGE_LENGTH_VALIDATOR,
3069}
3070
3071var SUGGESTED_PROP_NAME_GROUP = {}
3072
3073var validatorMap = {}
3074
3075const card = process.env.DEVICE_LEVEL === 'card'
3076var isLiteDevice = process.env.DEVICE_LEVEL === 'lite'
3077
3078var PROP_NAME_GROUPS = process.env.DEVICE_LEVEL === 'lite' ? LITE_PROP_NAME_GROUPS :
3079  card ? CARD_PROP_NAME_GROUPS : RICH_PROP_NAME_GROUPS
3080
3081/**
3082 * flatten `PROP_NAME_GROUPS` to `validatorMap`
3083 */
3084function genValidatorMap() {
3085  var groupName, group, name
3086  for (groupName in PROP_NAME_GROUPS) {
3087    group = PROP_NAME_GROUPS[groupName]
3088    for (name in group) {
3089      validatorMap[name] = group[name]
3090    }
3091  }
3092}
3093
3094genValidatorMap()
3095
3096function getValueUnit(dem) {
3097  var str = dem.toString()
3098  var getValue = str.match(/[-]{0,1}[1-9][0-9]*/)
3099  var getUnit = str.match(/px|cm|%|em|vp|fp/)
3100  var result = {value: getValue, unit: getUnit}
3101  return result
3102}
3103
3104function isOperator(value) {
3105  var operatorString = "+-*/()"
3106  return operatorString.indexOf(value) > -1
3107}
3108
3109function getPrioraty(value) {
3110  switch(value) {
3111    case '+':
3112    case '-':
3113      return 1
3114    case '*':
3115    case '/':
3116      return 2
3117    default:
3118      return 0
3119  }
3120}
3121
3122function prioraty(o1, o2) {
3123  return getPrioraty(o1) <= getPrioraty(o2)
3124}
3125
3126function dal2Rpn(exp) {
3127  var inputStack = []
3128  var outputStack = []
3129  var outputQueue = []
3130  var str =
3131    exp.replace(/calc/g, "").replace(/(?<!var\(\-\-\w+|var\(\-\-\w+\,\s*\w+)\)/g, " )").replace(/(?<!var)\(/g, "( ")
3132  var inputStack=str.split(/(?<!\,)\s+/)
3133  var value, log
3134  while(inputStack.length > 0) {
3135    var cur = inputStack.shift()
3136    if(isOperator(cur)) {
3137      if(cur == '(') {
3138        outputStack.push(cur)
3139      } else if(cur == ')') {
3140        var po = outputStack.pop()
3141        while(po != '(' && outputStack.length > 0) {
3142          outputQueue.push(po)
3143          po = outputStack.pop()
3144        }
3145        if(po != '(') {
3146          log = {reason: 'ERROR: Expression unmatched ()'}
3147        }
3148      } else {
3149        while(prioraty(cur, outputStack[outputStack.length - 1]) && outputStack.length > 0) {
3150          outputQueue.push(outputStack.pop())
3151        }
3152        outputStack.push(cur)
3153      }
3154    } else {
3155      outputQueue.push(cur)
3156    }
3157  }
3158  return {
3159    value: outputQueue,
3160    log: log
3161  }
3162}
3163
3164function checkComputation(left, right, operator) {
3165  var value, log
3166  if (operator == '*') {
3167    if ((right.match(/[a-zA-Z]/) && left.match(/[a-zA-Z]/)) || (!right.match(/[a-zA-Z]/) && !left.match(/[a-zA-Z]/))) {
3168      log = {reason: 'ERROR: The multiplier must contain and contain only one integer'}
3169    }
3170  }
3171  if (operator == '/') {
3172    if (right.match(/[a-zA-Z]|(?<![1-9])[0]/)) {
3173      log = {reason: 'ERROR: Divisor must be an integer and cannot be zero'}
3174    }
3175  }
3176  if (operator == '+') {
3177    if (!(right.match(/[a-zA-Z%]/) && left.match(/[a-zA-Z%]/))) {
3178      log = {reason: 'ERROR: Addition cannot contain integers'}
3179    }
3180  }
3181  if (operator == '-') {
3182    if (!(right.match(/[a-zA-Z%]/) && left.match(/[a-zA-Z%]/))) {
3183      log = {reason: 'ERROR: Subtraction cannot contain integers'}
3184    }
3185  }
3186  return log
3187}
3188
3189function getResult(left, right, operator) {
3190  var value, log, errLog
3191  if (left.match(/var/)) {
3192    left = cssVarFun(left)
3193  }
3194  if (right.match(/var/)) {
3195    right = cssVarFun(right)
3196  }
3197  errLog = checkComputation(left, right, operator)
3198  if (errLog) {
3199    return { value: null, log: errLog }
3200  }
3201  var result, value, unit
3202  var leftValue = getValueUnit(left)
3203  var rightValue = getValueUnit(right)
3204  if (left.match(/\(/) | right.match(/\(/)) {
3205    result = left + ' ' + operator + ' ' + right
3206  } else {
3207    if (operator == '*') {
3208      value = leftValue.value * rightValue.value
3209      if (leftValue.unit == null) {
3210        unit = rightValue.unit
3211      } else { unit = leftValue.unit}
3212      result = value + unit
3213    } else if (operator == '/') {
3214      if (parseInt(rightValue.value) != 0) {
3215        value = leftValue.value / rightValue.value
3216        unit = leftValue.unit
3217        result = value + unit
3218      }
3219    } else if (operator == '+') {
3220      if (JSON.stringify(leftValue.unit) == JSON.stringify(rightValue.unit)) {
3221        value = parseInt(leftValue.value) + parseInt(rightValue.value)
3222        unit = leftValue.unit
3223        result = value + unit
3224      } else result = '(' + left + ' ' + operator + ' ' + right + ')'
3225    } else if (operator == '-') {
3226      if (JSON.stringify(leftValue.unit) == JSON.stringify(rightValue.unit)) {
3227        value = parseInt(leftValue.value) - parseInt(rightValue.value)
3228        unit = leftValue.unit
3229        result = value + unit
3230      } else result = '(' + left + ' ' + operator + ' ' + right + ')'
3231    }
3232  }
3233  return { value: result, log: null }
3234}
3235
3236function evalRpn(rpnQueue) {
3237  var outputStack = []
3238  var value, res, log
3239  while(rpnQueue.length > 0) {
3240    var cur = rpnQueue.shift()
3241    if(!isOperator(cur)) {
3242      outputStack.push(cur)
3243    } else {
3244      if(outputStack.length < 2) {
3245      log = {reason: 'ERROR: Expression does not conform to specification'}
3246      }
3247      var sec = outputStack.pop()
3248      var fir = outputStack.pop()
3249      res = getResult(fir, sec, cur)
3250      log = res.log
3251      if (log) {
3252        return {
3253          value: null,
3254          log: log
3255        }
3256      } else {
3257        outputStack.push(res.value)
3258      }
3259    }
3260  }
3261  if(outputStack.length != 1) {
3262    log = {reason: 'ERROR: Expression does not conform to specification'}
3263  } else {
3264    if (outputStack[0].match(/[+-]/)) {
3265      value = 'calc' + outputStack[0]
3266    } else {
3267      value = outputStack[0]
3268    }
3269  }
3270  return {
3271    value: value,
3272    log: log
3273  }
3274}
3275
3276var cssPropData = []
3277
3278function saveCssProp(name, value) {
3279  if (name.match(/\-\-/)) {
3280    while (value.match(/var/)) {
3281      var value = cssVarFun(value)
3282    }
3283    cssPropData.push({name: name,value: value})
3284  }
3285}
3286
3287function cssVarFun(value) {
3288  if (value.match(/calc/)) {
3289    return value
3290  } else {
3291    if (value.match(/var/)) {
3292      if (value.match(/\,/)) {
3293        var cssVarFir = value.substring(0,value.indexOf(",")).replace("var(","").trim()
3294        var cssVarSec = value.substring(value.indexOf(",")+1,value.length).replace(")","").trim()
3295      } else {
3296          var cssVarFir = value.replace("var(","").replace(")","").trim()
3297          var cssVarSec = ""
3298      }
3299      let varValue = cssVarSec
3300      for(var i=0, len=cssPropData.length; i<len; i++) {
3301        var cPDName = cssPropData[i].name.trim()
3302        cssVarFir = util.hyphenedToCamelCase(cssVarFir)
3303        if (cssVarFir == cPDName) {
3304          varValue = cssPropData[i].value
3305        }
3306      }
3307      return varValue
3308    } else {
3309      return value
3310    }
3311  }
3312}
3313
3314function expValidate(name, value) {
3315  var res, log
3316  saveCssProp(name, value)
3317  if (typeof value === 'string' && name != 'border') {
3318    if (value.match(/var/)) {
3319      value = cssVarFun(value)
3320    }
3321    if (value.match(/calc/)) {
3322      var checkOp =
3323        /[a-zA-Z0-9()]\+|\+[a-zA-Z0-9()]|[a-zA-Z0-9()](?<!\-)\-(?!\-)|(?<!\-)\-(?!\-)[a-zA-Z0-9()]|[a-zA-Z0-9()]\*|\*[a-zA-Z0-9()]|[a-zA-Z0-9()]\/|\/[a-zA-Z0-9()]/
3324      if (value.match(checkOp) && value.match(/calc\(|var\(\-\-/)) {
3325        log = {reason: 'ERROR: Expression error, A space is required before and after the operator'}
3326        return {
3327          log: log
3328        }
3329      }
3330      res = dal2Rpn(value)
3331      res = evalRpn(res.value)
3332      log = res.log
3333      value = res.value
3334    }
3335  }
3336  return {
3337    value: value,
3338    log: log
3339  }
3340}
3341
3342/**
3343 * validate a CSS name/value pair
3344 *
3345 * @param  {string} name   camel cased
3346 * @param  {string} value
3347 * @return {object}
3348 * - value:string or null
3349 * - log:{reason:string} or undefined
3350 */
3351function validate(name, value) {
3352  var log, expRes
3353  expRes = expValidate(name, value)
3354  if (expRes.log) {
3355    return {
3356      value: null,
3357      log: expRes.log
3358    }
3359  } else {
3360    value = expRes.value
3361  }
3362
3363  var result
3364  var validator = validatorMap[name]
3365  if (typeof validator === 'function') {
3366    const flag = /{{{(.+?)}}}|{{(.+?)}}/.test(value) && card
3367    if (typeof value !== 'function' &&  !flag) {
3368      result = validator(value, name)
3369    }
3370    /* istanbul ignore else */
3371    else {
3372      result = {value: value}
3373    }
3374    if (result.reason) {
3375      log = {reason: result.reason(name, value, result.value)}
3376    }
3377  }
3378  else {
3379    // ensure number type, no `px`
3380    /* istanbul ignore else */
3381    if (typeof value !== 'function') {
3382      var match = value.match(LENGTH_REGEXP)
3383      if (match && (!match[1] || SUPPORT_CSS_UNIT.indexOf(match[1]) === -1)) {
3384        value = parseFloat(value)
3385      }
3386    }
3387    result = {value: value}
3388    var suggestedName = SUGGESTED_PROP_NAME_GROUP[name]
3389    var suggested = suggestedName ? ', suggest `' + util.camelCaseToHyphened(suggestedName) + '`' : ''
3390    log = {reason: 'WARNING: `' + util.camelCaseToHyphened(name) +
3391      '` is not a standard attribute name and may not be supported' + suggested}
3392  }
3393  return {
3394    value: result.value,
3395    log: log
3396  }
3397}
3398
3399var validateFuncMap = {
3400  length: LENGTH_VALIDATOR,
3401  number: NUMBER_VALIDATOR,
3402  date: DATE_VALIDATOR
3403}
3404
3405module.exports = {
3406  BASIC_COLOR_KEYWORDS: BASIC_COLOR_KEYWORDS,
3407  EXTENDED_COLOR_KEYWORDS: EXTENDED_COLOR_KEYWORDS,
3408
3409  LENGTH_VALIDATOR: LENGTH_VALIDATOR,
3410  COLOR_VALIDATOR: COLOR_VALIDATOR,
3411  COLOR_VAR_VALIDATOR: COLOR_VAR_VALIDATOR,
3412  NUMBER_VALIDATOR: NUMBER_VALIDATOR,
3413  INTEGER_VALIDATOR: INTEGER_VALIDATOR,
3414  genEnumValidator: genEnumValidator,
3415
3416  TRANSITION_PROPERTY_VALIDATOR: TRANSITION_PROPERTY_VALIDATOR,
3417  TRANSITION_DURATION_VALIDATOR: TRANSITION_INTERVAL_VALIDATOR,
3418  TRANSITION_DELAY_VALIDATOR: TRANSITION_INTERVAL_VALIDATOR,
3419  TRANSITION_TIMING_FUNCTION_VALIDATOR: TRANSITION_TIMING_FUNCTION_VALIDATOR,
3420
3421  PROP_NAME_GROUPS: PROP_NAME_GROUPS,
3422  validateFuncMap: validateFuncMap,
3423
3424  map: validatorMap,
3425  validate: validate
3426}
3427