• 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: PERCENTAGE_LENGTH_VALIDATOR,
2314    borderBottomLeftRadius: PERCENTAGE_LENGTH_VALIDATOR,
2315    borderBottomRightRadius: PERCENTAGE_LENGTH_VALIDATOR,
2316    borderTopLeftRadius: PERCENTAGE_LENGTH_VALIDATOR,
2317    borderTopRightRadius: PERCENTAGE_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    textDecorationColor: COLOR_VAR_VALIDATOR
2422  },
2423  calendar: {
2424    boundaryColOffset: LENGTH_VALIDATOR,
2425    boundaryRowOffset: LENGTH_VALIDATOR,
2426    colSpace: LENGTH_VALIDATOR,
2427    dailyFiveRowSpace: LENGTH_VALIDATOR,
2428    dayColor: COLOR_VAR_VALIDATOR,
2429    dayFontSize: LENGTH_VALIDATOR,
2430    dayHeight: LENGTH_VALIDATOR,
2431    dayWidth: LENGTH_VALIDATOR,
2432    focusedAreaBackgroundColor: COLOR_VAR_VALIDATOR,
2433    focusedAreaRadius: LENGTH_VALIDATOR,
2434    focusedDayColor: COLOR_VAR_VALIDATOR,
2435    focusedLunarColor: COLOR_VAR_VALIDATOR,
2436    gregorianCalendarHeight: LENGTH_VALIDATOR,
2437    lunarColor: COLOR_VAR_VALIDATOR,
2438    lunarDayFontSize: LENGTH_VALIDATOR,
2439    lunarDayYAxisOffset: LENGTH_VALIDATOR,
2440    lunarHeight: LENGTH_VALIDATOR,
2441    markLunarColor: COLOR_VAR_VALIDATOR,
2442    nonCurrentMonthDayColor: COLOR_VAR_VALIDATOR,
2443    nonCurrentMonthLunarColor: COLOR_VAR_VALIDATOR,
2444    nonCurrentMonthOffDayMarkColor: COLOR_VAR_VALIDATOR,
2445    nonCurrentMonthWorkDayMarkColor: COLOR_VAR_VALIDATOR,
2446    offDayMarkColor: COLOR_VAR_VALIDATOR,
2447    offDayMarkSize: LENGTH_VALIDATOR,
2448    scheduleMarkerRadius: LENGTH_VALIDATOR,
2449    scheduleMarkerXAxisOffset: LENGTH_VALIDATOR,
2450    scheduleMarkerYAxisOffset: LENGTH_VALIDATOR,
2451    underscoreLength: LENGTH_VALIDATOR,
2452    underscoreWidth: LENGTH_VALIDATOR,
2453    underscoreXAxisOffset: LENGTH_VALIDATOR,
2454    underscoreYAxisOffset: LENGTH_VALIDATOR,
2455    weekAndDayRowSpace: LENGTH_VALIDATOR,
2456    weekColor: COLOR_VAR_VALIDATOR,
2457    weekFontSize: LENGTH_VALIDATOR,
2458    weekHeight: LENGTH_VALIDATOR,
2459    weekWidth: LENGTH_VALIDATOR,
2460    weekendDayColor: COLOR_VAR_VALIDATOR,
2461    weekendLunarColor: COLOR_VAR_VALIDATOR,
2462    workDayMarkColor: COLOR_VAR_VALIDATOR,
2463    workDayMarkSize: LENGTH_VALIDATOR,
2464    workStateHorizontalMovingDistance: LENGTH_VALIDATOR,
2465    workStateVerticalMovingDistance: LENGTH_VALIDATOR,
2466    workStateWidth: LENGTH_VALIDATOR
2467  },
2468  rating: {
2469    starBackground: URL_VALIDATOR,
2470    starForeground: URL_VALIDATOR,
2471    starSecondary: URL_VALIDATOR,
2472    rtlFlip: genEnumValidator(['true', 'false'])
2473  },
2474  transition: {
2475    transitionProperty: TRANSITION_PROPERTY_VALIDATOR,
2476    transitionDuration: TRANSITION_INTERVAL_VALIDATOR,
2477    transitionDelay: TRANSITION_INTERVAL_VALIDATOR,
2478    transitionEnter: NAME_VALIDATOR,
2479    transitionExit: NAME_VALIDATOR,
2480    transitionDuration: TIME_VALIDATOR,
2481    transitionTimingFunction: TRANSITION_TIMING_FUNCTION_VALIDATOR
2482  },
2483  transform: {
2484    transform: TRANSFORM_VALIDATOR,
2485    transformOrigin: TRANSFORM_ORIGIN_VALIDATOR
2486  },
2487  customized: {
2488    itemSize: LENGTH_VALIDATOR,
2489    itemColor: COLOR_VAR_VALIDATOR,
2490    itemSelectedColor: COLOR_VAR_VALIDATOR,
2491    textColor: COLOR_VAR_VALIDATOR,
2492    timeColor: COLOR_VAR_VALIDATOR,
2493    textHighlightColor: COLOR_VAR_VALIDATOR
2494  },
2495  list: {
2496    itemExtent: PERCENTAGE_LENGTH_VALIDATOR,
2497    fadeColor: COLOR_VAR_VALIDATOR,
2498    dividerColor: COLOR_VAR_VALIDATOR,
2499    dividerHeight: LENGTH_VALIDATOR,
2500    dividerLength: LENGTH_VALIDATOR,
2501    dividerOrigin: LENGTH_VALIDATOR,
2502    scrollbarColor: COLOR_VALIDATOR,
2503    scrollbarWidth: LENGTH_VALIDATOR,
2504    scrollbarOffset: ARRAY_LENGTH_VALIDATOR
2505  },
2506  progress: {
2507    secondaryColor: COLOR_VAR_VALIDATOR,
2508    scaleWidth: LENGTH_VALIDATOR,
2509    scaleNumber: NUMBER_VALIDATOR,
2510    startAngle: ANGLE_VALIDATOR,
2511    totalAngle: ANGLE_VALIDATOR,
2512    centerX: LENGTH_VALIDATOR,
2513    centerY: LENGTH_VALIDATOR,
2514    radius: LENGTH_VALIDATOR,
2515    direction: genEnumValidator(['start-to-end', 'end-to-start']),
2516    sections: NAME_VALIDATOR,
2517    colors: ARRAY_COLOR_VALIDATOR,
2518    weights: ARRAY_NUMBER_VALIDATOR
2519  },
2520  navigation: {
2521    titleColor: COLOR_VAR_VALIDATOR,
2522    subtitleColor: COLOR_VAR_VALIDATOR
2523  },
2524  button: {
2525    iconWidth: LENGTH_VALIDATOR,
2526    iconHeight: LENGTH_VALIDATOR
2527  },
2528  switch: {
2529    textonColor: COLOR_VAR_VALIDATOR,
2530    textoffColor: COLOR_VAR_VALIDATOR,
2531    textPadding: LENGTH_VALIDATOR
2532  },
2533  share: {
2534    sharedTransitionEffect: genEnumValidator(['exchange', 'static']),
2535    sharedTransitionName: NAME_VALIDATOR,
2536    sharedTransitionTimingFunction: TRANSITION_TIMING_FUNCTION_VALIDATOR
2537  },
2538  image: {
2539    matchTextDirection: genEnumValidator(['false', 'true']),
2540    fitOriginalSize: genEnumValidator(['false', 'true']),
2541  },
2542  divider: {
2543    lineCap: genEnumValidator(['butt', 'square', 'round'])
2544  },
2545  picker: {
2546    columnHeight: LENGTH_VALIDATOR
2547  },
2548  pickerView: {
2549    selectedFontSize: LENGTH_VALIDATOR,
2550    selectedFontFamily: ANYTHING_VALIDATOR,
2551    focusColor: COLOR_VAR_VALIDATOR,
2552    focusFontSize: LENGTH_VALIDATOR,
2553    focusFontFamily: ANYTHING_VALIDATOR,
2554    disappearFontSize: LENGTH_VALIDATOR,
2555    disappearColor: COLOR_VAR_VALIDATOR
2556  },
2557  colorpicker: {
2558    colorPickerColor: Color_Picker_VALIDATOR
2559  },
2560  colorpickerView: {
2561    colorPickerColor: Color_Picker_VALIDATOR
2562  },
2563  slider: {
2564    blockColor: COLOR_VAR_VALIDATOR,
2565  },
2566  badge: {
2567    badgeColor: COLOR_VAR_VALIDATOR,
2568    badgeSize: LENGTH_VALIDATOR
2569  },
2570  ellipse: {
2571    fill: COLOR_VAR_VALIDATOR,
2572    fillOpacity: NUMBER_VALIDATOR,
2573    fillRule: genEnumValidator(['nonzero', 'evenodd']),
2574    opacity: NUMBER_VALIDATOR,
2575    stroke: COLOR_VAR_VALIDATOR,
2576    strokeDasharray: ANYTHING_VALIDATOR,
2577    strokeDashoffset: LENGTH_VALIDATOR,
2578    strokeLinejoin: genEnumValidator(['bevel', 'miter', 'round']),
2579    strokeLinecap: genEnumValidator(['butt', 'round', 'square']),
2580    strokeMiterlimit: NUMBER_VALIDATOR,
2581    strokeOpacity: NUMBER_VALIDATOR,
2582    strokeWidth: LENGTH_VALIDATOR,
2583    transform: TRANSFORM_VALIDATOR,
2584    id: ANYTHING_VALIDATOR,
2585    cx: PERCENTAGE_LENGTH_VALIDATOR,
2586    cy: PERCENTAGE_LENGTH_VALIDATOR,
2587    rx: PERCENTAGE_LENGTH_VALIDATOR,
2588    ry: PERCENTAGE_LENGTH_VALIDATOR
2589  },
2590  rect: {
2591    id: ANYTHING_VALIDATOR,
2592    fill: COLOR_VAR_VALIDATOR,
2593    fillOpacity: NUMBER_VALIDATOR,
2594    fillRule: genEnumValidator(['nonzero', 'evenodd']),
2595    opacity: NUMBER_VALIDATOR,
2596    strokeDasharray: ANYTHING_VALIDATOR,
2597    strokeLinejoin: genEnumValidator(['bevel', 'miter', 'round']),
2598    strokeLinecap: genEnumValidator(['butt', 'round', 'square']),
2599    strokeMiterlimit: NUMBER_VALIDATOR,
2600    strokeOpacity: NUMBER_VALIDATOR,
2601    strokeWidth: LENGTH_VALIDATOR,
2602    transform: TRANSFORM_VALIDATOR,
2603    width: PERCENTAGE_LENGTH_VALIDATOR,
2604    height: PERCENTAGE_LENGTH_VALIDATOR,
2605    x: PERCENTAGE_LENGTH_VALIDATOR,
2606    y: PERCENTAGE_LENGTH_VALIDATOR,
2607    rx: PERCENTAGE_LENGTH_VALIDATOR,
2608    ry: PERCENTAGE_LENGTH_VALIDATOR,
2609    stroke: COLOR_VAR_VALIDATOR,
2610    strokeDashoffset: LENGTH_VALIDATOR
2611  },
2612  circle: {
2613    fill: COLOR_VAR_VALIDATOR,
2614    fillOpacity: NUMBER_VALIDATOR,
2615    fillRule: genEnumValidator(['nonzero', 'evenodd']),
2616    opacity: NUMBER_VALIDATOR,
2617    stroke: COLOR_VAR_VALIDATOR,
2618    strokeDasharray: ANYTHING_VALIDATOR,
2619    strokeDashoffset: LENGTH_VALIDATOR,
2620    strokeLinejoin: genEnumValidator(['bevel', 'miter', 'round']),
2621    strokeLinecap: genEnumValidator(['butt', 'round', 'square']),
2622    strokeMiterlimit: NUMBER_VALIDATOR,
2623    strokeOpacity: NUMBER_VALIDATOR,
2624    strokeWidth: LENGTH_VALIDATOR,
2625    transform: TRANSFORM_VALIDATOR,
2626    id: ANYTHING_VALIDATOR,
2627    cx: PERCENTAGE_LENGTH_VALIDATOR,
2628    cy: PERCENTAGE_LENGTH_VALIDATOR,
2629    r: PERCENTAGE_LENGTH_VALIDATOR
2630  },
2631  path: {
2632    fillOpacity: NUMBER_VALIDATOR,
2633    fillRule: genEnumValidator(['nonzero', 'evenodd']),
2634    opacity: NUMBER_VALIDATOR,
2635    strokeDashoffset: LENGTH_VALIDATOR,
2636    strokeLinejoin: genEnumValidator(['bevel', 'miter', 'round']),
2637    strokeLinecap: genEnumValidator(['butt', 'round', 'square']),
2638    strokeMiterlimit: NUMBER_VALIDATOR,
2639    strokeOpacity: NUMBER_VALIDATOR,
2640    strokeWidth: LENGTH_VALIDATOR,
2641    transform: TRANSFORM_VALIDATOR,
2642    id: ANYTHING_VALIDATOR,
2643    d: ANYTHING_VALIDATOR,
2644    fill: COLOR_VAR_VALIDATOR,
2645    strokeDasharray: ANYTHING_VALIDATOR,
2646    stroke: COLOR_VAR_VALIDATOR
2647  },
2648  svg: {
2649    fill: COLOR_VAR_VALIDATOR,
2650    fillOpacity: NUMBER_VALIDATOR,
2651    fillRule: genEnumValidator(['nonzero', 'evenodd']),
2652    opacity: NUMBER_VALIDATOR,
2653    stroke: COLOR_VAR_VALIDATOR,
2654    strokeDasharray: ANYTHING_VALIDATOR,
2655    strokeDashoffset: LENGTH_VALIDATOR,
2656    strokeLinejoin: genEnumValidator(['bevel', 'miter', 'round']),
2657    strokeLinecap: genEnumValidator(['butt', 'round', 'square']),
2658    strokeMiterlimit: NUMBER_VALIDATOR,
2659    strokeOpacity: NUMBER_VALIDATOR,
2660    strokeWidth: LENGTH_VALIDATOR,
2661    transform: TRANSFORM_VALIDATOR,
2662    id: ANYTHING_VALIDATOR,
2663    width: PERCENTAGE_LENGTH_VALIDATOR,
2664    height: PERCENTAGE_LENGTH_VALIDATOR,
2665    x: PERCENTAGE_LENGTH_VALIDATOR,
2666    y: PERCENTAGE_LENGTH_VALIDATOR,
2667    viewbox: ANYTHING_VALIDATOR
2668  },
2669  polygon: {
2670    fill: COLOR_VAR_VALIDATOR,
2671    fillOpacity: NUMBER_VALIDATOR,
2672    opacity: NUMBER_VALIDATOR,
2673    stroke: COLOR_VAR_VALIDATOR,
2674    strokeDasharray: ANYTHING_VALIDATOR,
2675    strokeDashoffset: LENGTH_VALIDATOR,
2676    strokeLinejoin: genEnumValidator(['bevel', 'miter', 'round']),
2677    strokeLinecap: genEnumValidator(['butt', 'round', 'square']),
2678    strokeMiterlimit: NUMBER_VALIDATOR,
2679    strokeOpacity: NUMBER_VALIDATOR,
2680    strokeWidth: LENGTH_VALIDATOR,
2681    transform: TRANSFORM_VALIDATOR,
2682    id: ANYTHING_VALIDATOR,
2683    points: ANYTHING_VALIDATOR,
2684    fillRule: genEnumValidator(['nonzero', 'evenodd'])
2685  },
2686  polyline: {
2687    fill: COLOR_VAR_VALIDATOR,
2688    fillOpacity: NUMBER_VALIDATOR,
2689    opacity: NUMBER_VALIDATOR,
2690    stroke: COLOR_VAR_VALIDATOR,
2691    strokeDasharray: ANYTHING_VALIDATOR,
2692    strokeDashoffset: LENGTH_VALIDATOR,
2693    strokeLinejoin: genEnumValidator(['bevel', 'miter', 'round']),
2694    strokeLinecap: genEnumValidator(['butt', 'round', 'square']),
2695    strokeMiterlimit: NUMBER_VALIDATOR,
2696    strokeOpacity: NUMBER_VALIDATOR,
2697    strokeWidth: LENGTH_VALIDATOR,
2698    transform: TRANSFORM_VALIDATOR,
2699    id: ANYTHING_VALIDATOR,
2700    points: ANYTHING_VALIDATOR,
2701    fillRule: genEnumValidator(['nonzero', 'evenodd'])
2702  },
2703  tspan: {
2704    id: ANYTHING_VALIDATOR,
2705    x: PERCENTAGE_LENGTH_VALIDATOR,
2706    y: PERCENTAGE_LENGTH_VALIDATOR,
2707    dx: PERCENTAGE_LENGTH_VALIDATOR,
2708    dy: PERCENTAGE_LENGTH_VALIDATOR,
2709    rotate: NUMBER_VALIDATOR,
2710    fontSize: LENGTH_VALIDATOR,
2711    fill: COLOR_VAR_VALIDATOR,
2712    fillOpacity: NUMBER_VALIDATOR,
2713    stroke: COLOR_VAR_VALIDATOR,
2714    strokeOpacity: NUMBER_VALIDATOR,
2715    strokeWidth: LENGTH_VALIDATOR
2716  },
2717  textPath: {
2718    id: ANYTHING_VALIDATOR,
2719    path: ANYTHING_VALIDATOR,
2720    startOffset: PERCENTAGE_LENGTH_VALIDATOR,
2721    fontSize: LENGTH_VALIDATOR,
2722    fill: COLOR_VAR_VALIDATOR,
2723    fillOpacity: NUMBER_VALIDATOR,
2724    stroke: COLOR_VAR_VALIDATOR,
2725    strokeOpacity: NUMBER_VALIDATOR,
2726    strokeWidth: LENGTH_VALIDATOR
2727  },
2728  animate: {
2729    id: ANYTHING_VALIDATOR,
2730    attributeName: ANYTHING_VALIDATOR,
2731    begin: ANYTHING_VALIDATOR,
2732    dur: ANYTHING_VALIDATOR,
2733    end: ANYTHING_VALIDATOR,
2734    repeatCount: ANYTHING_VALIDATOR,
2735    fill: genEnumValidator(['freeze', 'remove']),
2736    calcMode: genEnumValidator(['discrete', 'linear', 'paced', 'spline']),
2737    keyTimes: ANYTHING_VALIDATOR,
2738    keySplines: ANYTHING_VALIDATOR,
2739    from: ANYTHING_VALIDATOR,
2740    to: ANYTHING_VALIDATOR,
2741    values: ANYTHING_VALIDATOR
2742  },
2743  animateMotion: {
2744    id: ANYTHING_VALIDATOR,
2745    attributeName: ANYTHING_VALIDATOR,
2746    begin: ANYTHING_VALIDATOR,
2747    dur: ANYTHING_VALIDATOR,
2748    end: ANYTHING_VALIDATOR,
2749    repeatCount: ANYTHING_VALIDATOR,
2750    fill: genEnumValidator(['freeze', 'remove']),
2751    calcMode: genEnumValidator(['discrete', 'linear', 'paced', 'spline']),
2752    keyTimes: ANYTHING_VALIDATOR,
2753    keySplines: ANYTHING_VALIDATOR,
2754    from: ANYTHING_VALIDATOR,
2755    to: ANYTHING_VALIDATOR,
2756    keyPoints: ANYTHING_VALIDATOR,
2757    path: ANYTHING_VALIDATOR,
2758    rotate: ANYTHING_VALIDATOR
2759  },
2760  animateTransform: {
2761    id: ANYTHING_VALIDATOR,
2762    attributeName: ANYTHING_VALIDATOR,
2763    begin: ANYTHING_VALIDATOR,
2764    dur: ANYTHING_VALIDATOR,
2765    end: ANYTHING_VALIDATOR,
2766    repeatCount: ANYTHING_VALIDATOR,
2767    fill: genEnumValidator(['freeze', 'remove']),
2768    calcMode: genEnumValidator(['discrete', 'linear', 'paced', 'spline']),
2769    from: ANYTHING_VALIDATOR,
2770    to: ANYTHING_VALIDATOR,
2771    type: genEnumValidator(['translate', 'scale', 'skewX', 'skewY'])
2772  },
2773  line: {
2774    fill: COLOR_VAR_VALIDATOR,
2775    fillOpacity: NUMBER_VALIDATOR,
2776    opacity: NUMBER_VALIDATOR,
2777    stroke: COLOR_VAR_VALIDATOR,
2778    strokeDasharray: ANYTHING_VALIDATOR,
2779    strokeDashoffset: LENGTH_VALIDATOR,
2780    strokeLinejoin: genEnumValidator(['bevel', 'miter', 'round']),
2781    strokeLinecap: genEnumValidator(['butt', 'round', 'square']),
2782    strokeMiterlimit: NUMBER_VALIDATOR,
2783    strokeOpacity: NUMBER_VALIDATOR,
2784    strokeWidth: LENGTH_VALIDATOR,
2785    fillRule: genEnumValidator(['nonzero', 'evenodd']),
2786    transform: TRANSFORM_VALIDATOR,
2787    id: ANYTHING_VALIDATOR,
2788    x1: PERCENTAGE_LENGTH_VALIDATOR,
2789    y1: PERCENTAGE_LENGTH_VALIDATOR,
2790    x2: PERCENTAGE_LENGTH_VALIDATOR,
2791    y2: PERCENTAGE_LENGTH_VALIDATOR
2792  }
2793}
2794
2795var LITE_PROP_NAME_GROUPS = {
2796  boxModel: {
2797    width: PERCENTAGE_LENGTH_VALIDATOR,
2798    height: PERCENTAGE_LENGTH_VALIDATOR,
2799    padding: SHORTHAND_LENGTH_VALIDATOR,
2800    paddingLeft: LENGTH_VALIDATOR,
2801    paddingRight: LENGTH_VALIDATOR,
2802    paddingTop: LENGTH_VALIDATOR,
2803    paddingBottom: LENGTH_VALIDATOR,
2804    margin:SHORTHAND_AUTO_PERCENTAGE_LENGTH_VALIDATOR,
2805    marginLeft: AUTO_PERCENTAGE_LENGTH_VALIDATOR,
2806    marginRight: AUTO_PERCENTAGE_LENGTH_VALIDATOR,
2807    marginTop: AUTO_PERCENTAGE_LENGTH_VALIDATOR,
2808    marginBottom: AUTO_PERCENTAGE_LENGTH_VALIDATOR,
2809    strokeWidth: LENGTH_VALIDATOR,
2810  },
2811  border:{
2812    borderWidth: SHORTHAND_LENGTH_VALIDATOR,
2813    borderColor: SHORTHAND_COLOR_VALIDATOR,
2814    borderRadius: LENGTH_VALIDATOR,
2815  },
2816  animation:{
2817    animationDuration: TIME_VALIDATOR,
2818    animationDelay: TIME_VALIDATOR,
2819    animationName: NAME_VALIDATOR,
2820    animationTimingFunction: genEnumValidator(['linear', 'ease-in', 'ease-out', 'ease-in-out']),
2821    animationIterationCount: ITERATIONCOUNT_VALIDATOR,
2822    animationFillMode: genEnumValidator(['none', 'forwards'])
2823  },
2824  flexbox: {
2825    flexDirection: genEnumValidator(['row', 'column']),
2826    flexWrap: genEnumValidator(['nowrap', 'wrap']),
2827    justifyContent: genEnumValidator(['flex-start', 'flex-end', 'center', 'space-between',
2828      'space-around', 'space-evenly']),
2829    alignItems: genEnumValidator(['stretch', 'flex-start', 'flex-end', 'center']),
2830  },
2831  position: {
2832    top: PERCENTAGE_LENGTH_VALIDATOR,
2833    left: PERCENTAGE_LENGTH_VALIDATOR,
2834  },
2835  common: {
2836    opacity: NUMBER_VALIDATOR,
2837    backgroundColor: COLOR_VAR_VALIDATOR,
2838    backgroundImage: URL_VALIDATOR,
2839    placeholderColor: COLOR_VAR_VALIDATOR,
2840    display: genEnumValidator(['flex', 'none']),
2841  },
2842  text: {
2843    color: COLOR_VAR_VALIDATOR,
2844    fontSize: LENGTH_VALIDATOR,
2845    fontFamily: genEnumValidator(['HYQiHei-65S']),
2846    letterSpacing: LENGTH_VALIDATOR,
2847    textAlign: genEnumValidator(['left', 'center', 'right']),
2848    textOverflow: genEnumValidator(['clip', 'ellipsis']),
2849  },
2850  slider: {
2851    selectedColor: COLOR_VAR_VALIDATOR,
2852    selectedFontSize: LENGTH_VALIDATOR,
2853    selectedFontFamily: genEnumValidator(['HYQiHei-65S']),
2854    blockColor: COLOR_VAR_VALIDATOR,
2855  },
2856  transform: {
2857    transform: TRANSFORM_VALIDATOR,
2858  },
2859  progress: {
2860    centerX: LENGTH_VALIDATOR,
2861    centerY: LENGTH_VALIDATOR,
2862    radius: LENGTH_VALIDATOR,
2863    startAngle: ANGLE_VALIDATOR,
2864    totalAngle: ANGLE_VALIDATOR
2865  }
2866}
2867
2868var CARD_PROP_NAME_GROUPS = {
2869  boxModel: {
2870    width: PERCENTAGE_LENGTH_VALIDATOR,
2871    height: PERCENTAGE_LENGTH_VALIDATOR,
2872    overflow: genEnumValidator(['auto', 'hidden','scroll','visible']),
2873    padding: SHORTHAND_PERCENTAGE_LENGTH_VALIDATOR,
2874    paddingLeft: PERCENTAGE_LENGTH_VALIDATOR,
2875    paddingRight: PERCENTAGE_LENGTH_VALIDATOR,
2876    paddingTop: PERCENTAGE_LENGTH_VALIDATOR,
2877    paddingBottom: PERCENTAGE_LENGTH_VALIDATOR,
2878    paddingStart: PERCENTAGE_LENGTH_VALIDATOR,
2879    paddingEnd: PERCENTAGE_LENGTH_VALIDATOR,
2880    margin: SHORTHAND_AUTO_PERCENTAGE_LENGTH_VALIDATOR,
2881    marginLeft: AUTO_PERCENTAGE_LENGTH_VALIDATOR,
2882    marginRight: AUTO_PERCENTAGE_LENGTH_VALIDATOR,
2883    marginTop: AUTO_PERCENTAGE_LENGTH_VALIDATOR,
2884    marginBottom: AUTO_PERCENTAGE_LENGTH_VALIDATOR,
2885    marginStart: PERCENTAGE_LENGTH_VALIDATOR,
2886    marginEnd: PERCENTAGE_LENGTH_VALIDATOR,
2887    columns: NUMBER_VALIDATOR,
2888    displayIndex: NUMBER_VALIDATOR,
2889    aspectRatio: NUMBER_VALIDATOR,
2890    minWidth: PERCENTAGE_LENGTH_VALIDATOR,
2891    minHeight: PERCENTAGE_LENGTH_VALIDATOR,
2892    maxWidth: PERCENTAGE_LENGTH_VALIDATOR,
2893    maxHeight: PERCENTAGE_LENGTH_VALIDATOR,
2894    flexWeight: NUMBER_VALIDATOR,
2895    boxShadow: BOX_SHADOW_VALIDATOR,
2896    boxShadowH: LENGTH_VALIDATOR,
2897    boxShadowV: LENGTH_VALIDATOR,
2898    boxShadowBlur: LENGTH_VALIDATOR,
2899    boxShadowSpread: LENGTH_VALIDATOR,
2900    boxShadowColor: COLOR_VAR_VALIDATOR,
2901    filter: FILTER_VALIDATOR,
2902    backdropFilter: FILTER_VALIDATOR,
2903    windowFilter: FILTER_PERCENTAGE_VALIDATOR
2904  },
2905  div: {
2906    gridTemplateColumns: GRID_TEMPLATE_VALIDATOR,
2907    gridTemplateRows: GRID_TEMPLATE_VALIDATOR,
2908    gridGap: LENGTH_VALIDATOR,
2909    gridColumnsGap: LENGTH_VALIDATOR,
2910    gridRowsGap: LENGTH_VALIDATOR,
2911    gridRowStart: NUMBER_VALIDATOR,
2912    gridRowEnd: NUMBER_VALIDATOR,
2913    gridColumnStart: NUMBER_VALIDATOR,
2914    gridColumnEnd: NUMBER_VALIDATOR
2915  },
2916  border: {
2917    border: BORDER_VALIDATOR,
2918    borderWidth: SHORTHAND_LENGTH_VALIDATOR,
2919    borderLeftWidth: LENGTH_VALIDATOR,
2920    borderTopWidth: LENGTH_VALIDATOR,
2921    borderRightWidth: LENGTH_VALIDATOR,
2922    borderBottomWidth: LENGTH_VALIDATOR,
2923    borderColor: SHORTHAND_COLOR_VALIDATOR,
2924    borderLeftColor: COLOR_VAR_VALIDATOR,
2925    borderTopColor: COLOR_VAR_VALIDATOR,
2926    borderRightColor: COLOR_VAR_VALIDATOR,
2927    borderBottomColor: COLOR_VAR_VALIDATOR,
2928    borderStyle: genEnumValidator(['solid', 'dashed', 'dotted']),
2929    borderTopStyle: genEnumValidator(['solid', 'dashed', 'dotted']),
2930    borderRightStyle: genEnumValidator(['solid', 'dashed', 'dotted']),
2931    borderBottomStyle: genEnumValidator(['solid', 'dashed', 'dotted']),
2932    borderLeftStyle: genEnumValidator(['solid', 'dashed', 'dotted']),
2933    borderRadius: LENGTH_VALIDATOR,
2934    borderBottomLeftRadius: LENGTH_VALIDATOR,
2935    borderBottomRightRadius: LENGTH_VALIDATOR,
2936    borderTopLeftRadius: LENGTH_VALIDATOR,
2937    borderTopRightRadius: LENGTH_VALIDATOR,
2938    borderLeft: BORDER_VALIDATOR,
2939    borderRight: BORDER_VALIDATOR,
2940    borderTop: BORDER_VALIDATOR,
2941    borderBottom: BORDER_VALIDATOR
2942  },
2943  flexbox: {
2944    flex: genEnumValidator(['none', 'auto', 'initial']),
2945    flexWrap: genEnumValidator(['nowrap', 'wrap']),
2946    flexGrow: NUMBER_VALIDATOR,
2947    flexShrink: NUMBER_VALIDATOR,
2948    flexBasis: LENGTH_VALIDATOR,
2949    flexDirection: genEnumValidator(['row', 'column']),
2950    justifyContent: genEnumValidator(['flex-start', 'flex-end', 'center', 'space-between',
2951      'space-around', 'space-evenly']),
2952    alignItems: genEnumValidator(['stretch', 'flex-start', 'flex-end', 'center', 'baseline']),
2953    alignContent: genEnumValidator(['stretch', 'flex-start', 'flex-end', 'center', 'space-between', 'space-around']),
2954  },
2955  position: {
2956    position: genEnumValidator(['relative', 'fixed', 'absolute']),
2957    top: PERCENTAGE_LENGTH_VALIDATOR,
2958    bottom: PERCENTAGE_LENGTH_VALIDATOR,
2959    left: PERCENTAGE_LENGTH_VALIDATOR,
2960    right: PERCENTAGE_LENGTH_VALIDATOR,
2961    zIndex: INTEGER_VALIDATOR
2962  },
2963  common: {
2964    background: BACKGROUND_VALIDATOR,
2965    backgroundColor: COLOR_VAR_VALIDATOR,
2966    backgroundImage: URL_VALIDATOR,
2967    backgroundSize: BACKGROUND_SIZE_VALIDATOR,
2968    backgroundRepeat: genEnumValidator(['repeat', 'no-repeat', 'repeat-x', 'repeat-y']),
2969    backgroundPosition: BACKGROUND_POSITION_VALIDATOR,
2970    opacity: NUMBER_VALIDATOR,
2971    appearingDuration: NUMBER_VALIDATOR,
2972    visibility: genEnumValidator(['visible', 'hidden']),
2973    display: genEnumValidator(['flex', 'none', 'grid']),
2974    imageFill: COLOR_VAR_VALIDATOR,
2975    maskImage: MASK_VALIDATOR,
2976    maskPosition: BACKGROUND_POSITION_VALIDATOR,
2977    maskSize: BACKGROUND_SIZE_VALIDATOR
2978  },
2979  text: {
2980    color: COLOR_VAR_VALIDATOR,
2981    fontSize: LENGTH_VALIDATOR,
2982    allowScale: genEnumValidator(['true', 'false']),
2983    letterSpacing: LENGTH_VALIDATOR,
2984    fontStyle: genEnumValidator(['normal', 'italic']),
2985    fontFamily: ANYTHING_VALIDATOR,
2986    fontWeight: genEnumValidator(['normal', 'lighter', 'bold', 'bolder', "medium", "regular",
2987      '100', '200', '300', '400', '500', '600', '700', '800', '900']),
2988    textDecoration: genEnumValidator(['none', 'underline', 'line-through']),
2989    textAlign: genEnumValidator(['start', 'end', 'left', 'center', 'right']),
2990    textOverflow: genEnumValidator(['clip', 'ellipsis']),
2991    textIndent: TEXT_INDENT_VALIDATOR,
2992    lineHeight: LENGTH_VALIDATOR,
2993    maxLines: ANYTHING_VALIDATOR,
2994    minFontSize: LENGTH_VALIDATOR,
2995    maxFontSize: LENGTH_VALIDATOR,
2996    fontSizeStep: LENGTH_VALIDATOR,
2997    preferFontSizes: ARRAY_LENGTH_VALIDATOR,
2998    adaptHeight: genEnumValidator(['true', 'false'])
2999  },
3000  progress: {
3001    secondaryColor: COLOR_VAR_VALIDATOR,
3002    scaleWidth: LENGTH_VALIDATOR,
3003    scaleNumber: NUMBER_VALIDATOR,
3004    startAngle: ANGLE_VALIDATOR,
3005    totalAngle: ANGLE_VALIDATOR,
3006    centerX: LENGTH_VALIDATOR,
3007    centerY: LENGTH_VALIDATOR,
3008    radius: LENGTH_VALIDATOR,
3009    direction: genEnumValidator(['start-to-end', 'end-to-start']),
3010    sections: NAME_VALIDATOR,
3011    colors: ARRAY_COLOR_VALIDATOR,
3012    weights: ARRAY_NUMBER_VALIDATOR
3013  },
3014  chart: {
3015    strokeWidth: LENGTH_VALIDATOR,
3016  },
3017  button: {
3018    textColor: COLOR_VAR_VALIDATOR,
3019    iconWidth: LENGTH_VALIDATOR,
3020    iconHeight: LENGTH_VALIDATOR
3021  },
3022  image: {
3023    objectFit: genEnumValidator(['cover', 'fill', 'contain', 'none', 'scale-down']),
3024    matchTextDirection: genEnumValidator(['false', 'true']),
3025    fitOriginalSize: genEnumValidator(['false', 'true']),
3026  },
3027  list: {
3028    itemExtent: PERCENTAGE_LENGTH_VALIDATOR,
3029    fadeColor: COLOR_VAR_VALIDATOR,
3030    dividerColor: COLOR_VAR_VALIDATOR,
3031    dividerHeight: LENGTH_VALIDATOR,
3032    dividerLength: LENGTH_VALIDATOR,
3033    dividerOrigin: LENGTH_VALIDATOR,
3034    scrollbarColor: COLOR_VALIDATOR,
3035    scrollbarWidth: LENGTH_VALIDATOR,
3036    scrollbarOffset: ARRAY_LENGTH_VALIDATOR
3037  }
3038}
3039
3040var backgroundValidatorMap = {
3041  linearGradient: LINEAR_GRADIENT_VALIDATOR,
3042  repeatingLinearGradient: LINEAR_GRADIENT_VALIDATOR,
3043  linearGradientColor: ARRAY_COLOR_STOP_VALIDATOR,
3044  linearGradientAngle: ANGLE_VALIDATOR,
3045  linearGradientDirection: GRADIENT_DIRECTION_VALIDATOR
3046}
3047
3048var transformValidatorMap = {
3049  translate: MULTIPLE_PERCENTAGE_LENGTH_VALIDATOR,
3050  translate3d: MULTIPLE_PERCENTAGE_LENGTH_VALIDATOR,
3051  translateX: PERCENTAGE_LENGTH_VALIDATOR,
3052  translateY: PERCENTAGE_LENGTH_VALIDATOR,
3053  translateZ: PERCENTAGE_LENGTH_VALIDATOR,
3054  scale: MULTIPLE_NUMBER_VALIDATOR,
3055  scale3d: MULTIPLE_NUMBER_VALIDATOR,
3056  scaleX: NUMBER_VALIDATOR,
3057  scaleY: NUMBER_VALIDATOR,
3058  scaleZ: NUMBER_VALIDATOR,
3059  rotate: MUTIPLE_ANGLE_VALIDATOR,
3060  rotate3d: ROTATE3D_VALIDATOR,
3061  rotateX: ANGLE_VALIDATOR,
3062  rotateY: ANGLE_VALIDATOR,
3063  rotateZ: ANGLE_VALIDATOR,
3064  skew: MUTIPLE_ANGLE_VALIDATOR,
3065  skewX: ANGLE_VALIDATOR,
3066  skewY: ANGLE_VALIDATOR,
3067  matrix: MULTIPLE_NUMBER_VALIDATOR,
3068  matrix3d: MULTIPLE_NUMBER_VALIDATOR,
3069  perspective: PERCENTAGE_LENGTH_VALIDATOR,
3070}
3071
3072var SUGGESTED_PROP_NAME_GROUP = {}
3073
3074var validatorMap = {}
3075
3076const card = process.env.DEVICE_LEVEL === 'card'
3077var isLiteDevice = process.env.DEVICE_LEVEL === 'lite'
3078
3079var PROP_NAME_GROUPS = process.env.DEVICE_LEVEL === 'lite' ? LITE_PROP_NAME_GROUPS :
3080  card ? CARD_PROP_NAME_GROUPS : RICH_PROP_NAME_GROUPS
3081
3082/**
3083 * flatten `PROP_NAME_GROUPS` to `validatorMap`
3084 */
3085function genValidatorMap() {
3086  var groupName, group, name
3087  for (groupName in PROP_NAME_GROUPS) {
3088    group = PROP_NAME_GROUPS[groupName]
3089    for (name in group) {
3090      validatorMap[name] = group[name]
3091    }
3092  }
3093}
3094
3095genValidatorMap()
3096
3097function getValueUnit(dem) {
3098  var str = dem.toString()
3099  var getValue = str.match(/[-]{0,1}[1-9][0-9]*/)
3100  var getUnit = str.match(/px|cm|%|em|vp|fp/)
3101  var result = {value: getValue, unit: getUnit}
3102  return result
3103}
3104
3105function isOperator(value) {
3106  var operatorString = "+-*/()"
3107  return operatorString.indexOf(value) > -1
3108}
3109
3110function getPrioraty(value) {
3111  switch(value) {
3112    case '+':
3113    case '-':
3114      return 1
3115    case '*':
3116    case '/':
3117      return 2
3118    default:
3119      return 0
3120  }
3121}
3122
3123function prioraty(o1, o2) {
3124  return getPrioraty(o1) <= getPrioraty(o2)
3125}
3126
3127function dal2Rpn(exp) {
3128  var inputStack = []
3129  var outputStack = []
3130  var outputQueue = []
3131  var str =
3132    exp.replace(/calc/g, "").replace(/(?<!var\(\-\-\w+|var\(\-\-\w+\,\s*\w+)\)/g, " )").replace(/(?<!var)\(/g, "( ")
3133  var inputStack=str.split(/(?<!\,)\s+/)
3134  var value, log
3135  while(inputStack.length > 0) {
3136    var cur = inputStack.shift()
3137    if(isOperator(cur)) {
3138      if(cur == '(') {
3139        outputStack.push(cur)
3140      } else if(cur == ')') {
3141        var po = outputStack.pop()
3142        while(po != '(' && outputStack.length > 0) {
3143          outputQueue.push(po)
3144          po = outputStack.pop()
3145        }
3146        if(po != '(') {
3147          log = {reason: 'ERROR: Expression unmatched ()'}
3148        }
3149      } else {
3150        while(prioraty(cur, outputStack[outputStack.length - 1]) && outputStack.length > 0) {
3151          outputQueue.push(outputStack.pop())
3152        }
3153        outputStack.push(cur)
3154      }
3155    } else {
3156      outputQueue.push(cur)
3157    }
3158  }
3159  return {
3160    value: outputQueue,
3161    log: log
3162  }
3163}
3164
3165function checkComputation(left, right, operator) {
3166  var value, log
3167  if (operator == '*') {
3168    if ((right.match(/[a-zA-Z]/) && left.match(/[a-zA-Z]/)) || (!right.match(/[a-zA-Z]/) && !left.match(/[a-zA-Z]/))) {
3169      log = {reason: 'ERROR: The multiplier must contain and contain only one integer'}
3170    }
3171  }
3172  if (operator == '/') {
3173    if (right.match(/[a-zA-Z]|(?<![1-9])[0]/)) {
3174      log = {reason: 'ERROR: Divisor must be an integer and cannot be zero'}
3175    }
3176  }
3177  if (operator == '+') {
3178    if (!(right.match(/[a-zA-Z%]/) && left.match(/[a-zA-Z%]/))) {
3179      log = {reason: 'ERROR: Addition cannot contain integers'}
3180    }
3181  }
3182  if (operator == '-') {
3183    if (!(right.match(/[a-zA-Z%]/) && left.match(/[a-zA-Z%]/))) {
3184      log = {reason: 'ERROR: Subtraction cannot contain integers'}
3185    }
3186  }
3187  return log
3188}
3189
3190function getResult(left, right, operator) {
3191  var value, log, errLog
3192  if (left.match(/var/)) {
3193    left = cssVarFun(left)
3194  }
3195  if (right.match(/var/)) {
3196    right = cssVarFun(right)
3197  }
3198  errLog = checkComputation(left, right, operator)
3199  if (errLog) {
3200    return { value: null, log: errLog }
3201  }
3202  var result, value, unit
3203  var leftValue = getValueUnit(left)
3204  var rightValue = getValueUnit(right)
3205  if (left.match(/\(/) | right.match(/\(/)) {
3206    result = left + ' ' + operator + ' ' + right
3207  } else {
3208    if (operator == '*') {
3209      value = leftValue.value * rightValue.value
3210      if (leftValue.unit == null) {
3211        unit = rightValue.unit
3212      } else { unit = leftValue.unit}
3213      result = value + unit
3214    } else if (operator == '/') {
3215      if (parseInt(rightValue.value) != 0) {
3216        value = leftValue.value / rightValue.value
3217        unit = leftValue.unit
3218        result = value + unit
3219      }
3220    } else if (operator == '+') {
3221      if (JSON.stringify(leftValue.unit) == JSON.stringify(rightValue.unit)) {
3222        value = parseInt(leftValue.value) + parseInt(rightValue.value)
3223        unit = leftValue.unit
3224        result = value + unit
3225      } else result = '(' + left + ' ' + operator + ' ' + right + ')'
3226    } else if (operator == '-') {
3227      if (JSON.stringify(leftValue.unit) == JSON.stringify(rightValue.unit)) {
3228        value = parseInt(leftValue.value) - parseInt(rightValue.value)
3229        unit = leftValue.unit
3230        result = value + unit
3231      } else result = '(' + left + ' ' + operator + ' ' + right + ')'
3232    }
3233  }
3234  return { value: result, log: null }
3235}
3236
3237function evalRpn(rpnQueue) {
3238  var outputStack = []
3239  var value, res, log
3240  while(rpnQueue.length > 0) {
3241    var cur = rpnQueue.shift()
3242    if(!isOperator(cur)) {
3243      outputStack.push(cur)
3244    } else {
3245      if(outputStack.length < 2) {
3246      log = {reason: 'ERROR: Expression does not conform to specification'}
3247      }
3248      var sec = outputStack.pop()
3249      var fir = outputStack.pop()
3250      res = getResult(fir, sec, cur)
3251      log = res.log
3252      if (log) {
3253        return {
3254          value: null,
3255          log: log
3256        }
3257      } else {
3258        outputStack.push(res.value)
3259      }
3260    }
3261  }
3262  if(outputStack.length != 1) {
3263    log = {reason: 'ERROR: Expression does not conform to specification'}
3264  } else {
3265    if (outputStack[0].match(/[+-]/)) {
3266      value = 'calc' + outputStack[0]
3267    } else {
3268      value = outputStack[0]
3269    }
3270  }
3271  return {
3272    value: value,
3273    log: log
3274  }
3275}
3276
3277var cssPropData = []
3278
3279function saveCssProp(name, value) {
3280  if (name.match(/\-\-/)) {
3281    while (value.match(/var/)) {
3282      var value = cssVarFun(value)
3283    }
3284    cssPropData.push({name: name,value: value})
3285  }
3286}
3287
3288function cssVarFun(value) {
3289  if (value.match(/calc/)) {
3290    return value
3291  } else {
3292    if (value.match(/var/)) {
3293      if (value.match(/\,/)) {
3294        var cssVarFir = value.substring(0,value.indexOf(",")).replace("var(","").trim()
3295        var cssVarSec = value.substring(value.indexOf(",")+1,value.length).replace(")","").trim()
3296      } else {
3297          var cssVarFir = value.replace("var(","").replace(")","").trim()
3298          var cssVarSec = ""
3299      }
3300      let varValue = cssVarSec
3301      for(var i=0, len=cssPropData.length; i<len; i++) {
3302        var cPDName = cssPropData[i].name.trim()
3303        cssVarFir = util.hyphenedToCamelCase(cssVarFir)
3304        if (cssVarFir == cPDName) {
3305          varValue = cssPropData[i].value
3306        }
3307      }
3308      return varValue
3309    } else {
3310      return value
3311    }
3312  }
3313}
3314
3315function expValidate(name, value) {
3316  var res, log
3317  saveCssProp(name, value)
3318  if (typeof value === 'string' && name != 'border') {
3319    if (value.match(/var/)) {
3320      value = cssVarFun(value)
3321    }
3322    if (value.match(/calc/)) {
3323      var checkOp =
3324        /[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()]/
3325      if (value.match(checkOp) && value.match(/calc\(|var\(\-\-/)) {
3326        log = {reason: 'ERROR: Expression error, A space is required before and after the operator'}
3327        return {
3328          log: log
3329        }
3330      }
3331      res = dal2Rpn(value)
3332      res = evalRpn(res.value)
3333      log = res.log
3334      value = res.value
3335    }
3336  }
3337  return {
3338    value: value,
3339    log: log
3340  }
3341}
3342
3343/**
3344 * validate a CSS name/value pair
3345 *
3346 * @param  {string} name   camel cased
3347 * @param  {string} value
3348 * @return {object}
3349 * - value:string or null
3350 * - log:{reason:string} or undefined
3351 */
3352function validate(name, value) {
3353  var log, expRes
3354  expRes = expValidate(name, value)
3355  if (expRes.log) {
3356    return {
3357      value: null,
3358      log: expRes.log
3359    }
3360  } else {
3361    value = expRes.value
3362  }
3363
3364  var result
3365  var validator = validatorMap[name]
3366  if (typeof validator === 'function') {
3367    const flag = /{{{(.+?)}}}|{{(.+?)}}/.test(value) && card
3368    if (typeof value !== 'function' &&  !flag) {
3369      result = validator(value, name)
3370    }
3371    /* istanbul ignore else */
3372    else {
3373      result = {value: value}
3374    }
3375    if (result.reason) {
3376      log = {reason: result.reason(name, value, result.value)}
3377    }
3378  }
3379  else {
3380    // ensure number type, no `px`
3381    /* istanbul ignore else */
3382    if (typeof value !== 'function') {
3383      var match = value.match(LENGTH_REGEXP)
3384      if (match && (!match[1] || SUPPORT_CSS_UNIT.indexOf(match[1]) === -1)) {
3385        value = parseFloat(value)
3386      }
3387    }
3388    result = {value: value}
3389    var suggestedName = SUGGESTED_PROP_NAME_GROUP[name]
3390    var suggested = suggestedName ? ', suggest `' + util.camelCaseToHyphened(suggestedName) + '`' : ''
3391    log = {reason: 'WARNING: `' + util.camelCaseToHyphened(name) +
3392      '` is not a standard attribute name and may not be supported' + suggested}
3393  }
3394  return {
3395    value: result.value,
3396    log: log
3397  }
3398}
3399
3400var validateFuncMap = {
3401  length: LENGTH_VALIDATOR,
3402  number: NUMBER_VALIDATOR,
3403  date: DATE_VALIDATOR
3404}
3405
3406module.exports = {
3407  BASIC_COLOR_KEYWORDS: BASIC_COLOR_KEYWORDS,
3408  EXTENDED_COLOR_KEYWORDS: EXTENDED_COLOR_KEYWORDS,
3409
3410  LENGTH_VALIDATOR: LENGTH_VALIDATOR,
3411  COLOR_VALIDATOR: COLOR_VALIDATOR,
3412  COLOR_VAR_VALIDATOR: COLOR_VAR_VALIDATOR,
3413  NUMBER_VALIDATOR: NUMBER_VALIDATOR,
3414  INTEGER_VALIDATOR: INTEGER_VALIDATOR,
3415  genEnumValidator: genEnumValidator,
3416
3417  TRANSITION_PROPERTY_VALIDATOR: TRANSITION_PROPERTY_VALIDATOR,
3418  TRANSITION_DURATION_VALIDATOR: TRANSITION_INTERVAL_VALIDATOR,
3419  TRANSITION_DELAY_VALIDATOR: TRANSITION_INTERVAL_VALIDATOR,
3420  TRANSITION_TIMING_FUNCTION_VALIDATOR: TRANSITION_TIMING_FUNCTION_VALIDATOR,
3421
3422  PROP_NAME_GROUPS: PROP_NAME_GROUPS,
3423  validateFuncMap: validateFuncMap,
3424
3425  map: validatorMap,
3426  validate: validate
3427}
3428