H5-contact/node_modules/@dcloudio/uni-nvue-styler/dist/uni-nvue-styler.cjs.js

2217 lines
72 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

'use strict';
var shared = require('@vue/shared');
var parseCSSFont = require('parse-css-font');
var postcss = require('postcss');
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
var parseCSSFont__default = /*#__PURE__*/_interopDefault(parseCSSFont);
var postcss__default = /*#__PURE__*/_interopDefault(postcss);
const COMBINATORS_RE = /^((?:(?:\.[A-Za-z0-9_\-]+)+[\+\~\> ])*)((?:\.[A-Za-z0-9_\-\:]+)+)$/;
// 单个类选择器或类串联选择器,支持逗号分隔(如 .class1, .class1.class2, .class1,.class2,.class3.class4
const SIMPLE_SELECTOR_RE = /^(?:\.[A-Za-z0-9_\-]+)+(?:\s*,\s*(?:\.[A-Za-z0-9_\-]+)+)*$/;
function createDecl(prop, value, important, raws, source) {
const decl = {
type: 'decl',
prop,
value: value.toString(),
raws,
source,
};
if (important) {
decl.important = true;
}
return decl;
}
const NUM_REGEXP = /^[-]?\d*\.?\d+$/;
const LENGTH_REGEXP = /^[-+]?\d*\.?\d+(\S*)$/;
const SUPPORTED_VALUES_REGEXP = /supported values are: ([^)]+)/;
const SUPPORT_CSS_UNIT = ['px', 'pt', 'wx', 'upx', 'rpx'];
const isNumber = (val) => typeof val === 'number';
const cacheStringFunction = (fn) => {
const cache = Object.create(null);
return ((str) => {
const hit = cache[str];
return hit || (cache[str] = fn(str));
});
};
const hyphenateRE = /([A-Z])/g;
const hyphenateStyleProperty = cacheStringFunction((str) => str
.replace(hyphenateRE, (_, m) => {
if (typeof m === 'string') {
return '-' + m.toLowerCase();
}
return m;
})
.toLowerCase());
function autofixedReason(v, result) {
return 'NOTE: property value `' + v + '` is autofixed to `' + result + '`';
}
function validReason(k, v) {
return ('ERROR: property value `' +
v +
'` is not valid for `' +
hyphenateStyleProperty(k) +
'`');
}
function defaultValueReason(k, v) {
return ('NOTE: property value `' +
v +
'` is the DEFAULT value for `' +
hyphenateStyleProperty(k) +
'` (could be removed)');
}
function supportedEnumReason(k, v, items) {
return ('ERROR: property value `' +
v +
'` is not supported for `' +
hyphenateStyleProperty(k) +
'` (supported values are: `' +
items.join('`|`') +
'`)');
}
function supportedValueWithTipsReason(k, v, tips) {
return ('ERROR: property value `' +
v +
'` is not supported for `' +
hyphenateStyleProperty(k) +
'` ' +
tips);
}
function supportedUnitWithAutofixedReason(unit, v, result) {
return ('NOTE: unit `' +
unit +
'` is not supported and property value `' +
v +
'` is autofixed to `' +
result +
'`');
}
function compatibilityReason(k) {
return ('NOTE: the ' +
hyphenateStyleProperty(k) +
' property may have compatibility problem on native');
}
function supportedPropertyReason(k) {
return ('WARNING: `' +
hyphenateStyleProperty(k) +
'` is not a standard property name (may not be supported)');
}
function getPlatformVersion(platform) {
return isDom2() ? platform?.unixVaporVer : platform?.unixVer;
}
function isDom2() {
return typeof process !== 'undefined' && process.env.UNI_APP_X_DOM2 === 'true';
}
function getSupportedPlatforms(uniPlatform) {
const supportedPlatforms = [];
if (getPlatformVersion(uniPlatform?.app?.android) !== 'x') {
supportedPlatforms.push('app-android');
}
if (getPlatformVersion(uniPlatform?.app?.ios) !== 'x') {
supportedPlatforms.push('app-ios');
}
if (getPlatformVersion(uniPlatform?.app?.harmony) !== 'x') {
supportedPlatforms.push('app-harmony');
}
return supportedPlatforms;
}
function normalizeReasons(reasons, k, v) {
let enums = [];
for (let i = 0; i < reasons.length; i++) {
const reason = reasons[i];
if (SUPPORTED_VALUES_REGEXP.test(reason)) {
const match = reason.match(SUPPORTED_VALUES_REGEXP);
if (match) {
const values = match[1]
.split('|')
.map((item) => item.replace(/`/g, ''))
.filter(Boolean);
enums.push(...values);
reasons.splice(i, 1);
i--;
}
}
}
if (enums.length > 0) {
enums = [...new Set(enums)];
reasons.push(supportedEnumReason(k, v, enums));
}
return reasons;
}
// http://www.w3.org/TR/css3-color/#svg-color
const EXTENDED_COLOR_KEYWORDS = {
aliceblue: '#F0F8FF',
antiquewhite: '#FAEBD7',
aqua: '#00FFFF',
aquamarine: '#7FFFD4',
azure: '#F0FFFF',
beige: '#F5F5DC',
bisque: '#FFE4C4',
black: '#000000',
blanchedalmond: '#FFEBCD',
blue: '#0000FF',
blueviolet: '#8A2BE2',
brown: '#A52A2A',
burlywood: '#DEB887',
cadetblue: '#5F9EA0',
chartreuse: '#7FFF00',
chocolate: '#D2691E',
coral: '#FF7F50',
cornflowerblue: '#6495ED',
cornsilk: '#FFF8DC',
crimson: '#DC143C',
cyan: '#00FFFF',
darkblue: '#00008B',
darkcyan: '#008B8B',
darkgoldenrod: '#B8860B',
darkgray: '#A9A9A9',
darkgreen: '#006400',
darkgrey: '#A9A9A9',
darkkhaki: '#BDB76B',
darkmagenta: '#8B008B',
darkolivegreen: '#556B2F',
darkorange: '#FF8C00',
darkorchid: '#9932CC',
darkred: '#8B0000',
darksalmon: '#E9967A',
darkseagreen: '#8FBC8F',
darkslateblue: '#483D8B',
darkslategray: '#2F4F4F',
darkslategrey: '#2F4F4F',
darkturquoise: '#00CED1',
darkviolet: '#9400D3',
deeppink: '#FF1493',
deepskyblue: '#00BFFF',
dimgray: '#696969',
dimgrey: '#696969',
dodgerblue: '#1E90FF',
firebrick: '#B22222',
floralwhite: '#FFFAF0',
forestgreen: '#228B22',
fuchsia: '#FF00FF',
gainsboro: '#DCDCDC',
ghostwhite: '#F8F8FF',
gold: '#FFD700',
goldenrod: '#DAA520',
gray: '#808080',
green: '#008000',
greenyellow: '#ADFF2F',
grey: '#808080',
honeydew: '#F0FFF0',
hotpink: '#FF69B4',
indianred: '#CD5C5C',
indigo: '#4B0082',
ivory: '#FFFFF0',
khaki: '#F0E68C',
lavender: '#E6E6FA',
lavenderblush: '#FFF0F5',
lawngreen: '#7CFC00',
lemonchiffon: '#FFFACD',
lightblue: '#ADD8E6',
lightcoral: '#F08080',
lightcyan: '#E0FFFF',
lightgoldenrodyellow: '#FAFAD2',
lightgray: '#D3D3D3',
lightgreen: '#90EE90',
lightgrey: '#D3D3D3',
lightpink: '#FFB6C1',
lightsalmon: '#FFA07A',
lightseagreen: '#20B2AA',
lightskyblue: '#87CEFA',
lightslategray: '#778899',
lightslategrey: '#778899',
lightsteelblue: '#B0C4DE',
lightyellow: '#FFFFE0',
lime: '#00FF00',
limegreen: '#32CD32',
linen: '#FAF0E6',
magenta: '#FF00FF',
maroon: '#800000',
mediumaquamarine: '#66CDAA',
mediumblue: '#0000CD',
mediumorchid: '#BA55D3',
mediumpurple: '#9370DB',
mediumseagreen: '#3CB371',
mediumslateblue: '#7B68EE',
mediumspringgreen: '#00FA9A',
mediumturquoise: '#48D1CC',
mediumvioletred: '#C71585',
midnightblue: '#191970',
mintcream: '#F5FFFA',
mistyrose: '#FFE4E1',
moccasin: '#FFE4B5',
navajowhite: '#FFDEAD',
navy: '#000080',
oldlace: '#FDF5E6',
olive: '#808000',
olivedrab: '#6B8E23',
orange: '#FFA500',
orangered: '#FF4500',
orchid: '#DA70D6',
palegoldenrod: '#EEE8AA',
palegreen: '#98FB98',
paleturquoise: '#AFEEEE',
palevioletred: '#DB7093',
papayawhip: '#FFEFD5',
peachpuff: '#FFDAB9',
peru: '#CD853F',
pink: '#FFC0CB',
plum: '#DDA0DD',
powderblue: '#B0E0E6',
purple: '#800080',
red: '#FF0000',
rosybrown: '#BC8F8F',
royalblue: '#4169E1',
saddlebrown: '#8B4513',
salmon: '#FA8072',
sandybrown: '#F4A460',
seagreen: '#2E8B57',
seashell: '#FFF5EE',
sienna: '#A0522D',
silver: '#C0C0C0',
skyblue: '#87CEEB',
slateblue: '#6A5ACD',
slategray: '#708090',
slategrey: '#708090',
snow: '#FFFAFA',
springgreen: '#00FF7F',
steelblue: '#4682B4',
tan: '#D2B48C',
teal: '#008080',
thistle: '#D8BFD8',
tomato: '#FF6347',
turquoise: '#40E0D0',
violet: '#EE82EE',
wheat: '#F5DEB3',
white: '#FFFFFF',
whitesmoke: '#F5F5F5',
yellow: '#FFFF00',
yellowgreen: '#9ACD32',
};
// from uni-api/ canvas
function checkColor(e) {
// 其他开发者适配的echarts会传入一个undefined到这里
e = e || '#000000';
let t = null;
if ((t = /^#([0-9|A-F|a-f]{6})$/.exec(e)) != null) {
const n = parseInt(t[1].slice(0, 2), 16);
const o = parseInt(t[1].slice(2, 4), 16);
const r = parseInt(t[1].slice(4), 16);
return [n, o, r, 255];
}
if ((t = /^#([0-9|A-F|a-f]{3})$/.exec(e)) != null) {
let n = t[1].slice(0, 1);
let o = t[1].slice(1, 2);
let r = t[1].slice(2, 3);
n = parseInt(n + n, 16);
o = parseInt(o + o, 16);
r = parseInt(r + r, 16);
return [n, o, r, 255];
}
if ((t = /^rgb\((.+)\)$/.exec(e)) != null) {
return t[1]
.split(',')
.map(function (e) {
return Math.min(255, parseInt(e.trim()));
})
.concat(255);
}
if ((t = /^rgba\((.+)\)$/.exec(e)) != null) {
return t[1].split(',').map(function (e, t) {
return t === 3
? Math.floor(255 * parseFloat(e.trim()))
: Math.min(255, parseInt(e.trim()));
});
}
var i = e.toLowerCase();
if (shared.hasOwn(EXTENDED_COLOR_KEYWORDS, i)) {
t = /^#([0-9|A-F|a-f]{6,8})$/.exec(EXTENDED_COLOR_KEYWORDS[i]);
const n = parseInt(t[1].slice(0, 2), 16);
const o = parseInt(t[1].slice(2, 4), 16);
const r = parseInt(t[1].slice(4, 6), 16);
let a = parseInt(t[1].slice(6, 8), 16);
a = a >= 0 ? a : 255;
return [n, o, r, a];
}
console.error('unsupported color:' + e);
return [0, 0, 0, 255];
}
/**
* css value 分割多值,兼容包含括号的 css 方法,比如 var/env/calc() 等
*/
function splitValues(value) {
const trimmedValue = value.trim();
if (!trimmedValue.includes('(')) {
return trimmedValue.split(/\s+/);
}
const parts = [];
let current = '';
let depth = 0;
for (let i = 0; i < trimmedValue.length; i++) {
const char = trimmedValue[i];
if (char === '(') {
depth++;
current += char;
}
else if (char === ')') {
if (depth > 0) {
depth--;
}
current += char;
}
else if (/\s/.test(char)) {
if (depth === 0) {
if (current) {
parts.push(current);
current = '';
}
}
else {
// 多个空格处理一个
if (current.length > 0 && !/\s$/.test(current)) {
current += ' ';
}
}
}
else {
current += char;
}
}
if (current) {
parts.push(current);
}
return parts;
}
const backgroundColor = 'background-color' ;
const backgroundImage = 'background-image' ;
const handleTransformBackground = (decl) => {
let { value, important, raws, source } = decl;
value = value.trim();
if (value === 'none') {
return [
createDecl(backgroundImage, 'none', important, raws, source),
createDecl(backgroundColor, 'transparent', important, raws, source),
];
}
if (/^#?\S+$/.test(value) || /^rgba?(.+)$/.test(value)) {
return [
createDecl(backgroundImage, 'none', important, raws, source),
createDecl(backgroundColor, value, important, raws, source),
];
}
else if (/^linear-gradient(.+)$/.test(value)) {
return [
createDecl(backgroundImage, value, important, raws, source),
createDecl(backgroundColor, 'transparent', important, raws, source),
];
}
else if (value == '') {
return [
createDecl(backgroundImage, 'none', important, raws, source),
createDecl(backgroundColor, 'transparent', important, raws, source),
];
}
return [decl];
};
const handleTransformBackgroundNvue = (decl) => {
const { value, important, raws, source } = decl;
if (/^#?\S+$/.test(value) || /^rgba?(.+)$/.test(value)) {
return [createDecl(backgroundColor, value, important, raws, source)];
}
else if (/^linear-gradient(.+)$/.test(value)) {
return [createDecl(backgroundImage, value, important, raws, source)];
}
else if (value == '') {
return [decl];
}
return [decl];
};
function createTransformBackground(options) {
return (decl) => {
// nvue 平台维持原有逻辑不变
const isUvuePlatform = options.type === 'uvue';
if (isUvuePlatform) {
return handleTransformBackground(decl);
}
else {
return handleTransformBackgroundNvue(decl);
}
};
}
const borderTop = 'border-top-' ;
const borderRight = 'border-right-' ;
const borderBottom = 'border-bottom-' ;
const borderLeft = 'border-left-' ;
const transformBorderColor = (decl) => {
let { prop, value, important, raws, source } = decl;
value = value.trim();
const _property_split = shared.hyphenate(prop).split('-');
let property = _property_split[_property_split.length - 1];
const splitResult = splitValues(value); // 1pt
switch (splitResult.length) {
case 1:
if (_property_split.length === 3) {
// border-top-width
return [decl];
}
// border-width
splitResult.push(splitResult[0], splitResult[0], splitResult[0]);
break;
case 2:
splitResult.push(splitResult[0], splitResult[1]);
break;
case 3:
splitResult.push(splitResult[1]);
break;
}
return [
createDecl(borderTop + property, splitResult[0], important, raws, source),
createDecl(borderRight + property, splitResult[1], important, raws, source),
createDecl(borderBottom + property, splitResult[2], important, raws, source),
createDecl(borderLeft + property, splitResult[3], important, raws, source),
];
};
const transformBorderColorNvue = (decl) => {
let { prop, value, important, raws, source } = decl;
value = value.trim();
let property = shared.hyphenate(prop).split('-')[1];
const splitResult = value.replace(/\s*,\s*/g, ',').split(/\s+/);
switch (splitResult.length) {
case 1:
return [decl];
case 2:
splitResult.push(splitResult[0], splitResult[1]);
break;
case 3:
splitResult.push(splitResult[1]);
break;
}
return [
createDecl(borderTop + property, splitResult[0], important, raws, source),
createDecl(borderRight + property, splitResult[1], important, raws, source),
createDecl(borderBottom + property, splitResult[2], important, raws, source),
createDecl(borderLeft + property, splitResult[3], important, raws, source),
];
};
const transformBorderStyle = transformBorderColor;
const transformBorderStyleNvue = transformBorderColorNvue;
const transformBorderWidth = transformBorderColor;
const transformBorderWidthNvue = transformBorderColorNvue;
function isSingleCssVarValue(value) {
const trimmedValue = value.trim();
if (splitValues(trimmedValue).length !== 1 || !/^var\(/i.test(trimmedValue)) {
return false;
}
let depth = 0;
for (let i = 0; i < trimmedValue.length; i++) {
const char = trimmedValue[i];
if (char === '(') {
depth++;
}
else if (char === ')') {
if (depth === 0) {
return false;
}
depth--;
if (depth === 0 && trimmedValue.slice(i + 1).trim()) {
return false;
}
}
}
return depth === 0;
}
function tryExpandSingleValueVarShorthand(decl, props, value) {
// 当整个简写值只有一个 var() 时,无法静态判断它属于哪个子属性,
// 这里直接复制到每个长属性,交给运行时再解析。
if (!isSingleCssVarValue(value)) {
return null;
}
const { important, raws, source } = decl;
return props.map((prop) => createDecl(prop, value, important, raws, source));
}
const borderWidth = '-width' ;
const borderStyle = '-style' ;
const borderColor = '-color' ;
const BORDER_WIDTH_REGEXP = /^(?:[\d.]+\S*|thin|medium|thick)$/;
// 这里按完整 CSS line-style 识别,后续再交给 border-*-style 的既有校验逻辑报精确错误。
const BORDER_STYLE_REGEXP = /^(?:none|hidden|dotted|dashed|solid|double|groove|ridge|inset|outset)$/;
const BORDER_SHORTHAND_VAR_ORDER_WARNING = '__borderShorthandVarOrderWarning';
function createBorderVarOrderWarning(prop, value) {
return supportedValueWithTipsReason(prop, value, '(border shorthand with CSS variables must follow `width style color`, for example: `1px solid var(--color, #999999)`)');
}
function isCssVarValue(value) {
return value.startsWith('var(');
}
function isBorderWidthValue(value) {
return isCssVarValue(value) || BORDER_WIDTH_REGEXP.test(value);
}
function isBorderStyleValue(value) {
return isCssVarValue(value) || BORDER_STYLE_REGEXP.test(value);
}
function isBorderColorValue(value) {
return (isCssVarValue(value) ||
(!BORDER_WIDTH_REGEXP.test(value) && !BORDER_STYLE_REGEXP.test(value)));
}
function createTransformBorder(options) {
return (decl) => {
const { prop, value, important, raws, source } = decl;
const singleVarResult = tryExpandSingleValueVarShorthand(decl, [prop + borderWidth, prop + borderStyle, prop + borderColor], value);
// 单个 var() 无法提前判断是 width/style/colordom2 下先平铺后继续展开。
if (singleVarResult) {
return [
...transformBorderWidth(singleVarResult[0]),
...transformBorderStyle(singleVarResult[1]),
...transformBorderColor(singleVarResult[2]),
];
}
let splitResult = splitValues(value);
const havVar = splitResult.some((str) => str.startsWith('var('));
let result = [];
// 包含 var 时按位置解析,避免把 style 误判成 color
if (havVar) {
if (splitResult.length > 3 ||
(splitResult.length === 3 &&
(!isBorderWidthValue(splitResult[0]) ||
!isBorderStyleValue(splitResult[1]) ||
!isBorderColorValue(splitResult[2])))) {
decl[BORDER_SHORTHAND_VAR_ORDER_WARNING] =
createBorderVarOrderWarning(prop, value);
return [];
}
result = splitResult;
splitResult = [];
}
else {
result = [BORDER_WIDTH_REGEXP, BORDER_STYLE_REGEXP, /\S+/].map((item) => {
const index = splitResult.findIndex((str) => item.test(str));
return index < 0 ? null : splitResult.splice(index, 1)[0];
});
}
if (splitResult.length > 0 && value != '') {
return [decl];
}
const defaultWidth = (str) => {
if (str != null) {
return str.trim();
}
return 'medium';
};
const defaultStyle = (str) => {
if (str != null) {
return str.trim();
}
return 'none';
};
const defaultColor = (str) => {
if (str != null) {
return str.trim();
}
return '#000000';
};
return [
...transformBorderWidth(createDecl(prop + borderWidth, defaultWidth(result[0]), important, raws, source)),
...transformBorderStyle(createDecl(prop + borderStyle, defaultStyle(result[1]), important, raws, source)),
...transformBorderColor(createDecl(prop + borderColor, defaultColor(result[2]), important, raws, source)),
];
};
}
/**
* nvue 逻辑不变
*/
function createTransformBorderNvue(options) {
return (decl) => {
let { prop, value, important, raws, source } = decl;
value = value.trim();
const splitResult = value.replace(/\s*,\s*/g, ',').split(/\s+/);
const result = [
/^[\d\.]+\S*|^(thin|medium|thick)$/,
/^(solid|dashed|dotted|none)$/,
/\S+/,
].map((item) => {
const index = splitResult.findIndex((str) => item.test(str));
return index < 0 ? null : splitResult.splice(index, 1)[0];
});
if (splitResult.length) {
return [decl];
}
return [
createDecl(prop + borderWidth, (result[0] || '0').trim(), important, raws, source),
createDecl(prop + borderStyle, (result[1] || 'solid').trim(), important, raws, source),
createDecl(prop + borderColor, (result[2] || '#000000').trim(), important, raws, source),
];
};
}
const borderTopLeftRadius = 'border-top-left-radius'
;
const borderTopRightRadius = 'border-top-right-radius'
;
const borderBottomRightRadius = 'border-bottom-right-radius'
;
const borderBottomLeftRadius = 'border-bottom-left-radius'
;
const transformBorderRadius = (decl) => {
let { value, important, raws, source } = decl;
value = value.trim();
const splitResult = splitValues(value);
if (value.includes('/')) {
return [decl];
}
switch (splitResult.length) {
case 1:
splitResult.push(splitResult[0], splitResult[0], splitResult[0]);
break;
case 2:
splitResult.push(splitResult[0], splitResult[1]);
break;
case 3:
splitResult.push(splitResult[1]);
break;
}
return [
createDecl(borderTopLeftRadius, splitResult[0], important, raws, source),
createDecl(borderTopRightRadius, splitResult[1], important, raws, source),
createDecl(borderBottomRightRadius, splitResult[2], important, raws, source),
createDecl(borderBottomLeftRadius, splitResult[3], important, raws, source),
];
};
const transformBorderRadiusNvue = (decl) => {
let { value, important, raws, source } = decl;
value = value.trim();
const splitResult = value.split(/\s+/);
if (value.includes('/')) {
return [decl];
}
// const isUvuePlatform = options.type === 'uvue'
switch (splitResult.length) {
case 1:
return [decl];
case 2:
splitResult.push(splitResult[0], splitResult[1]);
break;
case 3:
splitResult.push(splitResult[1]);
break;
}
return [
createDecl(borderTopLeftRadius, splitResult[0], important, raws, source),
createDecl(borderTopRightRadius, splitResult[1], important, raws, source),
createDecl(borderBottomRightRadius, splitResult[2], important, raws, source),
createDecl(borderBottomLeftRadius, splitResult[3], important, raws, source),
];
};
const flexDirection = 'flex-direction' ;
const flexWrap = 'flex-wrap' ;
const transformFlexFlow = (decl) => {
let { value, important, raws, source } = decl;
value = value.trim();
const splitResult = splitValues(value);
const singleVarResult = tryExpandSingleValueVarShorthand(decl, [flexDirection, flexWrap], value);
// 单个 var() 无法提前判断是 direction 还是 wrapdom2 下直接平铺。
if (singleVarResult) {
return singleVarResult;
}
const result = [
/^(column|column-reverse|row|row-reverse)$/,
/^(nowrap|wrap|wrap-reverse)$/,
].map((item) => {
const index = splitResult.findIndex((str) => item.test(str));
return index < 0 ? null : splitResult.splice(index, 1)[0];
});
if (splitResult.length) {
return [decl];
}
return [
createDecl(flexDirection, result[0] || 'column', important, raws, source),
createDecl(flexWrap, result[1] || 'nowrap', important, raws, source),
];
};
const transformFont = (decl) => {
let { value, important, raws, source } = decl;
value = value.trim();
const result = [];
const font = parseCSSFont__default.default(value);
if (font.system) {
return result;
}
const { style, weight, size, lineHeight, family } = font;
if (style) {
result.push(createDecl('font-style', style, important, raws, source));
}
if (weight) {
result.push(createDecl('font-weight', weight, important, raws, source));
}
if (size) {
result.push(createDecl('font-size', size, important, raws, source));
}
if (lineHeight) {
result.push(createDecl('line-height', lineHeight, important, raws, source));
}
if (family) {
result.push(createDecl('font-family', serialize(family), important, raws, source));
}
return result;
};
function serialize(family) {
return family.map((f) => (f.includes(' ') ? `"${f}"` : f)).join(', ');
}
const top = '-top' ;
const right = '-right' ;
const bottom = '-bottom' ;
const left = '-left' ;
const createTransformBox = (type) => {
return (decl) => {
const { value, important, raws, source } = decl;
const splitResult = splitValues(value);
switch (splitResult.length) {
case 1:
splitResult.push(splitResult[0], splitResult[0], splitResult[0]);
break;
case 2:
splitResult.push(splitResult[0], splitResult[1]);
break;
case 3:
splitResult.push(splitResult[1]);
break;
}
return [
createDecl(type + top, splitResult[0], important, raws, source),
createDecl(type + right, splitResult[1], important, raws, source),
createDecl(type + bottom, splitResult[2], important, raws, source),
createDecl(type + left, splitResult[3], important, raws, source),
];
};
};
const transformMargin = createTransformBox('margin');
const transformPadding = createTransformBox('padding');
const transitionProperty = 'transition-property'
;
const transitionDuration = 'transition-duration'
;
const transitionTimingFunction = 'transition-timing-function'
;
const transitionDelay = 'transition-delay' ;
const transformTransition = (decl) => {
let { value, important, raws, source } = decl;
value = value.trim();
const result = [];
let match;
// 针对 cubic-bezier 特殊处理
// eg: cubic-bezier(0.42, 0, 1.0, 3) // (0.2,-2,0.8,2)
if (value.includes('cubic-bezier')) {
const CHUNK_REGEXP = /^(\S*)?\s*(\d*\.?\d+(?:ms|s)?)?\s*((\S*)|cubic-bezier\(.*\))?\s*(\d*\.?\d+(?:ms|s)?)?$/;
match = value.match(CHUNK_REGEXP);
}
else {
const CHUNK_REGEXP = /^(\S*)?\s*(\d*\.?\d+(?:ms|s)?)?\s*(\S*)?\s*(\d*\.?\d+(?:ms|s)?)?$/;
match = value.match(CHUNK_REGEXP);
}
if (!match) {
return result;
}
match[1] &&
result.push(createDecl(transitionProperty, match[1], important, raws, source));
match[2] &&
result.push(createDecl(transitionDuration, match[2], important, raws, source));
match[3] &&
result.push(createDecl(transitionTimingFunction, match[3], important, raws, source));
match[4] &&
result.push(createDecl(transitionDelay, match[4], important, raws, source));
return result;
};
const flexGrow = 'flex-grow' ;
const flexShrink = 'flex-shrink' ;
const flexBasis = 'flex-basis' ;
const transformFlex = (decl) => {
let { value, important, raws, source } = decl;
value = value.trim();
const result = [];
const splitResult = splitValues(value);
const singleVarResult = tryExpandSingleValueVarShorthand(decl, [flexGrow, flexShrink, flexBasis], value);
// 单个 var() 无法提前拆出 grow/shrink/basisdom2 下按 border 的兜底逻辑平铺。
if (singleVarResult) {
return singleVarResult;
}
// 是否 flex-grow 的有效值 <number [0,∞]>
const isFlexGrowValid = (v) => isNumber(Number(v)) && !Number.isNaN(Number(v));
const isFlexShrinkValid = (v) => isNumber(Number(v)) && !Number.isNaN(Number(v)) && Number(v) >= 0;
const isFlexBasisValid = (v) => typeof v === 'string' && v.trim() !== '';
if (splitResult.length === 1) {
// 关键字处理
if (value === 'none') {
result.push(createDecl(flexGrow, '0', important, raws, source), createDecl(flexShrink, '0', important, raws, source), createDecl(flexBasis, 'auto', important, raws, source));
return result;
}
if (value === 'auto') {
result.push(createDecl(flexGrow, '1', important, raws, source), createDecl(flexShrink, '1', important, raws, source), createDecl(flexBasis, 'auto', important, raws, source));
return result;
}
if (value === 'initial') {
result.push(createDecl(flexGrow, '0', important, raws, source), createDecl(flexShrink, '1', important, raws, source), createDecl(flexBasis, 'auto', important, raws, source));
return result;
}
const v = splitResult[0];
// number 视为 flex-grow
if (isFlexGrowValid(v)) {
if (Number(v) < 0) {
return [];
}
result.push(createDecl(flexGrow, v, important, raws, source), createDecl(flexShrink, '1', important, raws, source), createDecl(flexBasis, '0%', important, raws, source));
return result;
}
else if (isFlexBasisValid(v)) {
result.push(createDecl(flexGrow, '1', important, raws, source), createDecl(flexShrink, '1', important, raws, source), createDecl(flexBasis, v, important, raws, source));
return result;
}
else {
return [decl];
}
}
else if (splitResult.length === 2) {
const [v1, v2] = splitResult;
if (isFlexGrowValid(v1)) {
if (isFlexShrinkValid(v2)) {
// flex: 1 2 => 1 2 0%
result.push(createDecl(flexGrow, v1, important, raws, source), createDecl(flexShrink, v2, important, raws, source), createDecl(flexBasis, '0%', important, raws, source));
return result;
}
else {
// flex: 1 100px => 1 1 100px
result.push(createDecl(flexGrow, v1, important, raws, source), createDecl(flexShrink, '1', important, raws, source), createDecl(flexBasis, v2, important, raws, source));
return result;
}
}
else {
return [decl];
}
}
else if (splitResult.length === 3) {
const [v1, v2, v3] = splitResult;
if (isFlexGrowValid(v1) && isFlexShrinkValid(v2)) {
result.push(createDecl(flexGrow, v1, important, raws, source), createDecl(flexShrink, v2, important, raws, source), createDecl(flexBasis, v3, important, raws, source));
return result;
}
else {
// fallback
return [decl];
}
}
// 其它情况,原样返回
return [decl];
};
function getDeclTransforms(options) {
const transformBorder = options.type === 'uvue'
? createTransformBorder()
: createTransformBorderNvue();
const styleMap = {
transition: transformTransition,
border: transformBorder,
background: createTransformBackground(options),
['borderTop']: transformBorder,
['borderRight']: transformBorder,
['borderBottom']: transformBorder,
['borderLeft']: transformBorder,
['borderStyle']: options.type === 'uvue' ? transformBorderStyle : transformBorderStyleNvue,
['borderWidth']: options.type === 'uvue' ? transformBorderWidth : transformBorderWidthNvue,
['borderColor']: options.type === 'uvue' ? transformBorderColor : transformBorderColorNvue,
['borderRadius']: options.type === 'uvue'
? transformBorderRadius
: transformBorderRadiusNvue,
// uvue已经支持这些简写属性不需要展开
// margin,padding继续展开确保样式的优先级
margin: transformMargin,
padding: transformPadding,
['flexFlow']: transformFlexFlow,
};
if (options.type === 'uvue') {
styleMap.flex = transformFlex;
}
let result = {};
{
styleMap.font = transformFont;
for (const property in styleMap) {
result[hyphenateStyleProperty(property)] = styleMap[property];
}
}
return result;
}
let DeclTransforms;
const expanded = Symbol('expanded');
function expand(options) {
const plugin = {
postcssPlugin: `${options.type || 'nvue'}:expand`,
Declaration(decl, helper) {
if (decl[expanded]) {
return;
}
if (!DeclTransforms) {
DeclTransforms = getDeclTransforms(options);
}
const transform = DeclTransforms[decl.prop];
if (transform) {
const res = transform(decl);
const reason = decl[BORDER_SHORTHAND_VAR_ORDER_WARNING];
if (reason && helper && decl.warn) {
let needLog = false;
if (options.logLevel === 'NOTE') {
needLog = true;
}
else if (options.logLevel === 'ERROR') {
if (reason.startsWith('ERROR:')) {
needLog = true;
}
}
else {
if (!reason.startsWith('NOTE:')) {
needLog = true;
}
}
if (needLog) {
decl.warn(helper.result, reason);
}
delete decl[BORDER_SHORTHAND_VAR_ORDER_WARNING];
}
const isSame = res.length === 1 && res[0] === decl;
if (!isSame) {
decl.replaceWith(res);
}
}
decl[expanded] = true;
},
};
return plugin;
}
function vueStyleValidator(options) {
const plugin = {
postcssPlugin: `${options.type || 'nvue'}:vue-style-validator`,
Declaration(decl, helper) {
const isUVue = options.type === 'uvue';
if (!isUVue) {
return;
}
if (decl.prop.startsWith('--')) {
const parent = decl.parent;
if (parent?.type === 'root' &&
(parent?.source?.input?.from.includes('&type=style') ||
parent?.source?.input?.from.endsWith('uvue.style.uts'))) {
// 命中:在根节点且不是 template 样式,需要禁止
const reason = `ERROR: CSS custom properties must be inside a CSS rule (selector) or @ rule. Found "${decl.prop}" at top level in Vue style block.`;
let needLog = false;
if (options.logLevel === 'NOTE') {
needLog = true;
}
else if (options.logLevel === 'ERROR') {
if (reason.startsWith('ERROR:')) {
needLog = true;
}
}
else {
if (!reason.startsWith('NOTE:')) {
needLog = true;
}
}
if (needLog && helper && decl.warn) {
decl.warn(helper.result, reason);
}
// 移除这个声明
decl.remove();
}
}
},
};
return plugin;
}
const normalizeColor = (v) => {
v = (v || '').toString();
if (v.match(/^#[0-9a-fA-F]{6}$/)) {
return { value: v };
}
// rgba issues 13371
if (v.match(/^#[0-9a-fA-F]{4}$/)) {
return {
value: '#' + v[1] + v[1] + v[2] + v[2] + v[3] + v[3] + v[4] + v[4],
reason: function reason(k, v, result) {
return autofixedReason(v, result);
},
};
}
if (v.match(/^#[0-9a-fA-F]{8}$/)) {
return {
value: v,
};
}
if (v.match(/^#[0-9a-fA-F]{3}$/)) {
return {
value: '#' + v[1] + v[1] + v[2] + v[2] + v[3] + v[3],
reason: function reason(k, v, result) {
return autofixedReason(v, result);
},
};
}
if (EXTENDED_COLOR_KEYWORDS[v]) {
return {
value: EXTENDED_COLOR_KEYWORDS[v],
reason: function reason(k, v, result) {
return autofixedReason(v, result);
},
};
}
let arrColor, r, g, b, a;
const RGB_REGEXP = /^rgb\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)$/gi;
const RGBA_REGEXP = /^rgba\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d*\.?\d+)\s*\)$/gi;
if ((arrColor = RGB_REGEXP.exec(v))) {
r = parseInt(arrColor[1]);
g = parseInt(arrColor[2]);
b = parseInt(arrColor[3]);
if (r >= 0 && r <= 255 && g >= 0 && g <= 255 && b >= 0 && b <= 255) {
return { value: 'rgb(' + [r, g, b].join(',') + ')' };
}
}
if ((arrColor = RGBA_REGEXP.exec(v))) {
r = parseInt(arrColor[1]);
g = parseInt(arrColor[2]);
b = parseInt(arrColor[3]);
a = parseFloat(arrColor[4]);
if (r >= 0 &&
r <= 255 &&
g >= 0 &&
g <= 255 &&
b >= 0 &&
b <= 255 &&
a >= 0 &&
a <= 1) {
return { value: 'rgba(' + [r, g, b, a].join(',') + ')' };
}
}
if (v === 'transparent') {
return { value: 'rgba(0,0,0,0)' };
}
return {
value: null,
reason(k, v, result) {
return validReason(k, v);
},
};
};
function createEnumNormalize(items) {
return (v) => {
const index = items.indexOf(v);
if (index > 0) {
return { value: v };
}
if (index === 0) {
return {
value: v,
reason: function reason(k, v, result) {
return defaultValueReason(k, v);
},
};
}
return {
value: null,
reason: function reason(k, v, result) {
return supportedEnumReason(k, v, items);
},
};
};
}
function createEnumNormalizeWithPlatform(items) {
return (v, { platform }) => {
const property = items.find((item) => item.name === v);
const supportedEnum = items
.filter((item) => {
const supportedPlatforms = getSupportedPlatforms(item.uniPlatform);
return supportedPlatforms.includes(platform);
})
.map((item) => item.name);
if (property) {
const supportedPlatforms = getSupportedPlatforms(property.uniPlatform);
// TODO 未跨平台支持的属性特殊提示
if (!supportedPlatforms.includes(platform)) {
return {
value: null,
reason: function reason(k, v, result) {
return supportedEnumReason(k, v, supportedEnum);
},
};
}
return { value: v };
}
return {
value: null,
reason: function reason(k, v, result) {
return supportedEnumReason(k, v, supportedEnum);
},
};
};
}
const normalizeFlexWrap = (v) => {
const values = ['nowrap', 'wrap', 'wrap-reverse'];
const index = values.indexOf(v);
if (index > 0) {
return {
value: v,
reason(k, v, result) {
return compatibilityReason(k);
},
};
}
if (index === 0) {
return {
value: v,
reason: function reason(k, v, result) {
return defaultValueReason(k, v);
},
};
}
return {
value: null,
reason(k, v, result) {
return supportedEnumReason(k, v, values);
},
};
};
const normalizeInteger = (v) => {
v = (v || '').toString();
if (v.match(/^[-+]?\d+$/)) {
return { value: parseInt(v, 10) };
}
return {
value: null,
reason: function reason(k, v, result) {
return supportedEnumReason(k, v, ['integer']);
},
};
};
function createNormalizeLength({ removePx, property, } = {}) {
return (v, options) => {
v = (v || '').toString();
if (options.type === 'uvue' &&
!v.includes('calc(') &&
((/var\([^)]+\)/.test(v) &&
(/--uni-safe-area-inset-(top|bottom|left|right)/.test(v) ||
/--status-bar-height/.test(v))) ||
/--window-(top|bottom)/.test(v) ||
/env\(([^)]+)\)/.test(v))) {
v = v.replace(/\s/g, '');
return { value: v };
}
const match = v.match(LENGTH_REGEXP);
if (match) {
var unit = match[1];
const uvue = options.type === 'uvue';
if (uvue) {
if (!unit || (unit === 'px' && removePx)) {
return { value: parseFloat(v) };
}
else if (unit === 'px' ||
unit === 'rpx' ||
// 只有line-height支持em单位
(unit === 'em' && property === 'line-height')) {
return { value: v };
}
}
else {
// nvue
if (!unit || unit === 'px') {
return { value: parseFloat(v) };
}
if (SUPPORT_CSS_UNIT.includes(unit)) {
return { value: v };
}
else {
return {
value: parseFloat(v),
reason(k, v, result) {
return supportedUnitWithAutofixedReason(unit, v, result);
},
};
}
}
}
return {
value: null,
reason(k, v, result) {
return supportedEnumReason(k, v, ['number', 'pixel']);
},
};
};
}
const normalizeLength = createNormalizeLength({
removePx: true,
});
const normalizeLengthWithOptions = createNormalizeLength;
const normalizePercent = (v) => {
v = (v || '').toString();
const match = v.match(LENGTH_REGEXP);
if (match) {
var unit = match[1];
if (unit === '%') {
return { value: v };
}
}
return {
value: null,
reason(k, v, result) {
return supportedEnumReason(k, v, ['percent']);
},
};
};
const normalizeNumber = (v) => {
v = (v || '').toString();
var match = v.match(LENGTH_REGEXP);
if (match && !match[1]) {
return { value: parseFloat(v) };
}
return {
value: null,
reason: function reason(k, v, result) {
return supportedEnumReason(k, v, ['number']);
},
};
};
const normalizeString = (v) => {
v = (v || '').toString().replace(/["']/g, '');
return {
value: v,
};
};
const normalizeShorthandLength = (v, options) => {
v = (v || '').toString();
let value = [];
let reason = [];
const results = v.split(/\s+/).map((v) => normalizeLength(v, options));
for (let i = 0; i < results.length; ++i) {
const res = results[i];
if (res.value === null) {
return res;
}
value.push(res.value);
reason.push(res.reason);
}
return {
value: value.join(' '),
reason: function (k, v, result) {
return reason
.map(function (res) {
if (shared.isFunction(res)) {
return res(k, v, result);
}
})
.join('\n');
},
};
};
const normalizeTransform = (v) => {
return { value: v };
};
const normalizeInterval = (v, options) => {
v = (v || 0).toString();
let match, num;
if ((match = v.match(/^\d*\.?\d+(ms|s)?$/))) {
const uvue = options.type === 'uvue';
if (uvue) {
// uvue 需要单位
if (match[1]) {
return { value: v };
}
}
else {
num = parseFloat(match[0]);
if (!match[1]) {
return { value: parseInt(num + '') };
}
if (match[1] === 's') {
num *= 1000;
}
return {
value: parseInt(num + ''),
reason(k, v, result) {
return autofixedReason(v, result);
},
};
}
}
return {
value: null,
reason(k, v, result) {
return supportedEnumReason(k, v, ['number of seconds', 'milliseconds']);
},
};
};
const normalizeTimingFunction = (v) => {
v = (v || '').toString();
if (v.match(/^linear|ease|ease-in|ease-out|ease-in-out$/)) {
return { value: v };
}
let match;
if ((match = v.match(/^cubic-bezier\(\s*(.*)\s*,\s*(.*)\s*,\s*(.*)\s*,\s*(.*)\s*\)$/))) {
if (match[1].match(NUM_REGEXP) &&
match[2].match(NUM_REGEXP) &&
match[3].match(NUM_REGEXP) &&
match[4].match(NUM_REGEXP)) {
const ret = [
parseFloat(match[1]),
parseFloat(match[2]),
parseFloat(match[3]),
parseFloat(match[4]),
].join(',');
return { value: 'cubic-bezier(' + ret + ')' };
}
}
return {
value: null,
reason(k, v, result) {
return supportedEnumReason(k, v, [
'linear',
'ease',
'ease-in',
'ease-out',
'ease-in-out',
'cubic-bezier(n,n,n,n)',
]);
},
};
};
function createCombinedNormalize(normalizes) {
return (v, options) => {
const reasons = [];
for (let i = 0; i < normalizes.length; i++) {
const result = normalizes[i](v, options);
if (result.value !== null) {
return result;
}
if (result.reason) {
reasons.push(result.reason);
}
}
return {
value: null,
reason(k, v, result) {
return normalizeReasons(reasons.map((reason) => reason(k, v, result)), k, v).join('\n');
},
};
};
}
const normalizeGradient = (v) => {
v = (v || '').toString();
if (/^linear-gradient(.+)$/s.test(v)) {
return { value: v };
}
return {
// 枚举里会做reason提示
value: null,
};
};
const normalizeUrl = (v) => {
v = (v || '').toString();
if (/^url(.+)$/s.test(v)) {
return { value: v };
}
return {
value: null,
};
};
function normalizePlatform(normalize, uniPlatform) {
return (v, options, declInfo) => {
// platform 未定义时候忽略
const currentPlatform = options.platform;
const supportedPlatforms = getSupportedPlatforms(uniPlatform);
// TODO 未跨平台支持的属性特殊提示
if (!supportedPlatforms.includes(currentPlatform)) {
return {
value: v,
reason(k, v, result) {
return supportedPropertyReason(k);
},
};
}
return normalize(v, options, declInfo);
};
}
function normalizeShorthandProperty(normalize) {
return (v, options) => {
v = (v || '').toString();
const value = [];
const reasons = [];
const results = v.split(/\s+/).map((v) => normalize(v, options));
for (let i = 0; i < results.length; ++i) {
const res = results[i];
if (res.value === null) {
return res;
}
if (res.reason) {
reasons.push(res.reason);
}
value.push(res.value);
}
return {
value: value.length === 1 ? value[0] : value.join(' '),
reason: function (k, v, result) {
return reasons.map((reason) => reason(k, v, result)).join('\n');
},
};
};
}
function normalizeFontFace(normalize) {
return (v, options, declInfo) => {
if (declInfo?.atRule === 'font-face') {
return {
value: null,
reason(k, v, result) {
const items = ['font-family', 'src'];
const name = '@' + declInfo.atRule;
return ('ERROR: property `' +
hyphenateStyleProperty(k) +
'` is not supported for `' +
name +
'` (supported properties are: `' +
items.join('`|`') +
'`)');
},
};
}
return normalize(v, options, declInfo);
};
}
// 只有@font-face下的src属性才支持
const normalizeSrc = (v, options, declInfo) => {
if (declInfo?.atRule === 'font-face') {
return { value: v };
}
return {
value: null,
reason(k, v, result) {
return supportedPropertyReason(k);
},
};
};
const normalizeFlexFlow = (v) => {
v = (v || '').toString();
const values = v.split(/\s+/);
// flex-flow 需要定义每一个属性值
if (values.length === 1) {
return {
value: v,
reason(k, v, result) {
return supportedValueWithTipsReason(k, v, '(both property values must be explicitly defined)');
},
};
}
return {
value: v,
};
};
// transition-property 不读 css.json
// 从 property.ts 中移动到 map 里,避免循环依赖
const normalizeProperty = (v, options) => {
v = (v || '').toString();
v = v
.split(/\s*,\s*/)
.map(shared.camelize)
.join(',');
// [all, none] 是特殊值
if (options.type === 'uvue') {
if (v === 'all' || v === 'none') {
return { value: v };
}
}
if (v.split(/\s*,\s*/).every((p) => {
return !!getNormalizeMap(options)[p];
})) {
return { value: v };
}
return {
value: null,
reason: function reason(k, v, result) {
return supportedEnumReason(k, v, ['css property']);
},
};
};
const normalizeDefault = (v) => {
return { value: v };
};
const NVUE_PROP_NAME_GROUPS = {
boxModel: {
display: createEnumNormalize(['flex']),
width: normalizeLength,
height: normalizeLength,
overflow: createEnumNormalize(['hidden']),
padding: normalizeShorthandLength,
paddingLeft: normalizeLength,
paddingRight: normalizeLength,
paddingTop: normalizeLength,
paddingBottom: normalizeLength,
margin: normalizeShorthandLength,
marginLeft: normalizeLength,
marginRight: normalizeLength,
marginTop: normalizeLength,
marginBottom: normalizeLength,
borderWidth: normalizeLength,
borderLeftWidth: normalizeLength,
borderTopWidth: normalizeLength,
borderRightWidth: normalizeLength,
borderBottomWidth: normalizeLength,
borderColor: normalizeColor,
borderLeftColor: normalizeColor,
borderTopColor: normalizeColor,
borderRightColor: normalizeColor,
borderBottomColor: normalizeColor,
borderStyle: createEnumNormalize(['dotted', 'dashed', 'solid']),
borderTopStyle: createEnumNormalize(['dotted', 'dashed', 'solid']),
borderRightStyle: createEnumNormalize(['dotted', 'dashed', 'solid']),
borderBottomStyle: createEnumNormalize(['dotted', 'dashed', 'solid']),
borderLeftStyle: createEnumNormalize(['dotted', 'dashed', 'solid']),
borderRadius: normalizeLength,
borderBottomLeftRadius: normalizeLength,
borderBottomRightRadius: normalizeLength,
borderTopLeftRadius: normalizeLength,
borderTopRightRadius: normalizeLength,
},
flexbox: {
flex: normalizeNumber,
flexWrap: normalizeFlexWrap,
flexDirection: createEnumNormalize([
'column',
'row',
'column-reverse',
'row-reverse',
]),
justifyContent: createEnumNormalize([
'flex-start',
'flex-end',
'center',
'space-between',
'space-around',
]),
alignItems: createEnumNormalize([
'stretch',
'flex-start',
'flex-end',
'center',
]),
},
position: {
position: createEnumNormalize(['relative', 'absolute', 'sticky', 'fixed']),
top: normalizeLength,
bottom: normalizeLength,
left: normalizeLength,
right: normalizeLength,
zIndex: normalizeInteger,
},
common: {
opacity: normalizeNumber,
boxShadow: normalizeDefault,
backgroundColor: normalizeColor,
backgroundImage: normalizeDefault,
},
text: {
lines: normalizeInteger,
color: normalizeColor,
fontSize: normalizeLength,
fontStyle: createEnumNormalize(['normal', 'italic']),
fontFamily: normalizeDefault,
fontWeight: createEnumNormalize([
'normal',
'bold',
'100',
'200',
'300',
'400',
'500',
'600',
'700',
'800',
'900',
]),
textDecoration: createEnumNormalize(['none', 'underline', 'line-through']),
textAlign: createEnumNormalize(['left', 'center', 'right']),
textOverflow: createEnumNormalize(['clip', 'ellipsis', 'unset', 'fade']),
lineHeight: normalizeLength,
},
transition: {
transitionProperty: normalizeProperty,
transitionDuration: normalizeInterval,
transitionDelay: normalizeInterval,
transitionTimingFunction: normalizeTimingFunction,
},
transform: {
transform: normalizeTransform,
transformOrigin: normalizeTransform, // fixed by xxxxxx
},
customized: {
itemSize: normalizeLength,
itemColor: normalizeColor,
itemSelectedColor: normalizeColor,
textColor: normalizeColor,
timeColor: normalizeColor,
textHighlightColor: normalizeColor,
},
};
// 特定属性
const uvueNormalizeMap = {
transform: normalizeTransform,
fontFamily: normalizeString,
textDecoration: normalizeDefault,
boxShadow: normalizeDefault,
textShadow: normalizeDefault,
// transition-property 支持逗号多值分割
transitionProperty: normalizeProperty,
transitionTimingFunction: normalizeTimingFunction,
};
const restrictionMap = {
["length" /* Restriction.LENGTH */]: normalizeLength,
["percentage" /* Restriction.PERCENTAGE */]: normalizePercent,
["number" /* Restriction.NUMBER */]: normalizeNumber,
["number(0-1)" /* Restriction.NUMBER_0_1 */]: normalizeNumber,
["integer" /* Restriction.INTEGER */]: normalizeInteger,
["color" /* Restriction.COLOR */]: normalizeColor,
["time" /* Restriction.TIME */]: normalizeInterval,
["property" /* Restriction.PROPERTY */]: normalizeProperty,
["timing-function" /* Restriction.TIMING_FUNCTION */]: normalizeTimingFunction,
["gradient" /* Restriction.GRADIENT */]: normalizeGradient,
["url" /* Restriction.URL */]: normalizeUrl,
};
// @font-face下不支持的属性
const invalidFontFaceProperties = ['fontWeight', 'fontStyle', 'fontVariant'];
function getUVueNormalizeMap(options) {
const result = {
src: normalizeSrc,
};
let cssJson;
try {
// eslint-disable-next-line no-restricted-globals
cssJson = require('../lib/css.json');
}
catch (e) {
// 单元测试环境,源码目录
// eslint-disable-next-line no-restricted-globals
cssJson = require('../../lib/css.json');
}
const { properties } = cssJson;
for (let i = 0; i < properties.length; i++) {
const property = properties[i];
const prop = shared.camelize(property.name);
let normalize;
if (uvueNormalizeMap[prop]) {
normalize = uvueNormalizeMap[prop];
}
else {
const normalizes = getNormalizes(property, options);
if (normalizes.length > 1) {
normalize = createCombinedNormalize(normalizes);
}
else if (normalizes.length === 1) {
normalize = normalizes[0];
}
else {
normalize = normalizeDefault;
}
// 简写属性
if (property.shorthand) {
normalize = normalizeShorthandProperty(normalize);
}
// 处理@font-face下不支持的属性
if (invalidFontFaceProperties.includes(prop)) {
normalize = normalizeFontFace(normalize);
}
// 校验flexFlow属性值的个数先临时写死后续考虑根据css.json动态判断
if (prop === 'flexFlow') {
normalize = createCombinedNormalize([normalizeFlexFlow, normalize]);
}
}
result[prop] = normalizePlatform(normalize, property.uniPlatform);
}
return result;
}
// 读取 css.json 的 restrictions
function getNormalizes(property, options) {
const normalizes = [];
const { restrictions } = property;
restrictions.forEach((restriction) => {
let normalize = restrictionMap[restriction];
if (normalize) {
if (restriction === "length" /* Restriction.LENGTH */) {
// 如果同时有number和length例如line-height: 1.5, line-height: 16px则不能移除px
normalize = normalizeLengthWithOptions({
removePx: options.keepUnitPx
? false
: !restrictions.includes("number" /* Restriction.NUMBER */),
property: property.name,
});
}
normalizes.push(normalize);
}
});
// enum
if (property?.values?.length) {
normalizes.push(createEnumNormalizeWithPlatform(property.values));
}
return normalizes;
}
let normalizeMap;
function getNormalizeMap(options) {
if (normalizeMap) {
return normalizeMap;
}
const uvue = options.type === 'uvue';
if (uvue) {
normalizeMap = getUVueNormalizeMap(options);
}
else {
normalizeMap = Object.keys(NVUE_PROP_NAME_GROUPS).reduce((res, name) => {
const group = NVUE_PROP_NAME_GROUPS[name];
Object.keys(group).forEach((prop) => {
res[prop] = group[prop];
});
return res;
}, {});
}
return normalizeMap;
}
const normalized = Symbol('normalized');
function normalize(opts = {}) {
if (!shared.hasOwn(opts, 'logLevel')) {
opts.logLevel = 'WARNING';
}
const plugin = {
postcssPlugin: `${opts.type || 'nvue'}:normalize`,
Declaration: createDeclarationProcessor(opts),
};
{
plugin.Rule = createRuleProcessor(opts);
}
return plugin;
}
function createRuleProcessor(opts = {}) {
return (rule, helper) => {
if (rule[normalized]) {
return;
}
rule.selector = rule.selectors
.map((selector) => {
const isUvue = opts.type === 'uvue';
if (isUvue) {
// 特殊处理 ::v-deep 选择器 和 ::v-deep(.xxx) 写法
const hasVDeep = selector.includes('::v-deep');
const hasDeepMethod = selector.includes(':deep(');
if (hasVDeep) {
selector = selector.replace(/::v-deep/g, '');
}
if (hasDeepMethod) {
selector = selector.replace(/:deep\(([^)]+)\)/g, '$1');
}
}
// 移除组合符周围的空格,合并多个空格
selector = selector
.replace(/\s*([\+\~\>])\s*/g, '$1')
.replace(/\s+/g, ' ');
// 组合符号
if (COMBINATORS_RE.test(selector)) {
return selector;
}
let type = opts.type || 'nvue';
rule.warn(helper.result, 'ERROR: Selector `' +
selector +
'` is not supported. ' +
type +
' only support classname selector');
return '';
})
.filter(Boolean)
.join(', ');
if (!rule.selector) {
rule.remove();
}
rule[normalized] = true;
};
}
function createDeclarationProcessor(options) {
return (decl, helper) => {
if (decl[normalized]) {
return;
}
if (decl.prop.startsWith('--')) {
return;
}
else {
// @ts-expect-error
decl.__originalProp = decl.prop;
decl.prop = shared.camelize(decl.prop);
}
const { value, log } = normalizeDecl(decl, options);
if (shared.isString(value) || isNumber(value)) {
decl.value = value;
}
if (log && log.reason && helper && decl.warn) {
const { reason } = log;
let needLog = false;
if (options.logLevel === 'NOTE') {
needLog = true;
}
else if (options.logLevel === 'ERROR') {
if (reason.startsWith('ERROR:')) {
needLog = true;
}
}
else {
if (!reason.startsWith('NOTE:')) {
needLog = true;
}
}
needLog && decl.warn(helper.result, reason);
}
if (value === null) {
decl.remove();
}
decl[normalized] = true;
};
}
function normalizeDecl(decl, options) {
let { prop: name, value } = decl;
let result, log;
const normalize = getNormalizeMap(options)[name];
if (options.type === 'uvue' && !value.includes('calc')) {
if (hasCssVar(value)) {
return {
value,
log,
};
}
}
if (shared.isFunction(normalize)) {
if (!shared.isFunction(value)) {
result = normalize(value, options, {
atRule: decl.parent?.type === 'atrule' ? decl.parent.name : '',
});
}
else {
result = { value: value };
}
if (result.reason) {
log = { reason: result.reason(name, value, result.value) };
}
}
else {
// ensure number type, no `px`
if (shared.isString(value)) {
const match = value.match(LENGTH_REGEXP);
if (match && (!match[1] || SUPPORT_CSS_UNIT.indexOf(match[1]) === -1)) {
value = parseFloat(value);
}
}
result = { value: value };
log = {
reason: supportedPropertyReason(name),
};
}
return {
value: result.value,
log,
};
}
function hasCssVar(value) {
return value.includes('var(');
}
function objectifier(node, options) {
return objectifierWithMessages(node, options).obj;
}
function objectifierWithMessages(node, options) {
if (!node) {
return { obj: {}, messages: [] };
}
const parseMessages = options.parseMessages || [];
function isInParseMessages(node) {
return parseMessages.some((message) => message.node.source === node.source);
}
const context = {
'FONT-FACE': [],
TRANSITION: {},
messages: [],
warn(node, message) {
// 如果parse阶段已经有该节点的错误则不再添加
if (!isInParseMessages(node)) {
context.messages.push(new postcss.Warning(message, { node }));
}
},
};
const result = transform(node, context, options);
if (options.trim) {
trimObj(result);
}
if (context['FONT-FACE'].length) {
result['@FONT-FACE'] = context['FONT-FACE'];
}
if (Object.keys(context.TRANSITION).length) {
result['@TRANSITION'] = context.TRANSITION;
}
return { obj: result, messages: context.messages };
}
function trimObj(obj) {
Object.keys(obj).forEach((name) => {
const value = obj[name];
if (Object.keys(value).length === 1 && shared.hasOwn(value, '')) {
obj[name] = value[''];
}
});
}
function transform(node, context, options) {
const result = {};
node.each((child) => {
if (child.type === 'atrule') {
const body = transform(child, context, options);
if (child.name === 'font-face') {
const fontFamily = body.fontFamily;
if (fontFamily && '"\''.indexOf(fontFamily[0]) > -1) {
body.fontFamily = fontFamily.slice(1, fontFamily.length - 1);
}
context['FONT-FACE'].push(body);
}
}
else if (child.type === 'rule') {
const body = transform(child, context, options);
child.selectors.forEach((selector) => {
transformSelector(child, selector, body, result, context, options);
});
}
else if (child.type === 'decl') {
let name = child.prop;
let value = child.value;
if (options.visitor) {
const result = options.visitor(child, context);
if (!result) {
return;
}
name = result.name;
value = result.value;
}
if (child.important) {
result['!' + name] = value;
// !important的值域优先级高故删除非!important的值域
delete result[name];
}
else {
if (!shared.hasOwn(result, '!' + name)) {
result[name] = value;
}
}
}
});
return result;
}
function transformSelector(node, selector, body, result, context, options) {
if (options.simpleSelectorOnly) {
if (!SIMPLE_SELECTOR_RE.test(selector)) {
context.warn(node, `Invalid selector "${selector}".`);
return;
}
}
const res = selector.match(COMBINATORS_RE);
if (!res) {
return;
}
let parentSelector = res[1];
let curSelector = res[2].substring(1);
// .a.b => a.b
const dotIndex = curSelector.indexOf('.');
if (dotIndex > -1) {
parentSelector += curSelector.substring(dotIndex);
curSelector = curSelector.substring(0, dotIndex);
}
const pseudoIndex = curSelector.indexOf(':');
if (pseudoIndex > -1) {
const pseudoClass = curSelector.slice(pseudoIndex);
curSelector = curSelector.slice(0, pseudoIndex);
Object.keys(body).forEach(function (name) {
body[name + pseudoClass] = body[name];
delete body[name];
});
}
transition(curSelector, body, context);
if (!Object.keys(body).length) {
return;
}
result = (result[curSelector] || (result[curSelector] = {}));
if (result[parentSelector]) {
// clone
result[parentSelector] = processImportant(shared.extend({}, result[parentSelector], body));
}
else {
result[parentSelector] = body;
}
}
/**
* 处理 important 属性,如果某个属性是 important需要将非 important 的该属性移除掉
* @param body
*/
function processImportant(body) {
Object.keys(body).forEach((name) => {
if (name.startsWith('!')) {
delete body[name.substring(1)];
}
});
return body;
}
function transition(className, body, { TRANSITION }) {
Object.keys(body).forEach((prop) => {
if (prop.indexOf('transition') === 0 && prop !== 'transition') {
const realProp = prop.replace('transition', '');
TRANSITION[className] = TRANSITION[className] || {};
TRANSITION[className][realProp[0].toLowerCase() + realProp.slice(1)] =
body[prop];
}
});
}
async function parse(input, options = {}) {
const { root, messages } = await postcss__default.default([
vueStyleValidator(options),
expand(options),
normalize(options),
])
.process(input, {
from: options.filename || 'foo.css',
})
.catch((err) => {
return {
root: null,
messages: [
{
type: 'error',
text: err.message,
},
],
};
});
if (options.noCode === true) {
return { code: '', messages };
}
const { obj, messages: objMessages } = root
? objectifierWithMessages(root, {
trim: !!options.trim,
parseMessages: messages,
})
: { obj: {}, messages: [] };
messages.push(...objMessages);
if (options.map || options.mapOf) {
return {
code: mapToInitStringChunk(objToMap(obj), options.ts, true, options.mapOf, options.padStyleMapOf, options.chunk),
messages,
};
}
let code = JSON.stringify(obj);
if (options.type === 'uvue') {
// TODO 暂时仅简易转换 CSS 变量
code = code.replace(/\:\s*"(.+?)"/g, function (str, p1) {
return isExpr(p1) ? `:${p1}` : str;
});
}
return { code, messages };
}
function mapToInitStringChunk(map, ts = false, isRoot = false, mapOf = '', padStyleMapOf = '', chunk = 0) {
if (!chunk) {
return mapToInitString(map, ts, isRoot, mapOf, padStyleMapOf);
}
const chunks = [];
let chunkMap = new Map();
let chunkCount = 0;
for (const [key, value] of map) {
if (chunkCount === chunk) {
chunks.push(mapToInitString(chunkMap, ts, isRoot, mapOf, padStyleMapOf));
chunkMap = new Map();
chunkCount = 0;
}
chunkMap.set(key, value);
chunkCount++;
}
if (chunkCount) {
chunks.push(mapToInitString(chunkMap, ts, isRoot, mapOf, padStyleMapOf));
}
return `[${chunks.join(',')}]`;
}
function mapToInitString(map, ts = false, isRoot = false, mapOf = '', padStyleMapOf = '') {
const entries = [];
for (let [key, value] of map) {
if (value instanceof Map) {
// trim
if (isRoot && !(value.values().next().value instanceof Map)) {
entries.push(`["${key}", ${padStyleMapOf}(${mapToInitString(value, ts, false, mapOf, padStyleMapOf)})]`);
}
else {
entries.push(`["${key}", ${mapToInitString(value, ts, false, mapOf, padStyleMapOf)}]`);
}
}
else {
entries.push(`["${key}", ${shared.isString(value) && isExpr(value) ? value : JSON.stringify(value)}]`);
}
}
if (mapOf) {
return `${mapOf}([${entries.join(', ')}])`;
}
return `new Map${ts
? isRoot
? '<string, Map<string, Map<string, any>>>'
: '<string, any>'
: ''}([${entries.join(', ')}])`;
}
function objToMap(obj) {
const map = new Map();
for (const key in obj) {
const value = obj[key];
if (typeof value === 'object') {
map.set(key, objToMap(value));
}
else {
map.set(key, value);
}
}
return map;
}
function isExpr(value) {
return value.startsWith('calc(');
}
exports.checkColor = checkColor;
exports.expand = expand;
exports.normalize = normalize;
exports.objectifier = objectifier;
exports.objectifierWithMessages = objectifierWithMessages;
exports.parse = parse;
exports.supportedPropertyReason = supportedPropertyReason;