From 3acbff46cd422009e1a51d1ab805e873ff53d838 Mon Sep 17 00:00:00 2001 From: "asamuzaK (Kazz)" Date: Sat, 13 Dec 2025 23:30:58 +0900 Subject: [PATCH 01/12] Add generator script --- .gitignore | 1 + package.json | 1 + scripts/generatePropertyDefinitions.mjs | 25 +++++++++++++++++++++++++ 3 files changed, 27 insertions(+) create mode 100644 scripts/generatePropertyDefinitions.mjs diff --git a/.gitignore b/.gitignore index 8297d482..3348a32e 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ node_modules npm-debug.log lib/generated/implementedProperties.js lib/generated/properties.js +lib/generated/propertyDefinitions.js diff --git a/package.json b/package.json index e4d4684b..53e44eec 100644 --- a/package.json +++ b/package.json @@ -42,6 +42,7 @@ "prepare": "run-p prepare:*", "prepare:implemented_properties": "node ./scripts/generateImplementedProperties.mjs", "prepare:properties": "node ./scripts/generateProperties.js", + "prepare:propertyDefinitions": "node ./scripts/generatePropertyDefinitions.mjs", "test": "node --test" }, "license": "MIT", diff --git a/scripts/generatePropertyDefinitions.mjs b/scripts/generatePropertyDefinitions.mjs new file mode 100644 index 00000000..457a8459 --- /dev/null +++ b/scripts/generatePropertyDefinitions.mjs @@ -0,0 +1,25 @@ +import fs from "node:fs"; +import path from "node:path"; +import css from "@webref/css"; +import allProperties from "../lib/generated/allProperties.js"; +import allExtraProperties from "../lib/utils/allExtraProperties.js"; + +const { properties } = await css.listAll(); +const unifiedProperties = + typeof allProperties.union === "function" + ? allProperties.union(allExtraProperties) + : new Set([...allProperties, ...allExtraProperties]); +const definitions = properties + .filter((definition) => unifiedProperties.has(definition.name)) + .sort((a, b) => a.name.localeCompare(b.name)) + .map((definition) => [definition.name, definition]); + +const [dateTodayFormatted] = new Date().toISOString().split("T"); +const output = `"use strict"; +// autogenerated - ${dateTodayFormatted} + +module.exports = new Map(${JSON.stringify(definitions, null, 2)}); +`; +const { dirname } = import.meta; +const outputFile = path.resolve(dirname, "../lib/generated/propertyDefinitions.js"); +fs.writeFileSync(outputFile, output); From 7f1efa0f56a7665328bde408ba659fa013d9ee1f Mon Sep 17 00:00:00 2001 From: "asamuzaK (Kazz)" Date: Sat, 13 Dec 2025 23:35:24 +0900 Subject: [PATCH 02/12] Update normalizer --- lib/CSSStyleDeclaration.js | 4 +- lib/normalize.js | 2301 +++++++++++++++++++----------------- 2 files changed, 1251 insertions(+), 1054 deletions(-) diff --git a/lib/CSSStyleDeclaration.js b/lib/CSSStyleDeclaration.js index 6d430623..e4d18388 100644 --- a/lib/CSSStyleDeclaration.js +++ b/lib/CSSStyleDeclaration.js @@ -10,7 +10,7 @@ const generatedProperties = require("./generated/properties"); const { borderProperties, getPositionValue, - normalizeBorderProperties, + normalizeProperties, prepareBorderProperties, prepareProperties, shorthandProperties @@ -150,7 +150,7 @@ class CSSStyleDeclaration { } properties.set(property, { property, value, priority }); } - const normalizedProperties = normalizeBorderProperties(properties); + const normalizedProperties = normalizeProperties(properties); const parts = []; for (const { property, value, priority } of normalizedProperties.values()) { if (priority) { diff --git a/lib/normalize.js b/lib/normalize.js index 6f7b1624..778064fd 100644 --- a/lib/normalize.js +++ b/lib/normalize.js @@ -1,6 +1,6 @@ "use strict"; -const implementedProperties = require("./generated/implementedProperties"); +const propertyDefinitions = require("./generated/propertyDefinitions"); const { hasVarFunc, isGlobalKeyword, isValidPropertyValue, splitValue } = require("./parsers"); const background = require("./properties/background"); const border = require("./properties/border"); @@ -16,38 +16,64 @@ const font = require("./properties/font"); const margin = require("./properties/margin"); const padding = require("./properties/padding"); -const borderImageProperty = "border-image"; +/* constants */ +const BACKGROUND = "background"; +const BACKGROUND_COLOR = "background-color"; +const BACKGROUND_SIZE = "background-size"; +const BORDER = "border"; +const BORDER_BOTTOM = "border-bottom"; +const BORDER_COLOR = "border-color"; +const BORDER_IMAGE = "border-image"; +const BORDER_LEFT = "border-left"; +const BORDER_RIGHT = "border-right"; +const BORDER_STYLE = "border-style"; +const BORDER_TOP = "border-top"; +const BORDER_WIDTH = "border-width"; +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 +}; -exports.shorthandProperties = new Map([ - ["background", background], +const shorthandProperties = new Map([ + [BACKGROUND, background], [ - "border", + BORDER, { definition: border.definition, parse: border.parse, shorthandFor: new Map([ ...border.shorthandFor, ...border.positionShorthandFor, - [borderImageProperty, null] + [BORDER_IMAGE, null] ]) } ], - ["border-width", borderWidth], - ["border-style", borderStyle], - ["border-color", borderColor], - ["border-top", borderTop], - ["border-right", borderRight], - ["border-bottom", borderBottom], - ["border-left", borderLeft], + [BORDER_WIDTH, borderWidth], + [BORDER_STYLE, borderStyle], + [BORDER_COLOR, borderColor], + [BORDER_TOP, borderTop], + [BORDER_RIGHT, borderRight], + [BORDER_BOTTOM, borderBottom], + [BORDER_LEFT, borderLeft], ["flex", flex], ["font", font], ["margin", margin], ["padding", padding] ]); -exports.borderProperties = new Set([ - "border", - borderImageProperty, +const borderProperties = new Set([ + BORDER, + BORDER_IMAGE, ...border.shorthandFor.keys(), ...border.positionShorthandFor.keys(), ...borderTop.shorthandFor.keys(), @@ -56,113 +82,167 @@ exports.borderProperties = new Set([ ...borderLeft.shorthandFor.keys() ]); -exports.getPositionValue = (positionValues, position) => { - switch (positionValues.length) { - case 1: { - const [val1] = positionValues; - return val1; +const borderElements = { + name: BORDER, + positions: [TOP, RIGHT, BOTTOM, LEFT], + lines: [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: { - const [val1, val2] = positionValues; - switch (position) { - case "top": { - return val1; - } - case "right": { - return val2; - } - case "bottom": { - return val1; - } - case "left": { - return val2; - } - default: { - if (val1 === val2) { - return val1; - } - return `${val1} ${val2}`; - } + if (val1 === val2) { + return val1; } + return `${val1} ${val2}`; } case 3: { - const [val1, val2, val3] = positionValues; - switch (position) { - case "top": { + if (val1 === val3) { + if (val1 === val2) { return val1; } - case "right": { - return val2; - } - case "bottom": { - return val3; - } - case "left": { - return val2; - } - default: { - if (val1 === val3) { - if (val1 === val2) { - return val1; - } - return `${val1} ${val2}`; - } - return `${val1} ${val2} ${val3}`; - } + return `${val1} ${val2}`; } + return `${val1} ${val2} ${val3}`; } case 4: { - const [val1, val2, val3, val4] = positionValues; - switch (position) { - case "top": { - return val1; - } - case "right": { - return val2; - } - case "bottom": { - return val3; - } - case "left": { - return val4; - } - default: { - if (val2 === val4) { - if (val1 === val3) { - if (val1 === val2) { - return val1; - } - return `${val1} ${val2}`; - } - return `${val1} ${val2} ${val3}`; + if (val2 === val4) { + if (val1 === val3) { + if (val1 === val2) { + return val1; } - return `${val1} ${val2} ${val3} ${val4}`; + return `${val1} ${val2}`; } + return `${val1} ${val2} ${val3}`; } + return `${val1} ${val2} ${val3} ${val4}`; + } + case 1: + default: { + return val1; } - default: } }; -const borderElements = { - name: "border", - positions: ["top", "right", "bottom", "left"], - lines: ["width", "style", "color"] -}; - -const getPropertyItem = (property, properties) => { - const propertyItem = properties.get(property) ?? { - property, - value: "", - priority: "" - }; - return propertyItem; +/** + * 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); + const bgValues = background.parse(shorthandValue, opt); + const bgLength = bgValues.length; + if (property === BACKGROUND_COLOR) { + 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 === BACKGROUND_SIZE) { + 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 } = opt; + const { globalObject, options } = opt; const obj = border.parse(shorthandValue, { - globalObject + globalObject, + options }); if (Object.hasOwn(obj, property)) { return value === obj[property]; @@ -170,17 +250,25 @@ const matchesBorderShorthandValue = (property, value, shorthandValue, opt = {}) 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 } = opt; + const { globalObject, options } = opt; const borderFirstInitialKey = border.initialValues.keys().next().value; const borderFirstInitialValue = border.initialValues.get(borderFirstInitialKey); - const valueObj = border.parse(value, { - globalObject - }); + const parseOpt = { + globalObject, + options + }; + const valueObj = border.parse(value, parseOpt); const shorthandObj = shorthandValue - ? border.parse(shorthandValue, { - globalObject - }) + ? border.parse(shorthandValue, parseOpt) : { [borderFirstInitialKey]: borderFirstInitialValue }; @@ -212,648 +300,797 @@ const replaceBorderShorthandValue = (value, shorthandValue, opt = {}) => { 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) => { - switch (positionValues.length) { - case 1: { - const [val1] = positionValues; - if (val1 === value) { - return positionValues.join(" "); - } - switch (position) { - case "top": { - return [value, val1, val1].join(" "); - } - case "right": { - return [val1, value, val1, val1].join(" "); - } - case "bottom": { - return [val1, val1, value].join(" "); - } - case "left": { - return [val1, val1, val1, value].join(" "); - } - default: - } - break; - } - case 2: { - const [val1, val2] = positionValues; - if (val1 === val2) { - return replacePositionValue(value, [val1], position); - } - switch (position) { - case "top": { - if (val1 === value) { - return positionValues.join(" "); + 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}`; + } } - return [value, val2, val1].join(" "); } - case "right": { - if (val2 === value) { - return positionValues.join(" "); + 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}`; + } } - return [val1, value, val1, val2].join(" "); } - case "bottom": { - if (val1 === value) { - return positionValues.join(" "); + 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}`; + } } - return [val1, val2, value].join(" "); } - case "left": { - if (val2 === value) { - return positionValues.join(" "); + 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}`; + } } - return [val1, val2, val1, value].join(" "); } - default: } - break; + } + } + // 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: { - const [val1, val2, val3] = positionValues; if (val1 === val3) { - return replacePositionValue(value, [val1, val2], position); - } - switch (position) { - case "top": { - if (val1 === value) { - return positionValues.join(" "); - } else if (val3 === value) { - return [value, val2].join(" "); - } - return [value, val2, val3].join(" "); - } - case "right": { - if (val2 === value) { - return positionValues.join(" "); - } - return [val1, value, val3, val2].join(" "); - } - case "bottom": { - if (val3 === value) { - return positionValues.join(" "); - } else if (val1 === value) { - return [val1, val2].join(" "); - } - return [val1, val2, value].join(" "); - } - case "left": { - if (val2 === value) { - return positionValues.join(" "); - } - return [val1, val2, val3, value].join(" "); + if (val1 === val2) { + return val1; } - default: + return `${val1} ${val2}`; } - break; + return `${val1} ${val2} ${val3}`; } case 4: { - const [val1, val2, val3, val4] = positionValues; if (val2 === val4) { - return replacePositionValue(value, [val1, val2, val3], position); - } - switch (position) { - case "top": { - if (val1 === value) { - return positionValues.join(" "); - } - return [value, val2, val3, val4].join(" "); - } - case "right": { - if (val2 === value) { - return positionValues.join(" "); - } else if (val4 === value) { - return [val1, value, val3].join(" "); - } - return [val1, value, val3, val4].join(" "); - } - case "bottom": { - if (val3 === value) { - return positionValues.join(" "); - } - return [val1, val2, value, val4].join(" "); - } - case "left": { - if (val4 === value) { - return positionValues.join(" "); - } else if (val2 === value) { - return [val1, val2, val3].join(" "); + if (val1 === val3) { + if (val1 === val2) { + return val1; } - return [val1, val2, val3, value].join(" "); + return `${val1} ${val2}`; } - default: + return `${val1} ${val2} ${val3}`; } - break; + return `${val1} ${val2} ${val3} ${val4}`; + } + case 1: + default: { + return val1; } - default: } }; -exports.prepareBorderProperties = (property, value, priority, properties, opt = {}) => { - if (typeof property !== "string" || value === null) { - return; - } - const { globalObject } = opt; - const { lines, name, positions } = borderElements; - const [prop1, prop2, prop3] = property.split("-"); - if (prop1 !== name) { - return; - } else if (positions.includes(prop2)) { - if (prop3) { - if (!lines.includes(prop3)) { - return; +/** + * 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 { lines, positions, name: nameProperty } = borderElements; + const nameItem = getPropertyItem(nameProperty, 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 === "") { + nameItem.value = ""; + lineItem.value = ""; + positionItem.value = ""; + } else if (isGlobalKeyword(propertyValue)) { + if (nameItem.value !== propertyValue) { + nameItem.value = ""; + } + if (lineItem.value !== propertyValue) { + lineItem.value = ""; + } + if (positionItem.value !== propertyValue) { + positionItem.value = ""; + } + } else { + if ( + nameItem.value && + !matchesBorderShorthandValue(lineProperty, propertyValue, nameItem.value, parseOpt) + ) { + nameItem.value = ""; + } + if (lineItem.value) { + lineItem.value = replacePositionValue(propertyValue, splitValue(lineItem.value), prop2); + } + if ( + positionItem.value && + !matchesBorderShorthandValue(lineProperty, propertyValue, positionItem.value, parseOpt) + ) { + positionItem.value = ""; } } - } else if (lines.includes(prop2)) { - if (prop3) { - return; + borderItems.set(nameProperty, nameItem); + 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 && positions.includes(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 === "") { + nameItem.value = ""; + lineWidthItem.value = ""; + lineStyleItem.value = ""; + lineColorItem.value = ""; + } else if (isGlobalKeyword(propertyValue)) { + if (nameItem.value !== propertyValue) { + nameItem.value = ""; + } + if (lineWidthItem.value !== propertyValue) { + lineWidthItem.value = ""; + } + if (lineStyleItem.value !== propertyValue) { + lineStyleItem.value = ""; + } + if (lineColorItem.value !== propertyValue) { + lineColorItem.value = ""; + } + } else { + if ( + nameItem.value && + !matchesBorderShorthandValue(property, propertyValue, nameItem.value, parseOpt) + ) { + nameItem.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; + } } - } - const borderItems = new Map(); - const nameProperty = prop1; - // Empty string, global keywords, var(), value of longhands. - if (typeof value === "string") { - // longhand properties - if (prop3) { - const nameItem = getPropertyItem(nameProperty, properties); - const imageItem = getPropertyItem(borderImageProperty, properties); - const lineProperty = `${prop1}-${prop3}`; - const lineItem = getPropertyItem(lineProperty, properties); - const positionProperty = `${prop1}-${prop2}`; - const positionItem = getPropertyItem(positionProperty, properties); - const longhandProperty = `${prop1}-${prop2}-${prop3}`; + for (const line of lines) { + const longhandProperty = `${prop1}-${prop2}-${line}`; const longhandItem = getPropertyItem(longhandProperty, properties); - longhandItem.value = value; + longhandItem.value = propertyValue; longhandItem.priority = priority; - const propertyValue = hasVarFunc(value) ? "" : value; - if (propertyValue === "") { + borderItems.set(longhandProperty, longhandItem); + } + borderItems.set(nameProperty, nameItem); + 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 && lines.includes(prop2)) { + const lineProperty = `${prop1}-${prop2}`; + const lineItem = getPropertyItem(lineProperty, properties); + lineItem.value = value; + lineItem.priority = priority; + const propertyValue = hasVarFunc(value) ? "" : value; + if (propertyValue === "") { + nameItem.value = ""; + } else if (isGlobalKeyword(propertyValue)) { + if (nameItem.value !== propertyValue) { nameItem.value = ""; - lineItem.value = ""; - positionItem.value = ""; - } else if (isGlobalKeyword(propertyValue)) { - if (nameItem.value !== propertyValue) { - nameItem.value = ""; - } - if (lineItem.value !== propertyValue) { - lineItem.value = ""; - } - if (positionItem.value !== propertyValue) { - positionItem.value = ""; - } + } + } + for (const position of positions) { + 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 { - if ( - nameItem.value && - !matchesBorderShorthandValue(lineProperty, propertyValue, nameItem.value, { - globalObject - }) - ) { - nameItem.value = ""; - } - if (lineItem.value) { - lineItem.value = replacePositionValue(propertyValue, splitValue(lineItem.value), prop2); - } - if ( - positionItem.value && - !matchesBorderShorthandValue(lineProperty, propertyValue, positionItem.value, { - globalObject - }) - ) { - positionItem.value = ""; - } + positionItem.value = ""; } - borderItems.set(nameProperty, nameItem); - borderItems.set(borderImageProperty, imageItem); - borderItems.set(lineProperty, lineItem); + longhandItem.value = propertyValue; + longhandItem.priority = priority; borderItems.set(positionProperty, positionItem); borderItems.set(longhandProperty, longhandItem); - // border-top, border-right, border-bottom, border-left shorthands - } else if (prop2 && positions.includes(prop2)) { - const nameItem = getPropertyItem(nameProperty, properties); - const imageItem = getPropertyItem(borderImageProperty, 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}`; + } + borderItems.set(nameProperty, nameItem); + 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 lines) { + const lineProperty = `${prop1}-${line}`; + const lineItem = getPropertyItem(lineProperty, properties); + lineItem.value = propertyValue; + lineItem.priority = priority; + borderItems.set(lineProperty, lineItem); + } + for (const position of positions) { + const positionProperty = `${prop1}-${position}`; const positionItem = getPropertyItem(positionProperty, properties); - positionItem.value = value; + positionItem.value = propertyValue; positionItem.priority = priority; - const propertyValue = hasVarFunc(value) ? "" : value; - if (propertyValue === "") { - nameItem.value = ""; - lineWidthItem.value = ""; - lineStyleItem.value = ""; - lineColorItem.value = ""; - } else if (isGlobalKeyword(propertyValue)) { - if (nameItem.value !== propertyValue) { - nameItem.value = ""; - } - if (lineWidthItem.value !== propertyValue) { - lineWidthItem.value = ""; - } - if (lineStyleItem.value !== propertyValue) { - lineStyleItem.value = ""; - } - if (lineColorItem.value !== propertyValue) { - lineColorItem.value = ""; - } - } else { - if ( - nameItem.value && - !matchesBorderShorthandValue(property, propertyValue, nameItem.value, { - globalObject - }) - ) { - nameItem.value = ""; - } - if (lineWidthItem.value && isValidPropertyValue(lineWidthProperty, propertyValue)) { - lineWidthItem.value = propertyValue; - } - if (lineStyleItem.value && isValidPropertyValue(lineStyleProperty, propertyValue)) { - lineStyleItem.value = propertyValue; - } - if (lineColorItem.value && isValidPropertyValue(lineColorProperty, propertyValue)) { - lineColorItem.value = propertyValue; - } - } + borderItems.set(positionProperty, positionItem); for (const line of lines) { - const longhandProperty = `${prop1}-${prop2}-${line}`; + const longhandProperty = `${positionProperty}-${line}`; const longhandItem = getPropertyItem(longhandProperty, properties); longhandItem.value = propertyValue; longhandItem.priority = priority; borderItems.set(longhandProperty, longhandItem); } - borderItems.set(nameProperty, nameItem); - borderItems.set(borderImageProperty, imageItem); - borderItems.set(lineWidthProperty, lineWidthItem); - borderItems.set(lineStyleProperty, lineStyleItem); - borderItems.set(lineColorProperty, lineColorItem); - borderItems.set(positionProperty, positionItem); - // border-width, border-style, border-color - } else if (prop2 && lines.includes(prop2)) { - const nameItem = getPropertyItem(nameProperty, properties); - const imageItem = getPropertyItem(borderImageProperty, properties); - const lineProperty = `${prop1}-${prop2}`; - const lineItem = getPropertyItem(lineProperty, properties); - lineItem.value = value; - lineItem.priority = priority; - const propertyValue = hasVarFunc(value) ? "" : value; - if (propertyValue === "") { + } + borderItems.set(property, nameItem); + 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 + }; + const { lines, positions, name: nameProperty } = borderElements; + if (!value.length || !lines.includes(prop2)) { + return; + } + const nameItem = getPropertyItem(nameProperty, properties); + const imageItem = getPropertyItem(BORDER_IMAGE, properties); + const lineProperty = `${prop1}-${prop2}`; + const lineItem = getPropertyItem(lineProperty, properties); + if (value.length === 1) { + const [propertyValue] = value; + if (nameItem.value) { + if (hasVarFunc(nameItem.value)) { nameItem.value = ""; - } else if (isGlobalKeyword(propertyValue)) { - if (nameItem.value !== propertyValue) { - nameItem.value = ""; - } - } - for (const position of positions) { - 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, { - globalObject - }); - } else { - positionItem.value = ""; - } - longhandItem.value = propertyValue; - longhandItem.priority = priority; - borderItems.set(positionProperty, positionItem); - borderItems.set(longhandProperty, longhandItem); - } - borderItems.set(nameProperty, nameItem); - borderItems.set(borderImageProperty, imageItem); - borderItems.set(lineProperty, lineItem); - // border shorthand - } else { - const nameItem = getPropertyItem(nameProperty, properties); - const imageItem = getPropertyItem(borderImageProperty, properties); - const propertyValue = hasVarFunc(value) ? "" : value; - imageItem.value = propertyValue ? "none" : ""; - for (const line of lines) { - const lineProperty = `${prop1}-${line}`; - const lineItem = getPropertyItem(lineProperty, properties); - lineItem.value = propertyValue; - lineItem.priority = priority; - borderItems.set(lineProperty, lineItem); + } else if (propertyValue) { + nameItem.value = replaceBorderShorthandValue(propertyValue, nameItem.value, parseOpt); } - for (const position of positions) { - const positionProperty = `${prop1}-${position}`; - const positionItem = getPropertyItem(positionProperty, properties); - positionItem.value = propertyValue; - positionItem.priority = priority; - borderItems.set(positionProperty, positionItem); - for (const line of lines) { - const longhandProperty = `${positionProperty}-${line}`; - const longhandItem = getPropertyItem(longhandProperty, properties); - longhandItem.value = propertyValue; - longhandItem.priority = priority; - borderItems.set(longhandProperty, longhandItem); - } - } - borderItems.set(property, nameItem); - borderItems.set(borderImageProperty, imageItem); } - // Values of border-width, border-style, border-color - } else if (Array.isArray(value)) { - if (!value.length || !lines.includes(prop2)) { + } else { + nameItem.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 positions) { + 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(nameProperty, nameItem); + 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 { lines, positions, name: nameProperty } = borderElements; + const imageItem = getPropertyItem(BORDER_IMAGE, properties); + // Handle position shorthands. + if (prop2) { + if (!positions.includes(prop2)) { return; } const nameItem = getPropertyItem(nameProperty, properties); - const imageItem = getPropertyItem(borderImageProperty, properties); - const lineProperty = `${prop1}-${prop2}`; - const lineItem = getPropertyItem(lineProperty, properties); - if (value.length === 1) { - const [propertyValue] = value; - if (nameItem.value && propertyValue) { - nameItem.value = replaceBorderShorthandValue(propertyValue, nameItem.value, { - globalObject - }); - } - } else { - nameItem.value = ""; - } - lineItem.value = value.join(" "); - lineItem.priority = priority; - const positionValues = {}; - switch (value.length) { - case 1: { - const [val1] = value; - positionValues.top = val1; - positionValues.right = val1; - positionValues.bottom = val1; - positionValues.left = val1; - break; - } - case 2: { - const [val1, val2] = value; - positionValues.top = val1; - positionValues.right = val2; - positionValues.bottom = val1; - positionValues.left = val2; - break; - } - case 3: { - const [val1, val2, val3] = value; - positionValues.top = val1; - positionValues.right = val2; - positionValues.bottom = val3; - positionValues.left = val2; - break; - } - case 4: { - const [val1, val2, val3, val4] = value; - positionValues.top = val1; - positionValues.right = val2; - positionValues.bottom = val3; - positionValues.left = val4; - break; - } - default: { - return; + 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 (nameItem.value) { + for (const positionValue of Object.values(value)) { + if (!matchesBorderShorthandValue(property, positionValue, nameItem.value, parseOpt)) { + nameItem.value = ""; + break; + } } } - for (const position of positions) { - const positionProperty = `${prop1}-${position}`; - const positionItem = getPropertyItem(positionProperty, properties); - if (positionItem.value && positionValues[position]) { - positionItem.value = replaceBorderShorthandValue( - positionValues[position], - positionItem.value, - { - globalObject - } + positionItem.value = Object.values(value).join(" "); + positionItem.priority = priority; + for (const line of lines) { + 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 ); } - const longhandProperty = `${positionProperty}-${prop2}`; - const longhandItem = getPropertyItem(longhandProperty, properties); - longhandItem.value = positionValues[position]; + longhandItem.value = itemValue; longhandItem.priority = priority; - borderItems.set(positionProperty, positionItem); borderItems.set(longhandProperty, longhandItem); } borderItems.set(nameProperty, nameItem); - borderItems.set(borderImageProperty, imageItem); - borderItems.set(lineProperty, lineItem); - // Values of border, border-top, border-right, border-bottom, border-top. - } else if (value && typeof value === "object") { - // position shorthands - if (prop2) { - if (!positions.includes(prop2)) { - return; - } - const nameItem = getPropertyItem(nameProperty, properties); - const imageItem = getPropertyItem(borderImageProperty, 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}`; + 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 nameItem = 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(" "); + nameItem.value = propertyValue; + nameItem.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 positions) { + const positionProperty = `${prop1}-${position}`; const positionItem = getPropertyItem(positionProperty, properties); - if (nameItem.value) { - for (const positionValue of Object.values(value)) { - if ( - !matchesBorderShorthandValue(property, positionValue, nameItem.value, { - globalObject - }) - ) { - nameItem.value = ""; - break; - } - } - } - positionItem.value = Object.values(value).join(" "); + positionItem.value = propertyValue; positionItem.priority = priority; for (const line of lines) { - const longhandProperty = `${prop1}-${prop2}-${line}`; + const longhandProperty = `${positionProperty}-${line}`; const longhandItem = getPropertyItem(longhandProperty, properties); - if (Object.hasOwn(value, longhandProperty)) { - const itemValue = value[longhandProperty]; - if (line === "width") { - if (lineWidthItem.value) { - lineWidthItem.value = replacePositionValue( - itemValue, - splitValue(lineWidthItem.value), - prop2 - ); - } - } else if (line === "style") { - if (lineStyleItem.value) { - lineStyleItem.value = replacePositionValue( - itemValue, - splitValue(lineStyleItem.value), - prop2 - ); - } - } else if (line === "color") { - if (lineColorItem.value) { - lineColorItem.value = replacePositionValue( - itemValue, - splitValue(lineColorItem.value), - prop2 - ); - } - } - longhandItem.value = itemValue; - longhandItem.priority = priority; + const lineProperty = `${prop1}-${line}`; + if (Object.hasOwn(value, lineProperty)) { + longhandItem.value = value[lineProperty]; } else { - const itemValue = border.initialValues.get(`${prop1}-${line}`); - if (line === "width") { - if (lineWidthItem.value) { - lineWidthItem.value = replacePositionValue( - itemValue, - splitValue(lineWidthItem.value), - prop2 - ); - } - } else if (line === "style") { - if (lineStyleItem.value) { - lineStyleItem.value = replacePositionValue( - itemValue, - splitValue(lineStyleItem.value), - prop2 - ); - } - } else if (line === "color") { - if (lineColorItem.value) { - lineColorItem.value = replacePositionValue( - itemValue, - splitValue(lineColorItem.value), - prop2 - ); - } - } - longhandItem.value = itemValue; - longhandItem.priority = priority; + longhandItem.value = border.initialValues.get(lineProperty); } + longhandItem.priority = priority; borderItems.set(longhandProperty, longhandItem); } - borderItems.set(nameProperty, nameItem); - borderItems.set(borderImageProperty, imageItem); - borderItems.set(lineWidthProperty, lineWidthItem); - borderItems.set(lineStyleProperty, lineStyleItem); - borderItems.set(lineColorProperty, lineColorItem); borderItems.set(positionProperty, positionItem); - // border shorthand + } + borderItems.set(property, nameItem); + 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; + } + const { lines, name, positions } = borderElements; + if (!property.startsWith(name)) { + return; + } + let prop2, prop3; + if (property.length > name.length) { + // Check if next char is '-' + if (property.charCodeAt(name.length) !== 45) { + return; + } + // property is like "border-..." + const remainder = property.substring(name.length + 1); + const hyphenIndex = remainder.indexOf("-"); + if (hyphenIndex !== -1) { + prop2 = remainder.substring(0, hyphenIndex); + prop3 = remainder.substring(hyphenIndex + 1); } else { - const nameItem = getPropertyItem(prop1, properties); - const imageItem = getPropertyItem(borderImageProperty, 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(" "); - nameItem.value = propertyValue; - nameItem.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 positions) { - const positionProperty = `${prop1}-${position}`; - const positionItem = getPropertyItem(positionProperty, properties); - positionItem.value = propertyValue; - positionItem.priority = priority; - for (const line of lines) { - 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, nameItem); - borderItems.set(borderImageProperty, imageItem); - borderItems.set(lineWidthProperty, lineWidthItem); - borderItems.set(lineStyleProperty, lineStyleItem); - borderItems.set(lineColorProperty, lineColorItem); + prop2 = remainder; } - } else { + } + // prop1 is assumed to be 'name' since we checked startsWith(name) + if ( + (positions.includes(prop2) && prop3 && !lines.includes(prop3)) || + (lines.includes(prop2) && prop3) + ) { return; } + const parts = { + prop1: name, + 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(name)) { return; } - const borderProperties = new Map([[name, borderItems.get(name)]]); + const borderProps = new Map([[name, borderItems.get(name)]]); for (const line of lines) { const lineProperty = `${name}-${line}`; - const lineItem = borderItems.get(lineProperty) ?? - properties.get(lineProperty) ?? { - property: lineProperty, - value: "", - priority: "" - }; - borderProperties.set(lineProperty, lineItem); + const lineItem = + borderItems.get(lineProperty) ?? + properties.get(lineProperty) ?? + createPropertyItem(lineProperty); + borderProps.set(lineProperty, lineItem); } for (const position of positions) { const positionProperty = `${name}-${position}`; - const positionItem = borderItems.get(positionProperty) ?? - properties.get(positionProperty) ?? { - property: positionProperty, - value: "", - priority: "" - }; - borderProperties.set(positionProperty, positionItem); + const positionItem = + borderItems.get(positionProperty) ?? + properties.get(positionProperty) ?? + createPropertyItem(positionProperty); + borderProps.set(positionProperty, positionItem); for (const line of lines) { const longhandProperty = `${name}-${position}-${line}`; - const longhandItem = borderItems.get(longhandProperty) ?? - properties.get(longhandProperty) ?? { - property: longhandProperty, - value: "", - priority: "" - }; - borderProperties.set(longhandProperty, longhandItem); + const longhandItem = + borderItems.get(longhandProperty) ?? + properties.get(longhandProperty) ?? + createPropertyItem(longhandProperty); + borderProps.set(longhandProperty, longhandItem); } } - const borderImageItem = borderItems.get(borderImageProperty) ?? { - property: borderImageProperty, - value: "", - priority: "" - }; - borderProperties.set(borderImageProperty, borderImageItem); - return borderProperties; + 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} prior - The priority of the property. + * @returns {Array} A key-value pair for the generated property. + */ const generateBorderLineShorthand = (items, property, prior) => { const values = []; for (const [, item] of items) { const { value: itemValue } = item; values.push(itemValue); } - const value = exports.getPositionValue(values); + const value = getPositionValue(values); const priority = prior ? prior : ""; - return [property, { property, value, priority }]; + 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} prior - The priority of the property. + * @returns {Array} A key-value pair for the generated property. + */ const generateBorderPositionShorthand = (items, property, prior) => { const values = []; for (const [, item] of items) { @@ -862,272 +1099,174 @@ const generateBorderPositionShorthand = (items, property, prior) => { } const value = values.join(" "); const priority = prior ? prior : ""; - return [property, { property, value, priority }]; + return [property, createPropertyItem(property, value, priority)]; }; +/** + * Generates a border name shorthand property if all components match. + * + * @param {Set|Array} items - The collection of property values. + * @param {string} property - The shorthand property name to generate. + * @param {string} prior - The priority of the property. + * @returns {Array|undefined} A key-value pair for the generated property or undefined. + */ const generateBorderNameShorthand = (items, property, prior) => { const values = new Set(items); if (values.size === 1) { const value = values.keys().next().value; const priority = prior ? prior : ""; - return [property, { property, value, priority }]; + return [property, createPropertyItem(property, value, priority)]; } }; -const prepareBorderShorthands = (properties) => { - const lineWidthItems = new Map(); - const lineWidthPriorItems = new Map(); - const lineStyleItems = new Map(); - const lineStylePriorItems = new Map(); - const lineColorItems = new Map(); - const lineColorPriorItems = new Map(); - const positionTopItems = new Map(); - const positionTopPriorItems = new Map(); - const positionRightItems = new Map(); - const positionRightPriorItems = new Map(); - const positionBottomItems = new Map(); - const positionBottomPriorItems = new Map(); - const positionLeftItems = new Map(); - const positionLeftPriorItems = new Map(); - for (const [property, { priority, value }] of properties) { - const [, positionPart, linePart] = property.split("-"); - switch (linePart) { - case "width": { - if (priority) { - lineWidthPriorItems.set(property, { property, value, priority }); - } else { - lineWidthItems.set(property, { property, value, priority }); - } - break; - } - case "style": { - if (priority) { - lineStylePriorItems.set(property, { property, value, priority }); - } else { - lineStyleItems.set(property, { property, value, priority }); - } - break; - } - case "color": { - if (priority) { - lineColorPriorItems.set(property, { property, value, priority }); - } else { - lineColorItems.set(property, { property, value, priority }); - } - break; - } - default: - } - switch (positionPart) { - case "top": { - if (priority) { - positionTopPriorItems.set(property, { property, value, priority }); - } else { - positionTopItems.set(property, { property, value, priority }); - } - break; - } - case "right": { - if (priority) { - positionRightPriorItems.set(property, { property, value, priority }); - } else { - positionRightItems.set(property, { property, value, priority }); - } - break; - } - case "bottom": { - if (priority) { - positionBottomPriorItems.set(property, { property, value, priority }); - } else { - positionBottomItems.set(property, { property, value, priority }); - } - break; - } - case "left": { - if (priority) { - positionLeftPriorItems.set(property, { property, value, priority }); - } else { - positionLeftItems.set(property, { property, value, priority }); - } - break; - } - default: - } - } - if (lineWidthItems.size === 4) { - const [property, item] = generateBorderLineShorthand(lineWidthItems, "border-width") ?? []; - if (property && item) { - properties.set(property, item); - } - } else if (lineWidthPriorItems.size === 4) { - const [property, item] = - generateBorderLineShorthand(lineWidthPriorItems, "border-width", "important") ?? []; - if (property && item) { - properties.set(property, item); - } - } - if (lineStyleItems.size === 4) { - const [property, item] = generateBorderLineShorthand(lineStyleItems, "border-style") ?? []; - if (property && item) { - properties.set(property, item); - } - } else if (lineStylePriorItems.size === 4) { - const [property, item] = - generateBorderLineShorthand(lineStylePriorItems, "border-style", "important") ?? []; - if (property && item) { - properties.set(property, item); - } - } - if (lineColorItems.size === 4) { - const [property, item] = generateBorderLineShorthand(lineColorItems, "border-color") ?? []; - if (property && item) { - properties.set(property, item); - } - } else if (lineColorPriorItems.size === 4) { - const [property, item] = - generateBorderLineShorthand(lineColorPriorItems, "border-color", "important") ?? []; - if (property && item) { - properties.set(property, item); - } +const borderCollections = { + [WIDTH]: { + shorthand: BORDER_WIDTH, + generator: generateBorderLineShorthand, + items: new Map(), + priorItems: new Map() + }, + [STYLE]: { + shorthand: BORDER_STYLE, + generator: generateBorderLineShorthand, + items: new Map(), + priorItems: new Map() + }, + [COLOR]: { + shorthand: BORDER_COLOR, + generator: generateBorderLineShorthand, + items: new Map(), + priorItems: new Map() + }, + [TOP]: { + shorthand: BORDER_TOP, + generator: generateBorderPositionShorthand, + items: new Map(), + priorItems: new Map() + }, + [RIGHT]: { + shorthand: BORDER_RIGHT, + generator: generateBorderPositionShorthand, + items: new Map(), + priorItems: new Map() + }, + [BOTTOM]: { + shorthand: BORDER_BOTTOM, + generator: generateBorderPositionShorthand, + items: new Map(), + priorItems: new Map() + }, + [LEFT]: { + shorthand: BORDER_LEFT, + generator: generateBorderPositionShorthand, + items: new Map(), + priorItems: new Map() } - const nameItems = []; - const namePriorItems = []; - if (positionTopItems.size === 3) { - const [property, item] = generateBorderPositionShorthand(positionTopItems, "border-top") ?? []; - if (property && item) { - properties.set(property, item); - if (properties.has(borderImageProperty)) { - const { value: imageValue } = properties.get(borderImageProperty); - if (imageValue === "none") { - const { value: itemValue } = item; - nameItems.push(itemValue); - } - } - } - } else if (positionTopPriorItems.size === 3) { - const [property, item] = - generateBorderPositionShorthand(positionTopPriorItems, "border-top", "important") ?? []; - if (property && item) { - properties.set(property, item); - if (properties.has(borderImageProperty)) { - const { value: imageValue } = properties.get(borderImageProperty); - if (imageValue === "none") { - const { value: itemValue } = item; - namePriorItems.push(itemValue); - } - } - } +}; + +/** + * 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) => { + for (const collection of Object.values(borderCollections)) { + collection.items.clear(); + collection.priorItems.clear(); } - if (positionRightItems.size === 3) { - const [property, item] = - generateBorderPositionShorthand(positionRightItems, "border-right") ?? []; - if (property && item) { - properties.set(property, item); - if (properties.has(borderImageProperty)) { - const { value: imageValue } = properties.get(borderImageProperty); - if (imageValue === "none") { - const { value: itemValue } = item; - nameItems.push(itemValue); - } - } - } - } else if (positionRightPriorItems.size === 3) { - const [property, item] = - generateBorderPositionShorthand(positionRightPriorItems, "border-right", "important") ?? []; - if (property && item) { - properties.set(property, item); - if (properties.has(borderImageProperty)) { - const { value: imageValue } = properties.get(borderImageProperty); - if (imageValue === "none") { - const { value: itemValue } = item; - nameItems.push(itemValue); - } + 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 (positionBottomItems.size === 3) { - const [property, item] = - generateBorderPositionShorthand(positionBottomItems, "border-bottom") ?? []; - if (property && item) { - properties.set(property, item); - if (properties.has(borderImageProperty)) { - const { value: imageValue } = properties.get(borderImageProperty); - if (imageValue === "none") { - const { value: itemValue } = item; - nameItems.push(itemValue); - } + if (linePart && borderCollections[linePart]) { + const collection = borderCollections[linePart]; + if (priority) { + collection.priorItems.set(property, { property, value, priority }); + } else { + collection.items.set(property, { property, value, priority }); } } - } else if (positionBottomPriorItems.size === 3) { - const [property, item] = - generateBorderPositionShorthand(positionBottomPriorItems, "border-bottom", "important") ?? []; - if (property && item) { - properties.set(property, item); - if (properties.has(borderImageProperty)) { - const { value: imageValue } = properties.get(borderImageProperty); - if (imageValue === "none") { - const { value: itemValue } = item; - nameItems.push(itemValue); - } + if (positionPart && borderCollections[positionPart]) { + const collection = borderCollections[positionPart]; + if (priority) { + collection.priorItems.set(property, { property, value, priority }); + } else { + collection.items.set(property, { property, value, priority }); } } } - if (positionLeftItems.size === 3) { - const [property, item] = - generateBorderPositionShorthand(positionLeftItems, "border-left") ?? []; - if (property && item) { - properties.set(property, item); - if (properties.has(borderImageProperty)) { - const { value: imageValue } = properties.get(borderImageProperty); - if (imageValue === "none") { - const { value: itemValue } = item; - nameItems.push(itemValue); + const nameItems = []; + const namePriorItems = []; + for (const [key, collection] of Object.entries(borderCollections)) { + const { shorthand, generator, items, priorItems } = collection; + const requiredSize = [WIDTH, STYLE, COLOR].includes(key) ? 4 : 3; + if (items.size === requiredSize) { + const [property, item] = generator(items, shorthand) ?? []; + if (property && item) { + properties.set(property, item); + // For position shorthands (top/right/bottom/left), check border-image compatibility + if ([TOP, RIGHT, BOTTOM, LEFT].includes(key)) { + if (properties.has(BORDER_IMAGE)) { + const { value: imageValue } = properties.get(BORDER_IMAGE); + if (imageValue === NONE) { + nameItems.push(item.value); + } + } } } - } - } else if (positionLeftPriorItems.size === 3) { - const [property, item] = - generateBorderPositionShorthand(positionLeftPriorItems, "border-left", "important") ?? []; - if (property && item) { - properties.set(property, item); - if (properties.has(borderImageProperty)) { - const { value: imageValue } = properties.get(borderImageProperty); - if (imageValue === "none") { - const { value: itemValue } = item; - nameItems.push(itemValue); + } else if (priorItems.size === requiredSize) { + const [property, item] = generator(priorItems, shorthand, "important") ?? []; + if (property && item) { + properties.set(property, item); + // For position shorthands + if ([TOP, RIGHT, BOTTOM, LEFT].includes(key)) { + if (properties.has(BORDER_IMAGE)) { + const { value: imageValue } = properties.get(BORDER_IMAGE); + if (imageValue === NONE) { + namePriorItems.push(item.value); + } + } } } } } const mixedPriorities = nameItems.length && namePriorItems.length; - const imageItem = { - property: borderImageProperty, - value: "none", - priority: "" - }; + const imageItem = createPropertyItem(BORDER_IMAGE, NONE); if (nameItems.length === 4) { - const [property, item] = generateBorderNameShorthand(nameItems, "border") ?? []; + const [property, item] = generateBorderNameShorthand(nameItems, BORDER) ?? []; if (property && item) { properties.set(property, item); - properties.delete(borderImageProperty); - properties.set(borderImageProperty, imageItem); + properties.delete(BORDER_IMAGE); + properties.set(BORDER_IMAGE, imageItem); } } else if (namePriorItems.length === 4) { - const [property, item] = - generateBorderNameShorthand(namePriorItems, "border", "important") ?? []; + const [property, item] = generateBorderNameShorthand(namePriorItems, BORDER, "important") ?? []; if (property && item) { properties.set(property, item); - properties.delete(borderImageProperty); - properties.set(borderImageProperty, imageItem); + properties.delete(BORDER_IMAGE); + properties.set(BORDER_IMAGE, imageItem); } - } else if (properties.has(borderImageProperty)) { - const { value: imageValue } = properties.get(borderImageProperty); - if (imageValue === "none") { + } else if (properties.has(BORDER_IMAGE)) { + const { value: imageValue } = properties.get(BORDER_IMAGE); + if (imageValue === NONE) { if (mixedPriorities) { - properties.delete(borderImageProperty); - properties.set(borderImageProperty, imageItem); + properties.delete(BORDER_IMAGE); + properties.set(BORDER_IMAGE, imageItem); } else { - properties.delete(borderImageProperty); + properties.delete(BORDER_IMAGE); } } } @@ -1149,48 +1288,194 @@ const prepareBorderShorthands = (properties) => { } return new Map([...items, ...priorItems]); } - if (properties.has(borderImageProperty)) { - properties.delete(borderImageProperty); - properties.set(borderImageProperty, imageItem); + if (properties.has(BORDER_IMAGE)) { + properties.delete(BORDER_IMAGE); + properties.set(BORDER_IMAGE, imageItem); } return properties; }; -exports.prepareProperties = (properties, opt = {}) => { - const { globalObject } = opt; +/** + * 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; +}; + +/** + * 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 { positions } = borderElements; + const longhandProperties = new Map(); + for (const [property, item] of borders) { + if (shorthandProperties.has(property)) { + const { value, priority } = item; + if (property === BORDER) { + 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 positions) { + const longhandProperty = `${namePart}-${position}-${linePart}`; + const longhandItem = createPropertyItem(longhandProperty, lineValue, priority); + if (longhandProperties.has(longhandProperty)) { + const { priority: longhandPriority } = longhandProperties.get(longhandProperty); + if (!longhandPriority) { + longhandProperties.delete(longhandProperty); + longhandProperties.set(longhandProperty, longhandItem); + } + } else { + longhandProperties.set(longhandProperty, longhandItem); + } + } + } + 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 positions) { + const longhandProperty = `${namePart}-${position}-${linePart}`; + const longhandValue = getPositionValue(parsedItem, position); + const longhandItem = createPropertyItem(longhandProperty, longhandValue, priority); + if (longhandProperties.has(longhandProperty)) { + const { priority: longhandPriority } = longhandProperties.get(longhandProperty); + if (!longhandPriority) { + longhandProperties.delete(longhandProperty); + longhandProperties.set(longhandProperty, longhandItem); + } + } else { + longhandProperties.set(longhandProperty, longhandItem); + } + } + } 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); + if (longhandProperties.has(longhandProperty)) { + const { priority: longhandPriority } = longhandProperties.get(longhandProperty); + if (!longhandPriority) { + longhandProperties.delete(longhandProperty); + longhandProperties.set(longhandProperty, longhandItem); + } + } else { + longhandProperties.set(longhandProperty, longhandItem); + } + } + } + } + } 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 prepareShorthands = new Map(); - const borderProperties = 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 } = implementedProperties.get(property) ?? {}; - if (exports.borderProperties.has(property)) { - borderProperties.set(property, { property, value, priority }); - } else if (exports.shorthandProperties.has(shorthandProperty)) { - if (!prepareShorthands.has(shorthandProperty)) { - prepareShorthands.set(shorthandProperty, new Map()); + 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 = prepareShorthands.get(shorthandProperty); + 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 }); - prepareShorthands.set(shorthandProperty, longhandItems); + shorthands.set(shorthandProperty, longhandItems); } else { parsedProperties.delete(shorthandProperty); } } else { longhandItems.set(property, { property, value, priority }); - prepareShorthands.set(shorthandProperty, longhandItems); + shorthands.set(shorthandProperty, longhandItems); } parsedProperties.set(property, item); - } else if (exports.shorthandProperties.has(property)) { - const shorthandItem = exports.shorthandProperties.get(property); - const parsedValues = shorthandItem.parse(value, { - globalObject - }); + } 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; @@ -1204,174 +1489,77 @@ exports.prepareProperties = (properties, opt = {}) => { } } const { position } = longhandItem; - const longhandValue = exports.getPositionValue([parsedValue], position); - parsedProperties.set(longhandProperty, { - property: longhandProperty, - value: longhandValue, - priority - }); + 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, { - property: longhandProperty, - value: longhandValue, - priority - }); + parsedProperties.set( + longhandProperty, + createPropertyItem(longhandProperty, longhandValue, priority) + ); } } - } else if (parsedValues) { + } else if (parsedValues && typeof parsedValues !== "string") { for (const longhandProperty of Object.keys(parsedValues)) { const longhandValue = parsedValues[longhandProperty]; - parsedProperties.set(longhandProperty, { - property: longhandProperty, - value: longhandValue, - priority - }); + parsedProperties.set( + longhandProperty, + createPropertyItem(longhandProperty, longhandValue, priority) + ); } } if (!omitShorthandProperty) { - parsedProperties.set(property, { property, value, priority }); + if (property === BACKGROUND) { + hasPrecedingBackground = true; + } + parsedProperties.set(property, createPropertyItem(property, value, priority)); } } else { - parsedProperties.set(property, { property, value, priority }); - } - } - if (prepareShorthands.size) { - for (const [property, item] of prepareShorthands) { - const shorthandItem = exports.shorthandProperties.get(property); - if (item.size === shorthandItem.shorthandFor.size) { - if (shorthandItem.position) { - const positionValues = []; - let priority = ""; - for (const { value: longhandValue, priority: longhandPriority } of item.values()) { - positionValues.push(longhandValue); - if (longhandPriority) { - priority = longhandPriority; - } - } - const value = exports.getPositionValue(positionValues, shorthandItem.position); - parsedProperties.set(property, { + parsedProperties.set(property, createPropertyItem(property, value, priority)); + if (hasPrecedingBackground) { + const { value: shorthandValue, priority: shorthandPriority } = properties.get(BACKGROUND); + if ((!shorthandPriority || priority) && !hasVarFunc(shorthandValue)) { + const replacedShorthandValue = replaceBackgroundShorthand( property, - value, - priority - }); + parsedProperties, + parseOpt + ); + properties.delete(BACKGROUND); + properties.set( + BACKGROUND, + createPropertyItem(BACKGROUND, replacedShorthandValue, shorthandPriority) + ); } } } } - if (borderProperties.size) { - const longhandProperties = new Map(); - for (const [property, item] of borderProperties) { - if (exports.shorthandProperties.has(property)) { - const { value, priority } = item; - if (property === "border") { - const lineItems = border.parse(value, { - globalObject - }); - for (const [key, initialValue] of border.initialValues) { - if (!Object.hasOwn(lineItems, key)) { - lineItems[key] = initialValue; - } - } - for (const lineProperty of Object.keys(lineItems)) { - const [namePart, linePart] = lineProperty.split("-"); - const lineValue = lineItems[lineProperty]; - for (const position of positions) { - const longhandProperty = `${namePart}-${position}-${linePart}`; - const longhandItem = { - property: longhandProperty, - value: lineValue, - priority - }; - if (longhandProperties.has(longhandProperty)) { - const { priority: longhandPriority } = longhandProperties.get(longhandProperty); - if (!longhandPriority) { - longhandProperties.delete(longhandProperty); - longhandProperties.set(longhandProperty, longhandItem); - } - } else { - longhandProperties.set(longhandProperty, longhandItem); - } - } - } - if (value) { - longhandProperties.set(borderImageProperty, { - property: borderImageProperty, - value: "none", - priority - }); - } - } else { - const shorthandItem = exports.shorthandProperties.get(property); - const parsedItem = shorthandItem.parse(value, { - globalObject - }); - if (Array.isArray(parsedItem)) { - const [namePart, linePart] = property.split("-"); - for (const position of positions) { - const longhandProperty = `${namePart}-${position}-${linePart}`; - const longhandValue = exports.getPositionValue(parsedItem, position); - const longhandItem = { - property: longhandProperty, - value: longhandValue, - priority - }; - if (longhandProperties.has(longhandProperty)) { - const { priority: longhandPriority } = longhandProperties.get(longhandProperty); - if (!longhandPriority) { - longhandProperties.delete(longhandProperty); - longhandProperties.set(longhandProperty, longhandItem); - } - } else { - longhandProperties.set(longhandProperty, longhandItem); - } - } - } 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 = { - property: longhandProperty, - value: longhandValue, - priority - }; - if (longhandProperties.has(longhandProperty)) { - const { priority: longhandPriority } = longhandProperties.get(longhandProperty); - if (!longhandPriority) { - longhandProperties.delete(longhandProperty); - longhandProperties.set(longhandProperty, longhandItem); - } - } else { - longhandProperties.set(longhandProperty, longhandItem); - } - } - } - } - } else if (longhandProperties.has(property)) { - const { priority } = longhandProperties.get(property); - if (!priority) { - longhandProperties.delete(property); - longhandProperties.set(property, item); - } - } else { - longhandProperties.set(property, item); - } + if (shorthands.size) { + const shorthandItems = processShorthandProperties(shorthands); + for (const [property, item] of shorthandItems) { + parsedProperties.set(property, item); } - const normalizedProperties = prepareBorderShorthands(longhandProperties); - for (const [property, item] of normalizedProperties) { + } + if (borders.size) { + const borderItems = processBorderProperties(borders, parseOpt); + for (const [property, item] of borderItems) { parsedProperties.set(property, item); } } return parsedProperties; }; -exports.normalizeBorderProperties = (properties) => { +/** + * 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) => { const { lines, name, positions } = borderElements; if (properties.has(name)) { for (const line of lines) { @@ -1415,3 +1603,12 @@ exports.normalizeBorderProperties = (properties) => { } return properties; }; + +module.exports = { + borderProperties, + getPositionValue, + normalizeProperties, + prepareBorderProperties, + prepareProperties, + shorthandProperties +}; From 141980581b724d1dd348b01901e70d143eba12f2 Mon Sep 17 00:00:00 2001 From: "asamuzaK (Kazz)" Date: Sun, 14 Dec 2025 13:38:33 +0900 Subject: [PATCH 03/12] Optimize code --- lib/normalize.js | 151 +++++++++++++++++++++-------------------------- 1 file changed, 68 insertions(+), 83 deletions(-) diff --git a/lib/normalize.js b/lib/normalize.js index 778064fd..861120f3 100644 --- a/lib/normalize.js +++ b/lib/normalize.js @@ -44,6 +44,7 @@ const TRBL_INDICES = { [LEFT]: 3 }; +/* shorthands */ const shorthandProperties = new Map([ [BACKGROUND, background], [ @@ -71,6 +72,7 @@ const shorthandProperties = new Map([ ["padding", padding] ]); +/* borders */ const borderProperties = new Set([ BORDER, BORDER_IMAGE, @@ -81,12 +83,8 @@ const borderProperties = new Set([ ...borderBottom.shorthandFor.keys(), ...borderLeft.shorthandFor.keys() ]); - -const borderElements = { - name: BORDER, - positions: [TOP, RIGHT, BOTTOM, LEFT], - lines: [WIDTH, STYLE, COLOR] -}; +const borderPositions = new Set([TOP, RIGHT, BOTTOM, LEFT]); +const borderLines = new Set([WIDTH, STYLE, COLOR]); /** * Ensures consistent object shape. @@ -528,8 +526,7 @@ const prepareBorderStringValue = ({ globalObject, options }; - const { lines, positions, name: nameProperty } = borderElements; - const nameItem = getPropertyItem(nameProperty, properties); + const nameItem = getPropertyItem(BORDER, properties); const imageItem = getPropertyItem(BORDER_IMAGE, properties); // Handle longhand properties. if (prop3) { @@ -573,13 +570,13 @@ const prepareBorderStringValue = ({ positionItem.value = ""; } } - borderItems.set(nameProperty, nameItem); + borderItems.set(BORDER, nameItem); 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 && positions.includes(prop2)) { + } else if (prop2 && borderPositions.has(prop2)) { const lineWidthProperty = `${prop1}-width`; const lineWidthItem = getPropertyItem(lineWidthProperty, properties); const lineStyleProperty = `${prop1}-style`; @@ -635,21 +632,21 @@ const prepareBorderStringValue = ({ lineColorItem.value = propertyValue; } } - for (const line of lines) { + 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(nameProperty, nameItem); + borderItems.set(BORDER, nameItem); 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 && lines.includes(prop2)) { + } else if (prop2 && borderLines.has(prop2)) { const lineProperty = `${prop1}-${prop2}`; const lineItem = getPropertyItem(lineProperty, properties); lineItem.value = value; @@ -662,7 +659,7 @@ const prepareBorderStringValue = ({ nameItem.value = ""; } } - for (const position of positions) { + for (const position of borderPositions) { const positionProperty = `${prop1}-${position}`; const positionItem = getPropertyItem(positionProperty, properties); const longhandProperty = `${prop1}-${position}-${prop2}`; @@ -681,27 +678,27 @@ const prepareBorderStringValue = ({ borderItems.set(positionProperty, positionItem); borderItems.set(longhandProperty, longhandItem); } - borderItems.set(nameProperty, nameItem); + borderItems.set(BORDER, nameItem); 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 lines) { + 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 positions) { + 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 lines) { + for (const line of borderLines) { const longhandProperty = `${positionProperty}-${line}`; const longhandItem = getPropertyItem(longhandProperty, properties); longhandItem.value = propertyValue; @@ -732,11 +729,10 @@ const prepareBorderArrayValue = ({ value, priority, properties, parts, opt, bord globalObject, options }; - const { lines, positions, name: nameProperty } = borderElements; - if (!value.length || !lines.includes(prop2)) { + if (!value.length || !borderLines.has(prop2)) { return; } - const nameItem = getPropertyItem(nameProperty, properties); + const nameItem = getPropertyItem(BORDER, properties); const imageItem = getPropertyItem(BORDER_IMAGE, properties); const lineProperty = `${prop1}-${prop2}`; const lineItem = getPropertyItem(lineProperty, properties); @@ -786,7 +782,7 @@ const prepareBorderArrayValue = ({ value, priority, properties, parts, opt, bord positionValues.left = val1; } } - for (const position of positions) { + for (const position of borderPositions) { const positionProperty = `${prop1}-${position}`; const positionItem = getPropertyItem(positionProperty, properties); if (positionItem.value && positionValues[position]) { @@ -803,7 +799,7 @@ const prepareBorderArrayValue = ({ value, priority, properties, parts, opt, bord borderItems.set(positionProperty, positionItem); borderItems.set(longhandProperty, longhandItem); } - borderItems.set(nameProperty, nameItem); + borderItems.set(BORDER, nameItem); borderItems.set(BORDER_IMAGE, imageItem); borderItems.set(lineProperty, lineItem); }; @@ -835,14 +831,13 @@ const prepareBorderObjectValue = ({ globalObject, options }; - const { lines, positions, name: nameProperty } = borderElements; const imageItem = getPropertyItem(BORDER_IMAGE, properties); // Handle position shorthands. if (prop2) { - if (!positions.includes(prop2)) { + if (!borderPositions.has(prop2)) { return; } - const nameItem = getPropertyItem(nameProperty, properties); + const nameItem = getPropertyItem(BORDER, properties); const lineWidthProperty = `${prop1}-width`; const lineWidthItem = getPropertyItem(lineWidthProperty, properties); const lineStyleProperty = `${prop1}-style`; @@ -861,7 +856,7 @@ const prepareBorderObjectValue = ({ } positionItem.value = Object.values(value).join(" "); positionItem.priority = priority; - for (const line of lines) { + for (const line of borderLines) { const longhandProperty = `${prop1}-${prop2}-${line}`; const longhandItem = getPropertyItem(longhandProperty, properties); const itemValue = Object.hasOwn(value, longhandProperty) @@ -890,7 +885,7 @@ const prepareBorderObjectValue = ({ longhandItem.priority = priority; borderItems.set(longhandProperty, longhandItem); } - borderItems.set(nameProperty, nameItem); + borderItems.set(BORDER, nameItem); borderItems.set(BORDER_IMAGE, imageItem); borderItems.set(lineWidthProperty, lineWidthItem); borderItems.set(lineStyleProperty, lineStyleItem); @@ -927,12 +922,12 @@ const prepareBorderObjectValue = ({ lineColorItem.value = border.initialValues.get(lineColorProperty); } lineColorItem.priority = priority; - for (const position of positions) { + for (const position of borderPositions) { const positionProperty = `${prop1}-${position}`; const positionItem = getPropertyItem(positionProperty, properties); positionItem.value = propertyValue; positionItem.priority = priority; - for (const line of lines) { + for (const line of borderLines) { const longhandProperty = `${positionProperty}-${line}`; const longhandItem = getPropertyItem(longhandProperty, properties); const lineProperty = `${prop1}-${line}`; @@ -968,18 +963,17 @@ const prepareBorderProperties = (property, value, priority, properties, opt = {} if (typeof property !== "string" || value === null) { return; } - const { lines, name, positions } = borderElements; - if (!property.startsWith(name)) { + if (!property.startsWith(BORDER)) { return; } let prop2, prop3; - if (property.length > name.length) { + if (property.length > BORDER.length) { // Check if next char is '-' - if (property.charCodeAt(name.length) !== 45) { + if (property.charCodeAt(BORDER.length) !== 45) { return; } // property is like "border-..." - const remainder = property.substring(name.length + 1); + const remainder = property.substring(BORDER.length + 1); const hyphenIndex = remainder.indexOf("-"); if (hyphenIndex !== -1) { prop2 = remainder.substring(0, hyphenIndex); @@ -988,15 +982,14 @@ const prepareBorderProperties = (property, value, priority, properties, opt = {} prop2 = remainder; } } - // prop1 is assumed to be 'name' since we checked startsWith(name) if ( - (positions.includes(prop2) && prop3 && !lines.includes(prop3)) || - (lines.includes(prop2) && prop3) + (borderPositions.has(prop2) && prop3 && !borderLines.has(prop3)) || + (borderLines.has(prop2) && prop3) ) { return; } const parts = { - prop1: name, + prop1: BORDER, prop2, prop3 }; @@ -1031,27 +1024,27 @@ const prepareBorderProperties = (property, value, priority, properties, opt = {} borderItems }); } - if (!borderItems.has(name)) { + if (!borderItems.has(BORDER)) { return; } - const borderProps = new Map([[name, borderItems.get(name)]]); - for (const line of lines) { - const lineProperty = `${name}-${line}`; + const borderProps = new Map([[BORDER, borderItems.get(BORDER)]]); + for (const line of borderLines) { + const lineProperty = `${BORDER}-${line}`; const lineItem = borderItems.get(lineProperty) ?? properties.get(lineProperty) ?? createPropertyItem(lineProperty); borderProps.set(lineProperty, lineItem); } - for (const position of positions) { - const positionProperty = `${name}-${position}`; + for (const position of borderPositions) { + const positionProperty = `${BORDER}-${position}`; const positionItem = borderItems.get(positionProperty) ?? properties.get(positionProperty) ?? createPropertyItem(positionProperty); borderProps.set(positionProperty, positionItem); - for (const line of lines) { - const longhandProperty = `${name}-${position}-${line}`; + for (const line of borderLines) { + const longhandProperty = `${BORDER}-${position}-${line}`; const longhandItem = borderItems.get(longhandProperty) ?? properties.get(longhandProperty) ?? @@ -1212,18 +1205,15 @@ const prepareBorderShorthands = (properties) => { const namePriorItems = []; for (const [key, collection] of Object.entries(borderCollections)) { const { shorthand, generator, items, priorItems } = collection; - const requiredSize = [WIDTH, STYLE, COLOR].includes(key) ? 4 : 3; + const requiredSize = borderLines.has(key) ? 4 : 3; if (items.size === requiredSize) { const [property, item] = generator(items, shorthand) ?? []; if (property && item) { properties.set(property, item); - // For position shorthands (top/right/bottom/left), check border-image compatibility - if ([TOP, RIGHT, BOTTOM, LEFT].includes(key)) { - if (properties.has(BORDER_IMAGE)) { - const { value: imageValue } = properties.get(BORDER_IMAGE); - if (imageValue === NONE) { - nameItems.push(item.value); - } + if (borderPositions.has(key) && properties.has(BORDER_IMAGE)) { + const { value: imageValue } = properties.get(BORDER_IMAGE); + if (imageValue === NONE) { + nameItems.push(item.value); } } } @@ -1231,13 +1221,10 @@ const prepareBorderShorthands = (properties) => { const [property, item] = generator(priorItems, shorthand, "important") ?? []; if (property && item) { properties.set(property, item); - // For position shorthands - if ([TOP, RIGHT, BOTTOM, LEFT].includes(key)) { - if (properties.has(BORDER_IMAGE)) { - const { value: imageValue } = properties.get(BORDER_IMAGE); - if (imageValue === NONE) { - namePriorItems.push(item.value); - } + if (borderPositions.has(key) && properties.has(BORDER_IMAGE)) { + const { value: imageValue } = properties.get(BORDER_IMAGE); + if (imageValue === NONE) { + namePriorItems.push(item.value); } } } @@ -1329,7 +1316,6 @@ const processShorthandProperties = (shorthands) => { * @returns {Map} A map of fully processed and normalized border properties. */ const processBorderProperties = (borders, parseOpt) => { - const { positions } = borderElements; const longhandProperties = new Map(); for (const [property, item] of borders) { if (shorthandProperties.has(property)) { @@ -1354,7 +1340,7 @@ const processBorderProperties = (borders, parseOpt) => { linePart = ""; } const lineValue = lineItems[lineProperty]; - for (const position of positions) { + for (const position of borderPositions) { const longhandProperty = `${namePart}-${position}-${linePart}`; const longhandItem = createPropertyItem(longhandProperty, lineValue, priority); if (longhandProperties.has(longhandProperty)) { @@ -1383,7 +1369,7 @@ const processBorderProperties = (borders, parseOpt) => { } else { namePart = property; } - for (const position of positions) { + for (const position of borderPositions) { const longhandProperty = `${namePart}-${position}-${linePart}`; const longhandValue = getPositionValue(parsedItem, position); const longhandItem = createPropertyItem(longhandProperty, longhandValue, priority); @@ -1560,36 +1546,35 @@ const prepareProperties = (properties, opt = {}) => { * @returns {Map} The normalized properties map. */ const normalizeProperties = (properties) => { - const { lines, name, positions } = borderElements; - if (properties.has(name)) { - for (const line of lines) { - properties.delete(`${name}-${line}`); + if (properties.has(BORDER)) { + for (const line of borderLines) { + properties.delete(`${BORDER}-${line}`); } - for (const position of positions) { - properties.delete(`${name}-${position}`); - for (const line of lines) { - properties.delete(`${name}-${position}-${line}`); + for (const position of borderPositions) { + properties.delete(`${BORDER}-${position}`); + for (const line of borderLines) { + properties.delete(`${BORDER}-${position}-${line}`); } } - properties.delete(`${name}-image`); + properties.delete(`${BORDER}-image`); } - for (const line of lines) { - const lineProperty = `${name}-${line}`; + for (const line of borderLines) { + const lineProperty = `${BORDER}-${line}`; if (properties.has(lineProperty)) { - for (const position of positions) { - const positionProperty = `${name}-${position}`; - const longhandProperty = `${name}-${position}-${line}`; + for (const position of borderPositions) { + const positionProperty = `${BORDER}-${position}`; + const longhandProperty = `${BORDER}-${position}-${line}`; properties.delete(positionProperty); properties.delete(longhandProperty); } } } - for (const position of positions) { - const positionProperty = `${name}-${position}`; + for (const position of borderPositions) { + const positionProperty = `${BORDER}-${position}`; if (properties.has(positionProperty)) { const longhandProperties = []; - for (const line of lines) { - const longhandProperty = `${name}-${position}-${line}`; + for (const line of borderLines) { + const longhandProperty = `${BORDER}-${position}-${line}`; longhandProperties.push(longhandProperty); } if (longhandProperties.length === 3) { From 75fc72ececf8becd77a382c42e9c9bee4a919fce Mon Sep 17 00:00:00 2001 From: "asamuzaK (Kazz)" Date: Wed, 17 Dec 2025 23:47:02 +0900 Subject: [PATCH 04/12] Refactor border shorthand generators to use default priority Updated generateBorderLineShorthand, generateBorderPositionShorthand, and generateBorderNameShorthand to use a default parameter for priority instead of reassigning within the function. This simplifies the function signatures and improves code clarity. --- lib/normalize.js | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/lib/normalize.js b/lib/normalize.js index 861120f3..18a95322 100644 --- a/lib/normalize.js +++ b/lib/normalize.js @@ -1062,17 +1062,16 @@ const prepareBorderProperties = (property, value, priority, properties, opt = {} * * @param {Map} items - The map of collected property items. * @param {string} property - The shorthand property name to generate. - * @param {string} prior - The priority of the property. + * @param {string} [priority=""] - The priority of the property. * @returns {Array} A key-value pair for the generated property. */ -const generateBorderLineShorthand = (items, property, prior) => { +const generateBorderLineShorthand = (items, property, priority = "") => { const values = []; for (const [, item] of items) { const { value: itemValue } = item; values.push(itemValue); } const value = getPositionValue(values); - const priority = prior ? prior : ""; return [property, createPropertyItem(property, value, priority)]; }; @@ -1081,17 +1080,16 @@ const generateBorderLineShorthand = (items, property, prior) => { * * @param {Map} items - The map of collected property items. * @param {string} property - The shorthand property name to generate. - * @param {string} prior - The priority of the property. + * @param {string} [priority=""] - The priority of the property. * @returns {Array} A key-value pair for the generated property. */ -const generateBorderPositionShorthand = (items, property, prior) => { +const generateBorderPositionShorthand = (items, property, priority = "") => { const values = []; for (const [, item] of items) { const { value: itemValue } = item; values.push(itemValue); } const value = values.join(" "); - const priority = prior ? prior : ""; return [property, createPropertyItem(property, value, priority)]; }; @@ -1100,14 +1098,13 @@ const generateBorderPositionShorthand = (items, property, prior) => { * * @param {Set|Array} items - The collection of property values. * @param {string} property - The shorthand property name to generate. - * @param {string} prior - The priority of the property. + * @param {string} [priority=""] - The priority of the property. * @returns {Array|undefined} A key-value pair for the generated property or undefined. */ -const generateBorderNameShorthand = (items, property, prior) => { +const generateBorderNameShorthand = (items, property, priority = "") => { const values = new Set(items); if (values.size === 1) { const value = values.keys().next().value; - const priority = prior ? prior : ""; return [property, createPropertyItem(property, value, priority)]; } }; From 7491e431dadd023826de8fe64f2d3b472399c914 Mon Sep 17 00:00:00 2001 From: "asamuzaK (Kazz)" Date: Thu, 18 Dec 2025 00:05:24 +0900 Subject: [PATCH 05/12] Refactor border property item retrieval logic Replaces direct calls to createPropertyItem with getPropertyItem for border-related properties in prepareBorderProperties, streamlining property item retrieval and improving code consistency. --- lib/normalize.js | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/lib/normalize.js b/lib/normalize.js index 18a95322..fd892c7c 100644 --- a/lib/normalize.js +++ b/lib/normalize.js @@ -1030,29 +1030,23 @@ const prepareBorderProperties = (property, value, priority, properties, opt = {} const borderProps = new Map([[BORDER, borderItems.get(BORDER)]]); for (const line of borderLines) { const lineProperty = `${BORDER}-${line}`; - const lineItem = - borderItems.get(lineProperty) ?? - properties.get(lineProperty) ?? - createPropertyItem(lineProperty); + const lineItem = borderItems.get(lineProperty) ?? getPropertyItem(lineProperty, properties); borderProps.set(lineProperty, lineItem); } for (const position of borderPositions) { const positionProperty = `${BORDER}-${position}`; const positionItem = - borderItems.get(positionProperty) ?? - properties.get(positionProperty) ?? - createPropertyItem(positionProperty); + borderItems.get(positionProperty) ?? getPropertyItem(positionProperty, properties); borderProps.set(positionProperty, positionItem); for (const line of borderLines) { const longhandProperty = `${BORDER}-${position}-${line}`; const longhandItem = - borderItems.get(longhandProperty) ?? - properties.get(longhandProperty) ?? - createPropertyItem(longhandProperty); + borderItems.get(longhandProperty) ?? getPropertyItem(longhandProperty, properties); borderProps.set(longhandProperty, longhandItem); } } - const borderImageItem = borderItems.get(BORDER_IMAGE) ?? createPropertyItem(BORDER_IMAGE); + const borderImageItem = + borderItems.get(BORDER_IMAGE) ?? getPropertyItem(BORDER_IMAGE, properties); borderProps.set(BORDER_IMAGE, borderImageItem); return borderProps; }; From 66437d1d888a3124529363599d5021d30a693bd7 Mon Sep 17 00:00:00 2001 From: "asamuzaK (Kazz)" Date: Thu, 18 Dec 2025 08:48:51 +0900 Subject: [PATCH 06/12] Refactor border shorthand collections and priority handling Replaces the borderCollections object with borderCollectionConfig and dynamically constructs borderCollections with items and priorityItems maps. Renames priorItems to priorityItems throughout for clarity and consistency, and updates related logic in prepareBorderShorthands. --- lib/normalize.js | 58 ++++++++++++++++++++---------------------------- 1 file changed, 24 insertions(+), 34 deletions(-) diff --git a/lib/normalize.js b/lib/normalize.js index fd892c7c..fbaa4c70 100644 --- a/lib/normalize.js +++ b/lib/normalize.js @@ -1103,48 +1103,34 @@ const generateBorderNameShorthand = (items, property, priority = "") => { } }; -const borderCollections = { +const borderCollectionConfig = { [WIDTH]: { shorthand: BORDER_WIDTH, - generator: generateBorderLineShorthand, - items: new Map(), - priorItems: new Map() + generator: generateBorderLineShorthand }, [STYLE]: { shorthand: BORDER_STYLE, - generator: generateBorderLineShorthand, - items: new Map(), - priorItems: new Map() + generator: generateBorderLineShorthand }, [COLOR]: { shorthand: BORDER_COLOR, - generator: generateBorderLineShorthand, - items: new Map(), - priorItems: new Map() + generator: generateBorderLineShorthand }, [TOP]: { shorthand: BORDER_TOP, - generator: generateBorderPositionShorthand, - items: new Map(), - priorItems: new Map() + generator: generateBorderPositionShorthand }, [RIGHT]: { shorthand: BORDER_RIGHT, - generator: generateBorderPositionShorthand, - items: new Map(), - priorItems: new Map() + generator: generateBorderPositionShorthand }, [BOTTOM]: { shorthand: BORDER_BOTTOM, - generator: generateBorderPositionShorthand, - items: new Map(), - priorItems: new Map() + generator: generateBorderPositionShorthand }, [LEFT]: { shorthand: BORDER_LEFT, - generator: generateBorderPositionShorthand, - items: new Map(), - priorItems: new Map() + generator: generateBorderPositionShorthand } }; @@ -1155,9 +1141,13 @@ const borderCollections = { * @returns {Map} The updated map with consolidated border properties. */ const prepareBorderShorthands = (properties) => { - for (const collection of Object.values(borderCollections)) { - collection.items.clear(); - collection.priorItems.clear(); + 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; @@ -1178,7 +1168,7 @@ const prepareBorderShorthands = (properties) => { if (linePart && borderCollections[linePart]) { const collection = borderCollections[linePart]; if (priority) { - collection.priorItems.set(property, { property, value, priority }); + collection.priorityItems.set(property, { property, value, priority }); } else { collection.items.set(property, { property, value, priority }); } @@ -1186,7 +1176,7 @@ const prepareBorderShorthands = (properties) => { if (positionPart && borderCollections[positionPart]) { const collection = borderCollections[positionPart]; if (priority) { - collection.priorItems.set(property, { property, value, priority }); + collection.priorityItems.set(property, { property, value, priority }); } else { collection.items.set(property, { property, value, priority }); } @@ -1195,7 +1185,7 @@ const prepareBorderShorthands = (properties) => { const nameItems = []; const namePriorItems = []; for (const [key, collection] of Object.entries(borderCollections)) { - const { shorthand, generator, items, priorItems } = collection; + const { shorthand, generator, items, priorityItems } = collection; const requiredSize = borderLines.has(key) ? 4 : 3; if (items.size === requiredSize) { const [property, item] = generator(items, shorthand) ?? []; @@ -1208,8 +1198,8 @@ const prepareBorderShorthands = (properties) => { } } } - } else if (priorItems.size === requiredSize) { - const [property, item] = generator(priorItems, shorthand, "important") ?? []; + } 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)) { @@ -1250,11 +1240,11 @@ const prepareBorderShorthands = (properties) => { } if (mixedPriorities) { const items = []; - const priorItems = []; + const priorityItems = []; for (const item of properties) { const [, { priority }] = item; if (priority) { - priorItems.push(item); + priorityItems.push(item); } else { items.push(item); } @@ -1262,9 +1252,9 @@ const prepareBorderShorthands = (properties) => { const firstPropertyKey = properties.keys().next().value; const { priority: firstPropertyPriority } = properties.get(firstPropertyKey); if (firstPropertyPriority) { - return new Map([...priorItems, ...items]); + return new Map([...priorityItems, ...items]); } - return new Map([...items, ...priorItems]); + return new Map([...items, ...priorityItems]); } if (properties.has(BORDER_IMAGE)) { properties.delete(BORDER_IMAGE); From d7ecb507efdac91d3bb655388d324559f6d59807 Mon Sep 17 00:00:00 2001 From: "asamuzaK (Kazz)" Date: Thu, 18 Dec 2025 09:00:17 +0900 Subject: [PATCH 07/12] Fix border shorthand variable name Renamed 'namePriorItems' to 'namePriorityItems' in prepareBorderShorthands for consistency and clarity. --- lib/normalize.js | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/lib/normalize.js b/lib/normalize.js index fbaa4c70..11ed4f5f 100644 --- a/lib/normalize.js +++ b/lib/normalize.js @@ -1183,7 +1183,7 @@ const prepareBorderShorthands = (properties) => { } } const nameItems = []; - const namePriorItems = []; + const namePriorityItems = []; for (const [key, collection] of Object.entries(borderCollections)) { const { shorthand, generator, items, priorityItems } = collection; const requiredSize = borderLines.has(key) ? 4 : 3; @@ -1205,13 +1205,13 @@ const prepareBorderShorthands = (properties) => { if (borderPositions.has(key) && properties.has(BORDER_IMAGE)) { const { value: imageValue } = properties.get(BORDER_IMAGE); if (imageValue === NONE) { - namePriorItems.push(item.value); + namePriorityItems.push(item.value); } } } } } - const mixedPriorities = nameItems.length && namePriorItems.length; + const mixedPriorities = nameItems.length && namePriorityItems.length; const imageItem = createPropertyItem(BORDER_IMAGE, NONE); if (nameItems.length === 4) { const [property, item] = generateBorderNameShorthand(nameItems, BORDER) ?? []; @@ -1220,8 +1220,9 @@ const prepareBorderShorthands = (properties) => { properties.delete(BORDER_IMAGE); properties.set(BORDER_IMAGE, imageItem); } - } else if (namePriorItems.length === 4) { - const [property, item] = generateBorderNameShorthand(namePriorItems, BORDER, "important") ?? []; + } else if (namePriorityItems.length === 4) { + const [property, item] = + generateBorderNameShorthand(namePriorityItems, BORDER, "important") ?? []; if (property && item) { properties.set(property, item); properties.delete(BORDER_IMAGE); From 6507ee383221a740a2861604b816180b0aef0eca Mon Sep 17 00:00:00 2001 From: "asamuzaK (Kazz)" Date: Thu, 18 Dec 2025 09:02:16 +0900 Subject: [PATCH 08/12] Refactor border longhand property updates Extracted repeated logic for updating border longhand properties into a new helper function, updatePositionLonghands. This improves code readability and maintainability in the border property normalization process. --- lib/normalize.js | 56 +++++++++++++++++++++++++----------------------- 1 file changed, 29 insertions(+), 27 deletions(-) diff --git a/lib/normalize.js b/lib/normalize.js index 11ed4f5f..a40aae2a 100644 --- a/lib/normalize.js +++ b/lib/normalize.js @@ -1290,6 +1290,33 @@ const processShorthandProperties = (shorthands) => { return shorthandItems; }; +/** + * Updates longhand properties for all 4 border positions (top, right, bottom, left). + * + * @param {Map} properties - The map of properties to update. + * @param {string} namePart - The property name prefix (e.g., "border"). + * @param {string} linePart - The property line suffix (e.g., "width", "style", "color"). + * @param {string|Array} value - The value to set (string or array for position-based values). + * @param {string} priority - The priority of the property. + */ +const updatePositionLonghands = (properties, namePart, linePart, value, priority) => { + for (const position of borderPositions) { + const longhandProperty = `${namePart}-${position}-${linePart}`; + const longhandValue = Array.isArray(value) ? getPositionValue(value, position) : value; + const longhandItem = createPropertyItem(longhandProperty, longhandValue, priority); + + if (properties.has(longhandProperty)) { + const { priority: existingPriority } = properties.get(longhandProperty); + if (!existingPriority) { + properties.delete(longhandProperty); + properties.set(longhandProperty, longhandItem); + } + } else { + properties.set(longhandProperty, longhandItem); + } + } +}; + /** * Processes border properties from the borders map, expanding and normalizing them. * @@ -1322,19 +1349,7 @@ const processBorderProperties = (borders, parseOpt) => { linePart = ""; } const lineValue = lineItems[lineProperty]; - for (const position of borderPositions) { - const longhandProperty = `${namePart}-${position}-${linePart}`; - const longhandItem = createPropertyItem(longhandProperty, lineValue, priority); - if (longhandProperties.has(longhandProperty)) { - const { priority: longhandPriority } = longhandProperties.get(longhandProperty); - if (!longhandPriority) { - longhandProperties.delete(longhandProperty); - longhandProperties.set(longhandProperty, longhandItem); - } - } else { - longhandProperties.set(longhandProperty, longhandItem); - } - } + updatePositionLonghands(longhandProperties, namePart, linePart, lineValue, priority); } if (value) { longhandProperties.set(BORDER_IMAGE, createPropertyItem(BORDER_IMAGE, NONE, priority)); @@ -1351,20 +1366,7 @@ const processBorderProperties = (borders, parseOpt) => { } else { namePart = property; } - for (const position of borderPositions) { - const longhandProperty = `${namePart}-${position}-${linePart}`; - const longhandValue = getPositionValue(parsedItem, position); - const longhandItem = createPropertyItem(longhandProperty, longhandValue, priority); - if (longhandProperties.has(longhandProperty)) { - const { priority: longhandPriority } = longhandProperties.get(longhandProperty); - if (!longhandPriority) { - longhandProperties.delete(longhandProperty); - longhandProperties.set(longhandProperty, longhandItem); - } - } else { - longhandProperties.set(longhandProperty, longhandItem); - } - } + updatePositionLonghands(longhandProperties, namePart, linePart, parsedItem, priority); } else if (parsedItem) { for (const [key, initialValue] of shorthandItem.initialValues) { if (!Object.hasOwn(parsedItem, key)) { From 4ba7f29b738413e44e5a24d362751308c22bfc22 Mon Sep 17 00:00:00 2001 From: "asamuzaK (Kazz)" Date: Thu, 18 Dec 2025 09:28:23 +0900 Subject: [PATCH 09/12] Undo unnecessary change --- lib/normalize.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/normalize.js b/lib/normalize.js index a40aae2a..6fa49be7 100644 --- a/lib/normalize.js +++ b/lib/normalize.js @@ -1045,8 +1045,7 @@ const prepareBorderProperties = (property, value, priority, properties, opt = {} borderProps.set(longhandProperty, longhandItem); } } - const borderImageItem = - borderItems.get(BORDER_IMAGE) ?? getPropertyItem(BORDER_IMAGE, properties); + const borderImageItem = borderItems.get(BORDER_IMAGE) ?? createPropertyItem(BORDER_IMAGE); borderProps.set(BORDER_IMAGE, borderImageItem); return borderProps; }; From a35b91565f71d3eab58998c5400dc4642e84c2ba Mon Sep 17 00:00:00 2001 From: "asamuzaK (Kazz)" Date: Sat, 20 Dec 2025 08:11:04 +0900 Subject: [PATCH 10/12] Refactor longhand property updates into helper function Introduces the updateLonghandProperties helper to consolidate logic for updating longhand properties in multiple places. This reduces code duplication and improves maintainability in normalize.js. --- lib/normalize.js | 55 ++++++++++++++++++++++++------------------------ 1 file changed, 27 insertions(+), 28 deletions(-) diff --git a/lib/normalize.js b/lib/normalize.js index 6fa49be7..0da8987f 100644 --- a/lib/normalize.js +++ b/lib/normalize.js @@ -1303,7 +1303,6 @@ const updatePositionLonghands = (properties, namePart, linePart, value, priority const longhandProperty = `${namePart}-${position}-${linePart}`; const longhandValue = Array.isArray(value) ? getPositionValue(value, position) : value; const longhandItem = createPropertyItem(longhandProperty, longhandValue, priority); - if (properties.has(longhandProperty)) { const { priority: existingPriority } = properties.get(longhandProperty); if (!existingPriority) { @@ -1316,6 +1315,30 @@ const updatePositionLonghands = (properties, namePart, linePart, value, priority } }; +/** + * Updates longhand properties based on a values object. + * + * @param {Map} properties - The map of properties to update. + * @param {Object} values - The object containing property keys and values. + * @param {string} priority - The priority of the properties. + * @param {boolean} [safe=false] - Whether to preserve existing priority. + */ +const updateLonghandProperties = (properties, values, priority, safe = false) => { + for (const property of Object.keys(values)) { + const value = values[property]; + const item = createPropertyItem(property, value, priority); + if (safe && properties.has(property)) { + const { priority: existingPriority } = properties.get(property); + if (!existingPriority) { + properties.delete(property); + properties.set(property, item); + } + } else { + properties.set(property, item); + } + } +}; + /** * Processes border properties from the borders map, expanding and normalizing them. * @@ -1372,19 +1395,7 @@ const processBorderProperties = (borders, parseOpt) => { parsedItem[key] = initialValue; } } - for (const longhandProperty of Object.keys(parsedItem)) { - const longhandValue = parsedItem[longhandProperty]; - const longhandItem = createPropertyItem(longhandProperty, longhandValue, priority); - if (longhandProperties.has(longhandProperty)) { - const { priority: longhandPriority } = longhandProperties.get(longhandProperty); - if (!longhandPriority) { - longhandProperties.delete(longhandProperty); - longhandProperties.set(longhandProperty, longhandItem); - } - } else { - longhandProperties.set(longhandProperty, longhandItem); - } - } + updateLonghandProperties(longhandProperties, parsedItem, priority, true); } } } else if (longhandProperties.has(property)) { @@ -1465,22 +1476,10 @@ const prepareProperties = (properties, opt = {}) => { ); } } else if (parsedValue) { - for (const longhandProperty of Object.keys(parsedValue)) { - const longhandValue = parsedValue[longhandProperty]; - parsedProperties.set( - longhandProperty, - createPropertyItem(longhandProperty, longhandValue, priority) - ); - } + updateLonghandProperties(parsedProperties, parsedValue, 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) - ); - } + updateLonghandProperties(parsedProperties, parsedValues, priority); } if (!omitShorthandProperty) { if (property === BACKGROUND) { From 37ff4371d4424eb11aaf2e1d3781f72b5c66864f Mon Sep 17 00:00:00 2001 From: "asamuzaK (Kazz)" Date: Sat, 20 Dec 2025 08:35:39 +0900 Subject: [PATCH 11/12] Refactor border property variable naming Replaces all instances of the variable 'nameItem' with 'shorthandItem'. No functional changes were made; this is a variable renaming for better meaning and code readability. --- lib/normalize.js | 76 +++++++++++++++++++++++++----------------------- 1 file changed, 40 insertions(+), 36 deletions(-) diff --git a/lib/normalize.js b/lib/normalize.js index 0da8987f..cf3f2d48 100644 --- a/lib/normalize.js +++ b/lib/normalize.js @@ -526,7 +526,7 @@ const prepareBorderStringValue = ({ globalObject, options }; - const nameItem = getPropertyItem(BORDER, properties); + const shorthandItem = getPropertyItem(BORDER, properties); const imageItem = getPropertyItem(BORDER_IMAGE, properties); // Handle longhand properties. if (prop3) { @@ -540,12 +540,12 @@ const prepareBorderStringValue = ({ longhandItem.priority = priority; const propertyValue = hasVarFunc(value) ? "" : value; if (propertyValue === "") { - nameItem.value = ""; + shorthandItem.value = ""; lineItem.value = ""; positionItem.value = ""; } else if (isGlobalKeyword(propertyValue)) { - if (nameItem.value !== propertyValue) { - nameItem.value = ""; + if (shorthandItem.value !== propertyValue) { + shorthandItem.value = ""; } if (lineItem.value !== propertyValue) { lineItem.value = ""; @@ -555,10 +555,10 @@ const prepareBorderStringValue = ({ } } else { if ( - nameItem.value && - !matchesBorderShorthandValue(lineProperty, propertyValue, nameItem.value, parseOpt) + shorthandItem.value && + !matchesBorderShorthandValue(lineProperty, propertyValue, shorthandItem.value, parseOpt) ) { - nameItem.value = ""; + shorthandItem.value = ""; } if (lineItem.value) { lineItem.value = replacePositionValue(propertyValue, splitValue(lineItem.value), prop2); @@ -570,7 +570,7 @@ const prepareBorderStringValue = ({ positionItem.value = ""; } } - borderItems.set(BORDER, nameItem); + borderItems.set(BORDER, shorthandItem); borderItems.set(BORDER_IMAGE, imageItem); borderItems.set(lineProperty, lineItem); borderItems.set(positionProperty, positionItem); @@ -589,13 +589,13 @@ const prepareBorderStringValue = ({ positionItem.priority = priority; const propertyValue = hasVarFunc(value) ? "" : value; if (propertyValue === "") { - nameItem.value = ""; + shorthandItem.value = ""; lineWidthItem.value = ""; lineStyleItem.value = ""; lineColorItem.value = ""; } else if (isGlobalKeyword(propertyValue)) { - if (nameItem.value !== propertyValue) { - nameItem.value = ""; + if (shorthandItem.value !== propertyValue) { + shorthandItem.value = ""; } if (lineWidthItem.value !== propertyValue) { lineWidthItem.value = ""; @@ -608,10 +608,10 @@ const prepareBorderStringValue = ({ } } else { if ( - nameItem.value && - !matchesBorderShorthandValue(property, propertyValue, nameItem.value, parseOpt) + shorthandItem.value && + !matchesBorderShorthandValue(property, propertyValue, shorthandItem.value, parseOpt) ) { - nameItem.value = ""; + shorthandItem.value = ""; } if ( lineWidthItem.value && @@ -639,7 +639,7 @@ const prepareBorderStringValue = ({ longhandItem.priority = priority; borderItems.set(longhandProperty, longhandItem); } - borderItems.set(BORDER, nameItem); + borderItems.set(BORDER, shorthandItem); borderItems.set(BORDER_IMAGE, imageItem); borderItems.set(lineWidthProperty, lineWidthItem); borderItems.set(lineStyleProperty, lineStyleItem); @@ -653,10 +653,10 @@ const prepareBorderStringValue = ({ lineItem.priority = priority; const propertyValue = hasVarFunc(value) ? "" : value; if (propertyValue === "") { - nameItem.value = ""; + shorthandItem.value = ""; } else if (isGlobalKeyword(propertyValue)) { - if (nameItem.value !== propertyValue) { - nameItem.value = ""; + if (shorthandItem.value !== propertyValue) { + shorthandItem.value = ""; } } for (const position of borderPositions) { @@ -678,7 +678,7 @@ const prepareBorderStringValue = ({ borderItems.set(positionProperty, positionItem); borderItems.set(longhandProperty, longhandItem); } - borderItems.set(BORDER, nameItem); + borderItems.set(BORDER, shorthandItem); borderItems.set(BORDER_IMAGE, imageItem); borderItems.set(lineProperty, lineItem); // Handle border shorthand. @@ -706,7 +706,7 @@ const prepareBorderStringValue = ({ borderItems.set(longhandProperty, longhandItem); } } - borderItems.set(property, nameItem); + borderItems.set(property, shorthandItem); borderItems.set(BORDER_IMAGE, imageItem); } }; @@ -732,21 +732,25 @@ const prepareBorderArrayValue = ({ value, priority, properties, parts, opt, bord if (!value.length || !borderLines.has(prop2)) { return; } - const nameItem = getPropertyItem(BORDER, properties); + const shorthandItem = getPropertyItem(BORDER, properties); const imageItem = getPropertyItem(BORDER_IMAGE, properties); const lineProperty = `${prop1}-${prop2}`; const lineItem = getPropertyItem(lineProperty, properties); if (value.length === 1) { const [propertyValue] = value; - if (nameItem.value) { - if (hasVarFunc(nameItem.value)) { - nameItem.value = ""; + if (shorthandItem.value) { + if (hasVarFunc(shorthandItem.value)) { + shorthandItem.value = ""; } else if (propertyValue) { - nameItem.value = replaceBorderShorthandValue(propertyValue, nameItem.value, parseOpt); + shorthandItem.value = replaceBorderShorthandValue( + propertyValue, + shorthandItem.value, + parseOpt + ); } } } else { - nameItem.value = ""; + shorthandItem.value = ""; } lineItem.value = value.join(" "); lineItem.priority = priority; @@ -799,7 +803,7 @@ const prepareBorderArrayValue = ({ value, priority, properties, parts, opt, bord borderItems.set(positionProperty, positionItem); borderItems.set(longhandProperty, longhandItem); } - borderItems.set(BORDER, nameItem); + borderItems.set(BORDER, shorthandItem); borderItems.set(BORDER_IMAGE, imageItem); borderItems.set(lineProperty, lineItem); }; @@ -837,7 +841,7 @@ const prepareBorderObjectValue = ({ if (!borderPositions.has(prop2)) { return; } - const nameItem = getPropertyItem(BORDER, properties); + const shorthandItem = getPropertyItem(BORDER, properties); const lineWidthProperty = `${prop1}-width`; const lineWidthItem = getPropertyItem(lineWidthProperty, properties); const lineStyleProperty = `${prop1}-style`; @@ -846,10 +850,10 @@ const prepareBorderObjectValue = ({ const lineColorItem = getPropertyItem(lineColorProperty, properties); const positionProperty = `${prop1}-${prop2}`; const positionItem = getPropertyItem(positionProperty, properties); - if (nameItem.value) { + if (shorthandItem.value) { for (const positionValue of Object.values(value)) { - if (!matchesBorderShorthandValue(property, positionValue, nameItem.value, parseOpt)) { - nameItem.value = ""; + if (!matchesBorderShorthandValue(property, positionValue, shorthandItem.value, parseOpt)) { + shorthandItem.value = ""; break; } } @@ -885,7 +889,7 @@ const prepareBorderObjectValue = ({ longhandItem.priority = priority; borderItems.set(longhandProperty, longhandItem); } - borderItems.set(BORDER, nameItem); + borderItems.set(BORDER, shorthandItem); borderItems.set(BORDER_IMAGE, imageItem); borderItems.set(lineWidthProperty, lineWidthItem); borderItems.set(lineStyleProperty, lineStyleItem); @@ -893,7 +897,7 @@ const prepareBorderObjectValue = ({ borderItems.set(positionProperty, positionItem); // Handle border shorthand. } else { - const nameItem = getPropertyItem(prop1, properties); + const shorthandItem = getPropertyItem(prop1, properties); const lineWidthProperty = `${prop1}-width`; const lineWidthItem = getPropertyItem(lineWidthProperty, properties); const lineStyleProperty = `${prop1}-style`; @@ -901,8 +905,8 @@ const prepareBorderObjectValue = ({ const lineColorProperty = `${prop1}-color`; const lineColorItem = getPropertyItem(lineColorProperty, properties); const propertyValue = Object.values(value).join(" "); - nameItem.value = propertyValue; - nameItem.priority = priority; + shorthandItem.value = propertyValue; + shorthandItem.priority = priority; imageItem.value = propertyValue ? NONE : ""; if (Object.hasOwn(value, lineWidthProperty)) { lineWidthItem.value = value[lineWidthProperty]; @@ -941,7 +945,7 @@ const prepareBorderObjectValue = ({ } borderItems.set(positionProperty, positionItem); } - borderItems.set(property, nameItem); + borderItems.set(property, shorthandItem); borderItems.set(BORDER_IMAGE, imageItem); borderItems.set(lineWidthProperty, lineWidthItem); borderItems.set(lineStyleProperty, lineStyleItem); From c67c95c586e8204dfa19af4f42d5beae01250eea Mon Sep 17 00:00:00 2001 From: "asamuzaK (Kazz)" Date: Sat, 20 Dec 2025 09:10:38 +0900 Subject: [PATCH 12/12] Refactor border shorthand generation functions Renamed generateBorderNameShorthand to generateBorderShorthand and updated related variable names for clarity. This improves code readability and better reflects the function's purpose. --- lib/normalize.js | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/lib/normalize.js b/lib/normalize.js index cf3f2d48..9ec9b661 100644 --- a/lib/normalize.js +++ b/lib/normalize.js @@ -1091,14 +1091,14 @@ const generateBorderPositionShorthand = (items, property, priority = "") => { }; /** - * Generates a border name shorthand property if all components match. + * Generates a border shorthand property if all components match. * - * @param {Set|Array} items - The collection of property values. + * @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 generateBorderNameShorthand = (items, property, priority = "") => { +const generateBorderShorthand = (items, property, priority = "") => { const values = new Set(items); if (values.size === 1) { const value = values.keys().next().value; @@ -1185,8 +1185,8 @@ const prepareBorderShorthands = (properties) => { } } } - const nameItems = []; - const namePriorityItems = []; + 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; @@ -1197,7 +1197,7 @@ const prepareBorderShorthands = (properties) => { if (borderPositions.has(key) && properties.has(BORDER_IMAGE)) { const { value: imageValue } = properties.get(BORDER_IMAGE); if (imageValue === NONE) { - nameItems.push(item.value); + shorthandItems.push(item.value); } } } @@ -1208,24 +1208,24 @@ const prepareBorderShorthands = (properties) => { if (borderPositions.has(key) && properties.has(BORDER_IMAGE)) { const { value: imageValue } = properties.get(BORDER_IMAGE); if (imageValue === NONE) { - namePriorityItems.push(item.value); + shorthandPriorityItems.push(item.value); } } } } } - const mixedPriorities = nameItems.length && namePriorityItems.length; + const mixedPriorities = shorthandItems.length && shorthandPriorityItems.length; const imageItem = createPropertyItem(BORDER_IMAGE, NONE); - if (nameItems.length === 4) { - const [property, item] = generateBorderNameShorthand(nameItems, BORDER) ?? []; + if (shorthandItems.length === 4) { + const [property, item] = generateBorderShorthand(shorthandItems, BORDER) ?? []; if (property && item) { properties.set(property, item); properties.delete(BORDER_IMAGE); properties.set(BORDER_IMAGE, imageItem); } - } else if (namePriorityItems.length === 4) { + } else if (shorthandPriorityItems.length === 4) { const [property, item] = - generateBorderNameShorthand(namePriorityItems, BORDER, "important") ?? []; + generateBorderShorthand(shorthandPriorityItems, BORDER, "important") ?? []; if (property && item) { properties.set(property, item); properties.delete(BORDER_IMAGE);