16a23e08bSopenharmony_ci/*
26a23e08bSopenharmony_ci * Copyright (c) 2021 Huawei Device Co., Ltd.
36a23e08bSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
46a23e08bSopenharmony_ci * you may not use this file except in compliance with the License.
56a23e08bSopenharmony_ci * You may obtain a copy of the License at
66a23e08bSopenharmony_ci *
76a23e08bSopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
86a23e08bSopenharmony_ci *
96a23e08bSopenharmony_ci * Unless required by applicable law or agreed to in writing, software
106a23e08bSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
116a23e08bSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
126a23e08bSopenharmony_ci * See the License for the specific language governing permissions and
136a23e08bSopenharmony_ci * limitations under the License.
146a23e08bSopenharmony_ci */
156a23e08bSopenharmony_ci
166a23e08bSopenharmony_ci/*
176a23e08bSopenharmony_ci * Customize the compiled style code into a styleSheet object, styleSheet object is divided into two parts, idSelectors
186a23e08bSopenharmony_ci * and classSelectors. There are some detailed rules to explain:
196a23e08bSopenharmony_ci * 1. Remove the "." And "#" symbols in front of the class selector and id selector;
206a23e08bSopenharmony_ci * 2. Convert all numeric strings to numbers, such as:"32px" convert to number 32; "11" convert to number 11;
216a23e08bSopenharmony_ci * 3. Convert all hex color to decimal number;
226a23e08bSopenharmony_ci * 4. Convert all boolean strings to boolean type;
236a23e08bSopenharmony_ci */
246a23e08bSopenharmony_ciconst {
256a23e08bSopenharmony_ci  SPECIAL_STYLE,
266a23e08bSopenharmony_ci  REGEXP_NUMBER_PX,
276a23e08bSopenharmony_ci  REGEXP_COLOR,
286a23e08bSopenharmony_ci  REGEXP_UNIT,
296a23e08bSopenharmony_ci  REGXP_QUOTES,
306a23e08bSopenharmony_ci} = require('./lite-enum');
316a23e08bSopenharmony_ci
326a23e08bSopenharmony_ci/**
336a23e08bSopenharmony_ci * Split style into id Selectors and classSelectors.
346a23e08bSopenharmony_ci * @param {Object} value Preliminary compilation results of css files.
356a23e08bSopenharmony_ci * @return {String} String result stylesheet.
366a23e08bSopenharmony_ci */
376a23e08bSopenharmony_cifunction transformStyle(value) {
386a23e08bSopenharmony_ci  const style = Function(`return ${value}`)();
396a23e08bSopenharmony_ci  const idSelectors = {};
406a23e08bSopenharmony_ci  const classSelectors = {};
416a23e08bSopenharmony_ci  const styleSheet = {};
426a23e08bSopenharmony_ci  let res = '';
436a23e08bSopenharmony_ci  const KEYFRAMES = '@KEYFRAMES';
446a23e08bSopenharmony_ci  const MEDIA_QUERY = '@MEDIA';
456a23e08bSopenharmony_ci  const keys = Object.keys(style);
466a23e08bSopenharmony_ci  for (const key of keys) {
476a23e08bSopenharmony_ci    if (key.charAt(0) === '.') {
486a23e08bSopenharmony_ci      classSelectors[key.slice(1)] = styleFormat(style[key]);
496a23e08bSopenharmony_ci    } else if (key.charAt(0) === '#') {
506a23e08bSopenharmony_ci      idSelectors[key.slice(1)] = styleFormat(style[key]);
516a23e08bSopenharmony_ci    } else if (key === KEYFRAMES) {
526a23e08bSopenharmony_ci      styleSheet['@keyframes'] = keyFrameFormat(style[key]);
536a23e08bSopenharmony_ci    } else if (key === MEDIA_QUERY) {
546a23e08bSopenharmony_ci      styleSheet['@media'] = mediaQueryFormat(style[key]);
556a23e08bSopenharmony_ci    } else {
566a23e08bSopenharmony_ci
576a23e08bSopenharmony_ci    }
586a23e08bSopenharmony_ci  }
596a23e08bSopenharmony_ci  if (style != null && keys.length !== 0) {
606a23e08bSopenharmony_ci    if (Object.keys(idSelectors).length !== 0) {
616a23e08bSopenharmony_ci      styleSheet['idSelectors'] = idSelectors;
626a23e08bSopenharmony_ci    }
636a23e08bSopenharmony_ci    if (Object.keys(classSelectors).length !== 0) {
646a23e08bSopenharmony_ci      styleSheet['classSelectors'] = classSelectors;
656a23e08bSopenharmony_ci    }
666a23e08bSopenharmony_ci  }
676a23e08bSopenharmony_ci  res = JSON.stringify(styleSheet);
686a23e08bSopenharmony_ci  return res;
696a23e08bSopenharmony_ci}
706a23e08bSopenharmony_ci
716a23e08bSopenharmony_ci/**
726a23e08bSopenharmony_ci * keyFrame style special compilation.
736a23e08bSopenharmony_ci * @param {Object} obj Preliminary compilation results of keyFrame style.
746a23e08bSopenharmony_ci * @return {Object} keyFrame style object.
756a23e08bSopenharmony_ci */
766a23e08bSopenharmony_cifunction keyFrameFormat(obj) {
776a23e08bSopenharmony_ci  for (const key of Object.keys(obj)) {
786a23e08bSopenharmony_ci    const value = obj[key];
796a23e08bSopenharmony_ci    for (const styleValue of value) {
806a23e08bSopenharmony_ci      for (const styleKey of Object.keys(styleValue)) {
816a23e08bSopenharmony_ci        const innerValue = styleValue[styleKey];
826a23e08bSopenharmony_ci        if (REGEXP_COLOR.test(innerValue)) {
836a23e08bSopenharmony_ci          styleValue[styleKey] = parseInt(innerValue.slice(1), 16);
846a23e08bSopenharmony_ci        }
856a23e08bSopenharmony_ci        try {
866a23e08bSopenharmony_ci          styleValue[styleKey] = JSON.parse(styleValue[styleKey]);
876a23e08bSopenharmony_ci        } catch (e) {
886a23e08bSopenharmony_ci          // Values cannot be converted to objects are not processed
896a23e08bSopenharmony_ci        }
906a23e08bSopenharmony_ci      }
916a23e08bSopenharmony_ci    }
926a23e08bSopenharmony_ci  }
936a23e08bSopenharmony_ci  return obj;
946a23e08bSopenharmony_ci}
956a23e08bSopenharmony_ci
966a23e08bSopenharmony_ci/**
976a23e08bSopenharmony_ci * media query special compilation.
986a23e08bSopenharmony_ci * @param {Array} mediaQueries the array of media query
996a23e08bSopenharmony_ci * @return {Array} media query style object
1006a23e08bSopenharmony_ci */
1016a23e08bSopenharmony_cifunction mediaQueryFormat(mediaQueries) {
1026a23e08bSopenharmony_ci  const target = [];
1036a23e08bSopenharmony_ci  for (const mediaQuery of mediaQueries) {
1046a23e08bSopenharmony_ci    const { condition, ...selectors } = mediaQuery;
1056a23e08bSopenharmony_ci    let style = transformStyle(JSON.stringify(selectors));
1066a23e08bSopenharmony_ci    if (style) {
1076a23e08bSopenharmony_ci      style = JSON.parse(style);
1086a23e08bSopenharmony_ci      target.push({ condition, ...style });
1096a23e08bSopenharmony_ci    }
1106a23e08bSopenharmony_ci  }
1116a23e08bSopenharmony_ci  return target;
1126a23e08bSopenharmony_ci}
1136a23e08bSopenharmony_ci
1146a23e08bSopenharmony_ciconst rules = [
1156a23e08bSopenharmony_ci  {
1166a23e08bSopenharmony_ci    match: function(key, value) {
1176a23e08bSopenharmony_ci      return (
1186a23e08bSopenharmony_ci        key === SPECIAL_STYLE.ANIMATION_DELAY ||
1196a23e08bSopenharmony_ci        key === SPECIAL_STYLE.ANIMATION_DURATION
1206a23e08bSopenharmony_ci      );
1216a23e08bSopenharmony_ci    },
1226a23e08bSopenharmony_ci    action: function(obj, key, value) {
1236a23e08bSopenharmony_ci      obj[key] = value;
1246a23e08bSopenharmony_ci    },
1256a23e08bSopenharmony_ci  },
1266a23e08bSopenharmony_ci  {
1276a23e08bSopenharmony_ci    match: function(key, value) {
1286a23e08bSopenharmony_ci      return key === SPECIAL_STYLE.ANIMATION_ITERATION_COUNT;
1296a23e08bSopenharmony_ci    },
1306a23e08bSopenharmony_ci    action: function(obj, key, value) {
1316a23e08bSopenharmony_ci      if (value === -1) {
1326a23e08bSopenharmony_ci        value = 'infinite';
1336a23e08bSopenharmony_ci      }
1346a23e08bSopenharmony_ci      obj[key] = value.toString();
1356a23e08bSopenharmony_ci    },
1366a23e08bSopenharmony_ci  },
1376a23e08bSopenharmony_ci  {
1386a23e08bSopenharmony_ci    match: function(key, value) {
1396a23e08bSopenharmony_ci      return [
1406a23e08bSopenharmony_ci        SPECIAL_STYLE.BACKGROUND_IMAGE,
1416a23e08bSopenharmony_ci        SPECIAL_STYLE.BACKGROUND_IMAGE_ACTIVE,
1426a23e08bSopenharmony_ci        SPECIAL_STYLE.BACKGROUND_IMAGE_CHECKED,
1436a23e08bSopenharmony_ci      ].includes(key);
1446a23e08bSopenharmony_ci    },
1456a23e08bSopenharmony_ci    action: function(obj, key, value) {
1466a23e08bSopenharmony_ci      obj[key] = value.replace(REGXP_QUOTES, '');
1476a23e08bSopenharmony_ci    },
1486a23e08bSopenharmony_ci  },
1496a23e08bSopenharmony_ci  {
1506a23e08bSopenharmony_ci    match: function(key, value) {
1516a23e08bSopenharmony_ci      return !isNaN(Number(value));
1526a23e08bSopenharmony_ci    },
1536a23e08bSopenharmony_ci    action: function(obj, key, value) {
1546a23e08bSopenharmony_ci      obj[key] = Number(value);
1556a23e08bSopenharmony_ci    },
1566a23e08bSopenharmony_ci  },
1576a23e08bSopenharmony_ci  {
1586a23e08bSopenharmony_ci    match: function(key, value) {
1596a23e08bSopenharmony_ci      return REGEXP_NUMBER_PX.test(value);
1606a23e08bSopenharmony_ci    },
1616a23e08bSopenharmony_ci    action: function(obj, key, value) {
1626a23e08bSopenharmony_ci      obj[key] = parseInt(value.replace(REGEXP_UNIT, ''), 10);
1636a23e08bSopenharmony_ci    },
1646a23e08bSopenharmony_ci  },
1656a23e08bSopenharmony_ci  {
1666a23e08bSopenharmony_ci    match: function(key, value) {
1676a23e08bSopenharmony_ci      return REGEXP_COLOR.test(value);
1686a23e08bSopenharmony_ci    },
1696a23e08bSopenharmony_ci    action: function(obj, key, value) {
1706a23e08bSopenharmony_ci      obj[key] = parseInt(value.slice(1), 16);
1716a23e08bSopenharmony_ci    },
1726a23e08bSopenharmony_ci  },
1736a23e08bSopenharmony_ci  {
1746a23e08bSopenharmony_ci    match: function(key, value) {
1756a23e08bSopenharmony_ci      return value === 'true';
1766a23e08bSopenharmony_ci    },
1776a23e08bSopenharmony_ci    action: function(obj, key, value) {
1786a23e08bSopenharmony_ci      obj[key] = true;
1796a23e08bSopenharmony_ci    },
1806a23e08bSopenharmony_ci  },
1816a23e08bSopenharmony_ci  {
1826a23e08bSopenharmony_ci    match: function(key, value) {
1836a23e08bSopenharmony_ci      return value === 'false';
1846a23e08bSopenharmony_ci    },
1856a23e08bSopenharmony_ci    action: function(obj, key, value) {
1866a23e08bSopenharmony_ci      obj[key] = false;
1876a23e08bSopenharmony_ci    },
1886a23e08bSopenharmony_ci  },
1896a23e08bSopenharmony_ci];
1906a23e08bSopenharmony_ci
1916a23e08bSopenharmony_ci/**
1926a23e08bSopenharmony_ci * Loop and format style, There are two rules defined here, types of number+px and color convert to number 16777215.
1936a23e08bSopenharmony_ci * @param {Object} obj Preliminary compilation results of style object.
1946a23e08bSopenharmony_ci * @return {Object} style object.
1956a23e08bSopenharmony_ci */
1966a23e08bSopenharmony_cifunction styleFormat(obj) {
1976a23e08bSopenharmony_ci  let value = '';
1986a23e08bSopenharmony_ci  for (const key of Object.keys(obj)) {
1996a23e08bSopenharmony_ci    value = obj[key];
2006a23e08bSopenharmony_ci    for (let i = 0; i < rules.length; i++) {
2016a23e08bSopenharmony_ci      if (rules[i].match(key, value)) {
2026a23e08bSopenharmony_ci        rules[i].action(obj, key, value);
2036a23e08bSopenharmony_ci        break;
2046a23e08bSopenharmony_ci      }
2056a23e08bSopenharmony_ci    }
2066a23e08bSopenharmony_ci  }
2076a23e08bSopenharmony_ci  return obj;
2086a23e08bSopenharmony_ci}
2096a23e08bSopenharmony_ci
2106a23e08bSopenharmony_ciexports.transformStyle = transformStyle;
211