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