@wix/css-property-parser
Version:
A comprehensive TypeScript library for parsing and serializing CSS property values with full MDN specification compliance
137 lines (136 loc) • 4.46 kB
JavaScript
"use strict";
// Border-style property parser
// Handles parsing of CSS border-style property according to MDN specification
// https://developer.mozilla.org/en-US/docs/Web/CSS/border-style
Object.defineProperty(exports, "__esModule", { value: true });
exports.parse = parse;
exports.toCSSValue = toCSSValue;
const css_variable_1 = require('./css-variable.cjs');
const shared_utils_1 = require('../utils/shared-utils.cjs');
// Import centralized types
const types_1 = require('../types.cjs');
/**
* Check if value is a border style keyword
*/
function isBorderStyleKeyword(value) {
return types_1.BORDER_STYLE_KEYWORDS.includes(value.toLowerCase());
}
/**
* Parse a single border style value
*/
function parseSingleBorderStyle(value) {
if (!value || typeof value !== 'string') {
return null;
}
const trimmed = value.trim();
if (trimmed === '') {
return null;
}
// Global keywords
if ((0, shared_utils_1.isGlobalKeyword)(trimmed)) {
return { type: 'keyword', keyword: trimmed.toLowerCase() };
}
// Border style keywords
if (isBorderStyleKeyword(trimmed)) {
return { type: 'keyword', keyword: trimmed.toLowerCase() };
}
return null;
}
/**
* Serialize a single border style value back to CSS
*/
function serializeSingleBorderStyle(value) {
if (!value) {
return null;
}
// Handle CSS variables
if ('CSSvariable' in value) {
return (0, css_variable_1.toCSSValue)(value);
}
return value.keyword;
}
/**
* Parse a CSS border-style property string
*/
function parse(value) {
if (!value || typeof value !== 'string') {
return null;
}
const trimmed = value.trim();
if (trimmed === '') {
return null;
}
// CSS variables - parse and return directly
if ((0, shared_utils_1.isCssVariable)(trimmed)) {
return (0, css_variable_1.parse)(trimmed);
}
// Tokenize the value (handles function boundaries and quoted strings)
const tokens = (0, shared_utils_1.tokenize)(trimmed);
// Validate token count (CSS shorthand supports 1-4 values)
if (tokens.length === 0 || tokens.length > 4) {
return null;
}
// Validate each token can be parsed as a border style
for (const token of tokens) {
if (!parseSingleBorderStyle(token)) {
return null;
}
}
// Expand shorthand values (1-4 values → 4 values)
const expandedTokens = (0, shared_utils_1.expandShorthandValues)(tokens);
// Parse each expanded token
const borderTopStyle = parseSingleBorderStyle(expandedTokens[0]);
const borderRightStyle = parseSingleBorderStyle(expandedTokens[1]);
const borderBottomStyle = parseSingleBorderStyle(expandedTokens[2]);
const borderLeftStyle = parseSingleBorderStyle(expandedTokens[3]);
// All values must be valid
if (!borderTopStyle || !borderRightStyle || !borderBottomStyle || !borderLeftStyle) {
return null;
}
return {
borderTopStyle,
borderRightStyle,
borderBottomStyle,
borderLeftStyle
};
}
/**
* Convert BorderStyleValue back to CSS string
*/
function toCSSValue(parsed) {
if (!parsed) {
return null;
}
// Handle CSS variables
if ('CSSvariable' in parsed) {
return (0, css_variable_1.toCSSValue)(parsed);
}
// Handle expanded border style
if ('borderTopStyle' in parsed) {
const top = serializeSingleBorderStyle(parsed.borderTopStyle);
const right = serializeSingleBorderStyle(parsed.borderRightStyle);
const bottom = serializeSingleBorderStyle(parsed.borderBottomStyle);
const left = serializeSingleBorderStyle(parsed.borderLeftStyle);
if (!top || !right || !bottom || !left) {
return null;
}
// Compress to shortest form
if (top === right && right === bottom && bottom === left) {
// All sides same: "solid"
return top;
}
else if (top === bottom && right === left) {
// Vertical/horizontal: "solid dashed"
return `${top} ${right}`;
}
else if (right === left) {
// Top, horizontal, bottom: "solid dashed dotted"
return `${top} ${right} ${bottom}`;
}
else {
// All different: "solid dashed dotted groove"
return `${top} ${right} ${bottom} ${left}`;
}
}
return null;
}