188c88e8eSopenharmony_ci'use strict'
288c88e8eSopenharmony_ci
388c88e8eSopenharmony_civar css = require('css')
488c88e8eSopenharmony_civar util = require('./lib/util')
588c88e8eSopenharmony_civar validateItem = require('./lib/validator').validate
688c88e8eSopenharmony_civar fs = require('fs')
788c88e8eSopenharmony_civar path = require('path')
888c88e8eSopenharmony_civar lodash = require('lodash')
988c88e8eSopenharmony_ci
1088c88e8eSopenharmony_civar SELECTOR_MATCHER = /^[\.#]?[A-Za-z0-9_\-:]+$/
1188c88e8eSopenharmony_civar DESCENDANT_SELECTOR_MATCHER = /^([.#]?[A-Za-z0-9_-]+(\s+|\s*>\s*))+([.#]?[A-Za-z0-9_\-:]+)$/
1288c88e8eSopenharmony_civar IMPORT_MATCHER = /(['"]([^()]+?)['"])|(['"]([^()]+?)['"]\s+(only|not)?\s?(screen)?\s?((and|or|,|not|landscape)?\s?[(]([^()])+[)]\s*)+)/g
1388c88e8eSopenharmony_civar LENGTH_REGEXP = /^[-+]?\d*\.?\d+(\S*)$/
1488c88e8eSopenharmony_ciconst CARD_SELECTOR = /^[\.#][A-Za-z0-9_\-]+$/
1588c88e8eSopenharmony_ciconst card = process.env.DEVICE_LEVEL === 'card'
1688c88e8eSopenharmony_civar ALL_SELECTOR_MATCHER = /^\*$/
1788c88e8eSopenharmony_civar ATTRIBUTE_SELECTOR = /^\[+(?![0-9])\w{0,}(\s*=\s*)((?![0-9])\w{0,}|\"\w{0,}\")\]+$/
1888c88e8eSopenharmony_civar ELEMENT_AND_ELEMENT = /^[a-zA-Z][a-zA-Z-]{0,}\s{0,}(\+\s{0,}[a-zA-Z][a-zA-Z-]{0,})+$/
1988c88e8eSopenharmony_civar CONTENT_ID = /^[a-zA-Z][a-zA-Z-]{0,}([#][a-zA-Z][a-zA-Z0-9-]{0,})(.+?::(after|before))+$/
2088c88e8eSopenharmony_ci
2188c88e8eSopenharmony_ci/**
2288c88e8eSopenharmony_ci * expand margin、padding、border、borderWidth、borderColor、borderStyle properties、animation
2388c88e8eSopenharmony_ci *
2488c88e8eSopenharmony_ci * @param {object} subResult
2588c88e8eSopenharmony_ci * @param {String} camelCasedName
2688c88e8eSopenharmony_ci * @param {object} ruleResult
2788c88e8eSopenharmony_ci */
2888c88e8eSopenharmony_cifunction expand (subResult, camelCasedName, ruleResult) {
2988c88e8eSopenharmony_ci  if (camelCasedName === 'border') {
3088c88e8eSopenharmony_ci    subResult.value.forEach(function (item) {
3188c88e8eSopenharmony_ci      if (item.type === 'Width' || item.type === 'Color' || item.type === 'Style') {
3288c88e8eSopenharmony_ci        const spliceName = [camelCasedName + 'Top' + item.type, camelCasedName + 'Right' + item.type, camelCasedName +
3388c88e8eSopenharmony_ci          'Bottom' + item.type, camelCasedName + 'Left' + item.type]
3488c88e8eSopenharmony_ci        util.splitAttr(ruleResult, item.value, spliceName)
3588c88e8eSopenharmony_ci      }
3688c88e8eSopenharmony_ci      else {
3788c88e8eSopenharmony_ci        ruleResult[camelCasedName + item.type] = item.value
3888c88e8eSopenharmony_ci      }
3988c88e8eSopenharmony_ci    })
4088c88e8eSopenharmony_ci  }
4188c88e8eSopenharmony_ci  else if (['borderTop', 'borderRight', 'borderBottom', 'borderLeft'].includes(camelCasedName)) {
4288c88e8eSopenharmony_ci    subResult.value.forEach(function (item) {
4388c88e8eSopenharmony_ci      ruleResult[camelCasedName + item.type] = item.value
4488c88e8eSopenharmony_ci    })
4588c88e8eSopenharmony_ci  }
4688c88e8eSopenharmony_ci  else if (camelCasedName === 'margin' || camelCasedName === 'padding') {
4788c88e8eSopenharmony_ci    const spliceName = [camelCasedName + 'Top', camelCasedName + 'Right',
4888c88e8eSopenharmony_ci      camelCasedName + 'Bottom', camelCasedName + 'Left']
4988c88e8eSopenharmony_ci    util.splitAttr(ruleResult, subResult.value, spliceName)
5088c88e8eSopenharmony_ci  }
5188c88e8eSopenharmony_ci  else if (camelCasedName === 'borderWidth') {
5288c88e8eSopenharmony_ci    util.splitAttr(ruleResult, subResult.value, ['borderTopWidth', 'borderRightWidth',
5388c88e8eSopenharmony_ci      'borderBottomWidth', 'borderLeftWidth'])
5488c88e8eSopenharmony_ci  }
5588c88e8eSopenharmony_ci  else if (camelCasedName === 'borderColor') {
5688c88e8eSopenharmony_ci    util.splitAttr(ruleResult, subResult.value, ['borderTopColor', 'borderRightColor',
5788c88e8eSopenharmony_ci      'borderBottomColor', 'borderLeftColor'])
5888c88e8eSopenharmony_ci  }
5988c88e8eSopenharmony_ci  else if (camelCasedName === 'borderStyle') {
6088c88e8eSopenharmony_ci    util.splitAttr(ruleResult, subResult.value, ['borderTopStyle', 'borderRightStyle',
6188c88e8eSopenharmony_ci      'borderBottomStyle', 'borderLeftStyle'])
6288c88e8eSopenharmony_ci  }
6388c88e8eSopenharmony_ci  else if (camelCasedName === 'borderRadius') {
6488c88e8eSopenharmony_ci    util.splitAttr(ruleResult, subResult.value, ['borderBottomLeftRadius', 'borderBottomRightRadius',
6588c88e8eSopenharmony_ci      'borderTopLeftRadius', 'borderTopRightRadius'])
6688c88e8eSopenharmony_ci  }
6788c88e8eSopenharmony_ci  else if (camelCasedName === 'gridGap') {
6888c88e8eSopenharmony_ci    util.splitAttr(ruleResult, subResult.value, ['gridRowsGap', 'gridColumnsGap'])
6988c88e8eSopenharmony_ci  }
7088c88e8eSopenharmony_ci  else if (camelCasedName === 'boxShadow') {
7188c88e8eSopenharmony_ci    subResult.value.forEach(function (item) {
7288c88e8eSopenharmony_ci      if (item.type === 'H' || item.type === 'V' || item.type === 'Blur' || item.type === 'Spread' ||
7388c88e8eSopenharmony_ci        item.type === 'Color') {
7488c88e8eSopenharmony_ci        util.splitAttr(ruleResult, item.value, [camelCasedName + item.type])
7588c88e8eSopenharmony_ci      }
7688c88e8eSopenharmony_ci    })
7788c88e8eSopenharmony_ci  }
7888c88e8eSopenharmony_ci  else if (camelCasedName === 'animation') {
7988c88e8eSopenharmony_ci    Object.assign(ruleResult, subResult.value);
8088c88e8eSopenharmony_ci  }
8188c88e8eSopenharmony_ci  else {
8288c88e8eSopenharmony_ci    // never to do
8388c88e8eSopenharmony_ci  }
8488c88e8eSopenharmony_ci}
8588c88e8eSopenharmony_ci
8688c88e8eSopenharmony_ci/**
8788c88e8eSopenharmony_ci * expand flex style
8888c88e8eSopenharmony_ci *
8988c88e8eSopenharmony_ci * @param {object} rule
9088c88e8eSopenharmony_ci * @param {Array} ruleLog
9188c88e8eSopenharmony_ci */
9288c88e8eSopenharmony_cifunction flexExpand(rule, ruleLog) {
9388c88e8eSopenharmony_ci  for (let i = 0; i < rule.declarations.length; i++) {
9488c88e8eSopenharmony_ci    let declaration = rule.declarations[i]
9588c88e8eSopenharmony_ci    if (declaration.property === 'flex') {
9688c88e8eSopenharmony_ci      let values =  declaration.value.split(/\s+/)
9788c88e8eSopenharmony_ci      rule.declarations.splice(i, 1)
9888c88e8eSopenharmony_ci      if (values.length === 1) {
9988c88e8eSopenharmony_ci        checkFlexOne(rule, ruleLog, declaration, values, i)
10088c88e8eSopenharmony_ci      } else if (values.length === 2) {
10188c88e8eSopenharmony_ci        checkFlexTwo(rule, ruleLog, declaration, values, i)
10288c88e8eSopenharmony_ci      } else if (values.length === 3) {
10388c88e8eSopenharmony_ci        checkFlexThree(rule, ruleLog, declaration, values, i)
10488c88e8eSopenharmony_ci      } else {
10588c88e8eSopenharmony_ci        ruleLog.push({
10688c88e8eSopenharmony_ci          line: declaration.position.start.line,
10788c88e8eSopenharmony_ci          column: declaration.position.start.column,
10888c88e8eSopenharmony_ci          reason: 'ERROR: Value `' + declaration.value + '` of the `' +
10988c88e8eSopenharmony_ci            declaration.property + '` attribute is incorrect.'
11088c88e8eSopenharmony_ci        })
11188c88e8eSopenharmony_ci      }
11288c88e8eSopenharmony_ci    }
11388c88e8eSopenharmony_ci  }
11488c88e8eSopenharmony_ci}
11588c88e8eSopenharmony_ci
11688c88e8eSopenharmony_cifunction getUnit(value) {
11788c88e8eSopenharmony_ci  value = value.toString().trim()
11888c88e8eSopenharmony_ci  let match = value.match(LENGTH_REGEXP)
11988c88e8eSopenharmony_ci  if (match) {
12088c88e8eSopenharmony_ci    let unit = match[1]
12188c88e8eSopenharmony_ci    if (unit) {
12288c88e8eSopenharmony_ci      if (unit === 'px') {
12388c88e8eSopenharmony_ci        return "px"
12488c88e8eSopenharmony_ci      }
12588c88e8eSopenharmony_ci    } else {
12688c88e8eSopenharmony_ci      return "none"
12788c88e8eSopenharmony_ci    }
12888c88e8eSopenharmony_ci  }
12988c88e8eSopenharmony_ci  return null
13088c88e8eSopenharmony_ci}
13188c88e8eSopenharmony_ci
13288c88e8eSopenharmony_cifunction checkFlexOne(rule, ruleLog, declaration, values, i) {
13388c88e8eSopenharmony_ci  const array = ['none', 'auto', 'initial']
13488c88e8eSopenharmony_ci  if (array.includes(values[0])) {
13588c88e8eSopenharmony_ci    rule.declarations.splice(i, 0, {type: 'declaration', property: 'flex',
13688c88e8eSopenharmony_ci      value: values[0], position: declaration.position})
13788c88e8eSopenharmony_ci  } else if (getUnit(values[0]) === 'px') {
13888c88e8eSopenharmony_ci    rule.declarations.splice(i, 0, {type: 'declaration', property: 'flex-basis',
13988c88e8eSopenharmony_ci      value: values[0], position: declaration.position})
14088c88e8eSopenharmony_ci  } else if (getUnit(values[0]) === 'none') {
14188c88e8eSopenharmony_ci    rule.declarations.splice(i, 0, {type: 'declaration', property: 'flex-grow',
14288c88e8eSopenharmony_ci      value: values[0], position: declaration.position})
14388c88e8eSopenharmony_ci  } else {
14488c88e8eSopenharmony_ci    ruleLog.push({
14588c88e8eSopenharmony_ci      line: declaration.position.start.line,
14688c88e8eSopenharmony_ci      column: declaration.position.start.column,
14788c88e8eSopenharmony_ci      reason: 'ERROR: Value `' + declaration.value + '` of the `' + declaration.property +
14888c88e8eSopenharmony_ci        '` attribute is incorrect.' + 'It must be a number, a number with unit `' + 'px`' +
14988c88e8eSopenharmony_ci        ', none, auto, or initial.'
15088c88e8eSopenharmony_ci    })
15188c88e8eSopenharmony_ci  }
15288c88e8eSopenharmony_ci}
15388c88e8eSopenharmony_ci
15488c88e8eSopenharmony_cifunction checkFlexTwo(rule, ruleLog, declaration, values, i) {
15588c88e8eSopenharmony_ci  if (getUnit(values[0]) === 'none') {
15688c88e8eSopenharmony_ci    rule.declarations.splice(i, 0, {type: 'declaration', property: 'flex-grow',
15788c88e8eSopenharmony_ci      value: values[0], position: declaration.position})
15888c88e8eSopenharmony_ci    if (getUnit(values[1]) === 'px') {
15988c88e8eSopenharmony_ci      rule.declarations.splice(i, 0, {type: 'declaration', property: 'flex-basis',
16088c88e8eSopenharmony_ci        value: values[1], position: declaration.position})
16188c88e8eSopenharmony_ci    } else if (getUnit(values[1]) === 'none') {
16288c88e8eSopenharmony_ci      rule.declarations.splice(i, 0, {type: 'declaration', property: 'flex-shrink',
16388c88e8eSopenharmony_ci        value: values[1], position: declaration.position})
16488c88e8eSopenharmony_ci    } else {
16588c88e8eSopenharmony_ci      ruleLog.push({
16688c88e8eSopenharmony_ci        line: declaration.position.start.line,
16788c88e8eSopenharmony_ci        column: declaration.position.start.column,
16888c88e8eSopenharmony_ci        reason: 'ERROR: Value `' + declaration.value + '` of the `' + declaration.property +
16988c88e8eSopenharmony_ci          '` attribute is incorrect. Value `' + values[1] +
17088c88e8eSopenharmony_ci          '` must be a number or a number with unit `' + 'px`.'
17188c88e8eSopenharmony_ci      })
17288c88e8eSopenharmony_ci    }
17388c88e8eSopenharmony_ci  } else {
17488c88e8eSopenharmony_ci    ruleLog.push({
17588c88e8eSopenharmony_ci      line: declaration.position.start.line,
17688c88e8eSopenharmony_ci      column: declaration.position.start.column,
17788c88e8eSopenharmony_ci      reason: 'ERROR: Value `' + declaration.value + '` of the `' +
17888c88e8eSopenharmony_ci      declaration.property + '` attribute is incorrect. Value `' + values[0] + '` must be a number.'
17988c88e8eSopenharmony_ci    })
18088c88e8eSopenharmony_ci  }
18188c88e8eSopenharmony_ci}
18288c88e8eSopenharmony_ci
18388c88e8eSopenharmony_cifunction checkFlexThree(rule, ruleLog, declaration, values, i) {
18488c88e8eSopenharmony_ci  if (getUnit(values[0]) === 'none' && getUnit(values[1]) === 'none' && getUnit(values[2]) === 'px') {
18588c88e8eSopenharmony_ci    rule.declarations.splice(i, 0, {type: 'declaration', property: 'flex-grow',
18688c88e8eSopenharmony_ci      value: values[0], position: declaration.position})
18788c88e8eSopenharmony_ci    rule.declarations.splice(i, 0, {type: 'declaration', property: 'flex-shrink',
18888c88e8eSopenharmony_ci      value: values[1], position: declaration.position})
18988c88e8eSopenharmony_ci    rule.declarations.splice(i, 0, {type: 'declaration', property: 'flex-basis',
19088c88e8eSopenharmony_ci      value: values[2], position: declaration.position})
19188c88e8eSopenharmony_ci  } else {
19288c88e8eSopenharmony_ci    ruleLog.push({
19388c88e8eSopenharmony_ci      line: declaration.position.start.line,
19488c88e8eSopenharmony_ci      column: declaration.position.start.column,
19588c88e8eSopenharmony_ci      reason: 'ERROR: Value `' + declaration.value + '` of the `' + declaration.property +
19688c88e8eSopenharmony_ci        '` attribute is incorrect. It must be in the format of (1, 1, 1px).'
19788c88e8eSopenharmony_ci    })
19888c88e8eSopenharmony_ci  }
19988c88e8eSopenharmony_ci}
20088c88e8eSopenharmony_ci
20188c88e8eSopenharmony_ci/**
20288c88e8eSopenharmony_ci * Parse `<style>` code to a JSON Object and log errors & warnings
20388c88e8eSopenharmony_ci *
20488c88e8eSopenharmony_ci * @param {string} code
20588c88e8eSopenharmony_ci * @param {function} done which will be called with
20688c88e8eSopenharmony_ci * - err:Error
20788c88e8eSopenharmony_ci * - data.jsonStyle{}: `classname.propname.value`-like object
20888c88e8eSopenharmony_ci * - data.log[{line, column, reason}]
20988c88e8eSopenharmony_ci */
21088c88e8eSopenharmony_cifunction parse(code, done, resourcePath) {
21188c88e8eSopenharmony_ci  var ast, err, jsonStyle = {}, log = []
21288c88e8eSopenharmony_ci
21388c88e8eSopenharmony_ci  // css parse
21488c88e8eSopenharmony_ci  ast = css.parse(code, {silent: true, source: resourcePath});
21588c88e8eSopenharmony_ci
21688c88e8eSopenharmony_ci  // catch syntax error
21788c88e8eSopenharmony_ci  if (ast.stylesheet.parsingErrors && ast.stylesheet.parsingErrors.length) {
21888c88e8eSopenharmony_ci    err = ast.stylesheet.parsingErrors
21988c88e8eSopenharmony_ci    err.forEach(function (error) {
22088c88e8eSopenharmony_ci      log.push({line: error.line, column: error.column, reason: error.toString().replace('Error', 'ERROR')})
22188c88e8eSopenharmony_ci    })
22288c88e8eSopenharmony_ci  }
22388c88e8eSopenharmony_ci
22488c88e8eSopenharmony_ci  // walk all
22588c88e8eSopenharmony_ci  /* istanbul ignore else */
22688c88e8eSopenharmony_ci  if (ast && ast.type === 'stylesheet' && ast.stylesheet &&
22788c88e8eSopenharmony_ci      ast.stylesheet.rules && ast.stylesheet.rules.length) {
22888c88e8eSopenharmony_ci    ast.stylesheet.rules.forEach(function (rule) {
22988c88e8eSopenharmony_ci      var type = rule.type
23088c88e8eSopenharmony_ci      var ruleResult = {}
23188c88e8eSopenharmony_ci      var ruleLog = []
23288c88e8eSopenharmony_ci
23388c88e8eSopenharmony_ci      if (type === 'rule') {
23488c88e8eSopenharmony_ci        if (rule.declarations && rule.declarations.length) {
23588c88e8eSopenharmony_ci          flexExpand(rule, ruleLog)
23688c88e8eSopenharmony_ci
23788c88e8eSopenharmony_ci          rule.declarations.forEach(function (declaration) {
23888c88e8eSopenharmony_ci            var subType = declaration.type
23988c88e8eSopenharmony_ci            var name, value, line, column, subResult, camelCasedName
24088c88e8eSopenharmony_ci
24188c88e8eSopenharmony_ci            /* istanbul ignore if */
24288c88e8eSopenharmony_ci            if (subType !== 'declaration') {
24388c88e8eSopenharmony_ci              return
24488c88e8eSopenharmony_ci            }
24588c88e8eSopenharmony_ci
24688c88e8eSopenharmony_ci            name = declaration.property
24788c88e8eSopenharmony_ci            value = declaration.value
24888c88e8eSopenharmony_ci
24988c88e8eSopenharmony_ci            // validate declarations and collect them to result
25088c88e8eSopenharmony_ci            camelCasedName = util.hyphenedToCamelCase(name)
25188c88e8eSopenharmony_ci            subResult = validateItem(camelCasedName, value)
25288c88e8eSopenharmony_ci
25388c88e8eSopenharmony_ci            // expand margin、padding、border、borderWidth、borderColor、borderStyle properties、animation
25488c88e8eSopenharmony_ci            if (subResult.value && Object.values(util.SPLECIAL_ATTR).indexOf(camelCasedName) !== -1) {
25588c88e8eSopenharmony_ci              expand(subResult, camelCasedName, ruleResult)
25688c88e8eSopenharmony_ci            }
25788c88e8eSopenharmony_ci
25888c88e8eSopenharmony_ci            /* istanbul ignore else */
25988c88e8eSopenharmony_ci            if ((typeof subResult.value === 'number' || typeof subResult.value === 'string')
26088c88e8eSopenharmony_ci              && !Object.values(util.SPLECIAL_ATTR).includes(camelCasedName)) {
26188c88e8eSopenharmony_ci              ruleResult[camelCasedName] = subResult.value
26288c88e8eSopenharmony_ci            }
26388c88e8eSopenharmony_ci            if (subResult.log) {
26488c88e8eSopenharmony_ci              subResult.log.line = declaration.position.start.line
26588c88e8eSopenharmony_ci              subResult.log.column = declaration.position.start.column
26688c88e8eSopenharmony_ci              ruleLog.push(subResult.log)
26788c88e8eSopenharmony_ci            }
26888c88e8eSopenharmony_ci          })
26988c88e8eSopenharmony_ci
27088c88e8eSopenharmony_ci          if (card && rule.selectors.length > 1) {
27188c88e8eSopenharmony_ci            log.push({
27288c88e8eSopenharmony_ci              line: rule.position.start.line,
27388c88e8eSopenharmony_ci              column: rule.position.start.column,
27488c88e8eSopenharmony_ci              reason: 'ERROR: The `' + rule.selectors.join(', ') + '` selector is not supported.'
27588c88e8eSopenharmony_ci            })
27688c88e8eSopenharmony_ci          } else {
27788c88e8eSopenharmony_ci            rule.selectors.forEach(function (selector) {
27888c88e8eSopenharmony_ci              const flag = card ? selector.match(CARD_SELECTOR) :
27988c88e8eSopenharmony_ci                selector.match(SELECTOR_MATCHER) || selector.match(DESCENDANT_SELECTOR_MATCHER) ||
28088c88e8eSopenharmony_ci                  selector.match(ALL_SELECTOR_MATCHER) || selector.match(ATTRIBUTE_SELECTOR) ||
28188c88e8eSopenharmony_ci                  selector.match(ELEMENT_AND_ELEMENT) || selector.match(CONTENT_ID)
28288c88e8eSopenharmony_ci              if (flag) {
28388c88e8eSopenharmony_ci                var className = selector
28488c88e8eSopenharmony_ci
28588c88e8eSopenharmony_ci                // handle pseudo class
28688c88e8eSopenharmony_ci                var pseudoIndex = className.indexOf(':')
28788c88e8eSopenharmony_ci                if (pseudoIndex > -1) {
28888c88e8eSopenharmony_ci                  var pseudoCls = className.slice(pseudoIndex)
28988c88e8eSopenharmony_ci                  className = className.slice(0, pseudoIndex)
29088c88e8eSopenharmony_ci                  var pseudoRuleResult = {}
29188c88e8eSopenharmony_ci                  Object.keys(ruleResult).forEach(function (prop) {
29288c88e8eSopenharmony_ci                    pseudoRuleResult[prop + pseudoCls] = ruleResult[prop]
29388c88e8eSopenharmony_ci                  })
29488c88e8eSopenharmony_ci                  ruleResult = pseudoRuleResult
29588c88e8eSopenharmony_ci                }
29688c88e8eSopenharmony_ci
29788c88e8eSopenharmony_ci                // merge style
29888c88e8eSopenharmony_ci                Object.keys(ruleResult).forEach(function (prop) {
29988c88e8eSopenharmony_ci                  // handle transition
30088c88e8eSopenharmony_ci                  if (prop.indexOf('transition') === 0 && prop !== 'transition') {
30188c88e8eSopenharmony_ci                    var realProp = prop.replace('transition', '')
30288c88e8eSopenharmony_ci                    realProp = realProp[0].toLowerCase() + realProp.slice(1)
30388c88e8eSopenharmony_ci                    jsonStyle['@TRANSITION'] = jsonStyle['@TRANSITION'] || {}
30488c88e8eSopenharmony_ci                    jsonStyle['@TRANSITION'][className] = jsonStyle['@TRANSITION'][className] || {}
30588c88e8eSopenharmony_ci                    jsonStyle['@TRANSITION'][className][realProp] = ruleResult[prop]
30688c88e8eSopenharmony_ci                  }
30788c88e8eSopenharmony_ci
30888c88e8eSopenharmony_ci                  jsonStyle[className] = jsonStyle[className] || {}
30988c88e8eSopenharmony_ci                  jsonStyle[className][prop] = ruleResult[prop]
31088c88e8eSopenharmony_ci                })
31188c88e8eSopenharmony_ci              } else {
31288c88e8eSopenharmony_ci                log.push({
31388c88e8eSopenharmony_ci                  line: rule.position.start.line,
31488c88e8eSopenharmony_ci                  column: rule.position.start.column,
31588c88e8eSopenharmony_ci                  reason: 'ERROR: The `' + selector + '` selector is not supported.'
31688c88e8eSopenharmony_ci                })
31788c88e8eSopenharmony_ci              }
31888c88e8eSopenharmony_ci            })
31988c88e8eSopenharmony_ci          }
32088c88e8eSopenharmony_ci          log = log.concat(ruleLog)
32188c88e8eSopenharmony_ci        }
32288c88e8eSopenharmony_ci      }
32388c88e8eSopenharmony_ci      /* istanbul ignore else */
32488c88e8eSopenharmony_ci      else if (type === 'font-face') {
32588c88e8eSopenharmony_ci        /* istanbul ignore else */
32688c88e8eSopenharmony_ci        if (rule.declarations && rule.declarations.length) {
32788c88e8eSopenharmony_ci          rule.declarations.forEach(function (declaration) {
32888c88e8eSopenharmony_ci            /* istanbul ignore if */
32988c88e8eSopenharmony_ci            if (declaration.type !== 'declaration') {
33088c88e8eSopenharmony_ci              return
33188c88e8eSopenharmony_ci            }
33288c88e8eSopenharmony_ci            var name = util.hyphenedToCamelCase(declaration.property)
33388c88e8eSopenharmony_ci            var value = declaration.value
33488c88e8eSopenharmony_ci            if (name === 'fontFamily' && '\"\''.indexOf(value[0]) > -1) {
33588c88e8eSopenharmony_ci              value = value.slice(1, value.length - 1)
33688c88e8eSopenharmony_ci            }
33788c88e8eSopenharmony_ci            ruleResult[name] = value
33888c88e8eSopenharmony_ci          })
33988c88e8eSopenharmony_ci          if (!jsonStyle['@FONT-FACE']) {
34088c88e8eSopenharmony_ci            jsonStyle['@FONT-FACE'] = []
34188c88e8eSopenharmony_ci          }
34288c88e8eSopenharmony_ci          jsonStyle['@FONT-FACE'].push(ruleResult)
34388c88e8eSopenharmony_ci        }
34488c88e8eSopenharmony_ci      }
34588c88e8eSopenharmony_ci      else if (type === 'import') {
34688c88e8eSopenharmony_ci        parseImport(resourcePath, rule, jsonStyle, log)
34788c88e8eSopenharmony_ci      }
34888c88e8eSopenharmony_ci      else if (type === 'keyframes' && !card) {
34988c88e8eSopenharmony_ci        if (!jsonStyle['@KEYFRAMES']) {
35088c88e8eSopenharmony_ci          jsonStyle['@KEYFRAMES'] = {}
35188c88e8eSopenharmony_ci        }
35288c88e8eSopenharmony_ci        var keyName = rule.name
35388c88e8eSopenharmony_ci        jsonStyle['@KEYFRAMES'][keyName] = []
35488c88e8eSopenharmony_ci        if (rule.keyframes && rule.keyframes.length) {
35588c88e8eSopenharmony_ci          if (card) {
35688c88e8eSopenharmony_ci            log.push({
35788c88e8eSopenharmony_ci              line: rule.position.start.line,
35888c88e8eSopenharmony_ci              column: rule.position.start.column,
35988c88e8eSopenharmony_ci              reason: 'ERROR: The keyframes is not supported!'
36088c88e8eSopenharmony_ci            })
36188c88e8eSopenharmony_ci          } else {
36288c88e8eSopenharmony_ci            rule.keyframes.forEach(function (keyframe) {
36388c88e8eSopenharmony_ci
36488c88e8eSopenharmony_ci              var keyframeType = keyframe.type
36588c88e8eSopenharmony_ci
36688c88e8eSopenharmony_ci              /* istanbul ignore if */
36788c88e8eSopenharmony_ci              if (keyframeType !== 'keyframe') {
36888c88e8eSopenharmony_ci                return
36988c88e8eSopenharmony_ci              }
37088c88e8eSopenharmony_ci
37188c88e8eSopenharmony_ci              if (keyframe.declarations && keyframe.declarations.length) {
37288c88e8eSopenharmony_ci                keyframe.declarations.forEach(function (declaration) {
37388c88e8eSopenharmony_ci                  var subType = declaration.type
37488c88e8eSopenharmony_ci                  var name, value, line, column, subResult, camelCasedName
37588c88e8eSopenharmony_ci
37688c88e8eSopenharmony_ci                  /* istanbul ignore if */
37788c88e8eSopenharmony_ci                  if (subType !== 'declaration') {
37888c88e8eSopenharmony_ci                    return
37988c88e8eSopenharmony_ci                  }
38088c88e8eSopenharmony_ci
38188c88e8eSopenharmony_ci                  name = declaration.property
38288c88e8eSopenharmony_ci                  value = declaration.value
38388c88e8eSopenharmony_ci
38488c88e8eSopenharmony_ci                  // validate declarations and collect them to result
38588c88e8eSopenharmony_ci                  camelCasedName = util.hyphenedToCamelCase(name)
38688c88e8eSopenharmony_ci                  subResult = validateItem(camelCasedName, value)
38788c88e8eSopenharmony_ci
38888c88e8eSopenharmony_ci                  // expand margin、padding、border、borderWidth、borderColor、borderStyle properties
38988c88e8eSopenharmony_ci                  if (subResult.value && Object.values(util.SPLECIAL_ATTR).indexOf(camelCasedName) !== -1) {
39088c88e8eSopenharmony_ci                    expand(subResult, camelCasedName, ruleResult)
39188c88e8eSopenharmony_ci                  }
39288c88e8eSopenharmony_ci                  /* istanbul ignore else */
39388c88e8eSopenharmony_ci                  if ((typeof subResult.value === 'number' || typeof subResult.value === 'string')
39488c88e8eSopenharmony_ci                    && !Object.values(util.SPLECIAL_ATTR).includes(camelCasedName)) {
39588c88e8eSopenharmony_ci                    ruleResult[camelCasedName] = subResult.value
39688c88e8eSopenharmony_ci                  }
39788c88e8eSopenharmony_ci                  if (subResult.log) {
39888c88e8eSopenharmony_ci                    subResult.log.line = declaration.position.start.line
39988c88e8eSopenharmony_ci                    subResult.log.column = declaration.position.start.column
40088c88e8eSopenharmony_ci                    ruleLog.push(subResult.log)
40188c88e8eSopenharmony_ci                  }
40288c88e8eSopenharmony_ci                })
40388c88e8eSopenharmony_ci              }
40488c88e8eSopenharmony_ci
40588c88e8eSopenharmony_ci              if (keyframe.values[0] === 'from') {
40688c88e8eSopenharmony_ci                var keyframeResult = {}
40788c88e8eSopenharmony_ci                Object.keys(ruleResult).forEach(function (prop) {
40888c88e8eSopenharmony_ci                  keyframeResult[prop] = ruleResult[prop]
40988c88e8eSopenharmony_ci                })
41088c88e8eSopenharmony_ci                keyframeResult['time'] = 0
41188c88e8eSopenharmony_ci                jsonStyle['@KEYFRAMES'][keyName].push(keyframeResult)
41288c88e8eSopenharmony_ci              }
41388c88e8eSopenharmony_ci              if (keyframe.values[0] === 'to') {
41488c88e8eSopenharmony_ci                var keyframeResult = {}
41588c88e8eSopenharmony_ci                Object.keys(ruleResult).forEach(function (prop) {
41688c88e8eSopenharmony_ci                  keyframeResult[prop] = ruleResult[prop]
41788c88e8eSopenharmony_ci                })
41888c88e8eSopenharmony_ci                keyframeResult['time'] = 100
41988c88e8eSopenharmony_ci                jsonStyle['@KEYFRAMES'][keyName].push(keyframeResult)
42088c88e8eSopenharmony_ci              }
42188c88e8eSopenharmony_ci              var patt = new RegExp(/^(100|[1-9]?\d)%$/)
42288c88e8eSopenharmony_ci              if (patt.test(keyframe.values[0])) {
42388c88e8eSopenharmony_ci                var keyframeResult = {}
42488c88e8eSopenharmony_ci                Object.keys(ruleResult).forEach(function (prop) {
42588c88e8eSopenharmony_ci                  keyframeResult[prop] = ruleResult[prop]
42688c88e8eSopenharmony_ci                })
42788c88e8eSopenharmony_ci                keyframeResult['time'] = keyframe.values[0].replace("%", "")
42888c88e8eSopenharmony_ci                jsonStyle['@KEYFRAMES'][keyName].push(keyframeResult)
42988c88e8eSopenharmony_ci              }
43088c88e8eSopenharmony_ci            })
43188c88e8eSopenharmony_ci            log = log.concat(ruleLog)
43288c88e8eSopenharmony_ci          }
43388c88e8eSopenharmony_ci        }
43488c88e8eSopenharmony_ci      }
43588c88e8eSopenharmony_ci      else if (type === 'media') {
43688c88e8eSopenharmony_ci        if (!jsonStyle['@MEDIA']) {
43788c88e8eSopenharmony_ci          jsonStyle['@MEDIA'] = []
43888c88e8eSopenharmony_ci        }
43988c88e8eSopenharmony_ci        var condition =  rule.media
44088c88e8eSopenharmony_ci        var mediaObj = {}
44188c88e8eSopenharmony_ci        mediaObj['condition'] = condition
44288c88e8eSopenharmony_ci
44388c88e8eSopenharmony_ci        if (rule.rules && rule.rules.length) {
44488c88e8eSopenharmony_ci          rule.rules.forEach(function(rule) {
44588c88e8eSopenharmony_ci            ruleResult = {}
44688c88e8eSopenharmony_ci            if (rule.type === 'import') {
44788c88e8eSopenharmony_ci              parseImport(resourcePath, rule, mediaObj, log)
44888c88e8eSopenharmony_ci            }
44988c88e8eSopenharmony_ci            if (rule.declarations && rule.declarations.length) {
45088c88e8eSopenharmony_ci              flexExpand(rule, ruleLog)
45188c88e8eSopenharmony_ci              rule.declarations.forEach(function (declaration) {
45288c88e8eSopenharmony_ci                var subType = declaration.type
45388c88e8eSopenharmony_ci                var name, value, line, column, subResult, camelCasedName
45488c88e8eSopenharmony_ci
45588c88e8eSopenharmony_ci                /* istanbul ignore if */
45688c88e8eSopenharmony_ci                if (subType !== 'declaration') {
45788c88e8eSopenharmony_ci                  return
45888c88e8eSopenharmony_ci                }
45988c88e8eSopenharmony_ci
46088c88e8eSopenharmony_ci                name = declaration.property
46188c88e8eSopenharmony_ci                value = declaration.value
46288c88e8eSopenharmony_ci
46388c88e8eSopenharmony_ci                // validate declarations and collect them to result
46488c88e8eSopenharmony_ci                camelCasedName = util.hyphenedToCamelCase(name)
46588c88e8eSopenharmony_ci                subResult = validateItem(camelCasedName, value)
46688c88e8eSopenharmony_ci                // expand margin、padding、border、borderWidth、borderColor、borderStyle properties
46788c88e8eSopenharmony_ci                if (subResult.value && Object.values(util.SPLECIAL_ATTR).indexOf(camelCasedName) !== -1) {
46888c88e8eSopenharmony_ci                  expand(subResult, camelCasedName, ruleResult)
46988c88e8eSopenharmony_ci                }
47088c88e8eSopenharmony_ci
47188c88e8eSopenharmony_ci                /* istanbul ignore else */
47288c88e8eSopenharmony_ci                if ((typeof subResult.value === 'number' || typeof subResult.value === 'string')
47388c88e8eSopenharmony_ci                  && !Object.values(util.SPLECIAL_ATTR).includes(camelCasedName)) {
47488c88e8eSopenharmony_ci                  ruleResult[camelCasedName] = subResult.value
47588c88e8eSopenharmony_ci                }
47688c88e8eSopenharmony_ci                if (subResult.log) {
47788c88e8eSopenharmony_ci                  subResult.log.line = declaration.position.start.line
47888c88e8eSopenharmony_ci                  subResult.log.column = declaration.position.start.column
47988c88e8eSopenharmony_ci                  ruleLog.push(subResult.log)
48088c88e8eSopenharmony_ci                }
48188c88e8eSopenharmony_ci              })
48288c88e8eSopenharmony_ci              rule.selectors.forEach(function (selector) {
48388c88e8eSopenharmony_ci                if (selector.match(SELECTOR_MATCHER) || selector.match(DESCENDANT_SELECTOR_MATCHER)) {
48488c88e8eSopenharmony_ci                  var className = selector
48588c88e8eSopenharmony_ci
48688c88e8eSopenharmony_ci                  // handle pseudo class
48788c88e8eSopenharmony_ci                  var pseudoIndex = className.indexOf(':')
48888c88e8eSopenharmony_ci                  if (pseudoIndex > -1) {
48988c88e8eSopenharmony_ci                    var pseudoCls = className.slice(pseudoIndex)
49088c88e8eSopenharmony_ci                    className = className.slice(0, pseudoIndex)
49188c88e8eSopenharmony_ci                    var pseudoRuleResult = {}
49288c88e8eSopenharmony_ci                    Object.keys(ruleResult).forEach(function (prop) {
49388c88e8eSopenharmony_ci                      pseudoRuleResult[prop + pseudoCls] = ruleResult[prop]
49488c88e8eSopenharmony_ci                    })
49588c88e8eSopenharmony_ci                    ruleResult = pseudoRuleResult
49688c88e8eSopenharmony_ci                  }
49788c88e8eSopenharmony_ci                  // merge style
49888c88e8eSopenharmony_ci                  Object.keys(ruleResult).forEach(function (prop) {
49988c88e8eSopenharmony_ci                    // handle transition
50088c88e8eSopenharmony_ci                    if (prop.indexOf('transition') === 0 && prop !== 'transition') {
50188c88e8eSopenharmony_ci                      var realProp = prop.replace('transition', '')
50288c88e8eSopenharmony_ci                      realProp = realProp[0].toLowerCase() + realProp.slice(1)
50388c88e8eSopenharmony_ci                      mediaObj['@TRANSITION'] = mediaObj['@TRANSITION'] || {}
50488c88e8eSopenharmony_ci                      mediaObj['@TRANSITION'][className] = mediaObj['@TRANSITION'][className] || {}
50588c88e8eSopenharmony_ci                      mediaObj['@TRANSITION'][className][realProp] = ruleResult[prop]
50688c88e8eSopenharmony_ci                    }
50788c88e8eSopenharmony_ci                    mediaObj[className] = mediaObj[className] || {}
50888c88e8eSopenharmony_ci                    mediaObj[className][prop] = ruleResult[prop]
50988c88e8eSopenharmony_ci                  })
51088c88e8eSopenharmony_ci                } else {
51188c88e8eSopenharmony_ci                  log.push({
51288c88e8eSopenharmony_ci                    line: rule.position.start.line,
51388c88e8eSopenharmony_ci                    column: rule.position.start.column,
51488c88e8eSopenharmony_ci                    reason: 'ERROR: The `' + selector + '` selector is not supported.'
51588c88e8eSopenharmony_ci                  })
51688c88e8eSopenharmony_ci                }
51788c88e8eSopenharmony_ci              })
51888c88e8eSopenharmony_ci              log = log.concat(ruleLog)
51988c88e8eSopenharmony_ci            }
52088c88e8eSopenharmony_ci          })
52188c88e8eSopenharmony_ci        }
52288c88e8eSopenharmony_ci        jsonStyle['@MEDIA'].push(mediaObj)
52388c88e8eSopenharmony_ci      }
52488c88e8eSopenharmony_ci    })
52588c88e8eSopenharmony_ci  }
52688c88e8eSopenharmony_ci
52788c88e8eSopenharmony_ci  done(err, {jsonStyle: jsonStyle, log: log})
52888c88e8eSopenharmony_ci}
52988c88e8eSopenharmony_ci
53088c88e8eSopenharmony_cifunction parseImport(resourcePath, rule, jsonStyle, log) {
53188c88e8eSopenharmony_ci  if(!resourcePath) {
53288c88e8eSopenharmony_ci    return
53388c88e8eSopenharmony_ci  }
53488c88e8eSopenharmony_ci  const resourcePath_ = resourcePath
53588c88e8eSopenharmony_ci  let importString = rule.import
53688c88e8eSopenharmony_ci  let importPath
53788c88e8eSopenharmony_ci  let mediaString = ''
53888c88e8eSopenharmony_ci  let source = ''
53988c88e8eSopenharmony_ci  if (importString.match(IMPORT_MATCHER)) {
54088c88e8eSopenharmony_ci    let filePath = importString.match(/['"]([^()]+?)['"]/)
54188c88e8eSopenharmony_ci    importPath = filePath[1]
54288c88e8eSopenharmony_ci    mediaString = importString.replace(importPath, '').replace(/['"]/g, '')
54388c88e8eSopenharmony_ci  }
54488c88e8eSopenharmony_ci  if(/^(\.)|(\.\.)\//.test(importPath)) {
54588c88e8eSopenharmony_ci    resourcePath = resourcePath.substring(0, resourcePath.lastIndexOf(path.sep) + 1);
54688c88e8eSopenharmony_ci    importPath = path.resolve(resourcePath, importPath)
54788c88e8eSopenharmony_ci  }
54888c88e8eSopenharmony_ci  if (!fs.existsSync(importPath)) {
54988c88e8eSopenharmony_ci    const fileSearch = findFile(importPath);
55088c88e8eSopenharmony_ci    if (fileSearch.result == true) {
55188c88e8eSopenharmony_ci      importPath = fileSearch.filePath;
55288c88e8eSopenharmony_ci    } else {
55388c88e8eSopenharmony_ci      writeErrorOption();
55488c88e8eSopenharmony_ci      log.push({
55588c88e8eSopenharmony_ci        line: rule.position.start.line,
55688c88e8eSopenharmony_ci        column: rule.position.start.column,
55788c88e8eSopenharmony_ci        reason: 'ERROR: no such file or directory, open ' + importPath
55888c88e8eSopenharmony_ci      });
55988c88e8eSopenharmony_ci      return;
56088c88e8eSopenharmony_ci    }
56188c88e8eSopenharmony_ci  }
56288c88e8eSopenharmony_ci  source = fs.readFileSync(importPath).toString();
56388c88e8eSopenharmony_ci  addPreviewCSS(importPath, resourcePath_);
56488c88e8eSopenharmony_ci  if (mediaString.length !== 0) {
56588c88e8eSopenharmony_ci    source = '@media ' + mediaString + '{\n' + source + '\n}'
56688c88e8eSopenharmony_ci  }
56788c88e8eSopenharmony_ci  parse(source, (err, obj) => {
56888c88e8eSopenharmony_ci    if (err) {
56988c88e8eSopenharmony_ci      throw(err)
57088c88e8eSopenharmony_ci    } else {
57188c88e8eSopenharmony_ci      jsonStyle = Object.assign(jsonStyle, obj.jsonStyle)
57288c88e8eSopenharmony_ci    }
57388c88e8eSopenharmony_ci  }, importPath)
57488c88e8eSopenharmony_ci}
57588c88e8eSopenharmony_ci
57688c88e8eSopenharmony_cifunction addPreviewCSS(importPath, resourcePath) {
57788c88e8eSopenharmony_ci  importPath = path.join(importPath);
57888c88e8eSopenharmony_ci  resourcePath = path.join(resourcePath);
57988c88e8eSopenharmony_ci  if (fs.existsSync(process.env.watchCSSFiles)) {
58088c88e8eSopenharmony_ci    const content = JSON.parse(fs.readFileSync(process.env.watchCSSFiles));
58188c88e8eSopenharmony_ci    if (content['entry'] && content['entry'][resourcePath]) {
58288c88e8eSopenharmony_ci      content[importPath] = content[importPath] || [];
58388c88e8eSopenharmony_ci      content[importPath].push(resourcePath);
58488c88e8eSopenharmony_ci      content[importPath] = lodash.uniqWith(content[importPath], lodash.isEqual);
58588c88e8eSopenharmony_ci    } else if (content[resourcePath]) {
58688c88e8eSopenharmony_ci      content[importPath] = content[importPath] || [];
58788c88e8eSopenharmony_ci      content[importPath].push(...content[resourcePath]);
58888c88e8eSopenharmony_ci      content[importPath] = lodash.uniqWith(content[importPath], lodash.isEqual);
58988c88e8eSopenharmony_ci    }
59088c88e8eSopenharmony_ci    content["atime"] = content["atime"] || {};
59188c88e8eSopenharmony_ci    content["atime"][importPath] = fs.statSync(importPath).atime.toString();
59288c88e8eSopenharmony_ci    fs.writeFileSync(process.env.watchCSSFiles, JSON.stringify(content, null, 2));
59388c88e8eSopenharmony_ci  }
59488c88e8eSopenharmony_ci}
59588c88e8eSopenharmony_ci
59688c88e8eSopenharmony_cifunction findFile(importPath) {
59788c88e8eSopenharmony_ci  const resultObject = {
59888c88e8eSopenharmony_ci    result: false
59988c88e8eSopenharmony_ci  };
60088c88e8eSopenharmony_ci  if (!importPath || !process.env.resolveModules) {
60188c88e8eSopenharmony_ci    return resultObject;
60288c88e8eSopenharmony_ci  }
60388c88e8eSopenharmony_ci  try {
60488c88e8eSopenharmony_ci    const modules = JSON.parse(process.env.resolveModules);
60588c88e8eSopenharmony_ci    modules.forEach(item => {
60688c88e8eSopenharmony_ci      if (fs.existsSync(item)) {
60788c88e8eSopenharmony_ci        if (fs.existsSync(path.join(item, importPath))) {
60888c88e8eSopenharmony_ci          resultObject.result = true;
60988c88e8eSopenharmony_ci          resultObject.filePath = path.join(item, importPath);
61088c88e8eSopenharmony_ci          return resultObject;
61188c88e8eSopenharmony_ci        }
61288c88e8eSopenharmony_ci      } else {
61388c88e8eSopenharmony_ci        const resolveItem = path.resolve(__dirname, item);
61488c88e8eSopenharmony_ci        if (fs.existsSync(resolveItem)) {
61588c88e8eSopenharmony_ci          resultObject.result = true;
61688c88e8eSopenharmony_ci          resultObject.filePath = path.join(resolveItem, importPath);
61788c88e8eSopenharmony_ci          return resultObject;
61888c88e8eSopenharmony_ci        }
61988c88e8eSopenharmony_ci      }
62088c88e8eSopenharmony_ci    });
62188c88e8eSopenharmony_ci  } catch (error) {
62288c88e8eSopenharmony_ci    resultObject.result = false;
62388c88e8eSopenharmony_ci  }
62488c88e8eSopenharmony_ci  return resultObject;
62588c88e8eSopenharmony_ci}
62688c88e8eSopenharmony_ci
62788c88e8eSopenharmony_cifunction writeErrorOption() {
62888c88e8eSopenharmony_ci  if (fs.existsSync(process.env.watchCSSFiles)) {
62988c88e8eSopenharmony_ci    const content = JSON.parse(fs.readFileSync(process.env.watchCSSFiles));
63088c88e8eSopenharmony_ci    content['clear'] = true;
63188c88e8eSopenharmony_ci    fs.writeFileSync(process.env.watchCSSFiles, JSON.stringify(content, null, 2));
63288c88e8eSopenharmony_ci  }
63388c88e8eSopenharmony_ci}
63488c88e8eSopenharmony_ci
63588c88e8eSopenharmony_ci/**
63688c88e8eSopenharmony_ci * Validate a JSON Object and log errors & warnings
63788c88e8eSopenharmony_ci *
63888c88e8eSopenharmony_ci * @param {object} json
63988c88e8eSopenharmony_ci * @param {function} done which will be called with
64088c88e8eSopenharmony_ci * - err:Error
64188c88e8eSopenharmony_ci * - data.jsonStyle{}: `classname.propname.value`-like object
64288c88e8eSopenharmony_ci * - data.log[{reason}]
64388c88e8eSopenharmony_ci */
64488c88e8eSopenharmony_cifunction validate(json, done) {
64588c88e8eSopenharmony_ci  var log = []
64688c88e8eSopenharmony_ci  var err
64788c88e8eSopenharmony_ci
64888c88e8eSopenharmony_ci  try {
64988c88e8eSopenharmony_ci    json = JSON.parse(JSON.stringify(json))
65088c88e8eSopenharmony_ci  }
65188c88e8eSopenharmony_ci  catch (e) {
65288c88e8eSopenharmony_ci    err = e
65388c88e8eSopenharmony_ci    json = {}
65488c88e8eSopenharmony_ci  }
65588c88e8eSopenharmony_ci
65688c88e8eSopenharmony_ci  Object.keys(json).forEach(function (selector) {
65788c88e8eSopenharmony_ci    var declarations = json[selector]
65888c88e8eSopenharmony_ci
65988c88e8eSopenharmony_ci    Object.keys(declarations).forEach(function (name) {
66088c88e8eSopenharmony_ci      var value = declarations[name]
66188c88e8eSopenharmony_ci      var result = validateItem(name, value)
66288c88e8eSopenharmony_ci
66388c88e8eSopenharmony_ci      if (typeof result.value === 'number' || typeof result.value === 'string') {
66488c88e8eSopenharmony_ci        declarations[name] = result.value
66588c88e8eSopenharmony_ci      }
66688c88e8eSopenharmony_ci      else {
66788c88e8eSopenharmony_ci        delete declarations[name]
66888c88e8eSopenharmony_ci      }
66988c88e8eSopenharmony_ci
67088c88e8eSopenharmony_ci      if (result.log) {
67188c88e8eSopenharmony_ci        log.push(result.log)
67288c88e8eSopenharmony_ci      }
67388c88e8eSopenharmony_ci    })
67488c88e8eSopenharmony_ci  })
67588c88e8eSopenharmony_ci
67688c88e8eSopenharmony_ci  done(err, {
67788c88e8eSopenharmony_ci    jsonStyle: json,
67888c88e8eSopenharmony_ci    log: log
67988c88e8eSopenharmony_ci  })
68088c88e8eSopenharmony_ci}
68188c88e8eSopenharmony_ci
68288c88e8eSopenharmony_cimodule.exports = {
68388c88e8eSopenharmony_ci  parse: parse,
68488c88e8eSopenharmony_ci  validate: validate,
68588c88e8eSopenharmony_ci  validateItem: validateItem,
68688c88e8eSopenharmony_ci  util: util,
68788c88e8eSopenharmony_ci  expand: expand,
68888c88e8eSopenharmony_ci  getUnit: getUnit,
68988c88e8eSopenharmony_ci}
69088c88e8eSopenharmony_ci
691