diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index fa8b7eb7..e116e733 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -18,8 +18,8 @@ jobs: - lts/* - latest steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 + - uses: actions/checkout@v5 + - uses: actions/setup-node@v5 with: node-version: ${{ matrix.node-version }} - run: npm ci diff --git a/.gitignore b/.gitignore index 8297d482..a840c57f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ node_modules npm-debug.log -lib/generated/implementedProperties.js lib/generated/properties.js +lib/generated/propertyDefinitions.js diff --git a/lib/CSSStyleDeclaration.js b/lib/CSSStyleDeclaration.js index a451cf9e..cd0c5709 100644 --- a/lib/CSSStyleDeclaration.js +++ b/lib/CSSStyleDeclaration.js @@ -4,13 +4,12 @@ */ "use strict"; -const allProperties = require("./generated/allProperties"); -const implementedProperties = require("./generated/implementedProperties"); const generatedProperties = require("./generated/properties"); +const propertyDefinitions = require("./generated/propertyDefinitions"); const { borderProperties, getPositionValue, - normalizeBorderProperties, + normalizeProperties, prepareBorderProperties, prepareProperties, shorthandProperties @@ -22,113 +21,54 @@ const { parsePropertyValue, prepareValue } = require("./parsers"); -const allExtraProperties = require("./utils/allExtraProperties"); -const { dashedToCamelCase } = require("./utils/camelize"); const { getPropertyDescriptor } = require("./utils/propertyDescriptors"); const { asciiLowercase } = require("./utils/strings"); +const ELEMENT_NODE = 1; + /** * @see https://drafts.csswg.org/cssom/#the-cssstyledeclaration-interface */ class CSSStyleDeclaration { /** - * @param {Function} onChangeCallback - * @param {object} [opt] - * @param {object} [opt.context] - Window, Element or CSSRule. + * @param {object} globalObject - Window + * @param {object} opt - Options + * @param {object} opt.context - Element or CSSStyleRule + * @param {string} opt.format - "specifiedValue" or "computedValue" + * @param {Function} opt.onChange - Callback when cssText is changed or the property is removed */ - constructor(onChangeCallback, opt = {}) { - // Make constructor and internals non-enumerable. - Object.defineProperties(this, { - constructor: { - enumerable: false, - writable: true - }, - - // Window - _global: { - value: globalThis, - enumerable: false, - writable: true - }, - - // Element - _ownerNode: { - value: null, - enumerable: false, - writable: true - }, - - // CSSRule - _parentNode: { - value: null, - enumerable: false, - writable: true - }, - - _onChange: { - value: null, - enumerable: false, - writable: true - }, - - _values: { - value: new Map(), - enumerable: false, - writable: true - }, - - _priorities: { - value: new Map(), - enumerable: false, - writable: true - }, - - _length: { - value: 0, - enumerable: false, - writable: true - }, + constructor(globalObject, opt = {}) { + const { context, format, onChange } = opt; - _computed: { - value: false, - enumerable: false, - writable: true - }, + // These help interface with jsdom. + this._global = globalObject; + this._onChange = onChange; - _readonly: { - value: false, - enumerable: false, - writable: true - }, - - _setInProgress: { - value: false, - enumerable: false, - writable: true - } - }); - - const { context } = opt; + // These correspond to https://drafts.csswg.org/cssom/#css-declaration-block. + this._computed = format === "computedValue"; + this._ownerNode = null; + this._parentRule = null; if (context) { - if (typeof context.getComputedStyle === "function") { - this._global = context; - this._computed = true; - this._readonly = true; - } else if (context.nodeType === 1 && Object.hasOwn(context, "style")) { - this._global = context.ownerDocument.defaultView; + // The context is an element. + if (context.nodeType === ELEMENT_NODE) { this._ownerNode = context; + // The context is a CSSStyleRule. } else if (Object.hasOwn(context, "parentRule")) { this._parentRule = context; - // Find Window from the owner node of the StyleSheet. - const window = context?.parentStyleSheet?.ownerNode?.ownerDocument?.defaultView; - if (window) { - this._global = window; - } } } - if (typeof onChangeCallback === "function") { - this._onChange = onChangeCallback; - } + this._readonly = false; + this._updating = false; + + // These correspond to the specification's "declarations". + this._values = new Map(); + this._priorities = new Map(); + this._length = 0; + + // This is used internally by parsers. e.g. parsers.resolveCalc(), parsers.parseColor(), etc. + this._options = { + format: format === "computedValue" ? format : "specifiedValue" + }; } get cssText() { @@ -150,7 +90,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) { @@ -168,19 +108,23 @@ class CSSStyleDeclaration { const name = "NoModificationAllowedError"; throw new this._global.DOMException(msg, name); } + if (this._updating) { + return; + } Array.prototype.splice.call(this, 0, this._length); this._values.clear(); this._priorities.clear(); - if (this._parentRule || (this._ownerNode && this._setInProgress)) { - return; - } - this._setInProgress = true; + this._updating = true; try { + // TBD: use cache? const valueObj = parseCSS( val, { - context: "declarationList", - parseValue: false + globalObject: this._global, + options: { + context: "declarationList", + parseValue: false + } }, true ); @@ -199,12 +143,12 @@ class CSSStyleDeclaration { shouldSkipNext = false; continue; } - const { - important, - property, - value: { value } - } = item; - if (typeof property === "string" && typeof value === "string") { + if (item.type === "Declaration") { + const { + important, + property, + value: { value } + } = item; const priority = important ? "important" : ""; const isCustomProperty = property.startsWith("--"); if (isCustomProperty || hasVarFunc(value)) { @@ -217,8 +161,10 @@ class CSSStyleDeclaration { properties.set(property, { property, value, priority }); } } else { + // TBD: use cache? const parsedValue = parsePropertyValue(property, value, { - globalObject: this._global + globalObject: this._global, + options: this._options }); if (parsedValue) { if (properties.has(property)) { @@ -236,7 +182,8 @@ class CSSStyleDeclaration { } } const parsedProperties = prepareProperties(properties, { - globalObject: this._global + globalObject: this._global, + options: this._options }); for (const [property, item] of parsedProperties) { const { priority, value } = item; @@ -247,7 +194,7 @@ class CSSStyleDeclaration { } catch { return; } - this._setInProgress = false; + this._updating = false; if (typeof this._onChange === "function") { this._onChange(this.cssText); } @@ -258,8 +205,7 @@ class CSSStyleDeclaration { } // This deletes indices if the new length is less then the current length. - // If the new length is more, it does nothing, the new indices will be - // undefined until set. + // If the new length is more, it does nothing, the new indices will be undefined until set. set length(len) { for (let i = len; i < this._length; i++) { delete this[i]; @@ -267,36 +213,6 @@ class CSSStyleDeclaration { this._length = len; } - // Readonly - get parentRule() { - return this._parentRule; - } - - get cssFloat() { - return this.getPropertyValue("float"); - } - - set cssFloat(value) { - this._setProperty("float", value); - } - - /** - * @param {string} property - */ - getPropertyPriority(property) { - return this._priorities.get(property) || ""; - } - - /** - * @param {string} property - */ - getPropertyValue(property) { - if (this._values.has(property)) { - return this._values.get(property).toString(); - } - return ""; - } - /** * @param {...number} args */ @@ -316,26 +232,18 @@ class CSSStyleDeclaration { /** * @param {string} property */ - removeProperty(property) { - if (this._readonly) { - const msg = `Property ${property} can not be modified.`; - const name = "NoModificationAllowedError"; - throw new this._global.DOMException(msg, name); - } - if (!this._values.has(property)) { - return ""; - } - const prevValue = this._values.get(property); - this._values.delete(property); - this._priorities.delete(property); - const index = Array.prototype.indexOf.call(this, property); - if (index >= 0) { - Array.prototype.splice.call(this, index, 1); - if (typeof this._onChange === "function") { - this._onChange(this.cssText); - } + getPropertyValue(property) { + if (this._values.has(property)) { + return this._values.get(property).toString(); } - return prevValue; + return ""; + } + + /** + * @param {string} property + */ + getPropertyPriority(property) { + return this._priorities.get(property) || ""; } /** @@ -362,7 +270,7 @@ class CSSStyleDeclaration { return; } const property = asciiLowercase(prop); - if (!allProperties.has(property) && !allExtraProperties.has(property)) { + if (!propertyDefinitions.has(property)) { return; } if (priority) { @@ -372,277 +280,285 @@ class CSSStyleDeclaration { } this[property] = value; } -} -// Internal methods -Object.defineProperties(CSSStyleDeclaration.prototype, { - _setProperty: { - /** - * @param {string} property - * @param {string} val - * @param {string} priority - */ - value(property, val, priority) { - if (typeof val !== "string") { - return; - } - if (val === "") { - this.removeProperty(property); - return; - } - let originalText = ""; + /** + * @param {string} property + */ + removeProperty(property) { + if (this._readonly) { + const msg = `Property ${property} can not be modified.`; + const name = "NoModificationAllowedError"; + throw new this._global.DOMException(msg, name); + } + if (!this._values.has(property)) { + return ""; + } + const prevValue = this._values.get(property); + this._values.delete(property); + this._priorities.delete(property); + const index = Array.prototype.indexOf.call(this, property); + if (index >= 0) { + Array.prototype.splice.call(this, index, 1); if (typeof this._onChange === "function") { - originalText = this.cssText; - } - if (this._values.has(property)) { - const index = Array.prototype.indexOf.call(this, property); - // The property already exists but is not indexed into `this` so add it. - if (index < 0) { - this[this._length] = property; - this._length++; - } - } else { - // New property. - this[this._length] = property; - this._length++; - } - if (priority === "important") { - this._priorities.set(property, priority); - } else { - this._priorities.delete(property); - } - this._values.set(property, val); - if ( - typeof this._onChange === "function" && - this.cssText !== originalText && - !this._setInProgress - ) { this._onChange(this.cssText); } - }, - enumerable: false - }, + } + return prevValue; + } - _borderSetter: { - /** - * @param {string} prop - * @param {object|Array|string} val - * @param {string} prior - */ - value(prop, val, prior) { - const properties = new Map(); - if (prop === "border") { - let priority = ""; - if (typeof prior === "string") { - priority = prior; - } else { - priority = this._priorities.get(prop) ?? ""; - } - properties.set(prop, { propery: prop, value: val, priority }); - } else { - for (let i = 0; i < this._length; i++) { - const property = this[i]; - if (borderProperties.has(property)) { - const value = this.getPropertyValue(property); - const longhandPriority = this._priorities.get(property) ?? ""; - let priority = longhandPriority; - if (prop === property && typeof prior === "string") { - priority = prior; - } - properties.set(property, { property, value, priority }); - } - } - } - const parsedProperties = prepareBorderProperties(prop, val, prior, properties, { - globalObject: this._global - }); - for (const [property, item] of parsedProperties) { - const { priority, value } = item; - this._setProperty(property, value, priority); - } - }, - enumerable: false - }, + get parentRule() { + return this._parentRule; + } - _flexBoxSetter: { - /** - * @param {string} prop - * @param {string} val - * @param {string} prior - * @param {string} shorthandProperty - */ - value(prop, val, prior, shorthandProperty) { - if (!shorthandProperty || !shorthandProperties.has(shorthandProperty)) { - return; + // Internal methods + /** + * @param {string} property + * @param {string} val + * @param {string} priority + */ + _setProperty(property, val, priority) { + if (typeof val !== "string") { + return; + } + if (val === "") { + this.removeProperty(property); + return; + } + let originalText = ""; + if (typeof this._onChange === "function") { + originalText = this.cssText; + } + if (this._values.has(property)) { + const index = Array.prototype.indexOf.call(this, property); + // The property already exists but is not indexed into `this` so add it. + if (index < 0) { + this[this._length] = property; + this._length++; } - const shorthandPriority = this._priorities.get(shorthandProperty); - this.removeProperty(shorthandProperty); + } else { + // New property. + this[this._length] = property; + this._length++; + } + if (priority === "important") { + this._priorities.set(property, priority); + } else { + this._priorities.delete(property); + } + this._values.set(property, val); + if (typeof this._onChange === "function" && this.cssText !== originalText && !this._updating) { + this._onChange(this.cssText); + } + } + + /** + * @param {string} prop + * @param {object|Array|string} val + * @param {string} prior + */ + _borderSetter(prop, val, prior) { + const properties = new Map(); + if (prop === "border") { let priority = ""; if (typeof prior === "string") { priority = prior; } else { priority = this._priorities.get(prop) ?? ""; } - this.removeProperty(prop); - if (shorthandPriority && priority) { - this._setProperty(prop, val); - } else { - this._setProperty(prop, val, priority); - } - if (val && !hasVarFunc(val)) { - const longhandValues = []; - const shorthandItem = shorthandProperties.get(shorthandProperty); - let hasGlobalKeyword = false; - for (const [longhandProperty] of shorthandItem.shorthandFor) { - if (longhandProperty === prop) { - if (isGlobalKeyword(val)) { - hasGlobalKeyword = true; - } - longhandValues.push(val); - } else { - const longhandValue = this.getPropertyValue(longhandProperty); - const longhandPriority = this._priorities.get(longhandProperty) ?? ""; - if (!longhandValue || longhandPriority !== priority) { - break; - } - if (isGlobalKeyword(longhandValue)) { - hasGlobalKeyword = true; - } - longhandValues.push(longhandValue); - } - } - if (longhandValues.length === shorthandItem.shorthandFor.size) { - if (hasGlobalKeyword) { - const [firstValue, ...restValues] = longhandValues; - if (restValues.every((value) => value === firstValue)) { - this._setProperty(shorthandProperty, firstValue, priority); - } - } else { - const parsedValue = shorthandItem.parse(longhandValues.join(" ")); - const shorthandValue = Object.values(parsedValue).join(" "); - this._setProperty(shorthandProperty, shorthandValue, priority); + properties.set(prop, { propery: prop, value: val, priority }); + } else { + for (let i = 0; i < this._length; i++) { + const property = this[i]; + if (borderProperties.has(property)) { + const value = this.getPropertyValue(property); + const longhandPriority = this._priorities.get(property) ?? ""; + let priority = longhandPriority; + if (prop === property && typeof prior === "string") { + priority = prior; } + properties.set(property, { property, value, priority }); } } - }, - enumerable: false - }, + } + const parsedProperties = prepareBorderProperties(prop, val, prior, properties, { + globalObject: this._global, + options: this._options + }); + for (const [property, item] of parsedProperties) { + const { priority, value } = item; + this._setProperty(property, value, priority); + } + } - _positionShorthandSetter: { - /** - * @param {string} prop - * @param {Array|string} val - * @param {string} prior - */ - value(prop, val, prior) { - if (!shorthandProperties.has(prop)) { - return; - } - const shorthandValues = []; - if (Array.isArray(val)) { - shorthandValues.push(...val); - } else if (typeof val === "string") { - shorthandValues.push(val); - } else { - return; - } - let priority = ""; - if (typeof prior === "string") { - priority = prior; - } else { - priority = this._priorities.get(prop) ?? ""; - } - const { position, shorthandFor } = shorthandProperties.get(prop); - let hasPriority = false; - for (const [longhandProperty, longhandItem] of shorthandFor) { - const { position: longhandPosition } = longhandItem; - const longhandValue = getPositionValue(shorthandValues, longhandPosition); - if (priority) { - this._setProperty(longhandProperty, longhandValue, priority); + /** + * @param {string} prop + * @param {string} val + * @param {string} prior + * @param {string} shorthandProperty + */ + _flexBoxSetter(prop, val, prior, shorthandProperty) { + if (!shorthandProperty || !shorthandProperties.has(shorthandProperty)) { + return; + } + const shorthandPriority = this._priorities.get(shorthandProperty); + this.removeProperty(shorthandProperty); + let priority = ""; + if (typeof prior === "string") { + priority = prior; + } else { + priority = this._priorities.get(prop) ?? ""; + } + this.removeProperty(prop); + if (shorthandPriority && priority) { + this._setProperty(prop, val); + } else { + this._setProperty(prop, val, priority); + } + if (val && !hasVarFunc(val)) { + const longhandValues = []; + const shorthandItem = shorthandProperties.get(shorthandProperty); + let hasGlobalKeyword = false; + for (const [longhandProperty] of shorthandItem.shorthandFor) { + if (longhandProperty === prop) { + if (isGlobalKeyword(val)) { + hasGlobalKeyword = true; + } + longhandValues.push(val); } else { + const longhandValue = this.getPropertyValue(longhandProperty); const longhandPriority = this._priorities.get(longhandProperty) ?? ""; - if (longhandPriority) { - hasPriority = true; - } else { - this._setProperty(longhandProperty, longhandValue, priority); + if (!longhandValue || longhandPriority !== priority) { + break; } + if (isGlobalKeyword(longhandValue)) { + hasGlobalKeyword = true; + } + longhandValues.push(longhandValue); } } - if (hasPriority) { - this.removeProperty(prop); - } else { - const shorthandValue = getPositionValue(shorthandValues, position); - this._setProperty(prop, shorthandValue, priority); + if (longhandValues.length === shorthandItem.shorthandFor.size) { + if (hasGlobalKeyword) { + const [firstValue, ...restValues] = longhandValues; + if (restValues.every((value) => value === firstValue)) { + this._setProperty(shorthandProperty, firstValue, priority); + } + } else { + const parsedValue = shorthandItem.parse(longhandValues.join(" ")); + if (parsedValue) { + const shorthandValue = Object.values(parsedValue).join(" "); + this._setProperty(shorthandProperty, shorthandValue, priority); + } + } } - }, - enumerable: false - }, + } + } - _positionLonghandSetter: { - /** - * @param {string} prop - * @param {string} val - * @param {string} prior - * @param {string} shorthandProperty - */ - value(prop, val, prior, shorthandProperty) { - if (!shorthandProperty || !shorthandProperties.has(shorthandProperty)) { - return; - } - const shorthandPriority = this._priorities.get(shorthandProperty); - this.removeProperty(shorthandProperty); - let priority = ""; - if (typeof prior === "string") { - priority = prior; + /** + * @param {string} prop + * @param {Array|string} val + * @param {string} prior + */ + _positionShorthandSetter(prop, val, prior) { + if (!shorthandProperties.has(prop)) { + return; + } + const shorthandValues = []; + if (Array.isArray(val)) { + shorthandValues.push(...val); + } else if (typeof val === "string") { + shorthandValues.push(val); + } else { + return; + } + let priority = ""; + if (typeof prior === "string") { + priority = prior; + } else { + priority = this._priorities.get(prop) ?? ""; + } + const { position, shorthandFor } = shorthandProperties.get(prop); + let hasPriority = false; + for (const [longhandProperty, longhandItem] of shorthandFor) { + const { position: longhandPosition } = longhandItem; + const longhandValue = getPositionValue(shorthandValues, longhandPosition); + if (priority) { + this._setProperty(longhandProperty, longhandValue, priority); } else { - priority = this._priorities.get(prop) ?? ""; + const longhandPriority = this._priorities.get(longhandProperty) ?? ""; + if (longhandPriority) { + hasPriority = true; + } else { + this._setProperty(longhandProperty, longhandValue, priority); + } } + } + if (hasPriority) { this.removeProperty(prop); - if (shorthandPriority && priority) { - this._setProperty(prop, val); - } else { - this._setProperty(prop, val, priority); - } - if (val && !hasVarFunc(val)) { - const longhandValues = []; - const { shorthandFor, position: shorthandPosition } = - shorthandProperties.get(shorthandProperty); - for (const [longhandProperty] of shorthandFor) { - const longhandValue = this.getPropertyValue(longhandProperty); - const longhandPriority = this._priorities.get(longhandProperty) ?? ""; - if (!longhandValue || longhandPriority !== priority) { - return; - } - longhandValues.push(longhandValue); - } - if (longhandValues.length === shorthandFor.size) { - const replacedValue = getPositionValue(longhandValues, shorthandPosition); - this._setProperty(shorthandProperty, replacedValue); + } else { + const shorthandValue = getPositionValue(shorthandValues, position); + this._setProperty(prop, shorthandValue, priority); + } + } + + /** + * @param {string} prop + * @param {string} val + * @param {string} prior + * @param {string} shorthandProperty + */ + _positionLonghandSetter(prop, val, prior, shorthandProperty) { + if (!shorthandProperty || !shorthandProperties.has(shorthandProperty)) { + return; + } + const shorthandPriority = this._priorities.get(shorthandProperty); + this.removeProperty(shorthandProperty); + let priority = ""; + if (typeof prior === "string") { + priority = prior; + } else { + priority = this._priorities.get(prop) ?? ""; + } + this.removeProperty(prop); + if (shorthandPriority && priority) { + this._setProperty(prop, val); + } else { + this._setProperty(prop, val, priority); + } + if (val && !hasVarFunc(val)) { + const longhandValues = []; + const { shorthandFor, position: shorthandPosition } = + shorthandProperties.get(shorthandProperty); + for (const [longhandProperty] of shorthandFor) { + const longhandValue = this.getPropertyValue(longhandProperty); + const longhandPriority = this._priorities.get(longhandProperty) ?? ""; + if (!longhandValue || longhandPriority !== priority) { + return; } + longhandValues.push(longhandValue); + } + if (longhandValues.length === shorthandFor.size) { + const replacedValue = getPositionValue(longhandValues, shorthandPosition); + this._setProperty(shorthandProperty, replacedValue, priority); } - }, - enumerable: false + } } -}); +} // Properties Object.defineProperties(CSSStyleDeclaration.prototype, generatedProperties); // Additional properties -[...allProperties, ...allExtraProperties].forEach((property) => { - if (!implementedProperties.has(property)) { +for (const definition of propertyDefinitions.values()) { + const { legacyAliasOf, name, styleDeclaration } = definition; + const property = legacyAliasOf ?? name; + if (!Object.hasOwn(generatedProperties, property)) { const declaration = getPropertyDescriptor(property); - Object.defineProperty(CSSStyleDeclaration.prototype, property, declaration); - const camel = dashedToCamelCase(property); - Object.defineProperty(CSSStyleDeclaration.prototype, camel, declaration); - if (/^webkit[A-Z]/.test(camel)) { - const pascal = camel.replace(/^webkit/, "Webkit"); - Object.defineProperty(CSSStyleDeclaration.prototype, pascal, declaration); + for (const aliasProperty of styleDeclaration) { + Object.defineProperty(CSSStyleDeclaration.prototype, aliasProperty, declaration); } } -}); +} module.exports = { - CSSStyleDeclaration, - propertyList: Object.fromEntries(implementedProperties) + CSSStyleDeclaration }; diff --git a/lib/generated/allProperties.js b/lib/generated/allProperties.js index a7a8c6ce..141be189 100644 --- a/lib/generated/allProperties.js +++ b/lib/generated/allProperties.js @@ -1,5 +1,5 @@ "use strict"; -// autogenerated - 2025-08-02 +// autogenerated - 2025-11-13 // https://www.w3.org/Style/CSS/all-properties.en.html module.exports = new Set([ @@ -310,7 +310,7 @@ module.exports = new Set([ "item-direction", "item-flow", "item-pack", - "item-slack", + "item-tolerance", "item-track", "item-wrap", "justify-content", @@ -461,6 +461,7 @@ module.exports = new Set([ "print-color-adjust", "quotes", "reading-flow", + "reading-order", "region-fragment", "resize", "rest", diff --git a/lib/index.js b/lib/index.js new file mode 100644 index 00000000..00d14b75 --- /dev/null +++ b/lib/index.js @@ -0,0 +1,11 @@ +"use strict"; + +const { CSSStyleDeclaration } = require("./CSSStyleDeclaration"); +const propertyDefinitions = require("./generated/propertyDefinitions"); +const propertyNames = require("./generated/allProperties"); + +module.exports = { + CSSStyleDeclaration, + propertyDefinitions: Object.fromEntries(propertyDefinitions), + propertyNames: [...propertyNames] +}; diff --git a/lib/normalize.js b/lib/normalize.js index 6f7b1624..1c30fa60 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,57 @@ const font = require("./properties/font"); const margin = require("./properties/margin"); const padding = require("./properties/padding"); -const borderImageProperty = "border-image"; +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"; -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,7 +75,7 @@ exports.borderProperties = new Set([ ...borderLeft.shorthandFor.keys() ]); -exports.getPositionValue = (positionValues, position) => { +const getPositionValue = (positionValues, position) => { switch (positionValues.length) { case 1: { const [val1] = positionValues; @@ -65,16 +84,16 @@ exports.getPositionValue = (positionValues, position) => { case 2: { const [val1, val2] = positionValues; switch (position) { - case "top": { + case TOP: { return val1; } - case "right": { + case RIGHT: { return val2; } - case "bottom": { + case BOTTOM: { return val1; } - case "left": { + case LEFT: { return val2; } default: { @@ -88,16 +107,16 @@ exports.getPositionValue = (positionValues, position) => { case 3: { const [val1, val2, val3] = positionValues; switch (position) { - case "top": { + case TOP: { return val1; } - case "right": { + case RIGHT: { return val2; } - case "bottom": { + case BOTTOM: { return val3; } - case "left": { + case LEFT: { return val2; } default: { @@ -114,16 +133,16 @@ exports.getPositionValue = (positionValues, position) => { case 4: { const [val1, val2, val3, val4] = positionValues; switch (position) { - case "top": { + case TOP: { return val1; } - case "right": { + case RIGHT: { return val2; } - case "bottom": { + case BOTTOM: { return val3; } - case "left": { + case LEFT: { return val4; } default: { @@ -144,12 +163,6 @@ exports.getPositionValue = (positionValues, position) => { } }; -const borderElements = { - name: "border", - positions: ["top", "right", "bottom", "left"], - lines: ["width", "style", "color"] -}; - const getPropertyItem = (property, properties) => { const propertyItem = properties.get(property) ?? { property, @@ -159,10 +172,52 @@ const getPropertyItem = (property, properties) => { return propertyItem; }; +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) { + if (value !== background.initialValues.get(longhand)) { + if (longhand === BACKGROUND_SIZE) { + bg.push(`/ ${value}`); + } else { + bg.push(value); + } + } + } + } + backgrounds.push(bg.join(" ")); + } + return backgrounds.join(", "); +}; + +const borderElements = { + name: BORDER, + positions: [TOP, RIGHT, BOTTOM, LEFT], + lines: [WIDTH, STYLE, COLOR] +}; + 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]; @@ -171,16 +226,16 @@ const matchesBorderShorthandValue = (property, value, shorthandValue, opt = {}) }; 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 }; @@ -220,16 +275,16 @@ const replacePositionValue = (value, positionValues, position) => { return positionValues.join(" "); } switch (position) { - case "top": { + case TOP: { return [value, val1, val1].join(" "); } - case "right": { + case RIGHT: { return [val1, value, val1, val1].join(" "); } - case "bottom": { + case BOTTOM: { return [val1, val1, value].join(" "); } - case "left": { + case LEFT: { return [val1, val1, val1, value].join(" "); } default: @@ -242,25 +297,25 @@ const replacePositionValue = (value, positionValues, position) => { return replacePositionValue(value, [val1], position); } switch (position) { - case "top": { + case TOP: { if (val1 === value) { return positionValues.join(" "); } return [value, val2, val1].join(" "); } - case "right": { + case RIGHT: { if (val2 === value) { return positionValues.join(" "); } return [val1, value, val1, val2].join(" "); } - case "bottom": { + case BOTTOM: { if (val1 === value) { return positionValues.join(" "); } return [val1, val2, value].join(" "); } - case "left": { + case LEFT: { if (val2 === value) { return positionValues.join(" "); } @@ -276,7 +331,7 @@ const replacePositionValue = (value, positionValues, position) => { return replacePositionValue(value, [val1, val2], position); } switch (position) { - case "top": { + case TOP: { if (val1 === value) { return positionValues.join(" "); } else if (val3 === value) { @@ -284,13 +339,13 @@ const replacePositionValue = (value, positionValues, position) => { } return [value, val2, val3].join(" "); } - case "right": { + case RIGHT: { if (val2 === value) { return positionValues.join(" "); } return [val1, value, val3, val2].join(" "); } - case "bottom": { + case BOTTOM: { if (val3 === value) { return positionValues.join(" "); } else if (val1 === value) { @@ -298,7 +353,7 @@ const replacePositionValue = (value, positionValues, position) => { } return [val1, val2, value].join(" "); } - case "left": { + case LEFT: { if (val2 === value) { return positionValues.join(" "); } @@ -314,13 +369,13 @@ const replacePositionValue = (value, positionValues, position) => { return replacePositionValue(value, [val1, val2, val3], position); } switch (position) { - case "top": { + case TOP: { if (val1 === value) { return positionValues.join(" "); } return [value, val2, val3, val4].join(" "); } - case "right": { + case RIGHT: { if (val2 === value) { return positionValues.join(" "); } else if (val4 === value) { @@ -328,13 +383,13 @@ const replacePositionValue = (value, positionValues, position) => { } return [val1, value, val3, val4].join(" "); } - case "bottom": { + case BOTTOM: { if (val3 === value) { return positionValues.join(" "); } return [val1, val2, value, val4].join(" "); } - case "left": { + case LEFT: { if (val4 === value) { return positionValues.join(" "); } else if (val2 === value) { @@ -350,11 +405,15 @@ const replacePositionValue = (value, positionValues, position) => { } }; -exports.prepareBorderProperties = (property, value, priority, properties, opt = {}) => { +const prepareBorderProperties = (property, value, priority, properties, opt = {}) => { if (typeof property !== "string" || value === null) { return; } - const { globalObject } = opt; + const { globalObject, options } = opt; + const parseOpt = { + globalObject, + options + }; const { lines, name, positions } = borderElements; const [prop1, prop2, prop3] = property.split("-"); if (prop1 !== name) { @@ -374,10 +433,10 @@ exports.prepareBorderProperties = (property, value, priority, properties, opt = const nameProperty = prop1; // Empty string, global keywords, var(), value of longhands. if (typeof value === "string") { - // longhand properties + // Handle longhand properties if (prop3) { const nameItem = getPropertyItem(nameProperty, properties); - const imageItem = getPropertyItem(borderImageProperty, properties); + const imageItem = getPropertyItem(BORDER_IMAGE, properties); const lineProperty = `${prop1}-${prop3}`; const lineItem = getPropertyItem(lineProperty, properties); const positionProperty = `${prop1}-${prop2}`; @@ -404,9 +463,7 @@ exports.prepareBorderProperties = (property, value, priority, properties, opt = } else { if ( nameItem.value && - !matchesBorderShorthandValue(lineProperty, propertyValue, nameItem.value, { - globalObject - }) + !matchesBorderShorthandValue(lineProperty, propertyValue, nameItem.value, parseOpt) ) { nameItem.value = ""; } @@ -415,22 +472,20 @@ exports.prepareBorderProperties = (property, value, priority, properties, opt = } if ( positionItem.value && - !matchesBorderShorthandValue(lineProperty, propertyValue, positionItem.value, { - globalObject - }) + !matchesBorderShorthandValue(lineProperty, propertyValue, positionItem.value, parseOpt) ) { positionItem.value = ""; } } borderItems.set(nameProperty, nameItem); - borderItems.set(borderImageProperty, imageItem); + borderItems.set(BORDER_IMAGE, imageItem); borderItems.set(lineProperty, lineItem); borderItems.set(positionProperty, positionItem); borderItems.set(longhandProperty, longhandItem); - // border-top, border-right, border-bottom, border-left shorthands + // Handle 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 imageItem = getPropertyItem(BORDER_IMAGE, properties); const lineWidthProperty = `${prop1}-width`; const lineWidthItem = getPropertyItem(lineWidthProperty, properties); const lineStyleProperty = `${prop1}-style`; @@ -463,19 +518,26 @@ exports.prepareBorderProperties = (property, value, priority, properties, opt = } else { if ( nameItem.value && - !matchesBorderShorthandValue(property, propertyValue, nameItem.value, { - globalObject - }) + !matchesBorderShorthandValue(property, propertyValue, nameItem.value, parseOpt) ) { nameItem.value = ""; } - if (lineWidthItem.value && isValidPropertyValue(lineWidthProperty, propertyValue)) { + if ( + lineWidthItem.value && + isValidPropertyValue(lineWidthProperty, propertyValue, globalObject) + ) { lineWidthItem.value = propertyValue; } - if (lineStyleItem.value && isValidPropertyValue(lineStyleProperty, propertyValue)) { + if ( + lineStyleItem.value && + isValidPropertyValue(lineStyleProperty, propertyValue, globalObject) + ) { lineStyleItem.value = propertyValue; } - if (lineColorItem.value && isValidPropertyValue(lineColorProperty, propertyValue)) { + if ( + lineColorItem.value && + isValidPropertyValue(lineColorProperty, propertyValue, globalObject) + ) { lineColorItem.value = propertyValue; } } @@ -487,15 +549,15 @@ exports.prepareBorderProperties = (property, value, priority, properties, opt = borderItems.set(longhandProperty, longhandItem); } borderItems.set(nameProperty, nameItem); - borderItems.set(borderImageProperty, imageItem); + borderItems.set(BORDER_IMAGE, imageItem); borderItems.set(lineWidthProperty, lineWidthItem); borderItems.set(lineStyleProperty, lineStyleItem); borderItems.set(lineColorProperty, lineColorItem); borderItems.set(positionProperty, positionItem); - // border-width, border-style, border-color + // Handle border-width, border-style, border-color shorthands } else if (prop2 && lines.includes(prop2)) { const nameItem = getPropertyItem(nameProperty, properties); - const imageItem = getPropertyItem(borderImageProperty, properties); + const imageItem = getPropertyItem(BORDER_IMAGE, properties); const lineProperty = `${prop1}-${prop2}`; const lineItem = getPropertyItem(lineProperty, properties); lineItem.value = value; @@ -514,9 +576,11 @@ exports.prepareBorderProperties = (property, value, priority, properties, opt = const longhandProperty = `${prop1}-${position}-${prop2}`; const longhandItem = getPropertyItem(longhandProperty, properties); if (propertyValue) { - positionItem.value = replaceBorderShorthandValue(propertyValue, positionItem.value, { - globalObject - }); + positionItem.value = replaceBorderShorthandValue( + propertyValue, + positionItem.value, + parseOpt + ); } else { positionItem.value = ""; } @@ -526,14 +590,14 @@ exports.prepareBorderProperties = (property, value, priority, properties, opt = borderItems.set(longhandProperty, longhandItem); } borderItems.set(nameProperty, nameItem); - borderItems.set(borderImageProperty, imageItem); + borderItems.set(BORDER_IMAGE, imageItem); borderItems.set(lineProperty, lineItem); - // border shorthand + // Handle border shorthand } else { const nameItem = getPropertyItem(nameProperty, properties); - const imageItem = getPropertyItem(borderImageProperty, properties); + const imageItem = getPropertyItem(BORDER_IMAGE, properties); const propertyValue = hasVarFunc(value) ? "" : value; - imageItem.value = propertyValue ? "none" : ""; + imageItem.value = propertyValue ? NONE : ""; for (const line of lines) { const lineProperty = `${prop1}-${line}`; const lineItem = getPropertyItem(lineProperty, properties); @@ -556,7 +620,7 @@ exports.prepareBorderProperties = (property, value, priority, properties, opt = } } borderItems.set(property, nameItem); - borderItems.set(borderImageProperty, imageItem); + borderItems.set(BORDER_IMAGE, imageItem); } // Values of border-width, border-style, border-color } else if (Array.isArray(value)) { @@ -564,15 +628,17 @@ exports.prepareBorderProperties = (property, value, priority, properties, opt = return; } const nameItem = getPropertyItem(nameProperty, properties); - const imageItem = getPropertyItem(borderImageProperty, 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 && propertyValue) { - nameItem.value = replaceBorderShorthandValue(propertyValue, nameItem.value, { - globalObject - }); + if (nameItem.value) { + if (hasVarFunc(nameItem.value)) { + nameItem.value = ""; + } else if (propertyValue) { + nameItem.value = replaceBorderShorthandValue(propertyValue, nameItem.value, parseOpt); + } } } else { nameItem.value = ""; @@ -624,9 +690,7 @@ exports.prepareBorderProperties = (property, value, priority, properties, opt = positionItem.value = replaceBorderShorthandValue( positionValues[position], positionItem.value, - { - globalObject - } + parseOpt ); } const longhandProperty = `${positionProperty}-${prop2}`; @@ -637,17 +701,17 @@ exports.prepareBorderProperties = (property, value, priority, properties, opt = borderItems.set(longhandProperty, longhandItem); } borderItems.set(nameProperty, nameItem); - borderItems.set(borderImageProperty, imageItem); + borderItems.set(BORDER_IMAGE, imageItem); borderItems.set(lineProperty, lineItem); // Values of border, border-top, border-right, border-bottom, border-top. } else if (value && typeof value === "object") { - // position shorthands + // Handle position shorthands if (prop2) { if (!positions.includes(prop2)) { return; } const nameItem = getPropertyItem(nameProperty, properties); - const imageItem = getPropertyItem(borderImageProperty, properties); + const imageItem = getPropertyItem(BORDER_IMAGE, properties); const lineWidthProperty = `${prop1}-width`; const lineWidthItem = getPropertyItem(lineWidthProperty, properties); const lineStyleProperty = `${prop1}-style`; @@ -658,11 +722,7 @@ exports.prepareBorderProperties = (property, value, priority, properties, opt = const positionItem = getPropertyItem(positionProperty, properties); if (nameItem.value) { for (const positionValue of Object.values(value)) { - if ( - !matchesBorderShorthandValue(property, positionValue, nameItem.value, { - globalObject - }) - ) { + if (!matchesBorderShorthandValue(property, positionValue, nameItem.value, parseOpt)) { nameItem.value = ""; break; } @@ -675,7 +735,7 @@ exports.prepareBorderProperties = (property, value, priority, properties, opt = const longhandItem = getPropertyItem(longhandProperty, properties); if (Object.hasOwn(value, longhandProperty)) { const itemValue = value[longhandProperty]; - if (line === "width") { + if (line === WIDTH) { if (lineWidthItem.value) { lineWidthItem.value = replacePositionValue( itemValue, @@ -683,7 +743,7 @@ exports.prepareBorderProperties = (property, value, priority, properties, opt = prop2 ); } - } else if (line === "style") { + } else if (line === STYLE) { if (lineStyleItem.value) { lineStyleItem.value = replacePositionValue( itemValue, @@ -691,7 +751,7 @@ exports.prepareBorderProperties = (property, value, priority, properties, opt = prop2 ); } - } else if (line === "color") { + } else if (line === COLOR) { if (lineColorItem.value) { lineColorItem.value = replacePositionValue( itemValue, @@ -704,7 +764,7 @@ exports.prepareBorderProperties = (property, value, priority, properties, opt = longhandItem.priority = priority; } else { const itemValue = border.initialValues.get(`${prop1}-${line}`); - if (line === "width") { + if (line === WIDTH) { if (lineWidthItem.value) { lineWidthItem.value = replacePositionValue( itemValue, @@ -712,7 +772,7 @@ exports.prepareBorderProperties = (property, value, priority, properties, opt = prop2 ); } - } else if (line === "style") { + } else if (line === STYLE) { if (lineStyleItem.value) { lineStyleItem.value = replacePositionValue( itemValue, @@ -720,7 +780,7 @@ exports.prepareBorderProperties = (property, value, priority, properties, opt = prop2 ); } - } else if (line === "color") { + } else if (line === COLOR) { if (lineColorItem.value) { lineColorItem.value = replacePositionValue( itemValue, @@ -735,15 +795,15 @@ exports.prepareBorderProperties = (property, value, priority, properties, opt = borderItems.set(longhandProperty, longhandItem); } borderItems.set(nameProperty, nameItem); - borderItems.set(borderImageProperty, imageItem); + borderItems.set(BORDER_IMAGE, imageItem); borderItems.set(lineWidthProperty, lineWidthItem); borderItems.set(lineStyleProperty, lineStyleItem); borderItems.set(lineColorProperty, lineColorItem); borderItems.set(positionProperty, positionItem); - // border shorthand + // Handle border shorthand } else { const nameItem = getPropertyItem(prop1, properties); - const imageItem = getPropertyItem(borderImageProperty, properties); + const imageItem = getPropertyItem(BORDER_IMAGE, properties); const lineWidthProperty = `${prop1}-width`; const lineWidthItem = getPropertyItem(lineWidthProperty, properties); const lineStyleProperty = `${prop1}-style`; @@ -753,7 +813,7 @@ exports.prepareBorderProperties = (property, value, priority, properties, opt = const propertyValue = Object.values(value).join(" "); nameItem.value = propertyValue; nameItem.priority = priority; - imageItem.value = propertyValue ? "none" : ""; + imageItem.value = propertyValue ? NONE : ""; if (Object.hasOwn(value, lineWidthProperty)) { lineWidthItem.value = value[lineWidthProperty]; } else { @@ -792,7 +852,7 @@ exports.prepareBorderProperties = (property, value, priority, properties, opt = borderItems.set(positionProperty, positionItem); } borderItems.set(property, nameItem); - borderItems.set(borderImageProperty, imageItem); + borderItems.set(BORDER_IMAGE, imageItem); borderItems.set(lineWidthProperty, lineWidthItem); borderItems.set(lineStyleProperty, lineStyleItem); borderItems.set(lineColorProperty, lineColorItem); @@ -803,7 +863,7 @@ exports.prepareBorderProperties = (property, value, priority, properties, opt = 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) ?? @@ -812,7 +872,7 @@ exports.prepareBorderProperties = (property, value, priority, properties, opt = value: "", priority: "" }; - borderProperties.set(lineProperty, lineItem); + borderProps.set(lineProperty, lineItem); } for (const position of positions) { const positionProperty = `${name}-${position}`; @@ -822,7 +882,7 @@ exports.prepareBorderProperties = (property, value, priority, properties, opt = value: "", priority: "" }; - borderProperties.set(positionProperty, positionItem); + borderProps.set(positionProperty, positionItem); for (const line of lines) { const longhandProperty = `${name}-${position}-${line}`; const longhandItem = borderItems.get(longhandProperty) ?? @@ -831,16 +891,16 @@ exports.prepareBorderProperties = (property, value, priority, properties, opt = value: "", priority: "" }; - borderProperties.set(longhandProperty, longhandItem); + borderProps.set(longhandProperty, longhandItem); } } - const borderImageItem = borderItems.get(borderImageProperty) ?? { - property: borderImageProperty, + const borderImageItem = borderItems.get(BORDER_IMAGE) ?? { + property: BORDER_IMAGE, value: "", priority: "" }; - borderProperties.set(borderImageProperty, borderImageItem); - return borderProperties; + borderProps.set(BORDER_IMAGE, borderImageItem); + return borderProps; }; const generateBorderLineShorthand = (items, property, prior) => { @@ -849,7 +909,7 @@ const generateBorderLineShorthand = (items, property, prior) => { 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 }]; }; @@ -892,7 +952,7 @@ const prepareBorderShorthands = (properties) => { for (const [property, { priority, value }] of properties) { const [, positionPart, linePart] = property.split("-"); switch (linePart) { - case "width": { + case WIDTH: { if (priority) { lineWidthPriorItems.set(property, { property, value, priority }); } else { @@ -900,7 +960,7 @@ const prepareBorderShorthands = (properties) => { } break; } - case "style": { + case STYLE: { if (priority) { lineStylePriorItems.set(property, { property, value, priority }); } else { @@ -908,7 +968,7 @@ const prepareBorderShorthands = (properties) => { } break; } - case "color": { + case COLOR: { if (priority) { lineColorPriorItems.set(property, { property, value, priority }); } else { @@ -919,7 +979,7 @@ const prepareBorderShorthands = (properties) => { default: } switch (positionPart) { - case "top": { + case TOP: { if (priority) { positionTopPriorItems.set(property, { property, value, priority }); } else { @@ -927,7 +987,7 @@ const prepareBorderShorthands = (properties) => { } break; } - case "right": { + case RIGHT: { if (priority) { positionRightPriorItems.set(property, { property, value, priority }); } else { @@ -935,7 +995,7 @@ const prepareBorderShorthands = (properties) => { } break; } - case "bottom": { + case BOTTOM: { if (priority) { positionBottomPriorItems.set(property, { property, value, priority }); } else { @@ -943,7 +1003,7 @@ const prepareBorderShorthands = (properties) => { } break; } - case "left": { + case LEFT: { if (priority) { positionLeftPriorItems.set(property, { property, value, priority }); } else { @@ -955,37 +1015,37 @@ const prepareBorderShorthands = (properties) => { } } if (lineWidthItems.size === 4) { - const [property, item] = generateBorderLineShorthand(lineWidthItems, "border-width") ?? []; + 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") ?? []; + generateBorderLineShorthand(lineWidthPriorItems, BORDER_WIDTH, "important") ?? []; if (property && item) { properties.set(property, item); } } if (lineStyleItems.size === 4) { - const [property, item] = generateBorderLineShorthand(lineStyleItems, "border-style") ?? []; + 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") ?? []; + generateBorderLineShorthand(lineStylePriorItems, BORDER_STYLE, "important") ?? []; if (property && item) { properties.set(property, item); } } if (lineColorItems.size === 4) { - const [property, item] = generateBorderLineShorthand(lineColorItems, "border-color") ?? []; + 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") ?? []; + generateBorderLineShorthand(lineColorPriorItems, BORDER_COLOR, "important") ?? []; if (property && item) { properties.set(property, item); } @@ -993,12 +1053,12 @@ const prepareBorderShorthands = (properties) => { const nameItems = []; const namePriorItems = []; if (positionTopItems.size === 3) { - const [property, item] = generateBorderPositionShorthand(positionTopItems, "border-top") ?? []; + 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") { + if (properties.has(BORDER_IMAGE)) { + const { value: imageValue } = properties.get(BORDER_IMAGE); + if (imageValue === NONE) { const { value: itemValue } = item; nameItems.push(itemValue); } @@ -1006,12 +1066,12 @@ const prepareBorderShorthands = (properties) => { } } else if (positionTopPriorItems.size === 3) { const [property, item] = - generateBorderPositionShorthand(positionTopPriorItems, "border-top", "important") ?? []; + 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") { + if (properties.has(BORDER_IMAGE)) { + const { value: imageValue } = properties.get(BORDER_IMAGE); + if (imageValue === NONE) { const { value: itemValue } = item; namePriorItems.push(itemValue); } @@ -1020,12 +1080,12 @@ const prepareBorderShorthands = (properties) => { } if (positionRightItems.size === 3) { const [property, item] = - generateBorderPositionShorthand(positionRightItems, "border-right") ?? []; + generateBorderPositionShorthand(positionRightItems, BORDER_RIGHT) ?? []; if (property && item) { properties.set(property, item); - if (properties.has(borderImageProperty)) { - const { value: imageValue } = properties.get(borderImageProperty); - if (imageValue === "none") { + if (properties.has(BORDER_IMAGE)) { + const { value: imageValue } = properties.get(BORDER_IMAGE); + if (imageValue === NONE) { const { value: itemValue } = item; nameItems.push(itemValue); } @@ -1033,12 +1093,12 @@ const prepareBorderShorthands = (properties) => { } } else if (positionRightPriorItems.size === 3) { const [property, item] = - generateBorderPositionShorthand(positionRightPriorItems, "border-right", "important") ?? []; + 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") { + if (properties.has(BORDER_IMAGE)) { + const { value: imageValue } = properties.get(BORDER_IMAGE); + if (imageValue === NONE) { const { value: itemValue } = item; nameItems.push(itemValue); } @@ -1047,12 +1107,12 @@ const prepareBorderShorthands = (properties) => { } if (positionBottomItems.size === 3) { const [property, item] = - generateBorderPositionShorthand(positionBottomItems, "border-bottom") ?? []; + generateBorderPositionShorthand(positionBottomItems, BORDER_BOTTOM) ?? []; if (property && item) { properties.set(property, item); - if (properties.has(borderImageProperty)) { - const { value: imageValue } = properties.get(borderImageProperty); - if (imageValue === "none") { + if (properties.has(BORDER_IMAGE)) { + const { value: imageValue } = properties.get(BORDER_IMAGE); + if (imageValue === NONE) { const { value: itemValue } = item; nameItems.push(itemValue); } @@ -1060,12 +1120,12 @@ const prepareBorderShorthands = (properties) => { } } else if (positionBottomPriorItems.size === 3) { const [property, item] = - generateBorderPositionShorthand(positionBottomPriorItems, "border-bottom", "important") ?? []; + 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") { + if (properties.has(BORDER_IMAGE)) { + const { value: imageValue } = properties.get(BORDER_IMAGE); + if (imageValue === NONE) { const { value: itemValue } = item; nameItems.push(itemValue); } @@ -1073,13 +1133,12 @@ const prepareBorderShorthands = (properties) => { } } if (positionLeftItems.size === 3) { - const [property, item] = - generateBorderPositionShorthand(positionLeftItems, "border-left") ?? []; + 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") { + if (properties.has(BORDER_IMAGE)) { + const { value: imageValue } = properties.get(BORDER_IMAGE); + if (imageValue === NONE) { const { value: itemValue } = item; nameItems.push(itemValue); } @@ -1087,12 +1146,12 @@ const prepareBorderShorthands = (properties) => { } } else if (positionLeftPriorItems.size === 3) { const [property, item] = - generateBorderPositionShorthand(positionLeftPriorItems, "border-left", "important") ?? []; + 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") { + if (properties.has(BORDER_IMAGE)) { + const { value: imageValue } = properties.get(BORDER_IMAGE); + if (imageValue === NONE) { const { value: itemValue } = item; nameItems.push(itemValue); } @@ -1101,33 +1160,32 @@ const prepareBorderShorthands = (properties) => { } const mixedPriorities = nameItems.length && namePriorItems.length; const imageItem = { - property: borderImageProperty, - value: "none", + property: BORDER_IMAGE, + value: NONE, priority: "" }; 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,25 +1207,30 @@ 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; +const prepareProperties = (properties, opt = {}) => { + const { globalObject, options } = opt; + const parseOpt = { + globalObject, + options + }; const { positions } = borderElements; const parsedProperties = new Map(); const prepareShorthands = new Map(); - const borderProperties = new Map(); + const borderProps = 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)) { + const { logicalPropertyGroup: shorthandProperty } = propertyDefinitions.get(property) ?? {}; + if (borderProperties.has(property)) { + borderProps.set(property, { property, value, priority }); + } else if (shorthandProperties.has(shorthandProperty)) { if (!prepareShorthands.has(shorthandProperty)) { prepareShorthands.set(shorthandProperty, new Map()); } @@ -1186,11 +1249,9 @@ exports.prepareProperties = (properties, opt = {}) => { prepareShorthands.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,7 +1265,7 @@ exports.prepareProperties = (properties, opt = {}) => { } } const { position } = longhandItem; - const longhandValue = exports.getPositionValue([parsedValue], position); + const longhandValue = getPositionValue([parsedValue], position); parsedProperties.set(longhandProperty, { property: longhandProperty, value: longhandValue, @@ -1221,7 +1282,7 @@ exports.prepareProperties = (properties, opt = {}) => { }); } } - } else if (parsedValues) { + } else if (parsedValues && typeof parsedValues !== "string") { for (const longhandProperty of Object.keys(parsedValues)) { const longhandValue = parsedValues[longhandProperty]; parsedProperties.set(longhandProperty, { @@ -1232,15 +1293,36 @@ exports.prepareProperties = (properties, opt = {}) => { } } if (!omitShorthandProperty) { - parsedProperties.set(property, { property, value, priority }); + if (property === BACKGROUND) { + hasPrecedingBackground = true; + parsedProperties.set(property, { property, value, priority }); + } else { + parsedProperties.set(property, { property, value, priority }); + } } } else { parsedProperties.set(property, { property, value, priority }); + if (hasPrecedingBackground) { + const { value: shorthandValue, priority: shorthandPriority } = properties.get(BACKGROUND); + if ((!shorthandPriority || priority) && !hasVarFunc(shorthandValue)) { + const replacedShorthandValue = replaceBackgroundShorthand( + property, + parsedProperties, + parseOpt + ); + properties.delete(BACKGROUND); + properties.set(BACKGROUND, { + property: BACKGROUND, + value: replacedShorthandValue, + priority: shorthandPriority + }); + } + } } } if (prepareShorthands.size) { for (const [property, item] of prepareShorthands) { - const shorthandItem = exports.shorthandProperties.get(property); + const shorthandItem = shorthandProperties.get(property); if (item.size === shorthandItem.shorthandFor.size) { if (shorthandItem.position) { const positionValues = []; @@ -1251,7 +1333,7 @@ exports.prepareProperties = (properties, opt = {}) => { priority = longhandPriority; } } - const value = exports.getPositionValue(positionValues, shorthandItem.position); + const value = getPositionValue(positionValues, shorthandItem.position); parsedProperties.set(property, { property, value, @@ -1261,15 +1343,13 @@ exports.prepareProperties = (properties, opt = {}) => { } } } - if (borderProperties.size) { + if (borderProps.size) { const longhandProperties = new Map(); - for (const [property, item] of borderProperties) { - if (exports.shorthandProperties.has(property)) { + for (const [property, item] of borderProps) { + if (shorthandProperties.has(property)) { const { value, priority } = item; - if (property === "border") { - const lineItems = border.parse(value, { - globalObject - }); + if (property === BORDER) { + const lineItems = border.parse(value, parseOpt); for (const [key, initialValue] of border.initialValues) { if (!Object.hasOwn(lineItems, key)) { lineItems[key] = initialValue; @@ -1297,22 +1377,20 @@ exports.prepareProperties = (properties, opt = {}) => { } } if (value) { - longhandProperties.set(borderImageProperty, { - property: borderImageProperty, - value: "none", + longhandProperties.set(BORDER_IMAGE, { + property: BORDER_IMAGE, + value: NONE, priority }); } } else { - const shorthandItem = exports.shorthandProperties.get(property); - const parsedItem = shorthandItem.parse(value, { - globalObject - }); + const shorthandItem = shorthandProperties.get(property); + const parsedItem = shorthandItem.parse(value, parseOpt); 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 longhandValue = getPositionValue(parsedItem, position); const longhandItem = { property: longhandProperty, value: longhandValue, @@ -1371,7 +1449,7 @@ exports.prepareProperties = (properties, opt = {}) => { return parsedProperties; }; -exports.normalizeBorderProperties = (properties) => { +const normalizeProperties = (properties) => { const { lines, name, positions } = borderElements; if (properties.has(name)) { for (const line of lines) { @@ -1415,3 +1493,12 @@ exports.normalizeBorderProperties = (properties) => { } return properties; }; + +module.exports = { + borderProperties, + getPositionValue, + normalizeProperties, + prepareBorderProperties, + prepareProperties, + shorthandProperties +}; diff --git a/lib/parsers.js b/lib/parsers.js index 8527e321..3a062bc9 100644 --- a/lib/parsers.js +++ b/lib/parsers.js @@ -6,6 +6,7 @@ const { } = require("@asamuzakjp/css-color"); const { next: syntaxes } = require("@csstools/css-syntax-patches-for-csstree"); const csstree = require("css-tree"); +const { getCache, setCache } = require("./utils/cache"); const { asciiLowercase } = require("./utils/strings"); // CSS global keywords @@ -73,7 +74,7 @@ const varContainedRegEx = /(?<=[*/\s(])var\(/; const cssTree = csstree.fork(syntaxes); // Prepare stringified value. -exports.prepareValue = (value, globalObject = globalThis) => { +const prepareValue = (value, globalObject = globalThis) => { // `null` is converted to an empty string. // @see https://webidl.spec.whatwg.org/#LegacyNullToEmptyString if (value === null) { @@ -100,30 +101,27 @@ exports.prepareValue = (value, globalObject = globalThis) => { }; // Value is a global keyword. -exports.isGlobalKeyword = (val) => { +const isGlobalKeyword = (val) => { return GLOBAL_KEY.includes(asciiLowercase(val)); }; // Value starts with and/or contains CSS var() function. -exports.hasVarFunc = (val) => { +const hasVarFunc = (val) => { return varRegEx.test(val) || varContainedRegEx.test(val); }; // Value starts with and/or contains CSS calc() related functions. -exports.hasCalcFunc = (val) => { +const hasCalcFunc = (val) => { return calcRegEx.test(val) || calcContainedRegEx.test(val); }; -// Splits value into an array. -// @see https://github.com/asamuzaK/cssColor/blob/main/src/js/util.ts -exports.splitValue = splitValue; - // Parse CSS to AST. -exports.parseCSS = (val, opt, toObject = false) => { +const parseCSS = (val, opt = {}, toObject = false) => { + const { globalObject, options } = opt; if (typeof val !== "string") { - val = exports.prepareValue(val); + val = prepareValue(val, globalObject); } - const ast = cssTree.parse(val, opt); + const ast = cssTree.parse(val, options); if (toObject) { return cssTree.toPlainObject(ast); } @@ -132,9 +130,9 @@ exports.parseCSS = (val, opt, toObject = false) => { // Value is a valid property value. // Returns `false` for custom property and/or var(). -exports.isValidPropertyValue = (prop, val) => { +const isValidPropertyValue = (prop, val, globalObject) => { if (typeof val !== "string") { - val = exports.prepareValue(val); + val = prepareValue(val, globalObject); } if (val === "") { return true; @@ -150,8 +148,12 @@ exports.isValidPropertyValue = (prop, val) => { } let ast; try { - ast = exports.parseCSS(val, { - context: "value" + // TBD: use cache? + ast = parseCSS(val, { + globalObject, + options: { + context: "value" + } }); } catch { return false; @@ -160,15 +162,30 @@ exports.isValidPropertyValue = (prop, val) => { return error === null && matched !== null; }; +const defaultOptions = { + format: "specifiedValue" +}; + // Simplify / resolve math functions. -exports.resolveCalc = (val, opt = { format: "specifiedValue" }) => { +const resolveCalc = (val, opt = {}) => { + const { globalObject, options } = opt; if (typeof val !== "string") { - val = exports.prepareValue(val); + val = prepareValue(val, globalObject); } - if (val === "" || exports.hasVarFunc(val) || !exports.hasCalcFunc(val)) { + if (val === "" || hasVarFunc(val) || !hasCalcFunc(val)) { return val; } - const obj = exports.parseCSS(val, { context: "value" }, true); + // TBD: use cache? + const obj = parseCSS( + val, + { + globalObject, + options: { + context: "value" + } + }, + true + ); if (!obj?.children) { return; } @@ -180,9 +197,10 @@ exports.resolveCalc = (val, opt = { format: "specifiedValue" }) => { const value = cssTree .generate(item) .replace(/\)(?!\)|\s|,)/g, ") ") + .replace(/,(?!\s)/g, ", ") .trim(); if (calcNameRegEx.test(itemName)) { - const newValue = cssCalc(value, opt); + const newValue = cssCalc(value, options ?? defaultOptions); values.push(newValue); } else { values.push(value); @@ -197,15 +215,13 @@ exports.resolveCalc = (val, opt = { format: "specifiedValue" }) => { }; // Parse property value. Returns string or array of parsed object. -exports.parsePropertyValue = (prop, val, opt = {}) => { +const parsePropertyValue = (prop, val, opt = {}) => { const { caseSensitive, globalObject, inArray } = opt; - val = exports.prepareValue(val, globalObject); - if (val === "" || exports.hasVarFunc(val)) { + val = prepareValue(val, globalObject); + if (val === "" || hasVarFunc(val)) { return val; - } else if (exports.hasCalcFunc(val)) { - const calculatedValue = exports.resolveCalc(val, { - format: "specifiedValue" - }); + } else if (hasCalcFunc(val)) { + const calculatedValue = resolveCalc(val, opt); if (typeof calculatedValue !== "string") { return; } @@ -237,8 +253,19 @@ exports.parsePropertyValue = (prop, val, opt = {}) => { return; } try { - const ast = exports.parseCSS(val, { - context: "value" + let cacheKey = ""; + if (inArray) { + cacheKey = `parsePropertyValue_${prop}_${val}_${caseSensitive}`; + const cachedValues = getCache(cacheKey); + if (Array.isArray(cachedValues)) { + return cachedValues; + } + } + const ast = parseCSS(val, { + globalObject, + options: { + context: "value" + } }); const { error, matched } = cssTree.lexer.matchProperty(prop, ast); if (error || !matched) { @@ -285,7 +312,7 @@ exports.parsePropertyValue = (prop, val, opt = {}) => { type: "Calc", name: "calc", isNumber: false, - value: `${asciiLowercase(itemValue)}`, + value: asciiLowercase(itemValue), raw }); } @@ -324,6 +351,9 @@ exports.parsePropertyValue = (prop, val, opt = {}) => { } } } + if (cacheKey) { + setCache(cacheKey, parsedValues); + } return parsedValues; } } catch { @@ -333,7 +363,7 @@ exports.parsePropertyValue = (prop, val, opt = {}) => { }; // Parse . -exports.parseNumber = (val, opt = {}) => { +const parseNumber = (val, opt = {}) => { const [item] = val; const { type, value } = item ?? {}; if (type !== "Number") { @@ -356,7 +386,7 @@ exports.parseNumber = (val, opt = {}) => { }; // Parse . -exports.parseLength = (val, opt = {}) => { +const parseLength = (val, opt = {}) => { const [item] = val; const { type, value, unit } = item ?? {}; if (type !== "Dimension" && !(type === "Number" && value === "0")) { @@ -378,12 +408,12 @@ exports.parseLength = (val, opt = {}) => { if (num === 0 && !unit) { return `${num}px`; } else if (unit) { - return `${num}${asciiLowercase(unit)}`; + return `${num}${unit}`; } }; // Parse . -exports.parsePercentage = (val, opt = {}) => { +const parsePercentage = (val, opt = {}) => { const [item] = val; const { type, value } = item ?? {}; if (type !== "Percentage" && !(type === "Number" && value === "0")) { @@ -409,7 +439,7 @@ exports.parsePercentage = (val, opt = {}) => { }; // Parse . -exports.parseLengthPercentage = (val, opt = {}) => { +const parseLengthPercentage = (val, opt = {}) => { const [item] = val; const { type, value, unit } = item ?? {}; if (type !== "Dimension" && type !== "Percentage" && !(type === "Number" && value === "0")) { @@ -432,7 +462,7 @@ exports.parseLengthPercentage = (val, opt = {}) => { if (/deg|g?rad|turn/i.test(unit)) { return; } - return `${num}${asciiLowercase(unit)}`; + return `${num}${unit}`; } else if (type === "Percentage") { return `${num}%`; } else if (num === 0) { @@ -441,7 +471,7 @@ exports.parseLengthPercentage = (val, opt = {}) => { }; // Parse . -exports.parseAngle = (val) => { +const parseAngle = (val) => { const [item] = val; const { type, value, unit } = item ?? {}; if (type !== "Dimension" && !(type === "Number" && value === "0")) { @@ -452,14 +482,14 @@ exports.parseAngle = (val) => { if (!/^(?:deg|g?rad|turn)$/i.test(unit)) { return; } - return `${num}${asciiLowercase(unit)}`; + return `${num}${unit}`; } else if (num === 0) { return `${num}deg`; } }; // Parse . -exports.parseUrl = (val) => { +const parseURL = (val) => { const [item] = val; const { type, value } = item ?? {}; if (type !== "Url") { @@ -470,7 +500,7 @@ exports.parseUrl = (val) => { }; // Parse . -exports.parseString = (val) => { +const parseString = (val) => { const [item] = val; const { type, value } = item ?? {}; if (type !== "String") { @@ -481,23 +511,19 @@ exports.parseString = (val) => { }; // Parse . -exports.parseColor = (val) => { +const parseColor = (val, opt = defaultOptions) => { const [item] = val; const { name, type, value } = item ?? {}; switch (type) { case "Function": { - const res = resolveColor(`${name}(${value})`, { - format: "specifiedValue" - }); + const res = resolveColor(`${name}(${value})`, opt); if (res) { return res; } break; } case "Hash": { - const res = resolveColor(`#${value}`, { - format: "specifiedValue" - }); + const res = resolveColor(`#${value}`, opt); if (res) { return res; } @@ -507,9 +533,7 @@ exports.parseColor = (val) => { if (SYS_COLOR.includes(name)) { return name; } - const res = resolveColor(name, { - format: "specifiedValue" - }); + const res = resolveColor(name, opt); if (res) { return res; } @@ -520,16 +544,35 @@ exports.parseColor = (val) => { }; // Parse . -exports.parseGradient = (val) => { +const parseGradient = (val, opt = defaultOptions) => { const [item] = val; const { name, type, value } = item ?? {}; if (type !== "Function") { return; } - const res = resolveGradient(`${name}(${value})`, { - format: "specifiedValue" - }); + const res = resolveGradient(`${name}(${value})`, opt); if (res) { return res; } }; + +module.exports = { + hasCalcFunc, + hasVarFunc, + isGlobalKeyword, + isValidPropertyValue, + parseAngle, + parseCSS, + parseColor, + parseGradient, + parseLength, + parseLengthPercentage, + parseNumber, + parsePercentage, + parsePropertyValue, + parseString, + parseURL, + prepareValue, + resolveCalc, + splitValue +}; diff --git a/lib/properties/background.js b/lib/properties/background.js index c94327bf..ce675c94 100644 --- a/lib/properties/background.js +++ b/lib/properties/background.js @@ -11,7 +11,8 @@ const backgroundAttachment = require("./backgroundAttachment"); const backgroundColor = require("./backgroundColor"); const property = "background"; -const initialValues = new Map([ + +module.exports.initialValues = new Map([ ["background-image", "none"], ["background-position", "0% 0%"], ["background-size", "auto"], @@ -34,13 +35,13 @@ module.exports.shorthandFor = new Map([ ]); module.exports.parse = function parse(v, opt = {}) { - const { globalObject } = opt; + const { globalObject, options } = opt; if (v === "") { return v; } else if (parsers.hasCalcFunc(v)) { - v = parsers.resolveCalc(v); + v = parsers.resolveCalc(v, opt); } - if (!parsers.isValidPropertyValue(property, v)) { + if (!parsers.isValidPropertyValue(property, v, globalObject)) { return; } const values = parsers.splitValue(v, { @@ -50,24 +51,24 @@ module.exports.parse = function parse(v, opt = {}) { const l = values.length; for (let i = 0; i < l; i++) { let bg = { - "background-image": initialValues.get("background-image"), - "background-position": initialValues.get("background-position"), - "background-size": initialValues.get("background-size"), - "background-repeat": initialValues.get("background-repeat"), - "background-origin": initialValues.get("background-origin"), - "background-clip": initialValues.get("background-clip"), - "background-attachment": initialValues.get("background-attachment"), - "background-color": initialValues.get("background-color") + "background-image": module.exports.initialValues.get("background-image"), + "background-position": module.exports.initialValues.get("background-position"), + "background-size": module.exports.initialValues.get("background-size"), + "background-repeat": module.exports.initialValues.get("background-repeat"), + "background-origin": module.exports.initialValues.get("background-origin"), + "background-clip": module.exports.initialValues.get("background-clip"), + "background-attachment": module.exports.initialValues.get("background-attachment"), + "background-color": module.exports.initialValues.get("background-color") }; if (l > 1 && i !== l - 1) { bg = { - "background-image": initialValues.get("background-image"), - "background-position": initialValues.get("background-position"), - "background-size": initialValues.get("background-size"), - "background-repeat": initialValues.get("background-repeat"), - "background-origin": initialValues.get("background-origin"), - "background-clip": initialValues.get("background-clip"), - "background-attachment": initialValues.get("background-attachment") + "background-image": module.exports.initialValues.get("background-image"), + "background-position": module.exports.initialValues.get("background-position"), + "background-size": module.exports.initialValues.get("background-size"), + "background-repeat": module.exports.initialValues.get("background-repeat"), + "background-origin": module.exports.initialValues.get("background-origin"), + "background-clip": module.exports.initialValues.get("background-clip"), + "background-attachment": module.exports.initialValues.get("background-attachment") }; } const bgPosition = []; @@ -85,12 +86,12 @@ module.exports.parse = function parse(v, opt = {}) { for (const part of parts1) { let partValid = false; for (const [longhand, value] of module.exports.shorthandFor) { - if (parsers.isValidPropertyValue(longhand, part)) { + if (parsers.isValidPropertyValue(longhand, part, globalObject)) { partValid = true; switch (longhand) { case "background-clip": case "background-origin": { - const parsedValue = value.parse(part, { globalObject }); + const parsedValue = value.parse(part, { globalObject, options }); if (parsedValue) { bgBox.push(parsedValue); } @@ -100,31 +101,25 @@ module.exports.parse = function parse(v, opt = {}) { if (i !== values.length - 1) { return; } - const parsedValue = value.parse(part, { globalObject }); + const parsedValue = value.parse(part, { globalObject, options }); if (parsedValue) { bg[longhand] = parsedValue; } break; } case "background-position": { - const parsedValue = value.parse(part, { globalObject }); - if (parsedValue) { - bgPosition.push(parsedValue); - } + bgPosition.push(part); break; } case "background-repeat": { - const parsedValue = value.parse(part, { globalObject }); - if (parsedValue) { - bgRepeat.push(parsedValue); - } + bgRepeat.push(part); break; } case "background-size": { break; } default: { - const parsedValue = value.parse(part, { globalObject }); + const parsedValue = value.parse(part, { globalObject, options }); if (parsedValue) { bg[longhand] = parsedValue; } @@ -141,12 +136,12 @@ module.exports.parse = function parse(v, opt = {}) { for (const part of parts2) { let partValid = false; for (const [longhand, value] of module.exports.shorthandFor) { - if (parsers.isValidPropertyValue(longhand, part)) { + if (parsers.isValidPropertyValue(longhand, part, globalObject)) { partValid = true; switch (longhand) { case "background-clip": case "background-origin": { - const parsedValue = value.parse(part, { globalObject }); + const parsedValue = value.parse(part, { globalObject, options }); if (parsedValue) { bgBox.push(parsedValue); } @@ -156,7 +151,7 @@ module.exports.parse = function parse(v, opt = {}) { if (i !== l - 1) { return; } - const parsedValue = value.parse(part, { globalObject }); + const parsedValue = value.parse(part, { globalObject, options }); if (parsedValue) { bg[longhand] = parsedValue; } @@ -166,21 +161,15 @@ module.exports.parse = function parse(v, opt = {}) { break; } case "background-repeat": { - const parsedValue = value.parse(part, { globalObject }); - if (parsedValue) { - bgRepeat.push(parsedValue); - } + bgRepeat.push(part); break; } case "background-size": { - const parsedValue = value.parse(part, { globalObject }); - if (parsedValue) { - bgSize.push(parsedValue); - } + bgSize.push(part); break; } default: { - const parsedValue = value.parse(part, { globalObject }); + const parsedValue = value.parse(part, { globalObject, options }); if (parsedValue) { bg[longhand] = parsedValue; } @@ -195,21 +184,21 @@ module.exports.parse = function parse(v, opt = {}) { } if (bgPosition.length) { const { parse: parser } = module.exports.shorthandFor.get("background-position"); - const value = parser(bgPosition.join(" "), { globalObject }); + const value = parser(bgPosition.join(" "), { globalObject, options }); if (value) { bg["background-position"] = value; } } if (bgSize.length) { const { parse: parser } = module.exports.shorthandFor.get("background-size"); - const value = parser(bgSize.join(" "), { globalObject }); + const value = parser(bgSize.join(" "), { globalObject, options }); if (value) { bg["background-size"] = value; } } if (bgRepeat.length) { const { parse: parser } = module.exports.shorthandFor.get("background-repeat"); - const value = parser(bgRepeat.join(" "), { globalObject }); + const value = parser(bgRepeat.join(" "), { globalObject, options }); if (value) { bg["background-repeat"] = value; } @@ -248,7 +237,8 @@ module.exports.definition = { this._setProperty(property, v); } else { const bgValues = module.exports.parse(v, { - globalObject: this._global + globalObject: this._global, + options: this._options }); if (!Array.isArray(bgValues)) { return; @@ -271,7 +261,7 @@ module.exports.definition = { const arr = bgMap.get(longhand); arr.push(value); bgMap.set(longhand, arr); - if (value !== initialValues.get(longhand)) { + if (value !== module.exports.initialValues.get(longhand)) { if (longhand === "background-size") { bg.push(`/ ${value}`); } else { @@ -314,7 +304,7 @@ module.exports.definition = { ) { return val; } - if (val !== initialValues.get(longhand)) { + if (val !== module.exports.initialValues.get(longhand)) { const imgValues = parsers.splitValue(val, { delimiter: "," }); @@ -322,10 +312,10 @@ module.exports.definition = { bgMap.set(longhand, imgValues); } } else if (longhand === "background-color") { - if (val !== initialValues.get(longhand) || v.includes(val)) { + if (val !== module.exports.initialValues.get(longhand) || v.includes(val)) { bgMap.set(longhand, [val]); } - } else if (val !== initialValues.get(longhand)) { + } else if (val !== module.exports.initialValues.get(longhand)) { bgMap.set( longhand, parsers.splitValue(val, { @@ -334,10 +324,42 @@ module.exports.definition = { ); } } + // No background-image if (l === 0) { - const [background] = bgMap.get("background-color"); - if (background) { - return background; + if (bgMap.size) { + const bgValue = []; + for (const [longhand, values] of bgMap) { + switch (longhand) { + case "background-color": { + const [value] = values; + if (parsers.hasVarFunc(value)) { + return ""; + } + bgValue.push(value); + break; + } + case "background-size": { + const [value] = values; + if (parsers.hasVarFunc(value)) { + return ""; + } + if (value && value !== module.exports.initialValues.get(longhand)) { + bgValue.push(`/ ${value}`); + } + break; + } + default: { + const [value] = values; + if (parsers.hasVarFunc(value)) { + return ""; + } + if (value && value !== module.exports.initialValues.get(longhand)) { + bgValue.push(value); + } + } + } + } + return bgValue.join(" "); } return ""; } @@ -354,7 +376,7 @@ module.exports.definition = { if (parsers.hasVarFunc(value)) { return ""; } - if (value && value !== initialValues.get(longhand)) { + if (value && value !== module.exports.initialValues.get(longhand)) { const bgValue = bgValues[i]; bgValue.push(value); } @@ -366,7 +388,7 @@ module.exports.definition = { if (parsers.hasVarFunc(value)) { return ""; } - if (value && value !== initialValues.get(longhand)) { + if (value && value !== module.exports.initialValues.get(longhand)) { const bgValue = bgValues[i]; bgValue.push(`/ ${value}`); } @@ -377,7 +399,7 @@ module.exports.definition = { if (parsers.hasVarFunc(value)) { return ""; } - if (value && value !== initialValues.get(longhand)) { + if (value && value !== module.exports.initialValues.get(longhand)) { const bgValue = bgValues[i]; bgValue.push(value); } diff --git a/lib/properties/backgroundAttachment.js b/lib/properties/backgroundAttachment.js index e8ee4565..1d440e66 100644 --- a/lib/properties/backgroundAttachment.js +++ b/lib/properties/backgroundAttachment.js @@ -6,15 +6,16 @@ const property = "background-attachment"; const shorthand = "background"; module.exports.parse = function parse(v, opt = {}) { - const { globalObject } = opt; if (v === "") { return v; } + const { globalObject, options } = opt; const values = parsers.splitValue(v, { delimiter: "," }); const parsedValues = []; for (const val of values) { const value = parsers.parsePropertyValue(property, val, { globalObject, + options, inArray: true }); if (Array.isArray(value) && value.length === 1) { @@ -46,7 +47,8 @@ module.exports.definition = { this._setProperty(property, v); } else { const val = module.exports.parse(v, { - globalObject: this._global + globalObject: this._global, + options: this._options }); if (typeof val === "string") { const shorthandPriority = this._priorities.get(shorthand); diff --git a/lib/properties/backgroundClip.js b/lib/properties/backgroundClip.js index 5eb2fe20..40aec9e7 100644 --- a/lib/properties/backgroundClip.js +++ b/lib/properties/backgroundClip.js @@ -6,15 +6,16 @@ const property = "background-clip"; const shorthand = "background"; module.exports.parse = function parse(v, opt = {}) { - const { globalObject } = opt; if (v === "") { return v; } + const { globalObject, options } = opt; const values = parsers.splitValue(v, { delimiter: "," }); const parsedValues = []; for (const val of values) { const value = parsers.parsePropertyValue(property, val, { globalObject, + options, inArray: true }); if (Array.isArray(value) && value.length === 1) { @@ -46,7 +47,8 @@ module.exports.definition = { this._setProperty(property, v); } else { const val = module.exports.parse(v, { - globalObject: this._global + globalObject: this._global, + options: this._options }); if (typeof val === "string") { const shorthandPriority = this._priorities.get(shorthand); diff --git a/lib/properties/backgroundColor.js b/lib/properties/backgroundColor.js index 8dfe76fb..f06bd8b0 100644 --- a/lib/properties/backgroundColor.js +++ b/lib/properties/backgroundColor.js @@ -6,12 +6,13 @@ const property = "background-color"; const shorthand = "background"; module.exports.parse = function parse(v, opt = {}) { - const { globalObject } = opt; if (v === "") { return v; } + const { globalObject, options } = opt; const value = parsers.parsePropertyValue(property, v, { globalObject, + options, inArray: true }); if (Array.isArray(value) && value.length === 1) { @@ -21,7 +22,7 @@ module.exports.parse = function parse(v, opt = {}) { return name; } default: { - return parsers.parseColor(value); + return parsers.parseColor(value, options); } } } else if (typeof value === "string") { @@ -37,7 +38,8 @@ module.exports.definition = { this._setProperty(property, v); } else { const val = module.exports.parse(v, { - globalObject: this._global + globalObject: this._global, + options: this._options }); if (typeof val === "string") { const shorthandPriority = this._priorities.get(shorthand); diff --git a/lib/properties/backgroundImage.js b/lib/properties/backgroundImage.js index 07a4e9d9..2eb41b17 100644 --- a/lib/properties/backgroundImage.js +++ b/lib/properties/backgroundImage.js @@ -6,15 +6,16 @@ const property = "background-image"; const shorthand = "background"; module.exports.parse = function parse(v, opt = {}) { - const { globalObject } = opt; if (v === "") { return v; } + const { globalObject, options } = opt; const values = parsers.splitValue(v, { delimiter: "," }); const parsedValues = []; for (const val of values) { const value = parsers.parsePropertyValue(property, val, { globalObject, + options, inArray: true }); if (Array.isArray(value) && value.length === 1) { @@ -26,7 +27,7 @@ module.exports.parse = function parse(v, opt = {}) { break; } case "Url": { - const parsedValue = parsers.parseUrl(value); + const parsedValue = parsers.parseURL(value, options); if (!parsedValue) { return; } @@ -34,7 +35,7 @@ module.exports.parse = function parse(v, opt = {}) { break; } default: { - const parsedValue = parsers.parseGradient(value); + const parsedValue = parsers.parseGradient(value, options); if (!parsedValue) { return; } @@ -60,7 +61,8 @@ module.exports.definition = { this._setProperty(property, v); } else { const val = module.exports.parse(v, { - globalObject: this._global + globalObject: this._global, + options: this._options }); if (typeof val === "string") { const shorthandPriority = this._priorities.get(shorthand); diff --git a/lib/properties/backgroundOrigin.js b/lib/properties/backgroundOrigin.js index 6c3cd4bd..604b8d52 100644 --- a/lib/properties/backgroundOrigin.js +++ b/lib/properties/backgroundOrigin.js @@ -6,15 +6,16 @@ const property = "background-origin"; const shorthand = "background"; module.exports.parse = function parse(v, opt = {}) { - const { globalObject } = opt; if (v === "") { return v; } + const { globalObject, options } = opt; const values = parsers.splitValue(v, { delimiter: "," }); const parsedValues = []; for (const val of values) { const value = parsers.parsePropertyValue(property, val, { globalObject, + options, inArray: true }); if (Array.isArray(value) && value.length === 1) { @@ -46,7 +47,8 @@ module.exports.definition = { this._setProperty(property, v); } else { const val = module.exports.parse(v, { - globalObject: this._global + globalObject: this._global, + options: this._options }); if (typeof val === "string") { const shorthandPriority = this._priorities.get(shorthand); diff --git a/lib/properties/backgroundPosition.js b/lib/properties/backgroundPosition.js index f99b9bc2..96b24e2c 100644 --- a/lib/properties/backgroundPosition.js +++ b/lib/properties/backgroundPosition.js @@ -11,10 +11,10 @@ const keywordsY = ["center", ...keyY]; const keywords = ["center", ...keyX, ...keyY]; module.exports.parse = function parse(v, opt = {}) { - const { globalObject } = opt; if (v === "") { return v; } + const { globalObject, options } = opt; const values = parsers.splitValue(v, { delimiter: "," }); @@ -22,6 +22,7 @@ module.exports.parse = function parse(v, opt = {}) { for (const val of values) { const value = parsers.parsePropertyValue(property, val, { globalObject, + options, inArray: true }); if (Array.isArray(value) && value.length) { @@ -30,7 +31,9 @@ module.exports.parse = function parse(v, opt = {}) { case 1: { const [part1] = value; const val1 = - part1.type === "Identifier" ? part1.name : parsers.parseLengthPercentage([part1]); + part1.type === "Identifier" + ? part1.name + : parsers.parseLengthPercentage([part1], options); if (val1) { if (val1 === "center") { parsedValue = `${val1} ${val1}`; @@ -45,9 +48,13 @@ module.exports.parse = function parse(v, opt = {}) { case 2: { const [part1, part2] = value; const val1 = - part1.type === "Identifier" ? part1.name : parsers.parseLengthPercentage([part1]); + part1.type === "Identifier" + ? part1.name + : parsers.parseLengthPercentage([part1], options); const val2 = - part2.type === "Identifier" ? part2.name : parsers.parseLengthPercentage([part2]); + part2.type === "Identifier" + ? part2.name + : parsers.parseLengthPercentage([part2], options); if (val1 && val2) { if (keywordsX.includes(val1) && keywordsY.includes(val2)) { parsedValue = `${val1} ${val2}`; @@ -71,9 +78,13 @@ module.exports.parse = function parse(v, opt = {}) { const [part1, part2, part3] = value; const val1 = part1.type === "Identifier" && part1.name; const val2 = - part2.type === "Identifier" ? part2.name : parsers.parseLengthPercentage([part2]); + part2.type === "Identifier" + ? part2.name + : parsers.parseLengthPercentage([part2], options); const val3 = - part3.type === "Identifier" ? part3.name : parsers.parseLengthPercentage([part3]); + part3.type === "Identifier" + ? part3.name + : parsers.parseLengthPercentage([part3], options); if (val1 && val2 && val3) { let posX = ""; let offX = ""; @@ -121,9 +132,9 @@ module.exports.parse = function parse(v, opt = {}) { case 4: { const [part1, part2, part3, part4] = value; const val1 = part1.type === "Identifier" && part1.name; - const val2 = parsers.parseLengthPercentage([part2]); + const val2 = parsers.parseLengthPercentage([part2], options); const val3 = part3.type === "Identifier" && part3.name; - const val4 = parsers.parseLengthPercentage([part4]); + const val4 = parsers.parseLengthPercentage([part4], options); if (val1 && val2 && val3 && val4) { let posX = ""; let offX = ""; @@ -175,7 +186,8 @@ module.exports.definition = { this._setProperty(property, v); } else { const val = module.exports.parse(v, { - globalObject: this._global + globalObject: this._global, + options: this._options }); if (typeof val === "string") { const shorthandPriority = this._priorities.get(shorthand); diff --git a/lib/properties/backgroundRepeat.js b/lib/properties/backgroundRepeat.js index 30fca2a8..5440421f 100644 --- a/lib/properties/backgroundRepeat.js +++ b/lib/properties/backgroundRepeat.js @@ -6,10 +6,10 @@ const property = "background-repeat"; const shorthand = "background"; module.exports.parse = function parse(v, opt = {}) { - const { globalObject } = opt; if (v === "") { return v; } + const { globalObject, options } = opt; const values = parsers.splitValue(v, { delimiter: "," }); @@ -17,6 +17,7 @@ module.exports.parse = function parse(v, opt = {}) { for (const val of values) { const value = parsers.parsePropertyValue(property, val, { globalObject, + options, inArray: true }); if (Array.isArray(value) && value.length) { @@ -71,7 +72,8 @@ module.exports.definition = { this._setProperty(property, v); } else { const val = module.exports.parse(v, { - globalObject: this._global + globalObject: this._global, + options: this._options }); if (typeof val === "string") { const shorthandPriority = this._priorities.get(shorthand); diff --git a/lib/properties/backgroundSize.js b/lib/properties/backgroundSize.js index bd59a1b7..ffb252ce 100644 --- a/lib/properties/backgroundSize.js +++ b/lib/properties/backgroundSize.js @@ -6,10 +6,10 @@ const property = "background-size"; const shorthand = "background"; module.exports.parse = function parse(v, opt = {}) { - const { globalObject } = opt; if (v === "") { return v; } + const { globalObject, options } = opt; const values = parsers.splitValue(v, { delimiter: "," }); @@ -17,6 +17,7 @@ module.exports.parse = function parse(v, opt = {}) { for (const val of values) { const value = parsers.parsePropertyValue(property, val, { globalObject, + options, inArray: true }); if (Array.isArray(value) && value.length) { @@ -36,7 +37,7 @@ module.exports.parse = function parse(v, opt = {}) { break; } default: { - const parsedValue = parsers.parseLengthPercentage(value); + const parsedValue = parsers.parseLengthPercentage(value, options); if (!parsedValue) { return; } @@ -102,7 +103,8 @@ module.exports.definition = { this._setProperty(property, v); } else { const val = module.exports.parse(v, { - globalObject: this._global + globalObject: this._global, + options: this._options }); if (typeof val === "string") { const shorthandPriority = this._priorities.get(shorthand); diff --git a/lib/properties/border.js b/lib/properties/border.js index c39f28c3..c3544b81 100644 --- a/lib/properties/border.js +++ b/lib/properties/border.js @@ -31,15 +31,16 @@ module.exports.positionShorthandFor = new Map([ ]); module.exports.parse = function parse(v, opt = {}) { - const { globalObject } = opt; if (v === "" || parsers.hasVarFunc(v)) { return v; } + const { globalObject, options } = opt; const values = parsers.splitValue(v); const parsedValues = new Map(); for (const val of values) { const value = parsers.parsePropertyValue(property, val, { globalObject, + options, inArray: true }); if (Array.isArray(value) && value.length === 1) { @@ -57,9 +58,13 @@ module.exports.parse = function parse(v, opt = {}) { if (parsedValues.has("border-width")) { return; } - const parsedValue = parsers.parseLength(value, { + const parseOpt = { min: 0 - }); + }; + for (const [key, optVal] of Object.entries(options)) { + parseOpt[key] = optVal; + } + const parsedValue = parsers.parseLength(value, parseOpt); if (!parsedValue) { return; } @@ -70,7 +75,7 @@ module.exports.parse = function parse(v, opt = {}) { if (parsedValues.has("border-color")) { return; } - const parsedValue = parsers.parseColor(value); + const parsedValue = parsers.parseColor(value, options); if (!parsedValue) { return; } @@ -84,7 +89,7 @@ module.exports.parse = function parse(v, opt = {}) { if (parsedValues.has("border-color")) { return; } - const parsedValue = parsers.parseColor(value); + const parsedValue = parsers.parseColor(value, options); if (!parsedValue) { return; } @@ -92,19 +97,19 @@ module.exports.parse = function parse(v, opt = {}) { break; } case "Identifier": { - if (parsers.isValidPropertyValue("border-width", name)) { + if (parsers.isValidPropertyValue("border-width", name, globalObject)) { if (parsedValues.has("border-width")) { return; } parsedValues.set("border-width", name); break; - } else if (parsers.isValidPropertyValue("border-style", name)) { + } else if (parsers.isValidPropertyValue("border-style", name, globalObject)) { if (parsedValues.has("border-style")) { return; } parsedValues.set("border-style", name); break; - } else if (parsers.isValidPropertyValue("border-color", name)) { + } else if (parsers.isValidPropertyValue("border-color", name, globalObject)) { if (parsedValues.has("border-color")) { return; } @@ -148,7 +153,8 @@ module.exports.definition = { this._borderSetter(property, v, ""); } else { const val = module.exports.parse(v, { - globalObject: this._global + globalObject: this._global, + options: this._options }); if (val || typeof val === "string") { const priority = this._priorities.get(property) ?? ""; diff --git a/lib/properties/borderBottom.js b/lib/properties/borderBottom.js index d624988b..381d85a7 100644 --- a/lib/properties/borderBottom.js +++ b/lib/properties/borderBottom.js @@ -21,15 +21,16 @@ module.exports.shorthandFor = new Map([ ]); module.exports.parse = function parse(v, opt = {}) { - const { globalObject } = opt; if (v === "") { return v; } + const { globalObject, options } = opt; const values = parsers.splitValue(v); const parsedValues = new Map(); for (const val of values) { const value = parsers.parsePropertyValue(property, val, { globalObject, + options, inArray: true }); if (Array.isArray(value) && value.length === 1) { @@ -47,9 +48,13 @@ module.exports.parse = function parse(v, opt = {}) { if (parsedValues.has("border-bottom-width")) { return; } - const parsedValue = parsers.parseLength(value, { + const parseOpt = { min: 0 - }); + }; + for (const [key, optVal] of Object.entries(options)) { + parseOpt[key] = optVal; + } + const parsedValue = parsers.parseLength(value, parseOpt); if (!parsedValue) { return; } @@ -60,7 +65,7 @@ module.exports.parse = function parse(v, opt = {}) { if (parsedValues.has("border-bottom-color")) { return; } - const parsedValue = parsers.parseColor(value); + const parsedValue = parsers.parseColor(value, options); if (!parsedValue) { return; } @@ -74,7 +79,7 @@ module.exports.parse = function parse(v, opt = {}) { if (parsedValues.has("border-bottom-color")) { return; } - const parsedValue = parsers.parseColor(value); + const parsedValue = parsers.parseColor(value, options); if (!parsedValue) { return; } @@ -82,19 +87,19 @@ module.exports.parse = function parse(v, opt = {}) { break; } case "Identifier": { - if (parsers.isValidPropertyValue("border-bottom-width", name)) { + if (parsers.isValidPropertyValue("border-bottom-width", name, globalObject)) { if (parsedValues.has("border-bottom-width")) { return; } parsedValues.set("border-bottom-width", name); break; - } else if (parsers.isValidPropertyValue("border-bottom-style", name)) { + } else if (parsers.isValidPropertyValue("border-bottom-style", name, globalObject)) { if (parsedValues.has("border-bottom-style")) { return; } parsedValues.set("border-bottom-style", name); break; - } else if (parsers.isValidPropertyValue("border-bottom-color", name)) { + } else if (parsers.isValidPropertyValue("border-bottom-color", name, globalObject)) { if (parsedValues.has("border-bottom-color")) { return; } @@ -138,7 +143,8 @@ module.exports.definition = { this._borderSetter(property, v, ""); } else { const val = module.exports.parse(v, { - globalObject: this._global + globalObject: this._global, + options: this._options }); if (val || typeof val === "string") { const shorthandPriority = this._priorities.get(shorthand); diff --git a/lib/properties/borderBottomColor.js b/lib/properties/borderBottomColor.js index 015a60fd..fc54da4c 100644 --- a/lib/properties/borderBottomColor.js +++ b/lib/properties/borderBottomColor.js @@ -8,12 +8,13 @@ const positionShorthand = "border-bottom"; const shorthand = "border"; module.exports.parse = function parse(v, opt = {}) { - const { globalObject } = opt; if (v === "") { return v; } + const { globalObject, options } = opt; const value = parsers.parsePropertyValue(property, v, { globalObject, + options, inArray: true }); if (Array.isArray(value) && value.length === 1) { @@ -23,7 +24,7 @@ module.exports.parse = function parse(v, opt = {}) { return name; } default: { - return parsers.parseColor(value); + return parsers.parseColor(value, options); } } } else if (typeof value === "string") { @@ -38,7 +39,8 @@ module.exports.definition = { this._borderSetter(property, v, ""); } else { const val = module.exports.parse(v, { - globalObject: this._global + globalObject: this._global, + options: this._options }); if (typeof val === "string") { const shorthandPriority = this._priorities.get(shorthand); diff --git a/lib/properties/borderBottomStyle.js b/lib/properties/borderBottomStyle.js index fc865b66..ad596756 100644 --- a/lib/properties/borderBottomStyle.js +++ b/lib/properties/borderBottomStyle.js @@ -8,12 +8,13 @@ const positionShorthand = "border-bottom"; const shorthand = "border"; module.exports.parse = function parse(v, opt = {}) { - const { globalObject } = opt; if (v === "") { return v; } + const { globalObject, options } = opt; const value = parsers.parsePropertyValue(property, v, { globalObject, + options, inArray: true }); if (Array.isArray(value) && value.length === 1) { @@ -37,7 +38,8 @@ module.exports.definition = { this._borderSetter(property, v, ""); } else { const val = module.exports.parse(v, { - globalObject: this._global + globalObject: this._global, + options: this._options }); if (typeof val === "string") { const shorthandPriority = this._priorities.get(shorthand); diff --git a/lib/properties/borderBottomWidth.js b/lib/properties/borderBottomWidth.js index 5e6b682a..4305290f 100644 --- a/lib/properties/borderBottomWidth.js +++ b/lib/properties/borderBottomWidth.js @@ -8,12 +8,13 @@ const positionShorthand = "border-bottom"; const shorthand = "border"; module.exports.parse = function parse(v, opt = {}) { - const { globalObject } = opt; if (v === "") { return v; } + const { globalObject, options } = opt; const value = parsers.parsePropertyValue(property, v, { globalObject, + options, inArray: true }); if (Array.isArray(value) && value.length === 1) { @@ -30,9 +31,13 @@ module.exports.parse = function parse(v, opt = {}) { return name; } default: { - return parsers.parseLength(value, { + const parseOpt = { min: 0 - }); + }; + for (const [key, val] of Object.entries(options)) { + parseOpt[key] = val; + } + return parsers.parseLength(value, parseOpt); } } } else if (typeof value === "string") { @@ -47,7 +52,8 @@ module.exports.definition = { this._borderSetter(property, v, ""); } else { const val = module.exports.parse(v, { - globalObject: this._global + globalObject: this._global, + options: this._options }); if (typeof val === "string") { const shorthandPriority = this._priorities.get(shorthand); diff --git a/lib/properties/borderCollapse.js b/lib/properties/borderCollapse.js index 55e56866..c8f49856 100644 --- a/lib/properties/borderCollapse.js +++ b/lib/properties/borderCollapse.js @@ -5,12 +5,13 @@ const parsers = require("../parsers"); const property = "border-collapse"; module.exports.parse = function parse(v, opt = {}) { - const { globalObject } = opt; if (v === "") { return v; } + const { globalObject, options } = opt; const value = parsers.parsePropertyValue(property, v, { globalObject, + options, inArray: true }); if (Array.isArray(value) && value.length === 1) { @@ -34,7 +35,8 @@ module.exports.definition = { this._setProperty(property, v); } else { const val = module.exports.parse(v, { - globalObject: this._global + globalObject: this._global, + options: this._options }); if (typeof val === "string") { const priority = this._priorities.get(property) ?? ""; diff --git a/lib/properties/borderColor.js b/lib/properties/borderColor.js index 156bdd9e..6cb17df4 100644 --- a/lib/properties/borderColor.js +++ b/lib/properties/borderColor.js @@ -17,12 +17,13 @@ module.exports.shorthandFor = new Map([ ]); module.exports.parse = function parse(v, opt = {}) { - const { globalObject } = opt; if (v === "") { return v; } + const { globalObject, options } = opt; const values = parsers.parsePropertyValue(property, v, { globalObject, + options, inArray: true }); const parsedValues = []; @@ -40,7 +41,7 @@ module.exports.parse = function parse(v, opt = {}) { return name; } default: { - const parsedValue = parsers.parseColor([value]); + const parsedValue = parsers.parseColor([value], options); if (!parsedValue) { return; } @@ -98,7 +99,8 @@ module.exports.definition = { this._borderSetter(property, v, ""); } else { const val = module.exports.parse(v, { - globalObject: this._global + globalObject: this._global, + options: this._options }); if (Array.isArray(val) || typeof val === "string") { const shorthandPriority = this._priorities.get(shorthand); diff --git a/lib/properties/borderLeft.js b/lib/properties/borderLeft.js index aaf0e28e..ec0a8084 100644 --- a/lib/properties/borderLeft.js +++ b/lib/properties/borderLeft.js @@ -21,15 +21,16 @@ module.exports.shorthandFor = new Map([ ]); module.exports.parse = function parse(v, opt = {}) { - const { globalObject } = opt; if (v === "") { return v; } + const { globalObject, options } = opt; const values = parsers.splitValue(v); const parsedValues = new Map(); for (const val of values) { const value = parsers.parsePropertyValue(property, val, { globalObject, + options, inArray: true }); if (Array.isArray(value) && value.length === 1) { @@ -47,9 +48,13 @@ module.exports.parse = function parse(v, opt = {}) { if (parsedValues.has("border-left-width")) { return; } - const parsedValue = parsers.parseLength(value, { + const parseOpt = { min: 0 - }); + }; + for (const [key, optVal] of Object.entries(options)) { + parseOpt[key] = optVal; + } + const parsedValue = parsers.parseLength(value, parseOpt); if (!parsedValue) { return; } @@ -60,7 +65,7 @@ module.exports.parse = function parse(v, opt = {}) { if (parsedValues.has("border-left-color")) { return; } - const parsedValue = parsers.parseColor(value); + const parsedValue = parsers.parseColor(value, options); if (!parsedValue) { return; } @@ -74,7 +79,7 @@ module.exports.parse = function parse(v, opt = {}) { if (parsedValues.has("border-left-color")) { return; } - const parsedValue = parsers.parseColor(value); + const parsedValue = parsers.parseColor(value, options); if (!parsedValue) { return; } @@ -82,19 +87,19 @@ module.exports.parse = function parse(v, opt = {}) { break; } case "Identifier": { - if (parsers.isValidPropertyValue("border-left-width", name)) { + if (parsers.isValidPropertyValue("border-left-width", name, globalObject)) { if (parsedValues.has("border-left-width")) { return; } parsedValues.set("border-left-width", name); break; - } else if (parsers.isValidPropertyValue("border-left-style", name)) { + } else if (parsers.isValidPropertyValue("border-left-style", name, globalObject)) { if (parsedValues.has("border-left-style")) { return; } parsedValues.set("border-left-style", name); break; - } else if (parsers.isValidPropertyValue("border-left-color", name)) { + } else if (parsers.isValidPropertyValue("border-left-color", name, globalObject)) { if (parsedValues.has("border-left-color")) { return; } @@ -138,7 +143,8 @@ module.exports.definition = { this._borderSetter(property, v, ""); } else { const val = module.exports.parse(v, { - globalObject: this._global + globalObject: this._global, + options: this._options }); if (val || typeof val === "string") { const shorthandPriority = this._priorities.get(shorthand); diff --git a/lib/properties/borderLeftColor.js b/lib/properties/borderLeftColor.js index d9c6b498..1f179628 100644 --- a/lib/properties/borderLeftColor.js +++ b/lib/properties/borderLeftColor.js @@ -8,12 +8,13 @@ const positionShorthand = "border-left"; const shorthand = "border"; module.exports.parse = function parse(v, opt = {}) { - const { globalObject } = opt; if (v === "") { return v; } + const { globalObject, options } = opt; const value = parsers.parsePropertyValue(property, v, { globalObject, + options, inArray: true }); if (Array.isArray(value) && value.length === 1) { @@ -23,7 +24,7 @@ module.exports.parse = function parse(v, opt = {}) { return name; } default: { - return parsers.parseColor(value); + return parsers.parseColor(value, options); } } } else if (typeof value === "string") { @@ -38,7 +39,8 @@ module.exports.definition = { this._borderSetter(property, v, ""); } else { const val = module.exports.parse(v, { - globalObject: this._global + globalObject: this._global, + options: this._options }); if (typeof val === "string") { const shorthandPriority = this._priorities.get(shorthand); diff --git a/lib/properties/borderLeftStyle.js b/lib/properties/borderLeftStyle.js index 115106a1..d54928a9 100644 --- a/lib/properties/borderLeftStyle.js +++ b/lib/properties/borderLeftStyle.js @@ -8,12 +8,13 @@ const positionShorthand = "border-left"; const shorthand = "border"; module.exports.parse = function parse(v, opt = {}) { - const { globalObject } = opt; if (v === "") { return v; } + const { globalObject, options } = opt; const value = parsers.parsePropertyValue(property, v, { globalObject, + options, inArray: true }); if (Array.isArray(value) && value.length === 1) { @@ -37,7 +38,8 @@ module.exports.definition = { this._borderSetter(property, v, ""); } else { const val = module.exports.parse(v, { - globalObject: this._global + globalObject: this._global, + options: this._options }); if (typeof val === "string") { const shorthandPriority = this._priorities.get(shorthand); diff --git a/lib/properties/borderLeftWidth.js b/lib/properties/borderLeftWidth.js index 51e20652..72e3bb83 100644 --- a/lib/properties/borderLeftWidth.js +++ b/lib/properties/borderLeftWidth.js @@ -8,12 +8,13 @@ const positionShorthand = "border-left"; const shorthand = "border"; module.exports.parse = function parse(v, opt = {}) { - const { globalObject } = opt; if (v === "") { return v; } + const { globalObject, options } = opt; const value = parsers.parsePropertyValue(property, v, { globalObject, + options, inArray: true }); if (Array.isArray(value) && value.length === 1) { @@ -30,9 +31,13 @@ module.exports.parse = function parse(v, opt = {}) { return name; } default: { - return parsers.parseLength(value, { + const parseOpt = { min: 0 - }); + }; + for (const [key, val] of Object.entries(options)) { + parseOpt[key] = val; + } + return parsers.parseLength(value, parseOpt); } } } else if (typeof value === "string") { @@ -47,7 +52,8 @@ module.exports.definition = { this._borderSetter(property, v, ""); } else { const val = module.exports.parse(v, { - globalObject: this._global + globalObject: this._global, + options: this._options }); if (typeof val === "string") { const shorthandPriority = this._priorities.get(shorthand); diff --git a/lib/properties/borderRight.js b/lib/properties/borderRight.js index cf1507e9..5a00f45f 100644 --- a/lib/properties/borderRight.js +++ b/lib/properties/borderRight.js @@ -21,15 +21,16 @@ module.exports.shorthandFor = new Map([ ]); module.exports.parse = function parse(v, opt = {}) { - const { globalObject } = opt; if (v === "") { return v; } + const { globalObject, options } = opt; const values = parsers.splitValue(v); const parsedValues = new Map(); for (const val of values) { const value = parsers.parsePropertyValue(property, val, { globalObject, + options, inArray: true }); if (Array.isArray(value) && value.length === 1) { @@ -47,9 +48,13 @@ module.exports.parse = function parse(v, opt = {}) { if (parsedValues.has("border-right-width")) { return; } - const parsedValue = parsers.parseLength(value, { + const parseOpt = { min: 0 - }); + }; + for (const [key, optVal] of Object.entries(options)) { + parseOpt[key] = optVal; + } + const parsedValue = parsers.parseLength(value, parseOpt); if (!parsedValue) { return; } @@ -60,7 +65,7 @@ module.exports.parse = function parse(v, opt = {}) { if (parsedValues.has("border-right-color")) { return; } - const parsedValue = parsers.parseColor(value); + const parsedValue = parsers.parseColor(value, options); if (!parsedValue) { return; } @@ -74,7 +79,7 @@ module.exports.parse = function parse(v, opt = {}) { if (parsedValues.has("border-right-color")) { return; } - const parsedValue = parsers.parseColor(value); + const parsedValue = parsers.parseColor(value, options); if (!parsedValue) { return; } @@ -82,19 +87,19 @@ module.exports.parse = function parse(v, opt = {}) { break; } case "Identifier": { - if (parsers.isValidPropertyValue("border-right-width", name)) { + if (parsers.isValidPropertyValue("border-right-width", name, globalObject)) { if (parsedValues.has("border-right-width")) { return; } parsedValues.set("border-right-width", name); break; - } else if (parsers.isValidPropertyValue("border-right-style", name)) { + } else if (parsers.isValidPropertyValue("border-right-style", name, globalObject)) { if (parsedValues.has("border-right-style")) { return; } parsedValues.set("border-right-style", name); break; - } else if (parsers.isValidPropertyValue("border-right-color", name)) { + } else if (parsers.isValidPropertyValue("border-right-color", name, globalObject)) { if (parsedValues.has("border-right-color")) { return; } @@ -138,7 +143,8 @@ module.exports.definition = { this._borderSetter(property, v, ""); } else { const val = module.exports.parse(v, { - globalObject: this._global + globalObject: this._global, + options: this._options }); if (val || typeof val === "string") { const shorthandPriority = this._priorities.get(shorthand); diff --git a/lib/properties/borderRightColor.js b/lib/properties/borderRightColor.js index 807b6df4..857ac14c 100644 --- a/lib/properties/borderRightColor.js +++ b/lib/properties/borderRightColor.js @@ -8,12 +8,13 @@ const positionShorthand = "border-right"; const shorthand = "border"; module.exports.parse = function parse(v, opt = {}) { - const { globalObject } = opt; if (v === "") { return v; } + const { globalObject, options } = opt; const value = parsers.parsePropertyValue(property, v, { globalObject, + options, inArray: true }); if (Array.isArray(value) && value.length === 1) { @@ -23,7 +24,7 @@ module.exports.parse = function parse(v, opt = {}) { return name; } default: { - return parsers.parseColor(value); + return parsers.parseColor(value, options); } } } else if (typeof value === "string") { @@ -38,7 +39,8 @@ module.exports.definition = { this._borderSetter(property, v, ""); } else { const val = module.exports.parse(v, { - globalObject: this._global + globalObject: this._global, + options: this._options }); if (typeof val === "string") { const shorthandPriority = this._priorities.get(shorthand); diff --git a/lib/properties/borderRightStyle.js b/lib/properties/borderRightStyle.js index 0d343c3b..ea43a6e3 100644 --- a/lib/properties/borderRightStyle.js +++ b/lib/properties/borderRightStyle.js @@ -8,12 +8,13 @@ const positionShorthand = "border-right"; const shorthand = "border"; module.exports.parse = function parse(v, opt = {}) { - const { globalObject } = opt; if (v === "") { return v; } + const { globalObject, options } = opt; const value = parsers.parsePropertyValue(property, v, { globalObject, + options, inArray: true }); if (Array.isArray(value) && value.length === 1) { @@ -37,7 +38,8 @@ module.exports.definition = { this._borderSetter(property, v, ""); } else { const val = module.exports.parse(v, { - globalObject: this._global + globalObject: this._global, + options: this._options }); if (typeof val === "string") { const shorthandPriority = this._priorities.get(shorthand); diff --git a/lib/properties/borderRightWidth.js b/lib/properties/borderRightWidth.js index f4c5147d..beb95674 100644 --- a/lib/properties/borderRightWidth.js +++ b/lib/properties/borderRightWidth.js @@ -8,12 +8,13 @@ const positionShorthand = "border-right"; const shorthand = "border"; module.exports.parse = function parse(v, opt = {}) { - const { globalObject } = opt; if (v === "") { return v; } + const { globalObject, options } = opt; const value = parsers.parsePropertyValue(property, v, { globalObject, + options, inArray: true }); if (Array.isArray(value) && value.length === 1) { @@ -30,9 +31,13 @@ module.exports.parse = function parse(v, opt = {}) { return name; } default: { - return parsers.parseLength(value, { + const parseOpt = { min: 0 - }); + }; + for (const [key, val] of Object.entries(options)) { + parseOpt[key] = val; + } + return parsers.parseLength(value, parseOpt); } } } else if (typeof value === "string") { @@ -47,7 +52,8 @@ module.exports.definition = { this._borderSetter(property, v, ""); } else { const val = module.exports.parse(v, { - globalObject: this._global + globalObject: this._global, + options: this._options }); if (typeof val === "string") { const shorthandPriority = this._priorities.get(shorthand); diff --git a/lib/properties/borderSpacing.js b/lib/properties/borderSpacing.js index d33df5a3..fee04259 100644 --- a/lib/properties/borderSpacing.js +++ b/lib/properties/borderSpacing.js @@ -5,19 +5,20 @@ const parsers = require("../parsers"); const property = "border-spacing"; module.exports.parse = function parse(v, opt = {}) { - const { globalObject } = opt; if (v === "") { return v; } + const { globalObject, options } = opt; const value = parsers.parsePropertyValue(property, v, { globalObject, + options, inArray: true }); if (Array.isArray(value) && value.length) { switch (value.length) { case 1: { const [part1] = value; - const val1 = parsers.parseLength([part1]); + const val1 = parsers.parseLength([part1], options); if (val1) { return val1; } @@ -25,8 +26,8 @@ module.exports.parse = function parse(v, opt = {}) { } case 2: { const [part1, part2] = value; - const val1 = parsers.parseLength([part1]); - const val2 = parsers.parseLength([part2]); + const val1 = parsers.parseLength([part1], options); + const val2 = parsers.parseLength([part2], options); if (val1 && val2) { return `${val1} ${val2}`; } @@ -46,7 +47,8 @@ module.exports.definition = { this._setProperty(property, v); } else { const val = module.exports.parse(v, { - globalObject: this._global + globalObject: this._global, + options: this._options }); if (typeof val === "string") { const priority = this._priorities.get(property) ?? ""; diff --git a/lib/properties/borderStyle.js b/lib/properties/borderStyle.js index ebeddbeb..c9c9f032 100644 --- a/lib/properties/borderStyle.js +++ b/lib/properties/borderStyle.js @@ -17,12 +17,13 @@ module.exports.shorthandFor = new Map([ ]); module.exports.parse = function parse(v, opt = {}) { - const { globalObject } = opt; if (v === "") { return v; } + const { globalObject, options } = opt; const values = parsers.parsePropertyValue(property, v, { globalObject, + options, inArray: true }); const parsedValues = []; @@ -98,7 +99,8 @@ module.exports.definition = { this._borderSetter(property, v, ""); } else { const val = module.exports.parse(v, { - globalObject: this._global + globalObject: this._global, + options: this._options }); if (Array.isArray(val) || typeof val === "string") { const shorthandPriority = this._priorities.get(shorthand); diff --git a/lib/properties/borderTop.js b/lib/properties/borderTop.js index 80dec4f0..f07d19bd 100644 --- a/lib/properties/borderTop.js +++ b/lib/properties/borderTop.js @@ -21,15 +21,16 @@ module.exports.shorthandFor = new Map([ ]); module.exports.parse = function parse(v, opt = {}) { - const { globalObject } = opt; if (v === "") { return v; } + const { globalObject, options } = opt; const values = parsers.splitValue(v); const parsedValues = new Map(); for (const val of values) { const value = parsers.parsePropertyValue(property, val, { globalObject, + options, inArray: true }); if (Array.isArray(value) && value.length === 1) { @@ -47,9 +48,13 @@ module.exports.parse = function parse(v, opt = {}) { if (parsedValues.has("border-top-width")) { return; } - const parsedValue = parsers.parseLength(value, { + const parseOpt = { min: 0 - }); + }; + for (const [key, optVal] of Object.entries(options)) { + parseOpt[key] = optVal; + } + const parsedValue = parsers.parseLength(value, parseOpt); if (!parsedValue) { return; } @@ -60,7 +65,7 @@ module.exports.parse = function parse(v, opt = {}) { if (parsedValues.has("border-top-color")) { return; } - const parsedValue = parsers.parseColor(value); + const parsedValue = parsers.parseColor(value, options); if (!parsedValue) { return; } @@ -74,7 +79,7 @@ module.exports.parse = function parse(v, opt = {}) { if (parsedValues.has("border-top-color")) { return; } - const parsedValue = parsers.parseColor(value); + const parsedValue = parsers.parseColor(value, options); if (!parsedValue) { return; } @@ -82,19 +87,19 @@ module.exports.parse = function parse(v, opt = {}) { break; } case "Identifier": { - if (parsers.isValidPropertyValue("border-top-width", name)) { + if (parsers.isValidPropertyValue("border-top-width", name, globalObject)) { if (parsedValues.has("border-top-width")) { return; } parsedValues.set("border-top-width", name); break; - } else if (parsers.isValidPropertyValue("border-top-style", name)) { + } else if (parsers.isValidPropertyValue("border-top-style", name, globalObject)) { if (parsedValues.has("border-top-style")) { return; } parsedValues.set("border-top-style", name); break; - } else if (parsers.isValidPropertyValue("border-top-color", name)) { + } else if (parsers.isValidPropertyValue("border-top-color", name, globalObject)) { if (parsedValues.has("border-top-color")) { return; } @@ -138,7 +143,8 @@ module.exports.definition = { this._borderSetter(property, v, ""); } else { const val = module.exports.parse(v, { - globalObject: this._global + globalObject: this._global, + options: this._options }); if (val || typeof val === "string") { const shorthandPriority = this._priorities.get(shorthand); diff --git a/lib/properties/borderTopColor.js b/lib/properties/borderTopColor.js index 8acfa672..be76ca59 100644 --- a/lib/properties/borderTopColor.js +++ b/lib/properties/borderTopColor.js @@ -8,12 +8,13 @@ const positionShorthand = "border-top"; const shorthand = "border"; module.exports.parse = function parse(v, opt = {}) { - const { globalObject } = opt; if (v === "") { return v; } + const { globalObject, options } = opt; const value = parsers.parsePropertyValue(property, v, { globalObject, + options, inArray: true }); if (Array.isArray(value) && value.length === 1) { @@ -23,7 +24,7 @@ module.exports.parse = function parse(v, opt = {}) { return name; } default: { - return parsers.parseColor(value); + return parsers.parseColor(value, options); } } } else if (typeof value === "string") { @@ -38,7 +39,8 @@ module.exports.definition = { this._borderSetter(property, v, ""); } else { const val = module.exports.parse(v, { - globalObject: this._global + globalObject: this._global, + options: this._options }); if (typeof val === "string") { const shorthandPriority = this._priorities.get(shorthand); diff --git a/lib/properties/borderTopStyle.js b/lib/properties/borderTopStyle.js index a90c2f68..0134de2c 100644 --- a/lib/properties/borderTopStyle.js +++ b/lib/properties/borderTopStyle.js @@ -8,12 +8,13 @@ const positionShorthand = "border-top"; const shorthand = "border"; module.exports.parse = function parse(v, opt = {}) { - const { globalObject } = opt; if (v === "") { return v; } + const { globalObject, options } = opt; const value = parsers.parsePropertyValue(property, v, { globalObject, + options, inArray: true }); if (Array.isArray(value) && value.length === 1) { @@ -37,7 +38,8 @@ module.exports.definition = { this._borderSetter(property, v, ""); } else { const val = module.exports.parse(v, { - globalObject: this._global + globalObject: this._global, + options: this._options }); if (typeof val === "string") { const shorthandPriority = this._priorities.get(shorthand); diff --git a/lib/properties/borderTopWidth.js b/lib/properties/borderTopWidth.js index f97d124c..74eeaf5d 100644 --- a/lib/properties/borderTopWidth.js +++ b/lib/properties/borderTopWidth.js @@ -8,12 +8,13 @@ const positionShorthand = "border-top"; const shorthand = "border"; module.exports.parse = function parse(v, opt = {}) { - const { globalObject } = opt; if (v === "") { return v; } + const { globalObject, options } = opt; const value = parsers.parsePropertyValue(property, v, { globalObject, + options, inArray: true }); if (Array.isArray(value) && value.length === 1) { @@ -30,9 +31,13 @@ module.exports.parse = function parse(v, opt = {}) { return name; } default: { - return parsers.parseLength(value, { + const parseOpt = { min: 0 - }); + }; + for (const [key, val] of Object.entries(options)) { + parseOpt[key] = val; + } + return parsers.parseLength(value, parseOpt); } } } else if (typeof value === "string") { @@ -47,7 +52,8 @@ module.exports.definition = { this._borderSetter(property, v, ""); } else { const val = module.exports.parse(v, { - globalObject: this._global + globalObject: this._global, + options: this._options }); if (typeof val === "string") { const shorthandPriority = this._priorities.get(shorthand); diff --git a/lib/properties/borderWidth.js b/lib/properties/borderWidth.js index b34496fa..92f27dd4 100644 --- a/lib/properties/borderWidth.js +++ b/lib/properties/borderWidth.js @@ -17,12 +17,13 @@ module.exports.shorthandFor = new Map([ ]); module.exports.parse = function parse(v, opt = {}) { - const { globalObject } = opt; if (v === "") { return v; } + const { globalObject, options } = opt; const values = parsers.parsePropertyValue(property, v, { globalObject, + options, inArray: true }); const parsedValues = []; @@ -51,9 +52,13 @@ module.exports.parse = function parse(v, opt = {}) { break; } default: { - const parsedValue = parsers.parseLength([value], { + const parseOpt = { min: 0 - }); + }; + for (const [key, val] of Object.entries(options)) { + parseOpt[key] = val; + } + const parsedValue = parsers.parseLength([value], parseOpt); if (!parsedValue) { return; } @@ -111,7 +116,8 @@ module.exports.definition = { this._borderSetter(property, v, ""); } else { const val = module.exports.parse(v, { - globalObject: this._global + globalObject: this._global, + options: this._options }); if (Array.isArray(val) || typeof val === "string") { const shorthandPriority = this._priorities.get(shorthand); diff --git a/lib/properties/bottom.js b/lib/properties/bottom.js index 0e1902d1..dc1fd22d 100644 --- a/lib/properties/bottom.js +++ b/lib/properties/bottom.js @@ -5,12 +5,13 @@ const parsers = require("../parsers"); const property = "bottom"; module.exports.parse = function parse(v, opt = {}) { - const { globalObject } = opt; if (v === "") { return v; } + const { globalObject, options } = opt; const value = parsers.parsePropertyValue(property, v, { globalObject, + options, inArray: true }); if (Array.isArray(value) && value.length === 1) { @@ -27,7 +28,7 @@ module.exports.parse = function parse(v, opt = {}) { return name; } default: { - return parsers.parseLengthPercentage(value); + return parsers.parseLengthPercentage(value, options); } } } else if (typeof value === "string") { @@ -42,7 +43,8 @@ module.exports.definition = { this._setProperty(property, v); } else { const val = module.exports.parse(v, { - globalObject: this._global + globalObject: this._global, + options: this._options }); if (typeof val === "string") { const priority = this._priorities.get(property) ?? ""; diff --git a/lib/properties/clear.js b/lib/properties/clear.js index cfd39c36..aa7eb085 100644 --- a/lib/properties/clear.js +++ b/lib/properties/clear.js @@ -5,12 +5,13 @@ const parsers = require("../parsers"); const property = "clear"; module.exports.parse = function parse(v, opt = {}) { - const { globalObject } = opt; if (v === "") { return v; } + const { globalObject, options } = opt; const value = parsers.parsePropertyValue(property, v, { globalObject, + options, inArray: true }); if (Array.isArray(value) && value.length === 1) { @@ -34,7 +35,8 @@ module.exports.definition = { this._setProperty(property, v); } else { const val = module.exports.parse(v, { - globalObject: this._global + globalObject: this._global, + options: this._options }); if (typeof val === "string") { const priority = this._priorities.get(property) ?? ""; diff --git a/lib/properties/clip.js b/lib/properties/clip.js index 09908c0a..afcb59f2 100644 --- a/lib/properties/clip.js +++ b/lib/properties/clip.js @@ -7,12 +7,13 @@ const parsers = require("../parsers"); const property = "clip"; module.exports.parse = function parse(v, opt = {}) { - const { globalObject } = opt; if (v === "") { return v; } + const { globalObject, options } = opt; const value = parsers.parsePropertyValue(property, v, { globalObject, + options, inArray: true }); if (Array.isArray(value) && value.length === 1) { @@ -24,8 +25,15 @@ module.exports.parse = function parse(v, opt = {}) { }); const parsedValues = []; for (const item of values) { - const parsedValue = parsers.parseCSS(item, { context: "value" }, true); - const val = parsers.parseLengthPercentage(parsedValue.children); + const parsedValue = parsers.parseCSS( + item, + { + globalObject, + options: { context: "value" } + }, + true + ); + const val = parsers.parseLengthPercentage(parsedValue.children, options); if (val) { parsedValues.push(val); } else { @@ -52,7 +60,8 @@ module.exports.definition = { this._setProperty(property, v); } else { const val = module.exports.parse(v, { - globalObject: this._global + globalObject: this._global, + options: this._options }); if (typeof val === "string") { const priority = this._priorities.get(property) ?? ""; diff --git a/lib/properties/color.js b/lib/properties/color.js index 74e398d0..9b48b9f9 100644 --- a/lib/properties/color.js +++ b/lib/properties/color.js @@ -5,12 +5,13 @@ const parsers = require("../parsers"); const property = "color"; module.exports.parse = function parse(v, opt = {}) { - const { globalObject } = opt; if (v === "") { return v; } + const { globalObject, options } = opt; const value = parsers.parsePropertyValue(property, v, { globalObject, + options, inArray: true }); if (Array.isArray(value) && value.length === 1) { @@ -20,7 +21,7 @@ module.exports.parse = function parse(v, opt = {}) { return name; } default: { - return parsers.parseColor(value); + return parsers.parseColor(value, options); } } } else if (typeof value === "string") { @@ -35,7 +36,8 @@ module.exports.definition = { this._setProperty(property, v); } else { const val = module.exports.parse(v, { - globalObject: this._global + globalObject: this._global, + options: this._options }); if (typeof val === "string") { const priority = this._priorities.get(property) ?? ""; diff --git a/lib/properties/display.js b/lib/properties/display.js index fb45c479..de06987f 100644 --- a/lib/properties/display.js +++ b/lib/properties/display.js @@ -9,12 +9,13 @@ const displayOutside = ["block", "inline", "run-in"]; const displayFlow = ["flow", "flow-root"]; module.exports.parse = function parse(v, opt = {}) { - const { globalObject } = opt; if (v === "") { return v; } + const { globalObject, options } = opt; const value = parsers.parsePropertyValue(property, v, { globalObject, + options, inArray: true }); if (Array.isArray(value) && value.length) { @@ -191,7 +192,8 @@ module.exports.definition = { this._setProperty(property, v); } else { const val = module.exports.parse(v, { - globalObject: this._global + globalObject: this._global, + options: this._options }); if (typeof val === "string") { const priority = this._priorities.get(property) ?? ""; diff --git a/lib/properties/flex.js b/lib/properties/flex.js index a319060e..dd484455 100644 --- a/lib/properties/flex.js +++ b/lib/properties/flex.js @@ -20,12 +20,13 @@ module.exports.shorthandFor = new Map([ ]); module.exports.parse = function parse(v, opt = {}) { - const { globalObject } = opt; if (v === "") { return v; } + const { globalObject, options } = opt; const value = parsers.parsePropertyValue(property, v, { globalObject, + options, inArray: true }); if (Array.isArray(value) && value.length) { @@ -115,6 +116,10 @@ module.exports.parse = function parse(v, opt = {}) { flex["flex-basis"] = `${val2.value}${val2.unit}`; break; } + case "Identifier": { + flex["flex-basis"] = val2.name; + break; + } case "Number": { flex["flex-shrink"] = val2.value; break; @@ -123,17 +128,12 @@ module.exports.parse = function parse(v, opt = {}) { flex["flex-basis"] = `${val2.value}%`; break; } - case "Identifier": { - flex["flex-basis"] = val2.name; - break; - } default: { return; } } } return flex; - // return [...Object.values(flex)].join(" "); } } else if (typeof value === "string") { return value; @@ -150,7 +150,8 @@ module.exports.definition = { this._setProperty(property, v); } else { const val = module.exports.parse(v, { - globalObject: this._global + globalObject: this._global, + options: this._options }); const priority = this._priorities.get(property) ?? ""; if (typeof val === "string") { diff --git a/lib/properties/flexBasis.js b/lib/properties/flexBasis.js index 194ba579..b0bbd2dd 100644 --- a/lib/properties/flexBasis.js +++ b/lib/properties/flexBasis.js @@ -6,12 +6,13 @@ const property = "flex-basis"; const shorthand = "flex"; module.exports.parse = function parse(v, opt = {}) { - const { globalObject } = opt; if (v === "") { return v; } + const { globalObject, options } = opt; const value = parsers.parsePropertyValue(property, v, { globalObject, + options, inArray: true }); if (Array.isArray(value) && value.length === 1) { @@ -28,7 +29,7 @@ module.exports.parse = function parse(v, opt = {}) { return name; } default: { - return parsers.parseLengthPercentage(value); + return parsers.parseLengthPercentage(value, options); } } } else if (typeof value === "string") { @@ -44,7 +45,8 @@ module.exports.definition = { this._setProperty(property, v); } else { const val = module.exports.parse(v, { - globalObject: this._global + globalObject: this._global, + options: this._options }); if (typeof val === "string") { const shorthandPriority = this._priorities.get(shorthand); diff --git a/lib/properties/flexGrow.js b/lib/properties/flexGrow.js index 89537d09..e40d7b89 100644 --- a/lib/properties/flexGrow.js +++ b/lib/properties/flexGrow.js @@ -6,12 +6,13 @@ const property = "flex-grow"; const shorthand = "flex"; module.exports.parse = function parse(v, opt = {}) { - const { globalObject } = opt; if (v === "") { return v; } + const { globalObject, options } = opt; const value = parsers.parsePropertyValue("flex-grow", v, { globalObject, + options, inArray: true }); if (Array.isArray(value) && value.length === 1) { @@ -27,7 +28,7 @@ module.exports.parse = function parse(v, opt = {}) { return name; } default: { - return parsers.parseNumber(value); + return parsers.parseNumber(value, options); } } } else if (typeof value === "string") { @@ -43,7 +44,8 @@ module.exports.definition = { this._setProperty(property, v); } else { const val = module.exports.parse(v, { - globalObject: this._global + globalObject: this._global, + options: this._options }); if (typeof val === "string") { const shorthandPriority = this._priorities.get(shorthand); diff --git a/lib/properties/flexShrink.js b/lib/properties/flexShrink.js index 7b205a4b..c4927189 100644 --- a/lib/properties/flexShrink.js +++ b/lib/properties/flexShrink.js @@ -6,12 +6,13 @@ const property = "flex-shrink"; const shorthand = "flex"; module.exports.parse = function parse(v, opt = {}) { - const { globalObject } = opt; if (v === "") { return v; } + const { globalObject, options } = opt; const value = parsers.parsePropertyValue(property, v, { globalObject, + options, inArray: true }); if (Array.isArray(value) && value.length === 1) { @@ -27,7 +28,7 @@ module.exports.parse = function parse(v, opt = {}) { return name; } default: { - return parsers.parseNumber(value); + return parsers.parseNumber(value, options); } } } else if (typeof value === "string") { @@ -43,7 +44,8 @@ module.exports.definition = { this._setProperty(property, v); } else { const val = module.exports.parse(v, { - globalObject: this._global + globalObject: this._global, + options: this._options }); if (typeof val === "string") { const shorthandPriority = this._priorities.get(shorthand); diff --git a/lib/properties/float.js b/lib/properties/float.js index 3e256318..6ffb6215 100644 --- a/lib/properties/float.js +++ b/lib/properties/float.js @@ -5,12 +5,13 @@ const parsers = require("../parsers"); const property = "float"; module.exports.parse = function parse(v, opt = {}) { - const { globalObject } = opt; if (v === "") { return v; } + const { globalObject, options } = opt; const value = parsers.parsePropertyValue(property, v, { globalObject, + options, inArray: true }); if (Array.isArray(value) && value.length === 1) { @@ -34,7 +35,8 @@ module.exports.definition = { this._setProperty(property, v); } else { const val = module.exports.parse(v, { - globalObject: this._global + globalObject: this._global, + options: this._options }); if (typeof val === "string") { const priority = this._priorities.get(property) ?? ""; diff --git a/lib/properties/floodColor.js b/lib/properties/floodColor.js index 280bb112..7d1ded01 100644 --- a/lib/properties/floodColor.js +++ b/lib/properties/floodColor.js @@ -5,12 +5,13 @@ const parsers = require("../parsers"); const property = "flood-color"; module.exports.parse = function parse(v, opt = {}) { - const { globalObject } = opt; if (v === "") { return v; } + const { globalObject, options } = opt; const value = parsers.parsePropertyValue(property, v, { globalObject, + options, inArray: true }); if (Array.isArray(value) && value.length === 1) { @@ -20,7 +21,7 @@ module.exports.parse = function parse(v, opt = {}) { return name; } default: { - return parsers.parseColor(value); + return parsers.parseColor(value, options); } } } else if (typeof value === "string") { @@ -35,7 +36,8 @@ module.exports.definition = { this._setProperty(property, v); } else { const val = module.exports.parse(v, { - globalObject: this._global + globalObject: this._global, + options: this._options }); if (typeof val === "string") { const priority = this._priorities.get(property) ?? ""; diff --git a/lib/properties/font.js b/lib/properties/font.js index 4cbcf553..804832f1 100644 --- a/lib/properties/font.js +++ b/lib/properties/font.js @@ -20,13 +20,13 @@ module.exports.shorthandFor = new Map([ ]); module.exports.parse = function parse(v, opt = {}) { - const { globalObject } = opt; + const { globalObject, options } = opt; if (v === "") { return v; } else if (parsers.hasCalcFunc(v)) { - v = parsers.resolveCalc(v); + v = parsers.resolveCalc(v, opt); } - if (!parsers.isValidPropertyValue(property, v)) { + if (!parsers.isValidPropertyValue(property, v, globalObject)) { return; } const [fontBlock, ...families] = parsers.splitValue(v, { @@ -47,13 +47,15 @@ module.exports.parse = function parse(v, opt = {}) { return; } const lineHeightB = lineHeight.parse(lineB, { - global + globalObject, + options }); if (typeof lineHeightB !== "string") { return; } const familyB = fontFamily.parse(familiesB.join(" "), { globalObject, + options, caseSensitive: true }); if (typeof familyB === "string") { @@ -71,7 +73,8 @@ module.exports.parse = function parse(v, opt = {}) { switch (longhand) { case "font-size": { const parsedValue = fontSize.parse(part, { - globalObject + globalObject, + options }); if (typeof parsedValue === "string") { font[longhand] = parsedValue; @@ -83,7 +86,8 @@ module.exports.parse = function parse(v, opt = {}) { if (font[longhand] === "normal") { const longhandItem = module.exports.shorthandFor.get(longhand); const parsedValue = longhandItem.parse(part, { - globalObject + globalObject, + options }); if (typeof parsedValue === "string") { font[longhand] = parsedValue; @@ -94,7 +98,8 @@ module.exports.parse = function parse(v, opt = {}) { case "font-variant": { if (font[longhand] === "normal") { const parsedValue = fontVariant.parse(part, { - globalObject + globalObject, + options }); if (typeof parsedValue === "string") { if (parsedValue === "small-cap") { @@ -122,6 +127,7 @@ module.exports.parse = function parse(v, opt = {}) { const [part] = revParts; const value = parsers.parsePropertyValue(property, part, { globalObject, + options, inArray: true }); if (Array.isArray(value) && value.length === 1) { @@ -158,7 +164,8 @@ module.exports.parse = function parse(v, opt = {}) { if (font[longhand] === "normal") { const longhandItem = module.exports.shorthandFor.get(longhand); const parsedValue = longhandItem.parse(part, { - globalObject + globalObject, + options }); if (typeof parsedValue === "string") { font[longhand] = parsedValue; @@ -169,7 +176,8 @@ module.exports.parse = function parse(v, opt = {}) { case "font-variant": { if (font[longhand] === "normal") { const parsedValue = fontVariant.parse(part, { - globalObject + globalObject, + options }); if (typeof parsedValue === "string") { if (parsedValue === "small-cap") { @@ -187,13 +195,15 @@ module.exports.parse = function parse(v, opt = {}) { } } else { const parsedFontSize = fontSize.parse(part, { - globalObject + globalObject, + options }); if (typeof parsedFontSize === "string") { fontSizeA = parsedFontSize; } else { const parsedFontFamily = fontFamily.parse(part, { globalObject, + options, caseSensitive: true }); if (typeof parsedFontFamily === "string") { @@ -206,6 +216,7 @@ module.exports.parse = function parse(v, opt = {}) { } const family = fontFamily.parse(revFontFamily.toReversed().join(" "), { globalObject, + options, caseSensitive: true }); if (fontSizeA && family) { @@ -218,6 +229,7 @@ module.exports.parse = function parse(v, opt = {}) { for (const family of families) { const parsedFontFamily = fontFamily.parse(family, { globalObject, + options, caseSensitive: true }); if (parsedFontFamily) { @@ -240,7 +252,8 @@ module.exports.definition = { this._setProperty(property, v); } else { const obj = module.exports.parse(v, { - globalObject: this._global + globalObject: this._global, + options: this._options }); if (!obj) { return; diff --git a/lib/properties/fontFamily.js b/lib/properties/fontFamily.js index db57001d..402cefae 100644 --- a/lib/properties/fontFamily.js +++ b/lib/properties/fontFamily.js @@ -6,10 +6,10 @@ const property = "font-family"; const shorthand = "font"; module.exports.parse = function parse(v, opt = {}) { - const { globalObject } = opt; if (v === "") { return v; } + const { globalObject, options } = opt; const values = parsers.splitValue(v, { delimiter: "," }); @@ -17,6 +17,7 @@ module.exports.parse = function parse(v, opt = {}) { for (const val of values) { const value = parsers.parsePropertyValue(property, val, { globalObject, + options, caseSensitive: true, inArray: true }); @@ -76,7 +77,8 @@ module.exports.definition = { this._setProperty(property, v); } else { const val = module.exports.parse(v, { - globalObject: this._global + globalObject: this._global, + options: this._options }); if (typeof val === "string") { const shorthandPriority = this._priorities.get(shorthand); diff --git a/lib/properties/fontSize.js b/lib/properties/fontSize.js index cdffa8e7..bcef3e6a 100644 --- a/lib/properties/fontSize.js +++ b/lib/properties/fontSize.js @@ -6,12 +6,13 @@ const property = "font-size"; const shorthand = "font"; module.exports.parse = function parse(v, opt = {}) { - const { globalObject } = opt; if (v === "") { return v; } + const { globalObject, options } = opt; const value = parsers.parsePropertyValue(property, v, { globalObject, + options, inArray: true }); if (Array.isArray(value) && value.length === 1) { @@ -28,9 +29,13 @@ module.exports.parse = function parse(v, opt = {}) { return name; } default: { - return parsers.parseLengthPercentage(value, { + const parseOpt = { min: 0 - }); + }; + for (const [key, val] of Object.entries(options)) { + parseOpt[key] = val; + } + return parsers.parseLengthPercentage(value, parseOpt); } } } else if (typeof value === "string") { @@ -46,7 +51,8 @@ module.exports.definition = { this._setProperty(property, v); } else { const val = module.exports.parse(v, { - globalObject: this._global + globalObject: this._global, + options: this._options }); if (typeof val === "string") { const shorthandPriority = this._priorities.get(shorthand); diff --git a/lib/properties/fontStyle.js b/lib/properties/fontStyle.js index b296798d..640afe90 100644 --- a/lib/properties/fontStyle.js +++ b/lib/properties/fontStyle.js @@ -6,12 +6,13 @@ const property = "font-style"; const shorthand = "font"; module.exports.parse = function parse(v, opt = {}) { - const { globalObject } = opt; if (v === "") { return v; } + const { globalObject, options } = opt; const value = parsers.parsePropertyValue(property, v, { globalObject, + options, inArray: true }); if (Array.isArray(value) && value.length) { @@ -27,7 +28,7 @@ module.exports.parse = function parse(v, opt = {}) { } else if (value.length === 2) { const [part1, part2] = value; const val1 = part1.type === "Identifier" && part1.name; - const val2 = parsers.parseAngle([part2]); + const val2 = parsers.parseAngle([part2], options); if (val1 && val1 === "oblique" && val2) { return `${val1} ${val2}`; } @@ -45,7 +46,8 @@ module.exports.definition = { this._setProperty(property, v); } else { const val = module.exports.parse(v, { - globalObject: this._global + globalObject: this._global, + options: this._options }); if (typeof val === "string") { const shorthandPriority = this._priorities.get(shorthand); diff --git a/lib/properties/fontVariant.js b/lib/properties/fontVariant.js index b0d7749d..4e230fa7 100644 --- a/lib/properties/fontVariant.js +++ b/lib/properties/fontVariant.js @@ -6,15 +6,16 @@ const property = "font-variant"; const shorthand = "font"; module.exports.parse = function parse(v, opt = {}) { - const { globalObject } = opt; if (v === "") { return v; } + const { globalObject, options } = opt; const values = parsers.splitValue(v); const parsedValues = []; for (const val of values) { const value = parsers.parsePropertyValue(property, val, { globalObject, + options, inArray: true }); if (Array.isArray(value) && value.length === 1) { @@ -55,7 +56,8 @@ module.exports.definition = { this._setProperty(property, v); } else { const val = module.exports.parse(v, { - globalObject: this._global + globalObject: this._global, + options: this._options }); if (typeof val === "string") { const shorthandPriority = this._priorities.get(shorthand); diff --git a/lib/properties/fontWeight.js b/lib/properties/fontWeight.js index d115a9dd..0bb826b4 100644 --- a/lib/properties/fontWeight.js +++ b/lib/properties/fontWeight.js @@ -6,12 +6,13 @@ const property = "font-weight"; const shorthand = "font"; module.exports.parse = function parse(v, opt = {}) { - const { globalObject } = opt; if (v === "") { return v; } + const { globalObject, options } = opt; const value = parsers.parsePropertyValue(property, v, { globalObject, + options, inArray: true }); if (Array.isArray(value) && value.length === 1) { @@ -28,10 +29,14 @@ module.exports.parse = function parse(v, opt = {}) { return name; } default: { - const parsedValue = parsers.parseNumber(value, { + const parseOpt = { min: 1, max: 1000 - }); + }; + for (const [key, val] of Object.entries(options)) { + parseOpt[key] = val; + } + const parsedValue = parsers.parseNumber(value, parseOpt); if (parsedValue) { return parsedValue; } @@ -50,7 +55,8 @@ module.exports.definition = { this._setProperty(property, v); } else { const val = module.exports.parse(v, { - globalObject: this._global + globalObject: this._global, + options: this._options }); if (typeof val === "string") { const shorthandPriority = this._priorities.get(shorthand); diff --git a/lib/properties/height.js b/lib/properties/height.js index 977d05f7..100e5ba6 100644 --- a/lib/properties/height.js +++ b/lib/properties/height.js @@ -5,12 +5,13 @@ const parsers = require("../parsers"); const property = "height"; module.exports.parse = function parse(v, opt = {}) { - const { globalObject } = opt; if (v === "") { return v; } + const { globalObject, options } = opt; const value = parsers.parsePropertyValue(property, v, { globalObject, + options, inArray: true }); if (Array.isArray(value) && value.length === 1) { @@ -27,7 +28,7 @@ module.exports.parse = function parse(v, opt = {}) { return name; } default: { - return parsers.parseLengthPercentage(value); + return parsers.parseLengthPercentage(value, options); } } } else if (typeof value === "string") { @@ -42,7 +43,8 @@ module.exports.definition = { this._setProperty(property, v); } else { const val = module.exports.parse(v, { - globalObject: this._global + globalObject: this._global, + options: this._options }); if (typeof val === "string") { const priority = this._priorities.get(property) ?? ""; diff --git a/lib/properties/left.js b/lib/properties/left.js index 8b8b8d01..5217e26c 100644 --- a/lib/properties/left.js +++ b/lib/properties/left.js @@ -5,12 +5,13 @@ const parsers = require("../parsers"); const property = "left"; module.exports.parse = function parse(v, opt = {}) { - const { globalObject } = opt; if (v === "") { return v; } + const { globalObject, options } = opt; const value = parsers.parsePropertyValue(property, v, { globalObject, + options, inArray: true }); if (Array.isArray(value) && value.length === 1) { @@ -27,7 +28,7 @@ module.exports.parse = function parse(v, opt = {}) { return name; } default: { - return parsers.parseLengthPercentage(value); + return parsers.parseLengthPercentage(value, options); } } } else if (typeof value === "string") { @@ -42,7 +43,8 @@ module.exports.definition = { this._setProperty(property, v); } else { const val = module.exports.parse(v, { - globalObject: this._global + globalObject: this._global, + options: this._options }); if (typeof val === "string") { const priority = this._priorities.get(property) ?? ""; diff --git a/lib/properties/lightingColor.js b/lib/properties/lightingColor.js index e1e321d4..21773f5b 100644 --- a/lib/properties/lightingColor.js +++ b/lib/properties/lightingColor.js @@ -5,12 +5,13 @@ const parsers = require("../parsers"); const property = "lighting-color"; module.exports.parse = function parse(v, opt = {}) { - const { globalObject } = opt; if (v === "") { return v; } + const { globalObject, options } = opt; const value = parsers.parsePropertyValue(property, v, { globalObject, + options, inArray: true }); if (Array.isArray(value) && value.length === 1) { @@ -20,7 +21,7 @@ module.exports.parse = function parse(v, opt = {}) { return name; } default: { - return parsers.parseColor(value); + return parsers.parseColor(value, options); } } } else if (typeof value === "string") { @@ -35,7 +36,8 @@ module.exports.definition = { this._setProperty(property, v); } else { const val = module.exports.parse(v, { - globalObject: this._global + globalObject: this._global, + options: this._options }); if (typeof val === "string") { const priority = this._priorities.get(property) ?? ""; diff --git a/lib/properties/lineHeight.js b/lib/properties/lineHeight.js index f7eb7598..ee60c563 100644 --- a/lib/properties/lineHeight.js +++ b/lib/properties/lineHeight.js @@ -6,16 +6,23 @@ const property = "line-height"; const shorthand = "font"; module.exports.parse = function parse(v, opt = {}) { - const { globalObject } = opt; if (v === "") { return v; } + const { globalObject, options } = opt; const value = parsers.parsePropertyValue(property, v, { globalObject, + options, inArray: true }); if (Array.isArray(value) && value.length === 1) { const [{ name, type, value: itemValue }] = value; + const parseOpt = { + min: 0 + }; + for (const [key, val] of Object.entries(options)) { + parseOpt[key] = val; + } switch (type) { case "Calc": { return `${name}(${itemValue})`; @@ -25,14 +32,10 @@ module.exports.parse = function parse(v, opt = {}) { return name; } case "Number": { - return parsers.parseNumber(value, { - min: 0 - }); + return parsers.parseNumber(value, parseOpt); } default: { - return parsers.parseLengthPercentage(value, { - min: 0 - }); + return parsers.parseLengthPercentage(value, parseOpt); } } } else if (typeof value === "string") { @@ -48,7 +51,8 @@ module.exports.definition = { this._setProperty(property, v); } else { const val = module.exports.parse(v, { - globalObject: this._global + globalObject: this._global, + options: this._options }); if (typeof val === "string") { const shorthandPriority = this._priorities.get(shorthand); diff --git a/lib/properties/margin.js b/lib/properties/margin.js index df68cc04..ca3c6f9b 100644 --- a/lib/properties/margin.js +++ b/lib/properties/margin.js @@ -18,12 +18,13 @@ module.exports.shorthandFor = new Map([ ]); module.exports.parse = function parse(v, opt = {}) { - const { globalObject } = opt; if (v === "") { return v; } + const { globalObject, options } = opt; const values = parsers.parsePropertyValue(property, v, { globalObject, + options, inArray: true }); const parsedValues = []; @@ -53,7 +54,7 @@ module.exports.parse = function parse(v, opt = {}) { break; } default: { - const parsedValue = parsers.parseLengthPercentage([value]); + const parsedValue = parsers.parseLengthPercentage([value], options); if (!parsedValue) { return; } @@ -79,7 +80,8 @@ module.exports.definition = { this._setProperty(property, v); } else { const val = module.exports.parse(v, { - globalObject: this._global + globalObject: this._global, + options: this._options }); if (Array.isArray(val) || typeof val === "string") { const priority = this._priorities.get(property) ?? ""; diff --git a/lib/properties/marginBottom.js b/lib/properties/marginBottom.js index 26aa15c0..f4cd4ddf 100644 --- a/lib/properties/marginBottom.js +++ b/lib/properties/marginBottom.js @@ -8,12 +8,13 @@ const shorthand = "margin"; module.exports.position = "bottom"; module.exports.parse = function parse(v, opt = {}) { - const { globalObject } = opt; if (v === "") { return v; } + const { globalObject, options } = opt; const value = parsers.parsePropertyValue(property, v, { globalObject, + options, inArray: true }); if (Array.isArray(value) && value.length === 1) { @@ -30,7 +31,7 @@ module.exports.parse = function parse(v, opt = {}) { return name; } default: { - return parsers.parseLengthPercentage(value); + return parsers.parseLengthPercentage(value, options); } } } else if (typeof value === "string") { @@ -46,7 +47,8 @@ module.exports.definition = { this._setProperty(property, v); } else { const val = module.exports.parse(v, { - globalObject: this._global + globalObject: this._global, + options: this._options }); if (typeof val === "string") { const shorthandPriority = this._priorities.get(shorthand); diff --git a/lib/properties/marginLeft.js b/lib/properties/marginLeft.js index ae7ad63f..c38ed941 100644 --- a/lib/properties/marginLeft.js +++ b/lib/properties/marginLeft.js @@ -8,12 +8,13 @@ const shorthand = "margin"; module.exports.position = "left"; module.exports.parse = function parse(v, opt = {}) { - const { globalObject } = opt; if (v === "") { return v; } + const { globalObject, options } = opt; const value = parsers.parsePropertyValue(property, v, { globalObject, + options, inArray: true }); if (Array.isArray(value) && value.length === 1) { @@ -30,7 +31,7 @@ module.exports.parse = function parse(v, opt = {}) { return name; } default: { - return parsers.parseLengthPercentage(value); + return parsers.parseLengthPercentage(value, options); } } } else if (typeof value === "string") { @@ -46,7 +47,8 @@ module.exports.definition = { this._setProperty(property, v); } else { const val = module.exports.parse(v, { - globalObject: this._global + globalObject: this._global, + options: this._options }); if (typeof val === "string") { const shorthandPriority = this._priorities.get(shorthand); diff --git a/lib/properties/marginRight.js b/lib/properties/marginRight.js index 41aca507..2e4a2174 100644 --- a/lib/properties/marginRight.js +++ b/lib/properties/marginRight.js @@ -8,12 +8,13 @@ const shorthand = "margin"; module.exports.position = "right"; module.exports.parse = function parse(v, opt = {}) { - const { globalObject } = opt; if (v === "") { return v; } + const { globalObject, options } = opt; const value = parsers.parsePropertyValue(property, v, { globalObject, + options, inArray: true }); if (Array.isArray(value) && value.length === 1) { @@ -30,7 +31,7 @@ module.exports.parse = function parse(v, opt = {}) { return name; } default: { - return parsers.parseLengthPercentage(value); + return parsers.parseLengthPercentage(value, options); } } } else if (typeof value === "string") { @@ -46,7 +47,8 @@ module.exports.definition = { this._setProperty(property, v); } else { const val = module.exports.parse(v, { - globalObject: this._global + globalObject: this._global, + options: this._options }); if (typeof val === "string") { const shorthandPriority = this._priorities.get(shorthand); diff --git a/lib/properties/marginTop.js b/lib/properties/marginTop.js index e33edf71..b16a9bee 100644 --- a/lib/properties/marginTop.js +++ b/lib/properties/marginTop.js @@ -8,12 +8,13 @@ const shorthand = "margin"; module.exports.position = "top"; module.exports.parse = function parse(v, opt = {}) { - const { globalObject } = opt; if (v === "") { return v; } + const { globalObject, options } = opt; const value = parsers.parsePropertyValue(property, v, { globalObject, + options, inArray: true }); if (Array.isArray(value) && value.length === 1) { @@ -30,7 +31,7 @@ module.exports.parse = function parse(v, opt = {}) { return name; } default: { - return parsers.parseLengthPercentage(value); + return parsers.parseLengthPercentage(value, options); } } } else if (typeof value === "string") { @@ -46,7 +47,8 @@ module.exports.definition = { this._setProperty(property, v); } else { const val = module.exports.parse(v, { - globalObject: this._global + globalObject: this._global, + options: this._options }); if (typeof val === "string") { const shorthandPriority = this._priorities.get(shorthand); diff --git a/lib/properties/opacity.js b/lib/properties/opacity.js index 467a349c..c252c05a 100644 --- a/lib/properties/opacity.js +++ b/lib/properties/opacity.js @@ -5,12 +5,13 @@ const parsers = require("../parsers"); const property = "opacity"; module.exports.parse = function parse(v, opt = {}) { - const { globalObject } = opt; if (v === "") { return v; } + const { globalObject, options } = opt; const value = parsers.parsePropertyValue(property, v, { globalObject, + options, inArray: true }); if (Array.isArray(value) && value.length === 1) { @@ -24,10 +25,10 @@ module.exports.parse = function parse(v, opt = {}) { return name; } case "Number": { - return parsers.parseNumber(value); + return parsers.parseNumber(value, options); } case "Percentage": { - return parsers.parsePercentage(value); + return parsers.parsePercentage(value, options); } default: } @@ -43,7 +44,8 @@ module.exports.definition = { this._setProperty(property, v); } else { const val = module.exports.parse(v, { - globalObject: this._global + globalObject: this._global, + options: this._options }); if (typeof val === "string") { const priority = this._priorities.get(property) ?? ""; diff --git a/lib/properties/outlineColor.js b/lib/properties/outlineColor.js index be62e661..a6ed9680 100644 --- a/lib/properties/outlineColor.js +++ b/lib/properties/outlineColor.js @@ -5,12 +5,13 @@ const parsers = require("../parsers"); const property = "outline-color"; module.exports.parse = function parse(v, opt = {}) { - const { globalObject } = opt; if (v === "") { return v; } + const { globalObject, options } = opt; const value = parsers.parsePropertyValue(property, v, { globalObject, + options, inArray: true }); if (Array.isArray(value) && value.length === 1) { @@ -20,7 +21,7 @@ module.exports.parse = function parse(v, opt = {}) { return name; } default: { - return parsers.parseColor(value); + return parsers.parseColor(value, options); } } } else if (typeof value === "string") { @@ -35,7 +36,8 @@ module.exports.definition = { this._setProperty(property, v); } else { const val = module.exports.parse(v, { - globalObject: this._global + globalObject: this._global, + options: this._options }); if (typeof val === "string") { const priority = this._priorities.get(property) ?? ""; diff --git a/lib/properties/padding.js b/lib/properties/padding.js index b574762f..c3d3f3ee 100644 --- a/lib/properties/padding.js +++ b/lib/properties/padding.js @@ -18,12 +18,13 @@ module.exports.shorthandFor = new Map([ ]); module.exports.parse = function parse(v, opt = {}) { - const { globalObject } = opt; if (v === "") { return v; } + const { globalObject, options } = opt; const values = parsers.parsePropertyValue(property, v, { globalObject, + options, inArray: true }); const parsedValues = []; @@ -49,9 +50,13 @@ module.exports.parse = function parse(v, opt = {}) { break; } default: { - const parsedValue = parsers.parseLengthPercentage([value], { + const parseOpt = { min: 0 - }); + }; + for (const [key, val] of Object.entries(options)) { + parseOpt[key] = val; + } + const parsedValue = parsers.parseLengthPercentage([value], parseOpt); if (!parsedValue) { return; } @@ -77,7 +82,8 @@ module.exports.definition = { this._setProperty(property, v); } else { const val = module.exports.parse(v, { - globalObject: this._global + globalObject: this._global, + options: this._options }); if (Array.isArray(val) || typeof val === "string") { const priority = this._priorities.get(property) ?? ""; diff --git a/lib/properties/paddingBottom.js b/lib/properties/paddingBottom.js index a2ec94da..89a6058e 100644 --- a/lib/properties/paddingBottom.js +++ b/lib/properties/paddingBottom.js @@ -8,12 +8,13 @@ const shorthand = "padding"; module.exports.position = "bottom"; module.exports.parse = function parse(v, opt = {}) { - const { globalObject } = opt; if (v === "") { return v; } + const { globalObject, options } = opt; const value = parsers.parsePropertyValue(property, v, { globalObject, + options, inArray: true }); if (Array.isArray(value) && value.length === 1) { @@ -29,9 +30,13 @@ module.exports.parse = function parse(v, opt = {}) { return name; } default: { - return parsers.parseLengthPercentage(value, { + const parseOpt = { min: 0 - }); + }; + for (const [key, val] of Object.entries(options)) { + parseOpt[key] = val; + } + return parsers.parseLengthPercentage(value, parseOpt); } } } else if (typeof value === "string") { @@ -47,7 +52,8 @@ module.exports.definition = { this._setProperty(property, v); } else { const val = module.exports.parse(v, { - globalObject: this._global + globalObject: this._global, + options: this._options }); if (typeof val === "string") { const shorthandPriority = this._priorities.get(shorthand); diff --git a/lib/properties/paddingLeft.js b/lib/properties/paddingLeft.js index fc67fd41..273fac3b 100644 --- a/lib/properties/paddingLeft.js +++ b/lib/properties/paddingLeft.js @@ -8,12 +8,13 @@ const shorthand = "padding"; module.exports.position = "left"; module.exports.parse = function parse(v, opt = {}) { - const { globalObject } = opt; if (v === "") { return v; } + const { globalObject, options } = opt; const value = parsers.parsePropertyValue(property, v, { globalObject, + options, inArray: true }); if (Array.isArray(value) && value.length === 1) { @@ -29,9 +30,13 @@ module.exports.parse = function parse(v, opt = {}) { return name; } default: { - return parsers.parseLengthPercentage(value, { + const parseOpt = { min: 0 - }); + }; + for (const [key, val] of Object.entries(options)) { + parseOpt[key] = val; + } + return parsers.parseLengthPercentage(value, parseOpt); } } } else if (typeof value === "string") { @@ -47,7 +52,8 @@ module.exports.definition = { this._setProperty(property, v); } else { const val = module.exports.parse(v, { - globalObject: this._global + globalObject: this._global, + options: this._options }); if (typeof val === "string") { const shorthandPriority = this._priorities.get(shorthand); diff --git a/lib/properties/paddingRight.js b/lib/properties/paddingRight.js index d6eb1ec7..f883f021 100644 --- a/lib/properties/paddingRight.js +++ b/lib/properties/paddingRight.js @@ -8,12 +8,13 @@ const shorthand = "padding"; module.exports.position = "right"; module.exports.parse = function parse(v, opt = {}) { - const { globalObject } = opt; if (v === "") { return v; } + const { globalObject, options } = opt; const value = parsers.parsePropertyValue(property, v, { globalObject, + options, inArray: true }); if (Array.isArray(value) && value.length === 1) { @@ -29,9 +30,13 @@ module.exports.parse = function parse(v, opt = {}) { return name; } default: { - return parsers.parseLengthPercentage(value, { + const parseOpt = { min: 0 - }); + }; + for (const [key, val] of Object.entries(options)) { + parseOpt[key] = val; + } + return parsers.parseLengthPercentage(value, parseOpt); } } } else if (typeof value === "string") { @@ -47,7 +52,8 @@ module.exports.definition = { this._setProperty(property, v); } else { const val = module.exports.parse(v, { - globalObject: this._global + globalObject: this._global, + options: this._options }); if (typeof val === "string") { const shorthandPriority = this._priorities.get(shorthand); diff --git a/lib/properties/paddingTop.js b/lib/properties/paddingTop.js index 59c84b86..7f44bf40 100644 --- a/lib/properties/paddingTop.js +++ b/lib/properties/paddingTop.js @@ -8,12 +8,13 @@ const shorthand = "padding"; module.exports.position = "top"; module.exports.parse = function parse(v, opt = {}) { - const { globalObject } = opt; if (v === "") { return v; } + const { globalObject, options } = opt; const value = parsers.parsePropertyValue(property, v, { globalObject, + options, inArray: true }); if (Array.isArray(value) && value.length === 1) { @@ -29,9 +30,13 @@ module.exports.parse = function parse(v, opt = {}) { return name; } default: { - return parsers.parseLengthPercentage(value, { + const parseOpt = { min: 0 - }); + }; + for (const [key, val] of Object.entries(options)) { + parseOpt[key] = val; + } + return parsers.parseLengthPercentage(value, parseOpt); } } } else if (typeof value === "string") { @@ -47,7 +52,8 @@ module.exports.definition = { this._setProperty(property, v); } else { const val = module.exports.parse(v, { - globalObject: this._global + globalObject: this._global, + options: this._options }); if (typeof val === "string") { const shorthandPriority = this._priorities.get(shorthand); diff --git a/lib/properties/right.js b/lib/properties/right.js index 46906797..38ece0fd 100644 --- a/lib/properties/right.js +++ b/lib/properties/right.js @@ -5,12 +5,13 @@ const parsers = require("../parsers"); const property = "right"; module.exports.parse = function parse(v, opt = {}) { - const { globalObject } = opt; if (v === "") { return v; } + const { globalObject, options } = opt; const value = parsers.parsePropertyValue(property, v, { globalObject, + options, inArray: true }); if (Array.isArray(value) && value.length === 1) { @@ -27,7 +28,7 @@ module.exports.parse = function parse(v, opt = {}) { return name; } default: { - return parsers.parseLengthPercentage(value); + return parsers.parseLengthPercentage(value, options); } } } else if (typeof value === "string") { @@ -42,7 +43,8 @@ module.exports.definition = { this._setProperty(property, v); } else { const val = module.exports.parse(v, { - globalObject: this._global + globalObject: this._global, + options: this._options }); if (typeof val === "string") { const priority = this._priorities.get(property) ?? ""; diff --git a/lib/properties/stopColor.js b/lib/properties/stopColor.js index 65c605c4..b3fa2114 100644 --- a/lib/properties/stopColor.js +++ b/lib/properties/stopColor.js @@ -5,12 +5,13 @@ const parsers = require("../parsers"); const property = "stop-color"; module.exports.parse = function parse(v, opt = {}) { - const { globalObject } = opt; if (v === "") { return v; } + const { globalObject, options } = opt; const value = parsers.parsePropertyValue(property, v, { globalObject, + options, inArray: true }); if (Array.isArray(value) && value.length === 1) { @@ -20,7 +21,7 @@ module.exports.parse = function parse(v, opt = {}) { return name; } default: { - return parsers.parseColor(value); + return parsers.parseColor(value, options); } } } else if (typeof value === "string") { @@ -35,7 +36,8 @@ module.exports.definition = { this._setProperty(property, v); } else { const val = module.exports.parse(v, { - globalObject: this._global + globalObject: this._global, + options: this._options }); if (typeof val === "string") { const priority = this._priorities.get(property) ?? ""; diff --git a/lib/properties/top.js b/lib/properties/top.js index 6da042ed..e8af5342 100644 --- a/lib/properties/top.js +++ b/lib/properties/top.js @@ -5,12 +5,13 @@ const parsers = require("../parsers"); const property = "top"; module.exports.parse = function parse(v, opt = {}) { - const { globalObject } = opt; if (v === "") { return v; } + const { globalObject, options } = opt; const value = parsers.parsePropertyValue(property, v, { globalObject, + options, inArray: true }); if (Array.isArray(value) && value.length === 1) { @@ -27,7 +28,7 @@ module.exports.parse = function parse(v, opt = {}) { return name; } default: { - return parsers.parseLengthPercentage(value); + return parsers.parseLengthPercentage(value, options); } } } else if (typeof value === "string") { @@ -42,7 +43,8 @@ module.exports.definition = { this._setProperty(property, v); } else { const val = module.exports.parse(v, { - globalObject: this._global + globalObject: this._global, + options: this._options }); if (typeof val === "string") { const priority = this._priorities.get(property) ?? ""; diff --git a/lib/properties/webkitBorderAfterColor.js b/lib/properties/webkitBorderAfterColor.js index d9d7411d..ee0bc4fa 100644 --- a/lib/properties/webkitBorderAfterColor.js +++ b/lib/properties/webkitBorderAfterColor.js @@ -5,12 +5,13 @@ const parsers = require("../parsers"); const property = "-webkit-border-after-color"; module.exports.parse = function parse(v, opt = {}) { - const { globalObject } = opt; if (v === "") { return v; } + const { globalObject, options } = opt; const value = parsers.parsePropertyValue(property, v, { globalObject, + options, inArray: true }); if (Array.isArray(value) && value.length === 1) { @@ -20,7 +21,7 @@ module.exports.parse = function parse(v, opt = {}) { return name; } default: { - return parsers.parseColor(value); + return parsers.parseColor(value, options); } } } else if (typeof value === "string") { @@ -35,7 +36,8 @@ module.exports.definition = { this._setProperty(property, v); } else { const val = module.exports.parse(v, { - globalObject: this._global + globalObject: this._global, + options: this._options }); if (typeof val === "string") { const priority = this._priorities.get(property) ?? ""; diff --git a/lib/properties/webkitBorderBeforeColor.js b/lib/properties/webkitBorderBeforeColor.js index 6d61e5a7..6dc7f996 100644 --- a/lib/properties/webkitBorderBeforeColor.js +++ b/lib/properties/webkitBorderBeforeColor.js @@ -5,12 +5,13 @@ const parsers = require("../parsers"); const property = "-webkit-border-before-color"; module.exports.parse = function parse(v, opt = {}) { - const { globalObject } = opt; if (v === "") { return v; } + const { globalObject, options } = opt; const value = parsers.parsePropertyValue(property, v, { globalObject, + options, inArray: true }); if (Array.isArray(value) && value.length === 1) { @@ -20,7 +21,7 @@ module.exports.parse = function parse(v, opt = {}) { return name; } default: { - return parsers.parseColor(value); + return parsers.parseColor(value, options); } } } else if (typeof value === "string") { @@ -35,7 +36,8 @@ module.exports.definition = { this._setProperty(property, v); } else { const val = module.exports.parse(v, { - globalObject: this._global + globalObject: this._global, + options: this._options }); if (typeof val === "string") { const priority = this._priorities.get(property) ?? ""; diff --git a/lib/properties/webkitBorderEndColor.js b/lib/properties/webkitBorderEndColor.js index b8c6debf..fb58c297 100644 --- a/lib/properties/webkitBorderEndColor.js +++ b/lib/properties/webkitBorderEndColor.js @@ -5,12 +5,13 @@ const parsers = require("../parsers"); const property = "-webkit-border-end-color"; module.exports.parse = function parse(v, opt = {}) { - const { globalObject } = opt; if (v === "") { return v; } + const { globalObject, options } = opt; const value = parsers.parsePropertyValue(property, v, { globalObject, + options, inArray: true }); if (Array.isArray(value) && value.length === 1) { @@ -20,7 +21,7 @@ module.exports.parse = function parse(v, opt = {}) { return name; } default: { - return parsers.parseColor(value); + return parsers.parseColor(value, options); } } } else if (typeof value === "string") { @@ -35,7 +36,8 @@ module.exports.definition = { this._setProperty(property, v); } else { const val = module.exports.parse(v, { - globalObject: this._global + globalObject: this._global, + options: this._options }); if (typeof val === "string") { const priority = this._priorities.get(property) ?? ""; diff --git a/lib/properties/webkitBorderStartColor.js b/lib/properties/webkitBorderStartColor.js index e60d1df4..e75c4a72 100644 --- a/lib/properties/webkitBorderStartColor.js +++ b/lib/properties/webkitBorderStartColor.js @@ -5,12 +5,13 @@ const parsers = require("../parsers"); const property = "-webkit-border-start-color"; module.exports.parse = function parse(v, opt = {}) { - const { globalObject } = opt; if (v === "") { return v; } + const { globalObject, options } = opt; const value = parsers.parsePropertyValue(property, v, { globalObject, + options, inArray: true }); if (Array.isArray(value) && value.length === 1) { @@ -20,7 +21,7 @@ module.exports.parse = function parse(v, opt = {}) { return name; } default: { - return parsers.parseColor(value); + return parsers.parseColor(value, options); } } } else if (typeof value === "string") { @@ -35,7 +36,8 @@ module.exports.definition = { this._setProperty(property, v); } else { const val = module.exports.parse(v, { - globalObject: this._global + globalObject: this._global, + options: this._options }); if (typeof val === "string") { const priority = this._priorities.get(property) ?? ""; diff --git a/lib/properties/webkitColumnRuleColor.js b/lib/properties/webkitColumnRuleColor.js index 0db57961..ec7e55da 100644 --- a/lib/properties/webkitColumnRuleColor.js +++ b/lib/properties/webkitColumnRuleColor.js @@ -5,12 +5,13 @@ const parsers = require("../parsers"); const property = "-webkit-column-rule-color"; module.exports.parse = function parse(v, opt = {}) { - const { globalObject } = opt; if (v === "") { return v; } + const { globalObject, options } = opt; const value = parsers.parsePropertyValue(property, v, { globalObject, + options, inArray: true }); if (Array.isArray(value) && value.length === 1) { @@ -20,7 +21,7 @@ module.exports.parse = function parse(v, opt = {}) { return name; } default: { - return parsers.parseColor(value); + return parsers.parseColor(value, options); } } } else if (typeof value === "string") { @@ -35,7 +36,8 @@ module.exports.definition = { this._setProperty(property, v); } else { const val = module.exports.parse(v, { - globalObject: this._global + globalObject: this._global, + options: this._options }); if (typeof val === "string") { const priority = this._priorities.get(property) ?? ""; diff --git a/lib/properties/webkitTapHighlightColor.js b/lib/properties/webkitTapHighlightColor.js index 06596563..f5f97d0a 100644 --- a/lib/properties/webkitTapHighlightColor.js +++ b/lib/properties/webkitTapHighlightColor.js @@ -5,12 +5,13 @@ const parsers = require("../parsers"); const property = "-webkit-tap-highlight-color"; module.exports.parse = function parse(v, opt = {}) { - const { globalObject } = opt; if (v === "") { return v; } + const { globalObject, options } = opt; const value = parsers.parsePropertyValue(property, v, { globalObject, + options, inArray: true }); if (Array.isArray(value) && value.length === 1) { @@ -20,7 +21,7 @@ module.exports.parse = function parse(v, opt = {}) { return name; } default: { - return parsers.parseColor(value); + return parsers.parseColor(value, options); } } } else if (typeof value === "string") { @@ -35,7 +36,8 @@ module.exports.definition = { this._setProperty(property, v); } else { const val = module.exports.parse(v, { - globalObject: this._global + globalObject: this._global, + options: this._options }); if (typeof val === "string") { const priority = this._priorities.get(property) ?? ""; diff --git a/lib/properties/webkitTextEmphasisColor.js b/lib/properties/webkitTextEmphasisColor.js index 84dac5ec..ab31c6ef 100644 --- a/lib/properties/webkitTextEmphasisColor.js +++ b/lib/properties/webkitTextEmphasisColor.js @@ -5,12 +5,13 @@ const parsers = require("../parsers"); const property = "-webkit-text-emphasis-color"; module.exports.parse = function parse(v, opt = {}) { - const { globalObject } = opt; if (v === "") { return v; } + const { globalObject, options } = opt; const value = parsers.parsePropertyValue(property, v, { globalObject, + options, inArray: true }); if (Array.isArray(value) && value.length === 1) { @@ -20,7 +21,7 @@ module.exports.parse = function parse(v, opt = {}) { return name; } default: { - return parsers.parseColor(value); + return parsers.parseColor(value, options); } } } else if (typeof value === "string") { @@ -35,7 +36,8 @@ module.exports.definition = { this._setProperty(property, v); } else { const val = module.exports.parse(v, { - globalObject: this._global + globalObject: this._global, + options: this._options }); if (typeof val === "string") { const priority = this._priorities.get(property) ?? ""; diff --git a/lib/properties/webkitTextFillColor.js b/lib/properties/webkitTextFillColor.js index f13dc649..dbb1aacd 100644 --- a/lib/properties/webkitTextFillColor.js +++ b/lib/properties/webkitTextFillColor.js @@ -5,12 +5,13 @@ const parsers = require("../parsers"); const property = "-webkit-text-fill-color"; module.exports.parse = function parse(v, opt = {}) { - const { globalObject } = opt; if (v === "") { return v; } + const { globalObject, options } = opt; const value = parsers.parsePropertyValue(property, v, { globalObject, + options, inArray: true }); if (Array.isArray(value) && value.length === 1) { @@ -20,7 +21,7 @@ module.exports.parse = function parse(v, opt = {}) { return name; } default: { - return parsers.parseColor(value); + return parsers.parseColor(value, options); } } } else if (typeof value === "string") { @@ -35,7 +36,8 @@ module.exports.definition = { this._setProperty(property, v); } else { const val = module.exports.parse(v, { - globalObject: this._global + globalObject: this._global, + options: this._options }); if (typeof val === "string") { const priority = this._priorities.get(property) ?? ""; diff --git a/lib/properties/webkitTextStrokeColor.js b/lib/properties/webkitTextStrokeColor.js index 2339702d..93241044 100644 --- a/lib/properties/webkitTextStrokeColor.js +++ b/lib/properties/webkitTextStrokeColor.js @@ -5,12 +5,13 @@ const parsers = require("../parsers"); const property = "-webkit-text-stroke-color"; module.exports.parse = function parse(v, opt = {}) { - const { globalObject } = opt; if (v === "") { return v; } + const { globalObject, options } = opt; const value = parsers.parsePropertyValue(property, v, { globalObject, + options, inArray: true }); if (Array.isArray(value) && value.length === 1) { @@ -20,7 +21,7 @@ module.exports.parse = function parse(v, opt = {}) { return name; } default: { - return parsers.parseColor(value); + return parsers.parseColor(value, options); } } } else if (typeof value === "string") { @@ -35,7 +36,8 @@ module.exports.definition = { this._setProperty(property, v); } else { const val = module.exports.parse(v, { - globalObject: this._global + globalObject: this._global, + options: this._options }); if (typeof val === "string") { const priority = this._priorities.get(property) ?? ""; diff --git a/lib/properties/width.js b/lib/properties/width.js index 6c60911f..6b212563 100644 --- a/lib/properties/width.js +++ b/lib/properties/width.js @@ -5,12 +5,13 @@ const parsers = require("../parsers"); const property = "width"; module.exports.parse = function parse(v, opt = {}) { - const { globalObject } = opt; if (v === "") { return v; } + const { globalObject, options } = opt; const value = parsers.parsePropertyValue(property, v, { globalObject, + options, inArray: true }); if (Array.isArray(value) && value.length === 1) { @@ -27,7 +28,7 @@ module.exports.parse = function parse(v, opt = {}) { return name; } default: { - return parsers.parseLengthPercentage(value); + return parsers.parseLengthPercentage(value, options); } } } else if (typeof value === "string") { @@ -42,7 +43,8 @@ module.exports.definition = { this._setProperty(property, v); } else { const val = module.exports.parse(v, { - globalObject: this._global + globalObject: this._global, + options: this._options }); if (typeof val === "string") { const priority = this._priorities.get(property) ?? ""; diff --git a/lib/utils/cache.js b/lib/utils/cache.js new file mode 100644 index 00000000..2669eb24 --- /dev/null +++ b/lib/utils/cache.js @@ -0,0 +1,34 @@ +"use strict"; + +const { LRUCache } = require("lru-cache"); + +// The lru-cache instance. +const lruCache = new LRUCache({ + max: 4096 +}); + +// The lru-cache requires non-null values, so substitute in this sentinel when we are given one. +const nullSentinel = Symbol("null"); + +/** + * @param key - Cache key. + * @param value - Value to cache. + * @returns void. + */ +const setCache = (key, value) => { + lruCache.set(key, value === null ? nullSentinel : value); +}; + +/** + * @param key - Cache key. + * @returns Cached item or false otherwise. + */ +const getCache = (key) => { + const value = lruCache.get(key); + return value === nullSentinel ? null : value; +}; + +module.exports = { + getCache, + setCache +}; diff --git a/lib/utils/propertyDescriptors.js b/lib/utils/propertyDescriptors.js index b0053db8..12612586 100644 --- a/lib/utils/propertyDescriptors.js +++ b/lib/utils/propertyDescriptors.js @@ -5,10 +5,66 @@ const parsers = require("../parsers"); exports.getPropertyDescriptor = function getPropertyDescriptor(property) { return { set(v) { - v = parsers.parsePropertyValue(property, v, { - globalObject: this._global - }); - this._setProperty(property, v); + const globalObject = this._global; + v = parsers.prepareValue(v, globalObject); + if (v === "" || parsers.hasVarFunc(v)) { + this._setProperty(property, v); + } else { + const options = this._options; + const val = parsers.parsePropertyValue(property, v, { + globalObject, + options, + inArray: true + }); + let value; + if (Array.isArray(val) && val.length === 1) { + const [{ name, raw, type, value: itemValue }] = val; + switch (type) { + case "Angle": { + value = parsers.parseAngle(val, options); + break; + } + case "Calc": { + value = `${name}(${itemValue})`; + break; + } + case "Dimension": { + value = parsers.parseLength(val, options); + break; + } + case "GlobalKeyword": + case "Identifier": { + value = name; + break; + } + case "Number": { + value = parsers.parseNumber(val, options); + break; + } + case "Percentage": { + value = parsers.parsePercentage(val, options); + break; + } + case "String": { + value = parsers.parseString(val, options); + break; + } + case "Url": { + value = parsers.parseURL(val, options); + break; + } + default: { + value = raw; + } + } + } else if (typeof val === "string") { + value = val; + } + if (typeof value === "string") { + const priority = this._priorities.get(property) ?? ""; + this._setProperty(property, value, priority); + } + } }, get() { return this.getPropertyValue(property); diff --git a/package-lock.json b/package-lock.json index a7a46446..007b9130 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,40 +9,41 @@ "version": "5.3.3", "license": "MIT", "dependencies": { - "@asamuzakjp/css-color": "^4.0.3", - "@csstools/css-syntax-patches-for-csstree": "^1.0.14", - "css-tree": "^3.1.0" + "@asamuzakjp/css-color": "^4.0.5", + "@csstools/css-syntax-patches-for-csstree": "^1.0.16", + "css-tree": "^3.1.0", + "lru-cache": "^11.2.2" }, "devDependencies": { - "@babel/generator": "^7.28.0", - "@babel/parser": "^7.28.0", - "@babel/traverse": "^7.28.0", - "@babel/types": "^7.28.2", + "@babel/generator": "^7.28.5", + "@babel/parser": "^7.28.5", + "@babel/traverse": "^7.28.5", + "@babel/types": "^7.28.5", "@domenic/eslint-config": "^4.0.1", - "@webref/css": "^6.23.6", - "eslint": "^9.32.0", + "@webref/css": "^8.0.1", + "eslint": "^9.39.1", "eslint-config-prettier": "^10.1.8", - "eslint-plugin-prettier": "^5.5.3", - "globals": "^16.3.0", - "npm-run-all": "^4.1.5", + "eslint-plugin-prettier": "^5.5.4", + "globals": "^16.5.0", + "npm-run-all2": "^8.0.4", "prettier": "^3.6.2", - "resolve": "^1.22.10" + "resolve": "^1.22.11" }, "engines": { "node": ">=20" } }, "node_modules/@asamuzakjp/css-color": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-4.0.3.tgz", - "integrity": "sha512-aixYrB8ESx3o1DnhOQsvjg5OCX0eK2pu4IjEKLbPhJofpREoUZDRp9orC6uUDih0V86eX8FINeU65LwiLOk32g==", + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-4.0.5.tgz", + "integrity": "sha512-lMrXidNhPGsDjytDy11Vwlb6OIGrT3CmLg3VWNFyWkLWtijKl7xjvForlh8vuj0SHGjgl4qZEQzUmYTeQA2JFQ==", "license": "MIT", "dependencies": { "@csstools/css-calc": "^2.1.4", - "@csstools/css-color-parser": "^3.0.10", + "@csstools/css-color-parser": "^3.1.0", "@csstools/css-parser-algorithms": "^3.0.5", "@csstools/css-tokenizer": "^3.0.4", - "lru-cache": "^11.1.0" + "lru-cache": "^11.2.1" } }, "node_modules/@babel/code-frame": { @@ -61,14 +62,14 @@ } }, "node_modules/@babel/generator": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.0.tgz", - "integrity": "sha512-lJjzvrbEeWrhB4P3QBsH7tey117PjLZnDbLiQEKjQ/fNJTjuq4HSqgFA+UNSwZT8D7dxxbnuSBMsa1lrWzKlQg==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.5.tgz", + "integrity": "sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/parser": "^7.28.0", - "@babel/types": "^7.28.0", + "@babel/parser": "^7.28.5", + "@babel/types": "^7.28.5", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" @@ -98,9 +99,9 @@ } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", - "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", "dev": true, "license": "MIT", "engines": { @@ -108,13 +109,13 @@ } }, "node_modules/@babel/parser": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.0.tgz", - "integrity": "sha512-jVZGvOxOuNSsuQuLRTh13nU0AogFlw32w/MT+LV6D3sP5WdbW61E77RnkbaO2dUvmPAYrBDJXGn5gGS6tH4j8g==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.5.tgz", + "integrity": "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/types": "^7.28.0" + "@babel/types": "^7.28.5" }, "bin": { "parser": "bin/babel-parser.js" @@ -139,18 +140,18 @@ } }, "node_modules/@babel/traverse": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.0.tgz", - "integrity": "sha512-mGe7UK5wWyh0bKRfupsUchrQGqvDbZDbKJw+kcRGSmdHVYrv+ltd0pnpDTVpiTqnaBru9iEvA8pz8W46v0Amwg==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.5.tgz", + "integrity": "sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==", "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.27.1", - "@babel/generator": "^7.28.0", + "@babel/generator": "^7.28.5", "@babel/helper-globals": "^7.28.0", - "@babel/parser": "^7.28.0", + "@babel/parser": "^7.28.5", "@babel/template": "^7.27.2", - "@babel/types": "^7.28.0", + "@babel/types": "^7.28.5", "debug": "^4.3.1" }, "engines": { @@ -158,23 +159,23 @@ } }, "node_modules/@babel/types": { - "version": "7.28.2", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.2.tgz", - "integrity": "sha512-ruv7Ae4J5dUYULmeXw1gmb7rYRz57OWCPM57pHojnLq/3Z1CK2lNSLTCVjxVk1F/TZHwOZZrOWi0ur95BbLxNQ==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.5.tgz", + "integrity": "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==", "dev": true, "license": "MIT", "dependencies": { "@babel/helper-string-parser": "^7.27.1", - "@babel/helper-validator-identifier": "^7.27.1" + "@babel/helper-validator-identifier": "^7.28.5" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@csstools/color-helpers": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-5.0.2.tgz", - "integrity": "sha512-JqWH1vsgdGcw2RR6VliXXdA0/59LttzlU8UlRT/iUUsEeWfYq8I+K0yhihEUTTHLRm1EXvpsCx3083EU15ecsA==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-5.1.0.tgz", + "integrity": "sha512-S11EXWJyy0Mz5SYvRmY8nJYTFFd1LCNV+7cXyAgQtOOuzb4EsgfqDufL+9esx72/eLhsRdGZwaldu/h+E4t4BA==", "funding": [ { "type": "github", @@ -214,9 +215,9 @@ } }, "node_modules/@csstools/css-color-parser": { - "version": "3.0.10", - "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-3.0.10.tgz", - "integrity": "sha512-TiJ5Ajr6WRd1r8HSiwJvZBiJOqtH86aHpUjq5aEKWHiII2Qfjqd/HCWKPOW8EP4vcspXbHnXrwIDlu5savQipg==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-3.1.0.tgz", + "integrity": "sha512-nbtKwh3a6xNVIp/VRuXV64yTKnb1IjTAEEh3irzS+HkKjAOYLTGNb9pmVNntZ8iVBHcWDA2Dof0QtPgFI1BaTA==", "funding": [ { "type": "github", @@ -229,7 +230,7 @@ ], "license": "MIT", "dependencies": { - "@csstools/color-helpers": "^5.0.2", + "@csstools/color-helpers": "^5.1.0", "@csstools/css-calc": "^2.1.4" }, "engines": { @@ -255,6 +256,7 @@ } ], "license": "MIT", + "peer": true, "engines": { "node": ">=18" }, @@ -263,9 +265,9 @@ } }, "node_modules/@csstools/css-syntax-patches-for-csstree": { - "version": "1.0.14", - "resolved": "https://registry.npmjs.org/@csstools/css-syntax-patches-for-csstree/-/css-syntax-patches-for-csstree-1.0.14.tgz", - "integrity": "sha512-zSlIxa20WvMojjpCSy8WrNpcZ61RqfTfX3XTaOeVlGJrt/8HF3YbzgFZa01yTbT4GWQLwfTcC3EB8i3XnB647Q==", + "version": "1.0.16", + "resolved": "https://registry.npmjs.org/@csstools/css-syntax-patches-for-csstree/-/css-syntax-patches-for-csstree-1.0.16.tgz", + "integrity": "sha512-2SpS4/UaWQaGpBINyG5ZuCHnUDeVByOhvbkARwfmnfxDvTaj80yOI1cD8Tw93ICV5Fx4fnyDKWQZI1CDtcWyUg==", "funding": [ { "type": "github", @@ -279,9 +281,6 @@ "license": "MIT-0", "engines": { "node": ">=18" - }, - "peerDependencies": { - "postcss": "^8.4" } }, "node_modules/@csstools/css-tokenizer": { @@ -299,6 +298,7 @@ } ], "license": "MIT", + "peer": true, "engines": { "node": ">=18" } @@ -314,9 +314,9 @@ } }, "node_modules/@eslint-community/eslint-utils": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.1.tgz", - "integrity": "sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA==", + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.0.tgz", + "integrity": "sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==", "dev": true, "license": "MIT", "dependencies": { @@ -356,13 +356,13 @@ } }, "node_modules/@eslint/config-array": { - "version": "0.21.0", - "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.0.tgz", - "integrity": "sha512-ENIdc4iLu0d93HeYirvKmrzshzofPw6VkZRKQGe9Nv46ZnWUzcF1xV01dcvEg/1wXUR61OmmlSfyeyO7EvjLxQ==", + "version": "0.21.1", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.1.tgz", + "integrity": "sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@eslint/object-schema": "^2.1.6", + "@eslint/object-schema": "^2.1.7", "debug": "^4.3.1", "minimatch": "^3.1.2" }, @@ -371,19 +371,22 @@ } }, "node_modules/@eslint/config-helpers": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.3.0.tgz", - "integrity": "sha512-ViuymvFmcJi04qdZeDc2whTHryouGcDlaxPqarTD0ZE10ISpxGUVZGZDx4w01upyIynL3iu6IXH2bS1NhclQMw==", + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.2.tgz", + "integrity": "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==", "dev": true, "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.17.0" + }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, "node_modules/@eslint/core": { - "version": "0.15.1", - "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.15.1.tgz", - "integrity": "sha512-bkOp+iumZCCbt1K1CmWf0R9pM5yKpDv+ZXtvSyQpudrI9kuFLp+bM2WOPXImuD/ceQuaa8f5pj93Y7zyECIGNA==", + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.17.0.tgz", + "integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -431,9 +434,9 @@ } }, "node_modules/@eslint/js": { - "version": "9.32.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.32.0.tgz", - "integrity": "sha512-BBpRFZK3eX6uMLKz8WxFOBIFFcGFJ/g8XuwjTHCqHROSIsopI+ddn/d5Cfh36+7+e5edVS8dbSHnBNhrLEX0zg==", + "version": "9.39.1", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.1.tgz", + "integrity": "sha512-S26Stp4zCy88tH94QbBv3XCuzRQiZ9yXofEILmglYTh/Ug/a9/umqvgFtYBAo3Lp0nsI/5/qH1CCrbdK3AP1Tw==", "dev": true, "license": "MIT", "engines": { @@ -444,9 +447,9 @@ } }, "node_modules/@eslint/object-schema": { - "version": "2.1.6", - "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.6.tgz", - "integrity": "sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==", + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.7.tgz", + "integrity": "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==", "dev": true, "license": "Apache-2.0", "engines": { @@ -454,13 +457,13 @@ } }, "node_modules/@eslint/plugin-kit": { - "version": "0.3.4", - "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.3.4.tgz", - "integrity": "sha512-Ul5l+lHEcw3L5+k8POx6r74mxEYKG5kOb6Xpy2gCRW6zweT6TEhAf8vhxGgjhqrd/VO/Dirhsb+1hNpD1ue9hw==", + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz", + "integrity": "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@eslint/core": "^0.15.1", + "@eslint/core": "^0.17.0", "levn": "^0.4.1" }, "engines": { @@ -600,9 +603,9 @@ "license": "MIT" }, "node_modules/@webref/css": { - "version": "6.23.6", - "resolved": "https://registry.npmjs.org/@webref/css/-/css-6.23.6.tgz", - "integrity": "sha512-PdgFNBJxoYc5WTJ5yxzpoxU6drWdtiXheaYmDh1YNiQc6sFxTJbUy5bfjHxXxQ37hhsLfWxuD3DG9L4GpRahoA==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@webref/css/-/css-8.0.1.tgz", + "integrity": "sha512-TxryLLjDGJnNbv55arQ1v3YAzmuniXARJ5RaBLMIA1Ijx/uICUQ0GCSvGem997K4LsMW+UztrXPpxmsop9JcdA==", "dev": true, "license": "MIT", "peerDependencies": { @@ -615,6 +618,7 @@ "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "dev": true, "license": "MIT", + "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -672,71 +676,6 @@ "dev": true, "license": "Python-2.0" }, - "node_modules/array-buffer-byte-length": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz", - "integrity": "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "is-array-buffer": "^3.0.5" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/arraybuffer.prototype.slice": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.4.tgz", - "integrity": "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "array-buffer-byte-length": "^1.0.1", - "call-bind": "^1.0.8", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.5", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.6", - "is-array-buffer": "^3.0.4" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/async-function": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/async-function/-/async-function-1.0.0.tgz", - "integrity": "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/available-typed-arrays": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", - "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "possible-typed-array-names": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -755,56 +694,6 @@ "concat-map": "0.0.1" } }, - "node_modules/call-bind": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", - "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.0", - "es-define-property": "^1.0.0", - "get-intrinsic": "^1.2.4", - "set-function-length": "^1.2.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/call-bind-apply-helpers": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", - "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/call-bound": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", - "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.2", - "get-intrinsic": "^1.3.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", @@ -879,6 +768,7 @@ "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-3.1.0.tgz", "integrity": "sha512-0eW44TGN5SQXU1mWSkKwFstI/22X2bG1nYzZTYMAWjylYURhse752YgbE4Cx46AC+bAvI+/dYTPRk1LqSUnu6w==", "license": "MIT", + "peer": true, "dependencies": { "mdn-data": "2.12.2", "source-map-js": "^1.0.1" @@ -887,60 +777,6 @@ "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" } }, - "node_modules/data-view-buffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.2.tgz", - "integrity": "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "es-errors": "^1.3.0", - "is-data-view": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/data-view-byte-length": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.2.tgz", - "integrity": "sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "es-errors": "^1.3.0", - "is-data-view": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/inspect-js" - } - }, - "node_modules/data-view-byte-offset": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.1.tgz", - "integrity": "sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "is-data-view": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/debug": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", @@ -966,200 +802,6 @@ "dev": true, "license": "MIT" }, - "node_modules/define-data-property": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", - "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", - "dev": true, - "license": "MIT", - "dependencies": { - "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "gopd": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/define-properties": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", - "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", - "dev": true, - "license": "MIT", - "dependencies": { - "define-data-property": "^1.0.1", - "has-property-descriptors": "^1.0.0", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/dunder-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", - "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.1", - "es-errors": "^1.3.0", - "gopd": "^1.2.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-arrayish": "^0.2.1" - } - }, - "node_modules/es-abstract": { - "version": "1.23.9", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.9.tgz", - "integrity": "sha512-py07lI0wjxAC/DcfK1S6G7iANonniZwTISvdPzk9hzeH0IZIshbuuFxLIU96OyF89Yb9hiqWn8M/bY83KY5vzA==", - "dev": true, - "license": "MIT", - "dependencies": { - "array-buffer-byte-length": "^1.0.2", - "arraybuffer.prototype.slice": "^1.0.4", - "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.8", - "call-bound": "^1.0.3", - "data-view-buffer": "^1.0.2", - "data-view-byte-length": "^1.0.2", - "data-view-byte-offset": "^1.0.1", - "es-define-property": "^1.0.1", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.0.0", - "es-set-tostringtag": "^2.1.0", - "es-to-primitive": "^1.3.0", - "function.prototype.name": "^1.1.8", - "get-intrinsic": "^1.2.7", - "get-proto": "^1.0.0", - "get-symbol-description": "^1.1.0", - "globalthis": "^1.0.4", - "gopd": "^1.2.0", - "has-property-descriptors": "^1.0.2", - "has-proto": "^1.2.0", - "has-symbols": "^1.1.0", - "hasown": "^2.0.2", - "internal-slot": "^1.1.0", - "is-array-buffer": "^3.0.5", - "is-callable": "^1.2.7", - "is-data-view": "^1.0.2", - "is-regex": "^1.2.1", - "is-shared-array-buffer": "^1.0.4", - "is-string": "^1.1.1", - "is-typed-array": "^1.1.15", - "is-weakref": "^1.1.0", - "math-intrinsics": "^1.1.0", - "object-inspect": "^1.13.3", - "object-keys": "^1.1.1", - "object.assign": "^4.1.7", - "own-keys": "^1.0.1", - "regexp.prototype.flags": "^1.5.3", - "safe-array-concat": "^1.1.3", - "safe-push-apply": "^1.0.0", - "safe-regex-test": "^1.1.0", - "set-proto": "^1.0.0", - "string.prototype.trim": "^1.2.10", - "string.prototype.trimend": "^1.0.9", - "string.prototype.trimstart": "^1.0.8", - "typed-array-buffer": "^1.0.3", - "typed-array-byte-length": "^1.0.3", - "typed-array-byte-offset": "^1.0.4", - "typed-array-length": "^1.0.7", - "unbox-primitive": "^1.1.0", - "which-typed-array": "^1.1.18" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/es-define-property": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", - "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-errors": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", - "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-object-atoms": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", - "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", - "dev": true, - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-set-tostringtag": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", - "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", - "dev": true, - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.6", - "has-tostringtag": "^1.0.2", - "hasown": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-to-primitive": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.3.0.tgz", - "integrity": "sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-callable": "^1.2.7", - "is-date-object": "^1.0.5", - "is-symbol": "^1.0.4" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/escape-string-regexp": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", @@ -1174,25 +816,25 @@ } }, "node_modules/eslint": { - "version": "9.32.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.32.0.tgz", - "integrity": "sha512-LSehfdpgMeWcTZkWZVIJl+tkZ2nuSkyyB9C27MZqFWXuph7DvaowgcTvKqxvpLW1JZIk8PN7hFY3Rj9LQ7m7lg==", + "version": "9.39.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.1.tgz", + "integrity": "sha512-BhHmn2yNOFA9H9JmmIVKJmd288g9hrVRDkdoIgRCRuSySRUHH7r/DI6aAXW9T1WwUuY3DFgrcaqB+deURBLR5g==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", - "@eslint/config-array": "^0.21.0", - "@eslint/config-helpers": "^0.3.0", - "@eslint/core": "^0.15.0", + "@eslint/config-array": "^0.21.1", + "@eslint/config-helpers": "^0.4.2", + "@eslint/core": "^0.17.0", "@eslint/eslintrc": "^3.3.1", - "@eslint/js": "9.32.0", - "@eslint/plugin-kit": "^0.3.4", + "@eslint/js": "9.39.1", + "@eslint/plugin-kit": "^0.4.1", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.2", "@types/estree": "^1.0.6", - "@types/json-schema": "^7.0.15", "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.6", @@ -1240,6 +882,7 @@ "integrity": "sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==", "dev": true, "license": "MIT", + "peer": true, "bin": { "eslint-config-prettier": "bin/cli.js" }, @@ -1251,9 +894,9 @@ } }, "node_modules/eslint-plugin-prettier": { - "version": "5.5.3", - "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.5.3.tgz", - "integrity": "sha512-NAdMYww51ehKfDyDhv59/eIItUVzU0Io9H2E8nHNGKEeeqlnci+1gCvrHib6EmZdf6GxF+LCV5K7UC65Ezvw7w==", + "version": "5.5.4", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.5.4.tgz", + "integrity": "sha512-swNtI95SToIz05YINMA6Ox5R057IMAmWZ26GqPxusAp1TZzj+IdY9tXNWWD3vkF/wEqydCONcwjTFpxybBqZsg==", "dev": true, "license": "MIT", "dependencies": { @@ -1454,22 +1097,6 @@ "dev": true, "license": "ISC" }, - "node_modules/for-each": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", - "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-callable": "^1.2.7" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/function-bind": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", @@ -1480,168 +1107,30 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/function.prototype.name": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.8.tgz", - "integrity": "sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==", + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.3", - "define-properties": "^1.2.1", - "functions-have-names": "^1.2.3", - "hasown": "^2.0.2", - "is-callable": "^1.2.7" + "is-glob": "^4.0.3" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=10.13.0" } }, - "node_modules/functions-have-names": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", - "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "node_modules/globals": { + "version": "16.5.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-16.5.0.tgz", + "integrity": "sha512-c/c15i26VrJ4IRt5Z89DnIzCGDn9EcebibhAOjw5ibqEHsE1wLUgkPn9RDmNcUKyU87GeaL633nyJ+pplFR2ZQ==", "dev": true, "license": "MIT", + "engines": { + "node": ">=18" + }, "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-intrinsic": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", - "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.2", - "es-define-property": "^1.0.1", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.1.1", - "function-bind": "^1.1.2", - "get-proto": "^1.0.1", - "gopd": "^1.2.0", - "has-symbols": "^1.1.0", - "hasown": "^2.0.2", - "math-intrinsics": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", - "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", - "dev": true, - "license": "MIT", - "dependencies": { - "dunder-proto": "^1.0.1", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/get-symbol-description": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.1.0.tgz", - "integrity": "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.6" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/globals": { - "version": "16.3.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-16.3.0.tgz", - "integrity": "sha512-bqWEnJ1Nt3neqx2q5SFfGS8r/ahumIakg3HcwtNlrVlwXIeNumWn/c7Pn/wKzGhf6SaW6H6uWXLqC30STCMchQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/globalthis": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", - "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "define-properties": "^1.2.1", - "gopd": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/gopd": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", - "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/has-bigints": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.1.0.tgz", - "integrity": "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/has-flag": { @@ -1654,64 +1143,6 @@ "node": ">=8" } }, - "node_modules/has-property-descriptors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", - "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", - "dev": true, - "license": "MIT", - "dependencies": { - "es-define-property": "^1.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-proto": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.2.0.tgz", - "integrity": "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "dunder-proto": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-symbols": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", - "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-tostringtag": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", - "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-symbols": "^1.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/hasown": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", @@ -1725,13 +1156,6 @@ "node": ">= 0.4" } }, - "node_modules/hosted-git-info": { - "version": "2.8.9", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", - "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", - "dev": true, - "license": "ISC" - }, "node_modules/ignore": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", @@ -1769,1469 +1193,490 @@ "node": ">=0.8.19" } }, - "node_modules/internal-slot": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz", - "integrity": "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==", + "node_modules/is-core-module": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", "dev": true, "license": "MIT", "dependencies": { - "es-errors": "^1.3.0", - "hasown": "^2.0.2", - "side-channel": "^1.1.0" + "hasown": "^2.0.2" }, "engines": { "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-array-buffer": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz", - "integrity": "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==", + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.3", - "get-intrinsic": "^1.2.6" + "is-extglob": "^2.1.1" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=0.10.0" } }, - "node_modules/is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", "dev": true, "license": "MIT" }, - "node_modules/is-async-function": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.1.1.tgz", - "integrity": "sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==", + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "dev": true, "license": "MIT", "dependencies": { - "async-function": "^1.0.0", - "call-bound": "^1.0.3", - "get-proto": "^1.0.1", - "has-tostringtag": "^1.0.2", - "safe-regex-test": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" + "argparse": "^2.0.1" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "bin": { + "js-yaml": "bin/js-yaml.js" } }, - "node_modules/is-bigint": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.1.0.tgz", - "integrity": "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==", + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", "dev": true, "license": "MIT", - "dependencies": { - "has-bigints": "^1.0.2" + "bin": { + "jsesc": "bin/jsesc" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=6" } }, - "node_modules/is-boolean-object": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.2.tgz", - "integrity": "sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==", + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-parse-even-better-errors": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-4.0.0.tgz", + "integrity": "sha512-lR4MXjGNgkJc7tkQ97kb2nuEMnNCyU//XYVH0MKTGcXEiSudQ5MKGKen3C5QubYy0vmq+JGitUg92uuywGEwIA==", "dev": true, "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "has-tostringtag": "^1.0.2" - }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": "^18.17.0 || >=20.5.0" } }, - "node_modules/is-callable": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", - "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", "dev": true, "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "dependencies": { + "json-buffer": "3.0.1" } }, - "node_modules/is-core-module": { - "version": "2.16.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", - "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", "dev": true, "license": "MIT", "dependencies": { - "hasown": "^2.0.2" + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">= 0.8.0" } }, - "node_modules/is-data-view": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.2.tgz", - "integrity": "sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==", + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", "dev": true, "license": "MIT", "dependencies": { - "call-bound": "^1.0.2", - "get-intrinsic": "^1.2.6", - "is-typed-array": "^1.1.13" + "p-locate": "^5.0.0" }, "engines": { - "node": ">= 0.4" + "node": ">=10" }, "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-date-object": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.1.0.tgz", - "integrity": "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "has-tostringtag": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-finalizationregistry": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.1.1.tgz", - "integrity": "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-generator-function": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.0.tgz", - "integrity": "sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "get-proto": "^1.0.0", - "has-tostringtag": "^1.0.2", - "safe-regex-test": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-map": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", - "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-number-object": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.1.1.tgz", - "integrity": "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "has-tostringtag": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-regex": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", - "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "gopd": "^1.2.0", - "has-tostringtag": "^1.0.2", - "hasown": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-set": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", - "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-shared-array-buffer": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.4.tgz", - "integrity": "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-string": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.1.1.tgz", - "integrity": "sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "has-tostringtag": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-symbol": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.1.1.tgz", - "integrity": "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "has-symbols": "^1.1.0", - "safe-regex-test": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-typed-array": { - "version": "1.1.15", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz", - "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "which-typed-array": "^1.1.16" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-weakmap": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", - "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-weakref": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.1.1.tgz", - "integrity": "sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-weakset": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.4.tgz", - "integrity": "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "get-intrinsic": "^1.2.6" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", - "dev": true, - "license": "MIT" - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true, - "license": "ISC" - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "license": "MIT", - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/jsesc": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", - "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", - "dev": true, - "license": "MIT", - "bin": { - "jsesc": "bin/jsesc" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/json-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", - "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/json-parse-better-errors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", - "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", - "dev": true, - "license": "MIT" - }, - "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true, - "license": "MIT" - }, - "node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true, - "license": "MIT" - }, - "node_modules/keyv": { - "version": "4.5.4", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", - "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", - "dev": true, - "license": "MIT", - "dependencies": { - "json-buffer": "3.0.1" - } - }, - "node_modules/levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/load-json-file": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", - "integrity": "sha512-Kx8hMakjX03tiGTLAIdJ+lL0htKnXjEZN6hk/tozf/WOuYGdZBJrZ+rCJRbVCugsjB3jMLn9746NsQIf5VjBMw==", - "dev": true, - "license": "MIT", - "dependencies": { - "graceful-fs": "^4.1.2", - "parse-json": "^4.0.0", - "pify": "^3.0.0", - "strip-bom": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/lru-cache": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.1.0.tgz", - "integrity": "sha512-QIXZUBJUx+2zHUdQujWejBkcD9+cs94tLn0+YL8UrCh+D5sCXZ4c7LaEH48pNwRY3MLDgqUFyhlCyjJPf1WP0A==", - "license": "ISC", - "engines": { - "node": "20 || >=22" - } - }, - "node_modules/math-intrinsics": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", - "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/mdn-data": { - "version": "2.12.2", - "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.12.2.tgz", - "integrity": "sha512-IEn+pegP1aManZuckezWCO+XZQDplx1366JoVhTpMpBB1sPey/SbveZQUosKiKiGYjg1wH4pMlNgXbCiYgihQA==", - "license": "CC0-1.0" - }, - "node_modules/memorystream": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz", - "integrity": "sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw==", - "dev": true, - "engines": { - "node": ">= 0.10.0" - } - }, - "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true, - "license": "MIT" - }, - "node_modules/nanoid": { - "version": "3.3.11", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", - "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "peer": true, - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, - "node_modules/natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true, - "license": "MIT" - }, - "node_modules/nice-try": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", - "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/normalize-package-data": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" - } - }, - "node_modules/npm-run-all": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/npm-run-all/-/npm-run-all-4.1.5.tgz", - "integrity": "sha512-Oo82gJDAVcaMdi3nuoKFavkIHBRVqQ1qvMb+9LHk/cF4P6B2m8aP04hGf7oL6wZ9BuGwX1onlLhpuoofSyoQDQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^3.2.1", - "chalk": "^2.4.1", - "cross-spawn": "^6.0.5", - "memorystream": "^0.3.1", - "minimatch": "^3.0.4", - "pidtree": "^0.3.0", - "read-pkg": "^3.0.0", - "shell-quote": "^1.6.1", - "string.prototype.padend": "^3.0.0" - }, - "bin": { - "npm-run-all": "bin/npm-run-all/index.js", - "run-p": "bin/run-p/index.js", - "run-s": "bin/run-s/index.js" - }, - "engines": { - "node": ">= 4" - } - }, - "node_modules/npm-run-all/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/npm-run-all/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/npm-run-all/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/npm-run-all/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true, - "license": "MIT" - }, - "node_modules/npm-run-all/node_modules/cross-spawn": { - "version": "6.0.6", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.6.tgz", - "integrity": "sha512-VqCUuhcd1iB+dsv8gxPttb5iZh/D0iubSP21g36KXdEuf6I5JiioesUVjpCdHV9MZRUfVFlvwtIUyPfxo5trtw==", - "dev": true, - "license": "MIT", - "dependencies": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - }, - "engines": { - "node": ">=4.8" - } - }, - "node_modules/npm-run-all/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/npm-run-all/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/npm-run-all/node_modules/path-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/npm-run-all/node_modules/shebang-command": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", - "dev": true, - "license": "MIT", - "dependencies": { - "shebang-regex": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/npm-run-all/node_modules/shebang-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/npm-run-all/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/npm-run-all/node_modules/which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "which": "bin/which" - } - }, - "node_modules/object-inspect": { - "version": "1.13.4", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", - "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/object.assign": { - "version": "4.1.7", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz", - "integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.3", - "define-properties": "^1.2.1", - "es-object-atoms": "^1.0.0", - "has-symbols": "^1.1.0", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/optionator": { - "version": "0.9.4", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", - "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", - "dev": true, - "license": "MIT", - "dependencies": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.5" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/own-keys": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/own-keys/-/own-keys-1.0.1.tgz", - "integrity": "sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==", - "dev": true, - "license": "MIT", - "dependencies": { - "get-intrinsic": "^1.2.6", - "object-keys": "^1.1.1", - "safe-push-apply": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "license": "MIT", - "dependencies": { - "callsites": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/parse-json": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==", - "dev": true, - "license": "MIT", - "dependencies": { - "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true, "license": "MIT" }, - "node_modules/path-type": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", - "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", - "dev": true, - "license": "MIT", - "dependencies": { - "pify": "^3.0.0" - }, + "node_modules/lru-cache": { + "version": "11.2.2", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.2.tgz", + "integrity": "sha512-F9ODfyqML2coTIsQpSkRHnLSZMtkU8Q+mSfcaIyKwy58u+8k5nvAYeiNhsyMARvzNcXJ9QfWVrcPsC9e9rAxtg==", + "license": "ISC", "engines": { - "node": ">=4" + "node": "20 || >=22" } }, - "node_modules/picocolors": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", - "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", - "license": "ISC" + "node_modules/mdn-data": { + "version": "2.12.2", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.12.2.tgz", + "integrity": "sha512-IEn+pegP1aManZuckezWCO+XZQDplx1366JoVhTpMpBB1sPey/SbveZQUosKiKiGYjg1wH4pMlNgXbCiYgihQA==", + "license": "CC0-1.0" }, - "node_modules/pidtree": { + "node_modules/memorystream": { "version": "0.3.1", - "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.3.1.tgz", - "integrity": "sha512-qQbW94hLHEqCg7nhby4yRC7G2+jYHY4Rguc2bjw7Uug4GIJuu1tvf2uHaZv5Q8zdt+WKJ6qK1FOI6amaWUo5FA==", - "dev": true, - "license": "MIT", - "bin": { - "pidtree": "bin/pidtree.js" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==", + "resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz", + "integrity": "sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw==", "dev": true, - "license": "MIT", "engines": { - "node": ">=4" + "node": ">= 0.10.0" } }, - "node_modules/possible-typed-array-names": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", - "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==", + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/postcss": { - "version": "8.5.6", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", - "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "peer": true, + "license": "ISC", "dependencies": { - "nanoid": "^3.3.11", - "picocolors": "^1.1.1", - "source-map-js": "^1.2.1" + "brace-expansion": "^1.1.7" }, "engines": { - "node": "^10 || ^12 || >=14" - } - }, - "node_modules/prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8.0" + "node": "*" } }, - "node_modules/prettier": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.6.2.tgz", - "integrity": "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==", + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "dev": true, - "license": "MIT", - "bin": { - "prettier": "bin/prettier.cjs" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" - } + "license": "MIT" }, - "node_modules/prettier-linter-helpers": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", - "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "dev": true, - "license": "MIT", - "dependencies": { - "fast-diff": "^1.1.2" - }, - "engines": { - "node": ">=6.0.0" - } + "license": "MIT" }, - "node_modules/punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "node_modules/npm-normalize-package-bin": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-4.0.0.tgz", + "integrity": "sha512-TZKxPvItzai9kN9H/TkmCtx/ZN/hvr3vUycjlfmH0ootY9yFBzNOpiXAdIn1Iteqsvk4lQn6B5PTrt+n6h8k/w==", "dev": true, - "license": "MIT", + "license": "ISC", "engines": { - "node": ">=6" + "node": "^18.17.0 || >=20.5.0" } }, - "node_modules/read-pkg": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", - "integrity": "sha512-BLq/cCO9two+lBgiTYNqD6GdtK8s4NpaWrl6/rCO9w0TUS8oJl7cmToOZfRYllKTISY6nt1U7jQ53brmKqY6BA==", + "node_modules/npm-run-all2": { + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/npm-run-all2/-/npm-run-all2-8.0.4.tgz", + "integrity": "sha512-wdbB5My48XKp2ZfJUlhnLVihzeuA1hgBnqB2J9ahV77wLS+/YAJAlN8I+X3DIFIPZ3m5L7nplmlbhNiFDmXRDA==", "dev": true, "license": "MIT", "dependencies": { - "load-json-file": "^4.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^3.0.0" + "ansi-styles": "^6.2.1", + "cross-spawn": "^7.0.6", + "memorystream": "^0.3.1", + "picomatch": "^4.0.2", + "pidtree": "^0.6.0", + "read-package-json-fast": "^4.0.0", + "shell-quote": "^1.7.3", + "which": "^5.0.0" + }, + "bin": { + "npm-run-all": "bin/npm-run-all/index.js", + "npm-run-all2": "bin/npm-run-all/index.js", + "run-p": "bin/run-p/index.js", + "run-s": "bin/run-s/index.js" }, "engines": { - "node": ">=4" + "node": "^20.5.0 || >=22.0.0", + "npm": ">= 10" } }, - "node_modules/reflect.getprototypeof": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz", - "integrity": "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==", + "node_modules/npm-run-all2/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", "dev": true, "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.9", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.0.0", - "get-intrinsic": "^1.2.7", - "get-proto": "^1.0.1", - "which-builtin-type": "^1.2.1" - }, "engines": { - "node": ">= 0.4" + "node": ">=12" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/regexp.prototype.flags": { - "version": "1.5.4", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz", - "integrity": "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==", + "node_modules/npm-run-all2/node_modules/isexe": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", + "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "define-properties": "^1.2.1", - "es-errors": "^1.3.0", - "get-proto": "^1.0.1", - "gopd": "^1.2.0", - "set-function-name": "^2.0.2" - }, + "license": "ISC", "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=16" } }, - "node_modules/resolve": { - "version": "1.22.10", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", - "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==", + "node_modules/npm-run-all2/node_modules/which": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-5.0.0.tgz", + "integrity": "sha512-JEdGzHwwkrbWoGOlIHqQ5gtprKGOenpDHpxE9zVR1bWbOtYRyPPHMe9FaP6x61CmNaTThSkb0DAJte5jD+DmzQ==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "is-core-module": "^2.16.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" + "isexe": "^3.1.1" }, "bin": { - "resolve": "bin/resolve" + "node-which": "bin/which.js" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" + "node": "^18.17.0 || >=20.5.0" } }, - "node_modules/safe-array-concat": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.3.tgz", - "integrity": "sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==", + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.2", - "get-intrinsic": "^1.2.6", - "has-symbols": "^1.1.0", - "isarray": "^2.0.5" + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" }, "engines": { - "node": ">=0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">= 0.8.0" } }, - "node_modules/safe-push-apply": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/safe-push-apply/-/safe-push-apply-1.0.0.tgz", - "integrity": "sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==", + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", "dev": true, "license": "MIT", "dependencies": { - "es-errors": "^1.3.0", - "isarray": "^2.0.5" + "yocto-queue": "^0.1.0" }, "engines": { - "node": ">= 0.4" + "node": ">=10" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/safe-regex-test": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz", - "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==", + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", "dev": true, "license": "MIT", "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "is-regex": "^1.2.1" + "p-limit": "^3.0.2" }, "engines": { - "node": ">= 0.4" + "node": ">=10" }, "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/set-function-length": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", - "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", - "dev": true, - "license": "MIT", - "dependencies": { - "define-data-property": "^1.1.4", - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.4", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/set-function-name": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", - "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "define-data-property": "^1.1.4", - "es-errors": "^1.3.0", - "functions-have-names": "^1.2.3", - "has-property-descriptors": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/set-proto": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/set-proto/-/set-proto-1.0.0.tgz", - "integrity": "sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==", + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", "dev": true, "license": "MIT", "dependencies": { - "dunder-proto": "^1.0.1", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.0.0" + "callsites": "^3.0.0" }, "engines": { - "node": ">= 0.4" + "node": ">=6" } }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", "dev": true, "license": "MIT", - "dependencies": { - "shebang-regex": "^3.0.0" - }, "engines": { "node": ">=8" } }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", "dev": true, "license": "MIT", "engines": { "node": ">=8" } }, - "node_modules/shell-quote": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.2.tgz", - "integrity": "sha512-AzqKpGKjrj7EM6rKVQEPpB288oCfnrEIuyoT9cyF4nmGa7V8Zk6f7RRqYisX8X9m+Q7bd632aZW4ky7EhbQztA==", + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true, + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", "engines": { - "node": ">= 0.4" + "node": ">=12" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/side-channel": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", - "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "node_modules/pidtree": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.6.0.tgz", + "integrity": "sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==", "dev": true, "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "object-inspect": "^1.13.3", - "side-channel-list": "^1.0.0", - "side-channel-map": "^1.0.1", - "side-channel-weakmap": "^1.0.2" + "bin": { + "pidtree": "bin/pidtree.js" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=0.10" } }, - "node_modules/side-channel-list": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", - "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", "dev": true, "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "object-inspect": "^1.13.3" - }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">= 0.8.0" } }, - "node_modules/side-channel-map": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", - "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "node_modules/prettier": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.6.2.tgz", + "integrity": "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==", "dev": true, "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.5", - "object-inspect": "^1.13.3" + "peer": true, + "bin": { + "prettier": "bin/prettier.cjs" }, "engines": { - "node": ">= 0.4" + "node": ">=14" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/prettier/prettier?sponsor=1" } }, - "node_modules/side-channel-weakmap": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", - "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "node_modules/prettier-linter-helpers": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", + "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", "dev": true, "license": "MIT", "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.5", - "object-inspect": "^1.13.3", - "side-channel-map": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" + "fast-diff": "^1.1.2" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/source-map-js": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", - "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", - "license": "BSD-3-Clause", "engines": { - "node": ">=0.10.0" + "node": ">=6.0.0" } }, - "node_modules/spdx-correct": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", - "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", "dev": true, - "license": "Apache-2.0", - "dependencies": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" + "license": "MIT", + "engines": { + "node": ">=6" } }, - "node_modules/spdx-exceptions": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", - "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", - "dev": true, - "license": "CC-BY-3.0" - }, - "node_modules/spdx-expression-parse": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", - "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "node_modules/read-package-json-fast": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/read-package-json-fast/-/read-package-json-fast-4.0.0.tgz", + "integrity": "sha512-qpt8EwugBWDw2cgE2W+/3oxC+KTez2uSVR8JU9Q36TXPAGCaozfQUs59v4j4GFpWTaw0i6hAZSvOmu1J0uOEUg==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" + "json-parse-even-better-errors": "^4.0.0", + "npm-normalize-package-bin": "^4.0.0" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" } }, - "node_modules/spdx-license-ids": { - "version": "3.0.21", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.21.tgz", - "integrity": "sha512-Bvg/8F5XephndSK3JffaRqdT+gyhfqIPwDHpX80tJrF8QQRYMo8sNMeaZ2Dp5+jhwKnUmIOyFFQfHRkjJm5nXg==", - "dev": true, - "license": "CC0-1.0" - }, - "node_modules/string.prototype.padend": { - "version": "3.1.6", - "resolved": "https://registry.npmjs.org/string.prototype.padend/-/string.prototype.padend-3.1.6.tgz", - "integrity": "sha512-XZpspuSB7vJWhvJc9DLSlrXl1mcA2BdoY5jjnS135ydXqLoqhs96JjDtCkjJEQHvfqZIp9hBuBMgI589peyx9Q==", + "node_modules/resolve": { + "version": "1.22.11", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", + "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==", "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.2", - "es-object-atoms": "^1.0.0" + "is-core-module": "^2.16.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" }, "engines": { "node": ">= 0.4" @@ -3240,58 +1685,45 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/string.prototype.trim": { - "version": "1.2.10", - "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.10.tgz", - "integrity": "sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==", + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "dev": true, "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.2", - "define-data-property": "^1.1.4", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.5", - "es-object-atoms": "^1.0.0", - "has-property-descriptors": "^1.0.2" - }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=4" } }, - "node_modules/string.prototype.trimend": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.9.tgz", - "integrity": "sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==", + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.2", - "define-properties": "^1.2.1", - "es-object-atoms": "^1.0.0" + "shebang-regex": "^3.0.0" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" } }, - "node_modules/string.prototype.trimstart": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", - "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", + "node_modules/shell-quote": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.3.tgz", + "integrity": "sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==", "dev": true, "license": "MIT", - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-object-atoms": "^1.0.0" - }, "engines": { "node": ">= 0.4" }, @@ -3299,14 +1731,13 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", - "dev": true, - "license": "MIT", + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "license": "BSD-3-Clause", "engines": { - "node": ">=4" + "node": ">=0.10.0" } }, "node_modules/strip-json-comments": { @@ -3377,103 +1808,6 @@ "node": ">= 0.8.0" } }, - "node_modules/typed-array-buffer": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz", - "integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "es-errors": "^1.3.0", - "is-typed-array": "^1.1.14" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/typed-array-byte-length": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.3.tgz", - "integrity": "sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "for-each": "^0.3.3", - "gopd": "^1.2.0", - "has-proto": "^1.2.0", - "is-typed-array": "^1.1.14" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/typed-array-byte-offset": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.4.tgz", - "integrity": "sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.8", - "for-each": "^0.3.3", - "gopd": "^1.2.0", - "has-proto": "^1.2.0", - "is-typed-array": "^1.1.15", - "reflect.getprototypeof": "^1.0.9" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/typed-array-length": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.7.tgz", - "integrity": "sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.7", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "is-typed-array": "^1.1.13", - "possible-typed-array-names": "^1.0.0", - "reflect.getprototypeof": "^1.0.6" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/unbox-primitive": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz", - "integrity": "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "has-bigints": "^1.0.2", - "has-symbols": "^1.1.0", - "which-boxed-primitive": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/uri-js": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", @@ -3484,17 +1818,6 @@ "punycode": "^2.1.0" } }, - "node_modules/validate-npm-package-license": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", - "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" - } - }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -3511,95 +1834,6 @@ "node": ">= 8" } }, - "node_modules/which-boxed-primitive": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.1.1.tgz", - "integrity": "sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-bigint": "^1.1.0", - "is-boolean-object": "^1.2.1", - "is-number-object": "^1.1.1", - "is-string": "^1.1.1", - "is-symbol": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/which-builtin-type": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.2.1.tgz", - "integrity": "sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "function.prototype.name": "^1.1.6", - "has-tostringtag": "^1.0.2", - "is-async-function": "^2.0.0", - "is-date-object": "^1.1.0", - "is-finalizationregistry": "^1.1.0", - "is-generator-function": "^1.0.10", - "is-regex": "^1.2.1", - "is-weakref": "^1.0.2", - "isarray": "^2.0.5", - "which-boxed-primitive": "^1.1.0", - "which-collection": "^1.0.2", - "which-typed-array": "^1.1.16" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/which-collection": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz", - "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-map": "^2.0.3", - "is-set": "^2.0.3", - "is-weakmap": "^2.0.2", - "is-weakset": "^2.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/which-typed-array": { - "version": "1.1.19", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.19.tgz", - "integrity": "sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==", - "dev": true, - "license": "MIT", - "dependencies": { - "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.8", - "call-bound": "^1.0.4", - "for-each": "^0.3.5", - "get-proto": "^1.0.1", - "gopd": "^1.2.0", - "has-tostringtag": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/word-wrap": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", diff --git a/package.json b/package.json index e9150c88..6671eebe 100644 --- a/package.json +++ b/package.json @@ -35,37 +35,39 @@ "files": [ "lib/" ], - "main": "./lib/CSSStyleDeclaration.js", + "main": "./lib/index.js", "dependencies": { - "@asamuzakjp/css-color": "^4.0.3", - "@csstools/css-syntax-patches-for-csstree": "^1.0.14", - "css-tree": "^3.1.0" + "@asamuzakjp/css-color": "^4.0.5", + "@csstools/css-syntax-patches-for-csstree": "^1.0.16", + "css-tree": "^3.1.0", + "lru-cache": "^11.2.2" }, "devDependencies": { - "@babel/generator": "^7.28.0", - "@babel/parser": "^7.28.0", - "@babel/traverse": "^7.28.0", - "@babel/types": "^7.28.2", + "@babel/generator": "^7.28.5", + "@babel/parser": "^7.28.5", + "@babel/traverse": "^7.28.5", + "@babel/types": "^7.28.5", "@domenic/eslint-config": "^4.0.1", - "@webref/css": "^6.23.6", - "eslint": "^9.32.0", + "@webref/css": "^8.0.1", + "eslint": "^9.39.1", "eslint-config-prettier": "^10.1.8", - "eslint-plugin-prettier": "^5.5.3", - "globals": "^16.3.0", - "npm-run-all": "^4.1.5", + "eslint-plugin-prettier": "^5.5.4", + "globals": "^16.5.0", + "npm-run-all2": "^8.0.4", "prettier": "^3.6.2", - "resolve": "^1.22.10" + "resolve": "^1.22.11" }, "scripts": { - "download": "node ./scripts/downloadLatestProperties.mjs", + "download": "node ./scripts/downloadLatestProperties.mjs && npm run generate", "generate": "run-p generate:*", - "generate:implemented_properties": "node ./scripts/generateImplementedProperties.mjs", "generate:properties": "node ./scripts/generateProperties.js", + "generate:propertyDefinitions": "node ./scripts/generatePropertyDefinitions.mjs", "lint": "npm run generate && eslint --max-warnings 0", "lint:fix": "eslint --fix --max-warnings 0", - "prepublishOnly": "npm run lint && npm run test", - "test": "npm run generate && node --test", - "test-ci": "npm run lint && npm run test" + "prepublishOnly": "npm run test-ci", + "test": "npm run generate && npm run test:unit", + "test:unit": "node --test", + "test-ci": "npm run lint && npm run test:unit" }, "license": "MIT", "engines": { diff --git a/lib/utils/camelize.js b/scripts/camelize.js similarity index 94% rename from lib/utils/camelize.js rename to scripts/camelize.js index 19aaf7de..7f3fcefe 100644 --- a/lib/utils/camelize.js +++ b/scripts/camelize.js @@ -1,6 +1,6 @@ "use strict"; -const { asciiLowercase } = require("./strings"); +const { asciiLowercase } = require("../lib/utils/strings"); // Utility to translate from `border-width` to `borderWidth`. // NOTE: For values prefixed with webkit, e.g. `-webkit-foo`, we need to provide diff --git a/scripts/downloadLatestProperties.mjs b/scripts/downloadLatestProperties.mjs index 28fa2edf..ad3beae3 100644 --- a/scripts/downloadLatestProperties.mjs +++ b/scripts/downloadLatestProperties.mjs @@ -6,11 +6,8 @@ import fs from "node:fs"; import path from "node:path"; -import { fileURLToPath } from "node:url"; const url = "https://www.w3.org/Style/CSS/all-properties.en.json"; -const outputFile = resolve("../lib/generated/allProperties.js"); -const unwantedStatuses = new Set(["NOTE", "ED"]); console.log("Downloading CSS properties..."); @@ -22,17 +19,17 @@ if (res.status !== 200) { const rawCSSProperties = await res.json(); const propertyNames = new Set(); +const unwantedStatuses = new Set(["NOTE", "ED"]); for (const cssProp of rawCSSProperties) { // Filter out properties from too-new statuses. // Also, '--*' needs additional logic to this module, so filter it out for now. if (unwantedStatuses.has(cssProp.status) || cssProp.property === "--*") { continue; } - propertyNames.add(cssProp.property); } -const propertyNamesJSON = JSON.stringify(Array.from(propertyNames), undefined, 2); +const propertyNamesJSON = JSON.stringify([...propertyNames], undefined, 2); const dateToday = new Date(); const [dateTodayFormatted] = dateToday.toISOString().split("T"); const output = `"use strict"; @@ -42,9 +39,6 @@ const output = `"use strict"; module.exports = new Set(${propertyNamesJSON}); `; +const { dirname } = import.meta; +const outputFile = path.resolve(dirname, "../lib/generated/allProperties.js"); fs.writeFileSync(outputFile, output); - -// TODO: remove when we can drop Node.js 18 support and use import.meta.dirname. -function resolve(relativePath) { - return path.resolve(path.dirname(fileURLToPath(import.meta.url)), relativePath); -} diff --git a/scripts/generateImplementedProperties.mjs b/scripts/generateImplementedProperties.mjs deleted file mode 100644 index efa807a0..00000000 --- a/scripts/generateImplementedProperties.mjs +++ /dev/null @@ -1,42 +0,0 @@ -import fs from "node:fs"; -import path from "node:path"; -import css from "@webref/css"; -import { camelCaseToDashed } from "../lib/utils/camelize.js"; - -const parsedFiles = await css.listAll(); -const definitions = new Map(); -for (const { properties } of Object.values(parsedFiles)) { - if (Array.isArray(properties)) { - for (const definition of properties) { - const { name } = definition; - if (name) { - definitions.set(name, definition); - } - } - } -} - -const { dirname } = import.meta; -const dashedProperties = fs - .readdirSync(path.resolve(dirname, "../lib/properties")) - .filter((propertyFile) => path.extname(propertyFile) === ".js") - .map((propertyFile) => camelCaseToDashed(path.basename(propertyFile, ".js"))) - .toSorted(); - -const implementedProperties = new Map(); -for (const property of dashedProperties) { - const definition = definitions.get(property); - implementedProperties.set(property, definition); -} - -const outputFile = path.resolve(dirname, "../lib/generated/implementedProperties.js"); - -const dateToday = new Date(); -const [dateTodayFormatted] = dateToday.toISOString().split("T"); -const output = `"use strict"; -// autogenerated - ${dateTodayFormatted} - -module.exports = new Map(${JSON.stringify([...implementedProperties], null, 2)}); -`; - -fs.writeFileSync(outputFile, output); diff --git a/scripts/generateProperties.js b/scripts/generateProperties.js index 61aec085..30372f2d 100644 --- a/scripts/generateProperties.js +++ b/scripts/generateProperties.js @@ -7,7 +7,7 @@ const t = require("@babel/types"); const generate = require("@babel/generator").default; const traverse = require("@babel/traverse").default; const resolve = require("resolve"); -const { camelCaseToDashed } = require("../lib/utils/camelize"); +const { camelCaseToDashed } = require("./camelize"); const { basename, dirname } = nodePath; diff --git a/scripts/generatePropertyDefinitions.mjs b/scripts/generatePropertyDefinitions.mjs new file mode 100644 index 00000000..40c7cefc --- /dev/null +++ b/scripts/generatePropertyDefinitions.mjs @@ -0,0 +1,47 @@ +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 unifiedProperties = + typeof allProperties.union === "function" + ? allProperties.union(allExtraProperties) + : new Set([...allProperties, ...allExtraProperties]); + +const { properties } = await css.listAll(); +const definitions = new Map(); +if (Array.isArray(properties)) { + for (const definition of properties) { + const { href, initial, inherited, computedValue, legacyAliasOf, name, styleDeclaration } = + definition; + if (unifiedProperties.has(name)) { + definitions.set(name, { + href, + initial, + inherited, + computedValue, + legacyAliasOf, + name, + styleDeclaration + }); + } + } +} + +const propertyDefinitions = new Map(); +for (const property of [...unifiedProperties].toSorted()) { + const definition = definitions.get(property); + if (definition) { + propertyDefinitions.set(property, definition); + } +} +const [dateTodayFormatted] = new Date().toISOString().split("T"); +const output = `"use strict"; +// autogenerated - ${dateTodayFormatted} + +module.exports = new Map(${JSON.stringify([...propertyDefinitions], null, 2)}); +`; +const { dirname } = import.meta; +const outputFile = path.resolve(dirname, "../lib/generated/propertyDefinitions.js"); +fs.writeFileSync(outputFile, output); diff --git a/test/CSSStyleDeclaration.test.js b/test/CSSStyleDeclaration.test.js index 91ab46e3..87109384 100644 --- a/test/CSSStyleDeclaration.test.js +++ b/test/CSSStyleDeclaration.test.js @@ -2,50 +2,133 @@ const { describe, it } = require("node:test"); const assert = require("node:assert/strict"); -const { CSSStyleDeclaration, propertyList } = require("../lib/CSSStyleDeclaration"); -const allProperties = require("../lib/generated/allProperties"); -const implementedProperties = require("../lib/generated/implementedProperties"); -const allExtraProperties = require("../lib/utils/allExtraProperties"); -const camelize = require("../lib/utils/camelize"); +const { CSSStyleDeclaration } = require("../lib/CSSStyleDeclaration"); +const propertyDefinitions = require("../lib/generated/propertyDefinitions"); +const camelize = require("../scripts/camelize"); + +const window = { + getComputedStyle: () => {}, + DOMException: globalThis.DOMException, + TypeError: globalThis.TypeError +}; + +function testPropertyValue(property, value, expected) { + const style = new CSSStyleDeclaration(window); + let res; + + style.setProperty(property, value); + res = style.getPropertyValue(property); + assert.strictEqual(res, expected, `setProperty("${property}", '${value}')`); + + style.setProperty(property, undefined); + res = style.getPropertyValue(property); + assert.strictEqual(res, expected, `setProperty("${property}", undefined)`); + + style.setProperty(property, null); + res = style.getPropertyValue(property); + assert.strictEqual(res, "", `setProperty("${property}", null)`); + + style[property] = value; + res = style[property]; + assert.strictEqual(res, expected, `set["${property}"] = '${value}'`); + + style[property] = undefined; + res = style[property]; + assert.strictEqual(res, expected, `set["${property}"] = undefined`); + + style[property] = null; + res = style[property]; + assert.strictEqual(res, "", `set["${property}"] = null`); +} + +function testImplicitPropertyValue(property, value, expected, sub) { + const style = new CSSStyleDeclaration(); + let res; + + style.setProperty(property, value); + res = style.getPropertyValue(property); + assert.strictEqual(res, expected, `setProperty("${property}", '${value}')`); + for (const [key, subExpected] of sub) { + res = style.getPropertyValue(key); + assert.strictEqual( + res, + subExpected, + `setProperty("${property}", '${value}') implicitly changes the value of ${key}` + ); + } -describe("CSSStyleDeclaration", () => { - const dashedProperties = [...allProperties, ...allExtraProperties]; - const allowedProperties = dashedProperties.map(camelize.dashedToCamelCase); - const invalidProperties = [...implementedProperties.keys()] - .map(camelize.dashedToCamelCase) - .filter((prop) => !allowedProperties.includes(prop)); + style.setProperty(property, undefined); + res = style.getPropertyValue(property); + assert.strictEqual(res, expected, `setProperty("${property}", undefined)`); + for (const [key, subExpected] of sub) { + res = style.getPropertyValue(key); + assert.strictEqual( + res, + subExpected, + `setProperty("${property}", undefined) does not change the value of ${key}` + ); + } - it("has only valid properties implemented", () => { - assert.strictEqual(invalidProperties.length, 0); - }); + style.setProperty(property, null); + res = style.getPropertyValue(property); + assert.strictEqual(res, "", `setProperty("${property}", null)`); + for (const [key] of sub) { + res = style.getPropertyValue(key); + assert.strictEqual( + res, + "", + `setProperty("${property}", null) implicitly changes the value of ${key}` + ); + } - it("does not enumerate constructor or internals", () => { - const style = new CSSStyleDeclaration(); - assert.strictEqual(Object.getOwnPropertyDescriptor(style, "constructor").enumerable, false); - for (const i in style) { - assert.strictEqual(i.startsWith("_"), false); - } - }); + for (const key of sub.keys()) { + style.setProperty(property, value); + style.setProperty(key, "var(--foo)"); + res = style.getPropertyValue(property); + assert.strictEqual( + res, + "", + `setProperty("${key}", "var(--foo)") implicitly changes the value of ${property}` + ); + style.setProperty(property, null); + } - it("has all properties", () => { - const style = new CSSStyleDeclaration(); - allProperties.forEach((property) => { - assert.ok(style.__lookupGetter__(property)); - assert.ok(style.__lookupSetter__(property)); - }); - }); + style[property] = value; + res = style[property]; + assert.strictEqual(res, expected, `set["${property}"] = '${value}'`); + for (const [key, subExpected] of sub) { + res = style.getPropertyValue(key); + assert.strictEqual( + res, + subExpected, + `set["${property}"] = '${value}' implicitly changes the value of ${key}` + ); + } - it("has dashed properties", () => { - const style = new CSSStyleDeclaration(); - dashedProperties.forEach((property) => { - assert.ok(style.__lookupGetter__(property)); - assert.ok(style.__lookupSetter__(property)); - }); - }); + style[property] = undefined; + res = style[property]; + assert.strictEqual(res, expected, `set["${property}"] = undefined`); + for (const [key, subExpected] of sub) { + res = style.getPropertyValue(key); + assert.strictEqual( + res, + subExpected, + `set["${property}"] = undefined does not change the value of ${key}` + ); + } - it("has all functions", () => { - const style = new CSSStyleDeclaration(); + style[property] = null; + res = style[property]; + assert.strictEqual(res, "", `set["${property}"] = null`); + for (const [key] of sub) { + res = style.getPropertyValue(key); + assert.strictEqual(res, "", `set["${property}"] = null implicitly changes the value of ${key}`); + } +} +describe("CSSStyleDeclaration", () => { + it("has methods", () => { + const style = new CSSStyleDeclaration(window); assert.strictEqual(typeof style.item, "function"); assert.strictEqual(typeof style.getPropertyValue, "function"); assert.strictEqual(typeof style.setProperty, "function"); @@ -53,149 +136,330 @@ describe("CSSStyleDeclaration", () => { assert.strictEqual(typeof style.removeProperty, "function"); }); - it("has PascalCase for webkit prefixed properties", () => { - const style = new CSSStyleDeclaration(); - for (const i in style) { - if (/^webkit[A-Z]/.test(i)) { - const pascal = i.replace(/^webkit/, "Webkit"); - assert.ok(style[pascal] !== undefined); + it("has attributes", () => { + const style = new CSSStyleDeclaration(window); + assert.ok(style.__lookupGetter__("cssText")); + assert.ok(style.__lookupSetter__("cssText")); + assert.ok(style.__lookupGetter__("length")); + assert.ok(style.__lookupSetter__("length")); + assert.ok(style.__lookupGetter__("parentRule")); + }); + + it("sets internals for Element", () => { + const node = { + nodeType: 1, + style: {}, + ownerDocument: { + defaultView: window } - } + }; + let callCount = 0; + const callback = () => { + callCount++; + }; + const style = new CSSStyleDeclaration(window, { + context: node, + onChange: callback + }); + style.cssText = "color: green;"; + assert.strictEqual(callCount, 1); + }); + + it("sets internals for CSSRule", () => { + const rule = { + parentRule: {}, + parentStyleSheet: { + ownerDocument: { + defaultView: { + DOMException: window.DOMException + } + } + } + }; + const style = new CSSStyleDeclaration(window, { + context: rule + }); + assert.deepEqual(style.parentRule, rule); + }); + + it("has format in internal options", () => { + const style = new CSSStyleDeclaration(window, { + foo: "bar" + }); + assert.deepEqual(style._options, { + format: "specifiedValue" + }); + }); + + it("should not override format if exists", () => { + const style = new CSSStyleDeclaration(window, { + format: "computedValue" + }); + assert.deepEqual(style._options, { + format: "computedValue" + }); + }); + + it("getting cssText returns empty string if computed flag is set", () => { + const style = new CSSStyleDeclaration(window, { + format: "computedValue" + }); + style.cssText = "color: red;"; + assert.strictEqual(style.cssText, ""); }); - it("throws if argument is not given", () => { - const style = new CSSStyleDeclaration(); + it("setting improper css to cssText should not throw", () => { + const style = new CSSStyleDeclaration(window); + style.cssText = "color: "; + assert.strictEqual(style.cssText, ""); + style.cssText = "color: red!"; + assert.strictEqual(style.cssText, ""); + }); + it("item() throws if argument is not given", () => { + const style = new CSSStyleDeclaration(window); assert.throws( () => { style.item(); }, (e) => { - assert.strictEqual(e instanceof globalThis.TypeError, true); + assert.strictEqual(e instanceof window.TypeError, true); assert.strictEqual(e.message, "1 argument required, but only 0 present."); return true; } ); }); - it("has special properties", () => { - const style = new CSSStyleDeclaration(); + it("camelcase properties are not assigned with setproperty()", () => { + const style = new CSSStyleDeclaration(window); + style.setProperty("fontSize", "12px"); + assert.strictEqual(style.cssText, ""); + }); - assert.ok(style.__lookupGetter__("cssText")); - assert.ok(style.__lookupSetter__("cssText")); - assert.ok(style.__lookupGetter__("length")); - assert.ok(style.__lookupSetter__("length")); - assert.ok(style.__lookupGetter__("parentRule")); + it("custom properties are case-sensitive", () => { + const style = new CSSStyleDeclaration(window); + style.cssText = "--fOo: purple"; + assert.strictEqual(style.getPropertyValue("--foo"), ""); + assert.strictEqual(style.getPropertyValue("--fOo"), "purple"); }); - it("sets internals for Window", () => { - const window = { - getComputedStyle: () => {}, - DOMException: globalThis.DOMException - }; - const style = new CSSStyleDeclaration(null, { - context: window - }); + it("getPropertyValue for custom properties in cssText", () => { + const style = new CSSStyleDeclaration(window); + style.cssText = "--foo: red"; + assert.strictEqual(style.getPropertyValue("--foo"), "red"); + }); - assert.strictEqual(style.cssText, ""); - assert.throws( - () => { - style.cssText = "color: green;"; - }, - (e) => { - assert.strictEqual(e instanceof window.DOMException, true); - assert.strictEqual(e.name, "NoModificationAllowedError"); - assert.strictEqual(e.message, "cssText can not be modified."); - return true; + it("getPropertyValue for custom properties with setProperty", () => { + const style = new CSSStyleDeclaration(window); + style.setProperty("--bar", "blue"); + assert.strictEqual(style.getPropertyValue("--bar"), "blue"); + }); + + it("getPropertyValue for custom properties with object setter", () => { + const style = new CSSStyleDeclaration(window); + style["--baz"] = "yellow"; + assert.strictEqual(style.getPropertyValue("--baz"), ""); + }); + + it("getPropertyPriority for property", () => { + const style = new CSSStyleDeclaration(window); + style.setProperty("color", "green", "important"); + assert.strictEqual(style.getPropertyPriority("color"), "important"); + }); + + it("getPropertyPriority for custom property", () => { + const style = new CSSStyleDeclaration(window); + style.setProperty("--foo", "green", "important"); + assert.strictEqual(style.getPropertyPriority("--foo"), "important"); + }); +}); + +describe("properties", () => { + it("is instanceof CSSStyleDeclaration", () => { + const style = new CSSStyleDeclaration(window); + assert.strictEqual(style instanceof CSSStyleDeclaration, true); + }); + + it("all dashed properties are included in propertyDefinitions", () => { + const style = new CSSStyleDeclaration(window); + for (const i in style) { + if (/^[a-z]+(?:-[a-z]+)*$/.test(i)) { + assert.strictEqual(propertyDefinitions.has(i), true, i); } - ); - assert.throws( - () => { - style.removeProperty("color"); - }, - (e) => { - assert.strictEqual(e instanceof window.DOMException, true); - assert.strictEqual(e.name, "NoModificationAllowedError"); - assert.strictEqual(e.message, "Property color can not be modified."); - return true; + } + }); + + it("has camelCased property for dashed property", () => { + const style = new CSSStyleDeclaration(window); + for (const i in style) { + if (/^[a-z]+(?:-[a-z]+)*$/.test(i)) { + const camel = camelize.dashedToCamelCase(i); + assert.ok(style[camel] !== undefined, i); + } + } + }); + + // FIXME: https://github.com/jsdom/cssstyle/issues/210 + it.skip("all webkit prefixed properties are included in propertyDefinitions", () => { + const style = new CSSStyleDeclaration(window); + for (const i in style) { + if (/^-webkit-[a-z]+(?:-[a-z]+)*$/.test(i)) { + assert.strictEqual(propertyDefinitions.has(i), true, i); + } + } + }); + + it("has camelCased property for webkit prefixed property", () => { + const style = new CSSStyleDeclaration(window); + for (const i in style) { + if (/^-webkit-[a-z]+(?:-[a-z]+)*$/.test(i)) { + const camel = camelize.dashedToCamelCase(i); + assert.ok(style[camel] !== undefined, i); + } + } + }); + + it("has PascalCased property for webkit prefixed property", () => { + const style = new CSSStyleDeclaration(window); + for (const i in style) { + if (/^webkit[A-Z]/.test(i)) { + const pascal = i.replace(/^webkit/, "Webkit"); + assert.ok(style[pascal] !== undefined); } + } + }); + + it("from style string", () => { + const style = new CSSStyleDeclaration(window); + style.cssText = "color: blue; background-color: red; width: 78%; height: 50vh;"; + assert.strictEqual(style.length, 4); + assert.strictEqual( + style.cssText, + "color: blue; background-color: red; width: 78%; height: 50vh;" ); + assert.strictEqual(style.getPropertyValue("color"), "blue"); + assert.strictEqual(style.item(0), "color"); + assert.strictEqual(style[1], "background-color"); + assert.strictEqual(style.backgroundColor, "red"); + style.cssText = ""; + assert.strictEqual(style.cssText, ""); + assert.strictEqual(style.length, 0); }); - it("sets internals for Element", () => { + it("from properties", () => { + const style = new CSSStyleDeclaration(window); + style.color = "blue"; + assert.strictEqual(style.length, 1); + assert.strictEqual(style[0], "color"); + assert.strictEqual(style.cssText, "color: blue;"); + assert.strictEqual(style.item(0), "color"); + assert.strictEqual(style.color, "blue"); + style.backgroundColor = "red"; + assert.strictEqual(style.length, 2); + assert.strictEqual(style[0], "color"); + assert.strictEqual(style[1], "background-color"); + assert.strictEqual(style.cssText, "color: blue; background-color: red;"); + assert.strictEqual(style.backgroundColor, "red"); + style.removeProperty("color"); + assert.strictEqual(style[0], "background-color"); + }); + + it("ignores invalid properties", () => { const node = { nodeType: 1, style: {}, ownerDocument: { - defaultView: { - DOMException: globalThis.DOMException - } + defaultView: window } }; - const style = new CSSStyleDeclaration(null, { + const style = new CSSStyleDeclaration(window, { context: node }); - style.cssText = "color: green"; - assert.strictEqual(style.cssText, "color: green;"); + style.cssText = "color: green; color: invalid!; background: blue;"; + // ignores invalid properties + assert.strictEqual(style.cssText, "color: green; background: blue;"); }); - it("sets empty string for invalid cssText", () => { + it("keeps the last one of the same property", () => { const node = { nodeType: 1, style: {}, ownerDocument: { - defaultView: { - DOMException: globalThis.DOMException - } + defaultView: window } }; - const style = new CSSStyleDeclaration(null, { + const style = new CSSStyleDeclaration(window, { context: node }); - style.cssText = "color: green!"; - assert.strictEqual(style.cssText, ""); + // only valid properties + style.cssText = "color: olivedrab; color: peru; background: bisque;"; + // keeps the last one of the same property + assert.strictEqual(style.cssText, "color: peru; background: bisque;"); }); - it("sets only the valid properties for partially valid cssText", () => { + it("ignores the nested selector rule", () => { const node = { nodeType: 1, style: {}, ownerDocument: { - defaultView: { - DOMException: globalThis.DOMException - } + defaultView: window } }; - const style = new CSSStyleDeclaration(null, { + const style = new CSSStyleDeclaration(window, { context: node }); - - // valid property followed by invalid property followed by valid property - style.cssText = "color: green; color: invalid!; background: blue;"; - // ignores invalid properties - assert.strictEqual(style.cssText, "color: green; background: blue;"); - - // only valid properties - style.cssText = "color: olivedrab; color: peru; background: bisque;"; - // keeps the last one of the same property - assert.strictEqual(style.cssText, "color: peru; background: bisque;"); - // valid property followed by a nested selector rule style.cssText = "color: olivedrab; &.d { color: peru; }"; // ignores the nested selector rule assert.strictEqual(style.cssText, "color: olivedrab;"); + }); + it("ignores the property immediately after the nested rule", () => { + const node = { + nodeType: 1, + style: {}, + ownerDocument: { + defaultView: window + } + }; + const style = new CSSStyleDeclaration(window, { + context: node + }); // valid property followed by a nested selector rule followed by two valid properties and an invalid property style.cssText = "color: olivedrab; &.d { color: peru; } color: green; background: red; invalid: rule;"; // ignores the property immediately after the nested rule assert.strictEqual(style.cssText, "color: olivedrab; background: red;"); + }); + it("includes the the property immediately after an at-rule", () => { + const node = { + nodeType: 1, + style: {}, + ownerDocument: { + defaultView: window + } + }; + const style = new CSSStyleDeclaration(window, { + context: node + }); // valid property followed by a at-rule followed by a valid property style.cssText = "color: blue; @media screen { color: red; } color: orange;"; // includes the the property immediately after an at-rule assert.strictEqual(style.cssText, "color: orange;"); + }); + it("ignores the first property found after the nested selector rule along with the at-rules", () => { + const node = { + nodeType: 1, + style: {}, + ownerDocument: { + defaultView: window + } + }; + const style = new CSSStyleDeclaration(window, { + context: node + }); // valid property followed by a nested rule, two at-rules and two valid properties style.cssText = ` color: blue; @@ -208,96 +472,26 @@ describe("CSSStyleDeclaration", () => { assert.strictEqual(style.cssText, "color: blue; background: orange;"); }); - it("sets internals for Element", () => { - const node = { - nodeType: 1, - style: {}, - ownerDocument: { - defaultView: { - DOMException: globalThis.DOMException - } - } - }; - const style = new CSSStyleDeclaration(null, { - context: node - }); - style.cssText = "color: light-dark(#008000, #0000ff)"; - assert.strictEqual(style.cssText, "color: light-dark(rgb(0, 128, 0), rgb(0, 0, 255));"); - }); - - it("sets internals for CSSRule", () => { - const rule = { - parentRule: {}, - parentStyleSheet: { - ownerDocument: { - defaultView: { - DOMException: globalThis.DOMException - } - } - } - }; - const style = new CSSStyleDeclaration(null, { - context: rule - }); - style.cssText = "color: green"; - assert.strictEqual(style.cssText, ""); - }); - - it("from style string", () => { - const style = new CSSStyleDeclaration(); - style.cssText = "color: blue; background-color: red; width: 78%; height: 50vh;"; - assert.strictEqual(style.length, 4); - assert.strictEqual( - style.cssText, - "color: blue; background-color: red; width: 78%; height: 50vh;" - ); - assert.strictEqual(style.getPropertyValue("color"), "blue"); - assert.strictEqual(style.item(0), "color"); - assert.strictEqual(style[1], "background-color"); - assert.strictEqual(style.backgroundColor, "red"); - style.cssText = ""; - assert.strictEqual(style.cssText, ""); - assert.strictEqual(style.length, 0); - }); - - it("from properties", () => { - const style = new CSSStyleDeclaration(); - style.color = "blue"; - assert.strictEqual(style.length, 1); - assert.strictEqual(style[0], "color"); - assert.strictEqual(style.cssText, "color: blue;"); - assert.strictEqual(style.item(0), "color"); - assert.strictEqual(style.color, "blue"); - style.backgroundColor = "red"; - assert.strictEqual(style.length, 2); - assert.strictEqual(style[0], "color"); - assert.strictEqual(style[1], "background-color"); - assert.strictEqual(style.cssText, "color: blue; background-color: red;"); - assert.strictEqual(style.backgroundColor, "red"); - style.removeProperty("color"); - assert.strictEqual(style[0], "background-color"); - }); - - it("shorthand properties", () => { - const style = new CSSStyleDeclaration(); - style.background = "blue url(http://www.example.com/some_img.jpg)"; - assert.strictEqual(style.backgroundColor, "blue"); - assert.strictEqual(style.backgroundImage, 'url("http://www.example.com/some_img.jpg")'); - assert.strictEqual(style.background, 'url("http://www.example.com/some_img.jpg") blue'); - style.border = "0 solid black"; - assert.strictEqual(style.borderWidth, "0px"); - assert.strictEqual(style.borderStyle, "solid"); - assert.strictEqual(style.borderColor, "black"); - assert.strictEqual(style.borderTopWidth, "0px"); - assert.strictEqual(style.borderLeftStyle, "solid"); - assert.strictEqual(style.borderBottomColor, "black"); - style.font = "12em monospace"; - assert.strictEqual(style.fontSize, "12em"); - assert.strictEqual(style.fontFamily, "monospace"); + it("shorthand properties", () => { + const style = new CSSStyleDeclaration(window); + style.background = "blue url(http://www.example.com/some_img.jpg)"; + assert.strictEqual(style.backgroundColor, "blue"); + assert.strictEqual(style.backgroundImage, 'url("http://www.example.com/some_img.jpg")'); + assert.strictEqual(style.background, 'url("http://www.example.com/some_img.jpg") blue'); + style.border = "0 solid black"; + assert.strictEqual(style.borderWidth, "0px"); + assert.strictEqual(style.borderStyle, "solid"); + assert.strictEqual(style.borderColor, "black"); + assert.strictEqual(style.borderTopWidth, "0px"); + assert.strictEqual(style.borderLeftStyle, "solid"); + assert.strictEqual(style.borderBottomColor, "black"); + style.font = "12em monospace"; + assert.strictEqual(style.fontSize, "12em"); + assert.strictEqual(style.fontFamily, "monospace"); }); it("width and height properties and null and empty strings", () => { - const style = new CSSStyleDeclaration(); + const style = new CSSStyleDeclaration(window); style.height = 6; assert.strictEqual(style.height, ""); style.width = 0; @@ -317,7 +511,7 @@ describe("CSSStyleDeclaration", () => { }); it("implicit properties", () => { - const style = new CSSStyleDeclaration(); + const style = new CSSStyleDeclaration(window); style.borderWidth = 0; assert.strictEqual(style.border, ""); assert.strictEqual(style.borderWidth, "0px"); @@ -329,7 +523,7 @@ describe("CSSStyleDeclaration", () => { }); it("top, left, right, bottom properties", () => { - const style = new CSSStyleDeclaration(); + const style = new CSSStyleDeclaration(window); style.top = 0; style.left = "0%"; style.right = "5em"; @@ -343,7 +537,7 @@ describe("CSSStyleDeclaration", () => { }); it('top, left, right, bottom properties should accept "auto"', () => { - const style = new CSSStyleDeclaration(); + const style = new CSSStyleDeclaration(window); style.cssText = `top: auto; right: auto; bottom: auto; left: auto;`; assert.strictEqual(style.top, "auto"); assert.strictEqual(style.right, "auto"); @@ -352,7 +546,7 @@ describe("CSSStyleDeclaration", () => { }); it("clear and clip properties", () => { - const style = new CSSStyleDeclaration(); + const style = new CSSStyleDeclaration(window); style.clear = "none"; assert.strictEqual(style.clear, "none"); style.clear = "lfet"; @@ -366,14 +560,14 @@ describe("CSSStyleDeclaration", () => { style.clip = "elipse(5px, 10px)"; assert.strictEqual(style.clip, ""); assert.strictEqual(style.length, 1); - style.clip = "rect(0, 3Em, 2pt, 50%)"; - assert.strictEqual(style.clip, "rect(0px, 3em, 2pt, 50%)"); + style.clip = "rect(0, 3Em, 2pt, 5px)"; + assert.strictEqual(style.clip, "rect(0px, 3em, 2pt, 5px)"); assert.strictEqual(style.length, 2); - assert.strictEqual(style.cssText, "clear: both; clip: rect(0px, 3em, 2pt, 50%);"); + assert.strictEqual(style.cssText, "clear: both; clip: rect(0px, 3em, 2pt, 5px);"); }); it("colors", () => { - const style = new CSSStyleDeclaration(); + const style = new CSSStyleDeclaration(window); style.color = "rgba(0,0,0,0)"; assert.strictEqual(style.color, "rgba(0, 0, 0, 0)"); style.color = "rgba(5%, 10%, 20%, 0.4)"; @@ -401,24 +595,24 @@ describe("CSSStyleDeclaration", () => { }); it("invalid hex color value", () => { - const style = new CSSStyleDeclaration(); + const style = new CSSStyleDeclaration(window); style.color = "#1234567"; assert.strictEqual(style.color, ""); }); it("shorthand properties with embedded spaces", () => { - let style = new CSSStyleDeclaration(); + let style = new CSSStyleDeclaration(window); style.background = "rgb(0, 0, 0) url(/something/somewhere.jpg)"; assert.strictEqual(style.backgroundColor, "rgb(0, 0, 0)"); assert.strictEqual(style.backgroundImage, 'url("/something/somewhere.jpg")'); assert.strictEqual(style.cssText, 'background: url("/something/somewhere.jpg") rgb(0, 0, 0);'); - style = new CSSStyleDeclaration(); + style = new CSSStyleDeclaration(window); style.border = " 1px solid black "; assert.strictEqual(style.border, "1px solid black"); }); it("setting shorthand properties to an empty string should clear all dependent properties", () => { - const style = new CSSStyleDeclaration(); + const style = new CSSStyleDeclaration(window); style.borderWidth = "1px"; assert.strictEqual(style.cssText, "border-width: 1px;"); style.border = ""; @@ -426,7 +620,7 @@ describe("CSSStyleDeclaration", () => { }); it("setting implicit properties to an empty string should clear all dependent properties", () => { - const style = new CSSStyleDeclaration(); + const style = new CSSStyleDeclaration(window); style.borderTopWidth = "1px"; assert.strictEqual(style.cssText, "border-top-width: 1px;"); style.borderWidth = ""; @@ -434,7 +628,7 @@ describe("CSSStyleDeclaration", () => { }); it("setting a shorthand property, whose shorthands are implicit properties, to an empty string should clear all dependent properties", () => { - const style = new CSSStyleDeclaration(); + const style = new CSSStyleDeclaration(window); style.borderTopWidth = "2px"; assert.strictEqual(style.cssText, "border-top-width: 2px;"); style.border = ""; @@ -446,7 +640,7 @@ describe("CSSStyleDeclaration", () => { }); it("set border as none", () => { - const style = new CSSStyleDeclaration(); + const style = new CSSStyleDeclaration(window); style.border = "none"; assert.strictEqual(style.border, "medium", "border"); assert.strictEqual(style.borderWidth, "medium", "border-width"); @@ -459,7 +653,7 @@ describe("CSSStyleDeclaration", () => { }); it("set border as none", () => { - const style = new CSSStyleDeclaration(); + const style = new CSSStyleDeclaration(window); style.border = "none"; assert.strictEqual(style.border, "medium", "border"); assert.strictEqual(style.borderWidth, "medium", "border-width"); @@ -472,7 +666,7 @@ describe("CSSStyleDeclaration", () => { }); it("set border-style as none", () => { - const style = new CSSStyleDeclaration(); + const style = new CSSStyleDeclaration(window); style.borderStyle = "none"; assert.strictEqual(style.border, "", "border"); assert.strictEqual(style.borderWidth, "", "border-width"); @@ -485,7 +679,7 @@ describe("CSSStyleDeclaration", () => { }); it("set border-top as none", () => { - const style = new CSSStyleDeclaration(); + const style = new CSSStyleDeclaration(window); style.borderTop = "none"; assert.strictEqual(style.border, "", "border"); assert.strictEqual(style.borderWidth, "", "border-width"); @@ -498,7 +692,7 @@ describe("CSSStyleDeclaration", () => { }); it("set border as 1px and change border-style to none", () => { - const style = new CSSStyleDeclaration(); + const style = new CSSStyleDeclaration(window); style.border = "1px"; style.borderStyle = "none"; assert.strictEqual(style.border, "1px", "border"); @@ -512,7 +706,7 @@ describe("CSSStyleDeclaration", () => { }); it("set border as 1px and change border-style to none", () => { - const style = new CSSStyleDeclaration(); + const style = new CSSStyleDeclaration(window); style.border = "1px"; style.borderStyle = "none"; assert.strictEqual(style.border, "1px", "border"); @@ -526,7 +720,7 @@ describe("CSSStyleDeclaration", () => { }); it("set border as 1px and change border-top to none", () => { - const style = new CSSStyleDeclaration(); + const style = new CSSStyleDeclaration(window); style.border = "1px"; style.borderTop = "none"; assert.strictEqual(style.border, "", "border"); @@ -544,7 +738,7 @@ describe("CSSStyleDeclaration", () => { }); it("set border as 1px solid and change border-top to none", () => { - const style = new CSSStyleDeclaration(); + const style = new CSSStyleDeclaration(window); style.border = "1px solid"; style.borderTop = "none"; assert.strictEqual(style.border, "", "border"); @@ -562,7 +756,7 @@ describe("CSSStyleDeclaration", () => { }); it("set border as none and change border-style to null", () => { - const style = new CSSStyleDeclaration(); + const style = new CSSStyleDeclaration(window); style.border = "none"; style.borderStyle = null; assert.strictEqual(style.border, "", "border"); @@ -580,7 +774,7 @@ describe("CSSStyleDeclaration", () => { }); it("set border as solid and change border-top to none", () => { - const style = new CSSStyleDeclaration(); + const style = new CSSStyleDeclaration(window); style.border = "solid"; style.borderTop = "none"; assert.strictEqual(style.border, "", "border"); @@ -598,7 +792,7 @@ describe("CSSStyleDeclaration", () => { }); it("set border as solid and change border-style to none", () => { - const style = new CSSStyleDeclaration(); + const style = new CSSStyleDeclaration(window); style.border = "solid"; style.borderStyle = "none"; assert.strictEqual(style.border, "medium", "border"); @@ -612,7 +806,7 @@ describe("CSSStyleDeclaration", () => { }); it("set border-style as solid and change border-top to none", () => { - const style = new CSSStyleDeclaration(); + const style = new CSSStyleDeclaration(window); style.borderStyle = "solid"; style.borderTop = "none"; assert.strictEqual(style.border, "", "border"); @@ -630,7 +824,7 @@ describe("CSSStyleDeclaration", () => { }); it("set border-top as solid and change border-style to none", () => { - const style = new CSSStyleDeclaration(); + const style = new CSSStyleDeclaration(window); style.borderTop = "solid"; style.borderStyle = "none"; assert.strictEqual(style.border, "", "border"); @@ -648,7 +842,7 @@ describe("CSSStyleDeclaration", () => { }); it("set border-style as solid and change border-top to null", () => { - const style = new CSSStyleDeclaration(); + const style = new CSSStyleDeclaration(window); style.borderStyle = "solid"; style.borderTop = null; assert.strictEqual( @@ -666,7 +860,7 @@ describe("CSSStyleDeclaration", () => { }); it("setting border values to none should change dependent values", () => { - const style = new CSSStyleDeclaration(); + const style = new CSSStyleDeclaration(window); style.borderTopWidth = "1px"; assert.strictEqual(style.cssText, "border-top-width: 1px;"); style.border = "none"; @@ -718,21 +912,21 @@ describe("CSSStyleDeclaration", () => { }); it("setting border to green", () => { - const style = new CSSStyleDeclaration(); + const style = new CSSStyleDeclaration(window); style.border = "green"; assert.strictEqual(style.cssText, "border: green;"); assert.strictEqual(style.border, "green"); }); it("setting border to green", () => { - const style = new CSSStyleDeclaration(); + const style = new CSSStyleDeclaration(window); style.border = "green"; assert.strictEqual(style.cssText, "border: green;"); assert.strictEqual(style.border, "green"); }); it("setting border to initial should set all properties initial", () => { - const style = new CSSStyleDeclaration(); + const style = new CSSStyleDeclaration(window); style.border = "initial"; assert.strictEqual(style.cssText, "border: initial;"); assert.strictEqual(style.border, "initial"); @@ -747,7 +941,7 @@ describe("CSSStyleDeclaration", () => { }); it("setting borderTop to initial should set top related properties initial", () => { - const style = new CSSStyleDeclaration(); + const style = new CSSStyleDeclaration(window); style.borderTop = "initial"; assert.strictEqual(style.cssText, "border-top: initial;"); assert.strictEqual(style.border, ""); @@ -762,26 +956,26 @@ describe("CSSStyleDeclaration", () => { }); it("setting border to 0 should be okay", () => { - const style = new CSSStyleDeclaration(); + const style = new CSSStyleDeclaration(window); style.border = 0; assert.strictEqual(style.cssText, "border: 0px;"); assert.strictEqual(style.border, "0px"); }); it("setting borderColor to var() should be okay", () => { - const style = new CSSStyleDeclaration(); + const style = new CSSStyleDeclaration(window); style.borderColor = "var(--foo)"; assert.strictEqual(style.cssText, "border-color: var(--foo);"); }); it("setting borderColor to inherit should be okay", () => { - const style = new CSSStyleDeclaration(); + const style = new CSSStyleDeclaration(window); style.borderColor = "inherit"; assert.strictEqual(style.cssText, "border-color: inherit;"); }); it("setting values implicit and shorthand properties via csstext and setproperty should propagate to dependent properties", () => { - const style = new CSSStyleDeclaration(); + const style = new CSSStyleDeclaration(window); style.cssText = "border: 1px solid black;"; assert.strictEqual(style.cssText, "border: 1px solid black;"); assert.strictEqual(style.borderTop, "1px solid black"); @@ -792,7 +986,7 @@ describe("CSSStyleDeclaration", () => { }); it("setting opacity should work", () => { - const style = new CSSStyleDeclaration(); + const style = new CSSStyleDeclaration(window); style.setProperty("opacity", 0.75); assert.strictEqual(style.cssText, "opacity: 0.75;"); style.opacity = "0.50"; @@ -802,18 +996,18 @@ describe("CSSStyleDeclaration", () => { }); it("width and height of auto should work", () => { - let style = new CSSStyleDeclaration(); + let style = new CSSStyleDeclaration(window); style.width = "auto"; assert.strictEqual(style.cssText, "width: auto;"); assert.strictEqual(style.width, "auto"); - style = new CSSStyleDeclaration(); + style = new CSSStyleDeclaration(window); style.height = "auto"; assert.strictEqual(style.cssText, "height: auto;"); assert.strictEqual(style.height, "auto"); }); it("Shorthand serialization with just longhands", () => { - const style = new CSSStyleDeclaration(); + const style = new CSSStyleDeclaration(window); style.cssText = "margin-right: 10px; margin-left: 10px; margin-top: 10px; margin-bottom: 10px;"; assert.strictEqual(style.cssText, "margin: 10px;"); assert.strictEqual(style.margin, "10px"); @@ -833,7 +1027,7 @@ describe("CSSStyleDeclaration", () => { }); it("padding and margin should set/clear shorthand properties", () => { - const style = new CSSStyleDeclaration(); + const style = new CSSStyleDeclaration(window); const parts = ["Top", "Right", "Bottom", "Left"]; const testParts = function (name, v, V) { style[name] = v; @@ -860,7 +1054,7 @@ describe("CSSStyleDeclaration", () => { }); it("padding and margin shorthands should set main properties", () => { - const style = new CSSStyleDeclaration(); + const style = new CSSStyleDeclaration(window); const parts = ["Top", "Right", "Bottom", "Left"]; const testParts = function (name, v, V) { let expected; @@ -880,7 +1074,7 @@ describe("CSSStyleDeclaration", () => { }); it("setting individual padding and margin properties to an empty string should clear them", () => { - const style = new CSSStyleDeclaration(); + const style = new CSSStyleDeclaration(window); const properties = ["padding", "margin"]; const parts = ["Top", "Right", "Bottom", "Left"]; @@ -897,7 +1091,7 @@ describe("CSSStyleDeclaration", () => { }); it("removing and setting individual margin properties updates the combined property accordingly", () => { - const style = new CSSStyleDeclaration(); + const style = new CSSStyleDeclaration(window); style.margin = "1px 2px 3px 4px"; style.marginTop = ""; assert.strictEqual(style.margin, ""); @@ -922,7 +1116,7 @@ describe("CSSStyleDeclaration", () => { for (const property of ["padding", "margin"]) { it(`removing an individual ${property} property should remove the combined property and replace it with the remaining individual ones`, () => { - const style = new CSSStyleDeclaration(); + const style = new CSSStyleDeclaration(window); const parts = ["Top", "Right", "Bottom", "Left"]; const partValues = ["1px", "2px", "3px", "4px"]; @@ -949,7 +1143,7 @@ describe("CSSStyleDeclaration", () => { }); it(`setting additional ${property} properties keeps important status of others`, () => { - const style = new CSSStyleDeclaration(); + const style = new CSSStyleDeclaration(window); const importantProperty = `${property}-top: 3px !important;`; style.cssText = importantProperty; assert.strictEqual(style.cssText.includes(importantProperty), true); @@ -965,7 +1159,7 @@ describe("CSSStyleDeclaration", () => { }); it(`setting individual ${property} keeps important status of others`, () => { - const style = new CSSStyleDeclaration(); + const style = new CSSStyleDeclaration(window); style.cssText = `${property}: 3px !important;`; style[`${property}Top`] = "4px"; assert.strictEqual(style.cssText.includes(`${property}-top: 4px;`), true); @@ -977,16 +1171,26 @@ describe("CSSStyleDeclaration", () => { } it("setting a value to 0 should return the string value", () => { - const style = new CSSStyleDeclaration(); + const style = new CSSStyleDeclaration(window); style.setProperty("fill-opacity", 0); assert.strictEqual(style.fillOpacity, "0"); }); it("onchange callback should be called when the csstext changes", () => { + const node = { + nodeType: 1, + style: {}, + ownerDocument: { + defaultView: window + } + }; let called = 0; - const style = new CSSStyleDeclaration(function (cssText) { - called++; - assert.strictEqual(cssText, "opacity: 0;"); + const style = new CSSStyleDeclaration(window, { + context: node, + onChange: (cssText) => { + called++; + assert.strictEqual(cssText, "opacity: 0;"); + } }); style.cssText = "opacity: 0;"; assert.strictEqual(called, 1); @@ -995,19 +1199,39 @@ describe("CSSStyleDeclaration", () => { }); it("onchange callback should be called only once when multiple properties were added", () => { + const node = { + nodeType: 1, + style: {}, + ownerDocument: { + defaultView: window + } + }; let called = 0; - const style = new CSSStyleDeclaration(function (cssText) { - called++; - assert.strictEqual(cssText, "width: 100px; height: 100px;"); + const style = new CSSStyleDeclaration(window, { + context: node, + onChange: (cssText) => { + called++; + assert.strictEqual(cssText, "width: 100px; height: 100px;"); + } }); style.cssText = "width: 100px;height:100px;"; assert.strictEqual(called, 1); }); it("onchange callback should not be called when property is set to the same value", () => { + const node = { + nodeType: 1, + style: {}, + ownerDocument: { + defaultView: window + } + }; let called = 0; - const style = new CSSStyleDeclaration(function () { - called++; + const style = new CSSStyleDeclaration(window, { + context: node, + onChange: () => { + called++; + } }); style.setProperty("opacity", 0); @@ -1017,22 +1241,26 @@ describe("CSSStyleDeclaration", () => { }); it("onchange callback should not be called when removeProperty was called on non-existing property", () => { + const node = { + nodeType: 1, + style: {}, + ownerDocument: { + defaultView: window + } + }; let called = 0; - const style = new CSSStyleDeclaration(function () { - called++; + const style = new CSSStyleDeclaration(window, { + context: node, + onChange: () => { + called++; + } }); style.removeProperty("opacity"); assert.strictEqual(called, 0); }); - it("setting float should work the same as cssfloat", () => { - const style = new CSSStyleDeclaration(); - style.float = "left"; - assert.strictEqual(style.cssFloat, "left"); - }); - it("setting improper css to csstext should not throw", () => { - const style = new CSSStyleDeclaration(); + const style = new CSSStyleDeclaration(window); style.cssText = "color: "; assert.strictEqual(style.cssText, ""); style.color = "black"; @@ -1041,7 +1269,7 @@ describe("CSSStyleDeclaration", () => { }); it("url parsing works with quotes", () => { - const style = new CSSStyleDeclaration(); + const style = new CSSStyleDeclaration(window); style.backgroundImage = "url(http://some/url/here1.png)"; assert.strictEqual(style.backgroundImage, 'url("http://some/url/here1.png")'); style.backgroundImage = "url('http://some/url/here2.png')"; @@ -1051,7 +1279,7 @@ describe("CSSStyleDeclaration", () => { }); it("setting 0 to a padding or margin works", () => { - const style = new CSSStyleDeclaration(); + const style = new CSSStyleDeclaration(window); style.padding = 0; assert.strictEqual(style.cssText, "padding: 0px;"); style.margin = "1em"; @@ -1060,7 +1288,7 @@ describe("CSSStyleDeclaration", () => { }); it("setting ex units to a padding or margin works", () => { - const style = new CSSStyleDeclaration(); + const style = new CSSStyleDeclaration(window); style.padding = "1ex"; assert.strictEqual(style.cssText, "padding: 1ex;"); style.margin = "1em"; @@ -1069,7 +1297,7 @@ describe("CSSStyleDeclaration", () => { }); it("setting empty string and null to a padding or margin works", () => { - const style = new CSSStyleDeclaration(); + const style = new CSSStyleDeclaration(window); const parts = ["Top", "Right", "Bottom", "Left"]; function testParts(base, nullValue) { const props = [base].concat(parts.map((part) => base + part)); @@ -1089,7 +1317,7 @@ describe("CSSStyleDeclaration", () => { }); it("setting undefined to a padding or margin does nothing", () => { - const style = new CSSStyleDeclaration(); + const style = new CSSStyleDeclaration(window); const parts = ["Top", "Right", "Bottom", "Left"]; function testParts(base) { const props = [base].concat(parts.map((part) => base + part)); @@ -1106,7 +1334,7 @@ describe("CSSStyleDeclaration", () => { }); it("setting null to background works", () => { - const style = new CSSStyleDeclaration(); + const style = new CSSStyleDeclaration(window); style.background = "red"; assert.strictEqual(style.cssText, "background: red;"); style.background = null; @@ -1114,7 +1342,7 @@ describe("CSSStyleDeclaration", () => { }); it("flex properties should keep their values", () => { - const style = new CSSStyleDeclaration(); + const style = new CSSStyleDeclaration(window); style.flexDirection = "column"; assert.strictEqual(style.cssText, "flex-direction: column;"); style.flexDirection = "row"; @@ -1122,351 +1350,2549 @@ describe("CSSStyleDeclaration", () => { }); it("camelcase properties are not assigned with `.setproperty()`", () => { - const style = new CSSStyleDeclaration(); + const style = new CSSStyleDeclaration(window); style.setProperty("fontSize", "12px"); assert.strictEqual(style.cssText, ""); }); it("casing is ignored in `.setproperty()`", () => { - const style = new CSSStyleDeclaration(); + const style = new CSSStyleDeclaration(window); style.setProperty("FoNt-SiZe", "12px"); assert.strictEqual(style.fontSize, "12px"); assert.strictEqual(style.getPropertyValue("font-size"), "12px"); }); it("support non string entries in border-spacing", () => { - const style = new CSSStyleDeclaration(); + const style = new CSSStyleDeclaration(window); style.borderSpacing = 0; assert.strictEqual(style.cssText, "border-spacing: 0px;"); }); it("float should be valid property for `.setproperty()`", () => { - const style = new CSSStyleDeclaration(); + const style = new CSSStyleDeclaration(window); style.setProperty("float", "left"); assert.strictEqual(style.float, "left"); assert.strictEqual(style.getPropertyValue("float"), "left"); }); - it("flex-shrink works", () => { - const style = new CSSStyleDeclaration(); - style.setProperty("flex-shrink", 0); - assert.strictEqual(style.getPropertyValue("flex-shrink"), "0"); - style.setProperty("flex-shrink", 1); - assert.strictEqual(style.getPropertyValue("flex-shrink"), "1"); - assert.strictEqual(style.cssText, "flex-shrink: 1;"); + it("flex-shrink works", () => { + const style = new CSSStyleDeclaration(window); + style.setProperty("flex-shrink", 0); + assert.strictEqual(style.getPropertyValue("flex-shrink"), "0"); + style.setProperty("flex-shrink", 1); + assert.strictEqual(style.getPropertyValue("flex-shrink"), "1"); + assert.strictEqual(style.cssText, "flex-shrink: 1;"); + }); + + it("flex-grow works", () => { + const style = new CSSStyleDeclaration(window); + style.setProperty("flex-grow", 2); + assert.strictEqual(style.getPropertyValue("flex-grow"), "2"); + assert.strictEqual(style.cssText, "flex-grow: 2;"); + }); + + it("flex-basis works", () => { + const style = new CSSStyleDeclaration(window); + style.setProperty("flex-basis", 0); + assert.strictEqual(style.getPropertyValue("flex-basis"), "0px"); + style.setProperty("flex-basis", "250px"); + assert.strictEqual(style.getPropertyValue("flex-basis"), "250px"); + style.setProperty("flex-basis", "10em"); + assert.strictEqual(style.getPropertyValue("flex-basis"), "10em"); + style.setProperty("flex-basis", "30%"); + assert.strictEqual(style.getPropertyValue("flex-basis"), "30%"); + assert.strictEqual(style.cssText, "flex-basis: 30%;"); + }); + + it("shorthand flex works", () => { + const style = new CSSStyleDeclaration(window); + style.setProperty("flex", "none"); + assert.strictEqual(style.getPropertyValue("flex-grow"), "0"); + assert.strictEqual(style.getPropertyValue("flex-shrink"), "0"); + assert.strictEqual(style.getPropertyValue("flex-basis"), "auto"); + style.removeProperty("flex"); + style.removeProperty("flex-basis"); + style.setProperty("flex", "auto"); + assert.strictEqual(style.getPropertyValue("flex-grow"), "1"); + assert.strictEqual(style.getPropertyValue("flex-shrink"), "1"); + assert.strictEqual(style.getPropertyValue("flex-basis"), "auto"); + style.removeProperty("flex"); + style.setProperty("flex", "0 1 250px"); + assert.strictEqual(style.getPropertyValue("flex"), "0 1 250px"); + assert.strictEqual(style.getPropertyValue("flex-grow"), "0"); + assert.strictEqual(style.getPropertyValue("flex-shrink"), "1"); + assert.strictEqual(style.getPropertyValue("flex-basis"), "250px"); + style.removeProperty("flex"); + style.setProperty("flex", "2"); + assert.strictEqual(style.getPropertyValue("flex-grow"), "2"); + assert.strictEqual(style.getPropertyValue("flex-shrink"), "1"); + assert.strictEqual(style.getPropertyValue("flex-basis"), "0%"); + style.removeProperty("flex"); + style.setProperty("flex", "20%"); + assert.strictEqual(style.getPropertyValue("flex-grow"), "1"); + assert.strictEqual(style.getPropertyValue("flex-shrink"), "1"); + assert.strictEqual(style.getPropertyValue("flex-basis"), "20%"); + style.removeProperty("flex"); + style.setProperty("flex", "2 2"); + assert.strictEqual(style.getPropertyValue("flex-grow"), "2"); + assert.strictEqual(style.getPropertyValue("flex-shrink"), "2"); + assert.strictEqual(style.getPropertyValue("flex-basis"), "0%"); + style.removeProperty("flex"); + }); + + it("font-size get a valid value", () => { + const style = new CSSStyleDeclaration(window); + const invalidValue = "1r5px"; + style.cssText = "font-size: 15px"; + assert.strictEqual(1, style.length); + style.cssText = `font-size: ${invalidValue}`; + assert.strictEqual(0, style.length); + assert.strictEqual(undefined, style[0]); + }); + + it("getPropertyValue for custom properties in cssText", () => { + const style = new CSSStyleDeclaration(window); + style.cssText = "--foo: red"; + + assert.strictEqual(style.getPropertyValue("--foo"), "red"); + }); + + it("getPropertyValue for custom properties with setProperty", () => { + const style = new CSSStyleDeclaration(window); + style.setProperty("--bar", "blue"); + + assert.strictEqual(style.getPropertyValue("--bar"), "blue"); + }); + + it("getPropertyValue for custom properties with object setter", () => { + const style = new CSSStyleDeclaration(window); + style["--baz"] = "yellow"; + + assert.strictEqual(style.getPropertyValue("--baz"), ""); + }); + + it("custom properties are case-sensitive", () => { + const style = new CSSStyleDeclaration(window); + style.cssText = "--fOo: purple"; + + assert.strictEqual(style.getPropertyValue("--foo"), ""); + assert.strictEqual(style.getPropertyValue("--fOo"), "purple"); + }); + + for (const property of [ + "width", + "height", + "margin", + "margin-top", + "bottom", + "right", + "padding" + ]) { + it(`supports calc for ${property}`, () => { + const style = new CSSStyleDeclaration(window); + style.setProperty(property, "calc(100% - 100px)"); + assert.strictEqual(style.getPropertyValue(property), "calc(100% - 100px)"); + }); + } + + it("supports nested calc", () => { + const style = new CSSStyleDeclaration(window); + style.setProperty("width", "calc(100% - calc(200px - 100px))"); + assert.strictEqual(style.getPropertyValue("width"), "calc(100% - 100px)"); + }); + + it("supports nested calc", () => { + const style = new CSSStyleDeclaration(window); + style.setProperty("width", "calc(100% * calc(2 / 3))"); + assert.strictEqual(style.getPropertyValue("width"), "calc(66.6667%)"); + }); + + it("supports var", () => { + const style = new CSSStyleDeclaration(window); + style.setProperty("width", "var(--foo)"); + assert.strictEqual(style.getPropertyValue("width"), "var(--foo)"); + }); + + it("supports var with fallback", () => { + const style = new CSSStyleDeclaration(window); + style.setProperty("width", "var(--foo, 100px)"); + assert.strictEqual(style.getPropertyValue("width"), "var(--foo, 100px)"); + }); + + it("supports var with var fallback", () => { + const style = new CSSStyleDeclaration(window); + style.setProperty("width", "var(--foo, var(--bar))"); + assert.strictEqual(style.getPropertyValue("width"), "var(--foo, var(--bar))"); + }); + + it("supports calc with var inside", () => { + const style = new CSSStyleDeclaration(window); + style.setProperty("width", "calc(100% - var(--foo))"); + assert.strictEqual(style.getPropertyValue("width"), "calc(100% - var(--foo))"); + }); + + it("supports var with calc inside", () => { + const style = new CSSStyleDeclaration(window); + style.setProperty("width", "var(--foo, calc(var(--bar) + 3px))"); + assert.strictEqual(style.getPropertyValue("width"), "var(--foo, calc(var(--bar) + 3px))"); + }); + + it("supports color var", () => { + const style = new CSSStyleDeclaration(window); + style.setProperty("color", "var(--foo)"); + assert.strictEqual(style.getPropertyValue("color"), "var(--foo)"); + }); + + it("should not normalize if var() is included", () => { + const style = new CSSStyleDeclaration(window); + style.setProperty("line-height", "calc( /* comment */ 100% - calc(var(--foo) *2 ))"); + assert.strictEqual( + style.getPropertyValue("line-height"), + "calc( /* comment */ 100% - calc(var(--foo) *2 ))" + ); + }); + + it("supports abs", () => { + const style = new CSSStyleDeclaration(window); + style.setProperty("line-height", "abs(1 - 2 * 3)"); + assert.strictEqual(style.getPropertyValue("line-height"), "calc(5)"); + }); + + it("supports abs inside calc", () => { + const style = new CSSStyleDeclaration(window); + style.setProperty("line-height", "calc(abs(1) + abs(2))"); + assert.strictEqual(style.getPropertyValue("line-height"), "calc(3)"); + }); + + it("supports sign", () => { + const style = new CSSStyleDeclaration(window); + style.setProperty("line-height", "sign(.1)"); + assert.strictEqual(style.getPropertyValue("line-height"), "calc(1)"); + }); + + it("supports sign inside calc", () => { + const style = new CSSStyleDeclaration(window); + style.setProperty("line-height", "calc(sign(.1) + sign(.2))"); + assert.strictEqual(style.getPropertyValue("line-height"), "calc(2)"); + }); + + it("no-op for setting undefined to width", () => { + const style = new CSSStyleDeclaration(window); + style.setProperty("width", "10px"); + assert.strictEqual(style.getPropertyValue("width"), "10px"); + + style.setProperty("width", undefined); + assert.strictEqual(style.getPropertyValue("width"), "10px"); + + style.width = undefined; + assert.strictEqual(style.getPropertyValue("width"), "10px"); + }); + + it("shorthand serialization with shorthand and longhands mixed", () => { + const style = new CSSStyleDeclaration(window); + style.cssText = "background-color: blue; background: red !important; background-color: green;"; + assert.strictEqual(style.cssText, "background: red !important;"); + }); + + it("shorthand serialization", () => { + const style = new CSSStyleDeclaration(window); + style.cssText = + "border-top: 1px; border-right: 1px; border-bottom: 1px; border-left: 1px; border-image: none;"; + assert.strictEqual(style.cssText, "border: 1px;"); + }); + + it("shorthand serialization", () => { + const style = new CSSStyleDeclaration(window); + style.cssText = "border-width: 1px;"; + assert.strictEqual(style.cssText, "border-width: 1px;"); + }); + + it("shorthand serialization", () => { + const style = new CSSStyleDeclaration(window); + style.cssText = "border: 1px; border-top: 1px !important;"; + assert.strictEqual( + style.cssText, + "border-right: 1px; border-bottom: 1px; border-left: 1px; border-image: none; border-top: 1px !important;" + ); + }); + + it("set cssText as none", () => { + const style = new CSSStyleDeclaration(window); + style.cssText = "border: none;"; + assert.strictEqual(style.cssText, "border: medium;"); + }); + + it("invalid cssText should be parsed", () => { + const style = new CSSStyleDeclaration(window); + style.cssText = "color: red; }"; + assert.strictEqual(style.cssText, "color: red;"); + }); + + it("single value flex with CSS-wide keyword", () => { + const style = new CSSStyleDeclaration(window); + style.cssText = "flex: initial;"; + assert.strictEqual(style.flex, "initial"); + assert.strictEqual(style.flexGrow, "initial"); + assert.strictEqual(style.flexShrink, "initial"); + assert.strictEqual(style.flexBasis, "initial"); + assert.strictEqual(style.cssText, "flex: initial;"); + }); + + it("single value flex with non-CSS-wide value", () => { + const style = new CSSStyleDeclaration(window); + style.cssText = "flex: 0;"; + assert.strictEqual(style.flex, "0 1 0%"); + assert.strictEqual(style.flexGrow, "0"); + assert.strictEqual(style.flexShrink, "1"); + assert.strictEqual(style.flexBasis, "0%"); + assert.strictEqual(style.cssText, "flex: 0 1 0%;"); + }); + + it("multiple values flex with CSS-wide keyword", () => { + const style = new CSSStyleDeclaration(window); + style.cssText = "flex: initial; flex-basis: initial; flex-shrink: initial;"; + assert.strictEqual(style.flex, "initial"); + assert.strictEqual(style.flexGrow, "initial"); + assert.strictEqual(style.flexShrink, "initial"); + assert.strictEqual(style.flexBasis, "initial"); + assert.strictEqual(style.cssText, "flex: initial;"); + }); + + it("multiple values flex with CSS-wide keywords and non-CSS-wide value", () => { + const style = new CSSStyleDeclaration(window); + style.cssText = "flex: initial; flex-shrink: 0;"; + assert.strictEqual(style.flex, ""); + assert.strictEqual(style.flexGrow, "initial"); + assert.strictEqual(style.flexShrink, "0"); + assert.strictEqual(style.flexBasis, "initial"); + assert.strictEqual(style.cssText, "flex-grow: initial; flex-basis: initial; flex-shrink: 0;"); + }); + + it("multiple values flex with CSS-wide and two non-CSS-wide-keyword values", () => { + const style = new CSSStyleDeclaration(window); + style.cssText = "flex: initial; flex-basis: 0; flex-shrink: 2;"; + assert.strictEqual(style.flex, ""); + assert.strictEqual(style.flexGrow, "initial"); + assert.strictEqual(style.flexShrink, "2"); + assert.strictEqual(style.flexBasis, "0px"); + assert.strictEqual(style.cssText, "flex-grow: initial; flex-basis: 0px; flex-shrink: 2;"); + }); +}); + +describe("background", () => { + it("background-attachment should set / get keyword", () => { + testPropertyValue("background-attachment", "fixed", "fixed"); + }); + + it("background-attachment should set / get multiple values", () => { + testPropertyValue("background-attachment", "fixed, scroll", "fixed, scroll"); + }); + + it("background-clip should set / get keyword", () => { + testPropertyValue("background-clip", "border-box", "border-box"); + }); + + it("background-clip should set / get multiple values", () => { + testPropertyValue("background-clip", "padding-box, content-box", "padding-box, content-box"); + }); + + it("background-color should set / get color", () => { + testPropertyValue("background-color", "green", "green"); + }); + + it("background-color should set / get color", () => { + testPropertyValue("background-color", "#008000", "rgb(0, 128, 0)"); + }); + + it("background-color should set / get color", () => { + testPropertyValue("background-color", "rgb(0 128 0)", "rgb(0, 128, 0)"); + }); + + it("background-color should not set / get multiple values", () => { + testPropertyValue("background-color", "green, blue", ""); + }); + + it("background-image should set / get keyword", () => { + testPropertyValue("background-image", "none", "none"); + }); + + it("background-image should set / get image URL", () => { + testPropertyValue("background-image", "url(example.png)", 'url("example.png")'); + }); + + it("background-image should set / get gradient image", () => { + testPropertyValue( + "background-image", + "linear-gradient(to right, green, blue)", + "linear-gradient(to right, green, blue)" + ); + }); + + it("background-image should set / get gradient image", () => { + testPropertyValue( + "background-image", + "radial-gradient(ellipse closest-side, #1e90ff 50%, #008000)", + "radial-gradient(closest-side, rgb(30, 144, 255) 50%, rgb(0, 128, 0))" + ); + }); + + it("background-image should set / get multiple values", () => { + testPropertyValue( + "background-image", + "url(example.png), linear-gradient(to right, green, blue)", + 'url("example.png"), linear-gradient(to right, green, blue)' + ); + }); + + it("background-origin should set / get keyword", () => { + testPropertyValue("background-origin", "border-box", "border-box"); + }); + + it("background-origin should set / get multiple values", () => { + testPropertyValue("background-origin", "padding-box, content-box", "padding-box, content-box"); + }); + + it("background-position should set / get keywords", () => { + testPropertyValue("background-position", "center", "center center"); + }); + + it("background-position should set / get keywords", () => { + testPropertyValue("background-position", "left", "left center"); + }); + + it("background-position should set / get keywords", () => { + testPropertyValue("background-position", "top", "center top"); + }); + + it("background-position should set / get keywords", () => { + testPropertyValue("background-position", "left center", "left center"); + }); + + it("background-position should set / get keywords", () => { + testPropertyValue("background-position", "top left", "left top"); + }); + + it("background-position should set / get keywords", () => { + testPropertyValue("background-position", "top center", "center top"); + }); + + it("background-position should not set / get keyword", () => { + testPropertyValue("background-position", "left right", ""); + }); + + it("background-position should set / get length keyword", () => { + testPropertyValue("background-position", "10px", "10px center"); + }); + + it("background-position should set / get length", () => { + testPropertyValue("background-position", "10px 20px", "10px 20px"); + }); + + it("background-position should set / get percent keyword", () => { + testPropertyValue("background-position", "10%", "10% center"); + }); + + it("background-position should set / get percents", () => { + testPropertyValue("background-position", "10% 20%", "10% 20%"); + }); + + it("background-position should set / get length percent", () => { + testPropertyValue("background-position", "10px 20%", "10px 20%"); + }); + + it("background-position should set / get keyword length", () => { + testPropertyValue("background-position", "left 10px", "left 10px"); + }); + + it("background-position should not set / get keyword length", () => { + testPropertyValue("background-position", "10px left", ""); + }); + + it("background-position should set / get keyword length", () => { + testPropertyValue("background-position", "10px top", "10px top"); + }); + + it("background-position should not set / get keyword length", () => { + testPropertyValue("background-position", "top 10px", ""); + }); + + it("background-position should not set / get keyword", () => { + testPropertyValue("background-position", "left right bottom", ""); + }); + + it("background-position should not set / get length percent", () => { + testPropertyValue("background-position", "10px 20% 30px", ""); + }); + + it("background-position should set / get keyword length with offset", () => { + testPropertyValue("background-position", "center 10px center", ""); + }); + + it("background-position should set / get keyword length with offset", () => { + testPropertyValue("background-position", "center center 10px", ""); + }); + + it("background-position should set / get keyword length with offset", () => { + testPropertyValue("background-position", "left 10px top", "left 10px top"); + }); + + it("background-position should set / get keyword length with offset", () => { + testPropertyValue("background-position", "left top 20px", "left top 20px"); + }); + + it("background-position should set / get keyword length with offset", () => { + testPropertyValue("background-position", "top 20px left", "left top 20px"); + }); + + it("background-position should set / get keyword length with offset", () => { + testPropertyValue("background-position", "top left 10px", "left 10px top"); + }); + + it("background-position should not set / get keyword", () => { + testPropertyValue("background-position", "left right top bottom", ""); + }); + + it("background-position should not set / get length percent", () => { + testPropertyValue("background-position", "10px 20% 30px 40%", ""); + }); + + it("background-position should set / get keyword length with offset", () => { + testPropertyValue("background-position", "center 10px center 20px", ""); + }); + + it("background-position should set / get keyword length with offset", () => { + testPropertyValue("background-position", "left 10px top 20px", "left 10px top 20px"); + }); + + it("background-position should set / get keyword length with offset", () => { + testPropertyValue("background-position", "top 10px left 20px", "left 20px top 10px"); + }); + + it("background-position should set / get multiple values", () => { + testPropertyValue("background-position", "left top, bottom right", "left top, right bottom"); + }); + + it("background-repeat should set / get keyword", () => { + testPropertyValue("background-repeat", "repeat", "repeat"); + }); + + it("background-repeat should set / get keyword keyword", () => { + testPropertyValue("background-repeat", "repeat no-repeat", "repeat-x"); + }); + + it("background-repeat should set / get keyword keyword", () => { + testPropertyValue("background-repeat", "no-repeat repeat", "repeat-y"); + }); + + it("background-repeat should set / get keyword keyword", () => { + testPropertyValue("background-repeat", "repeat repeat", "repeat"); + }); + + it("background-repeat should set / get keyword keyword", () => { + testPropertyValue("background-repeat", "repeat space", "repeat space"); + }); + + it("background-repeat should not set / get multiple axis keywords", () => { + testPropertyValue("background-repeat", "repeat-x repeat-y", ""); + }); + + it("background-repeat should set / get multiple values", () => { + testPropertyValue("background-repeat", "repeat, no-repeat", "repeat, no-repeat"); + }); + + it("background-size should set / get keyword", () => { + testPropertyValue("background-size", "contain", "contain"); + }); + + it("background-size should not set / get multiple ratio keywords", () => { + testPropertyValue("background-size", "contain cover", ""); + }); + + it("background-size should set / get keyword", () => { + testPropertyValue("background-size", "auto auto", "auto"); + }); + + it("background-size should set / get length and length", () => { + testPropertyValue("background-size", "10px 20px", "10px 20px"); + }); + + it("background-size should not set / get negative length", () => { + testPropertyValue("background-size", "-10px 20px", ""); + }); + + it("background-size should not set / get negative length", () => { + testPropertyValue("background-size", "10px -20px", ""); + }); + + it("background-size should set / get percent", () => { + testPropertyValue("background-size", "10% 20%", "10% 20%"); + }); + + it("background-size should not set / get negative percent", () => { + testPropertyValue("background-size", "-10% 20%", ""); + }); + + it("background-size should not set / get negative percent", () => { + testPropertyValue("background-size", "10% -20%%", ""); + }); + + it("background-size should set / get keyword and length", () => { + testPropertyValue("background-size", "auto 10px", "auto 10px"); + }); + + it("background-size should set / get length", () => { + testPropertyValue("background-size", "10px auto", "10px"); + }); + + it("background-size should set / get multiple values", () => { + testPropertyValue("background-size", "contain, cover", "contain, cover"); + }); + + it("background shorthand should set / get value", () => { + testImplicitPropertyValue( + "background", + "none", + "none", + new Map([ + ["background-image", "none"], + ["background-position", "0% 0%"], + ["background-size", "auto"], + ["background-repeat", "repeat"], + ["background-origin", "padding-box"], + ["background-clip", "border-box"], + ["background-attachment", "scroll"], + ["background-color", "transparent"] + ]) + ); + }); + + it("background shorthand should set / get value", () => { + testImplicitPropertyValue( + "background", + "transparent", + "transparent", + new Map([ + ["background-image", "none"], + ["background-position", "0% 0%"], + ["background-size", "auto"], + ["background-repeat", "repeat"], + ["background-origin", "padding-box"], + ["background-clip", "border-box"], + ["background-attachment", "scroll"], + ["background-color", "transparent"] + ]) + ); + }); + + it("background shorthand should set / get sub longhand values", () => { + testImplicitPropertyValue( + "background", + "fixed left / 50% repeat url(example.png) green", + 'url("example.png") left center / 50% fixed green', + new Map([ + ["background-image", 'url("example.png")'], + ["background-position", "left center"], + ["background-size", "50%"], + ["background-repeat", "repeat"], + ["background-origin", "padding-box"], + ["background-clip", "border-box"], + ["background-attachment", "fixed"], + ["background-color", "green"] + ]) + ); + }); + + it("background shorthand should set / get multiple values", () => { + testImplicitPropertyValue( + "background", + "fixed left / 50% repeat url(example.png), linear-gradient(to right, green, blue) green", + 'url("example.png") left center / 50% fixed, linear-gradient(to right, green, blue) green', + new Map([ + ["background-image", 'url("example.png"), linear-gradient(to right, green, blue)'], + ["background-position", "left center, 0% 0%"], + ["background-size", "50%, auto"], + ["background-repeat", "repeat, repeat"], + ["background-origin", "padding-box, padding-box"], + ["background-clip", "border-box, border-box"], + ["background-attachment", "fixed, scroll"], + ["background-color", "green"] + ]) + ); + }); + + it("background shorthand should set / get value", () => { + testImplicitPropertyValue( + "background", + "fixed left repeat url(example.png) var(--foo)", + "fixed left repeat url(example.png) var(--foo)", + new Map([ + ["background-image", ""], + ["background-position", ""], + ["background-size", ""], + ["background-repeat", ""], + ["background-origin", ""], + ["background-clip", ""], + ["background-attachment", ""], + ["background-color", ""] + ]) + ); + }); +}); + +describe("border", () => { + it("border-top-color should set / get color", () => { + testPropertyValue("border-top-color", "green", "green"); + }); + + it("border-top-color should set / get color", () => { + testPropertyValue("border-top-color", "#008000", "rgb(0, 128, 0)"); + }); + + it("border-top-color should set / get color", () => { + testPropertyValue("border-top-color", "rgb(0 128 0)", "rgb(0, 128, 0)"); + }); + + it("border-right-color should set / get color", () => { + testPropertyValue("border-right-color", "green", "green"); + }); + + it("border-right-color should set / get color", () => { + testPropertyValue("border-right-color", "#008000", "rgb(0, 128, 0)"); + }); + + it("border-right-color should set / get color", () => { + testPropertyValue("border-right-color", "rgb(0 128 0)", "rgb(0, 128, 0)"); + }); + + it("border-bottom-color should set / get color", () => { + testPropertyValue("border-bottom-color", "green", "green"); + }); + + it("border-bottom-color should set / get color", () => { + testPropertyValue("border-bottom-color", "#008000", "rgb(0, 128, 0)"); + }); + + it("border-bottom-color should set / get color", () => { + testPropertyValue("border-bottom-color", "rgb(0 128 0)", "rgb(0, 128, 0)"); + }); + + it("border-left-color should set / get color", () => { + testPropertyValue("border-left-color", "green", "green"); + }); + + it("border-left-color should set / get color", () => { + testPropertyValue("border-left-color", "#008000", "rgb(0, 128, 0)"); + }); + + it("border-left-color should set / get color", () => { + testPropertyValue("border-left-color", "rgb(0 128 0)", "rgb(0, 128, 0)"); + }); + + it("border-top-width should set / get keyword", () => { + testPropertyValue("border-top-width", "medium", "medium"); + }); + + it("border-top-width should set / get length", () => { + testPropertyValue("border-top-width", "10px", "10px"); + }); + + it("border-top-width should not set / get negative length", () => { + testPropertyValue("border-top-width", "-10px", ""); + }); + + it("border-right-width should set / get keyword", () => { + testPropertyValue("border-right-width", "medium", "medium"); + }); + + it("border-right-width should set / get length", () => { + testPropertyValue("border-right-width", "10px", "10px"); + }); + + it("border-right-width should not set / get negative length", () => { + testPropertyValue("border-right-width", "-10px", ""); + }); + + it("border-bottom-width should set / get keyword", () => { + testPropertyValue("border-bottom-width", "medium", "medium"); + }); + + it("border-bottom-width should set / get length", () => { + testPropertyValue("border-bottom-width", "10px", "10px"); + }); + + it("border-bottom-width should not set / get negative length", () => { + testPropertyValue("border-bottom-width", "-10px", ""); + }); + + it("border-left-width should set / get keyword", () => { + testPropertyValue("border-left-width", "medium", "medium"); + }); + + it("border-left-width should set / get length", () => { + testPropertyValue("border-left-width", "10px", "10px"); + }); + + it("border-left-width should not set / get negative length", () => { + testPropertyValue("border-left-width", "-10px", ""); + }); + + it("border-top-style should set / get keyword", () => { + testPropertyValue("border-top-style", "dotted", "dotted"); + }); + + it("border-right-style should set / get keyword", () => { + testPropertyValue("border-right-style", "dotted", "dotted"); + }); + + it("border-bottom-style should set / get keyword", () => { + testPropertyValue("border-bottom-style", "dotted", "dotted"); + }); + + it("border-left-style should set / get keyword", () => { + testPropertyValue("border-left-style", "dotted", "dotted"); + }); + + it("border-color should set / get color", () => { + testImplicitPropertyValue( + "border-color", + "green", + "green", + new Map([ + ["border-top-color", "green"], + ["border-right-color", "green"], + ["border-bottom-color", "green"], + ["border-left-color", "green"] + ]) + ); + }); + + it("border-color should set / get color", () => { + testImplicitPropertyValue( + "border-color", + "green blue", + "green blue", + new Map([ + ["border-top-color", "green"], + ["border-right-color", "blue"], + ["border-bottom-color", "green"], + ["border-left-color", "blue"] + ]) + ); + }); + + it("border-color should set / get color", () => { + testImplicitPropertyValue( + "border-color", + "green blue yellow", + "green blue yellow", + new Map([ + ["border-top-color", "green"], + ["border-right-color", "blue"], + ["border-bottom-color", "yellow"], + ["border-left-color", "blue"] + ]) + ); + }); + + it("border-color should set / get color", () => { + testImplicitPropertyValue( + "border-color", + "green blue yellow purple", + "green blue yellow purple", + new Map([ + ["border-top-color", "green"], + ["border-right-color", "blue"], + ["border-bottom-color", "yellow"], + ["border-left-color", "purple"] + ]) + ); + }); + + it("border-width should set / get keyword", () => { + testImplicitPropertyValue( + "border-width", + "thick", + "thick", + new Map([ + ["border-top-width", "thick"], + ["border-right-width", "thick"], + ["border-bottom-width", "thick"], + ["border-left-width", "thick"] + ]) + ); + }); + + it("border-width should set / get keyword", () => { + testImplicitPropertyValue( + "border-width", + "thick thin", + "thick thin", + new Map([ + ["border-top-width", "thick"], + ["border-right-width", "thin"], + ["border-bottom-width", "thick"], + ["border-left-width", "thin"] + ]) + ); + }); + + it("border-width should set / get keyword", () => { + testImplicitPropertyValue( + "border-width", + "thick thin medium", + "thick thin medium", + new Map([ + ["border-top-width", "thick"], + ["border-right-width", "thin"], + ["border-bottom-width", "medium"], + ["border-left-width", "thin"] + ]) + ); + }); + + it("border-width should set / get keyword and value", () => { + testImplicitPropertyValue( + "border-width", + "thick thin medium 10px", + "thick thin medium 10px", + new Map([ + ["border-top-width", "thick"], + ["border-right-width", "thin"], + ["border-bottom-width", "medium"], + ["border-left-width", "10px"] + ]) + ); + }); + + it("border-style should set / get keyword", () => { + testImplicitPropertyValue( + "border-style", + "dotted", + "dotted", + new Map([ + ["border-top-style", "dotted"], + ["border-right-style", "dotted"], + ["border-bottom-style", "dotted"], + ["border-left-style", "dotted"] + ]) + ); + }); + + it("border-style should set / get keyword", () => { + testImplicitPropertyValue( + "border-style", + "none", + "none", + new Map([ + ["border-top-style", "none"], + ["border-right-style", "none"], + ["border-bottom-style", "none"], + ["border-left-style", "none"] + ]) + ); + }); + + it("border-style should set / get keyword", () => { + testImplicitPropertyValue( + "border-style", + "dotted groove", + "dotted groove", + new Map([ + ["border-top-style", "dotted"], + ["border-right-style", "groove"], + ["border-bottom-style", "dotted"], + ["border-left-style", "groove"] + ]) + ); + }); + + it("border-style should set / get keyword", () => { + testImplicitPropertyValue( + "border-style", + "dotted groove double", + "dotted groove double", + new Map([ + ["border-top-style", "dotted"], + ["border-right-style", "groove"], + ["border-bottom-style", "double"], + ["border-left-style", "groove"] + ]) + ); + }); + + it("border-style should set / get keyword", () => { + testImplicitPropertyValue( + "border-style", + "dotted groove double none", + "dotted groove double none", + new Map([ + ["border-top-style", "dotted"], + ["border-right-style", "groove"], + ["border-bottom-style", "double"], + ["border-left-style", "none"] + ]) + ); + }); + + it("border-collapse should set / get keyword", () => { + testPropertyValue("border-collapse", "collapse", "collapse"); + }); + + it("border-spacing should set / get length", () => { + testPropertyValue("border-spacing", "10px", "10px"); + }); + + it("border-spacing should set / get length", () => { + testPropertyValue("border-spacing", "10px 20px", "10px 20px"); + }); + + it("border-top shorthand should set / get value", () => { + testImplicitPropertyValue( + "border-top", + "1px solid green", + "1px solid green", + new Map([ + ["border-top-width", "1px"], + ["border-top-style", "solid"], + ["border-top-color", "green"] + ]) + ); + }); + + it("border-top shorthand should set / get value", () => { + testImplicitPropertyValue( + "border-top", + "1px var(--foo) green", + "1px var(--foo) green", + new Map([ + ["border-top-width", ""], + ["border-top-style", ""], + ["border-top-color", ""] + ]) + ); + }); + + it("border-right shorthand should set / get value", () => { + testImplicitPropertyValue( + "border-right", + "1px solid green", + "1px solid green", + new Map([ + ["border-right-width", "1px"], + ["border-right-style", "solid"], + ["border-right-color", "green"] + ]) + ); + }); + + it("border-right shorthand should set / get value", () => { + testImplicitPropertyValue( + "border-right", + "1px var(--foo) green", + "1px var(--foo) green", + new Map([ + ["border-right-width", ""], + ["border-right-style", ""], + ["border-right-color", ""] + ]) + ); + }); + + it("border-bottom shorthand should set / get value", () => { + testImplicitPropertyValue( + "border-bottom", + "1px solid green", + "1px solid green", + new Map([ + ["border-bottom-width", "1px"], + ["border-bottom-style", "solid"], + ["border-bottom-color", "green"] + ]) + ); + }); + + it("border-bottom shorthand should set / get value", () => { + testImplicitPropertyValue( + "border-bottom", + "1px var(--foo) green", + "1px var(--foo) green", + new Map([ + ["border-bottom-width", ""], + ["border-bottom-style", ""], + ["border-bottom-color", ""] + ]) + ); + }); + + it("border-left shorthand should set / get value", () => { + testImplicitPropertyValue( + "border-left", + "1px solid green", + "1px solid green", + new Map([ + ["border-left-width", "1px"], + ["border-left-style", "solid"], + ["border-left-color", "green"] + ]) + ); + }); + + it("border-left shorthand should set / get value", () => { + testImplicitPropertyValue( + "border-left", + "1px var(--foo) green", + "1px var(--foo) green", + new Map([ + ["border-left-width", ""], + ["border-left-style", ""], + ["border-left-color", ""] + ]) + ); + }); + + it("border shorthand should set / get value", () => { + testImplicitPropertyValue( + "border", + "1px solid green", + "1px solid green", + new Map([ + ["border-top-width", "1px"], + ["border-top-style", "solid"], + ["border-top-color", "green"], + ["border-right-width", "1px"], + ["border-right-style", "solid"], + ["border-right-color", "green"], + ["border-bottom-width", "1px"], + ["border-bottom-style", "solid"], + ["border-bottom-color", "green"], + ["border-left-width", "1px"], + ["border-left-style", "solid"], + ["border-left-color", "green"] + ]) + ); + }); + + it("border shorthand should set / get value", () => { + testImplicitPropertyValue( + "border", + "1px var(--foo) green", + "1px var(--foo) green", + new Map([ + ["border-top-width", ""], + ["border-top-style", ""], + ["border-top-color", ""], + ["border-right-width", ""], + ["border-right-style", ""], + ["border-right-color", ""], + ["border-bottom-width", ""], + ["border-bottom-style", ""], + ["border-bottom-color", ""], + ["border-left-width", ""], + ["border-left-style", ""], + ["border-left-color", ""] + ]) + ); + }); +}); + +describe("box model", () => { + it("margin-top should set / get keyword", () => { + testPropertyValue("margin-top", "auto", "auto"); + }); + + it("margin-top should set / get length", () => { + testPropertyValue("margin-top", "0", "0px"); + }); + + it("margin-top should set / get length", () => { + testPropertyValue("margin-top", "10px", "10px"); + }); + + it("margin-top should set / get negative length", () => { + testPropertyValue("margin-top", "-10px", "-10px"); + }); + + it("margin-top should set / get percent", () => { + testPropertyValue("margin-top", "10%", "10%"); + }); + + it("margin-top should set / get negative percent", () => { + testPropertyValue("margin-top", "-10%", "-10%"); + }); + + it("margin-right should set / get keyword", () => { + testPropertyValue("margin-right", "auto", "auto"); + }); + + it("margin-right should set / get length", () => { + testPropertyValue("margin-right", "0", "0px"); + }); + + it("margin-right should set / get length", () => { + testPropertyValue("margin-right", "10px", "10px"); + }); + + it("margin-right should set / get negative length", () => { + testPropertyValue("margin-right", "-10px", "-10px"); + }); + + it("margin-right should set / get percent", () => { + testPropertyValue("margin-right", "10%", "10%"); + }); + + it("margin-right should set / get negative percent", () => { + testPropertyValue("margin-right", "-10%", "-10%"); + }); + + it("margin-bottom should set / get keyword", () => { + testPropertyValue("margin-bottom", "auto", "auto"); + }); + + it("margin-bottom should set / get length", () => { + testPropertyValue("margin-bottom", "0", "0px"); + }); + + it("margin-bottom should set / get length", () => { + testPropertyValue("margin-bottom", "10px", "10px"); + }); + + it("margin-bottom should set / get negative length", () => { + testPropertyValue("margin-bottom", "-10px", "-10px"); + }); + + it("margin-bottom should set / get percent", () => { + testPropertyValue("margin-bottom", "10%", "10%"); + }); + + it("margin-bottom should set / get negative percent", () => { + testPropertyValue("margin-bottom", "-10%", "-10%"); + }); + + it("margin-left should set / get keyword", () => { + testPropertyValue("margin-left", "auto", "auto"); + }); + + it("margin-left should set / get length", () => { + testPropertyValue("margin-left", "0", "0px"); + }); + + it("margin-left should set / get length", () => { + testPropertyValue("margin-left", "10px", "10px"); + }); + + it("margin-left should set / get negative length", () => { + testPropertyValue("margin-left", "-10px", "-10px"); + }); + + it("margin-left should set / get percent", () => { + testPropertyValue("margin-left", "10%", "10%"); + }); + + it("margin-left should set / get negative percent", () => { + testPropertyValue("margin-left", "-10%", "-10%"); + }); + + it("margin shorthand should set / get keyword", () => { + testImplicitPropertyValue( + "margin", + "auto", + "auto", + new Map([ + ["margin-top", "auto"], + ["margin-right", "auto"], + ["margin-bottom", "auto"], + ["margin-left", "auto"] + ]) + ); + }); + + it("margin shorthand should set / get value", () => { + testImplicitPropertyValue( + "margin", + "10px", + "10px", + new Map([ + ["margin-top", "10px"], + ["margin-right", "10px"], + ["margin-bottom", "10px"], + ["margin-left", "10px"] + ]) + ); + }); + + it("margin shorthand should set / get value", () => { + testImplicitPropertyValue( + "margin", + "10px 20px", + "10px 20px", + new Map([ + ["margin-top", "10px"], + ["margin-right", "20px"], + ["margin-bottom", "10px"], + ["margin-left", "20px"] + ]) + ); + }); + + it("margin shorthand should set / get value", () => { + testImplicitPropertyValue( + "margin", + "10px 20px 30px", + "10px 20px 30px", + new Map([ + ["margin-top", "10px"], + ["margin-right", "20px"], + ["margin-bottom", "30px"], + ["margin-left", "20px"] + ]) + ); + }); + + it("margin shorthand should set / get value", () => { + testImplicitPropertyValue( + "margin", + "10px 20px 30px 40px", + "10px 20px 30px 40px", + new Map([ + ["margin-top", "10px"], + ["margin-right", "20px"], + ["margin-bottom", "30px"], + ["margin-left", "40px"] + ]) + ); + }); + + it("margin shorthand should set / get value", () => { + testImplicitPropertyValue( + "margin", + "10px var(--foo)", + "10px var(--foo)", + new Map([ + ["margin-top", ""], + ["margin-right", ""], + ["margin-bottom", ""], + ["margin-left", ""] + ]) + ); + }); + + it("margin shorthand should set / get value", () => { + testImplicitPropertyValue( + "margin", + "initial", + "initial", + new Map([ + ["margin-top", "initial"], + ["margin-right", "initial"], + ["margin-bottom", "initial"], + ["margin-left", "initial"] + ]) + ); + }); + + it("padding-top should set / get length", () => { + testPropertyValue("padding-top", "0", "0px"); + }); + + it("padding-top should set / get length", () => { + testPropertyValue("padding-top", "10px", "10px"); + }); + + it("padding-top should not set / get negative length", () => { + testPropertyValue("padding-top", "-10px", ""); + }); + + it("padding-top should set / get percent", () => { + testPropertyValue("padding-top", "10%", "10%"); + }); + + it("padding-top should not set / get negative percent", () => { + testPropertyValue("padding-top", "-10%", ""); + }); + + it("padding-right should set / get length", () => { + testPropertyValue("padding-right", "0", "0px"); + }); + + it("padding-right should set / get length", () => { + testPropertyValue("padding-right", "10px", "10px"); + }); + + it("padding-right should not set / get negative length", () => { + testPropertyValue("padding-right", "-10px", ""); + }); + + it("padding-right should set / get percent", () => { + testPropertyValue("padding-right", "10%", "10%"); + }); + + it("padding-right should not set / get negative percent", () => { + testPropertyValue("padding-right", "-10%", ""); + }); + + it("padding-bottom should set / get length", () => { + testPropertyValue("padding-bottom", "0", "0px"); + }); + + it("padding-bottom should set / get length", () => { + testPropertyValue("padding-bottom", "10px", "10px"); + }); + + it("padding-bottom should not set / get negative length", () => { + testPropertyValue("padding-bottom", "-10px", ""); + }); + + it("padding-bottom should set / get percent", () => { + testPropertyValue("padding-bottom", "10%", "10%"); + }); + + it("padding-bottom should not set / get negative percent", () => { + testPropertyValue("padding-bottom", "-10%", ""); + }); + + it("padding-left should set / get length", () => { + testPropertyValue("padding-left", "0", "0px"); + }); + + it("padding-left should set / get length", () => { + testPropertyValue("padding-left", "10px", "10px"); + }); + + it("padding-left should not set / get negative length", () => { + testPropertyValue("padding-left", "-10px", ""); + }); + + it("padding-left should set / get percent", () => { + testPropertyValue("padding-left", "10%", "10%"); + }); + + it("padding-left should not set / get negative percent", () => { + testPropertyValue("padding-left", "-10%", ""); + }); + + it("padding shorthand should set / get value", () => { + testImplicitPropertyValue( + "padding", + "10px", + "10px", + new Map([ + ["padding-top", "10px"], + ["padding-right", "10px"], + ["padding-bottom", "10px"], + ["padding-left", "10px"] + ]) + ); + }); + + it("padding shorthand should set / get value", () => { + testImplicitPropertyValue( + "padding", + "10px 20px", + "10px 20px", + new Map([ + ["padding-top", "10px"], + ["padding-right", "20px"], + ["padding-bottom", "10px"], + ["padding-left", "20px"] + ]) + ); + }); + + it("padding shorthand should set / get value", () => { + testImplicitPropertyValue( + "padding", + "10px 20px 30px", + "10px 20px 30px", + new Map([ + ["padding-top", "10px"], + ["padding-right", "20px"], + ["padding-bottom", "30px"], + ["padding-left", "20px"] + ]) + ); + }); + + it("padding shorthand should set / get value", () => { + testImplicitPropertyValue( + "padding", + "10px 20px 30px 40px", + "10px 20px 30px 40px", + new Map([ + ["padding-top", "10px"], + ["padding-right", "20px"], + ["padding-bottom", "30px"], + ["padding-left", "40px"] + ]) + ); + }); + + it("padding shorthand should set / get value", () => { + testImplicitPropertyValue( + "padding", + "10px var(--foo)", + "10px var(--foo)", + new Map([ + ["padding-top", ""], + ["padding-right", ""], + ["padding-bottom", ""], + ["padding-left", ""] + ]) + ); + }); + + it("padding shorthand should set / get value", () => { + testImplicitPropertyValue( + "padding", + "initial", + "initial", + new Map([ + ["padding-top", "initial"], + ["padding-right", "initial"], + ["padding-bottom", "initial"], + ["padding-left", "initial"] + ]) + ); + }); +}); + +describe("box sizing", () => { + it("height should set / get keyword", () => { + testPropertyValue("height", "auto", "auto"); + }); + + it("height should set / get length", () => { + testPropertyValue("height", "0", "0px"); + }); + + it("height should set / get length", () => { + testPropertyValue("height", "10px", "10px"); + }); + + it("height should not set / get negative length", () => { + testPropertyValue("height", "-10px", ""); + }); + + it("height should set / get percent", () => { + testPropertyValue("height", "10%", "10%"); + }); + + it("height should not set / get negative percent", () => { + testPropertyValue("height", "-10%", ""); + }); + + it("width should set / get keyword", () => { + testPropertyValue("width", "auto", "auto"); + }); + + it("height should set / get length", () => { + testPropertyValue("width", "0", "0px"); + }); + + it("width should set / get length", () => { + testPropertyValue("width", "10px", "10px"); + }); + + it("width should not set / get negative length", () => { + testPropertyValue("width", "-10px", ""); + }); + + it("width should set / get percent", () => { + testPropertyValue("width", "10%", "10%"); + }); + + it("width should not set / get negative percent", () => { + testPropertyValue("width", "-10%", ""); + }); +}); + +describe("color", () => { + it("color should set / get color name", () => { + testPropertyValue("color", "green", "green"); + }); + + it("color should set / get hex color", () => { + testPropertyValue("color", "#008000", "rgb(0, 128, 0)"); + }); + + it("color should set / get color function", () => { + testPropertyValue("color", "rgb(0 128 0)", "rgb(0, 128, 0)"); + }); + + it("color should set / get color function", () => { + testPropertyValue( + "color", + "light-dark(#008000, #0000ff)", + "light-dark(rgb(0, 128, 0), rgb(0, 0, 255))" + ); + }); + + it("color should not should set / get invalid value", () => { + testPropertyValue( + "color", + "color-mix(in hsl, hsl(120deg 10% 20%) 0%, hsl(30deg 30% 40%) 0%)", + "" + ); + }); + + it("color should not should set / get invalid value", () => { + testPropertyValue("color", "color(srgb 0 0 0 0)", ""); + }); + + it("opacity should set / get keyword", () => { + testPropertyValue("opacity", "inherit", "inherit"); + }); + + it("opacity should set / get number", () => { + testPropertyValue("opacity", "0.5", "0.5"); + }); + + it("opacity should set / get number", () => { + testPropertyValue("opacity", ".5", "0.5"); + }); + + it("opacity should set / get number", () => { + testPropertyValue("opacity", "1.5", "1.5"); + }); + + it("opacity should set / get number", () => { + testPropertyValue("opacity", "-1", "-1"); + }); + + it("opacity should set / get percent", () => { + testPropertyValue("opacity", "50%", "50%"); + }); + + it("opacity should set / get percent", () => { + testPropertyValue("opacity", "150%", "150%"); + }); + + it("opacity should set / get percent", () => { + testPropertyValue("opacity", "-50%", "-50%"); + }); +}); + +describe("display", () => { + it("display should set / get keyword", () => { + testPropertyValue("display", "block", "block"); + }); + + it("display should set / get keyword", () => { + testPropertyValue("display", "inline", "inline"); + }); + + it("display should set / get keyword", () => { + testPropertyValue("display", "inline-block", "inline-block"); + }); + + it("display should set / get keyword", () => { + testPropertyValue("display", "flex", "flex"); + }); + + it("display should set / get keyword", () => { + testPropertyValue("display", "inline-flex", "inline-flex"); + }); + + it("display should set / get keyword", () => { + testPropertyValue("display", "grid", "grid"); + }); + + it("display should set / get keyword", () => { + testPropertyValue("display", "inline-grid", "inline-grid"); + }); + + it("display should set / get keyword", () => { + testPropertyValue("display", "flow", "block"); + }); + + it("display should set / get keyword", () => { + testPropertyValue("display", "flow-root", "flow-root"); + }); + + it("display should set / get keyword", () => { + testPropertyValue("display", "none", "none"); + }); + + it("display should set / get keyword", () => { + testPropertyValue("display", "contents", "contents"); + }); + + it("display should set / get keyword", () => { + testPropertyValue("display", "table-row", "table-row"); + }); + + it("display should set / get keyword", () => { + testPropertyValue("display", "flow list-item", "list-item"); + }); + + it("display should set / get keyword", () => { + testPropertyValue("display", "list-item flow", "list-item"); + }); + + it("display should set / get keyword", () => { + testPropertyValue("display", "block list-item", "list-item"); + }); + + it("display should not set / get keyword", () => { + testPropertyValue("display", "list-item block", "list-item"); + }); + + it("display should set / get keyword", () => { + testPropertyValue("display", "flow-root list-item", "flow-root list-item"); + }); + + it("display should not set / get keyword", () => { + testPropertyValue("display", "list-item flow-root", "flow-root list-item"); + }); + + it("display should set / get keyword", () => { + testPropertyValue("display", "block flow list-item", "list-item"); + }); + + it("display should set / get keyword", () => { + testPropertyValue("display", "block list-item flow", "list-item"); + }); + + it("display should set / get keyword", () => { + testPropertyValue("display", "block flow-root list-item", "flow-root list-item"); + }); + + it("display should set / get keyword", () => { + testPropertyValue("display", "block list-item flow-root", "flow-root list-item"); + }); + + it("display should set / get keyword", () => { + testPropertyValue("display", "flow block list-item", "list-item"); + }); + + it("display should set / get keyword", () => { + testPropertyValue("display", "flow list-item block", "list-item"); + }); + + it("display should set / get keyword", () => { + testPropertyValue("display", "flow-root block list-item", "flow-root list-item"); + }); + + it("display should set / get keyword", () => { + testPropertyValue("display", "flow-root list-item block", "flow-root list-item"); + }); + + it("display should not set / get keyword", () => { + testPropertyValue("display", "list-item block flow", "list-item"); + }); + + it("display should not set / get keyword", () => { + testPropertyValue("display", "list-item flow block", "list-item"); + }); + + it("display should not set / get keyword", () => { + testPropertyValue("display", "list-item block flow-root", "flow-root list-item"); + }); + + it("display should not set / get keyword", () => { + testPropertyValue("display", "list-item flow-root block", "flow-root list-item"); + }); + + it("display should set / get keyword", () => { + testPropertyValue("display", "inline flow list-item", "inline list-item"); + }); + + it("display should set / get keyword", () => { + testPropertyValue("display", "inline flow-root list-item", "inline flow-root list-item"); + }); + + it("display should set / get keyword", () => { + testPropertyValue("display", "run-in flow list-item", "run-in list-item"); + }); + + it("display should set / get keyword", () => { + testPropertyValue("display", "run-in flow-root list-item", "run-in flow-root list-item"); + }); + + it("display should set / get keyword", () => { + testPropertyValue("display", "block flow", "block"); + }); + + it("display should set / get keyword", () => { + testPropertyValue("display", "flow block", "block"); + }); + + it("display should set / get keyword", () => { + testPropertyValue("display", "block flow-root", "flow-root"); + }); + + it("display should set / get keyword", () => { + testPropertyValue("display", "block flex", "flex"); + }); + + it("display should set / get keyword", () => { + testPropertyValue("display", "block ruby", "block ruby"); + }); + + it("display should set / get keyword", () => { + testPropertyValue("display", "inline flow", "inline"); + }); + + it("display should set / get keyword", () => { + testPropertyValue("display", "flow inline", "inline"); + }); + + it("display should set / get keyword", () => { + testPropertyValue("display", "inline flow-root", "inline-block"); + }); + + it("display should set / get keyword", () => { + testPropertyValue("display", "inline flex", "inline-flex"); + }); + + it("display should set / get keyword", () => { + testPropertyValue("display", "inline ruby", "ruby"); + }); + + it("display should set / get keyword", () => { + testPropertyValue("display", "run-in flow", "run-in"); + }); + + it("display should set / get keyword", () => { + testPropertyValue("display", "flow run-in", "run-in"); + }); + + it("display should set / get keyword", () => { + testPropertyValue("display", "run-in flow-root", "run-in flow-root"); + }); + + it("display should set / get keyword", () => { + testPropertyValue("display", "run-in flex", "run-in flex"); + }); + + it("display should set / get keyword", () => { + testPropertyValue("display", "run-in ruby", "run-in ruby"); + }); +}); + +describe("flex box", () => { + it("flex-grow should set / get number", () => { + testPropertyValue("flex-grow", ".5", "0.5"); + }); + + it("flex-grow should not set / get negative number", () => { + testPropertyValue("flex-grow", "-1", ""); + }); + + it("flex-shrink should set / get number", () => { + testPropertyValue("flex-shrink", ".5", "0.5"); + }); + + it("flex-shrink should not set / get negative number", () => { + testPropertyValue("flex-shrink", "-1", ""); + }); + + it("flex-basis should set / get keyword", () => { + testPropertyValue("flex-basis", "content", "content"); + }); + + it("flex-basis should not set / get length", () => { + testPropertyValue("flex-basis", "10px", "10px"); + }); + + it("flex-basis should not set / get length", () => { + testPropertyValue("flex-basis", "0", "0px"); + }); + + it("flex-basis should not set / get percent", () => { + testPropertyValue("flex-basis", "10%", "10%"); + }); + + it("flex-basis should not set / get percent", () => { + testPropertyValue("flex-basis", "0%", "0%"); + }); + + it("flex should set / get keyword", () => { + testPropertyValue("flex", "none", "0 0 auto"); + }); + + it("flex should set / get keyword", () => { + testPropertyValue("flex", "auto", "1 1 auto"); + }); + + it("flex should set / get keyword", () => { + testPropertyValue("flex", "initial", "initial"); + }); + + it("flex should set / get keyword", () => { + testPropertyValue("flex", "unset", "unset"); + }); + + it("flex shorthand should not set / get longhand value", () => { + testPropertyValue("flex", "2 1 3", ""); + }); + + it("flex shorthand should not set / get longhand value", () => { + testPropertyValue("flex", "2 1 calc(3)", ""); + }); + + it("flex shorthand should set / get longhand value", () => { + testPropertyValue("flex", "2", "2 1 0%"); + }); + + it("flex shorthand should set / get longhand value", () => { + testPropertyValue("flex", "10%", "1 1 10%"); + }); + + it("flex shorthand should set / get longhand value", () => { + testPropertyValue("flex", "2 10px", "2 1 10px"); + }); + + it("flex shorthand should set / get longhand value", () => { + testPropertyValue("flex", "2 3", "2 3 0%"); + }); + + it("flex shorthand should set / get longhand value", () => { + testPropertyValue("flex", "2 3 10px", "2 3 10px"); + }); + + it("flex shorthand should set / get longhand value", () => { + testImplicitPropertyValue( + "flex", + "2 var(--foo) 10px", + "2 var(--foo) 10px", + new Map([ + ["flex-grow", ""], + ["flex-shrink", ""], + ["flex-basis", ""] + ]) + ); + }); + + it("flex shorthand should set / get longhand value", () => { + testImplicitPropertyValue( + "flex", + "calc(2px * 3)", + "1 1 calc(6px)", + new Map([ + ["flex-grow", "1"], + ["flex-shrink", "1"], + ["flex-basis", "calc(6px)"] + ]) + ); + }); + + it("flex shorthand should set / get longhand value", () => { + testImplicitPropertyValue( + "flex", + "calc(2 * 3)", + "calc(6) 1 0%", + new Map([ + ["flex-grow", "calc(6)"], + ["flex-shrink", "1"], + ["flex-basis", "0%"] + ]) + ); + }); + + it("flex shorthand should set / get longhand value", () => { + testImplicitPropertyValue( + "flex", + "initial", + "initial", + new Map([ + ["flex-grow", "initial"], + ["flex-shrink", "initial"], + ["flex-basis", "initial"] + ]) + ); + }); +}); + +describe("font", () => { + it("font-style should set / get keyword", () => { + testPropertyValue("font-style", "italic", "italic"); + }); + + it("font-variant should set / get keyword", () => { + testPropertyValue("font-variant", "normal", "normal"); + }); + + it("font-variant should set / get keyword", () => { + testPropertyValue("font-variant", "none", "none"); + }); + + it("font-variant should set / get keyword", () => { + testPropertyValue("font-variant", "none", "none"); + }); + + it("font-variant should set / get keyword", () => { + testPropertyValue("font-variant", "common-ligatures", "common-ligatures"); + }); + + it("font-variant should set / get keyword", () => { + testPropertyValue("font-variant", "no-common-ligatures", "no-common-ligatures"); + }); + + it("font-variant should set / get keyword", () => { + testPropertyValue("font-variant", "small-caps", "small-caps"); + }); + + it("font-variant should set / get keyword", () => { + testPropertyValue("font-variant", "stylistic(flowing)", "stylistic(flowing)"); + }); + + it("font-variant should set / get keyword", () => { + testPropertyValue( + "font-variant", + "stylistic(flowing) historical-forms styleset(flowing) character-variant(flowing) swash(flowing) ornaments(flowing) annotation(flowing)", + "stylistic(flowing) historical-forms styleset(flowing) character-variant(flowing) swash(flowing) ornaments(flowing) annotation(flowing)" + ); + }); + + it("font-variant should set / get keyword", () => { + testPropertyValue("font-variant", "jis78", "jis78"); + }); + + it("font-variant should set / get keyword", () => { + testPropertyValue("font-variant", "ruby", "ruby"); + }); + + it("font-variant should set / get keyword", () => { + testPropertyValue("font-variant", "sub", "sub"); + }); + + it("font-variant should set / get keyword", () => { + testPropertyValue("font-variant", "super", "super"); + }); + + it("font-variant should not set / get invalid keywords", () => { + testPropertyValue("font-variant", "normal none", ""); + }); + + it("font-variant should not set / get invalid keywords", () => { + testPropertyValue("font-variant", "normal small-caps", ""); + }); + + it("font-variant should not set / get invalid keywords", () => { + testPropertyValue("font-variant", "none small-caps", ""); + }); + + it("font-weight should set / get keyword", () => { + testPropertyValue("font-weight", "bold", "bold"); + }); + + it("font-weight should set / get number", () => { + testPropertyValue("font-weight", "400", "400"); + }); + + it("font-weight should not set / get number greater than 1000", () => { + testPropertyValue("font-weight", "1001", ""); + }); + + it("font-weight should not set / get negative number", () => { + testPropertyValue("font-weight", "-1", ""); + }); + + it("font-size should set / get keyword", () => { + testPropertyValue("font-size", "medium", "medium"); + }); + + it("font-size should set / get keyword", () => { + testPropertyValue("font-size", "larger", "larger"); + }); + + it("font-size should set / get length", () => { + testPropertyValue("font-size", "1em", "1em"); + }); + + it("font-size not should set / get negative length", () => { + testPropertyValue("font-size", "-1em", ""); + }); + + it("font-size should set / get percent", () => { + testPropertyValue("font-size", "90%", "90%"); + }); + + it("font-size should not set / get negative percent", () => { + testPropertyValue("font-size", "-10%", ""); + }); + + it("line-height should set / get keyword", () => { + testPropertyValue("line-height", "normal", "normal"); + }); + + it("line-height should set / get number", () => { + testPropertyValue("line-height", "1.2", "1.2"); + }); + + it("line-height should not set / get negative number", () => { + testPropertyValue("line-height", "-1", ""); + }); + + it("line-height should set / get length", () => { + testPropertyValue("line-height", "10px", "10px"); + }); + + it("line-height should not set / get negative length", () => { + testPropertyValue("line-height", "-10px", ""); + }); + + it("line-height should set / get percent", () => { + testPropertyValue("line-height", "10%", "10%"); + }); + + it("line-height should not set / get negative percent", () => { + testPropertyValue("line-height", "-10%", ""); + }); + + it("font-family should set / get keyword", () => { + testPropertyValue("font-family", "sans-serif", "sans-serif"); + }); + + it("font-family should set / get keyword", () => { + testPropertyValue("font-family", '"sans-serif"', '"sans-serif"'); + }); + + it("font-family should set / get family name", () => { + testPropertyValue("font-family", "Times", "Times"); + }); + + it("font-family should set / get quoted family name", () => { + testPropertyValue("font-family", '"Times New Roman"', '"Times New Roman"'); + }); + + it("font-family should set / get family values", () => { + testPropertyValue( + "font-family", + 'Times, "Times New Roman", Georgia, serif', + 'Times, "Times New Roman", Georgia, serif' + ); + }); + + it("font-family should set / get family values", () => { + testPropertyValue("font-family", "Times\\ New Roman, serif", '"Times New Roman", serif'); + }); + + it("font-family should set / get family values", () => { + testPropertyValue("font-family", '"Times\\ New Roman", serif', '"Times New Roman", serif'); + }); + + it("font-family should set / get family values", () => { + testPropertyValue( + "font-family", + '"Gill Sans Extrabold", sans-serif', + '"Gill Sans Extrabold", sans-serif' + ); + }); + + it("font-family should set / get family values", () => { + testPropertyValue( + "font-family", + '"Goudy Bookletter 1911", sans-serif', + '"Goudy Bookletter 1911", sans-serif' + ); + }); + + it("font-family should not set / get invalid family values", () => { + testPropertyValue("font-family", "Goudy Bookletter 1911, sans-serif", ""); + }); + + it("font-family should not set / get invalid family values", () => { + testPropertyValue("font-family", "Red/Black, sans-serif", ""); + }); + + it("font-family should not set / get invalid family values", () => { + testPropertyValue("font-family", '"Lucida" Grande, sans-serif', ""); + }); + + it("font-family should not set / get invalid family values", () => { + testPropertyValue("font-family", 'Lucida "Grande", sans-serif', ""); + }); + + it("font-family should not set / get invalid family values", () => { + testPropertyValue("font-family", "Ahem!, sans-serif", ""); + }); + + it("font-family should not set / get invalid family values", () => { + testPropertyValue("font-family", "test@foo, sans-serif", ""); + }); + + it("font-family should not set / get invalid family values", () => { + testPropertyValue("font-family", "#POUND, sans-serif", ""); + }); + + it("font-family should not set / get invalid family values", () => { + testPropertyValue("font-family", "Hawaii 5-0, sans-serif", ""); + }); + + it("font-family should set / get family values", () => { + testPropertyValue("font-family", "generic(fangsong)", "generic(fangsong)"); + }); + + it("font-family should set / get family values", () => { + testPropertyValue("font-family", "generic(kai)", "generic(kai)"); }); - it("flex-grow works", () => { - const style = new CSSStyleDeclaration(); - style.setProperty("flex-grow", 2); - assert.strictEqual(style.getPropertyValue("flex-grow"), "2"); - assert.strictEqual(style.cssText, "flex-grow: 2;"); + it("font-family should set / get family values", () => { + testPropertyValue("font-family", "generic(khmer-mul)", "generic(khmer-mul)"); }); - it("flex-basis works", () => { - const style = new CSSStyleDeclaration(); - style.setProperty("flex-basis", 0); - assert.strictEqual(style.getPropertyValue("flex-basis"), "0px"); - style.setProperty("flex-basis", "250px"); - assert.strictEqual(style.getPropertyValue("flex-basis"), "250px"); - style.setProperty("flex-basis", "10em"); - assert.strictEqual(style.getPropertyValue("flex-basis"), "10em"); - style.setProperty("flex-basis", "30%"); - assert.strictEqual(style.getPropertyValue("flex-basis"), "30%"); - assert.strictEqual(style.cssText, "flex-basis: 30%;"); + it("font-family should set / get family values", () => { + testPropertyValue("font-family", "generic(nastaliq)", "generic(nastaliq)"); }); - it("shorthand flex works", () => { - const style = new CSSStyleDeclaration(); - style.setProperty("flex", "none"); - assert.strictEqual(style.getPropertyValue("flex-grow"), "0"); - assert.strictEqual(style.getPropertyValue("flex-shrink"), "0"); - assert.strictEqual(style.getPropertyValue("flex-basis"), "auto"); - style.removeProperty("flex"); - style.removeProperty("flex-basis"); - style.setProperty("flex", "auto"); - assert.strictEqual(style.getPropertyValue("flex-grow"), "1"); - assert.strictEqual(style.getPropertyValue("flex-shrink"), "1"); - assert.strictEqual(style.getPropertyValue("flex-basis"), "auto"); - style.removeProperty("flex"); - style.setProperty("flex", "0 1 250px"); - assert.strictEqual(style.getPropertyValue("flex"), "0 1 250px"); - assert.strictEqual(style.getPropertyValue("flex-grow"), "0"); - assert.strictEqual(style.getPropertyValue("flex-shrink"), "1"); - assert.strictEqual(style.getPropertyValue("flex-basis"), "250px"); - style.removeProperty("flex"); - style.setProperty("flex", "0 0 auto"); - assert.strictEqual(style.getPropertyValue("flex"), "0 0 auto"); - assert.strictEqual(style.getPropertyValue("flex-grow"), "0"); - assert.strictEqual(style.getPropertyValue("flex-shrink"), "0"); - assert.strictEqual(style.getPropertyValue("flex-basis"), "auto"); - style.removeProperty("flex"); - style.setProperty("flex", "0 auto"); - assert.strictEqual(style.getPropertyValue("flex"), "0 1 auto"); - assert.strictEqual(style.getPropertyValue("flex-grow"), "0"); - assert.strictEqual(style.getPropertyValue("flex-shrink"), "1"); - assert.strictEqual(style.getPropertyValue("flex-basis"), "auto"); - style.removeProperty("flex"); - style.setProperty("flex", "2"); - assert.strictEqual(style.getPropertyValue("flex-grow"), "2"); - assert.strictEqual(style.getPropertyValue("flex-shrink"), "1"); - assert.strictEqual(style.getPropertyValue("flex-basis"), "0%"); - style.removeProperty("flex"); - style.setProperty("flex", "20%"); - assert.strictEqual(style.getPropertyValue("flex-grow"), "1"); - assert.strictEqual(style.getPropertyValue("flex-shrink"), "1"); - assert.strictEqual(style.getPropertyValue("flex-basis"), "20%"); - style.removeProperty("flex"); - style.setProperty("flex", "2 2"); - assert.strictEqual(style.getPropertyValue("flex-grow"), "2"); - assert.strictEqual(style.getPropertyValue("flex-shrink"), "2"); - assert.strictEqual(style.getPropertyValue("flex-basis"), "0%"); - style.removeProperty("flex"); + it("font-family should not set / get invalid family values", () => { + testPropertyValue("font-family", "generic(foo)", ""); }); - it("font-size get a valid value", () => { - const style = new CSSStyleDeclaration(); - const invalidValue = "1r5px"; - style.cssText = "font-size: 15px"; - assert.strictEqual(1, style.length); - style.cssText = `font-size: ${invalidValue}`; - assert.strictEqual(0, style.length); - assert.strictEqual(undefined, style[0]); + it("font shorthand should set / get values", () => { + testImplicitPropertyValue( + "font", + 'normal medium Times, "Times New Roman", Georgia, serif', + 'medium Times, "Times New Roman", Georgia, serif', + new Map([ + ["font-style", "normal"], + ["font-variant", "normal"], + ["font-weight", "normal"], + ["font-size", "medium"], + ["line-height", "normal"], + ["font-family", 'Times, "Times New Roman", Georgia, serif'] + ]) + ); }); - it("getPropertyValue for custom properties in cssText", () => { - const style = new CSSStyleDeclaration(); - style.cssText = "--foo: red"; + it("font shorthand should set / get values", () => { + testImplicitPropertyValue( + "font", + "normal medium Gill Sans Extrabold, sans-serif", + 'medium "Gill Sans Extrabold", sans-serif', + new Map([ + ["font-style", "normal"], + ["font-variant", "normal"], + ["font-weight", "normal"], + ["font-size", "medium"], + ["line-height", "normal"], + ["font-family", '"Gill Sans Extrabold", sans-serif'] + ]) + ); + }); - assert.strictEqual(style.getPropertyValue("--foo"), "red"); + it("font shorthand should set / get values", () => { + testImplicitPropertyValue( + "font", + 'normal medium "Goudy Bookletter 1911", sans-serif', + 'medium "Goudy Bookletter 1911", sans-serif', + new Map([ + ["font-style", "normal"], + ["font-variant", "normal"], + ["font-weight", "normal"], + ["font-size", "medium"], + ["line-height", "normal"], + ["font-family", '"Goudy Bookletter 1911", sans-serif'] + ]) + ); }); - it("getPropertyValue for custom properties with setProperty", () => { - const style = new CSSStyleDeclaration(); - style.setProperty("--bar", "blue"); + it("font shorthand should set / get values", () => { + testImplicitPropertyValue( + "font", + "normal medium generic(fangsong)", + "medium generic(fangsong)", + new Map([ + ["font-style", "normal"], + ["font-variant", "normal"], + ["font-weight", "normal"], + ["font-size", "medium"], + ["line-height", "normal"], + ["font-family", "generic(fangsong)"] + ]) + ); + }); - assert.strictEqual(style.getPropertyValue("--bar"), "blue"); + it("font shorthand should not set / get invalid values", () => { + testImplicitPropertyValue( + "font", + "normal medium Goudy Bookletter 1911, sans-serif", + "", + new Map([ + ["font-style", ""], + ["font-variant", ""], + ["font-weight", ""], + ["font-size", ""], + ["line-height", ""], + ["font-family", ""] + ]) + ); }); - it("getPropertyValue for custom properties with object setter", () => { - const style = new CSSStyleDeclaration(); - style["--baz"] = "yellow"; + it("font shorthand should not set / get invalid values", () => { + testImplicitPropertyValue( + "font", + "normal medium Red/Black, sans-serif", + "", + new Map([ + ["font-style", ""], + ["font-variant", ""], + ["font-weight", ""], + ["font-size", ""], + ["line-height", ""], + ["font-family", ""] + ]) + ); + }); - assert.strictEqual(style.getPropertyValue("--baz"), ""); + it("font shorthand should not set / get invalid values", () => { + testImplicitPropertyValue( + "font", + 'normal medium "Lucida" Grande, sans-serif', + "", + new Map([ + ["font-style", ""], + ["font-variant", ""], + ["font-weight", ""], + ["font-size", ""], + ["line-height", ""], + ["font-family", ""] + ]) + ); }); - it("custom properties are case-sensitive", () => { - const style = new CSSStyleDeclaration(); - style.cssText = "--fOo: purple"; + it("font shorthand should not set / get invalid values", () => { + testImplicitPropertyValue( + "font", + 'normal medium Lucida "Grande", sans-serif', + "", + new Map([ + ["font-style", ""], + ["font-variant", ""], + ["font-weight", ""], + ["font-size", ""], + ["line-height", ""], + ["font-family", ""] + ]) + ); + }); - assert.strictEqual(style.getPropertyValue("--foo"), ""); - assert.strictEqual(style.getPropertyValue("--fOo"), "purple"); + it("font shorthand should not set / get invalid values", () => { + testImplicitPropertyValue( + "font", + "normal medium Ahem!, sans-serif", + "", + new Map([ + ["font-style", ""], + ["font-variant", ""], + ["font-weight", ""], + ["font-size", ""], + ["line-height", ""], + ["font-family", ""] + ]) + ); }); - for (const property of [ - "width", - "height", - "margin", - "margin-top", - "bottom", - "right", - "padding" - ]) { - it(`supports calc for ${property}`, () => { - const style = new CSSStyleDeclaration(); - style.setProperty(property, "calc(100% - 100px)"); - assert.strictEqual(style.getPropertyValue(property), "calc(100% - 100px)"); - }); - } + it("font shorthand should not set / get invalid values", () => { + testImplicitPropertyValue( + "font", + "normal medium test@foo, sans-serif", + "", + new Map([ + ["font-style", ""], + ["font-variant", ""], + ["font-weight", ""], + ["font-size", ""], + ["line-height", ""], + ["font-family", ""] + ]) + ); + }); - it("supports nested calc", () => { - const style = new CSSStyleDeclaration(); - style.setProperty("width", "calc(100% - calc(200px - 100px))"); - assert.strictEqual(style.getPropertyValue("width"), "calc(100% - 100px)"); + it("font shorthand should not set / get invalid values", () => { + testImplicitPropertyValue( + "font", + "normal medium #POUND, sans-serif", + "", + new Map([ + ["font-style", ""], + ["font-variant", ""], + ["font-weight", ""], + ["font-size", ""], + ["line-height", ""], + ["font-family", ""] + ]) + ); }); - it("supports nested calc", () => { - const style = new CSSStyleDeclaration(); - style.setProperty("width", "calc(100% * calc(2 / 3))"); - assert.strictEqual(style.getPropertyValue("width"), "calc(66.6667%)"); + it("font shorthand should not set / get invalid values", () => { + testImplicitPropertyValue( + "font", + "normal medium Hawaii 5-0, sans-serif", + "", + new Map([ + ["font-style", ""], + ["font-variant", ""], + ["font-weight", ""], + ["font-size", ""], + ["line-height", ""], + ["font-family", ""] + ]) + ); }); - it("supports var", () => { - const style = new CSSStyleDeclaration(); - style.setProperty("width", "var(--foo)"); - assert.strictEqual(style.getPropertyValue("width"), "var(--foo)"); + it("font shorthand should set / get values", () => { + testImplicitPropertyValue( + "font", + 'italic bold medium/1.2 Times, "Times New Roman", Georgia, serif', + 'italic bold medium / 1.2 Times, "Times New Roman", Georgia, serif', + new Map([ + ["font-style", "italic"], + ["font-variant", "normal"], + ["font-weight", "bold"], + ["font-size", "medium"], + ["line-height", "1.2"], + ["font-family", 'Times, "Times New Roman", Georgia, serif'] + ]) + ); }); - it("supports var with fallback", () => { - const style = new CSSStyleDeclaration(); - style.setProperty("width", "var(--foo, 100px)"); - assert.strictEqual(style.getPropertyValue("width"), "var(--foo, 100px)"); + it("font shorthand should set / get values", () => { + testImplicitPropertyValue( + "font", + 'italic bold calc(3em/2)/1.2 Times, "Times New Roman", Georgia, serif', + 'italic bold calc(1.5em) / 1.2 Times, "Times New Roman", Georgia, serif', + new Map([ + ["font-style", "italic"], + ["font-variant", "normal"], + ["font-weight", "bold"], + ["font-size", "calc(1.5em)"], + ["line-height", "1.2"], + ["font-family", 'Times, "Times New Roman", Georgia, serif'] + ]) + ); }); - it("supports var with var fallback", () => { - const style = new CSSStyleDeclaration(); - style.setProperty("width", "var(--foo, var(--bar))"); - assert.strictEqual(style.getPropertyValue("width"), "var(--foo, var(--bar))"); + it("font shorthand should set / get values", () => { + testImplicitPropertyValue( + "font", + 'italic bold var(--foo)/1.2 Times, "Times New Roman", Georgia, serif', + 'italic bold var(--foo)/1.2 Times, "Times New Roman", Georgia, serif', + new Map([ + ["font-style", ""], + ["font-variant", ""], + ["font-weight", ""], + ["font-size", ""], + ["line-height", ""], + ["font-family", ""] + ]) + ); }); - it("supports calc with var inside", () => { - const style = new CSSStyleDeclaration(); - style.setProperty("width", "calc(100% - var(--foo))"); - assert.strictEqual(style.getPropertyValue("width"), "calc(100% - var(--foo))"); + it("font shorthand should set / get values", () => { + testImplicitPropertyValue( + "font", + "initial", + "initial", + new Map([ + ["font-style", "initial"], + ["font-variant", "initial"], + ["font-weight", "initial"], + ["font-size", "initial"], + ["line-height", "initial"], + ["font-family", "initial"] + ]) + ); }); +}); - it("supports var with calc inside", () => { - const style = new CSSStyleDeclaration(); - style.setProperty("width", "var(--foo, calc(var(--bar) + 3px))"); - assert.strictEqual(style.getPropertyValue("width"), "var(--foo, calc(var(--bar) + 3px))"); +describe("logical", () => { + it("clear should set / get keyword", () => { + testPropertyValue("clear", "left", "left"); }); - it("supports color var", () => { - const style = new CSSStyleDeclaration(); - style.setProperty("color", "var(--foo)"); - assert.strictEqual(style.getPropertyValue("color"), "var(--foo)"); + it("clear should set / get keyword", () => { + testPropertyValue("clear", "none", "none"); }); - it("should not normalize if var() is included", () => { - const style = new CSSStyleDeclaration(); - style.setProperty("line-height", "calc( /* comment */ 100% - calc(var(--foo) *2 ))"); - assert.strictEqual( - style.getPropertyValue("line-height"), - "calc( /* comment */ 100% - calc(var(--foo) *2 ))" - ); + it("float should set / get keyword", () => { + testPropertyValue("float", "left", "left"); }); - it("supports abs", () => { - const style = new CSSStyleDeclaration(); - style.setProperty("line-height", "abs(1 - 2 * 3)"); - assert.strictEqual(style.getPropertyValue("line-height"), "calc(5)"); + it("float should set / get keyword", () => { + testPropertyValue("float", "none", "none"); }); +}); - it("supports abs inside calc", () => { - const style = new CSSStyleDeclaration(); - style.setProperty("line-height", "calc(abs(1) + abs(2))"); - assert.strictEqual(style.getPropertyValue("line-height"), "calc(3)"); +describe("masking", () => { + it("clip should set / get keyword", () => { + testPropertyValue("clip", "auto", "auto"); }); - it("supports sign", () => { - const style = new CSSStyleDeclaration(); - style.setProperty("line-height", "sign(.1)"); - assert.strictEqual(style.getPropertyValue("line-height"), "calc(1)"); + it("clip should set / get legacy ", () => { + testPropertyValue("clip", "rect(0, 10px, 2cm, 40EM)", "rect(0px, 10px, 2cm, 40em)"); }); +}); - it("supports sign inside calc", () => { - const style = new CSSStyleDeclaration(); - style.setProperty("line-height", "calc(sign(.1) + sign(.2))"); - assert.strictEqual(style.getPropertyValue("line-height"), "calc(2)"); +describe("positioning", () => { + it("bottom should set / get keyword", () => { + testPropertyValue("bottom", "auto", "auto"); }); - it("no-op for setting undefined to width", () => { - const style = new CSSStyleDeclaration(); - style.setProperty("width", "10px"); - assert.strictEqual(style.getPropertyValue("width"), "10px"); + it("bottom should set / get length", () => { + testPropertyValue("bottom", "10px", "10px"); + }); - style.setProperty("width", undefined); - assert.strictEqual(style.getPropertyValue("width"), "10px"); + it("bottom should set / get percent", () => { + testPropertyValue("bottom", "10%", "10%"); + }); - style.width = undefined; - assert.strictEqual(style.getPropertyValue("width"), "10px"); + it("left should set / get keyword", () => { + testPropertyValue("left", "auto", "auto"); }); - it("shorthand serialization with shorthand and longhands mixed", () => { - const style = new CSSStyleDeclaration(); - style.cssText = "background-color: blue; background: red !important; background-color: green;"; - assert.strictEqual(style.cssText, "background: red !important;"); + it("left should set / get length", () => { + testPropertyValue("left", "10px", "10px"); }); - it("shorthand serialization", () => { - const style = new CSSStyleDeclaration(); - style.cssText = - "border-top: 1px; border-right: 1px; border-bottom: 1px; border-left: 1px; border-image: none;"; - assert.strictEqual(style.cssText, "border: 1px;"); + it("left should set / get percent", () => { + testPropertyValue("left", "10%", "10%"); }); - it("shorthand serialization", () => { - const style = new CSSStyleDeclaration(); - style.cssText = "border-width: 1px;"; - assert.strictEqual(style.cssText, "border-width: 1px;"); + it("right should set / get keyword", () => { + testPropertyValue("right", "auto", "auto"); }); - it("shorthand serialization", () => { - const style = new CSSStyleDeclaration(); - style.cssText = "border: 1px; border-top: 1px !important;"; - assert.strictEqual( - style.cssText, - "border-right: 1px; border-bottom: 1px; border-left: 1px; border-image: none; border-top: 1px !important;" - ); + it("right should set / get length", () => { + testPropertyValue("right", "10px", "10px"); }); - it("set cssText as none", () => { - const style = new CSSStyleDeclaration(); - style.cssText = "border: none;"; - assert.strictEqual(style.cssText, "border: medium;"); + it("right should set / get percent", () => { + testPropertyValue("right", "10%", "10%"); }); - it("invalid cssText should be parsed", () => { - const style = new CSSStyleDeclaration(); - style.cssText = "color: red; }"; - assert.strictEqual(style.cssText, "color: red;"); + it("top should set / get keyword", () => { + testPropertyValue("top", "auto", "auto"); }); - it("single value flex with CSS-wide keyword", () => { - const style = new CSSStyleDeclaration(); - style.cssText = "flex: initial;"; - assert.strictEqual(style.flex, "initial"); - assert.strictEqual(style.flexGrow, "initial"); - assert.strictEqual(style.flexShrink, "initial"); - assert.strictEqual(style.flexBasis, "initial"); - assert.strictEqual(style.cssText, "flex: initial;"); + it("top should set / get length", () => { + testPropertyValue("top", "10px", "10px"); }); - it("single value flex with non-CSS-wide value", () => { - const style = new CSSStyleDeclaration(); - style.cssText = "flex: 0;"; - assert.strictEqual(style.flex, "0 1 0%"); - assert.strictEqual(style.flexGrow, "0"); - assert.strictEqual(style.flexShrink, "1"); - assert.strictEqual(style.flexBasis, "0%"); - assert.strictEqual(style.cssText, "flex: 0 1 0%;"); + it("top should set / get percent", () => { + testPropertyValue("top", "10%", "10%"); }); +}); - it("multiple values flex with CSS-wide keyword", () => { - const style = new CSSStyleDeclaration(); - style.cssText = "flex: initial; flex-basis: initial; flex-shrink: initial;"; - assert.strictEqual(style.flex, "initial"); - assert.strictEqual(style.flexGrow, "initial"); - assert.strictEqual(style.flexShrink, "initial"); - assert.strictEqual(style.flexBasis, "initial"); - assert.strictEqual(style.cssText, "flex: initial;"); +describe("user interface", () => { + it("outline-color should set / get color name", () => { + testPropertyValue("outline-color", "green", "green"); }); - it("multiple values flex with CSS-wide keywords and non-CSS-wide value", () => { - const style = new CSSStyleDeclaration(); - style.cssText = "flex: initial; flex-shrink: 0;"; - assert.strictEqual(style.flex, ""); - assert.strictEqual(style.flexGrow, "initial"); - assert.strictEqual(style.flexShrink, "0"); - assert.strictEqual(style.flexBasis, "initial"); - assert.strictEqual(style.cssText, "flex-grow: initial; flex-basis: initial; flex-shrink: 0;"); + it("outline-color should set / get hex color", () => { + testPropertyValue("outline-color", "#008000", "rgb(0, 128, 0)"); }); - it("multiple values flex with CSS-wide and two non-CSS-wide-keyword values", () => { - const style = new CSSStyleDeclaration(); - style.cssText = "flex: initial; flex-basis: 0; flex-shrink: 2;"; - assert.strictEqual(style.flex, ""); - assert.strictEqual(style.flexGrow, "initial"); - assert.strictEqual(style.flexShrink, "2"); - assert.strictEqual(style.flexBasis, "0px"); - assert.strictEqual(style.cssText, "flex-grow: initial; flex-basis: 0px; flex-shrink: 2;"); + it("outline-color should set / get color function", () => { + testPropertyValue("outline-color", "rgb(0 128 0)", "rgb(0, 128, 0)"); }); }); /* regression tests */ describe("regression test for https://github.com/jsdom/jsdom/issues/3833", () => { it("should set global value unset", () => { - const style = new CSSStyleDeclaration(); + const style = new CSSStyleDeclaration(window); style.setProperty("width", "10px"); assert.strictEqual(style.getPropertyValue("width"), "10px"); @@ -1477,29 +3903,26 @@ describe("regression test for https://github.com/jsdom/jsdom/issues/3833", () => describe("regression test for https://github.com/jsdom/jsdom/issues/3878", () => { it("should not set custom properties twice", () => { - const style = new CSSStyleDeclaration(); + const style = new CSSStyleDeclaration(window); style.setProperty("--foo", 0); style.setProperty("--foo", 1); assert.strictEqual(style.length, 1); assert.strictEqual(style.item(0), "--foo"); assert.strictEqual(style.item(1), ""); - assert.deepEqual(JSON.parse(JSON.stringify(style)), { - 0: "--foo" - }); assert.strictEqual(style.getPropertyValue("--foo"), "1"); }); }); describe("regression test for https://github.com/jsdom/cssstyle/issues/129", () => { it("should set stringified value", () => { - const style = new CSSStyleDeclaration(); + const style = new CSSStyleDeclaration(window); style.setProperty("--foo", true); assert.strictEqual(style.getPropertyValue("--foo"), "true"); }); it("throws for setting Symbol", () => { - const style = new CSSStyleDeclaration(); + const style = new CSSStyleDeclaration(window); assert.throws( () => style.setProperty("width", Symbol("foo")), (e) => { @@ -1523,21 +3946,21 @@ describe("regression test for https://github.com/jsdom/cssstyle/issues/129", () describe("regression test for https://github.com/jsdom/cssstyle/issues/70", () => { it('returns empty string for "webkit-*", without leading "-"', () => { - const style = new CSSStyleDeclaration(); + const style = new CSSStyleDeclaration(window); style.cssText = "background-color: green; webkit-transform: scale(3);"; assert.strictEqual(style.backgroundColor, "green"); assert.strictEqual(style.webkitTransform, ""); }); it('should set/get value for "-webkit-*"', () => { - const style = new CSSStyleDeclaration(); + const style = new CSSStyleDeclaration(window); style.cssText = "background-color: green; -webkit-transform: scale(3);"; assert.strictEqual(style.backgroundColor, "green"); assert.strictEqual(style.webkitTransform, "scale(3)"); }); it('returns undefined for unknown "-webkit-*"', () => { - const style = new CSSStyleDeclaration(); + const style = new CSSStyleDeclaration(window); style.cssText = "background-color: green; -webkit-foo: scale(3);"; assert.strictEqual(style.backgroundColor, "green"); assert.strictEqual(style.webkitFoo, undefined); @@ -1546,7 +3969,7 @@ describe("regression test for https://github.com/jsdom/cssstyle/issues/70", () = describe("regression test for https://github.com/jsdom/cssstyle/issues/124", () => { it("no-op when setting undefined to border", () => { - const style = new CSSStyleDeclaration(); + const style = new CSSStyleDeclaration(window); style.border = "1px solid green"; assert.strictEqual(style.border, "1px solid green"); style.border = undefined; @@ -1554,7 +3977,7 @@ describe("regression test for https://github.com/jsdom/cssstyle/issues/124", () }); it("no-op when setting undefined to borderWidth", () => { - const style = new CSSStyleDeclaration(); + const style = new CSSStyleDeclaration(window); style.borderWidth = "1px"; assert.strictEqual(style.borderWidth, "1px"); style.border = undefined; @@ -1577,7 +4000,7 @@ describe("regression test for https://github.com/jsdom/cssstyle/issues/212", () "ui-monospace", "ui-rounded" ]; - const style = new CSSStyleDeclaration(); + const style = new CSSStyleDeclaration(window); for (const keyword of keywords) { style.fontFamily = keyword; assert.strictEqual(style.fontFamily, keyword); @@ -1591,7 +4014,7 @@ describe("regression test for https://github.com/jsdom/cssstyle/issues/212", () "generic(khmer-mul)", "generic(nastaliq)" ]; - const style = new CSSStyleDeclaration(); + const style = new CSSStyleDeclaration(window); for (const keyword of keywords) { style.fontFamily = keyword; assert.strictEqual(style.fontFamily, keyword); @@ -1601,7 +4024,7 @@ describe("regression test for https://github.com/jsdom/cssstyle/issues/212", () // see https://drafts.csswg.org/css-fonts-4/#changes-2021-12-21 it("should support removed generic keywords as non generic family name", () => { const keywords = ["emoji", "fangsong"]; - const style = new CSSStyleDeclaration(); + const style = new CSSStyleDeclaration(window); for (const keyword of keywords) { style.fontFamily = keyword; assert.strictEqual(style.fontFamily, keyword); @@ -1609,7 +4032,7 @@ describe("regression test for https://github.com/jsdom/cssstyle/issues/212", () }); it("should support `-webkit-` prefixed family name", () => { - const style = new CSSStyleDeclaration(); + const style = new CSSStyleDeclaration(window); style.fontFamily = "-webkit-body"; assert.strictEqual(style.fontFamily, "-webkit-body"); }); @@ -1617,7 +4040,7 @@ describe("regression test for https://github.com/jsdom/cssstyle/issues/212", () describe("regression test for https://github.com/jsdom/jsdom/issues/3021", () => { it("should get normalized value for font shorthand", () => { - const style = new CSSStyleDeclaration(); + const style = new CSSStyleDeclaration(window); style.font = "normal bold 4px sans-serif"; assert.strictEqual(style.font, "bold 4px sans-serif"); }); @@ -1625,7 +4048,7 @@ describe("regression test for https://github.com/jsdom/jsdom/issues/3021", () => describe("regression test for https://github.com/jsdom/cssstyle/issues/214", () => { it("should return value for each property", () => { - const style = new CSSStyleDeclaration(); + const style = new CSSStyleDeclaration(window); const key = "background-color"; const camel = "backgroundColor"; const value = "var(--foo)"; @@ -1637,16 +4060,70 @@ describe("regression test for https://github.com/jsdom/cssstyle/issues/214", () }); it("should set var() values for background-attachment correctly", () => { - const style = new CSSStyleDeclaration(); + const style = new CSSStyleDeclaration(window); style.backgroundAttachment = "var(--foo)"; assert.strictEqual(style.backgroundAttachment, "var(--foo)"); style.setProperty("background-attachment", "var(--bar)"); assert.strictEqual(style.backgroundAttachment, "var(--bar)"); }); + + it("should allow changing a single property on a border, when border contains a css variable", () => { + const style = new CSSStyleDeclaration(window); + style.border = "0.1rem solid var(--my-color-value)"; + assert.strictEqual(style.border, "0.1rem solid var(--my-color-value)"); + style.borderWidth = "0.2rem"; + assert.strictEqual(style.borderWidth, "0.2rem"); + assert.strictEqual(style.border, ""); + }); + + it("should get value and priority", () => { + const style = new CSSStyleDeclaration(window); + style.cssText = "word-spacing: 1px !important;"; + assert.strictEqual(style.cssText, "word-spacing: 1px !important;", "cssText"); + assert.strictEqual(style.getPropertyValue("word-spacing"), "1px", "value"); + assert.strictEqual(style.getPropertyPriority("word-spacing"), "important", "priority"); + }); }); -describe("propertyList", () => { - it("should get property list", () => { - assert.deepEqual(propertyList, Object.fromEntries(implementedProperties)); +describe("regression test for https://github.com/jsdom/jsdom/issues/3944", () => { + it("should get overwritten value", () => { + const style = new CSSStyleDeclaration(window); + style.cssText = + "background: linear-gradient(rgb(0 0 255 / 0.5), rgb(255 255 0 / 0.5)) center center;"; + assert.strictEqual( + style.cssText, + "background: linear-gradient(rgba(0, 0, 255, 0.5), rgba(255, 255, 0, 0.5)) center center;" + ); + assert.strictEqual(style.backgroundPosition, "center center"); + + style.cssText = + "background:linear-gradient(rgb(0 0 255 / 0.5), rgb(255 255 0 / 0.5)) center center; background-position: top;"; + assert.strictEqual( + style.cssText, + "background: linear-gradient(rgba(0, 0, 255, 0.5), rgba(255, 255, 0, 0.5)) center top;" + ); + assert.strictEqual(style.backgroundPosition, "center top"); + }); + + it("should not overwrite value", () => { + const style = new CSSStyleDeclaration(window); + style.cssText = + "background: linear-gradient(rgb(0 0 255 / 0.5), rgb(255 255 0 / 0.5)) center center !important; background-position: top;"; + assert.strictEqual( + style.cssText, + "background: linear-gradient(rgba(0, 0, 255, 0.5), rgba(255, 255, 0, 0.5)) center center !important;" + ); + assert.strictEqual(style.backgroundPosition, "center center"); + }); + + it("should get overwritten value", () => { + const style = new CSSStyleDeclaration(window); + style.cssText = + "background:linear-gradient(rgb(0 0 255 / 0.5), rgb(255 255 0 / 0.5)) center center !important; background-position: top !important;"; + assert.strictEqual( + style.cssText, + "background: linear-gradient(rgba(0, 0, 255, 0.5), rgba(255, 255, 0, 0.5)) center top !important;" + ); + assert.strictEqual(style.backgroundPosition, "center top"); }); }); diff --git a/test/camelize.test.js b/test/camelize.test.js index ce68f424..9d1cb011 100644 --- a/test/camelize.test.js +++ b/test/camelize.test.js @@ -2,7 +2,7 @@ const { describe, it } = require("node:test"); const assert = require("node:assert/strict"); -const camelize = require("../lib/utils/camelize"); +const camelize = require("../scripts/camelize"); describe("dashedToCamelCase", () => { it("should not camelize custom property", () => { diff --git a/test/parsers.test.js b/test/parsers.test.js index 2964102a..b98ef630 100644 --- a/test/parsers.test.js +++ b/test/parsers.test.js @@ -267,6 +267,13 @@ describe("resolveCalc", () => { assert.strictEqual(output, "calc(10px + 100vh)"); }); + + it("should return serialized value", () => { + const input = "translate(calc(10%), 10%)"; + const output = parsers.resolveCalc(input); + + assert.strictEqual(output, "translate(calc(10%), 10%)"); + }); }); describe("parseNumber", () => { @@ -979,17 +986,17 @@ describe("parseAngle", () => { }); }); -describe("parseUrl", () => { +describe("parseURL", () => { it("should return undefined", () => { const input = ""; - const output = parsers.parseUrl(input); + const output = parsers.parseURL(input); assert.strictEqual(output, undefined); }); it("should return undefined", () => { const input = []; - const output = parsers.parseUrl(input); + const output = parsers.parseURL(input); assert.strictEqual(output, undefined); }); @@ -1001,7 +1008,7 @@ describe("parseUrl", () => { value: "foo" } ]; - const output = parsers.parseUrl(input); + const output = parsers.parseURL(input); assert.strictEqual(output, undefined); }); @@ -1013,7 +1020,7 @@ describe("parseUrl", () => { value: "" } ]; - const output = parsers.parseUrl(input); + const output = parsers.parseURL(input); assert.strictEqual(output, 'url("")'); }); @@ -1025,7 +1032,7 @@ describe("parseUrl", () => { value: "sample.png" } ]; - const output = parsers.parseUrl(input); + const output = parsers.parseURL(input); assert.strictEqual(output, 'url("sample.png")'); }); @@ -1037,7 +1044,7 @@ describe("parseUrl", () => { value: "sample\\\\-escaped.png" } ]; - const output = parsers.parseUrl(input); + const output = parsers.parseURL(input); assert.strictEqual(output, 'url("sample\\-escaped.png")'); }); @@ -1049,7 +1056,7 @@ describe("parseUrl", () => { value: "sample escaped -space.png" } ]; - const output = parsers.parseUrl(input); + const output = parsers.parseURL(input); assert.strictEqual(output, 'url("sample escaped -space.png")'); }); @@ -1061,7 +1068,7 @@ describe("parseUrl", () => { value: "sample\tescaped\t-tab.png" } ]; - const output = parsers.parseUrl(input); + const output = parsers.parseURL(input); assert.strictEqual(output, 'url("sample\tescaped\t-tab.png")'); }); @@ -1073,7 +1080,7 @@ describe("parseUrl", () => { value: "sample'escaped'-quote.png" } ]; - const output = parsers.parseUrl(input); + const output = parsers.parseURL(input); // prettier-ignore assert.strictEqual(output, "url(\"sample'escaped'-quote.png\")"); @@ -1086,7 +1093,7 @@ describe("parseUrl", () => { value: 'sample"escaped"-double-quote.png' } ]; - const output = parsers.parseUrl(input); + const output = parsers.parseURL(input); assert.strictEqual(output, 'url("sample\\"escaped\\"-double-quote.png")'); }); @@ -1389,8 +1396,10 @@ describe("parseCSS", () => { it("should get ast", () => { const input = "color: green !important;"; const opt = { - context: "declarationList", - parseValue: false + options: { + context: "declarationList", + parseValue: false + } }; const output = parsers.parseCSS(input, opt); assert.strictEqual(output.type, "DeclarationList"); @@ -1400,8 +1409,10 @@ describe("parseCSS", () => { it("should get ast", () => { const input = "green"; const opt = { - context: "value", - parseValue: false + options: { + context: "value", + parseValue: false + } }; const output = parsers.parseCSS(input, opt); assert.strictEqual(output.type, "Value"); @@ -1411,8 +1422,10 @@ describe("parseCSS", () => { it("should get object", () => { const input = "color: green !important;"; const opt = { - context: "declarationList", - parseValue: false + options: { + context: "declarationList", + parseValue: false + } }; const output = parsers.parseCSS(input, opt, true); const [ diff --git a/test/properties.test.js b/test/properties.test.js deleted file mode 100644 index 4594780b..00000000 --- a/test/properties.test.js +++ /dev/null @@ -1,2329 +0,0 @@ -"use strict"; - -const { describe, it } = require("node:test"); -const assert = require("node:assert/strict"); -const { CSSStyleDeclaration } = require("../lib/CSSStyleDeclaration"); - -function testPropertyValue(property, value, expected) { - const style = new CSSStyleDeclaration(); - let res; - - style.setProperty(property, value); - res = style.getPropertyValue(property); - assert.strictEqual(res, expected, `setProperty("${property}", '${value}')`); - - style.setProperty(property, undefined); - res = style.getPropertyValue(property); - assert.strictEqual(res, expected, `setProperty("${property}", undefined)`); - - style.setProperty(property, null); - res = style.getPropertyValue(property); - assert.strictEqual(res, "", `setProperty("${property}", null)`); - - style[property] = value; - res = style[property]; - assert.strictEqual(res, expected, `set["${property}"] = '${value}'`); - - style[property] = undefined; - res = style[property]; - assert.strictEqual(res, expected, `set["${property}"] = undefined`); - - style[property] = null; - res = style[property]; - assert.strictEqual(res, "", `set["${property}"] = null`); -} - -function testImplicitPropertyValue(property, value, expected, sub) { - const style = new CSSStyleDeclaration(); - let res; - - style.setProperty(property, value); - res = style.getPropertyValue(property); - assert.strictEqual(res, expected, `setProperty("${property}", '${value}')`); - for (const [key, subExpected] of sub) { - res = style.getPropertyValue(key); - assert.strictEqual( - res, - subExpected, - `setProperty("${property}", '${value}') implicitly changes the value of ${key}` - ); - } - - style.setProperty(property, undefined); - res = style.getPropertyValue(property); - assert.strictEqual(res, expected, `setProperty("${property}", undefined)`); - for (const [key, subExpected] of sub) { - res = style.getPropertyValue(key); - assert.strictEqual( - res, - subExpected, - `setProperty("${property}", undefined) does not change the value of ${key}` - ); - } - - style.setProperty(property, null); - res = style.getPropertyValue(property); - assert.strictEqual(res, "", `setProperty("${property}", null)`); - for (const [key] of sub) { - res = style.getPropertyValue(key); - assert.strictEqual( - res, - "", - `setProperty("${property}", null) implicitly changes the value of ${key}` - ); - } - - for (const key of sub.keys()) { - style.setProperty(property, value); - style.setProperty(key, "var(--foo)"); - res = style.getPropertyValue(property); - assert.strictEqual( - res, - "", - `setProperty("${key}", "var(--foo)") implicitly changes the value of ${property}` - ); - style.setProperty(property, null); - } - - style[property] = value; - res = style[property]; - assert.strictEqual(res, expected, `set["${property}"] = '${value}'`); - for (const [key, subExpected] of sub) { - res = style.getPropertyValue(key); - assert.strictEqual( - res, - subExpected, - `set["${property}"] = '${value}' implicitly changes the value of ${key}` - ); - } - - style[property] = undefined; - res = style[property]; - assert.strictEqual(res, expected, `set["${property}"] = undefined`); - for (const [key, subExpected] of sub) { - res = style.getPropertyValue(key); - assert.strictEqual( - res, - subExpected, - `set["${property}"] = undefined does not change the value of ${key}` - ); - } - - style[property] = null; - res = style[property]; - assert.strictEqual(res, "", `set["${property}"] = null`); - for (const [key] of sub) { - res = style.getPropertyValue(key); - assert.strictEqual(res, "", `set["${property}"] = null implicitly changes the value of ${key}`); - } -} - -describe("background", () => { - it("background-attachment should set / get keyword", () => { - testPropertyValue("background-attachment", "fixed", "fixed"); - }); - - it("background-attachment should set / get multiple values", () => { - testPropertyValue("background-attachment", "fixed, scroll", "fixed, scroll"); - }); - - it("background-clip should set / get keyword", () => { - testPropertyValue("background-clip", "border-box", "border-box"); - }); - - it("background-clip should set / get multiple values", () => { - testPropertyValue("background-clip", "padding-box, content-box", "padding-box, content-box"); - }); - - it("background-color should set / get color", () => { - testPropertyValue("background-color", "green", "green"); - }); - - it("background-color should set / get color", () => { - testPropertyValue("background-color", "#008000", "rgb(0, 128, 0)"); - }); - - it("background-color should set / get color", () => { - testPropertyValue("background-color", "rgb(0 128 0)", "rgb(0, 128, 0)"); - }); - - it("background-color should not set / get multiple values", () => { - testPropertyValue("background-color", "green, blue", ""); - }); - - it("background-image should set / get keyword", () => { - testPropertyValue("background-image", "none", "none"); - }); - - it("background-image should set / get image URL", () => { - testPropertyValue("background-image", "url(example.png)", 'url("example.png")'); - }); - - it("background-image should set / get gradient image", () => { - testPropertyValue( - "background-image", - "linear-gradient(to right, green, blue)", - "linear-gradient(to right, green, blue)" - ); - }); - - it("background-image should set / get gradient image", () => { - testPropertyValue( - "background-image", - "radial-gradient(ellipse closest-side, #1e90ff 50%, #008000)", - "radial-gradient(closest-side, rgb(30, 144, 255) 50%, rgb(0, 128, 0))" - ); - }); - - it("background-image should set / get multiple values", () => { - testPropertyValue( - "background-image", - "url(example.png), linear-gradient(to right, green, blue)", - 'url("example.png"), linear-gradient(to right, green, blue)' - ); - }); - - it("background-origin should set / get keyword", () => { - testPropertyValue("background-origin", "border-box", "border-box"); - }); - - it("background-origin should set / get multiple values", () => { - testPropertyValue("background-origin", "padding-box, content-box", "padding-box, content-box"); - }); - - it("background-position should set / get keywords", () => { - testPropertyValue("background-position", "center", "center center"); - }); - - it("background-position should set / get keywords", () => { - testPropertyValue("background-position", "left", "left center"); - }); - - it("background-position should set / get keywords", () => { - testPropertyValue("background-position", "top", "center top"); - }); - - it("background-position should set / get keywords", () => { - testPropertyValue("background-position", "left center", "left center"); - }); - - it("background-position should set / get keywords", () => { - testPropertyValue("background-position", "top left", "left top"); - }); - - it("background-position should set / get keywords", () => { - testPropertyValue("background-position", "top center", "center top"); - }); - - it("background-position should not set / get keyword", () => { - testPropertyValue("background-position", "left right", ""); - }); - - it("background-position should set / get length keyword", () => { - testPropertyValue("background-position", "10px", "10px center"); - }); - - it("background-position should set / get length", () => { - testPropertyValue("background-position", "10px 20px", "10px 20px"); - }); - - it("background-position should set / get percent keyword", () => { - testPropertyValue("background-position", "10%", "10% center"); - }); - - it("background-position should set / get percents", () => { - testPropertyValue("background-position", "10% 20%", "10% 20%"); - }); - - it("background-position should set / get length percent", () => { - testPropertyValue("background-position", "10px 20%", "10px 20%"); - }); - - it("background-position should set / get keyword length", () => { - testPropertyValue("background-position", "left 10px", "left 10px"); - }); - - it("background-position should not set / get keyword length", () => { - testPropertyValue("background-position", "10px left", ""); - }); - - it("background-position should set / get keyword length", () => { - testPropertyValue("background-position", "10px top", "10px top"); - }); - - it("background-position should not set / get keyword length", () => { - testPropertyValue("background-position", "top 10px", ""); - }); - - it("background-position should not set / get keyword", () => { - testPropertyValue("background-position", "left right bottom", ""); - }); - - it("background-position should not set / get length percent", () => { - testPropertyValue("background-position", "10px 20% 30px", ""); - }); - - it("background-position should set / get keyword length with offset", () => { - testPropertyValue("background-position", "center 10px center", ""); - }); - - it("background-position should set / get keyword length with offset", () => { - testPropertyValue("background-position", "center center 10px", ""); - }); - - it("background-position should set / get keyword length with offset", () => { - testPropertyValue("background-position", "left 10px top", "left 10px top"); - }); - - it("background-position should set / get keyword length with offset", () => { - testPropertyValue("background-position", "left top 20px", "left top 20px"); - }); - - it("background-position should set / get keyword length with offset", () => { - testPropertyValue("background-position", "top 20px left", "left top 20px"); - }); - - it("background-position should set / get keyword length with offset", () => { - testPropertyValue("background-position", "top left 10px", "left 10px top"); - }); - - it("background-position should not set / get keyword", () => { - testPropertyValue("background-position", "left right top bottom", ""); - }); - - it("background-position should not set / get length percent", () => { - testPropertyValue("background-position", "10px 20% 30px 40%", ""); - }); - - it("background-position should set / get keyword length with offset", () => { - testPropertyValue("background-position", "center 10px center 20px", ""); - }); - - it("background-position should set / get keyword length with offset", () => { - testPropertyValue("background-position", "left 10px top 20px", "left 10px top 20px"); - }); - - it("background-position should set / get keyword length with offset", () => { - testPropertyValue("background-position", "top 10px left 20px", "left 20px top 10px"); - }); - - it("background-position should set / get multiple values", () => { - testPropertyValue("background-position", "left top, bottom right", "left top, right bottom"); - }); - - it("background-repeat should set / get keyword", () => { - testPropertyValue("background-repeat", "repeat", "repeat"); - }); - - it("background-repeat should set / get keyword keyword", () => { - testPropertyValue("background-repeat", "repeat no-repeat", "repeat-x"); - }); - - it("background-repeat should set / get keyword keyword", () => { - testPropertyValue("background-repeat", "no-repeat repeat", "repeat-y"); - }); - - it("background-repeat should set / get keyword keyword", () => { - testPropertyValue("background-repeat", "repeat repeat", "repeat"); - }); - - it("background-repeat should set / get keyword keyword", () => { - testPropertyValue("background-repeat", "repeat space", "repeat space"); - }); - - it("background-repeat should not set / get multiple axis keywords", () => { - testPropertyValue("background-repeat", "repeat-x repeat-y", ""); - }); - - it("background-repeat should set / get multiple values", () => { - testPropertyValue("background-repeat", "repeat, no-repeat", "repeat, no-repeat"); - }); - - it("background-size should set / get keyword", () => { - testPropertyValue("background-size", "contain", "contain"); - }); - - it("background-size should not set / get multiple ratio keywords", () => { - testPropertyValue("background-size", "contain cover", ""); - }); - - it("background-size should set / get keyword", () => { - testPropertyValue("background-size", "auto auto", "auto"); - }); - - it("background-size should set / get length and length", () => { - testPropertyValue("background-size", "10px 20px", "10px 20px"); - }); - - it("background-size should not set / get negative length", () => { - testPropertyValue("background-size", "-10px 20px", ""); - }); - - it("background-size should not set / get negative length", () => { - testPropertyValue("background-size", "10px -20px", ""); - }); - - it("background-size should set / get percent", () => { - testPropertyValue("background-size", "10% 20%", "10% 20%"); - }); - - it("background-size should not set / get negative percent", () => { - testPropertyValue("background-size", "-10% 20%", ""); - }); - - it("background-size should not set / get negative percent", () => { - testPropertyValue("background-size", "10% -20%%", ""); - }); - - it("background-size should set / get keyword and length", () => { - testPropertyValue("background-size", "auto 10px", "auto 10px"); - }); - - it("background-size should set / get length", () => { - testPropertyValue("background-size", "10px auto", "10px"); - }); - - it("background-size should set / get multiple values", () => { - testPropertyValue("background-size", "contain, cover", "contain, cover"); - }); - - it("background shorthand should set / get value", () => { - testImplicitPropertyValue( - "background", - "none", - "none", - new Map([ - ["background-image", "none"], - ["background-position", "0% 0%"], - ["background-size", "auto"], - ["background-repeat", "repeat"], - ["background-origin", "padding-box"], - ["background-clip", "border-box"], - ["background-attachment", "scroll"], - ["background-color", "transparent"] - ]) - ); - }); - - it("background shorthand should set / get value", () => { - testImplicitPropertyValue( - "background", - "transparent", - "transparent", - new Map([ - ["background-image", "none"], - ["background-position", "0% 0%"], - ["background-size", "auto"], - ["background-repeat", "repeat"], - ["background-origin", "padding-box"], - ["background-clip", "border-box"], - ["background-attachment", "scroll"], - ["background-color", "transparent"] - ]) - ); - }); - - it("background shorthand should set / get sub longhand values", () => { - testImplicitPropertyValue( - "background", - "fixed left / 50% repeat url(example.png) green", - 'url("example.png") left center / 50% fixed green', - new Map([ - ["background-image", 'url("example.png")'], - ["background-position", "left center"], - ["background-size", "50%"], - ["background-repeat", "repeat"], - ["background-origin", "padding-box"], - ["background-clip", "border-box"], - ["background-attachment", "fixed"], - ["background-color", "green"] - ]) - ); - }); - - it("background shorthand should set / get multiple values", () => { - testImplicitPropertyValue( - "background", - "fixed left / 50% repeat url(example.png), linear-gradient(to right, green, blue) green", - 'url("example.png") left center / 50% fixed, linear-gradient(to right, green, blue) green', - new Map([ - ["background-image", 'url("example.png"), linear-gradient(to right, green, blue)'], - ["background-position", "left center, 0% 0%"], - ["background-size", "50%, auto"], - ["background-repeat", "repeat, repeat"], - ["background-origin", "padding-box, padding-box"], - ["background-clip", "border-box, border-box"], - ["background-attachment", "fixed, scroll"], - ["background-color", "green"] - ]) - ); - }); - - it("background shorthand should set / get value", () => { - testImplicitPropertyValue( - "background", - "fixed left repeat url(example.png) var(--foo)", - "fixed left repeat url(example.png) var(--foo)", - new Map([ - ["background-image", ""], - ["background-position", ""], - ["background-size", ""], - ["background-repeat", ""], - ["background-origin", ""], - ["background-clip", ""], - ["background-attachment", ""], - ["background-color", ""] - ]) - ); - }); -}); - -describe("border", () => { - it("border-top-color should set / get color", () => { - testPropertyValue("border-top-color", "green", "green"); - }); - - it("border-top-color should set / get color", () => { - testPropertyValue("border-top-color", "#008000", "rgb(0, 128, 0)"); - }); - - it("border-top-color should set / get color", () => { - testPropertyValue("border-top-color", "rgb(0 128 0)", "rgb(0, 128, 0)"); - }); - - it("border-right-color should set / get color", () => { - testPropertyValue("border-right-color", "green", "green"); - }); - - it("border-right-color should set / get color", () => { - testPropertyValue("border-right-color", "#008000", "rgb(0, 128, 0)"); - }); - - it("border-right-color should set / get color", () => { - testPropertyValue("border-right-color", "rgb(0 128 0)", "rgb(0, 128, 0)"); - }); - - it("border-bottom-color should set / get color", () => { - testPropertyValue("border-bottom-color", "green", "green"); - }); - - it("border-bottom-color should set / get color", () => { - testPropertyValue("border-bottom-color", "#008000", "rgb(0, 128, 0)"); - }); - - it("border-bottom-color should set / get color", () => { - testPropertyValue("border-bottom-color", "rgb(0 128 0)", "rgb(0, 128, 0)"); - }); - - it("border-left-color should set / get color", () => { - testPropertyValue("border-left-color", "green", "green"); - }); - - it("border-left-color should set / get color", () => { - testPropertyValue("border-left-color", "#008000", "rgb(0, 128, 0)"); - }); - - it("border-left-color should set / get color", () => { - testPropertyValue("border-left-color", "rgb(0 128 0)", "rgb(0, 128, 0)"); - }); - - it("border-top-width should set / get keyword", () => { - testPropertyValue("border-top-width", "medium", "medium"); - }); - - it("border-top-width should set / get length", () => { - testPropertyValue("border-top-width", "10px", "10px"); - }); - - it("border-top-width should not set / get negative length", () => { - testPropertyValue("border-top-width", "-10px", ""); - }); - - it("border-right-width should set / get keyword", () => { - testPropertyValue("border-right-width", "medium", "medium"); - }); - - it("border-right-width should set / get length", () => { - testPropertyValue("border-right-width", "10px", "10px"); - }); - - it("border-right-width should not set / get negative length", () => { - testPropertyValue("border-right-width", "-10px", ""); - }); - - it("border-bottom-width should set / get keyword", () => { - testPropertyValue("border-bottom-width", "medium", "medium"); - }); - - it("border-bottom-width should set / get length", () => { - testPropertyValue("border-bottom-width", "10px", "10px"); - }); - - it("border-bottom-width should not set / get negative length", () => { - testPropertyValue("border-bottom-width", "-10px", ""); - }); - - it("border-left-width should set / get keyword", () => { - testPropertyValue("border-left-width", "medium", "medium"); - }); - - it("border-left-width should set / get length", () => { - testPropertyValue("border-left-width", "10px", "10px"); - }); - - it("border-left-width should not set / get negative length", () => { - testPropertyValue("border-left-width", "-10px", ""); - }); - - it("border-top-style should set / get keyword", () => { - testPropertyValue("border-top-style", "dotted", "dotted"); - }); - - it("border-right-style should set / get keyword", () => { - testPropertyValue("border-right-style", "dotted", "dotted"); - }); - - it("border-bottom-style should set / get keyword", () => { - testPropertyValue("border-bottom-style", "dotted", "dotted"); - }); - - it("border-left-style should set / get keyword", () => { - testPropertyValue("border-left-style", "dotted", "dotted"); - }); - - it("border-color should set / get color", () => { - testImplicitPropertyValue( - "border-color", - "green", - "green", - new Map([ - ["border-top-color", "green"], - ["border-right-color", "green"], - ["border-bottom-color", "green"], - ["border-left-color", "green"] - ]) - ); - }); - - it("border-color should set / get color", () => { - testImplicitPropertyValue( - "border-color", - "green blue", - "green blue", - new Map([ - ["border-top-color", "green"], - ["border-right-color", "blue"], - ["border-bottom-color", "green"], - ["border-left-color", "blue"] - ]) - ); - }); - - it("border-color should set / get color", () => { - testImplicitPropertyValue( - "border-color", - "green blue yellow", - "green blue yellow", - new Map([ - ["border-top-color", "green"], - ["border-right-color", "blue"], - ["border-bottom-color", "yellow"], - ["border-left-color", "blue"] - ]) - ); - }); - - it("border-color should set / get color", () => { - testImplicitPropertyValue( - "border-color", - "green blue yellow purple", - "green blue yellow purple", - new Map([ - ["border-top-color", "green"], - ["border-right-color", "blue"], - ["border-bottom-color", "yellow"], - ["border-left-color", "purple"] - ]) - ); - }); - - it("border-width should set / get keyword", () => { - testImplicitPropertyValue( - "border-width", - "thick", - "thick", - new Map([ - ["border-top-width", "thick"], - ["border-right-width", "thick"], - ["border-bottom-width", "thick"], - ["border-left-width", "thick"] - ]) - ); - }); - - it("border-width should set / get keyword", () => { - testImplicitPropertyValue( - "border-width", - "thick thin", - "thick thin", - new Map([ - ["border-top-width", "thick"], - ["border-right-width", "thin"], - ["border-bottom-width", "thick"], - ["border-left-width", "thin"] - ]) - ); - }); - - it("border-width should set / get keyword", () => { - testImplicitPropertyValue( - "border-width", - "thick thin medium", - "thick thin medium", - new Map([ - ["border-top-width", "thick"], - ["border-right-width", "thin"], - ["border-bottom-width", "medium"], - ["border-left-width", "thin"] - ]) - ); - }); - - it("border-width should set / get keyword and value", () => { - testImplicitPropertyValue( - "border-width", - "thick thin medium 10px", - "thick thin medium 10px", - new Map([ - ["border-top-width", "thick"], - ["border-right-width", "thin"], - ["border-bottom-width", "medium"], - ["border-left-width", "10px"] - ]) - ); - }); - - it("border-style should set / get keyword", () => { - testImplicitPropertyValue( - "border-style", - "dotted", - "dotted", - new Map([ - ["border-top-style", "dotted"], - ["border-right-style", "dotted"], - ["border-bottom-style", "dotted"], - ["border-left-style", "dotted"] - ]) - ); - }); - - it("border-style should set / get keyword", () => { - testImplicitPropertyValue( - "border-style", - "none", - "none", - new Map([ - ["border-top-style", "none"], - ["border-right-style", "none"], - ["border-bottom-style", "none"], - ["border-left-style", "none"] - ]) - ); - }); - - it("border-style should set / get keyword", () => { - testImplicitPropertyValue( - "border-style", - "dotted groove", - "dotted groove", - new Map([ - ["border-top-style", "dotted"], - ["border-right-style", "groove"], - ["border-bottom-style", "dotted"], - ["border-left-style", "groove"] - ]) - ); - }); - - it("border-style should set / get keyword", () => { - testImplicitPropertyValue( - "border-style", - "dotted groove double", - "dotted groove double", - new Map([ - ["border-top-style", "dotted"], - ["border-right-style", "groove"], - ["border-bottom-style", "double"], - ["border-left-style", "groove"] - ]) - ); - }); - - it("border-style should set / get keyword", () => { - testImplicitPropertyValue( - "border-style", - "dotted groove double none", - "dotted groove double none", - new Map([ - ["border-top-style", "dotted"], - ["border-right-style", "groove"], - ["border-bottom-style", "double"], - ["border-left-style", "none"] - ]) - ); - }); - - it("border-collapse should set / get keyword", () => { - testPropertyValue("border-collapse", "collapse", "collapse"); - }); - - it("border-spacing should set / get length", () => { - testPropertyValue("border-spacing", "10px", "10px"); - }); - - it("border-spacing should set / get length", () => { - testPropertyValue("border-spacing", "10px 20px", "10px 20px"); - }); - - it("border-top shorthand should set / get value", () => { - testImplicitPropertyValue( - "border-top", - "1px solid green", - "1px solid green", - new Map([ - ["border-top-width", "1px"], - ["border-top-style", "solid"], - ["border-top-color", "green"] - ]) - ); - }); - - it("border-top shorthand should set / get value", () => { - testImplicitPropertyValue( - "border-top", - "1px var(--foo) green", - "1px var(--foo) green", - new Map([ - ["border-top-width", ""], - ["border-top-style", ""], - ["border-top-color", ""] - ]) - ); - }); - - it("border-right shorthand should set / get value", () => { - testImplicitPropertyValue( - "border-right", - "1px solid green", - "1px solid green", - new Map([ - ["border-right-width", "1px"], - ["border-right-style", "solid"], - ["border-right-color", "green"] - ]) - ); - }); - - it("border-right shorthand should set / get value", () => { - testImplicitPropertyValue( - "border-right", - "1px var(--foo) green", - "1px var(--foo) green", - new Map([ - ["border-right-width", ""], - ["border-right-style", ""], - ["border-right-color", ""] - ]) - ); - }); - - it("border-bottom shorthand should set / get value", () => { - testImplicitPropertyValue( - "border-bottom", - "1px solid green", - "1px solid green", - new Map([ - ["border-bottom-width", "1px"], - ["border-bottom-style", "solid"], - ["border-bottom-color", "green"] - ]) - ); - }); - - it("border-bottom shorthand should set / get value", () => { - testImplicitPropertyValue( - "border-bottom", - "1px var(--foo) green", - "1px var(--foo) green", - new Map([ - ["border-bottom-width", ""], - ["border-bottom-style", ""], - ["border-bottom-color", ""] - ]) - ); - }); - - it("border-left shorthand should set / get value", () => { - testImplicitPropertyValue( - "border-left", - "1px solid green", - "1px solid green", - new Map([ - ["border-left-width", "1px"], - ["border-left-style", "solid"], - ["border-left-color", "green"] - ]) - ); - }); - - it("border-left shorthand should set / get value", () => { - testImplicitPropertyValue( - "border-left", - "1px var(--foo) green", - "1px var(--foo) green", - new Map([ - ["border-left-width", ""], - ["border-left-style", ""], - ["border-left-color", ""] - ]) - ); - }); - - it("border shorthand should set / get value", () => { - testImplicitPropertyValue( - "border", - "1px solid green", - "1px solid green", - new Map([ - ["border-top-width", "1px"], - ["border-top-style", "solid"], - ["border-top-color", "green"], - ["border-right-width", "1px"], - ["border-right-style", "solid"], - ["border-right-color", "green"], - ["border-bottom-width", "1px"], - ["border-bottom-style", "solid"], - ["border-bottom-color", "green"], - ["border-left-width", "1px"], - ["border-left-style", "solid"], - ["border-left-color", "green"] - ]) - ); - }); - - it("border shorthand should set / get value", () => { - testImplicitPropertyValue( - "border", - "1px var(--foo) green", - "1px var(--foo) green", - new Map([ - ["border-top-width", ""], - ["border-top-style", ""], - ["border-top-color", ""], - ["border-right-width", ""], - ["border-right-style", ""], - ["border-right-color", ""], - ["border-bottom-width", ""], - ["border-bottom-style", ""], - ["border-bottom-color", ""], - ["border-left-width", ""], - ["border-left-style", ""], - ["border-left-color", ""] - ]) - ); - }); -}); - -describe("box model", () => { - it("margin-top should set / get keyword", () => { - testPropertyValue("margin-top", "auto", "auto"); - }); - - it("margin-top should set / get length", () => { - testPropertyValue("margin-top", "0", "0px"); - }); - - it("margin-top should set / get length", () => { - testPropertyValue("margin-top", "10px", "10px"); - }); - - it("margin-top should set / get negative length", () => { - testPropertyValue("margin-top", "-10px", "-10px"); - }); - - it("margin-top should set / get percent", () => { - testPropertyValue("margin-top", "10%", "10%"); - }); - - it("margin-top should set / get negative percent", () => { - testPropertyValue("margin-top", "-10%", "-10%"); - }); - - it("margin-right should set / get keyword", () => { - testPropertyValue("margin-right", "auto", "auto"); - }); - - it("margin-right should set / get length", () => { - testPropertyValue("margin-right", "0", "0px"); - }); - - it("margin-right should set / get length", () => { - testPropertyValue("margin-right", "10px", "10px"); - }); - - it("margin-right should set / get negative length", () => { - testPropertyValue("margin-right", "-10px", "-10px"); - }); - - it("margin-right should set / get percent", () => { - testPropertyValue("margin-right", "10%", "10%"); - }); - - it("margin-right should set / get negative percent", () => { - testPropertyValue("margin-right", "-10%", "-10%"); - }); - - it("margin-bottom should set / get keyword", () => { - testPropertyValue("margin-bottom", "auto", "auto"); - }); - - it("margin-bottom should set / get length", () => { - testPropertyValue("margin-bottom", "0", "0px"); - }); - - it("margin-bottom should set / get length", () => { - testPropertyValue("margin-bottom", "10px", "10px"); - }); - - it("margin-bottom should set / get negative length", () => { - testPropertyValue("margin-bottom", "-10px", "-10px"); - }); - - it("margin-bottom should set / get percent", () => { - testPropertyValue("margin-bottom", "10%", "10%"); - }); - - it("margin-bottom should set / get negative percent", () => { - testPropertyValue("margin-bottom", "-10%", "-10%"); - }); - - it("margin-left should set / get keyword", () => { - testPropertyValue("margin-left", "auto", "auto"); - }); - - it("margin-left should set / get length", () => { - testPropertyValue("margin-left", "0", "0px"); - }); - - it("margin-left should set / get length", () => { - testPropertyValue("margin-left", "10px", "10px"); - }); - - it("margin-left should set / get negative length", () => { - testPropertyValue("margin-left", "-10px", "-10px"); - }); - - it("margin-left should set / get percent", () => { - testPropertyValue("margin-left", "10%", "10%"); - }); - - it("margin-left should set / get negative percent", () => { - testPropertyValue("margin-left", "-10%", "-10%"); - }); - - it("margin shorthand should set / get keyword", () => { - testImplicitPropertyValue( - "margin", - "auto", - "auto", - new Map([ - ["margin-top", "auto"], - ["margin-right", "auto"], - ["margin-bottom", "auto"], - ["margin-left", "auto"] - ]) - ); - }); - - it("margin shorthand should set / get value", () => { - testImplicitPropertyValue( - "margin", - "10px", - "10px", - new Map([ - ["margin-top", "10px"], - ["margin-right", "10px"], - ["margin-bottom", "10px"], - ["margin-left", "10px"] - ]) - ); - }); - - it("margin shorthand should set / get value", () => { - testImplicitPropertyValue( - "margin", - "10px 20px", - "10px 20px", - new Map([ - ["margin-top", "10px"], - ["margin-right", "20px"], - ["margin-bottom", "10px"], - ["margin-left", "20px"] - ]) - ); - }); - - it("margin shorthand should set / get value", () => { - testImplicitPropertyValue( - "margin", - "10px 20px 30px", - "10px 20px 30px", - new Map([ - ["margin-top", "10px"], - ["margin-right", "20px"], - ["margin-bottom", "30px"], - ["margin-left", "20px"] - ]) - ); - }); - - it("margin shorthand should set / get value", () => { - testImplicitPropertyValue( - "margin", - "10px 20px 30px 40px", - "10px 20px 30px 40px", - new Map([ - ["margin-top", "10px"], - ["margin-right", "20px"], - ["margin-bottom", "30px"], - ["margin-left", "40px"] - ]) - ); - }); - - it("margin shorthand should set / get value", () => { - testImplicitPropertyValue( - "margin", - "10px var(--foo)", - "10px var(--foo)", - new Map([ - ["margin-top", ""], - ["margin-right", ""], - ["margin-bottom", ""], - ["margin-left", ""] - ]) - ); - }); - - it("margin shorthand should set / get value", () => { - testImplicitPropertyValue( - "margin", - "initial", - "initial", - new Map([ - ["margin-top", "initial"], - ["margin-right", "initial"], - ["margin-bottom", "initial"], - ["margin-left", "initial"] - ]) - ); - }); - - it("padding-top should set / get length", () => { - testPropertyValue("padding-top", "0", "0px"); - }); - - it("padding-top should set / get length", () => { - testPropertyValue("padding-top", "10px", "10px"); - }); - - it("padding-top should not set / get negative length", () => { - testPropertyValue("padding-top", "-10px", ""); - }); - - it("padding-top should set / get percent", () => { - testPropertyValue("padding-top", "10%", "10%"); - }); - - it("padding-top should not set / get negative percent", () => { - testPropertyValue("padding-top", "-10%", ""); - }); - - it("padding-right should set / get length", () => { - testPropertyValue("padding-right", "0", "0px"); - }); - - it("padding-right should set / get length", () => { - testPropertyValue("padding-right", "10px", "10px"); - }); - - it("padding-right should not set / get negative length", () => { - testPropertyValue("padding-right", "-10px", ""); - }); - - it("padding-right should set / get percent", () => { - testPropertyValue("padding-right", "10%", "10%"); - }); - - it("padding-right should not set / get negative percent", () => { - testPropertyValue("padding-right", "-10%", ""); - }); - - it("padding-bottom should set / get length", () => { - testPropertyValue("padding-bottom", "0", "0px"); - }); - - it("padding-bottom should set / get length", () => { - testPropertyValue("padding-bottom", "10px", "10px"); - }); - - it("padding-bottom should not set / get negative length", () => { - testPropertyValue("padding-bottom", "-10px", ""); - }); - - it("padding-bottom should set / get percent", () => { - testPropertyValue("padding-bottom", "10%", "10%"); - }); - - it("padding-bottom should not set / get negative percent", () => { - testPropertyValue("padding-bottom", "-10%", ""); - }); - - it("padding-left should set / get length", () => { - testPropertyValue("padding-left", "0", "0px"); - }); - - it("padding-left should set / get length", () => { - testPropertyValue("padding-left", "10px", "10px"); - }); - - it("padding-left should not set / get negative length", () => { - testPropertyValue("padding-left", "-10px", ""); - }); - - it("padding-left should set / get percent", () => { - testPropertyValue("padding-left", "10%", "10%"); - }); - - it("padding-left should not set / get negative percent", () => { - testPropertyValue("padding-left", "-10%", ""); - }); - - it("padding shorthand should set / get value", () => { - testImplicitPropertyValue( - "padding", - "10px", - "10px", - new Map([ - ["padding-top", "10px"], - ["padding-right", "10px"], - ["padding-bottom", "10px"], - ["padding-left", "10px"] - ]) - ); - }); - - it("padding shorthand should set / get value", () => { - testImplicitPropertyValue( - "padding", - "10px 20px", - "10px 20px", - new Map([ - ["padding-top", "10px"], - ["padding-right", "20px"], - ["padding-bottom", "10px"], - ["padding-left", "20px"] - ]) - ); - }); - - it("padding shorthand should set / get value", () => { - testImplicitPropertyValue( - "padding", - "10px 20px 30px", - "10px 20px 30px", - new Map([ - ["padding-top", "10px"], - ["padding-right", "20px"], - ["padding-bottom", "30px"], - ["padding-left", "20px"] - ]) - ); - }); - - it("padding shorthand should set / get value", () => { - testImplicitPropertyValue( - "padding", - "10px 20px 30px 40px", - "10px 20px 30px 40px", - new Map([ - ["padding-top", "10px"], - ["padding-right", "20px"], - ["padding-bottom", "30px"], - ["padding-left", "40px"] - ]) - ); - }); - - it("padding shorthand should set / get value", () => { - testImplicitPropertyValue( - "padding", - "10px var(--foo)", - "10px var(--foo)", - new Map([ - ["padding-top", ""], - ["padding-right", ""], - ["padding-bottom", ""], - ["padding-left", ""] - ]) - ); - }); - - it("padding shorthand should set / get value", () => { - testImplicitPropertyValue( - "padding", - "initial", - "initial", - new Map([ - ["padding-top", "initial"], - ["padding-right", "initial"], - ["padding-bottom", "initial"], - ["padding-left", "initial"] - ]) - ); - }); -}); - -describe("box sizing", () => { - it("height should set / get keyword", () => { - testPropertyValue("height", "auto", "auto"); - }); - - it("height should set / get length", () => { - testPropertyValue("height", "0", "0px"); - }); - - it("height should set / get length", () => { - testPropertyValue("height", "10px", "10px"); - }); - - it("height should not set / get negative length", () => { - testPropertyValue("height", "-10px", ""); - }); - - it("height should set / get percent", () => { - testPropertyValue("height", "10%", "10%"); - }); - - it("height should not set / get negative percent", () => { - testPropertyValue("height", "-10%", ""); - }); - - it("width should set / get keyword", () => { - testPropertyValue("width", "auto", "auto"); - }); - - it("height should set / get length", () => { - testPropertyValue("width", "0", "0px"); - }); - - it("width should set / get length", () => { - testPropertyValue("width", "10px", "10px"); - }); - - it("width should not set / get negative length", () => { - testPropertyValue("width", "-10px", ""); - }); - - it("width should set / get percent", () => { - testPropertyValue("width", "10%", "10%"); - }); - - it("width should not set / get negative percent", () => { - testPropertyValue("width", "-10%", ""); - }); -}); - -describe("color", () => { - it("color should set / get color name", () => { - testPropertyValue("color", "green", "green"); - }); - - it("color should set / get hex color", () => { - testPropertyValue("color", "#008000", "rgb(0, 128, 0)"); - }); - - it("color should set / get color function", () => { - testPropertyValue("color", "rgb(0 128 0)", "rgb(0, 128, 0)"); - }); - - it("color should set / get color function", () => { - testPropertyValue( - "color", - "light-dark(#008000, #0000ff)", - "light-dark(rgb(0, 128, 0), rgb(0, 0, 255))" - ); - }); - - it("color should not should set / get invalid value", () => { - testPropertyValue( - "color", - "color-mix(in hsl, hsl(120deg 10% 20%) 0%, hsl(30deg 30% 40%) 0%)", - "" - ); - }); - - it("color should not should set / get invalid value", () => { - testPropertyValue("color", "color(srgb 0 0 0 0)", ""); - }); - - it("opacity should set / get keyword", () => { - testPropertyValue("opacity", "inherit", "inherit"); - }); - - it("opacity should set / get number", () => { - testPropertyValue("opacity", "0.5", "0.5"); - }); - - it("opacity should set / get number", () => { - testPropertyValue("opacity", ".5", "0.5"); - }); - - it("opacity should set / get number", () => { - testPropertyValue("opacity", "1.5", "1.5"); - }); - - it("opacity should set / get number", () => { - testPropertyValue("opacity", "-1", "-1"); - }); - - it("opacity should set / get percent", () => { - testPropertyValue("opacity", "50%", "50%"); - }); - - it("opacity should set / get percent", () => { - testPropertyValue("opacity", "150%", "150%"); - }); - - it("opacity should set / get percent", () => { - testPropertyValue("opacity", "-50%", "-50%"); - }); -}); - -describe("display", () => { - it("display should set / get keyword", () => { - testPropertyValue("display", "block", "block"); - }); - - it("display should set / get keyword", () => { - testPropertyValue("display", "inline", "inline"); - }); - - it("display should set / get keyword", () => { - testPropertyValue("display", "inline-block", "inline-block"); - }); - - it("display should set / get keyword", () => { - testPropertyValue("display", "flex", "flex"); - }); - - it("display should set / get keyword", () => { - testPropertyValue("display", "inline-flex", "inline-flex"); - }); - - it("display should set / get keyword", () => { - testPropertyValue("display", "grid", "grid"); - }); - - it("display should set / get keyword", () => { - testPropertyValue("display", "inline-grid", "inline-grid"); - }); - - it("display should set / get keyword", () => { - testPropertyValue("display", "flow", "block"); - }); - - it("display should set / get keyword", () => { - testPropertyValue("display", "flow-root", "flow-root"); - }); - - it("display should set / get keyword", () => { - testPropertyValue("display", "none", "none"); - }); - - it("display should set / get keyword", () => { - testPropertyValue("display", "contents", "contents"); - }); - - it("display should set / get keyword", () => { - testPropertyValue("display", "table-row", "table-row"); - }); - - it("display should set / get keyword", () => { - testPropertyValue("display", "flow list-item", "list-item"); - }); - - it("display should set / get keyword", () => { - testPropertyValue("display", "list-item flow", "list-item"); - }); - - it("display should set / get keyword", () => { - testPropertyValue("display", "block list-item", "list-item"); - }); - - it("display should not set / get keyword", () => { - testPropertyValue("display", "list-item block", "list-item"); - }); - - it("display should set / get keyword", () => { - testPropertyValue("display", "flow-root list-item", "flow-root list-item"); - }); - - it("display should not set / get keyword", () => { - testPropertyValue("display", "list-item flow-root", "flow-root list-item"); - }); - - it("display should set / get keyword", () => { - testPropertyValue("display", "block flow list-item", "list-item"); - }); - - it("display should set / get keyword", () => { - testPropertyValue("display", "block list-item flow", "list-item"); - }); - - it("display should set / get keyword", () => { - testPropertyValue("display", "block flow-root list-item", "flow-root list-item"); - }); - - it("display should set / get keyword", () => { - testPropertyValue("display", "block list-item flow-root", "flow-root list-item"); - }); - - it("display should set / get keyword", () => { - testPropertyValue("display", "flow block list-item", "list-item"); - }); - - it("display should set / get keyword", () => { - testPropertyValue("display", "flow list-item block", "list-item"); - }); - - it("display should set / get keyword", () => { - testPropertyValue("display", "flow-root block list-item", "flow-root list-item"); - }); - - it("display should set / get keyword", () => { - testPropertyValue("display", "flow-root list-item block", "flow-root list-item"); - }); - - it("display should not set / get keyword", () => { - testPropertyValue("display", "list-item block flow", "list-item"); - }); - - it("display should not set / get keyword", () => { - testPropertyValue("display", "list-item flow block", "list-item"); - }); - - it("display should not set / get keyword", () => { - testPropertyValue("display", "list-item block flow-root", "flow-root list-item"); - }); - - it("display should not set / get keyword", () => { - testPropertyValue("display", "list-item flow-root block", "flow-root list-item"); - }); - - it("display should set / get keyword", () => { - testPropertyValue("display", "inline flow list-item", "inline list-item"); - }); - - it("display should set / get keyword", () => { - testPropertyValue("display", "inline flow-root list-item", "inline flow-root list-item"); - }); - - it("display should set / get keyword", () => { - testPropertyValue("display", "run-in flow list-item", "run-in list-item"); - }); - - it("display should set / get keyword", () => { - testPropertyValue("display", "run-in flow-root list-item", "run-in flow-root list-item"); - }); - - it("display should set / get keyword", () => { - testPropertyValue("display", "block flow", "block"); - }); - - it("display should set / get keyword", () => { - testPropertyValue("display", "flow block", "block"); - }); - - it("display should set / get keyword", () => { - testPropertyValue("display", "block flow-root", "flow-root"); - }); - - it("display should set / get keyword", () => { - testPropertyValue("display", "block flex", "flex"); - }); - - it("display should set / get keyword", () => { - testPropertyValue("display", "block ruby", "block ruby"); - }); - - it("display should set / get keyword", () => { - testPropertyValue("display", "inline flow", "inline"); - }); - - it("display should set / get keyword", () => { - testPropertyValue("display", "flow inline", "inline"); - }); - - it("display should set / get keyword", () => { - testPropertyValue("display", "inline flow-root", "inline-block"); - }); - - it("display should set / get keyword", () => { - testPropertyValue("display", "inline flex", "inline-flex"); - }); - - it("display should set / get keyword", () => { - testPropertyValue("display", "inline ruby", "ruby"); - }); - - it("display should set / get keyword", () => { - testPropertyValue("display", "run-in flow", "run-in"); - }); - - it("display should set / get keyword", () => { - testPropertyValue("display", "flow run-in", "run-in"); - }); - - it("display should set / get keyword", () => { - testPropertyValue("display", "run-in flow-root", "run-in flow-root"); - }); - - it("display should set / get keyword", () => { - testPropertyValue("display", "run-in flex", "run-in flex"); - }); - - it("display should set / get keyword", () => { - testPropertyValue("display", "run-in ruby", "run-in ruby"); - }); -}); - -describe("flex box", () => { - it("flex-grow should set / get number", () => { - testPropertyValue("flex-grow", ".5", "0.5"); - }); - - it("flex-grow should not set / get negative number", () => { - testPropertyValue("flex-grow", "-1", ""); - }); - - it("flex-shrink should set / get number", () => { - testPropertyValue("flex-shrink", ".5", "0.5"); - }); - - it("flex-shrink should not set / get negative number", () => { - testPropertyValue("flex-shrink", "-1", ""); - }); - - it("flex-basis should set / get keyword", () => { - testPropertyValue("flex-basis", "content", "content"); - }); - - it("flex-basis should not set / get length", () => { - testPropertyValue("flex-basis", "10px", "10px"); - }); - - it("flex-basis should not set / get length", () => { - testPropertyValue("flex-basis", "0", "0px"); - }); - - it("flex-basis should not set / get percent", () => { - testPropertyValue("flex-basis", "10%", "10%"); - }); - - it("flex-basis should not set / get percent", () => { - testPropertyValue("flex-basis", "0%", "0%"); - }); - - it("flex should set / get keyword", () => { - testPropertyValue("flex", "none", "0 0 auto"); - }); - - it("flex should set / get keyword", () => { - testPropertyValue("flex", "auto", "1 1 auto"); - }); - - it("flex should set / get keyword", () => { - testPropertyValue("flex", "initial", "initial"); - }); - - it("flex should set / get keyword", () => { - testPropertyValue("flex", "unset", "unset"); - }); - - it("flex shorthand should not set / get longhand value", () => { - testPropertyValue("flex", "2 1 3", ""); - }); - - it("flex shorthand should not set / get longhand value", () => { - testPropertyValue("flex", "2 1 calc(3)", ""); - }); - - it("flex shorthand should set / get longhand value", () => { - testPropertyValue("flex", "2", "2 1 0%"); - }); - - it("flex shorthand should set / get longhand value", () => { - testPropertyValue("flex", "10%", "1 1 10%"); - }); - - it("flex shorthand should set / get longhand value", () => { - testPropertyValue("flex", "2 10px", "2 1 10px"); - }); - - it("flex shorthand should set / get longhand value", () => { - testPropertyValue("flex", "2 3", "2 3 0%"); - }); - - it("flex shorthand should set / get longhand value", () => { - testPropertyValue("flex", "2 3 10px", "2 3 10px"); - }); - - it("flex shorthand should set / get longhand value", () => { - testImplicitPropertyValue( - "flex", - "2 var(--foo) 10px", - "2 var(--foo) 10px", - new Map([ - ["flex-grow", ""], - ["flex-shrink", ""], - ["flex-basis", ""] - ]) - ); - }); - - it("flex shorthand should set / get longhand value", () => { - testImplicitPropertyValue( - "flex", - "calc(2px * 3)", - "1 1 calc(6px)", - new Map([ - ["flex-grow", "1"], - ["flex-shrink", "1"], - ["flex-basis", "calc(6px)"] - ]) - ); - }); - - it("flex shorthand should set / get longhand value", () => { - testImplicitPropertyValue( - "flex", - "calc(2 * 3)", - "calc(6) 1 0%", - new Map([ - ["flex-grow", "calc(6)"], - ["flex-shrink", "1"], - ["flex-basis", "0%"] - ]) - ); - }); - - it("flex shorthand should set / get longhand value", () => { - testImplicitPropertyValue( - "flex", - "initial", - "initial", - new Map([ - ["flex-grow", "initial"], - ["flex-shrink", "initial"], - ["flex-basis", "initial"] - ]) - ); - }); -}); - -describe("font", () => { - it("font-style should set / get keyword", () => { - testPropertyValue("font-style", "italic", "italic"); - }); - - it("font-variant should set / get keyword", () => { - testPropertyValue("font-variant", "normal", "normal"); - }); - - it("font-variant should set / get keyword", () => { - testPropertyValue("font-variant", "none", "none"); - }); - - it("font-variant should set / get keyword", () => { - testPropertyValue("font-variant", "none", "none"); - }); - - it("font-variant should set / get keyword", () => { - testPropertyValue("font-variant", "common-ligatures", "common-ligatures"); - }); - - it("font-variant should set / get keyword", () => { - testPropertyValue("font-variant", "no-common-ligatures", "no-common-ligatures"); - }); - - it("font-variant should set / get keyword", () => { - testPropertyValue("font-variant", "small-caps", "small-caps"); - }); - - it("font-variant should set / get keyword", () => { - testPropertyValue("font-variant", "stylistic(flowing)", "stylistic(flowing)"); - }); - - it("font-variant should set / get keyword", () => { - testPropertyValue( - "font-variant", - "stylistic(flowing) historical-forms styleset(flowing) character-variant(flowing) swash(flowing) ornaments(flowing) annotation(flowing)", - "stylistic(flowing) historical-forms styleset(flowing) character-variant(flowing) swash(flowing) ornaments(flowing) annotation(flowing)" - ); - }); - - it("font-variant should set / get keyword", () => { - testPropertyValue("font-variant", "jis78", "jis78"); - }); - - it("font-variant should set / get keyword", () => { - testPropertyValue("font-variant", "ruby", "ruby"); - }); - - it("font-variant should set / get keyword", () => { - testPropertyValue("font-variant", "sub", "sub"); - }); - - it("font-variant should set / get keyword", () => { - testPropertyValue("font-variant", "super", "super"); - }); - - it("font-variant should not set / get invalid keywords", () => { - testPropertyValue("font-variant", "normal none", ""); - }); - - it("font-variant should not set / get invalid keywords", () => { - testPropertyValue("font-variant", "normal small-caps", ""); - }); - - it("font-variant should not set / get invalid keywords", () => { - testPropertyValue("font-variant", "none small-caps", ""); - }); - - it("font-weight should set / get keyword", () => { - testPropertyValue("font-weight", "bold", "bold"); - }); - - it("font-weight should set / get number", () => { - testPropertyValue("font-weight", "400", "400"); - }); - - it("font-weight should not set / get number greater than 1000", () => { - testPropertyValue("font-weight", "1001", ""); - }); - - it("font-weight should not set / get negative number", () => { - testPropertyValue("font-weight", "-1", ""); - }); - - it("font-size should set / get keyword", () => { - testPropertyValue("font-size", "medium", "medium"); - }); - - it("font-size should set / get keyword", () => { - testPropertyValue("font-size", "larger", "larger"); - }); - - it("font-size should set / get length", () => { - testPropertyValue("font-size", "1em", "1em"); - }); - - it("font-size not should set / get negative length", () => { - testPropertyValue("font-size", "-1em", ""); - }); - - it("font-size should set / get percent", () => { - testPropertyValue("font-size", "90%", "90%"); - }); - - it("font-size should not set / get negative percent", () => { - testPropertyValue("font-size", "-10%", ""); - }); - - it("line-height should set / get keyword", () => { - testPropertyValue("line-height", "normal", "normal"); - }); - - it("line-height should set / get number", () => { - testPropertyValue("line-height", "1.2", "1.2"); - }); - - it("line-height should not set / get negative number", () => { - testPropertyValue("line-height", "-1", ""); - }); - - it("line-height should set / get length", () => { - testPropertyValue("line-height", "10px", "10px"); - }); - - it("line-height should not set / get negative length", () => { - testPropertyValue("line-height", "-10px", ""); - }); - - it("line-height should set / get percent", () => { - testPropertyValue("line-height", "10%", "10%"); - }); - - it("line-height should not set / get negative percent", () => { - testPropertyValue("line-height", "-10%", ""); - }); - - it("font-family should set / get keyword", () => { - testPropertyValue("font-family", "sans-serif", "sans-serif"); - }); - - it("font-family should set / get keyword", () => { - testPropertyValue("font-family", '"sans-serif"', '"sans-serif"'); - }); - - it("font-family should set / get family name", () => { - testPropertyValue("font-family", "Times", "Times"); - }); - - it("font-family should set / get quoted family name", () => { - testPropertyValue("font-family", '"Times New Roman"', '"Times New Roman"'); - }); - - it("font-family should set / get family values", () => { - testPropertyValue( - "font-family", - 'Times, "Times New Roman", Georgia, serif', - 'Times, "Times New Roman", Georgia, serif' - ); - }); - - it("font-family should set / get family values", () => { - testPropertyValue("font-family", "Times\\ New Roman, serif", '"Times New Roman", serif'); - }); - - it("font-family should set / get family values", () => { - testPropertyValue("font-family", '"Times\\ New Roman", serif', '"Times New Roman", serif'); - }); - - it("font-family should set / get family values", () => { - testPropertyValue( - "font-family", - '"Gill Sans Extrabold", sans-serif', - '"Gill Sans Extrabold", sans-serif' - ); - }); - - it("font-family should set / get family values", () => { - testPropertyValue( - "font-family", - '"Goudy Bookletter 1911", sans-serif', - '"Goudy Bookletter 1911", sans-serif' - ); - }); - - it("font-family should not set / get invalid family values", () => { - testPropertyValue("font-family", "Goudy Bookletter 1911, sans-serif", ""); - }); - - it("font-family should not set / get invalid family values", () => { - testPropertyValue("font-family", "Red/Black, sans-serif", ""); - }); - - it("font-family should not set / get invalid family values", () => { - testPropertyValue("font-family", '"Lucida" Grande, sans-serif', ""); - }); - - it("font-family should not set / get invalid family values", () => { - testPropertyValue("font-family", 'Lucida "Grande", sans-serif', ""); - }); - - it("font-family should not set / get invalid family values", () => { - testPropertyValue("font-family", "Ahem!, sans-serif", ""); - }); - - it("font-family should not set / get invalid family values", () => { - testPropertyValue("font-family", "test@foo, sans-serif", ""); - }); - - it("font-family should not set / get invalid family values", () => { - testPropertyValue("font-family", "#POUND, sans-serif", ""); - }); - - it("font-family should not set / get invalid family values", () => { - testPropertyValue("font-family", "Hawaii 5-0, sans-serif", ""); - }); - - it("font-family should set / get family values", () => { - testPropertyValue("font-family", "generic(fangsong)", "generic(fangsong)"); - }); - - it("font-family should set / get family values", () => { - testPropertyValue("font-family", "generic(kai)", "generic(kai)"); - }); - - it("font-family should set / get family values", () => { - testPropertyValue("font-family", "generic(khmer-mul)", "generic(khmer-mul)"); - }); - - it("font-family should set / get family values", () => { - testPropertyValue("font-family", "generic(nastaliq)", "generic(nastaliq)"); - }); - - it("font-family should not set / get invalid family values", () => { - testPropertyValue("font-family", "generic(foo)", ""); - }); - - it("font shorthand should set / get values", () => { - testImplicitPropertyValue( - "font", - 'normal medium Times, "Times New Roman", Georgia, serif', - 'medium Times, "Times New Roman", Georgia, serif', - new Map([ - ["font-style", "normal"], - ["font-variant", "normal"], - ["font-weight", "normal"], - ["font-size", "medium"], - ["line-height", "normal"], - ["font-family", 'Times, "Times New Roman", Georgia, serif'] - ]) - ); - }); - - it("font shorthand should set / get values", () => { - testImplicitPropertyValue( - "font", - "normal medium Gill Sans Extrabold, sans-serif", - 'medium "Gill Sans Extrabold", sans-serif', - new Map([ - ["font-style", "normal"], - ["font-variant", "normal"], - ["font-weight", "normal"], - ["font-size", "medium"], - ["line-height", "normal"], - ["font-family", '"Gill Sans Extrabold", sans-serif'] - ]) - ); - }); - - it("font shorthand should set / get values", () => { - testImplicitPropertyValue( - "font", - 'normal medium "Goudy Bookletter 1911", sans-serif', - 'medium "Goudy Bookletter 1911", sans-serif', - new Map([ - ["font-style", "normal"], - ["font-variant", "normal"], - ["font-weight", "normal"], - ["font-size", "medium"], - ["line-height", "normal"], - ["font-family", '"Goudy Bookletter 1911", sans-serif'] - ]) - ); - }); - - it("font shorthand should set / get values", () => { - testImplicitPropertyValue( - "font", - "normal medium generic(fangsong)", - "medium generic(fangsong)", - new Map([ - ["font-style", "normal"], - ["font-variant", "normal"], - ["font-weight", "normal"], - ["font-size", "medium"], - ["line-height", "normal"], - ["font-family", "generic(fangsong)"] - ]) - ); - }); - - it("font shorthand should not set / get invalid values", () => { - testImplicitPropertyValue( - "font", - "normal medium Goudy Bookletter 1911, sans-serif", - "", - new Map([ - ["font-style", ""], - ["font-variant", ""], - ["font-weight", ""], - ["font-size", ""], - ["line-height", ""], - ["font-family", ""] - ]) - ); - }); - - it("font shorthand should not set / get invalid values", () => { - testImplicitPropertyValue( - "font", - "normal medium Red/Black, sans-serif", - "", - new Map([ - ["font-style", ""], - ["font-variant", ""], - ["font-weight", ""], - ["font-size", ""], - ["line-height", ""], - ["font-family", ""] - ]) - ); - }); - - it("font shorthand should not set / get invalid values", () => { - testImplicitPropertyValue( - "font", - 'normal medium "Lucida" Grande, sans-serif', - "", - new Map([ - ["font-style", ""], - ["font-variant", ""], - ["font-weight", ""], - ["font-size", ""], - ["line-height", ""], - ["font-family", ""] - ]) - ); - }); - - it("font shorthand should not set / get invalid values", () => { - testImplicitPropertyValue( - "font", - 'normal medium Lucida "Grande", sans-serif', - "", - new Map([ - ["font-style", ""], - ["font-variant", ""], - ["font-weight", ""], - ["font-size", ""], - ["line-height", ""], - ["font-family", ""] - ]) - ); - }); - - it("font shorthand should not set / get invalid values", () => { - testImplicitPropertyValue( - "font", - "normal medium Ahem!, sans-serif", - "", - new Map([ - ["font-style", ""], - ["font-variant", ""], - ["font-weight", ""], - ["font-size", ""], - ["line-height", ""], - ["font-family", ""] - ]) - ); - }); - - it("font shorthand should not set / get invalid values", () => { - testImplicitPropertyValue( - "font", - "normal medium test@foo, sans-serif", - "", - new Map([ - ["font-style", ""], - ["font-variant", ""], - ["font-weight", ""], - ["font-size", ""], - ["line-height", ""], - ["font-family", ""] - ]) - ); - }); - - it("font shorthand should not set / get invalid values", () => { - testImplicitPropertyValue( - "font", - "normal medium #POUND, sans-serif", - "", - new Map([ - ["font-style", ""], - ["font-variant", ""], - ["font-weight", ""], - ["font-size", ""], - ["line-height", ""], - ["font-family", ""] - ]) - ); - }); - - it("font shorthand should not set / get invalid values", () => { - testImplicitPropertyValue( - "font", - "normal medium Hawaii 5-0, sans-serif", - "", - new Map([ - ["font-style", ""], - ["font-variant", ""], - ["font-weight", ""], - ["font-size", ""], - ["line-height", ""], - ["font-family", ""] - ]) - ); - }); - - it("font shorthand should set / get values", () => { - testImplicitPropertyValue( - "font", - 'italic bold medium/1.2 Times, "Times New Roman", Georgia, serif', - 'italic bold medium / 1.2 Times, "Times New Roman", Georgia, serif', - new Map([ - ["font-style", "italic"], - ["font-variant", "normal"], - ["font-weight", "bold"], - ["font-size", "medium"], - ["line-height", "1.2"], - ["font-family", 'Times, "Times New Roman", Georgia, serif'] - ]) - ); - }); - - it("font shorthand should set / get values", () => { - testImplicitPropertyValue( - "font", - 'italic bold calc(3em/2)/1.2 Times, "Times New Roman", Georgia, serif', - 'italic bold calc(1.5em) / 1.2 Times, "Times New Roman", Georgia, serif', - new Map([ - ["font-style", "italic"], - ["font-variant", "normal"], - ["font-weight", "bold"], - ["font-size", "calc(1.5em)"], - ["line-height", "1.2"], - ["font-family", 'Times, "Times New Roman", Georgia, serif'] - ]) - ); - }); - - it("font shorthand should set / get values", () => { - testImplicitPropertyValue( - "font", - 'italic bold var(--foo)/1.2 Times, "Times New Roman", Georgia, serif', - 'italic bold var(--foo)/1.2 Times, "Times New Roman", Georgia, serif', - new Map([ - ["font-style", ""], - ["font-variant", ""], - ["font-weight", ""], - ["font-size", ""], - ["line-height", ""], - ["font-family", ""] - ]) - ); - }); - - it("font shorthand should set / get values", () => { - testImplicitPropertyValue( - "font", - "initial", - "initial", - new Map([ - ["font-style", "initial"], - ["font-variant", "initial"], - ["font-weight", "initial"], - ["font-size", "initial"], - ["line-height", "initial"], - ["font-family", "initial"] - ]) - ); - }); -}); - -describe("logical", () => { - it("clear should set / get keyword", () => { - testPropertyValue("clear", "left", "left"); - }); - - it("clear should set / get keyword", () => { - testPropertyValue("clear", "none", "none"); - }); - - it("float should set / get keyword", () => { - testPropertyValue("float", "left", "left"); - }); - - it("float should set / get keyword", () => { - testPropertyValue("float", "none", "none"); - }); -}); - -describe("masking", () => { - it("clip should set / get keyword", () => { - testPropertyValue("clip", "auto", "auto"); - }); - - it("clip should set / get legacy ", () => { - testPropertyValue("clip", "rect(0, 10px, 20%, 40EM)", "rect(0px, 10px, 20%, 40em)"); - }); -}); - -describe("positioning", () => { - it("bottom should set / get keyword", () => { - testPropertyValue("bottom", "auto", "auto"); - }); - - it("bottom should set / get length", () => { - testPropertyValue("bottom", "10px", "10px"); - }); - - it("bottom should set / get percent", () => { - testPropertyValue("bottom", "10%", "10%"); - }); - - it("left should set / get keyword", () => { - testPropertyValue("left", "auto", "auto"); - }); - - it("left should set / get length", () => { - testPropertyValue("left", "10px", "10px"); - }); - - it("left should set / get percent", () => { - testPropertyValue("left", "10%", "10%"); - }); - - it("right should set / get keyword", () => { - testPropertyValue("right", "auto", "auto"); - }); - - it("right should set / get length", () => { - testPropertyValue("right", "10px", "10px"); - }); - - it("right should set / get percent", () => { - testPropertyValue("right", "10%", "10%"); - }); - - it("top should set / get keyword", () => { - testPropertyValue("top", "auto", "auto"); - }); - - it("top should set / get length", () => { - testPropertyValue("top", "10px", "10px"); - }); - - it("top should set / get percent", () => { - testPropertyValue("top", "10%", "10%"); - }); -}); - -describe("user interface", () => { - it("outline-color should set / get color name", () => { - testPropertyValue("outline-color", "green", "green"); - }); - - it("outline-color should set / get hex color", () => { - testPropertyValue("outline-color", "#008000", "rgb(0, 128, 0)"); - }); - - it("outline-color should set / get color function", () => { - testPropertyValue("outline-color", "rgb(0 128 0)", "rgb(0, 128, 0)"); - }); -});