You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1387 lines
42 KiB
1387 lines
42 KiB
'use strict'; |
|
|
|
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); |
|
|
|
/** |
|
* Make a map and return a function for checking if a key |
|
* is in that map. |
|
* IMPORTANT: all calls of this function must be prefixed with |
|
* \/\*#\_\_PURE\_\_\*\/ |
|
* So that rollup can tree-shake them if necessary. |
|
*/ |
|
|
|
(process.env.NODE_ENV !== 'production') |
|
? Object.freeze({}) |
|
: {}; |
|
(process.env.NODE_ENV !== 'production') ? Object.freeze([]) : []; |
|
const extend = Object.assign; |
|
const hasOwnProperty = Object.prototype.hasOwnProperty; |
|
const hasOwn = (val, key) => hasOwnProperty.call(val, key); |
|
const isFunction = (val) => typeof val === 'function'; |
|
const isString = (val) => typeof val === 'string'; |
|
const cacheStringFunction$1 = (fn) => { |
|
const cache = Object.create(null); |
|
return ((str) => { |
|
const hit = cache[str]; |
|
return hit || (cache[str] = fn(str)); |
|
}); |
|
}; |
|
const camelizeRE = /-(\w)/g; |
|
/** |
|
* @private |
|
*/ |
|
const camelize = cacheStringFunction$1((str) => { |
|
return str.replace(camelizeRE, (_, c) => (c ? c.toUpperCase() : '')); |
|
}); |
|
const hyphenateRE$1 = /\B([A-Z])/g; |
|
/** |
|
* @private |
|
*/ |
|
const hyphenate = cacheStringFunction$1((str) => str.replace(hyphenateRE$1, '-$1').toLowerCase()); |
|
|
|
const COMBINATORS_RE = /^((?:(?:\.[A-Za-z0-9_\-]+)+[\+\~\> ])*)((?:\.[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 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'); |
|
} |
|
|
|
const backgroundColor = 'background-color' ; |
|
const backgroundImage = 'background-image' ; |
|
const transformBackground = (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)]; |
|
} |
|
return [decl]; |
|
}; |
|
|
|
const borderWidth = '-width' ; |
|
const borderStyle = '-style' ; |
|
const borderColor = '-color' ; |
|
const transformBorder = (decl) => { |
|
const { prop, value, important, raws, source } = decl; |
|
const splitResult = value.replace(/\s*,\s*/g, ',').split(/\s+/); |
|
const result = [/^[\d\.]+\S*$/, /^(solid|dashed|dotted)$/, /\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 borderTop = 'border-top-' ; |
|
const borderRight = 'border-right-' ; |
|
const borderBottom = 'border-bottom-' ; |
|
const borderLeft = 'border-left-' ; |
|
const transformBorderColor = (decl) => { |
|
const { prop, value, important, raws, source } = decl; |
|
let property = 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 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) => { |
|
const { value, important, raws, source } = decl; |
|
const splitResult = value.split(/\s+/); |
|
if (value.includes('/')) { |
|
return [decl]; |
|
} |
|
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 transformBorderStyle = transformBorderColor; |
|
|
|
const transformBorderWidth = transformBorderColor; |
|
|
|
const flexDirection = 'flex-direction' ; |
|
const flexWrap = 'flex-wrap' ; |
|
const transformFlexFlow = (decl) => { |
|
const { value, important, raws, source } = decl; |
|
const splitResult = value.split(/\s+/); |
|
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) => { |
|
const { value, important, raws, source } = decl; |
|
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 = value.split(/\s+/); |
|
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) => { |
|
const CHUNK_REGEXP = /^(\S*)?\s*(\d*\.?\d+(?:ms|s)?)?\s*(\S*)?\s*(\d*\.?\d+(?:ms|s)?)?$/; |
|
const { value, important, raws, source } = decl; |
|
const result = []; |
|
const 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 DeclTransforms = { |
|
transition: transformTransition, |
|
margin: transformMargin, |
|
padding: transformPadding, |
|
border: transformBorder, |
|
background: transformBackground, |
|
}; |
|
{ |
|
extend(DeclTransforms, { |
|
'border-top': transformBorder, |
|
'border-right': transformBorder, |
|
'border-bottom': transformBorder, |
|
'border-left': transformBorder, |
|
'border-style': transformBorderStyle, |
|
'border-width': transformBorderWidth, |
|
'border-color': transformBorderColor, |
|
'border-radius': transformBorderRadius, |
|
'flex-flow': transformFlexFlow, |
|
font: transformFont, |
|
}); |
|
} |
|
const expanded = Symbol('expanded'); |
|
const expand = { |
|
postcssPlugin: 'nvue:expand', |
|
Declaration(decl) { |
|
if (decl[expanded]) { |
|
return; |
|
} |
|
const transform = DeclTransforms[decl.prop]; |
|
if (transform) { |
|
const res = transform(decl); |
|
const isSame = res.length === 1 && res[0] === decl; |
|
if (!isSame) { |
|
decl.replaceWith(res); |
|
} |
|
} |
|
decl[expanded] = true; |
|
}, |
|
}; |
|
|
|
const normalizeColor = (v) => { |
|
v = (v || '').toString(); |
|
if (v.match(/^#[0-9a-fA-F]{6}$/)) { |
|
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); |
|
}, |
|
}; |
|
}; |
|
// 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', |
|
}; |
|
|
|
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); |
|
}, |
|
}; |
|
}; |
|
} |
|
|
|
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 supportedValueWithTipsReason(k, v, `(only integer is supported)`); |
|
}, |
|
}; |
|
}; |
|
|
|
const normalizeLength = createNormalizeLength(); |
|
const normalizeLengthWithPercent = createNormalizeLength({ |
|
percent: true, |
|
}); |
|
const normalizeLengthWithAutoAndPercent = createNormalizeLength({ |
|
auto: true, |
|
percent: true, |
|
}); |
|
function createNormalizeLength(options = {}) { |
|
return (v) => { |
|
v = (v || '').toString(); |
|
const match = v.match(LENGTH_REGEXP); |
|
if (match) { |
|
var unit = match[1]; |
|
if (!unit || unit === 'px') { |
|
return { value: parseFloat(v) }; |
|
} |
|
else if (SUPPORT_CSS_UNIT.includes(unit) || |
|
(options.percent && unit === '%')) { |
|
return { value: v }; |
|
} |
|
else { |
|
return { |
|
value: parseFloat(v), |
|
reason(k, v, result) { |
|
return supportedUnitWithAutofixedReason(unit, v, result); |
|
}, |
|
}; |
|
} |
|
} |
|
else { |
|
if (options.auto && v === 'auto') { |
|
return { value: v }; |
|
} |
|
} |
|
return { |
|
value: null, |
|
reason(k, v, result) { |
|
return supportedValueWithTipsReason(k, v, `(only number and pixel values are supported)`); |
|
}, |
|
}; |
|
}; |
|
} |
|
|
|
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 supportedValueWithTipsReason(k, v, '(only number is supported)'); |
|
}, |
|
}; |
|
}; |
|
|
|
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 (isFunction(res)) { |
|
return res(k, v, result); |
|
} |
|
}) |
|
.join('\n'); |
|
}, |
|
}; |
|
}; |
|
|
|
const normalizeTransform = (v) => { |
|
return { value: v }; |
|
}; |
|
|
|
const normalizeTransitionInterval = (v) => { |
|
v = (v || 0).toString(); |
|
let match, num; |
|
if ((match = v.match(/^\d*\.?\d+(ms|s)?$/))) { |
|
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 supportedValueWithTipsReason(k, v, '(only number of seconds and milliseconds is valid)'); |
|
}, |
|
}; |
|
}; |
|
|
|
const normalizeTransitionProperty = (v, options) => { |
|
v = (v || '').toString(); |
|
v = v |
|
.split(/\s*,\s*/) |
|
.map(camelize) |
|
.join(','); |
|
if (v.split(/\s*,\s*/).every((p) => !!getNormalizeMap(options)[p])) { |
|
return { value: v }; |
|
} |
|
return { |
|
value: null, |
|
reason: function reason(k, v, result) { |
|
return supportedValueWithTipsReason(k, v, '(only css property is valid)'); |
|
}, |
|
}; |
|
}; |
|
|
|
const normalizeTransitionTimingFunction = (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)', |
|
]); |
|
}, |
|
}; |
|
}; |
|
|
|
const normalizeDefault = (v) => { |
|
return { value: v }; |
|
}; |
|
const UVUE_PROP_NAME_GROUPS = { |
|
boxModel: { |
|
display: createEnumNormalize(['flex', 'none']), |
|
width: normalizeLengthWithPercent, |
|
height: normalizeLengthWithPercent, |
|
minWidth: normalizeLengthWithPercent, |
|
minHeight: normalizeLengthWithPercent, |
|
maxWidth: normalizeLengthWithPercent, |
|
maxHeight: normalizeLengthWithPercent, |
|
overflow: createEnumNormalize(['hidden', 'visible']), |
|
padding: normalizeShorthandLength, |
|
paddingLeft: normalizeLengthWithAutoAndPercent, |
|
paddingRight: normalizeLengthWithAutoAndPercent, |
|
paddingTop: normalizeLengthWithAutoAndPercent, |
|
paddingBottom: normalizeLengthWithAutoAndPercent, |
|
margin: normalizeShorthandLength, |
|
marginLeft: normalizeLengthWithAutoAndPercent, |
|
marginRight: normalizeLengthWithAutoAndPercent, |
|
marginTop: normalizeLengthWithAutoAndPercent, |
|
marginBottom: normalizeLengthWithAutoAndPercent, |
|
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: normalizeDefault, |
|
flexShrink: normalizeDefault, |
|
flexGrow: normalizeDefault, |
|
flexBasis: normalizeDefault, |
|
flexWrap: normalizeFlexWrap, |
|
flexFlow: normalizeDefault, |
|
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', |
|
'baseline', |
|
]), |
|
alignContent: createEnumNormalize([ |
|
'stretch', |
|
'flex-start', |
|
'flex-end', |
|
'center', |
|
'space-between', |
|
'space-around', |
|
]), |
|
}, |
|
position: { |
|
position: createEnumNormalize(['relative', 'absolute', 'sticky', 'fixed']), |
|
top: normalizeLengthWithAutoAndPercent, |
|
bottom: normalizeLengthWithAutoAndPercent, |
|
left: normalizeLengthWithAutoAndPercent, |
|
right: normalizeLengthWithAutoAndPercent, |
|
zIndex: normalizeInteger, |
|
}, |
|
common: { |
|
opacity: normalizeNumber, |
|
boxShadow: normalizeDefault, |
|
boxSizing: createEnumNormalize(['content-box', 'border-box']), |
|
backgroundColor: normalizeColor, |
|
backgroundImage: normalizeDefault, |
|
backgroundClip: createEnumNormalize([ |
|
'border-box', |
|
'padding-box', |
|
'content-box', |
|
]), |
|
}, |
|
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: normalizeTransitionProperty, |
|
transitionDuration: normalizeTransitionInterval, |
|
transitionDelay: normalizeTransitionInterval, |
|
transitionTimingFunction: normalizeTransitionTimingFunction, |
|
}, |
|
transform: { |
|
transform: normalizeTransform, |
|
transformOrigin: normalizeTransform, // fixed by xxxxxx |
|
}, |
|
customized: { |
|
itemSize: normalizeLength, |
|
itemColor: normalizeColor, |
|
itemSelectedColor: normalizeColor, |
|
textColor: normalizeColor, |
|
timeColor: normalizeColor, |
|
textHighlightColor: normalizeColor, |
|
}, |
|
}; |
|
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: normalizeTransitionProperty, |
|
transitionDuration: normalizeTransitionInterval, |
|
transitionDelay: normalizeTransitionInterval, |
|
transitionTimingFunction: normalizeTransitionTimingFunction, |
|
}, |
|
transform: { |
|
transform: normalizeTransform, |
|
transformOrigin: normalizeTransform, // fixed by xxxxxx |
|
}, |
|
customized: { |
|
itemSize: normalizeLength, |
|
itemColor: normalizeColor, |
|
itemSelectedColor: normalizeColor, |
|
textColor: normalizeColor, |
|
timeColor: normalizeColor, |
|
textHighlightColor: normalizeColor, |
|
}, |
|
}; |
|
let normalizeMap; |
|
function getNormalizeMap(options) { |
|
if (normalizeMap) { |
|
return normalizeMap; |
|
} |
|
const uvue = options.type === 'uvue'; |
|
const PROP_NAME_GROUPS = uvue ? UVUE_PROP_NAME_GROUPS : NVUE_PROP_NAME_GROUPS; |
|
normalizeMap = Object.keys(PROP_NAME_GROUPS).reduce((res, name) => { |
|
const group = 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 (!hasOwn(opts, 'logLevel')) { |
|
opts.logLevel = 'WARNING'; |
|
} |
|
const plugin = { |
|
postcssPlugin: `${opts.type || 'nvue'}:normalize`, |
|
Declaration: createDeclarationProcessor(opts), |
|
}; |
|
{ |
|
plugin.Rule = createRuleProcessor(); |
|
} |
|
return plugin; |
|
} |
|
function createRuleProcessor() { |
|
return (rule, helper) => { |
|
if (rule[normalized]) { |
|
return; |
|
} |
|
rule.selector = rule.selectors |
|
.map((selector) => { |
|
selector = selector |
|
.replace(/\s*([\+\~\>])\s*/g, '$1') |
|
.replace(/\s+/, ' '); |
|
if (COMBINATORS_RE.test(selector)) { |
|
return selector; |
|
} |
|
rule.warn(helper.result, 'ERROR: Selector `' + |
|
selector + |
|
'` is not supported. nvue 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; |
|
} |
|
decl.prop = camelize(decl.prop); |
|
const { value, log } = normalizeDecl(decl.prop, decl.value, options); |
|
if (isString(value) || isNumber(value)) { |
|
decl.value = value; |
|
} |
|
if (log && log.reason && helper) { |
|
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(name, value, options) { |
|
let result, log; |
|
const normalize = getNormalizeMap(options)[name]; |
|
if (isFunction(normalize)) { |
|
if (!isFunction(value)) { |
|
result = normalize(value, options); |
|
} |
|
else { |
|
result = { value: value }; |
|
} |
|
if (result.reason) { |
|
log = { reason: result.reason(name, value, result.value) }; |
|
} |
|
} |
|
else { |
|
// ensure number type, no `px` |
|
if (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: 'WARNING: `' + |
|
hyphenateStyleProperty(name) + |
|
'` is not a standard property name (may not be supported)', |
|
}; |
|
} |
|
return { |
|
value: result.value, |
|
log, |
|
}; |
|
} |
|
|
|
function objectifier(node) { |
|
if (!node) { |
|
return {}; |
|
} |
|
const context = { |
|
'FONT-FACE': [], |
|
TRANSITION: {}, |
|
}; |
|
const result = transform(node, context); |
|
if (context['FONT-FACE'].length) { |
|
result['@FONT-FACE'] = context['FONT-FACE']; |
|
} |
|
if (Object.keys(context.TRANSITION).length) { |
|
result['@TRANSITION'] = context.TRANSITION; |
|
} |
|
return result; |
|
} |
|
function transform(node, context) { |
|
const result = {}; |
|
node.each((child) => { |
|
if (child.type === 'atrule') { |
|
const body = transform(child, context); |
|
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); |
|
child.selectors.forEach((selector) => { |
|
transformSelector(selector, body, result, context); |
|
}); |
|
} |
|
else if (child.type === 'decl') { |
|
if (child.important) { |
|
result['!' + child.prop] = child.value; |
|
// !important的值域优先级高,故删除非!important的值域 |
|
delete result[child.prop]; |
|
} |
|
else { |
|
if (!hasOwn(result, '!' + child.prop)) { |
|
result[child.prop] = child.value; |
|
} |
|
} |
|
} |
|
}); |
|
return result; |
|
} |
|
function transformSelector(selector, body, result, context) { |
|
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(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([expand, 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 = root ? objectifier(root) : {}; |
|
if (options.map) { |
|
return { |
|
code: mapToInitStringChunk(objToMap(obj), options.ts, true, options.chunk), |
|
messages, |
|
}; |
|
} |
|
return { code: JSON.stringify(obj), messages }; |
|
} |
|
function mapToInitStringChunk(map, ts = false, isRoot = false, chunk = 0) { |
|
if (!chunk) { |
|
return mapToInitString(map, ts, isRoot); |
|
} |
|
const chunks = []; |
|
let chunkMap = new Map(); |
|
let chunkCount = 0; |
|
for (const [key, value] of map) { |
|
if (chunkCount === chunk) { |
|
chunks.push(mapToInitString(chunkMap, ts, isRoot)); |
|
chunkMap = new Map(); |
|
chunkCount = 0; |
|
} |
|
chunkMap.set(key, value); |
|
chunkCount++; |
|
} |
|
if (chunkCount) { |
|
chunks.push(mapToInitString(chunkMap, ts, isRoot)); |
|
} |
|
return `[${chunks.join(',')}]`; |
|
} |
|
function mapToInitString(map, ts = false, isRoot = false) { |
|
const entries = []; |
|
for (let [key, value] of map) { |
|
if (value instanceof Map) { |
|
entries.push(`["${key}", ${mapToInitString(value, ts)}]`); |
|
} |
|
else { |
|
entries.push(`["${key}", ${JSON.stringify(value)}]`); |
|
} |
|
} |
|
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; |
|
} |
|
|
|
exports.expand = expand; |
|
exports.normalize = normalize; |
|
exports.objectifier = objectifier; |
|
exports.parse = parse;
|
|
|