@hippy/vue-next
Version:
Vue-Next binding for Hippy native framework
1,687 lines (1,682 loc) • 294 kB
JavaScript
/*!
* @hippy/vue-next v3.3.2
* (Using Vue v3.4.32 and Hippy-Vue-Next v3.3.2)
* Build at: Fri Nov 08 2024 20:45:13 GMT+0800 (中国标准时间)
*
* Tencent is pleased to support the open source community by making
* Hippy available.
*
* Copyright (C) 2023-2024 THL A29 Limited, a Tencent company.
* All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { camelize, capitalize, looseEqual, isFunction, isString, isOn } from '@vue/shared';
import { nextTick, toRaw, h, callWithAsyncErrorHandling, ErrorCodes, camelize as camelize$1, createRenderer, createHydrationRenderer } from '@vue/runtime-core';
/*
* Tencent is pleased to support the open source community by making
* Hippy available.
*
* Copyright (C) 2017-2022 THL A29 Limited, a Tencent company.
* All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
const names = {
transparent: 0x00000000,
aliceblue: 0xf0f8ffff,
antiquewhite: 0xfaebd7ff,
aqua: 0x00ffffff,
aquamarine: 0x7fffd4ff,
azure: 0xf0ffffff,
beige: 0xf5f5dcff,
bisque: 0xffe4c4ff,
black: 0x000000ff,
blanchedalmond: 0xffebcdff,
blue: 0x0000ffff,
blueviolet: 0x8a2be2ff,
brown: 0xa52a2aff,
burlywood: 0xdeb887ff,
burntsienna: 0xea7e5dff,
cadetblue: 0x5f9ea0ff,
chartreuse: 0x7fff00ff,
chocolate: 0xd2691eff,
coral: 0xff7f50ff,
cornflowerblue: 0x6495edff,
cornsilk: 0xfff8dcff,
crimson: 0xdc143cff,
cyan: 0x00ffffff,
darkblue: 0x00008bff,
darkcyan: 0x008b8bff,
darkgoldenrod: 0xb8860bff,
darkgray: 0xa9a9a9ff,
darkgreen: 0x006400ff,
darkgrey: 0xa9a9a9ff,
darkkhaki: 0xbdb76bff,
darkmagenta: 0x8b008bff,
darkolivegreen: 0x556b2fff,
darkorange: 0xff8c00ff,
darkorchid: 0x9932ccff,
darkred: 0x8b0000ff,
darksalmon: 0xe9967aff,
darkseagreen: 0x8fbc8fff,
darkslateblue: 0x483d8bff,
darkslategray: 0x2f4f4fff,
darkslategrey: 0x2f4f4fff,
darkturquoise: 0x00ced1ff,
darkviolet: 0x9400d3ff,
deeppink: 0xff1493ff,
deepskyblue: 0x00bfffff,
dimgray: 0x696969ff,
dimgrey: 0x696969ff,
dodgerblue: 0x1e90ffff,
firebrick: 0xb22222ff,
floralwhite: 0xfffaf0ff,
forestgreen: 0x228b22ff,
fuchsia: 0xff00ffff,
gainsboro: 0xdcdcdcff,
ghostwhite: 0xf8f8ffff,
gold: 0xffd700ff,
goldenrod: 0xdaa520ff,
gray: 0x808080ff,
green: 0x008000ff,
greenyellow: 0xadff2fff,
grey: 0x808080ff,
honeydew: 0xf0fff0ff,
hotpink: 0xff69b4ff,
indianred: 0xcd5c5cff,
indigo: 0x4b0082ff,
ivory: 0xfffff0ff,
khaki: 0xf0e68cff,
lavender: 0xe6e6faff,
lavenderblush: 0xfff0f5ff,
lawngreen: 0x7cfc00ff,
lemonchiffon: 0xfffacdff,
lightblue: 0xadd8e6ff,
lightcoral: 0xf08080ff,
lightcyan: 0xe0ffffff,
lightgoldenrodyellow: 0xfafad2ff,
lightgray: 0xd3d3d3ff,
lightgreen: 0x90ee90ff,
lightgrey: 0xd3d3d3ff,
lightpink: 0xffb6c1ff,
lightsalmon: 0xffa07aff,
lightseagreen: 0x20b2aaff,
lightskyblue: 0x87cefaff,
lightslategray: 0x778899ff,
lightslategrey: 0x778899ff,
lightsteelblue: 0xb0c4deff,
lightyellow: 0xffffe0ff,
lime: 0x00ff00ff,
limegreen: 0x32cd32ff,
linen: 0xfaf0e6ff,
magenta: 0xff00ffff,
maroon: 0x800000ff,
mediumaquamarine: 0x66cdaaff,
mediumblue: 0x0000cdff,
mediumorchid: 0xba55d3ff,
mediumpurple: 0x9370dbff,
mediumseagreen: 0x3cb371ff,
mediumslateblue: 0x7b68eeff,
mediumspringgreen: 0x00fa9aff,
mediumturquoise: 0x48d1ccff,
mediumvioletred: 0xc71585ff,
midnightblue: 0x191970ff,
mintcream: 0xf5fffaff,
mistyrose: 0xffe4e1ff,
moccasin: 0xffe4b5ff,
navajowhite: 0xffdeadff,
navy: 0x000080ff,
oldlace: 0xfdf5e6ff,
olive: 0x808000ff,
olivedrab: 0x6b8e23ff,
orange: 0xffa500ff,
orangered: 0xff4500ff,
orchid: 0xda70d6ff,
palegoldenrod: 0xeee8aaff,
palegreen: 0x98fb98ff,
paleturquoise: 0xafeeeeff,
palevioletred: 0xdb7093ff,
papayawhip: 0xffefd5ff,
peachpuff: 0xffdab9ff,
peru: 0xcd853fff,
pink: 0xffc0cbff,
plum: 0xdda0ddff,
powderblue: 0xb0e0e6ff,
purple: 0x800080ff,
rebeccapurple: 0x663399ff,
red: 0xff0000ff,
rosybrown: 0xbc8f8fff,
royalblue: 0x4169e1ff,
saddlebrown: 0x8b4513ff,
salmon: 0xfa8072ff,
sandybrown: 0xf4a460ff,
seagreen: 0x2e8b57ff,
seashell: 0xfff5eeff,
sienna: 0xa0522dff,
silver: 0xc0c0c0ff,
skyblue: 0x87ceebff,
slateblue: 0x6a5acdff,
slategray: 0x708090ff,
slategrey: 0x708090ff,
snow: 0xfffafaff,
springgreen: 0x00ff7fff,
steelblue: 0x4682b4ff,
tan: 0xd2b48cff,
teal: 0x008080ff,
thistle: 0xd8bfd8ff,
tomato: 0xff6347ff,
turquoise: 0x40e0d0ff,
violet: 0xee82eeff,
wheat: 0xf5deb3ff,
white: 0xffffffff,
whitesmoke: 0xf5f5f5ff,
yellow: 0xffff00ff,
yellowgreen: 0x9acd32ff,
};
const convertRegExp = (...args) => `\\(\\s*(${args.join(')\\s*,\\s*(')})\\s*\\)`;
const NUMBER = '[-+]?\\d*\\.?\\d+';
const PERCENTAGE = `${NUMBER}%`;
const matchers = {
rgb: new RegExp(`rgb${convertRegExp(NUMBER, NUMBER, NUMBER)}`),
rgba: new RegExp(`rgba${convertRegExp(NUMBER, NUMBER, NUMBER, NUMBER)}`),
hsl: new RegExp(`hsl${convertRegExp(NUMBER, PERCENTAGE, PERCENTAGE)}`),
hsla: new RegExp(`hsla${convertRegExp(NUMBER, PERCENTAGE, PERCENTAGE, NUMBER)}`),
hex3: /^#([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])$/,
hex4: /^#([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])$/,
hex6: /^#([0-9a-fA-F]{6})$/,
hex8: /^#([0-9a-fA-F]{8})$/,
};
const parse255 = (str) => {
const int = parseInt(str, 10);
if (int < 0) {
return 0;
}
if (int > 255) {
return 255;
}
return int;
};
const parse1 = (str) => {
const num = parseFloat(str);
if (num < 0) {
return 0;
}
if (num > 1) {
return 255;
}
return Math.round(num * 255);
};
const hue2rgb = (p, q, tx) => {
let t = tx;
if (t < 0) {
t += 1;
}
if (t > 1) {
t -= 1;
}
if (t < 1 / 6) {
return p + (q - p) * 6 * t;
}
if (t < 1 / 2) {
return q;
}
if (t < 2 / 3) {
return p + (q - p) * (2 / 3 - t) * 6;
}
return p;
};
const hslToRgb = (h, s, l) => {
const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
const p = 2 * l - q;
const r = hue2rgb(p, q, h + 1 / 3);
const g = hue2rgb(p, q, h);
const b = hue2rgb(p, q, h - 1 / 3);
return ((Math.round(r * 255) << 24)
| (Math.round(g * 255) << 16)
| (Math.round(b * 255) << 8));
};
const parse360 = (str) => {
const int = parseFloat(str);
return (((int % 360) + 360) % 360) / 360;
};
const parsePercentage = (str) => {
const int = parseFloat(str);
if (int < 0) {
return 0;
}
if (int > 100) {
return 1;
}
return int / 100;
};
// eslint-disable-next-line complexity
function baseColor(color) {
let match;
if (typeof color === 'number') {
if (color >>> 0 === color && color >= 0 && color <= 0xffffffff) {
return color;
}
return null;
}
match = matchers.hex6.exec(color);
if (Array.isArray(match)) {
return parseInt(`${match[1]}ff`, 16) >>> 0;
}
if (Object.hasOwnProperty.call(names, color)) {
return names[color];
}
match = matchers.rgb.exec(color);
if (Array.isArray(match)) {
return (((parse255(match[1]) << 24) // r
| (parse255(match[2]) << 16) // g
| (parse255(match[3]) << 8) // b
| 0x000000ff) // a
>>> 0);
}
match = matchers.rgba.exec(color);
if (match) {
return (((parse255(match[1]) << 24) // r
| (parse255(match[2]) << 16) // g
| (parse255(match[3]) << 8) // b
| parse1(match[4])) // a
>>> 0);
}
match = matchers.hex3.exec(color);
if (match) {
return (parseInt(`${match[1]
+ match[1] // r
+ match[2]
+ match[2] // g
+ match[3]
+ match[3] // b
}ff`, // a
16) >>> 0);
}
match = matchers.hex8.exec(color);
if (match) {
return parseInt(match[1], 16) >>> 0;
}
match = matchers.hex4.exec(color);
if (match) {
return (parseInt(match[1]
+ match[1] // r
+ match[2]
+ match[2] // g
+ match[3]
+ match[3] // b
+ match[4]
+ match[4], // a
16) >>> 0);
}
match = matchers.hsl.exec(color);
if (match) {
return ((hslToRgb(parse360(match[1]), // h
parsePercentage(match[2]), // s
parsePercentage(match[3]))
| 0x000000ff) // a
>>> 0);
}
match = matchers.hsla.exec(color);
if (match) {
return ((hslToRgb(parse360(match[1]), // h
parsePercentage(match[2]), // s
parsePercentage(match[3]))
| parse1(match[4])) // a
>>> 0);
}
return null;
}
/**
* Convert css color value or string description to native supported color format
*
* @param color - color value or string description
*
* @public
*/
function translateColor(color) {
let int32Color = baseColor(color);
if (int32Color === null) {
throw new Error(`Bad color value: ${color}`);
}
int32Color = ((int32Color << 24) | (int32Color >>> 8)) >>> 0;
return int32Color;
}
/*
* Tencent is pleased to support the open source community by making
* Hippy available.
*
* Copyright (C) 2017-2022 THL A29 Limited, a Tencent company.
* All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* properties map
*
* @public
*/
const PROPERTIES_MAP = {
textDecoration: 'textDecorationLine',
boxShadowOffset: 'shadowOffset',
boxShadowOffsetX: 'shadowOffsetX',
boxShadowOffsetY: 'shadowOffsetY',
boxShadowOpacity: 'shadowOpacity',
boxShadowRadius: 'shadowRadius',
boxShadowSpread: 'shadowSpread',
boxShadowColor: 'shadowColor',
};
// linear-gradient direction description map
const LINEAR_GRADIENT_DIRECTION_MAP = {
totop: '0',
totopright: 'totopright',
toright: '90',
tobottomright: 'tobottomright',
tobottom: '180',
tobottomleft: 'tobottomleft',
toleft: '270',
totopleft: 'totopleft',
};
// degree unit
const DEGREE_UNIT = {
TURN: 'turn',
RAD: 'rad',
DEG: 'deg',
};
// regular expression of comment
const commentRegexp = /\/\*.{0,1000}?\*\//gms;
/**
* Output warning debug information to console
*
* @param context - output content
*/
function warn$1(...context) {
if (process.env.NODE_ENV === 'production') {
return;
}
// eslint-disable-next-line no-console
console.warn(...context);
}
// regular expression of number
const numberRegEx$1 = new RegExp('^(?=.+)[+-]?\\d*\\.?\\d*([Ee][+-]?\\d+)?$');
/**
* convert to number
* @param str - target string or number
*/
function tryConvertNumber$1(str) {
if (typeof str === 'number') {
return str;
}
if (numberRegEx$1.test(str)) {
try {
return parseFloat(str);
}
catch (err) {
// pass
}
}
return str;
}
/**
* Convert the px unit value to the pt unit value used by the native
*
* @param value - target px unit value
*/
function convertPxUnitToPt(value) {
// If value is number just ignore
if (Number.isInteger(value)) {
return value;
}
// If value unit is px, change to use pt as 1:1.
if (typeof value === 'string' && value.endsWith('px')) {
const num = parseFloat(value.slice(0, value.indexOf('px')));
if (!Number.isNaN(num)) {
value = num;
}
}
return value;
}
/**
* Convert the angle value of a string to an angle value
*
* @param value - target value
* @param unit - unit type
*
* @public
*/
function convertToDegree(value, unit = DEGREE_UNIT.DEG) {
const convertedNumValue = parseFloat(value);
let result = value || '';
const [, decimals] = value.split('.');
if (decimals && decimals.length > 2) {
result = convertedNumValue.toFixed(2);
}
switch (unit) {
// turn unit
case DEGREE_UNIT.TURN:
result = `${(convertedNumValue * 360).toFixed(2)}`;
break;
// radius unit
case DEGREE_UNIT.RAD:
result = `${((180 / Math.PI) * convertedNumValue).toFixed(2)}`;
break;
}
return result;
}
/**
* Get the angle value of the linear gradient
*
* @param value - target value
*
* @public
*/
function getLinearGradientAngle(value) {
const processedValue = (value || '').replace(/\s*/g, '').toLowerCase();
const reg = /^([+-]?(?=(?<digit>\d+))\k<digit>\.?\d*)+(deg|turn|rad)|(to\w+)$/g;
const valueList = reg.exec(processedValue);
if (!Array.isArray(valueList))
return '';
// default direction is to bottom, i.e. 180degree
let angle = '180';
const [direction, angleValue, angleUnit] = valueList;
if (angleValue && angleUnit) {
// handling values of type angular
angle = convertToDegree(angleValue, angleUnit);
}
else if (direction
&& typeof LINEAR_GRADIENT_DIRECTION_MAP[direction] !== 'undefined') {
// direct direction
angle = LINEAR_GRADIENT_DIRECTION_MAP[direction];
}
else {
warn$1('linear-gradient direction or angle is invalid, default value [to bottom] would be used');
}
return angle;
}
/**
* Get the color value of the linear gradient when it stops
*
* @param value - color
*
* @public
*/
function getLinearGradientColorStop(value = '') {
const processedValue = value.replace(/\s+/g, ' ').trim();
const [color, percentage] = processedValue.split(/\s+(?![^(]*?\))/);
const percentageCheckReg = /^([+-]?\d+\.?\d*)%$/g;
if (color && !percentageCheckReg.exec(color) && !percentage) {
return {
color: translateColor(color),
};
}
if (color && percentageCheckReg.exec(percentage)) {
return {
// color stop ratio
ratio: parseFloat(percentage.split('%')[0]) / 100,
color: translateColor(color),
};
}
return null;
}
/**
* parse background image style attribute
*
* @param property - property name
* @param value - property value
*
* @public
*/
function parseBackgroundImage(property, value) {
let processedValue = value;
let processedProperty = property;
if (value.indexOf('linear-gradient') === 0) {
processedProperty = 'linearGradient';
const valueString = value.substring(value.indexOf('(') + 1, value.lastIndexOf(')'));
const tokens = valueString.split(/,(?![^(]*?\))/);
const colorStopList = [];
processedValue = {};
tokens.forEach((token, index) => {
if (index === 0) {
// the angle of linear-gradient parameter can be optional
const angle = getLinearGradientAngle(token);
if (angle) {
processedValue.angle = angle;
}
else {
// if angle ignored, default direction is to bottom, i.e. 180degree
processedValue.angle = '180';
const colorObject = getLinearGradientColorStop(token);
if (colorObject)
colorStopList.push(colorObject);
}
}
else {
const colorObject = getLinearGradientColorStop(token);
if (colorObject)
colorStopList.push(colorObject);
}
});
processedValue.colorStopList = colorStopList;
}
else {
const regexp = /(?:\(['"]?)(.*?)(?:['"]?\))/;
const executed = regexp.exec(value);
if (executed && executed.length > 1) {
[, processedValue] = executed;
}
}
return [processedProperty, processedValue];
}
/**
* Recursively add non-enumerable parent nodes
*
* @param obj - target object
* @param parent - parent node
*/
function addParent(obj, parent) {
const isNode = obj && typeof obj.type === 'string';
const childParent = isNode ? obj : parent;
// Take all the keys of the node, and judge the value, if it is an array and an object, then recursively addParent
Object.keys(obj).forEach((k) => {
const value = obj[k];
if (Array.isArray(value)) {
value.forEach((v) => {
addParent(v, childParent);
});
}
else if (value && typeof value === 'object') {
addParent(value, childParent);
}
});
// If it is a node type, add a parent node, if no parent node is passed in, set it to null
if (isNode) {
Object.defineProperty(obj, 'parent', {
configurable: true,
writable: true,
enumerable: false,
value: parent,
});
}
return obj;
}
/**
* parse css code into AST tree
*
* @param css - css code
* @param options - parse options
*
* @public
*/
function parseCSS(css, options = { source: 0 }) {
// position
let lineno = 1;
let column = 1;
/**
* update lineno and column
*/
function updatePosition(str) {
const lines = str.match(/\n/g);
if (lines)
lineno += lines.length;
const i = str.lastIndexOf('\n');
column = ~i ? str.length - i : column + str.length;
}
/**
* Match `re` and return captures.
*/
function match(re) {
const m = re.exec(css);
if (!m) {
return null;
}
const str = m[0];
updatePosition(str);
css = css.slice(str.length);
return m;
}
/**
* Remove the whitespace at the beginning of css and update the location information
*/
function whitespace() {
match(/^\s*/);
}
/**
* Record the position and set the value of node.position
*/
function position() {
return (node) => {
node.position = {
start: { line: lineno, column },
end: { line: lineno, column },
source: options.source,
content: css,
};
whitespace();
return node;
};
}
const errorsList = [];
function error(msg) {
const errorInstance = new Error(`${options.source}:${lineno}:${column}: ${msg}`);
const newError = {
...errorInstance,
reason: msg,
filename: options.source,
line: lineno,
column,
source: css,
};
if (options.silent) {
errorsList.push(newError);
}
else {
throw newError;
}
}
/**
* Parse comment.
*/
function comment() {
const pos = position();
if (css.charAt(0) !== '/' || css.charAt(1) !== '*') {
return null;
}
let i = 2;
while (css.charAt(i) !== ''
&& (css.charAt(i) !== '*' || css.charAt(i + 1) !== '/')) {
i += 1;
}
i += 2;
if (css.charAt(i - 1) === '') {
return error('End of comment missing');
}
const str = css.slice(2, i - 2);
column += 2;
updatePosition(str);
css = css.slice(i);
column += 2;
return pos({
type: 'comment',
comment: str,
});
}
/**
* Parse comments;
*/
function comments(rawRules = []) {
let c;
const commentRules = rawRules || [];
while ((c = comment())) {
if (c !== false) {
commentRules.push(c);
}
}
return commentRules;
}
/**
* Generate rule set
*/
function rules() {
let node;
const actualRules = [];
whitespace();
comments(actualRules);
// eslint-disable-next-line @typescript-eslint/no-use-before-define
while (css.length && css.charAt(0) !== '}' && (node = atrule() || rule())) {
if (node) {
actualRules.push(node);
comments(actualRules);
}
}
return actualRules;
}
/**
* Process the stylesheet and get a list of rules
*/
function stylesheet() {
const rulesList = rules();
return {
type: 'stylesheet',
stylesheet: {
source: options.source,
rules: rulesList,
parsingErrors: errorsList,
},
};
}
/**
* Remove whitespace between opening brace and content
*/
function open() {
return match(/^{\s*/);
}
/**
* Remove whitespace between closing brace and content
*/
function close() {
return match(/^}/);
}
/**
* Parse selector.
*/
function selector() {
const matched = match(/^([^{]+)/);
if (!matched) {
return null;
}
/* @fix Remove all comments from selectors like #root .result /* df *\/ div
* http://ostermiller.org/findcomment.html */
return matched[0]
.trim()
.replace(/\/\*([^*]|[\r\n]|(\*+([^*/]|[\r\n])))*\*\/+/g, '')
.replace(/"(?:\\"|[^"])*"|'(?:\\'|[^'])*'/g, m => m.replace(/,/g, '\u200C'))
.split(/\s*(?![^(]*\)),\s*/)
.map(s => s.replace(/\u200C/g, ','));
}
/**
* Parse declaration.
*/
// eslint-disable-next-line complexity
function declaration() {
const pos = position();
// prop
let prop = match(/^(\*?[-#/*\\\w]+(\[[0-9a-z_-]+])?)\s*/);
if (!prop) {
return null;
}
prop = prop[0].trim();
// :
if (!match(/^:\s*/)) {
return error('property missing \':\'');
}
// val
const propertyName = prop.replace(commentRegexp, '');
const camelizeProperty = camelize(propertyName);
let property = (() => {
const mapProperty = PROPERTIES_MAP[camelizeProperty];
if (mapProperty) {
return mapProperty;
}
return camelizeProperty;
})();
const val = match(/^((?:'(?:\\'|.)*?'|"(?:\\"|.)*?"|\([^)]{0,500}?\)|[^};])+)/);
let value = val ? val[0].trim().replace(commentRegexp, '') : '';
switch (property) {
case 'backgroundImage': {
[property, value] = parseBackgroundImage(property, value);
break;
}
case 'transform': {
const keyReg = /((\w+)\s*\()/;
const valueReg = /(?:\(['"]?)(.*?)(?:['"]?\))/;
const oldValue = value;
value = [];
oldValue.split(' ').forEach((transformKeyValue) => {
if (keyReg.test(transformKeyValue)) {
let key;
let v;
const matchedKey = keyReg.exec(transformKeyValue);
const matchedValue = valueReg.exec(transformKeyValue);
if (matchedKey) {
[, , key] = matchedKey;
}
if (matchedValue) {
[, v] = matchedValue;
}
if (v.indexOf('.') === 0) {
v = `0${v}`;
}
if (parseFloat(v).toString() === v) {
v = parseFloat(v);
}
const transform = {};
transform[key] = v;
value.push(transform);
}
else {
error('missing \'(\'');
}
});
break;
}
case 'fontWeight':
// Keep string and going on.
break;
case 'shadowOffset': {
const declarationPos = value
.split(' ')
.filter(v => v)
.map(v => convertPxUnitToPt(v));
const [x] = declarationPos;
let [, y] = declarationPos;
if (!y) {
y = x;
}
// FIXME: should not be width and height, should be x and y.
value = {
x,
y,
};
break;
}
case 'collapsable':
value = Boolean(value);
break;
default: {
value = tryConvertNumber$1(value);
// Convert the px to pt for specific properties
const sizeProperties = [
'top',
'left',
'right',
'bottom',
'height',
'width',
'size',
'padding',
'margin',
'ratio',
'radius',
'offset',
'spread',
];
if (sizeProperties.find(size => property.toLowerCase().indexOf(size) > -1)) {
value = convertPxUnitToPt(value);
}
}
}
const ret = pos({
type: 'declaration',
value,
property,
});
match(/^[;\s]*/);
return ret;
}
/**
* Parse declarations.
*/
function declarations() {
let decls = [];
if (!open())
return error('missing \'{\'');
comments(decls);
// declarations
let decl;
while ((decl = declaration())) {
if (decl !== false) {
if (Array.isArray(decl)) {
decls = decls.concat(decl);
}
else {
decls.push(decl);
}
comments(decls);
}
}
if (!close())
return error('missing \'}\'');
return decls;
}
/**
* Parse rule.
*/
function rule() {
const pos = position();
const sel = selector();
if (!sel)
return error('selector missing');
comments();
return pos({
type: 'rule',
selectors: sel,
declarations: declarations(),
});
}
/**
* Parse keyframe.
*/
function keyframe() {
let m;
const vals = [];
const pos = position();
while ((m = match(/^((\d+\.\d+|\.\d+|\d+)%?|[a-z]+)\s*/))) {
vals.push(m[1]);
match(/^,\s*/);
}
if (!vals.length) {
return null;
}
return pos({
type: 'keyframe',
values: vals,
declarations: declarations(),
});
}
/**
* Parse keyframes.
*/
function atkeyframes() {
const pos = position();
let m = match(/^@([-\w]+)?keyframes\s*/);
if (!m) {
return null;
}
const vendor = m[1];
// identifier
m = match(/^([-\w]+)\s*/);
if (!m) {
return error('@keyframes missing name');
}
const name = m[1];
if (!open())
return error('@keyframes missing \'{\'');
let frame;
let frames = comments();
while ((frame = keyframe())) {
frames.push(frame);
frames = frames.concat(comments());
}
if (!close())
return error('@keyframes missing \'}\'');
return pos({
type: 'keyframes',
name,
vendor,
keyframes: frames,
});
}
/**
* Parse supports.
*/
function atsupports() {
const pos = position();
const m = match(/^@supports *([^{]+)/);
if (!m) {
return null;
}
const supports = m[1].trim();
if (!open())
return error('@supports missing \'{\'');
const style = comments().concat(rules());
if (!close())
return error('@supports missing \'}\'');
return pos({
type: 'supports',
supports,
rules: style,
});
}
/**
* Parse host.
*/
function athost() {
const pos = position();
const m = match(/^@host\s*/);
if (!m) {
return null;
}
if (!open()) {
return error('@host missing \'{\'');
}
const style = comments().concat(rules());
if (!close()) {
return error('@host missing \'}\'');
}
return pos({
type: 'host',
rules: style,
});
}
/**
* Parse media.
*/
function atmedia() {
const pos = position();
const m = match(/^@media *([^{]+)/);
if (!m) {
return null;
}
const media = m[1].trim();
if (!open()) {
return error('@media missing \'{\'');
}
const style = comments().concat(rules());
if (!close()) {
return error('@media missing \'}\'');
}
return pos({
type: 'media',
media,
rules: style,
});
}
/**
* Parse custom-media.
*/
function atcustommedia() {
const pos = position();
const m = match(/^@custom-media\s+(--[^\s]+)\s*([^{;]{1,200}?);/);
if (!m) {
return null;
}
return pos({
type: 'custom-media',
name: m[1].trim(),
media: m[2].trim(),
});
}
/**
* Parse paged media.
*/
function atpage() {
const pos = position();
const m = match(/^@page */);
if (!m) {
return null;
}
const sel = selector() || [];
if (!open()) {
return error('@page missing \'{\'');
}
let decls = comments();
// declarations
let decl;
while ((decl = declaration())) {
decls.push(decl);
decls = decls.concat(comments());
}
if (!close()) {
return error('@page missing \'}\'');
}
return pos({
type: 'page',
selectors: sel,
declarations: decls,
});
}
/**
* Parse document.
*/
function atdocument() {
const pos = position();
const m = match(/^@([-\w]+)?document *([^{]+)/);
if (!m) {
return null;
}
const vendor = m[1].trim();
const doc = m[2].trim();
if (!open()) {
return error('@document missing \'{\'');
}
const style = comments().concat(rules());
if (!close()) {
return error('@document missing \'}\'');
}
return pos({
type: 'document',
document: doc,
vendor,
rules: style,
});
}
/**
* Parse font-face.
*/
function atfontface() {
const pos = position();
const m = match(/^@font-face\s*/);
if (!m) {
return null;
}
if (!open()) {
return error('@font-face missing \'{\'');
}
let decls = comments();
// declarations
let decl;
while ((decl = declaration())) {
decls.push(decl);
decls = decls.concat(comments());
}
if (!close()) {
return error('@font-face missing \'}\'');
}
return pos({
type: 'font-face',
declarations: decls,
});
}
/**
* Parse non-block at-rules
*/
function compileAtRule(name) {
const re = new RegExp(`^@${name}\\s*([^;]+);`);
return () => {
const pos = position();
const m = match(re);
if (!m) {
return null;
}
const ret = { type: name };
ret[name] = m[1].trim();
return pos(ret);
};
}
/**
* Parse import
*/
const atimport = compileAtRule('import');
/**
* Parse charset
*/
const atcharset = compileAtRule('charset');
/**
* Parse namespace
*/
const atnamespace = compileAtRule('namespace');
/**
* Parse at rule.
*/
// eslint-disable-next-line complexity
function atrule() {
if (css[0] !== '@') {
return null;
}
return (atkeyframes()
|| atmedia()
|| atcustommedia()
|| atsupports()
|| atimport()
|| atcharset()
|| atnamespace()
|| atdocument()
|| atpage()
|| athost()
|| atfontface());
}
return addParent(stylesheet(), null);
}
/*
* Tencent is pleased to support the open source community by making
* Hippy available.
*
* Copyright (C) 2022 THL A29 Limited, a Tencent company.
* All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* stores the Selector list matched by the node
*/
class SelectorsMatch {
constructor() {
this.changeMap = new Map();
}
/**
* Add attribute
*
* @param node - target node
* @param attribute - attribute name
*/
addAttribute(node, attribute) {
const deps = this.properties(node);
if (!deps.attributes) {
deps.attributes = new Set();
}
deps.attributes.add(attribute);
}
/**
* add pseudo class
*
* @param node - target node
* @param pseudoClass - pseudo class
*/
addPseudoClass(node, pseudoClass) {
const deps = this.properties(node);
if (!deps.pseudoClasses) {
deps.pseudoClasses = new Set();
}
deps.pseudoClasses.add(pseudoClass);
}
properties(node) {
let set = this.changeMap.get(node);
if (!set) {
this.changeMap.set(node, (set = {}));
}
return set;
}
}
/**
* selectors map class
*
* @public
*
*/
class SelectorsMap {
constructor(ruleSets) {
this.id = {};
this.class = {};
this.type = {};
this.universal = [];
this.position = 0;
this.ruleSets = ruleSets;
ruleSets.forEach(rule => rule.lookupSort(this));
}
/**
* Remove the specified style from the style rules map
*
* @param map - style map
* @param head - style key
* @param sel - selector
*/
static removeFromMap(map, head, sel) {
const list = map[head];
const index = list.findIndex(item => { var _a; return item.sel.ruleSet.hash === ((_a = sel.ruleSet) === null || _a === void 0 ? void 0 : _a.hash); });
if (index !== -1) {
list.splice(index, 1);
}
}
/**
* Append a new list of style rules
*
* @param appendRules - list of style rules
*/
append(appendRules) {
this.ruleSets = this.ruleSets.concat(appendRules);
appendRules.forEach(rule => rule.lookupSort(this));
}
/**
* Find the style in the list of style rules according to the hash value and delete it
*
* @param hash - hash of style chunk
*/
delete(hash) {
const removeRuleSets = [];
// Find the style in the list of style rules according to the hash value
this.ruleSets = this.ruleSets.filter((rule) => {
if (rule.hash !== hash) {
return true;
}
removeRuleSets.push(rule);
return false;
});
// Call the remove rule api to remove the deactivated style rule
removeRuleSets.forEach(rule => rule.removeSort(this));
}
/**
* Find the matching style information according to the id, class, attribute of the hippy node
*
* @param node - target node
* @param ssrNodes - ssr node list
*/
query(node, ssrNodes) {
const { tagName, id, classList, props } = node;
let domId = id;
let domClassList = classList;
if (props === null || props === void 0 ? void 0 : props.attributes) {
// props and attributes exist means this node is generated from server side(except development).
// so we need to use these props first
const { attributes } = props;
domClassList = new Set(((attributes === null || attributes === void 0 ? void 0 : attributes.class) || '').split(' ').filter(x => x.trim()));
domId = attributes.id;
}
const selectorClasses = [this.universal, this.id[domId], this.type[tagName]];
if (domClassList === null || domClassList === void 0 ? void 0 : domClassList.size) {
domClassList.forEach(c => selectorClasses.push(this.class[c]));
}
const selectors = selectorClasses
.filter(arr => !!arr)
.reduce((cur, next) => cur.concat(next), []);
const selectorsMatch = new SelectorsMatch();
selectorsMatch.selectors = selectors
.filter(sel => sel.sel.accumulateChanges(node, selectorsMatch, ssrNodes))
.sort((a, b) => a.sel.specificity - b.sel.specificity || a.pos - b.pos)
.map(docSel => docSel.sel);
return selectorsMatch;
}
removeById(id, sel) {
SelectorsMap.removeFromMap(this.id, id, sel);
}
sortById(id, sel) {
this.addToMap(this.id, id, sel);
}
removeByClass(cssClass, sel) {
SelectorsMap.removeFromMap(this.class, cssClass, sel);
}
sortByClass(cssClass, sel) {
this.addToMap(this.class, cssClass, sel);
}
removeByType(cssType, sel) {
SelectorsMap.removeFromMap(this.type, cssType, sel);
}
sortByType(cssType, sel) {
this.addToMap(this.type, cssType, sel);
}
removeAsUniversal(sel) {
const index = this.universal.findIndex(item => { var _a, _b; return ((_a = item.sel.ruleSet) === null || _a === void 0 ? void 0 : _a.hash) === ((_b = sel.ruleSet) === null || _b === void 0 ? void 0 : _b.hash); });
if (index !== -1) {
this.universal.splice(index);
}
}
sortAsUniversal(sel) {
this.universal.push(this.makeDocSelector(sel));
}
/**
* add style selector to map
*
* @param map - style map
* @param head - style key
* @param sel - selector
*/
addToMap(map, head, sel) {
this.position += 1;
const list = map[head];
if (list) {
list.push(this.makeDocSelector(sel));
}
else {
map[head] = [this.makeDocSelector(sel)];
}
}
makeDocSelector(sel) {
this.position += 1;
return { sel, pos: this.position };
}
}
/*
* Tencent is pleased to support the open source community by making
* Hippy available.
*
* Copyright (C) 2022 THL A29 Limited, a Tencent company.
* All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* determine if the value is null or undefined
*
* @param value - value
*/
function isNullOrUndefined$1(value) {
return typeof value === 'undefined' || value === null;
}
/**
* wrap string text
*
* @param text - string
*/
function wrap(text) {
return text ? ` ${text}` : '';
}
/**
* get node's parent node, in client side, node has parentNode props. in server side, find parentNode
* by pId
*
* @param node - child node
* @param ssrNodes - ssr node list
*
* @internal
*/
function getParentNode(node, ssrNodes) {
if (ssrNodes) {
// in server side mode, find parent node with pId
if ((node === null || node === void 0 ? void 0 : node.pId) && ssrNodes[node.pId]) {
return ssrNodes[node.pId];
}
return null;
}
return node === null || node === void 0 ? void 0 : node.parentNode;
}
/**
* Base classes
*/
class SelectorCore {
constructor() {
// style weight
this.specificity = 0;
}
/**
* Sort and store style rules according to categories,
* such as id selectors are grouped into one category, class names are grouped into one category, etc.
*
* @param sorter - sort rules
* @param base - base
*/
lookupSort(sorter, base) {
sorter.sortAsUniversal(base !== null && base !== void 0 ? base : this);
}
/**
* remove sort
*
* @param sorter - sort rules
* @param base - base
*/
removeSort(sorter, base) {
sorter.removeAsUniversal(base !== null && base !== void 0 ? base : this);
}
}
/**
* Simple selector type
* provides the method for judging whether a node matches and the method for tracking node attributes
*/
class SimpleSelector extends SelectorCore {
constructor() {
super(...arguments);
// rarity of style
this.rarity = 0;
}
accumulateChanges(node, match) {
if (!this.dynamic) {
return this.match(node);
}
if (this.mayMatch(node)) {
this.trackChanges(node, match);
return true;
}
return false;
}
/**
* determine if the node matches
*
* @param node - target node
*/
match(node) {
return !!node;
}
/**
* prejudgment
*
* @param node - target node
*/
mayMatch(node) {
return this.match(node);
}
/**
* track changes of node
*
* @param node - target node
* @param match - SelectorsMatch
*/
trackChanges(node, match) {
}
}
class SimpleSelectorSequence extends SimpleSelector {
constructor(selectors) {
super();
this.specificity = selectors.reduce((sum, sel) => sel.specificity + sum, 0);
this.head = selectors.reduce((prev, curr) => {
return !prev
|| (prev instanceof SimpleSelector && curr.rarity > prev.rarity)
? curr
: prev;
}, null);
this.dynamic = selectors.some(sel => sel.dynamic);
this.selectors = selectors;
}
toString() {
return `${this.selectors.join('')}${wrap(this.combinator)}`;
}
match(node) {
if (!node) {
return false;
}
return this.selectors.every(sel => sel.match(node));
}
mayMatch(node) {
if (!node) {
return false;
}
return this.selectors.every(sel => sel.mayMatch(node));
}
trackChanges(node, match) {
this.selectors.forEach(sel => sel.trackChanges(node, match));
}
lookupSort(sorter, base) {
if (this.head && this.head instanceof SimpleSelector) {
this.head.lookupSort(sorter, base !== null && base !== void 0 ? base : this);
}
}
removeSort(sorter, base) {
if (this.head && this.head instanceof SimpleSelector) {
this.head.removeSort(sorter, base !== null && base !== void 0 ? base : this);
}
}
}
/**
* Generic selector type, eg. *
*/
class UniversalSelector extends SimpleSelector {
constructor() {
super();
this.specificity = 0x00000000;
this.rarity = 0;
this.dynamic = false;
}
toString() {
return `*${wrap(this.combinator)}`;
}
match() {
// universal selectors can all match
return true;
}
}
/**
* ID selector, eg. #root
*/
class IdSelector extends SimpleSelector {
constructor(id) {
super();
this.specificity = 0x00010000;
this.rarity = 3;
this.dynamic = false;
this.id = id;
}
toString() {
return `#${this.id}${wrap(this.combinator)}`;
}
match(node) {
var _a, _b;
if (!node) {
return false;
}
// ssr node's id is native id, the dom id is attribute's id
return ((_b = (_a = node.props) === null || _a === void 0 ? void 0 : _a.attributes) === null || _b === void 0 ? void 0 : _b.id) === this.id || node.id === this.id;
}
lookupSort(sorter, base) {
sorter.sortById(this.id, base !== null && base !== void 0 ? base : this);
}
removeSort(sorter, base) {
sorter.removeById(this.id, base !== null && base !== void 0 ? base : this);
}
}
/**
* tag selector, eg. div, ul
*/
class TypeSelector extends SimpleSelector {
constructor(cssType) {
super();
this.specificity = 0x00000001;
this.rarity = 1;
this.dynamic = false;
this.cssType = cssType;
}
toString() {
return `${this.cssType}${wrap(this.combinator)}`;
}
match(node) {
if (!node) {
return false;
}
return node.tagName === this.cssType;
}
lookupSort(sorter, base) {
sorter.sortByType(this.cssType, base !== null && base !== void 0 ? base : this);
}
removeSort(sorter, base) {
sorter.removeByType(this.cssType, base !== null && base !== void 0 ? base : this);
}
}
/**
* class selector
*/
class ClassSelector extends SimpleSelector {
constructor(className) {
super();
this.specificity = 0x00000100;
this.rarity = 2;
this.dynamic = false;
this.className = className;
}
toString() {
return `.${this.className