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