aboutsummaryrefslogtreecommitdiffstats
path: root/vanilla/node_modules/cssstyle/lib/normalize.js
diff options
context:
space:
mode:
Diffstat (limited to 'vanilla/node_modules/cssstyle/lib/normalize.js')
-rw-r--r--vanilla/node_modules/cssstyle/lib/normalize.js1574
1 files changed, 1574 insertions, 0 deletions
diff --git a/vanilla/node_modules/cssstyle/lib/normalize.js b/vanilla/node_modules/cssstyle/lib/normalize.js
new file mode 100644
index 0000000..bc39b70
--- /dev/null
+++ b/vanilla/node_modules/cssstyle/lib/normalize.js
@@ -0,0 +1,1574 @@
+"use strict";
+
+const propertyDefinitions = require("./generated/propertyDefinitions");
+const { hasVarFunc, isGlobalKeyword, isValidPropertyValue, splitValue } = require("./parsers");
+const background = require("./properties/background");
+const backgroundColor = require("./properties/backgroundColor");
+const backgroundSize = require("./properties/backgroundSize");
+const border = require("./properties/border");
+const borderWidth = require("./properties/borderWidth");
+const borderStyle = require("./properties/borderStyle");
+const borderColor = require("./properties/borderColor");
+const borderTop = require("./properties/borderTop");
+const borderRight = require("./properties/borderRight");
+const borderBottom = require("./properties/borderBottom");
+const borderLeft = require("./properties/borderLeft");
+const flex = require("./properties/flex");
+const font = require("./properties/font");
+const margin = require("./properties/margin");
+const padding = require("./properties/padding");
+
+/* constants */
+const BORDER_IMAGE = "border-image";
+const TOP = "top";
+const RIGHT = "right";
+const BOTTOM = "bottom";
+const LEFT = "left";
+const WIDTH = "width";
+const STYLE = "style";
+const COLOR = "color";
+const NONE = "none";
+const TRBL_INDICES = {
+ [TOP]: 0,
+ [RIGHT]: 1,
+ [BOTTOM]: 2,
+ [LEFT]: 3
+};
+
+/* shorthands */
+const shorthandProperties = new Map([
+ [background.property, background],
+ [
+ border.property,
+ {
+ definition: border.definition,
+ parse: border.parse,
+ shorthandFor: new Map([
+ ...border.shorthandFor,
+ ...border.positionShorthandFor,
+ [BORDER_IMAGE, null]
+ ])
+ }
+ ],
+ [borderWidth.property, borderWidth],
+ [borderStyle.property, borderStyle],
+ [borderColor.property, borderColor],
+ [borderTop.property, borderTop],
+ [borderRight.property, borderRight],
+ [borderBottom.property, borderBottom],
+ [borderLeft.property, borderLeft],
+ ["flex", flex],
+ ["font", font],
+ ["margin", margin],
+ ["padding", padding]
+]);
+
+/* borders */
+const borderProperties = new Set([
+ border.property,
+ BORDER_IMAGE,
+ ...border.shorthandFor.keys(),
+ ...border.positionShorthandFor.keys(),
+ ...borderTop.shorthandFor.keys(),
+ ...borderRight.shorthandFor.keys(),
+ ...borderBottom.shorthandFor.keys(),
+ ...borderLeft.shorthandFor.keys()
+]);
+const borderPositions = new Set([TOP, RIGHT, BOTTOM, LEFT]);
+const borderLines = new Set([WIDTH, STYLE, COLOR]);
+
+/**
+ * Ensures consistent object shape.
+ *
+ * @param {string} property - The property name.
+ * @param {string} [value=""] - The property value.
+ * @param {string} [priority=""] - The priority.
+ * @returns {Object} The property item object.
+ */
+const createPropertyItem = (property, value = "", priority = "") => ({
+ property,
+ value,
+ priority
+});
+
+/**
+ * Retrieves a property item from the map or creates a default one if it doesn't exist.
+ *
+ * @param {string} property - The name of the property.
+ * @param {Map} properties - The map containing all properties.
+ * @returns {Object} The property item containing name, value, and priority.
+ */
+const getPropertyItem = (property, properties) => {
+ const propertyItem = properties.get(property) ?? createPropertyItem(property);
+ return propertyItem;
+};
+
+/**
+ * Calculates the value for a specific position (top, right, bottom, left)
+ * based on the array of values provided for a shorthand property.
+ *
+ * @param {string[]} positionValues - The values extracted from the shorthand property.
+ * @param {string} position - The specific position (top, right, bottom, left) to retrieve.
+ * @returns {string} The calculated value for the position.
+ */
+const getPositionValue = (positionValues, position) => {
+ const [val1, val2, val3, val4] = positionValues;
+ const index = TRBL_INDICES[position] ?? -1;
+ // If a specific position (top, right, bottom, left) is requested.
+ if (index !== -1) {
+ switch (positionValues.length) {
+ case 2: {
+ // Index 0 (Top) & 2 (Bottom) -> val1
+ // Index 1 (Right) & 3 (Left) -> val2
+ return index % 2 === 0 ? val1 : val2;
+ }
+ case 3: {
+ // Index 0 (Top) -> val1
+ // Index 1 (Right) & 3 (Left) -> val2
+ // Index 2 (Bottom) -> val3
+ if (index === 2) {
+ return val3;
+ }
+ return index % 2 === 0 ? val1 : val2;
+ }
+ case 4: {
+ return positionValues[index];
+ }
+ case 1:
+ default: {
+ return val1;
+ }
+ }
+ }
+ // Fallback logic for when no specific position is requested.
+ switch (positionValues.length) {
+ case 2: {
+ if (val1 === val2) {
+ return val1;
+ }
+ return `${val1} ${val2}`;
+ }
+ case 3: {
+ if (val1 === val3) {
+ if (val1 === val2) {
+ return val1;
+ }
+ return `${val1} ${val2}`;
+ }
+ return `${val1} ${val2} ${val3}`;
+ }
+ case 4: {
+ if (val2 === val4) {
+ if (val1 === val3) {
+ if (val1 === val2) {
+ return val1;
+ }
+ return `${val1} ${val2}`;
+ }
+ return `${val1} ${val2} ${val3}`;
+ }
+ return `${val1} ${val2} ${val3} ${val4}`;
+ }
+ case 1:
+ default: {
+ return val1;
+ }
+ }
+};
+
+/**
+ * Replaces the background shorthand property based on individual longhand values.
+ *
+ * @param {string} property - The specific background longhand property being updated.
+ * @param {Map} properties - The map of all properties.
+ * @param {Object} opt - Parsing options including global object and configurations.
+ * @returns {string} The constructed background shorthand string.
+ */
+const replaceBackgroundShorthand = (property, properties, opt) => {
+ const { value: propertyValue } = properties.get(property);
+ const parsedValue = background.shorthandFor.get(property).parse(propertyValue, opt);
+ const values = splitValue(parsedValue, {
+ delimiter: ","
+ });
+ const { value: shorthandValue } = properties.get(background.property);
+ const bgValues = background.parse(shorthandValue, opt);
+ const bgLength = bgValues.length;
+ if (property === backgroundColor.property) {
+ bgValues[bgLength - 1][property] = parsedValue[0];
+ } else {
+ for (let i = 0; i < bgLength; i++) {
+ bgValues[i][property] = values[i];
+ }
+ }
+ const backgrounds = [];
+ for (const bgValue of bgValues) {
+ const bg = [];
+ for (const [longhand, value] of Object.entries(bgValue)) {
+ if (!value || value === background.initialValues.get(longhand)) {
+ continue;
+ }
+ if (longhand === backgroundSize.property) {
+ bg.push(`/ ${value}`);
+ } else {
+ bg.push(value);
+ }
+ }
+ backgrounds.push(bg.join(" "));
+ }
+ return backgrounds.join(", ");
+};
+
+/**
+ * Checks if a property value matches the value within a border shorthand.
+ *
+ * @param {string} property - The property to check.
+ * @param {string} value - The value to compare.
+ * @param {string} shorthandValue - The shorthand string to parse and compare against.
+ * @param {Object} [opt={}] - Parsing options.
+ * @returns {boolean} True if the value matches the shorthand's value.
+ */
+const matchesBorderShorthandValue = (property, value, shorthandValue, opt = {}) => {
+ const { globalObject, options } = opt;
+ const obj = border.parse(shorthandValue, {
+ globalObject,
+ options
+ });
+ if (Object.hasOwn(obj, property)) {
+ return value === obj[property];
+ }
+ return value === border.initialValues.get(property);
+};
+
+/**
+ * Replaces or updates a value within a border shorthand string.
+ *
+ * @param {string} value - The new value to insert.
+ * @param {string} shorthandValue - The existing shorthand string.
+ * @param {Object} [opt={}] - Parsing options.
+ * @returns {string} The updated border shorthand string.
+ */
+const replaceBorderShorthandValue = (value, shorthandValue, opt = {}) => {
+ const { globalObject, options } = opt;
+ const borderFirstInitialKey = border.initialValues.keys().next().value;
+ const borderFirstInitialValue = border.initialValues.get(borderFirstInitialKey);
+ const parseOpt = {
+ globalObject,
+ options
+ };
+ const valueObj = border.parse(value, parseOpt);
+ const shorthandObj = shorthandValue
+ ? border.parse(shorthandValue, parseOpt)
+ : {
+ [borderFirstInitialKey]: borderFirstInitialValue
+ };
+ const keys = border.shorthandFor.keys();
+ for (const key of keys) {
+ const initialValue = border.initialValues.get(key);
+ let parsedValue = initialValue;
+ if (Object.hasOwn(valueObj, key)) {
+ parsedValue = valueObj[key];
+ }
+ if (parsedValue === initialValue) {
+ if (key === borderFirstInitialKey) {
+ if (!Object.hasOwn(shorthandObj, key)) {
+ shorthandObj[key] = parsedValue;
+ }
+ } else {
+ delete shorthandObj[key];
+ }
+ } else {
+ shorthandObj[key] = parsedValue;
+ if (
+ shorthandObj[borderFirstInitialKey] &&
+ shorthandObj[borderFirstInitialKey] === borderFirstInitialValue
+ ) {
+ delete shorthandObj[borderFirstInitialKey];
+ }
+ }
+ }
+ return Object.values(shorthandObj).join(" ");
+};
+
+/**
+ * Replaces a value at a specific position (top, right, bottom, left) within a position shorthand.
+ *
+ * @param {string} value - The new value to set.
+ * @param {string[]} positionValues - The array of existing position values.
+ * @param {string} position - The position to update.
+ * @returns {string} The updated shorthand string.
+ */
+const replacePositionValue = (value, positionValues, position) => {
+ const index = TRBL_INDICES[position] ?? -1;
+ let currentValues = positionValues;
+ if (index !== -1) {
+ // Loop for reducing array length (instead of recursion)
+ while (true) {
+ const [val1, val2, val3, val4] = currentValues;
+ switch (currentValues.length) {
+ case 2: {
+ if (val1 === val2) {
+ currentValues = [val1];
+ continue;
+ }
+ switch (index) {
+ // Top
+ case 0: {
+ if (val1 === value) {
+ return currentValues.join(" ");
+ }
+ return `${value} ${val2} ${val1}`;
+ }
+ // Right
+ case 1: {
+ if (val2 === value) {
+ return currentValues.join(" ");
+ }
+ return `${val1} ${value} ${val1} ${val2}`;
+ }
+ // Bottom
+ case 2: {
+ if (val1 === value) {
+ return currentValues.join(" ");
+ }
+ return `${val1} ${val2} ${value}`;
+ }
+ // Left
+ case 3:
+ default: {
+ if (val2 === value) {
+ return currentValues.join(" ");
+ }
+ return `${val1} ${val2} ${val1} ${value}`;
+ }
+ }
+ }
+ case 3: {
+ if (val1 === val3) {
+ currentValues = [val1, val2];
+ continue;
+ }
+ switch (index) {
+ // Top
+ case 0: {
+ if (val1 === value) {
+ return currentValues.join(" ");
+ } else if (val3 === value) {
+ return `${value} ${val2}`;
+ }
+ return `${value} ${val2} ${val3}`;
+ }
+ // Right
+ case 1: {
+ if (val2 === value) {
+ return currentValues.join(" ");
+ }
+ return `${val1} ${value} ${val3} ${val2}`;
+ }
+ // Bottom
+ case 2: {
+ if (val3 === value) {
+ return currentValues.join(" ");
+ } else if (val1 === value) {
+ return `${val1} ${val2}`;
+ }
+ return `${val1} ${val2} ${value}`;
+ }
+ // Left
+ case 3:
+ default: {
+ if (val2 === value) {
+ return currentValues.join(" ");
+ }
+ return `${val1} ${val2} ${val3} ${value}`;
+ }
+ }
+ }
+ case 4: {
+ if (val2 === val4) {
+ currentValues = [val1, val2, val3];
+ continue;
+ }
+ switch (index) {
+ // Top
+ case 0: {
+ if (val1 === value) {
+ return currentValues.join(" ");
+ }
+ return `${value} ${val2} ${val3} ${val4}`;
+ }
+ // Right
+ case 1: {
+ if (val2 === value) {
+ return currentValues.join(" ");
+ } else if (val4 === value) {
+ return `${val1} ${value} ${val3}`;
+ }
+ return `${val1} ${value} ${val3} ${val4}`;
+ }
+ // Bottom
+ case 2: {
+ if (val3 === value) {
+ return currentValues.join(" ");
+ }
+ return `${val1} ${val2} ${value} ${val4}`;
+ }
+ // Left
+ case 3:
+ default: {
+ if (val4 === value) {
+ return currentValues.join(" ");
+ } else if (val2 === value) {
+ return `${val1} ${val2} ${val3}`;
+ }
+ return `${val1} ${val2} ${val3} ${value}`;
+ }
+ }
+ }
+ case 1:
+ default: {
+ const [val] = currentValues;
+ if (val === value) {
+ return currentValues.join(" ");
+ }
+ switch (index) {
+ // Top
+ case 0: {
+ return `${value} ${val} ${val}`;
+ }
+ // Right
+ case 1: {
+ return `${val} ${value} ${val} ${val}`;
+ }
+ // Bottom
+ case 2: {
+ return `${val} ${val} ${value}`;
+ }
+ // Left
+ case 3:
+ default: {
+ return `${val} ${val} ${val} ${value}`;
+ }
+ }
+ }
+ }
+ }
+ }
+ // Fallback logic for when no specific position is requested.
+ const [val1, val2, val3, val4] = currentValues;
+ switch (currentValues.length) {
+ case 2: {
+ if (val1 === val2) {
+ return val1;
+ }
+ return `${val1} ${val2}`;
+ }
+ case 3: {
+ if (val1 === val3) {
+ if (val1 === val2) {
+ return val1;
+ }
+ return `${val1} ${val2}`;
+ }
+ return `${val1} ${val2} ${val3}`;
+ }
+ case 4: {
+ if (val2 === val4) {
+ if (val1 === val3) {
+ if (val1 === val2) {
+ return val1;
+ }
+ return `${val1} ${val2}`;
+ }
+ return `${val1} ${val2} ${val3}`;
+ }
+ return `${val1} ${val2} ${val3} ${val4}`;
+ }
+ case 1:
+ default: {
+ return val1;
+ }
+ }
+};
+
+/**
+ * Handles border property preparation when the value is a string.
+ *
+ * @param {Object} params - The parameters object.
+ * @param {string} params.property - The property name.
+ * @param {string} params.value - The property value.
+ * @param {string} params.priority - The property priority.
+ * @param {Map} params.properties - The map of properties.
+ * @param {Object} params.parts - The split property name parts.
+ * @param {Object} params.opt - Parsing options.
+ * @param {Map} params.borderItems - The map to store processed border items.
+ */
+const prepareBorderStringValue = ({
+ property,
+ value,
+ priority,
+ properties,
+ parts,
+ opt,
+ borderItems
+}) => {
+ const { prop1, prop2, prop3 } = parts;
+ const { globalObject, options } = opt;
+ const parseOpt = {
+ globalObject,
+ options
+ };
+ const shorthandItem = getPropertyItem(border.property, properties);
+ const imageItem = getPropertyItem(BORDER_IMAGE, properties);
+ // Handle longhand properties.
+ if (prop3) {
+ const lineProperty = `${prop1}-${prop3}`;
+ const lineItem = getPropertyItem(lineProperty, properties);
+ const positionProperty = `${prop1}-${prop2}`;
+ const positionItem = getPropertyItem(positionProperty, properties);
+ const longhandProperty = `${prop1}-${prop2}-${prop3}`;
+ const longhandItem = getPropertyItem(longhandProperty, properties);
+ longhandItem.value = value;
+ longhandItem.priority = priority;
+ const propertyValue = hasVarFunc(value) ? "" : value;
+ if (propertyValue === "") {
+ shorthandItem.value = "";
+ lineItem.value = "";
+ positionItem.value = "";
+ } else if (isGlobalKeyword(propertyValue)) {
+ if (shorthandItem.value !== propertyValue) {
+ shorthandItem.value = "";
+ }
+ if (lineItem.value !== propertyValue) {
+ lineItem.value = "";
+ }
+ if (positionItem.value !== propertyValue) {
+ positionItem.value = "";
+ }
+ } else {
+ if (
+ shorthandItem.value &&
+ !matchesBorderShorthandValue(lineProperty, propertyValue, shorthandItem.value, parseOpt)
+ ) {
+ shorthandItem.value = "";
+ }
+ if (lineItem.value) {
+ lineItem.value = replacePositionValue(propertyValue, splitValue(lineItem.value), prop2);
+ }
+ if (
+ positionItem.value &&
+ !matchesBorderShorthandValue(lineProperty, propertyValue, positionItem.value, parseOpt)
+ ) {
+ positionItem.value = "";
+ }
+ }
+ borderItems.set(border.property, shorthandItem);
+ borderItems.set(BORDER_IMAGE, imageItem);
+ borderItems.set(lineProperty, lineItem);
+ borderItems.set(positionProperty, positionItem);
+ borderItems.set(longhandProperty, longhandItem);
+ // Handle side-specific border shorthands (border-top, border-right, border-bottom, border-left).
+ } else if (prop2 && borderPositions.has(prop2)) {
+ const lineWidthProperty = `${prop1}-width`;
+ const lineWidthItem = getPropertyItem(lineWidthProperty, properties);
+ const lineStyleProperty = `${prop1}-style`;
+ const lineStyleItem = getPropertyItem(lineStyleProperty, properties);
+ const lineColorProperty = `${prop1}-color`;
+ const lineColorItem = getPropertyItem(lineColorProperty, properties);
+ const positionProperty = `${prop1}-${prop2}`;
+ const positionItem = getPropertyItem(positionProperty, properties);
+ positionItem.value = value;
+ positionItem.priority = priority;
+ const propertyValue = hasVarFunc(value) ? "" : value;
+ if (propertyValue === "") {
+ shorthandItem.value = "";
+ lineWidthItem.value = "";
+ lineStyleItem.value = "";
+ lineColorItem.value = "";
+ } else if (isGlobalKeyword(propertyValue)) {
+ if (shorthandItem.value !== propertyValue) {
+ shorthandItem.value = "";
+ }
+ if (lineWidthItem.value !== propertyValue) {
+ lineWidthItem.value = "";
+ }
+ if (lineStyleItem.value !== propertyValue) {
+ lineStyleItem.value = "";
+ }
+ if (lineColorItem.value !== propertyValue) {
+ lineColorItem.value = "";
+ }
+ } else {
+ if (
+ shorthandItem.value &&
+ !matchesBorderShorthandValue(property, propertyValue, shorthandItem.value, parseOpt)
+ ) {
+ shorthandItem.value = "";
+ }
+ if (
+ lineWidthItem.value &&
+ isValidPropertyValue(lineWidthProperty, propertyValue, globalObject)
+ ) {
+ lineWidthItem.value = propertyValue;
+ }
+ if (
+ lineStyleItem.value &&
+ isValidPropertyValue(lineStyleProperty, propertyValue, globalObject)
+ ) {
+ lineStyleItem.value = propertyValue;
+ }
+ if (
+ lineColorItem.value &&
+ isValidPropertyValue(lineColorProperty, propertyValue, globalObject)
+ ) {
+ lineColorItem.value = propertyValue;
+ }
+ }
+ for (const line of borderLines) {
+ const longhandProperty = `${prop1}-${prop2}-${line}`;
+ const longhandItem = getPropertyItem(longhandProperty, properties);
+ longhandItem.value = propertyValue;
+ longhandItem.priority = priority;
+ borderItems.set(longhandProperty, longhandItem);
+ }
+ borderItems.set(border.property, shorthandItem);
+ borderItems.set(BORDER_IMAGE, imageItem);
+ borderItems.set(lineWidthProperty, lineWidthItem);
+ borderItems.set(lineStyleProperty, lineStyleItem);
+ borderItems.set(lineColorProperty, lineColorItem);
+ borderItems.set(positionProperty, positionItem);
+ // Handle property-specific border shorthands (border-width, border-style, border-color).
+ } else if (prop2 && borderLines.has(prop2)) {
+ const lineProperty = `${prop1}-${prop2}`;
+ const lineItem = getPropertyItem(lineProperty, properties);
+ lineItem.value = value;
+ lineItem.priority = priority;
+ const propertyValue = hasVarFunc(value) ? "" : value;
+ if (propertyValue === "") {
+ shorthandItem.value = "";
+ } else if (isGlobalKeyword(propertyValue)) {
+ if (shorthandItem.value !== propertyValue) {
+ shorthandItem.value = "";
+ }
+ }
+ for (const position of borderPositions) {
+ const positionProperty = `${prop1}-${position}`;
+ const positionItem = getPropertyItem(positionProperty, properties);
+ const longhandProperty = `${prop1}-${position}-${prop2}`;
+ const longhandItem = getPropertyItem(longhandProperty, properties);
+ if (propertyValue) {
+ positionItem.value = replaceBorderShorthandValue(
+ propertyValue,
+ positionItem.value,
+ parseOpt
+ );
+ } else {
+ positionItem.value = "";
+ }
+ longhandItem.value = propertyValue;
+ longhandItem.priority = priority;
+ borderItems.set(positionProperty, positionItem);
+ borderItems.set(longhandProperty, longhandItem);
+ }
+ borderItems.set(border.property, shorthandItem);
+ borderItems.set(BORDER_IMAGE, imageItem);
+ borderItems.set(lineProperty, lineItem);
+ // Handle border shorthand.
+ } else {
+ const propertyValue = hasVarFunc(value) ? "" : value;
+ imageItem.value = propertyValue ? NONE : "";
+ for (const line of borderLines) {
+ const lineProperty = `${prop1}-${line}`;
+ const lineItem = getPropertyItem(lineProperty, properties);
+ lineItem.value = propertyValue;
+ lineItem.priority = priority;
+ borderItems.set(lineProperty, lineItem);
+ }
+ for (const position of borderPositions) {
+ const positionProperty = `${prop1}-${position}`;
+ const positionItem = getPropertyItem(positionProperty, properties);
+ positionItem.value = propertyValue;
+ positionItem.priority = priority;
+ borderItems.set(positionProperty, positionItem);
+ for (const line of borderLines) {
+ const longhandProperty = `${positionProperty}-${line}`;
+ const longhandItem = getPropertyItem(longhandProperty, properties);
+ longhandItem.value = propertyValue;
+ longhandItem.priority = priority;
+ borderItems.set(longhandProperty, longhandItem);
+ }
+ }
+ borderItems.set(property, shorthandItem);
+ borderItems.set(BORDER_IMAGE, imageItem);
+ }
+};
+
+/**
+ * Handles border property preparation when the value is an array.
+ *
+ * @param {Object} params - The parameters object.
+ * @param {Array} params.value - The property value.
+ * @param {string} params.priority - The property priority.
+ * @param {Map} params.properties - The map of properties.
+ * @param {Object} params.parts - The split property name parts.
+ * @param {Object} params.opt - Parsing options.
+ * @param {Map} params.borderItems - The map to store processed border items.
+ */
+const prepareBorderArrayValue = ({ value, priority, properties, parts, opt, borderItems }) => {
+ const { prop1, prop2 } = parts;
+ const { globalObject, options } = opt;
+ const parseOpt = {
+ globalObject,
+ options
+ };
+ if (!value.length || !borderLines.has(prop2)) {
+ return;
+ }
+ const shorthandItem = getPropertyItem(border.property, properties);
+ const imageItem = getPropertyItem(BORDER_IMAGE, properties);
+ const lineProperty = `${prop1}-${prop2}`;
+ const lineItem = getPropertyItem(lineProperty, properties);
+ if (value.length === 1) {
+ const [propertyValue] = value;
+ if (shorthandItem.value) {
+ if (hasVarFunc(shorthandItem.value)) {
+ shorthandItem.value = "";
+ } else if (propertyValue) {
+ shorthandItem.value = replaceBorderShorthandValue(
+ propertyValue,
+ shorthandItem.value,
+ parseOpt
+ );
+ }
+ }
+ } else {
+ shorthandItem.value = "";
+ }
+ lineItem.value = value.join(" ");
+ lineItem.priority = priority;
+ const positionValues = {};
+ const [val1, val2, val3, val4] = value;
+ switch (value.length) {
+ case 2: {
+ positionValues.top = val1;
+ positionValues.right = val2;
+ positionValues.bottom = val1;
+ positionValues.left = val2;
+ break;
+ }
+ case 3: {
+ positionValues.top = val1;
+ positionValues.right = val2;
+ positionValues.bottom = val3;
+ positionValues.left = val2;
+ break;
+ }
+ case 4: {
+ positionValues.top = val1;
+ positionValues.right = val2;
+ positionValues.bottom = val3;
+ positionValues.left = val4;
+ break;
+ }
+ case 1:
+ default: {
+ positionValues.top = val1;
+ positionValues.right = val1;
+ positionValues.bottom = val1;
+ positionValues.left = val1;
+ }
+ }
+ for (const position of borderPositions) {
+ const positionProperty = `${prop1}-${position}`;
+ const positionItem = getPropertyItem(positionProperty, properties);
+ if (positionItem.value && positionValues[position]) {
+ positionItem.value = replaceBorderShorthandValue(
+ positionValues[position],
+ positionItem.value,
+ parseOpt
+ );
+ }
+ const longhandProperty = `${positionProperty}-${prop2}`;
+ const longhandItem = getPropertyItem(longhandProperty, properties);
+ longhandItem.value = positionValues[position];
+ longhandItem.priority = priority;
+ borderItems.set(positionProperty, positionItem);
+ borderItems.set(longhandProperty, longhandItem);
+ }
+ borderItems.set(border.property, shorthandItem);
+ borderItems.set(BORDER_IMAGE, imageItem);
+ borderItems.set(lineProperty, lineItem);
+};
+
+/**
+ * Handles border property preparation when the value is an object.
+ *
+ * @param {Object} params - The parameters object.
+ * @param {string} params.property - The property name.
+ * @param {Object} params.value - The property value.
+ * @param {string} params.priority - The property priority.
+ * @param {Map} params.properties - The map of properties.
+ * @param {Object} params.parts - The split property name parts.
+ * @param {Object} params.opt - Parsing options.
+ * @param {Map} params.borderItems - The map to store processed border items.
+ */
+const prepareBorderObjectValue = ({
+ property,
+ value,
+ priority,
+ properties,
+ parts,
+ opt,
+ borderItems
+}) => {
+ const { prop1, prop2 } = parts;
+ const { globalObject, options } = opt;
+ const parseOpt = {
+ globalObject,
+ options
+ };
+ const imageItem = getPropertyItem(BORDER_IMAGE, properties);
+ // Handle position shorthands.
+ if (prop2) {
+ if (!borderPositions.has(prop2)) {
+ return;
+ }
+ const shorthandItem = getPropertyItem(border.property, properties);
+ const lineWidthProperty = `${prop1}-width`;
+ const lineWidthItem = getPropertyItem(lineWidthProperty, properties);
+ const lineStyleProperty = `${prop1}-style`;
+ const lineStyleItem = getPropertyItem(lineStyleProperty, properties);
+ const lineColorProperty = `${prop1}-color`;
+ const lineColorItem = getPropertyItem(lineColorProperty, properties);
+ const positionProperty = `${prop1}-${prop2}`;
+ const positionItem = getPropertyItem(positionProperty, properties);
+ if (shorthandItem.value) {
+ for (const positionValue of Object.values(value)) {
+ if (!matchesBorderShorthandValue(property, positionValue, shorthandItem.value, parseOpt)) {
+ shorthandItem.value = "";
+ break;
+ }
+ }
+ }
+ positionItem.value = Object.values(value).join(" ");
+ positionItem.priority = priority;
+ for (const line of borderLines) {
+ const longhandProperty = `${prop1}-${prop2}-${line}`;
+ const longhandItem = getPropertyItem(longhandProperty, properties);
+ const itemValue = Object.hasOwn(value, longhandProperty)
+ ? value[longhandProperty]
+ : border.initialValues.get(`${prop1}-${line}`);
+ if (line === WIDTH && lineWidthItem.value) {
+ lineWidthItem.value = replacePositionValue(
+ itemValue,
+ splitValue(lineWidthItem.value),
+ prop2
+ );
+ } else if (line === STYLE && lineStyleItem.value) {
+ lineStyleItem.value = replacePositionValue(
+ itemValue,
+ splitValue(lineStyleItem.value),
+ prop2
+ );
+ } else if (line === COLOR && lineColorItem.value) {
+ lineColorItem.value = replacePositionValue(
+ itemValue,
+ splitValue(lineColorItem.value),
+ prop2
+ );
+ }
+ longhandItem.value = itemValue;
+ longhandItem.priority = priority;
+ borderItems.set(longhandProperty, longhandItem);
+ }
+ borderItems.set(border.property, shorthandItem);
+ borderItems.set(BORDER_IMAGE, imageItem);
+ borderItems.set(lineWidthProperty, lineWidthItem);
+ borderItems.set(lineStyleProperty, lineStyleItem);
+ borderItems.set(lineColorProperty, lineColorItem);
+ borderItems.set(positionProperty, positionItem);
+ // Handle border shorthand.
+ } else {
+ const shorthandItem = getPropertyItem(prop1, properties);
+ const lineWidthProperty = `${prop1}-width`;
+ const lineWidthItem = getPropertyItem(lineWidthProperty, properties);
+ const lineStyleProperty = `${prop1}-style`;
+ const lineStyleItem = getPropertyItem(lineStyleProperty, properties);
+ const lineColorProperty = `${prop1}-color`;
+ const lineColorItem = getPropertyItem(lineColorProperty, properties);
+ const propertyValue = Object.values(value).join(" ");
+ shorthandItem.value = propertyValue;
+ shorthandItem.priority = priority;
+ imageItem.value = propertyValue ? NONE : "";
+ if (Object.hasOwn(value, lineWidthProperty)) {
+ lineWidthItem.value = value[lineWidthProperty];
+ } else {
+ lineWidthItem.value = border.initialValues.get(lineWidthProperty);
+ }
+ lineWidthItem.priority = priority;
+ if (Object.hasOwn(value, lineStyleProperty)) {
+ lineStyleItem.value = value[lineStyleProperty];
+ } else {
+ lineStyleItem.value = border.initialValues.get(lineStyleProperty);
+ }
+ lineStyleItem.priority = priority;
+ if (Object.hasOwn(value, lineColorProperty)) {
+ lineColorItem.value = value[lineColorProperty];
+ } else {
+ lineColorItem.value = border.initialValues.get(lineColorProperty);
+ }
+ lineColorItem.priority = priority;
+ for (const position of borderPositions) {
+ const positionProperty = `${prop1}-${position}`;
+ const positionItem = getPropertyItem(positionProperty, properties);
+ positionItem.value = propertyValue;
+ positionItem.priority = priority;
+ for (const line of borderLines) {
+ const longhandProperty = `${positionProperty}-${line}`;
+ const longhandItem = getPropertyItem(longhandProperty, properties);
+ const lineProperty = `${prop1}-${line}`;
+ if (Object.hasOwn(value, lineProperty)) {
+ longhandItem.value = value[lineProperty];
+ } else {
+ longhandItem.value = border.initialValues.get(lineProperty);
+ }
+ longhandItem.priority = priority;
+ borderItems.set(longhandProperty, longhandItem);
+ }
+ borderItems.set(positionProperty, positionItem);
+ }
+ borderItems.set(property, shorthandItem);
+ borderItems.set(BORDER_IMAGE, imageItem);
+ borderItems.set(lineWidthProperty, lineWidthItem);
+ borderItems.set(lineStyleProperty, lineStyleItem);
+ borderItems.set(lineColorProperty, lineColorItem);
+ }
+};
+
+/**
+ * Prepares border properties by splitting shorthands and handling updates.
+ *
+ * @param {string} property - The border property name.
+ * @param {string|Array|Object} value - The value of the property.
+ * @param {string} priority - The priority of the property (e.g., "important").
+ * @param {Map} properties - The map of all properties.
+ * @param {Object} [opt={}] - Parsing options.
+ * @returns {Map|undefined} A map of expanded or updated border properties.
+ */
+const prepareBorderProperties = (property, value, priority, properties, opt = {}) => {
+ if (typeof property !== "string" || value === null) {
+ return;
+ }
+ if (!property.startsWith(border.property)) {
+ return;
+ }
+ let prop2, prop3;
+ if (property.length > border.property.length) {
+ // Check if next char is '-'
+ if (property.charCodeAt(border.property.length) !== 45) {
+ return;
+ }
+ // property is like "border-..."
+ const remainder = property.substring(border.property.length + 1);
+ const hyphenIndex = remainder.indexOf("-");
+ if (hyphenIndex !== -1) {
+ prop2 = remainder.substring(0, hyphenIndex);
+ prop3 = remainder.substring(hyphenIndex + 1);
+ } else {
+ prop2 = remainder;
+ }
+ }
+ if (
+ (borderPositions.has(prop2) && prop3 && !borderLines.has(prop3)) ||
+ (borderLines.has(prop2) && prop3)
+ ) {
+ return;
+ }
+ const parts = {
+ prop1: border.property,
+ prop2,
+ prop3
+ };
+ const borderItems = new Map();
+ if (typeof value === "string") {
+ prepareBorderStringValue({
+ property,
+ value,
+ priority,
+ properties,
+ parts,
+ opt,
+ borderItems
+ });
+ } else if (Array.isArray(value)) {
+ prepareBorderArrayValue({
+ value,
+ priority,
+ properties,
+ parts,
+ opt,
+ borderItems
+ });
+ } else if (value && typeof value === "object") {
+ prepareBorderObjectValue({
+ property,
+ value,
+ priority,
+ properties,
+ parts,
+ opt,
+ borderItems
+ });
+ }
+ if (!borderItems.has(border.property)) {
+ return;
+ }
+ const borderProps = new Map([[border.property, borderItems.get(border.property)]]);
+ for (const line of borderLines) {
+ const lineProperty = `${border.property}-${line}`;
+ const lineItem = borderItems.get(lineProperty) ?? getPropertyItem(lineProperty, properties);
+ borderProps.set(lineProperty, lineItem);
+ }
+ for (const position of borderPositions) {
+ const positionProperty = `${border.property}-${position}`;
+ const positionItem =
+ borderItems.get(positionProperty) ?? getPropertyItem(positionProperty, properties);
+ borderProps.set(positionProperty, positionItem);
+ for (const line of borderLines) {
+ const longhandProperty = `${border.property}-${position}-${line}`;
+ const longhandItem =
+ borderItems.get(longhandProperty) ?? getPropertyItem(longhandProperty, properties);
+ borderProps.set(longhandProperty, longhandItem);
+ }
+ }
+ const borderImageItem = borderItems.get(BORDER_IMAGE) ?? createPropertyItem(BORDER_IMAGE);
+ borderProps.set(BORDER_IMAGE, borderImageItem);
+ return borderProps;
+};
+
+/**
+ * Generates a border line shorthand property if all line components are present.
+ *
+ * @param {Map} items - The map of collected property items.
+ * @param {string} property - The shorthand property name to generate.
+ * @param {string} [priority=""] - The priority of the property.
+ * @returns {Array} A key-value pair for the generated property.
+ */
+const generateBorderLineShorthand = (items, property, priority = "") => {
+ const values = [];
+ for (const [, item] of items) {
+ const { value: itemValue } = item;
+ values.push(itemValue);
+ }
+ const value = getPositionValue(values);
+ return [property, createPropertyItem(property, value, priority)];
+};
+
+/**
+ * Generates a border position shorthand property if all position components are present.
+ *
+ * @param {Map} items - The map of collected property items.
+ * @param {string} property - The shorthand property name to generate.
+ * @param {string} [priority=""] - The priority of the property.
+ * @returns {Array} A key-value pair for the generated property.
+ */
+const generateBorderPositionShorthand = (items, property, priority = "") => {
+ const values = [];
+ for (const [, item] of items) {
+ const { value: itemValue } = item;
+ values.push(itemValue);
+ }
+ const value = values.join(" ");
+ return [property, createPropertyItem(property, value, priority)];
+};
+
+/**
+ * Generates a border shorthand property if all components match.
+ *
+ * @param {Array} items - The collection of property values.
+ * @param {string} property - The shorthand property name to generate.
+ * @param {string} [priority=""] - The priority of the property.
+ * @returns {Array|undefined} A key-value pair for the generated property or undefined.
+ */
+const generateBorderShorthand = (items, property, priority = "") => {
+ const values = new Set(items);
+ if (values.size === 1) {
+ const value = values.keys().next().value;
+ return [property, createPropertyItem(property, value, priority)];
+ }
+};
+
+const borderCollectionConfig = {
+ [WIDTH]: {
+ shorthand: borderWidth.property,
+ generator: generateBorderLineShorthand
+ },
+ [STYLE]: {
+ shorthand: borderStyle.property,
+ generator: generateBorderLineShorthand
+ },
+ [COLOR]: {
+ shorthand: borderColor.property,
+ generator: generateBorderLineShorthand
+ },
+ [TOP]: {
+ shorthand: borderTop.property,
+ generator: generateBorderPositionShorthand
+ },
+ [RIGHT]: {
+ shorthand: borderRight.property,
+ generator: generateBorderPositionShorthand
+ },
+ [BOTTOM]: {
+ shorthand: borderBottom.property,
+ generator: generateBorderPositionShorthand
+ },
+ [LEFT]: {
+ shorthand: borderLeft.property,
+ generator: generateBorderPositionShorthand
+ }
+};
+
+/**
+ * Processes and consolidates border-related longhands into shorthands where possible.
+ *
+ * @param {Map} properties - The map of current properties.
+ * @returns {Map} The updated map with consolidated border properties.
+ */
+const prepareBorderShorthands = (properties) => {
+ const borderCollections = {};
+ for (const key of Object.keys(borderCollectionConfig)) {
+ borderCollections[key] = {
+ ...borderCollectionConfig[key],
+ items: new Map(),
+ priorityItems: new Map()
+ };
+ }
+ for (const [property, item] of properties) {
+ const { priority, value } = item;
+ let positionPart, linePart;
+ // We can assume property starts with "border-"
+ const firstHyphen = property.indexOf("-");
+ if (firstHyphen !== -1) {
+ const remainder = property.substring(firstHyphen + 1);
+ const secondHyphen = remainder.indexOf("-");
+ if (secondHyphen !== -1) {
+ positionPart = remainder.substring(0, secondHyphen);
+ linePart = remainder.substring(secondHyphen + 1);
+ } else {
+ positionPart = remainder;
+ linePart = undefined;
+ }
+ }
+ if (linePart && borderCollections[linePart]) {
+ const collection = borderCollections[linePart];
+ if (priority) {
+ collection.priorityItems.set(property, { property, value, priority });
+ } else {
+ collection.items.set(property, { property, value, priority });
+ }
+ }
+ if (positionPart && borderCollections[positionPart]) {
+ const collection = borderCollections[positionPart];
+ if (priority) {
+ collection.priorityItems.set(property, { property, value, priority });
+ } else {
+ collection.items.set(property, { property, value, priority });
+ }
+ }
+ }
+ const shorthandItems = [];
+ const shorthandPriorityItems = [];
+ for (const [key, collection] of Object.entries(borderCollections)) {
+ const { shorthand, generator, items, priorityItems } = collection;
+ const requiredSize = borderLines.has(key) ? 4 : 3;
+ if (items.size === requiredSize) {
+ const [property, item] = generator(items, shorthand) ?? [];
+ if (property && item) {
+ properties.set(property, item);
+ if (borderPositions.has(key) && properties.has(BORDER_IMAGE)) {
+ const { value: imageValue } = properties.get(BORDER_IMAGE);
+ if (imageValue === NONE) {
+ shorthandItems.push(item.value);
+ }
+ }
+ }
+ } else if (priorityItems.size === requiredSize) {
+ const [property, item] = generator(priorityItems, shorthand, "important") ?? [];
+ if (property && item) {
+ properties.set(property, item);
+ if (borderPositions.has(key) && properties.has(BORDER_IMAGE)) {
+ const { value: imageValue } = properties.get(BORDER_IMAGE);
+ if (imageValue === NONE) {
+ shorthandPriorityItems.push(item.value);
+ }
+ }
+ }
+ }
+ }
+ const mixedPriorities = shorthandItems.length && shorthandPriorityItems.length;
+ const imageItem = createPropertyItem(BORDER_IMAGE, NONE);
+ if (shorthandItems.length === 4) {
+ const [property, item] = generateBorderShorthand(shorthandItems, border.property) ?? [];
+ if (property && item) {
+ properties.set(property, item);
+ properties.delete(BORDER_IMAGE);
+ properties.set(BORDER_IMAGE, imageItem);
+ }
+ } else if (shorthandPriorityItems.length === 4) {
+ const [property, item] =
+ generateBorderShorthand(shorthandPriorityItems, border.property, "important") ?? [];
+ if (property && item) {
+ properties.set(property, item);
+ properties.delete(BORDER_IMAGE);
+ properties.set(BORDER_IMAGE, imageItem);
+ }
+ } else if (properties.has(BORDER_IMAGE)) {
+ const { value: imageValue } = properties.get(BORDER_IMAGE);
+ if (imageValue === NONE) {
+ if (mixedPriorities) {
+ properties.delete(BORDER_IMAGE);
+ properties.set(BORDER_IMAGE, imageItem);
+ } else {
+ properties.delete(BORDER_IMAGE);
+ }
+ }
+ }
+ if (mixedPriorities) {
+ const items = [];
+ const priorityItems = [];
+ for (const item of properties) {
+ const [, { priority }] = item;
+ if (priority) {
+ priorityItems.push(item);
+ } else {
+ items.push(item);
+ }
+ }
+ const firstPropertyKey = properties.keys().next().value;
+ const { priority: firstPropertyPriority } = properties.get(firstPropertyKey);
+ if (firstPropertyPriority) {
+ return new Map([...priorityItems, ...items]);
+ }
+ return new Map([...items, ...priorityItems]);
+ }
+ if (properties.has(BORDER_IMAGE)) {
+ properties.delete(BORDER_IMAGE);
+ properties.set(BORDER_IMAGE, imageItem);
+ }
+ return properties;
+};
+
+/**
+ * Processes shorthand properties from the shorthands map.
+ *
+ * @param {Map} shorthands - The map containing shorthand property groups.
+ * @returns {Map} A map of processed shorthand properties.
+ */
+const processShorthandProperties = (shorthands) => {
+ const shorthandItems = new Map();
+ for (const [property, item] of shorthands) {
+ const shorthandItem = shorthandProperties.get(property);
+ if (item.size === shorthandItem.shorthandFor.size && shorthandItem.position) {
+ const positionValues = [];
+ let priority = "";
+ for (const { value: longhandValue, priority: longhandPriority } of item.values()) {
+ positionValues.push(longhandValue);
+ if (longhandPriority) {
+ priority = longhandPriority;
+ }
+ }
+ const value = getPositionValue(positionValues, shorthandItem.position);
+ shorthandItems.set(property, createPropertyItem(property, value, priority));
+ }
+ }
+ return shorthandItems;
+};
+
+/**
+ * Updates the longhand properties map with a new property item.
+ * If a property with normal priority already exists, it will be overwritten by the new item.
+ * If the existing property has "important" priority, it will not be overwritten.
+ *
+ * @param {string} property - The CSS property name.
+ * @param {Object} item - The property item object containing value and priority.
+ * @param {Map} longhandProperties - The map of longhand properties to update.
+ */
+const updateLonghandProperties = (property, item, longhandProperties) => {
+ if (longhandProperties.has(property)) {
+ const { priority: longhandPriority } = longhandProperties.get(property);
+ if (!longhandPriority) {
+ longhandProperties.delete(property);
+ longhandProperties.set(property, item);
+ }
+ } else {
+ longhandProperties.set(property, item);
+ }
+};
+
+/**
+ * Processes border properties from the borders map, expanding and normalizing them.
+ *
+ * @param {Map} borders - The map containing accumulated border properties.
+ * @param {Object} parseOpt - Options for parsing values.
+ * @returns {Map} A map of fully processed and normalized border properties.
+ */
+const processBorderProperties = (borders, parseOpt) => {
+ const longhandProperties = new Map();
+ for (const [property, item] of borders) {
+ if (shorthandProperties.has(property)) {
+ const { value, priority } = item;
+ if (property === border.property) {
+ const lineItems = border.parse(value, parseOpt);
+ for (const [key, initialValue] of border.initialValues) {
+ if (!Object.hasOwn(lineItems, key)) {
+ lineItems[key] = initialValue;
+ }
+ }
+ for (const lineProperty of Object.keys(lineItems)) {
+ let namePart, linePart;
+ const hyphenIndex = lineProperty.indexOf("-");
+ if (hyphenIndex !== -1) {
+ namePart = lineProperty.substring(0, hyphenIndex);
+ linePart = lineProperty.substring(hyphenIndex + 1);
+ } else {
+ // fallback for safety, though lineProperty from border.parse keys
+ // should have hyphen
+ namePart = lineProperty;
+ linePart = "";
+ }
+ const lineValue = lineItems[lineProperty];
+ for (const position of borderPositions) {
+ const longhandProperty = `${namePart}-${position}-${linePart}`;
+ const longhandItem = createPropertyItem(longhandProperty, lineValue, priority);
+ updateLonghandProperties(longhandProperty, longhandItem, longhandProperties);
+ }
+ }
+ if (value) {
+ longhandProperties.set(BORDER_IMAGE, createPropertyItem(BORDER_IMAGE, NONE, priority));
+ }
+ } else {
+ const shorthandItem = shorthandProperties.get(property);
+ const parsedItem = shorthandItem.parse(value, parseOpt);
+ if (Array.isArray(parsedItem)) {
+ let namePart, linePart;
+ const hyphenIndex = property.indexOf("-");
+ if (hyphenIndex !== -1) {
+ namePart = property.substring(0, hyphenIndex);
+ linePart = property.substring(hyphenIndex + 1);
+ } else {
+ namePart = property;
+ }
+ for (const position of borderPositions) {
+ const longhandProperty = `${namePart}-${position}-${linePart}`;
+ const longhandValue = getPositionValue(parsedItem, position);
+ const longhandItem = createPropertyItem(longhandProperty, longhandValue, priority);
+ updateLonghandProperties(longhandProperty, longhandItem, longhandProperties);
+ }
+ } else if (parsedItem) {
+ for (const [key, initialValue] of shorthandItem.initialValues) {
+ if (!Object.hasOwn(parsedItem, key)) {
+ parsedItem[key] = initialValue;
+ }
+ }
+ for (const longhandProperty of Object.keys(parsedItem)) {
+ const longhandValue = parsedItem[longhandProperty];
+ const longhandItem = createPropertyItem(longhandProperty, longhandValue, priority);
+ updateLonghandProperties(longhandProperty, longhandItem, longhandProperties);
+ }
+ }
+ }
+ } else if (longhandProperties.has(property)) {
+ const { priority } = longhandProperties.get(property);
+ if (!priority) {
+ longhandProperties.delete(property);
+ longhandProperties.set(property, item);
+ }
+ } else {
+ longhandProperties.set(property, item);
+ }
+ }
+ const borderItems = prepareBorderShorthands(longhandProperties);
+ return borderItems;
+};
+
+/**
+ * Normalize and prepare CSS properties, handling shorthands and longhands.
+ *
+ * @param {Map} properties - The initial map of properties.
+ * @param {Object} [opt={}] - Parsing options.
+ * @returns {Map} The normalized map of properties.
+ */
+const prepareProperties = (properties, opt = {}) => {
+ const { globalObject, options } = opt;
+ const parseOpt = {
+ globalObject,
+ options
+ };
+ const parsedProperties = new Map();
+ const shorthands = new Map();
+ const borders = new Map();
+ let hasPrecedingBackground = false;
+ for (const [property, item] of properties) {
+ const { value, priority } = item;
+ const { logicalPropertyGroup: shorthandProperty } = propertyDefinitions.get(property) ?? {};
+ if (borderProperties.has(property)) {
+ borders.set(property, { property, value, priority });
+ } else if (shorthandProperties.has(shorthandProperty)) {
+ if (!shorthands.has(shorthandProperty)) {
+ shorthands.set(shorthandProperty, new Map());
+ }
+ const longhandItems = shorthands.get(shorthandProperty);
+ if (longhandItems.size) {
+ const firstPropertyKey = longhandItems.keys().next().value;
+ const { priority: firstPropertyPriority } = longhandItems.get(firstPropertyKey);
+ if (priority === firstPropertyPriority) {
+ longhandItems.set(property, { property, value, priority });
+ shorthands.set(shorthandProperty, longhandItems);
+ } else {
+ parsedProperties.delete(shorthandProperty);
+ }
+ } else {
+ longhandItems.set(property, { property, value, priority });
+ shorthands.set(shorthandProperty, longhandItems);
+ }
+ parsedProperties.set(property, item);
+ } else if (shorthandProperties.has(property)) {
+ const shorthandItem = shorthandProperties.get(property);
+ const parsedValues = shorthandItem.parse(value, parseOpt);
+ let omitShorthandProperty = false;
+ if (Array.isArray(parsedValues)) {
+ const [parsedValue] = parsedValues;
+ if (typeof parsedValue === "string") {
+ for (const [longhandProperty, longhandItem] of shorthandItem.shorthandFor) {
+ if (!priority && properties.has(longhandProperty)) {
+ const { priority: longhandPriority } = properties.get(longhandProperty);
+ if (longhandPriority) {
+ omitShorthandProperty = true;
+ continue;
+ }
+ }
+ const { position } = longhandItem;
+ const longhandValue = getPositionValue([parsedValue], position);
+ parsedProperties.set(
+ longhandProperty,
+ createPropertyItem(longhandProperty, longhandValue, priority)
+ );
+ }
+ } else if (parsedValue) {
+ for (const longhandProperty of Object.keys(parsedValue)) {
+ const longhandValue = parsedValue[longhandProperty];
+ parsedProperties.set(
+ longhandProperty,
+ createPropertyItem(longhandProperty, longhandValue, priority)
+ );
+ }
+ }
+ } else if (parsedValues && typeof parsedValues !== "string") {
+ for (const longhandProperty of Object.keys(parsedValues)) {
+ const longhandValue = parsedValues[longhandProperty];
+ parsedProperties.set(
+ longhandProperty,
+ createPropertyItem(longhandProperty, longhandValue, priority)
+ );
+ }
+ }
+ if (!omitShorthandProperty) {
+ if (property === background.property) {
+ hasPrecedingBackground = true;
+ }
+ parsedProperties.set(property, createPropertyItem(property, value, priority));
+ }
+ } else {
+ parsedProperties.set(property, createPropertyItem(property, value, priority));
+ if (hasPrecedingBackground) {
+ const { value: shorthandValue, priority: shorthandPriority } = properties.get(
+ background.property
+ );
+ if ((!shorthandPriority || priority) && !hasVarFunc(shorthandValue)) {
+ const replacedShorthandValue = replaceBackgroundShorthand(
+ property,
+ parsedProperties,
+ parseOpt
+ );
+ properties.delete(background.property);
+ properties.set(
+ background.property,
+ createPropertyItem(background.property, replacedShorthandValue, shorthandPriority)
+ );
+ }
+ }
+ }
+ }
+ if (shorthands.size) {
+ const shorthandItems = processShorthandProperties(shorthands);
+ for (const [property, item] of shorthandItems) {
+ parsedProperties.set(property, item);
+ }
+ }
+ if (borders.size) {
+ const borderItems = processBorderProperties(borders, parseOpt);
+ for (const [property, item] of borderItems) {
+ parsedProperties.set(property, item);
+ }
+ }
+ return parsedProperties;
+};
+
+/**
+ * Cleans up redundancy in border properties by removing longhands that are covered by shorthands.
+ *
+ * @param {Map} properties - The map of properties to normalize.
+ * @returns {Map} The normalized properties map.
+ */
+const normalizeProperties = (properties) => {
+ if (properties.has(border.property)) {
+ for (const line of borderLines) {
+ properties.delete(`${border.property}-${line}`);
+ }
+ for (const position of borderPositions) {
+ properties.delete(`${border.property}-${position}`);
+ for (const line of borderLines) {
+ properties.delete(`${border.property}-${position}-${line}`);
+ }
+ }
+ properties.delete(`${border.property}-image`);
+ }
+ for (const line of borderLines) {
+ const lineProperty = `${border.property}-${line}`;
+ if (properties.has(lineProperty)) {
+ for (const position of borderPositions) {
+ const positionProperty = `${border.property}-${position}`;
+ const longhandProperty = `${border.property}-${position}-${line}`;
+ properties.delete(positionProperty);
+ properties.delete(longhandProperty);
+ }
+ }
+ }
+ for (const position of borderPositions) {
+ const positionProperty = `${border.property}-${position}`;
+ if (properties.has(positionProperty)) {
+ const longhandProperties = [];
+ for (const line of borderLines) {
+ const longhandProperty = `${border.property}-${position}-${line}`;
+ longhandProperties.push(longhandProperty);
+ }
+ if (longhandProperties.length === 3) {
+ for (const longhandProperty of longhandProperties) {
+ properties.delete(longhandProperty);
+ }
+ } else {
+ properties.delete(positionProperty);
+ }
+ }
+ }
+ return properties;
+};
+
+module.exports = {
+ borderProperties,
+ getPositionValue,
+ normalizeProperties,
+ prepareBorderProperties,
+ prepareProperties,
+ shorthandProperties
+};