UNPKG

6.32 kBJavaScriptView Raw
1"use strict";
2Object.defineProperty(exports, "__esModule", {
3 value: true
4});
5function _export(target, all) {
6 for(var name in all)Object.defineProperty(target, name, {
7 enumerable: true,
8 get: all[name]
9 });
10}
11_export(exports, {
12 normalize: ()=>normalize,
13 url: ()=>url,
14 number: ()=>number,
15 percentage: ()=>percentage,
16 length: ()=>length,
17 lineWidth: ()=>lineWidth,
18 shadow: ()=>shadow,
19 color: ()=>color,
20 image: ()=>image,
21 gradient: ()=>gradient,
22 position: ()=>position,
23 familyName: ()=>familyName,
24 genericName: ()=>genericName,
25 absoluteSize: ()=>absoluteSize,
26 relativeSize: ()=>relativeSize
27});
28const _color = require("./color");
29const _parseBoxShadowValue = require("./parseBoxShadowValue");
30const _splitAtTopLevelOnly = require("./splitAtTopLevelOnly");
31let cssFunctions = [
32 "min",
33 "max",
34 "clamp",
35 "calc"
36];
37// Ref: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Types
38function isCSSFunction(value) {
39 return cssFunctions.some((fn)=>new RegExp(`^${fn}\\(.*\\)`).test(value));
40}
41function normalize(value, isRoot = true) {
42 // Keep raw strings if it starts with `url(`
43 if (value.includes("url(")) {
44 return value.split(/(url\(.*?\))/g).filter(Boolean).map((part)=>{
45 if (/^url\(.*?\)$/.test(part)) {
46 return part;
47 }
48 return normalize(part, false);
49 }).join("");
50 }
51 // Convert `_` to ` `, except for escaped underscores `\_`
52 value = value.replace(/([^\\])_+/g, (fullMatch, characterBefore)=>characterBefore + " ".repeat(fullMatch.length - 1)).replace(/^_/g, " ").replace(/\\_/g, "_");
53 // Remove leftover whitespace
54 if (isRoot) {
55 value = value.trim();
56 }
57 // Add spaces around operators inside math functions like calc() that do not follow an operator
58 // or '('.
59 value = value.replace(/(calc|min|max|clamp)\(.+\)/g, (match)=>{
60 return match.replace(/(-?\d*\.?\d(?!\b-.+[,)](?![^+\-/*])\D)(?:%|[a-z]+)?|\))([+\-/*])/g, "$1 $2 ");
61 });
62 return value;
63}
64function url(value) {
65 return value.startsWith("url(");
66}
67function number(value) {
68 return !isNaN(Number(value)) || isCSSFunction(value);
69}
70function percentage(value) {
71 return value.endsWith("%") && number(value.slice(0, -1)) || isCSSFunction(value);
72}
73let lengthUnits = [
74 "cm",
75 "mm",
76 "Q",
77 "in",
78 "pc",
79 "pt",
80 "px",
81 "em",
82 "ex",
83 "ch",
84 "rem",
85 "lh",
86 "vw",
87 "vh",
88 "vmin",
89 "vmax"
90];
91let lengthUnitsPattern = `(?:${lengthUnits.join("|")})`;
92function length(value) {
93 return value === "0" || new RegExp(`^[+-]?[0-9]*\.?[0-9]+(?:[eE][+-]?[0-9]+)?${lengthUnitsPattern}$`).test(value) || isCSSFunction(value);
94}
95let lineWidths = new Set([
96 "thin",
97 "medium",
98 "thick"
99]);
100function lineWidth(value) {
101 return lineWidths.has(value);
102}
103function shadow(value) {
104 let parsedShadows = (0, _parseBoxShadowValue.parseBoxShadowValue)(normalize(value));
105 for (let parsedShadow of parsedShadows){
106 if (!parsedShadow.valid) {
107 return false;
108 }
109 }
110 return true;
111}
112function color(value) {
113 let colors = 0;
114 let result = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(value, "_").every((part)=>{
115 part = normalize(part);
116 if (part.startsWith("var(")) return true;
117 if ((0, _color.parseColor)(part, {
118 loose: true
119 }) !== null) return colors++, true;
120 return false;
121 });
122 if (!result) return false;
123 return colors > 0;
124}
125function image(value) {
126 let images = 0;
127 let result = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(value, ",").every((part)=>{
128 part = normalize(part);
129 if (part.startsWith("var(")) return true;
130 if (url(part) || gradient(part) || [
131 "element(",
132 "image(",
133 "cross-fade(",
134 "image-set("
135 ].some((fn)=>part.startsWith(fn))) {
136 images++;
137 return true;
138 }
139 return false;
140 });
141 if (!result) return false;
142 return images > 0;
143}
144let gradientTypes = new Set([
145 "linear-gradient",
146 "radial-gradient",
147 "repeating-linear-gradient",
148 "repeating-radial-gradient",
149 "conic-gradient"
150]);
151function gradient(value) {
152 value = normalize(value);
153 for (let type of gradientTypes){
154 if (value.startsWith(`${type}(`)) {
155 return true;
156 }
157 }
158 return false;
159}
160let validPositions = new Set([
161 "center",
162 "top",
163 "right",
164 "bottom",
165 "left"
166]);
167function position(value) {
168 let positions = 0;
169 let result = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(value, "_").every((part)=>{
170 part = normalize(part);
171 if (part.startsWith("var(")) return true;
172 if (validPositions.has(part) || length(part) || percentage(part)) {
173 positions++;
174 return true;
175 }
176 return false;
177 });
178 if (!result) return false;
179 return positions > 0;
180}
181function familyName(value) {
182 let fonts = 0;
183 let result = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(value, ",").every((part)=>{
184 part = normalize(part);
185 if (part.startsWith("var(")) return true;
186 // If it contains spaces, then it should be quoted
187 if (part.includes(" ")) {
188 if (!/(['"])([^"']+)\1/g.test(part)) {
189 return false;
190 }
191 }
192 // If it starts with a number, it's invalid
193 if (/^\d/g.test(part)) {
194 return false;
195 }
196 fonts++;
197 return true;
198 });
199 if (!result) return false;
200 return fonts > 0;
201}
202let genericNames = new Set([
203 "serif",
204 "sans-serif",
205 "monospace",
206 "cursive",
207 "fantasy",
208 "system-ui",
209 "ui-serif",
210 "ui-sans-serif",
211 "ui-monospace",
212 "ui-rounded",
213 "math",
214 "emoji",
215 "fangsong"
216]);
217function genericName(value) {
218 return genericNames.has(value);
219}
220let absoluteSizes = new Set([
221 "xx-small",
222 "x-small",
223 "small",
224 "medium",
225 "large",
226 "x-large",
227 "x-large",
228 "xxx-large"
229]);
230function absoluteSize(value) {
231 return absoluteSizes.has(value);
232}
233let relativeSizes = new Set([
234 "larger",
235 "smaller"
236]);
237function relativeSize(value) {
238 return relativeSizes.has(value);
239}