uni-nvue-styler.cjs.js 50 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652
  1. 'use strict';
  2. var parseCSSFont = require('parse-css-font');
  3. var postcss = require('postcss');
  4. function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
  5. var parseCSSFont__default = /*#__PURE__*/_interopDefault(parseCSSFont);
  6. var postcss__default = /*#__PURE__*/_interopDefault(postcss);
  7. const COMBINATORS_RE = /^((?:(?:\.[A-Za-z0-9_\-]+)+[\+\~\> ])*)((?:\.[A-Za-z0-9_\-\:]+)+)$/;
  8. function createDecl(prop, value, important, raws, source) {
  9. const decl = {
  10. type: 'decl',
  11. prop,
  12. value: value.toString(),
  13. raws,
  14. source,
  15. };
  16. if (important) {
  17. decl.important = true;
  18. }
  19. return decl;
  20. }
  21. const NUM_REGEXP = /^[-]?\d*\.?\d+$/;
  22. const LENGTH_REGEXP = /^[-+]?\d*\.?\d+(\S*)$/;
  23. const SUPPORTED_VALUES_REGEXP = /supported values are: ([^)]+)/;
  24. const SUPPORT_CSS_UNIT = ['px', 'pt', 'wx', 'upx', 'rpx'];
  25. const isNumber = (val) => typeof val === 'number';
  26. const cacheStringFunction$1 = (fn) => {
  27. const cache = Object.create(null);
  28. return ((str) => {
  29. const hit = cache[str];
  30. return hit || (cache[str] = fn(str));
  31. });
  32. };
  33. const hyphenateRE$1 = /([A-Z])/g;
  34. const hyphenateStyleProperty = cacheStringFunction$1((str) => str
  35. .replace(hyphenateRE$1, (_, m) => {
  36. if (typeof m === 'string') {
  37. return '-' + m.toLowerCase();
  38. }
  39. return m;
  40. })
  41. .toLowerCase());
  42. function autofixedReason(v, result) {
  43. return 'NOTE: property value `' + v + '` is autofixed to `' + result + '`';
  44. }
  45. function validReason(k, v) {
  46. return ('ERROR: property value `' +
  47. v +
  48. '` is not valid for `' +
  49. hyphenateStyleProperty(k) +
  50. '`');
  51. }
  52. function defaultValueReason(k, v) {
  53. return ('NOTE: property value `' +
  54. v +
  55. '` is the DEFAULT value for `' +
  56. hyphenateStyleProperty(k) +
  57. '` (could be removed)');
  58. }
  59. function supportedEnumReason(k, v, items) {
  60. return ('ERROR: property value `' +
  61. v +
  62. '` is not supported for `' +
  63. hyphenateStyleProperty(k) +
  64. '` (supported values are: `' +
  65. items.join('`|`') +
  66. '`)');
  67. }
  68. function supportedValueWithTipsReason(k, v, tips) {
  69. return ('ERROR: property value `' +
  70. v +
  71. '` is not supported for `' +
  72. hyphenateStyleProperty(k) +
  73. '` ' +
  74. tips);
  75. }
  76. function supportedUnitWithAutofixedReason(unit, v, result) {
  77. return ('NOTE: unit `' +
  78. unit +
  79. '` is not supported and property value `' +
  80. v +
  81. '` is autofixed to `' +
  82. result +
  83. '`');
  84. }
  85. function compatibilityReason(k) {
  86. return ('NOTE: the ' +
  87. hyphenateStyleProperty(k) +
  88. ' property may have compatibility problem on native');
  89. }
  90. function supportedPropertyReason(k) {
  91. return ('WARNING: `' +
  92. hyphenateStyleProperty(k) +
  93. '` is not a standard property name (may not be supported)');
  94. }
  95. function getSupportedPlatforms(uniPlatform) {
  96. const supportedPlatforms = [];
  97. if (uniPlatform?.app?.android?.unixVer !== 'x') {
  98. supportedPlatforms.push('app-android');
  99. }
  100. if (uniPlatform?.app.ios?.unixVer !== 'x') {
  101. supportedPlatforms.push('app-ios');
  102. }
  103. return supportedPlatforms;
  104. }
  105. function normalizeReasons(reasons, k, v) {
  106. let enums = [];
  107. for (let i = 0; i < reasons.length; i++) {
  108. const reason = reasons[i];
  109. if (SUPPORTED_VALUES_REGEXP.test(reason)) {
  110. const match = reason.match(SUPPORTED_VALUES_REGEXP);
  111. if (match) {
  112. const values = match[1]
  113. .split('|')
  114. .map((item) => item.replace(/`/g, ''))
  115. .filter(Boolean);
  116. enums.push(...values);
  117. reasons.splice(i, 1);
  118. i--;
  119. }
  120. }
  121. }
  122. if (enums.length > 0) {
  123. enums = [...new Set(enums)];
  124. reasons.push(supportedEnumReason(k, v, enums));
  125. }
  126. return reasons;
  127. }
  128. const backgroundColor = 'background-color' ;
  129. const backgroundImage = 'background-image' ;
  130. const transformBackground = (decl) => {
  131. const { value, important, raws, source } = decl;
  132. if (/^#?\S+$/.test(value) || /^rgba?(.+)$/.test(value)) {
  133. return [createDecl(backgroundColor, value, important, raws, source)];
  134. }
  135. else if (/^linear-gradient(.+)$/.test(value)) {
  136. return [createDecl(backgroundImage, value, important, raws, source)];
  137. }
  138. return [decl];
  139. };
  140. const borderWidth = '-width' ;
  141. const borderStyle = '-style' ;
  142. const borderColor = '-color' ;
  143. function createTransformBorder(options) {
  144. return (decl) => {
  145. const { prop, value, important, raws, source } = decl;
  146. const splitResult = value.replace(/\s*,\s*/g, ',').split(/\s+/);
  147. const result = [
  148. /^[\d\.]+\S*|^(thin|medium|thick)$/,
  149. /^(solid|dashed|dotted|none)$/,
  150. /\S+/,
  151. ].map((item) => {
  152. const index = splitResult.findIndex((str) => item.test(str));
  153. return index < 0 ? null : splitResult.splice(index, 1)[0];
  154. });
  155. if (splitResult.length) {
  156. return [decl];
  157. }
  158. return [
  159. createDecl(prop + borderWidth, (result[0] || (options.type === 'uvue' ? 'medium' : '0')).trim(), important, raws, source),
  160. createDecl(prop + borderStyle, (result[1] || (options.type === 'uvue' ? 'none' : 'solid')).trim(), important, raws, source),
  161. createDecl(prop + borderColor, (result[2] || '#000000').trim(), important, raws, source),
  162. ];
  163. };
  164. }
  165. !!(process.env.NODE_ENV !== "production") ? Object.freeze({}) : {};
  166. !!(process.env.NODE_ENV !== "production") ? Object.freeze([]) : [];
  167. const extend = Object.assign;
  168. const hasOwnProperty = Object.prototype.hasOwnProperty;
  169. const hasOwn = (val, key) => hasOwnProperty.call(val, key);
  170. const isFunction = (val) => typeof val === "function";
  171. const isString = (val) => typeof val === "string";
  172. const cacheStringFunction = (fn) => {
  173. const cache = /* @__PURE__ */ Object.create(null);
  174. return (str) => {
  175. const hit = cache[str];
  176. return hit || (cache[str] = fn(str));
  177. };
  178. };
  179. const camelizeRE = /-(\w)/g;
  180. const camelize = cacheStringFunction((str) => {
  181. return str.replace(camelizeRE, (_, c) => c ? c.toUpperCase() : "");
  182. });
  183. const hyphenateRE = /\B([A-Z])/g;
  184. const hyphenate = cacheStringFunction(
  185. (str) => str.replace(hyphenateRE, "-$1").toLowerCase()
  186. );
  187. const borderTop = 'border-top-' ;
  188. const borderRight = 'border-right-' ;
  189. const borderBottom = 'border-bottom-' ;
  190. const borderLeft = 'border-left-' ;
  191. const transformBorderColor = (decl) => {
  192. const { prop, value, important, raws, source } = decl;
  193. let property = hyphenate(prop).split('-')[1];
  194. const splitResult = value.replace(/\s*,\s*/g, ',').split(/\s+/);
  195. switch (splitResult.length) {
  196. case 1:
  197. return [decl];
  198. case 2:
  199. splitResult.push(splitResult[0], splitResult[1]);
  200. break;
  201. case 3:
  202. splitResult.push(splitResult[1]);
  203. break;
  204. }
  205. return [
  206. createDecl(borderTop + property, splitResult[0], important, raws, source),
  207. createDecl(borderRight + property, splitResult[1], important, raws, source),
  208. createDecl(borderBottom + property, splitResult[2], important, raws, source),
  209. createDecl(borderLeft + property, splitResult[3], important, raws, source),
  210. ];
  211. };
  212. const borderTopLeftRadius = 'border-top-left-radius'
  213. ;
  214. const borderTopRightRadius = 'border-top-right-radius'
  215. ;
  216. const borderBottomRightRadius = 'border-bottom-right-radius'
  217. ;
  218. const borderBottomLeftRadius = 'border-bottom-left-radius'
  219. ;
  220. const transformBorderRadius = (decl) => {
  221. const { value, important, raws, source } = decl;
  222. const splitResult = value.split(/\s+/);
  223. if (value.includes('/')) {
  224. return [decl];
  225. }
  226. switch (splitResult.length) {
  227. case 1:
  228. return [decl];
  229. case 2:
  230. splitResult.push(splitResult[0], splitResult[1]);
  231. break;
  232. case 3:
  233. splitResult.push(splitResult[1]);
  234. break;
  235. }
  236. return [
  237. createDecl(borderTopLeftRadius, splitResult[0], important, raws, source),
  238. createDecl(borderTopRightRadius, splitResult[1], important, raws, source),
  239. createDecl(borderBottomRightRadius, splitResult[2], important, raws, source),
  240. createDecl(borderBottomLeftRadius, splitResult[3], important, raws, source),
  241. ];
  242. };
  243. const transformBorderStyle = transformBorderColor;
  244. const transformBorderWidth = transformBorderColor;
  245. const flexDirection = 'flex-direction' ;
  246. const flexWrap = 'flex-wrap' ;
  247. const transformFlexFlow = (decl) => {
  248. const { value, important, raws, source } = decl;
  249. const splitResult = value.split(/\s+/);
  250. const result = [
  251. /^(column|column-reverse|row|row-reverse)$/,
  252. /^(nowrap|wrap|wrap-reverse)$/,
  253. ].map((item) => {
  254. const index = splitResult.findIndex((str) => item.test(str));
  255. return index < 0 ? null : splitResult.splice(index, 1)[0];
  256. });
  257. if (splitResult.length) {
  258. return [decl];
  259. }
  260. return [
  261. createDecl(flexDirection, result[0] || 'column', important, raws, source),
  262. createDecl(flexWrap, result[1] || 'nowrap', important, raws, source),
  263. ];
  264. };
  265. const transformFont = (decl) => {
  266. const { value, important, raws, source } = decl;
  267. const result = [];
  268. const font = parseCSSFont__default.default(value);
  269. if (font.system) {
  270. return result;
  271. }
  272. const { style, weight, size, lineHeight, family } = font;
  273. if (style) {
  274. result.push(createDecl('font-style', style, important, raws, source));
  275. }
  276. if (weight) {
  277. result.push(createDecl('font-weight', weight, important, raws, source));
  278. }
  279. if (size) {
  280. result.push(createDecl('font-size', size, important, raws, source));
  281. }
  282. if (lineHeight) {
  283. result.push(createDecl('line-height', lineHeight, important, raws, source));
  284. }
  285. if (family) {
  286. result.push(createDecl('font-family', serialize(family), important, raws, source));
  287. }
  288. return result;
  289. };
  290. function serialize(family) {
  291. return family.map((f) => (f.includes(' ') ? `"${f}"` : f)).join(', ');
  292. }
  293. const top = '-top' ;
  294. const right = '-right' ;
  295. const bottom = '-bottom' ;
  296. const left = '-left' ;
  297. const createTransformBox = (type) => {
  298. return (decl) => {
  299. const { value, important, raws, source } = decl;
  300. const splitResult = value.split(/\s+/);
  301. switch (splitResult.length) {
  302. case 1:
  303. splitResult.push(splitResult[0], splitResult[0], splitResult[0]);
  304. break;
  305. case 2:
  306. splitResult.push(splitResult[0], splitResult[1]);
  307. break;
  308. case 3:
  309. splitResult.push(splitResult[1]);
  310. break;
  311. }
  312. return [
  313. createDecl(type + top, splitResult[0], important, raws, source),
  314. createDecl(type + right, splitResult[1], important, raws, source),
  315. createDecl(type + bottom, splitResult[2], important, raws, source),
  316. createDecl(type + left, splitResult[3], important, raws, source),
  317. ];
  318. };
  319. };
  320. const transformMargin = createTransformBox('margin');
  321. const transformPadding = createTransformBox('padding');
  322. const transitionProperty = 'transition-property'
  323. ;
  324. const transitionDuration = 'transition-duration'
  325. ;
  326. const transitionTimingFunction = 'transition-timing-function'
  327. ;
  328. const transitionDelay = 'transition-delay' ;
  329. const transformTransition = (decl) => {
  330. const CHUNK_REGEXP = /^(\S*)?\s*(\d*\.?\d+(?:ms|s)?)?\s*(\S*)?\s*(\d*\.?\d+(?:ms|s)?)?$/;
  331. const { value, important, raws, source } = decl;
  332. const result = [];
  333. const match = value.match(CHUNK_REGEXP);
  334. if (!match) {
  335. return result;
  336. }
  337. match[1] &&
  338. result.push(createDecl(transitionProperty, match[1], important, raws, source));
  339. match[2] &&
  340. result.push(createDecl(transitionDuration, match[2], important, raws, source));
  341. match[3] &&
  342. result.push(createDecl(transitionTimingFunction, match[3], important, raws, source));
  343. match[4] &&
  344. result.push(createDecl(transitionDelay, match[4], important, raws, source));
  345. return result;
  346. };
  347. function getDeclTransforms(options) {
  348. const transformBorder = createTransformBorder(options);
  349. const styleMap = {
  350. transition: transformTransition,
  351. border: transformBorder,
  352. background: transformBackground,
  353. borderTop: transformBorder,
  354. borderRight: transformBorder,
  355. borderBottom: transformBorder,
  356. borderLeft: transformBorder,
  357. borderStyle: transformBorderStyle,
  358. borderWidth: transformBorderWidth,
  359. borderColor: transformBorderColor,
  360. borderRadius: transformBorderRadius,
  361. // uvue已经支持这些简写属性,不需要展开
  362. // margin,padding继续展开,确保样式的优先级
  363. margin: transformMargin,
  364. padding: transformPadding,
  365. /* eslint-disable no-restricted-syntax */
  366. ...(options.type !== 'uvue'
  367. ? {
  368. flexFlow: transformFlexFlow,
  369. }
  370. : {}),
  371. };
  372. let result = {};
  373. {
  374. styleMap.font = transformFont;
  375. for (const property in styleMap) {
  376. result[hyphenateStyleProperty(property)] = styleMap[property];
  377. }
  378. }
  379. return result;
  380. }
  381. let DeclTransforms;
  382. const expanded = Symbol('expanded');
  383. function expand(options) {
  384. const plugin = {
  385. postcssPlugin: 'nvue:expand',
  386. Declaration(decl) {
  387. if (decl[expanded]) {
  388. return;
  389. }
  390. if (!DeclTransforms) {
  391. DeclTransforms = getDeclTransforms(options);
  392. }
  393. const transform = DeclTransforms[decl.prop];
  394. if (transform) {
  395. const res = transform(decl);
  396. const isSame = res.length === 1 && res[0] === decl;
  397. if (!isSame) {
  398. decl.replaceWith(res);
  399. }
  400. }
  401. decl[expanded] = true;
  402. },
  403. };
  404. return plugin;
  405. }
  406. const normalizeColor = (v) => {
  407. v = (v || '').toString();
  408. if (v.match(/^#[0-9a-fA-F]{6}$/)) {
  409. return { value: v };
  410. }
  411. if (v.match(/^#[0-9a-fA-F]{3}$/)) {
  412. return {
  413. value: '#' + v[1] + v[1] + v[2] + v[2] + v[3] + v[3],
  414. reason: function reason(k, v, result) {
  415. return autofixedReason(v, result);
  416. },
  417. };
  418. }
  419. if (EXTENDED_COLOR_KEYWORDS[v]) {
  420. return {
  421. value: EXTENDED_COLOR_KEYWORDS[v],
  422. reason: function reason(k, v, result) {
  423. return autofixedReason(v, result);
  424. },
  425. };
  426. }
  427. let arrColor, r, g, b, a;
  428. const RGB_REGEXP = /^rgb\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)$/gi;
  429. const RGBA_REGEXP = /^rgba\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d*\.?\d+)\s*\)$/gi;
  430. if ((arrColor = RGB_REGEXP.exec(v))) {
  431. r = parseInt(arrColor[1]);
  432. g = parseInt(arrColor[2]);
  433. b = parseInt(arrColor[3]);
  434. if (r >= 0 && r <= 255 && g >= 0 && g <= 255 && b >= 0 && b <= 255) {
  435. return { value: 'rgb(' + [r, g, b].join(',') + ')' };
  436. }
  437. }
  438. if ((arrColor = RGBA_REGEXP.exec(v))) {
  439. r = parseInt(arrColor[1]);
  440. g = parseInt(arrColor[2]);
  441. b = parseInt(arrColor[3]);
  442. a = parseFloat(arrColor[4]);
  443. if (r >= 0 &&
  444. r <= 255 &&
  445. g >= 0 &&
  446. g <= 255 &&
  447. b >= 0 &&
  448. b <= 255 &&
  449. a >= 0 &&
  450. a <= 1) {
  451. return { value: 'rgba(' + [r, g, b, a].join(',') + ')' };
  452. }
  453. }
  454. if (v === 'transparent') {
  455. return { value: 'rgba(0,0,0,0)' };
  456. }
  457. return {
  458. value: null,
  459. reason(k, v, result) {
  460. return validReason(k, v);
  461. },
  462. };
  463. };
  464. // http://www.w3.org/TR/css3-color/#svg-color
  465. const EXTENDED_COLOR_KEYWORDS = {
  466. aliceblue: '#F0F8FF',
  467. antiquewhite: '#FAEBD7',
  468. aqua: '#00FFFF',
  469. aquamarine: '#7FFFD4',
  470. azure: '#F0FFFF',
  471. beige: '#F5F5DC',
  472. bisque: '#FFE4C4',
  473. black: '#000000',
  474. blanchedalmond: '#FFEBCD',
  475. blue: '#0000FF',
  476. blueviolet: '#8A2BE2',
  477. brown: '#A52A2A',
  478. burlywood: '#DEB887',
  479. cadetblue: '#5F9EA0',
  480. chartreuse: '#7FFF00',
  481. chocolate: '#D2691E',
  482. coral: '#FF7F50',
  483. cornflowerblue: '#6495ED',
  484. cornsilk: '#FFF8DC',
  485. crimson: '#DC143C',
  486. cyan: '#00FFFF',
  487. darkblue: '#00008B',
  488. darkcyan: '#008B8B',
  489. darkgoldenrod: '#B8860B',
  490. darkgray: '#A9A9A9',
  491. darkgreen: '#006400',
  492. darkgrey: '#A9A9A9',
  493. darkkhaki: '#BDB76B',
  494. darkmagenta: '#8B008B',
  495. darkolivegreen: '#556B2F',
  496. darkorange: '#FF8C00',
  497. darkorchid: '#9932CC',
  498. darkred: '#8B0000',
  499. darksalmon: '#E9967A',
  500. darkseagreen: '#8FBC8F',
  501. darkslateblue: '#483D8B',
  502. darkslategray: '#2F4F4F',
  503. darkslategrey: '#2F4F4F',
  504. darkturquoise: '#00CED1',
  505. darkviolet: '#9400D3',
  506. deeppink: '#FF1493',
  507. deepskyblue: '#00BFFF',
  508. dimgray: '#696969',
  509. dimgrey: '#696969',
  510. dodgerblue: '#1E90FF',
  511. firebrick: '#B22222',
  512. floralwhite: '#FFFAF0',
  513. forestgreen: '#228B22',
  514. fuchsia: '#FF00FF',
  515. gainsboro: '#DCDCDC',
  516. ghostwhite: '#F8F8FF',
  517. gold: '#FFD700',
  518. goldenrod: '#DAA520',
  519. gray: '#808080',
  520. green: '#008000',
  521. greenyellow: '#ADFF2F',
  522. grey: '#808080',
  523. honeydew: '#F0FFF0',
  524. hotpink: '#FF69B4',
  525. indianred: '#CD5C5C',
  526. indigo: '#4B0082',
  527. ivory: '#FFFFF0',
  528. khaki: '#F0E68C',
  529. lavender: '#E6E6FA',
  530. lavenderblush: '#FFF0F5',
  531. lawngreen: '#7CFC00',
  532. lemonchiffon: '#FFFACD',
  533. lightblue: '#ADD8E6',
  534. lightcoral: '#F08080',
  535. lightcyan: '#E0FFFF',
  536. lightgoldenrodyellow: '#FAFAD2',
  537. lightgray: '#D3D3D3',
  538. lightgreen: '#90EE90',
  539. lightgrey: '#D3D3D3',
  540. lightpink: '#FFB6C1',
  541. lightsalmon: '#FFA07A',
  542. lightseagreen: '#20B2AA',
  543. lightskyblue: '#87CEFA',
  544. lightslategray: '#778899',
  545. lightslategrey: '#778899',
  546. lightsteelblue: '#B0C4DE',
  547. lightyellow: '#FFFFE0',
  548. lime: '#00FF00',
  549. limegreen: '#32CD32',
  550. linen: '#FAF0E6',
  551. magenta: '#FF00FF',
  552. maroon: '#800000',
  553. mediumaquamarine: '#66CDAA',
  554. mediumblue: '#0000CD',
  555. mediumorchid: '#BA55D3',
  556. mediumpurple: '#9370DB',
  557. mediumseagreen: '#3CB371',
  558. mediumslateblue: '#7B68EE',
  559. mediumspringgreen: '#00FA9A',
  560. mediumturquoise: '#48D1CC',
  561. mediumvioletred: '#C71585',
  562. midnightblue: '#191970',
  563. mintcream: '#F5FFFA',
  564. mistyrose: '#FFE4E1',
  565. moccasin: '#FFE4B5',
  566. navajowhite: '#FFDEAD',
  567. navy: '#000080',
  568. oldlace: '#FDF5E6',
  569. olive: '#808000',
  570. olivedrab: '#6B8E23',
  571. orange: '#FFA500',
  572. orangered: '#FF4500',
  573. orchid: '#DA70D6',
  574. palegoldenrod: '#EEE8AA',
  575. palegreen: '#98FB98',
  576. paleturquoise: '#AFEEEE',
  577. palevioletred: '#DB7093',
  578. papayawhip: '#FFEFD5',
  579. peachpuff: '#FFDAB9',
  580. peru: '#CD853F',
  581. pink: '#FFC0CB',
  582. plum: '#DDA0DD',
  583. powderblue: '#B0E0E6',
  584. purple: '#800080',
  585. red: '#FF0000',
  586. rosybrown: '#BC8F8F',
  587. royalblue: '#4169E1',
  588. saddlebrown: '#8B4513',
  589. salmon: '#FA8072',
  590. sandybrown: '#F4A460',
  591. seagreen: '#2E8B57',
  592. seashell: '#FFF5EE',
  593. sienna: '#A0522D',
  594. silver: '#C0C0C0',
  595. skyblue: '#87CEEB',
  596. slateblue: '#6A5ACD',
  597. slategray: '#708090',
  598. slategrey: '#708090',
  599. snow: '#FFFAFA',
  600. springgreen: '#00FF7F',
  601. steelblue: '#4682B4',
  602. tan: '#D2B48C',
  603. teal: '#008080',
  604. thistle: '#D8BFD8',
  605. tomato: '#FF6347',
  606. turquoise: '#40E0D0',
  607. violet: '#EE82EE',
  608. wheat: '#F5DEB3',
  609. white: '#FFFFFF',
  610. whitesmoke: '#F5F5F5',
  611. yellow: '#FFFF00',
  612. yellowgreen: '#9ACD32',
  613. };
  614. function createEnumNormalize(items) {
  615. return (v) => {
  616. const index = items.indexOf(v);
  617. if (index > 0) {
  618. return { value: v };
  619. }
  620. if (index === 0) {
  621. return {
  622. value: v,
  623. reason: function reason(k, v, result) {
  624. return defaultValueReason(k, v);
  625. },
  626. };
  627. }
  628. return {
  629. value: null,
  630. reason: function reason(k, v, result) {
  631. return supportedEnumReason(k, v, items);
  632. },
  633. };
  634. };
  635. }
  636. function createEnumNormalizeWithPlatform(items) {
  637. return (v, { platform }) => {
  638. const property = items.find((item) => item.name === v);
  639. const supportedEnum = items
  640. .filter((item) => {
  641. const supportedPlatforms = getSupportedPlatforms(item.uniPlatform);
  642. return supportedPlatforms.includes(platform);
  643. })
  644. .map((item) => item.name);
  645. if (property) {
  646. const supportedPlatforms = getSupportedPlatforms(property.uniPlatform);
  647. // TODO 未跨平台支持的属性特殊提示
  648. if (!supportedPlatforms.includes(platform)) {
  649. return {
  650. value: null,
  651. reason: function reason(k, v, result) {
  652. return supportedEnumReason(k, v, supportedEnum);
  653. },
  654. };
  655. }
  656. return { value: v };
  657. }
  658. return {
  659. value: null,
  660. reason: function reason(k, v, result) {
  661. return supportedEnumReason(k, v, supportedEnum);
  662. },
  663. };
  664. };
  665. }
  666. const normalizeFlexWrap = (v) => {
  667. const values = ['nowrap', 'wrap', 'wrap-reverse'];
  668. const index = values.indexOf(v);
  669. if (index > 0) {
  670. return {
  671. value: v,
  672. reason(k, v, result) {
  673. return compatibilityReason(k);
  674. },
  675. };
  676. }
  677. if (index === 0) {
  678. return {
  679. value: v,
  680. reason: function reason(k, v, result) {
  681. return defaultValueReason(k, v);
  682. },
  683. };
  684. }
  685. return {
  686. value: null,
  687. reason(k, v, result) {
  688. return supportedEnumReason(k, v, values);
  689. },
  690. };
  691. };
  692. const normalizeInteger = (v) => {
  693. v = (v || '').toString();
  694. if (v.match(/^[-+]?\d+$/)) {
  695. return { value: parseInt(v, 10) };
  696. }
  697. return {
  698. value: null,
  699. reason: function reason(k, v, result) {
  700. return supportedEnumReason(k, v, ['integer']);
  701. },
  702. };
  703. };
  704. function createNormalizeLength({ removePx, property, } = {}) {
  705. return (v, options) => {
  706. v = (v || '').toString();
  707. // css 变量
  708. if (v.includes('CSS_VAR_')) {
  709. return { value: v };
  710. }
  711. const match = v.match(LENGTH_REGEXP);
  712. if (match) {
  713. var unit = match[1];
  714. const uvue = options.type === 'uvue';
  715. if (uvue) {
  716. if (!unit || (unit === 'px' && removePx)) {
  717. return { value: parseFloat(v) };
  718. }
  719. else if (unit === 'px' ||
  720. unit === 'rpx' ||
  721. // 只有line-height支持em单位
  722. (unit === 'em' && property === 'line-height')) {
  723. return { value: v };
  724. }
  725. }
  726. else {
  727. // nvue
  728. if (!unit || unit === 'px') {
  729. return { value: parseFloat(v) };
  730. }
  731. if (SUPPORT_CSS_UNIT.includes(unit)) {
  732. return { value: v };
  733. }
  734. else {
  735. return {
  736. value: parseFloat(v),
  737. reason(k, v, result) {
  738. return supportedUnitWithAutofixedReason(unit, v, result);
  739. },
  740. };
  741. }
  742. }
  743. }
  744. return {
  745. value: null,
  746. reason(k, v, result) {
  747. return supportedEnumReason(k, v, ['number', 'pixel']);
  748. },
  749. };
  750. };
  751. }
  752. const normalizeLength = createNormalizeLength({
  753. removePx: true,
  754. });
  755. const normalizeLengthWithOptions = createNormalizeLength;
  756. const normalizePercent = (v) => {
  757. v = (v || '').toString();
  758. const match = v.match(LENGTH_REGEXP);
  759. if (match) {
  760. var unit = match[1];
  761. if (unit === '%') {
  762. return { value: v };
  763. }
  764. }
  765. return {
  766. value: null,
  767. reason(k, v, result) {
  768. return supportedEnumReason(k, v, ['percent']);
  769. },
  770. };
  771. };
  772. const normalizeNumber = (v) => {
  773. v = (v || '').toString();
  774. var match = v.match(LENGTH_REGEXP);
  775. if (match && !match[1]) {
  776. return { value: parseFloat(v) };
  777. }
  778. return {
  779. value: null,
  780. reason: function reason(k, v, result) {
  781. return supportedEnumReason(k, v, ['number']);
  782. },
  783. };
  784. };
  785. const normalizeString = (v) => {
  786. v = (v || '').toString().replace(/["']/g, '');
  787. return {
  788. value: v,
  789. };
  790. };
  791. const normalizeShorthandLength = (v, options) => {
  792. v = (v || '').toString();
  793. let value = [];
  794. let reason = [];
  795. const results = v.split(/\s+/).map((v) => normalizeLength(v, options));
  796. for (let i = 0; i < results.length; ++i) {
  797. const res = results[i];
  798. if (res.value === null) {
  799. return res;
  800. }
  801. value.push(res.value);
  802. reason.push(res.reason);
  803. }
  804. return {
  805. value: value.join(' '),
  806. reason: function (k, v, result) {
  807. return reason
  808. .map(function (res) {
  809. if (isFunction(res)) {
  810. return res(k, v, result);
  811. }
  812. })
  813. .join('\n');
  814. },
  815. };
  816. };
  817. const normalizeTransform = (v) => {
  818. return { value: v };
  819. };
  820. const normalizeInterval = (v, options) => {
  821. v = (v || 0).toString();
  822. let match, num;
  823. if ((match = v.match(/^\d*\.?\d+(ms|s)?$/))) {
  824. const uvue = options.type === 'uvue';
  825. if (uvue) {
  826. // uvue 需要单位
  827. if (match[1]) {
  828. return { value: v };
  829. }
  830. }
  831. else {
  832. num = parseFloat(match[0]);
  833. if (!match[1]) {
  834. return { value: parseInt(num + '') };
  835. }
  836. if (match[1] === 's') {
  837. num *= 1000;
  838. }
  839. return {
  840. value: parseInt(num + ''),
  841. reason(k, v, result) {
  842. return autofixedReason(v, result);
  843. },
  844. };
  845. }
  846. }
  847. return {
  848. value: null,
  849. reason(k, v, result) {
  850. return supportedEnumReason(k, v, ['number of seconds', 'milliseconds']);
  851. },
  852. };
  853. };
  854. const normalizeTimingFunction = (v) => {
  855. v = (v || '').toString();
  856. if (v.match(/^linear|ease|ease-in|ease-out|ease-in-out$/)) {
  857. return { value: v };
  858. }
  859. let match;
  860. if ((match = v.match(/^cubic-bezier\(\s*(.*)\s*,\s*(.*)\s*,\s*(.*)\s*,\s*(.*)\s*\)$/))) {
  861. if (match[1].match(NUM_REGEXP) &&
  862. match[2].match(NUM_REGEXP) &&
  863. match[3].match(NUM_REGEXP) &&
  864. match[4].match(NUM_REGEXP)) {
  865. const ret = [
  866. parseFloat(match[1]),
  867. parseFloat(match[2]),
  868. parseFloat(match[3]),
  869. parseFloat(match[4]),
  870. ].join(',');
  871. return { value: 'cubic-bezier(' + ret + ')' };
  872. }
  873. }
  874. return {
  875. value: null,
  876. reason(k, v, result) {
  877. return supportedEnumReason(k, v, [
  878. 'linear',
  879. 'ease',
  880. 'ease-in',
  881. 'ease-out',
  882. 'ease-in-out',
  883. 'cubic-bezier(n,n,n,n)',
  884. ]);
  885. },
  886. };
  887. };
  888. function createCombinedNormalize(normalizes) {
  889. return (v, options) => {
  890. const reasons = [];
  891. for (let i = 0; i < normalizes.length; i++) {
  892. const result = normalizes[i](v, options);
  893. if (result.value !== null) {
  894. return result;
  895. }
  896. if (result.reason) {
  897. reasons.push(result.reason);
  898. }
  899. }
  900. return {
  901. value: null,
  902. reason(k, v, result) {
  903. return normalizeReasons(reasons.map((reason) => reason(k, v, result)), k, v).join('\n');
  904. },
  905. };
  906. };
  907. }
  908. const normalizeGradient = (v) => {
  909. v = (v || '').toString();
  910. if (/^linear-gradient(.+)$/s.test(v)) {
  911. return { value: v };
  912. }
  913. return {
  914. // 枚举里会做reason提示
  915. value: null,
  916. };
  917. };
  918. const normalizeUrl = (v) => {
  919. v = (v || '').toString();
  920. if (/^url(.+)$/s.test(v)) {
  921. return { value: v };
  922. }
  923. return {
  924. value: null,
  925. };
  926. };
  927. function normalizePlatform(normalize, uniPlatform) {
  928. return (v, options, declInfo) => {
  929. const currentPlatform = options.platform;
  930. const supportedPlatforms = getSupportedPlatforms(uniPlatform);
  931. // TODO 未跨平台支持的属性特殊提示
  932. if (!supportedPlatforms.includes(currentPlatform)) {
  933. return {
  934. value: v,
  935. reason(k, v, result) {
  936. return supportedPropertyReason(k);
  937. },
  938. };
  939. }
  940. return normalize(v, options, declInfo);
  941. };
  942. }
  943. function normalizeShorthandProperty(normalize) {
  944. return (v, options) => {
  945. v = (v || '').toString();
  946. const value = [];
  947. const reasons = [];
  948. const results = v.split(/\s+/).map((v) => normalize(v, options));
  949. for (let i = 0; i < results.length; ++i) {
  950. const res = results[i];
  951. if (res.value === null) {
  952. return res;
  953. }
  954. if (res.reason) {
  955. reasons.push(res.reason);
  956. }
  957. value.push(res.value);
  958. }
  959. return {
  960. value: value.length === 1 ? value[0] : value.join(' '),
  961. reason: function (k, v, result) {
  962. return reasons.map((reason) => reason(k, v, result)).join('\n');
  963. },
  964. };
  965. };
  966. }
  967. function normalizeFontFace(normalize) {
  968. return (v, options, declInfo) => {
  969. if (declInfo?.atRule === 'font-face') {
  970. return {
  971. value: null,
  972. reason(k, v, result) {
  973. const items = ['font-family', 'src'];
  974. const name = '@' + declInfo.atRule;
  975. return ('ERROR: property `' +
  976. hyphenateStyleProperty(k) +
  977. '` is not supported for `' +
  978. name +
  979. '` (supported properties are: `' +
  980. items.join('`|`') +
  981. '`)');
  982. },
  983. };
  984. }
  985. return normalize(v, options, declInfo);
  986. };
  987. }
  988. // 只有@font-face下的src属性才支持
  989. const normalizeSrc = (v, options, declInfo) => {
  990. if (declInfo?.atRule === 'font-face') {
  991. return { value: v };
  992. }
  993. return {
  994. value: null,
  995. reason(k, v, result) {
  996. return supportedPropertyReason(k);
  997. },
  998. };
  999. };
  1000. const normalizeFlexFlow = (v) => {
  1001. v = (v || '').toString();
  1002. const values = v.split(/\s+/);
  1003. // flex-flow 需要定义每一个属性值
  1004. if (values.length === 1) {
  1005. return {
  1006. value: v,
  1007. reason(k, v, result) {
  1008. return supportedValueWithTipsReason(k, v, '(both property values must be explicitly defined)');
  1009. },
  1010. };
  1011. }
  1012. return {
  1013. value: v,
  1014. };
  1015. };
  1016. // 从 property.ts 中移动到 map 里,避免循环依赖
  1017. const normalizeProperty = (v, options) => {
  1018. v = (v || '').toString();
  1019. v = v
  1020. .split(/\s*,\s*/)
  1021. .map(camelize)
  1022. .join(',');
  1023. if (v.split(/\s*,\s*/).every((p) => !!getNormalizeMap(options)[p])) {
  1024. return { value: v };
  1025. }
  1026. return {
  1027. value: null,
  1028. reason: function reason(k, v, result) {
  1029. return supportedEnumReason(k, v, ['css property']);
  1030. },
  1031. };
  1032. };
  1033. const normalizeDefault = (v) => {
  1034. return { value: v };
  1035. };
  1036. const NVUE_PROP_NAME_GROUPS = {
  1037. boxModel: {
  1038. display: createEnumNormalize(['flex']),
  1039. width: normalizeLength,
  1040. height: normalizeLength,
  1041. overflow: createEnumNormalize(['hidden']),
  1042. padding: normalizeShorthandLength,
  1043. paddingLeft: normalizeLength,
  1044. paddingRight: normalizeLength,
  1045. paddingTop: normalizeLength,
  1046. paddingBottom: normalizeLength,
  1047. margin: normalizeShorthandLength,
  1048. marginLeft: normalizeLength,
  1049. marginRight: normalizeLength,
  1050. marginTop: normalizeLength,
  1051. marginBottom: normalizeLength,
  1052. borderWidth: normalizeLength,
  1053. borderLeftWidth: normalizeLength,
  1054. borderTopWidth: normalizeLength,
  1055. borderRightWidth: normalizeLength,
  1056. borderBottomWidth: normalizeLength,
  1057. borderColor: normalizeColor,
  1058. borderLeftColor: normalizeColor,
  1059. borderTopColor: normalizeColor,
  1060. borderRightColor: normalizeColor,
  1061. borderBottomColor: normalizeColor,
  1062. borderStyle: createEnumNormalize(['dotted', 'dashed', 'solid']),
  1063. borderTopStyle: createEnumNormalize(['dotted', 'dashed', 'solid']),
  1064. borderRightStyle: createEnumNormalize(['dotted', 'dashed', 'solid']),
  1065. borderBottomStyle: createEnumNormalize(['dotted', 'dashed', 'solid']),
  1066. borderLeftStyle: createEnumNormalize(['dotted', 'dashed', 'solid']),
  1067. borderRadius: normalizeLength,
  1068. borderBottomLeftRadius: normalizeLength,
  1069. borderBottomRightRadius: normalizeLength,
  1070. borderTopLeftRadius: normalizeLength,
  1071. borderTopRightRadius: normalizeLength,
  1072. },
  1073. flexbox: {
  1074. flex: normalizeNumber,
  1075. flexWrap: normalizeFlexWrap,
  1076. flexDirection: createEnumNormalize([
  1077. 'column',
  1078. 'row',
  1079. 'column-reverse',
  1080. 'row-reverse',
  1081. ]),
  1082. justifyContent: createEnumNormalize([
  1083. 'flex-start',
  1084. 'flex-end',
  1085. 'center',
  1086. 'space-between',
  1087. 'space-around',
  1088. ]),
  1089. alignItems: createEnumNormalize([
  1090. 'stretch',
  1091. 'flex-start',
  1092. 'flex-end',
  1093. 'center',
  1094. ]),
  1095. },
  1096. position: {
  1097. position: createEnumNormalize(['relative', 'absolute', 'sticky', 'fixed']),
  1098. top: normalizeLength,
  1099. bottom: normalizeLength,
  1100. left: normalizeLength,
  1101. right: normalizeLength,
  1102. zIndex: normalizeInteger,
  1103. },
  1104. common: {
  1105. opacity: normalizeNumber,
  1106. boxShadow: normalizeDefault,
  1107. backgroundColor: normalizeColor,
  1108. backgroundImage: normalizeDefault,
  1109. },
  1110. text: {
  1111. lines: normalizeInteger,
  1112. color: normalizeColor,
  1113. fontSize: normalizeLength,
  1114. fontStyle: createEnumNormalize(['normal', 'italic']),
  1115. fontFamily: normalizeDefault,
  1116. fontWeight: createEnumNormalize([
  1117. 'normal',
  1118. 'bold',
  1119. '100',
  1120. '200',
  1121. '300',
  1122. '400',
  1123. '500',
  1124. '600',
  1125. '700',
  1126. '800',
  1127. '900',
  1128. ]),
  1129. textDecoration: createEnumNormalize(['none', 'underline', 'line-through']),
  1130. textAlign: createEnumNormalize(['left', 'center', 'right']),
  1131. textOverflow: createEnumNormalize(['clip', 'ellipsis', 'unset', 'fade']),
  1132. lineHeight: normalizeLength,
  1133. },
  1134. transition: {
  1135. transitionProperty: normalizeProperty,
  1136. transitionDuration: normalizeInterval,
  1137. transitionDelay: normalizeInterval,
  1138. transitionTimingFunction: normalizeTimingFunction,
  1139. },
  1140. transform: {
  1141. transform: normalizeTransform,
  1142. transformOrigin: normalizeTransform, // fixed by xxxxxx
  1143. },
  1144. customized: {
  1145. itemSize: normalizeLength,
  1146. itemColor: normalizeColor,
  1147. itemSelectedColor: normalizeColor,
  1148. textColor: normalizeColor,
  1149. timeColor: normalizeColor,
  1150. textHighlightColor: normalizeColor,
  1151. },
  1152. };
  1153. const uvueNormalizeMap = {
  1154. transform: normalizeTransform,
  1155. fontFamily: normalizeString,
  1156. textDecoration: normalizeDefault,
  1157. boxShadow: normalizeDefault,
  1158. transitionProperty: normalizeProperty,
  1159. transitionTimingFunction: normalizeTimingFunction,
  1160. };
  1161. const restrictionMap = {
  1162. ["length" /* Restriction.LENGTH */]: normalizeLength,
  1163. ["percentage" /* Restriction.PERCENTAGE */]: normalizePercent,
  1164. ["number" /* Restriction.NUMBER */]: normalizeNumber,
  1165. ["number(0-1)" /* Restriction.NUMBER_0_1 */]: normalizeNumber,
  1166. ["integer" /* Restriction.INTEGER */]: normalizeInteger,
  1167. ["color" /* Restriction.COLOR */]: normalizeColor,
  1168. ["time" /* Restriction.TIME */]: normalizeInterval,
  1169. ["property" /* Restriction.PROPERTY */]: normalizeProperty,
  1170. ["timing-function" /* Restriction.TIMING_FUNCTION */]: normalizeTimingFunction,
  1171. ["gradient" /* Restriction.GRADIENT */]: normalizeGradient,
  1172. ["url" /* Restriction.URL */]: normalizeUrl,
  1173. };
  1174. // @font-face下不支持的属性
  1175. const invalidFontFaceProperties = ['fontWeight', 'fontStyle', 'fontVariant'];
  1176. function getUVueNormalizeMap() {
  1177. const result = {
  1178. src: normalizeSrc,
  1179. };
  1180. let cssJson;
  1181. try {
  1182. // eslint-disable-next-line no-restricted-globals
  1183. cssJson = require('../lib/css.json');
  1184. }
  1185. catch (e) {
  1186. // 单元测试环境,源码目录
  1187. // eslint-disable-next-line no-restricted-globals
  1188. cssJson = require('../../lib/css.json');
  1189. }
  1190. const { properties } = cssJson;
  1191. for (let i = 0; i < properties.length; i++) {
  1192. const property = properties[i];
  1193. const prop = camelize(property.name);
  1194. let normalize;
  1195. if (uvueNormalizeMap[prop]) {
  1196. normalize = uvueNormalizeMap[prop];
  1197. }
  1198. else {
  1199. const normalizes = getNormalizes(property);
  1200. if (normalizes.length > 1) {
  1201. normalize = createCombinedNormalize(normalizes);
  1202. }
  1203. else if (normalizes.length === 1) {
  1204. normalize = normalizes[0];
  1205. }
  1206. else {
  1207. normalize = normalizeDefault;
  1208. }
  1209. // 简写属性
  1210. if (property.shorthand) {
  1211. normalize = normalizeShorthandProperty(normalize);
  1212. }
  1213. // 处理@font-face下不支持的属性
  1214. if (invalidFontFaceProperties.includes(prop)) {
  1215. normalize = normalizeFontFace(normalize);
  1216. }
  1217. // 校验flexFlow属性值的个数,先临时写死,后续考虑根据css.json动态判断
  1218. if (prop === 'flexFlow') {
  1219. normalize = createCombinedNormalize([normalizeFlexFlow, normalize]);
  1220. }
  1221. }
  1222. result[prop] = normalizePlatform(normalize, property.uniPlatform);
  1223. }
  1224. return result;
  1225. }
  1226. function getNormalizes(property) {
  1227. const normalizes = [];
  1228. const { restrictions } = property;
  1229. restrictions.forEach((restriction) => {
  1230. let normalize = restrictionMap[restriction];
  1231. if (normalize) {
  1232. if (restriction === "length" /* Restriction.LENGTH */) {
  1233. // 如果同时有number和length,例如line-height: 1.5, line-height: 16px,则不能移除px
  1234. normalize = normalizeLengthWithOptions({
  1235. removePx: !restrictions.includes("number" /* Restriction.NUMBER */),
  1236. property: property.name,
  1237. });
  1238. }
  1239. normalizes.push(normalize);
  1240. }
  1241. });
  1242. // enum
  1243. if (property?.values?.length) {
  1244. normalizes.push(createEnumNormalizeWithPlatform(property.values));
  1245. }
  1246. return normalizes;
  1247. }
  1248. let normalizeMap;
  1249. function getNormalizeMap(options) {
  1250. if (normalizeMap) {
  1251. return normalizeMap;
  1252. }
  1253. const uvue = options.type === 'uvue';
  1254. if (uvue) {
  1255. normalizeMap = getUVueNormalizeMap();
  1256. }
  1257. else {
  1258. normalizeMap = Object.keys(NVUE_PROP_NAME_GROUPS).reduce((res, name) => {
  1259. const group = NVUE_PROP_NAME_GROUPS[name];
  1260. Object.keys(group).forEach((prop) => {
  1261. res[prop] = group[prop];
  1262. });
  1263. return res;
  1264. }, {});
  1265. }
  1266. return normalizeMap;
  1267. }
  1268. const normalized = Symbol('normalized');
  1269. function normalize(opts = {}) {
  1270. if (!hasOwn(opts, 'logLevel')) {
  1271. opts.logLevel = 'WARNING';
  1272. }
  1273. const plugin = {
  1274. postcssPlugin: `${opts.type || 'nvue'}:normalize`,
  1275. Declaration: createDeclarationProcessor(opts),
  1276. };
  1277. {
  1278. plugin.Rule = createRuleProcessor(opts);
  1279. }
  1280. return plugin;
  1281. }
  1282. function createRuleProcessor(opts = {}) {
  1283. return (rule, helper) => {
  1284. if (rule[normalized]) {
  1285. return;
  1286. }
  1287. rule.selector = rule.selectors
  1288. .map((selector) => {
  1289. selector = selector
  1290. .replace(/\s*([\+\~\>])\s*/g, '$1')
  1291. .replace(/\s+/, ' ');
  1292. if (COMBINATORS_RE.test(selector)) {
  1293. return selector;
  1294. }
  1295. let type = opts.type || 'nvue';
  1296. rule.warn(helper.result, 'ERROR: Selector `' +
  1297. selector +
  1298. '` is not supported. ' +
  1299. type +
  1300. ' only support classname selector');
  1301. return '';
  1302. })
  1303. .filter(Boolean)
  1304. .join(', ');
  1305. if (!rule.selector) {
  1306. rule.remove();
  1307. }
  1308. rule[normalized] = true;
  1309. };
  1310. }
  1311. function createDeclarationProcessor(options) {
  1312. return (decl, helper) => {
  1313. if (decl[normalized]) {
  1314. return;
  1315. }
  1316. decl.prop = camelize(decl.prop);
  1317. const { value, log } = normalizeDecl(decl, options);
  1318. if (isString(value) || isNumber(value)) {
  1319. decl.value = value;
  1320. }
  1321. if (log && log.reason && helper) {
  1322. const { reason } = log;
  1323. let needLog = false;
  1324. if (options.logLevel === 'NOTE') {
  1325. needLog = true;
  1326. }
  1327. else if (options.logLevel === 'ERROR') {
  1328. if (reason.startsWith('ERROR:')) {
  1329. needLog = true;
  1330. }
  1331. }
  1332. else {
  1333. if (!reason.startsWith('NOTE:')) {
  1334. needLog = true;
  1335. }
  1336. }
  1337. needLog && decl.warn(helper.result, reason);
  1338. }
  1339. if (value === null) {
  1340. decl.remove();
  1341. }
  1342. decl[normalized] = true;
  1343. };
  1344. }
  1345. function normalizeDecl(decl, options) {
  1346. let { prop: name, value } = decl;
  1347. let result, log;
  1348. const normalize = getNormalizeMap(options)[name];
  1349. if (options.type === 'uvue') {
  1350. if (hasCssVar(value)) {
  1351. return {
  1352. value: normalizeCssVar(value),
  1353. log,
  1354. };
  1355. }
  1356. }
  1357. if (isFunction(normalize)) {
  1358. if (!isFunction(value)) {
  1359. result = normalize(value, options, {
  1360. atRule: decl.parent?.type === 'atrule' ? decl.parent.name : '',
  1361. });
  1362. }
  1363. else {
  1364. result = { value: value };
  1365. }
  1366. if (result.reason) {
  1367. log = { reason: result.reason(name, value, result.value) };
  1368. }
  1369. }
  1370. else {
  1371. // ensure number type, no `px`
  1372. if (isString(value)) {
  1373. const match = value.match(LENGTH_REGEXP);
  1374. if (match && (!match[1] || SUPPORT_CSS_UNIT.indexOf(match[1]) === -1)) {
  1375. value = parseFloat(value);
  1376. }
  1377. }
  1378. result = { value: value };
  1379. log = {
  1380. reason: 'WARNING: `' +
  1381. hyphenateStyleProperty(name) +
  1382. '` is not a standard property name (may not be supported)',
  1383. };
  1384. }
  1385. return {
  1386. value: result.value,
  1387. log,
  1388. };
  1389. }
  1390. function hasCssVar(value) {
  1391. return value.includes('var(');
  1392. }
  1393. function normalizeCssVar(value) {
  1394. return value
  1395. .replaceAll(`var(--window-top)`, `CSS_VAR_WINDOW_TOP`)
  1396. .replaceAll(`var(--window-bottom)`, `CSS_VAR_WINDOW_BOTTOM`)
  1397. .replaceAll(`var(--status-bar-height)`, `CSS_VAR_STATUS_BAR_HEIGHT`);
  1398. }
  1399. function objectifier(node, { trim } = { trim: false }) {
  1400. if (!node) {
  1401. return {};
  1402. }
  1403. const context = {
  1404. 'FONT-FACE': [],
  1405. TRANSITION: {},
  1406. };
  1407. const result = transform(node, context);
  1408. if (trim) {
  1409. trimObj(result);
  1410. }
  1411. if (context['FONT-FACE'].length) {
  1412. result['@FONT-FACE'] = context['FONT-FACE'];
  1413. }
  1414. if (Object.keys(context.TRANSITION).length) {
  1415. result['@TRANSITION'] = context.TRANSITION;
  1416. }
  1417. return result;
  1418. }
  1419. function trimObj(obj) {
  1420. Object.keys(obj).forEach((name) => {
  1421. const value = obj[name];
  1422. if (Object.keys(value).length === 1 && hasOwn(value, '')) {
  1423. obj[name] = value[''];
  1424. }
  1425. });
  1426. }
  1427. function transform(node, context) {
  1428. const result = {};
  1429. node.each((child) => {
  1430. if (child.type === 'atrule') {
  1431. const body = transform(child, context);
  1432. const fontFamily = body.fontFamily;
  1433. if (fontFamily && '"\''.indexOf(fontFamily[0]) > -1) {
  1434. body.fontFamily = fontFamily.slice(1, fontFamily.length - 1);
  1435. }
  1436. context['FONT-FACE'].push(body);
  1437. }
  1438. else if (child.type === 'rule') {
  1439. const body = transform(child, context);
  1440. child.selectors.forEach((selector) => {
  1441. transformSelector(selector, body, result, context);
  1442. });
  1443. }
  1444. else if (child.type === 'decl') {
  1445. if (child.important) {
  1446. result['!' + child.prop] = child.value;
  1447. // !important的值域优先级高,故删除非!important的值域
  1448. delete result[child.prop];
  1449. }
  1450. else {
  1451. if (!hasOwn(result, '!' + child.prop)) {
  1452. result[child.prop] = child.value;
  1453. }
  1454. }
  1455. }
  1456. });
  1457. return result;
  1458. }
  1459. function transformSelector(selector, body, result, context) {
  1460. const res = selector.match(COMBINATORS_RE);
  1461. if (!res) {
  1462. return;
  1463. }
  1464. let parentSelector = res[1];
  1465. let curSelector = res[2].substring(1);
  1466. // .a.b => a.b
  1467. const dotIndex = curSelector.indexOf('.');
  1468. if (dotIndex > -1) {
  1469. parentSelector += curSelector.substring(dotIndex);
  1470. curSelector = curSelector.substring(0, dotIndex);
  1471. }
  1472. const pseudoIndex = curSelector.indexOf(':');
  1473. if (pseudoIndex > -1) {
  1474. const pseudoClass = curSelector.slice(pseudoIndex);
  1475. curSelector = curSelector.slice(0, pseudoIndex);
  1476. Object.keys(body).forEach(function (name) {
  1477. body[name + pseudoClass] = body[name];
  1478. delete body[name];
  1479. });
  1480. }
  1481. transition(curSelector, body, context);
  1482. if (!Object.keys(body).length) {
  1483. return;
  1484. }
  1485. result = (result[curSelector] || (result[curSelector] = {}));
  1486. if (result[parentSelector]) {
  1487. // clone
  1488. result[parentSelector] = processImportant(extend({}, result[parentSelector], body));
  1489. }
  1490. else {
  1491. result[parentSelector] = body;
  1492. }
  1493. }
  1494. /**
  1495. * 处理 important 属性,如果某个属性是 important,需要将非 important 的该属性移除掉
  1496. * @param body
  1497. */
  1498. function processImportant(body) {
  1499. Object.keys(body).forEach((name) => {
  1500. if (name.startsWith('!')) {
  1501. delete body[name.substring(1)];
  1502. }
  1503. });
  1504. return body;
  1505. }
  1506. function transition(className, body, { TRANSITION }) {
  1507. Object.keys(body).forEach((prop) => {
  1508. if (prop.indexOf('transition') === 0 && prop !== 'transition') {
  1509. const realProp = prop.replace('transition', '');
  1510. TRANSITION[className] = TRANSITION[className] || {};
  1511. TRANSITION[className][realProp[0].toLowerCase() + realProp.slice(1)] =
  1512. body[prop];
  1513. }
  1514. });
  1515. }
  1516. async function parse(input, options = {}) {
  1517. const { root, messages } = await postcss__default.default([
  1518. expand(options),
  1519. normalize(options),
  1520. ])
  1521. .process(input, {
  1522. from: options.filename || 'foo.css',
  1523. })
  1524. .catch((err) => {
  1525. return {
  1526. root: null,
  1527. messages: [
  1528. {
  1529. type: 'error',
  1530. text: err.message,
  1531. },
  1532. ],
  1533. };
  1534. });
  1535. if (options.noCode === true) {
  1536. return { code: '', messages };
  1537. }
  1538. const obj = root ? objectifier(root, { trim: !!options.trim }) : {};
  1539. if (options.map || options.mapOf) {
  1540. return {
  1541. code: mapToInitStringChunk(objToMap(obj), options.ts, true, options.mapOf, options.chunk),
  1542. messages,
  1543. };
  1544. }
  1545. return { code: JSON.stringify(obj), messages };
  1546. }
  1547. function mapToInitStringChunk(map, ts = false, isRoot = false, mapOf = '', chunk = 0) {
  1548. if (!chunk) {
  1549. return mapToInitString(map, ts, isRoot, mapOf);
  1550. }
  1551. const chunks = [];
  1552. let chunkMap = new Map();
  1553. let chunkCount = 0;
  1554. for (const [key, value] of map) {
  1555. if (chunkCount === chunk) {
  1556. chunks.push(mapToInitString(chunkMap, ts, isRoot, mapOf));
  1557. chunkMap = new Map();
  1558. chunkCount = 0;
  1559. }
  1560. chunkMap.set(key, value);
  1561. chunkCount++;
  1562. }
  1563. if (chunkCount) {
  1564. chunks.push(mapToInitString(chunkMap, ts, isRoot, mapOf));
  1565. }
  1566. return `[${chunks.join(',')}]`;
  1567. }
  1568. function mapToInitString(map, ts = false, isRoot = false, mapOf = '') {
  1569. const entries = [];
  1570. for (let [key, value] of map) {
  1571. if (value instanceof Map) {
  1572. // trim
  1573. if (isRoot && !(value.values().next().value instanceof Map)) {
  1574. entries.push(`["${key}", padStyleMapOf(${mapToInitString(value, ts, false, mapOf)})]`);
  1575. }
  1576. else {
  1577. entries.push(`["${key}", ${mapToInitString(value, ts, false, mapOf)}]`);
  1578. }
  1579. }
  1580. else {
  1581. entries.push(`["${key}", ${isString(value) && isExpr(value) ? value : JSON.stringify(value)}]`);
  1582. }
  1583. }
  1584. if (mapOf) {
  1585. return `${mapOf}([${entries.join(', ')}])`;
  1586. }
  1587. return `new Map${ts
  1588. ? isRoot
  1589. ? '<string, Map<string, Map<string, any>>>'
  1590. : '<string, any>'
  1591. : ''}([${entries.join(', ')}])`;
  1592. }
  1593. function objToMap(obj) {
  1594. const map = new Map();
  1595. for (const key in obj) {
  1596. const value = obj[key];
  1597. if (typeof value === 'object') {
  1598. map.set(key, objToMap(value));
  1599. }
  1600. else {
  1601. map.set(key, value);
  1602. }
  1603. }
  1604. return map;
  1605. }
  1606. function isExpr(value) {
  1607. const v = value.slice(0, 5);
  1608. return /* CSS_VAR_ */ v === 'CSS_V' || v === 'calc(';
  1609. }
  1610. exports.expand = expand;
  1611. exports.normalize = normalize;
  1612. exports.objectifier = objectifier;
  1613. exports.parse = parse;