Complete Email Sortierer implementation with Appwrite and Stripe integration

This commit is contained in:
2026-01-14 20:02:16 +01:00
commit 95349af50b
3355 changed files with 644802 additions and 0 deletions

16
server/node_modules/.bin/mime generated vendored Normal file
View File

@@ -0,0 +1,16 @@
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*|*MINGW*|*MSYS*)
if command -v cygpath > /dev/null 2>&1; then
basedir=`cygpath -w "$basedir"`
fi
;;
esac
if [ -x "$basedir/node" ]; then
exec "$basedir/node" "$basedir/../mime/cli.js" "$@"
else
exec node "$basedir/../mime/cli.js" "$@"
fi

17
server/node_modules/.bin/mime.cmd generated vendored Normal file
View File

@@ -0,0 +1,17 @@
@ECHO off
GOTO start
:find_dp0
SET dp0=%~dp0
EXIT /b
:start
SETLOCAL
CALL :find_dp0
IF EXIST "%dp0%\node.exe" (
SET "_prog=%dp0%\node.exe"
) ELSE (
SET "_prog=node"
SET PATHEXT=%PATHEXT:;.JS;=;%
)
endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\mime\cli.js" %*

28
server/node_modules/.bin/mime.ps1 generated vendored Normal file
View File

@@ -0,0 +1,28 @@
#!/usr/bin/env pwsh
$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
$exe=""
if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
# Fix case when both the Windows and Linux builds of Node
# are installed in the same directory
$exe=".exe"
}
$ret=0
if (Test-Path "$basedir/node$exe") {
# Support pipeline input
if ($MyInvocation.ExpectingInput) {
$input | & "$basedir/node$exe" "$basedir/../mime/cli.js" $args
} else {
& "$basedir/node$exe" "$basedir/../mime/cli.js" $args
}
$ret=$LASTEXITCODE
} else {
# Support pipeline input
if ($MyInvocation.ExpectingInput) {
$input | & "node$exe" "$basedir/../mime/cli.js" $args
} else {
& "node$exe" "$basedir/../mime/cli.js" $args
}
$ret=$LASTEXITCODE
}
exit $ret

16
server/node_modules/.bin/tldts generated vendored Normal file
View File

@@ -0,0 +1,16 @@
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*|*MINGW*|*MSYS*)
if command -v cygpath > /dev/null 2>&1; then
basedir=`cygpath -w "$basedir"`
fi
;;
esac
if [ -x "$basedir/node" ]; then
exec "$basedir/node" "$basedir/../tldts/bin/cli.js" "$@"
else
exec node "$basedir/../tldts/bin/cli.js" "$@"
fi

17
server/node_modules/.bin/tldts.cmd generated vendored Normal file
View File

@@ -0,0 +1,17 @@
@ECHO off
GOTO start
:find_dp0
SET dp0=%~dp0
EXIT /b
:start
SETLOCAL
CALL :find_dp0
IF EXIST "%dp0%\node.exe" (
SET "_prog=%dp0%\node.exe"
) ELSE (
SET "_prog=node"
SET PATHEXT=%PATHEXT:;.JS;=;%
)
endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\tldts\bin\cli.js" %*

28
server/node_modules/.bin/tldts.ps1 generated vendored Normal file
View File

@@ -0,0 +1,28 @@
#!/usr/bin/env pwsh
$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
$exe=""
if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
# Fix case when both the Windows and Linux builds of Node
# are installed in the same directory
$exe=".exe"
}
$ret=0
if (Test-Path "$basedir/node$exe") {
# Support pipeline input
if ($MyInvocation.ExpectingInput) {
$input | & "$basedir/node$exe" "$basedir/../tldts/bin/cli.js" $args
} else {
& "$basedir/node$exe" "$basedir/../tldts/bin/cli.js" $args
}
$ret=$LASTEXITCODE
} else {
# Support pipeline input
if ($MyInvocation.ExpectingInput) {
$input | & "node$exe" "$basedir/../tldts/bin/cli.js" $args
} else {
& "node$exe" "$basedir/../tldts/bin/cli.js" $args
}
$ret=$LASTEXITCODE
}
exit $ret

1506
server/node_modules/.package-lock.json generated vendored Normal file

File diff suppressed because it is too large Load Diff

20
server/node_modules/@acemir/cssom/LICENSE.txt generated vendored Normal file
View File

@@ -0,0 +1,20 @@
Copyright (c) Nikita Vasilyev
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

64
server/node_modules/@acemir/cssom/README.mdown generated vendored Normal file
View File

@@ -0,0 +1,64 @@
# CSSOM
CSSOM.js is a CSS parser written in pure JavaScript. It is also a partial implementation of [CSS Object Model](http://dev.w3.org/csswg/cssom/).
CSSOM.parse("body {color: black}")
-> {
cssRules: [
{
selectorText: "body",
style: {
0: "color",
color: "black",
length: 1
}
}
]
}
## [Parser demo](https://acemir.github.io/CSSOM/docs/parse.html)
Works well in Google Chrome 6+, Safari 5+, Firefox 3.6+, Opera 10.63+.
Doesn't work in IE < 9 because of unsupported getters/setters.
To use CSSOM.js in the browser you might want to build a one-file version that exposes a single `CSSOM` global variable:
➤ git clone https://github.com/acemir/CSSOM.git
➤ cd CSSOM
➤ node build.js
build/CSSOM.js is done
To use it with Node.js or any other CommonJS loader:
➤ npm install @acemir/cssom
## Dont use it if...
You parse CSS to mungle, minify or reformat code like this:
```css
div {
background: gray;
background: linear-gradient(to bottom, white 0%, black 100%);
}
```
This pattern is often used to give browsers that dont understand linear gradients a fallback solution (e.g. gray color in the example).
In CSSOM, `background: gray` [gets overwritten](http://nv.github.io/CSSOM/docs/parse.html#css=div%20%7B%0A%20%20%20%20%20%20background%3A%20gray%3B%0A%20%20%20%20background%3A%20linear-gradient(to%20bottom%2C%20white%200%25%2C%20black%20100%25)%3B%0A%7D).
It does **NOT** get preserved.
If you do CSS mungling, minification, or image inlining, considere using one of the following:
* [postcss](https://github.com/postcss/postcss)
* [reworkcss/css](https://github.com/reworkcss/css)
* [csso](https://github.com/css/csso)
* [mensch](https://github.com/brettstimmerman/mensch)
## [Tests](https://acemir.github.io/CSSOM/spec/)
To run tests locally:
➤ git submodule init
➤ git submodule update

6611
server/node_modules/@acemir/cssom/build/CSSOM.js generated vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,32 @@
//.CommonJS
var CSSOM = {
CSSRule: require("./CSSRule").CSSRule,
CSSRuleList: require("./CSSRuleList").CSSRuleList,
CSSGroupingRule: require("./CSSGroupingRule").CSSGroupingRule
};
///CommonJS
/**
* @constructor
* @see https://www.w3.org/TR/css-conditional-3/#the-cssconditionrule-interface
*/
CSSOM.CSSConditionRule = function CSSConditionRule() {
CSSOM.CSSGroupingRule.call(this);
this.__conditionText = '';
};
CSSOM.CSSConditionRule.prototype = Object.create(CSSOM.CSSGroupingRule.prototype);
CSSOM.CSSConditionRule.prototype.constructor = CSSOM.CSSConditionRule;
Object.setPrototypeOf(CSSOM.CSSConditionRule, CSSOM.CSSGroupingRule);
Object.defineProperty(CSSOM.CSSConditionRule.prototype, "conditionText", {
get: function () {
return this.__conditionText;
}
});
//.CommonJS
exports.CSSConditionRule = CSSOM.CSSConditionRule;
///CommonJS

View File

@@ -0,0 +1,70 @@
//.CommonJS
var CSSOM = {
CSSRule: require("./CSSRule").CSSRule,
CSSRuleList: require("./CSSRuleList").CSSRuleList,
CSSGroupingRule: require("./CSSGroupingRule").CSSGroupingRule,
CSSConditionRule: require("./CSSConditionRule").CSSConditionRule,
};
///CommonJS
/**
* @constructor
* @see https://drafts.csswg.org/css-contain-3/
* @see https://www.w3.org/TR/css-contain-3/
*/
CSSOM.CSSContainerRule = function CSSContainerRule() {
CSSOM.CSSConditionRule.call(this);
};
CSSOM.CSSContainerRule.prototype = Object.create(CSSOM.CSSConditionRule.prototype);
CSSOM.CSSContainerRule.prototype.constructor = CSSOM.CSSContainerRule;
Object.setPrototypeOf(CSSOM.CSSContainerRule, CSSOM.CSSConditionRule);
Object.defineProperty(CSSOM.CSSContainerRule.prototype, "type", {
value: 17,
writable: false
});
Object.defineProperties(CSSOM.CSSContainerRule.prototype, {
"cssText": {
get: function() {
var values = "";
var valuesArr = [" {"];
if (this.cssRules.length) {
valuesArr.push(this.cssRules.reduce(function(acc, rule){
if (rule.cssText !== "") {
acc.push(rule.cssText);
}
return acc;
}, []).join("\n "));
}
values = valuesArr.join("\n ") + "\n}";
return "@container " + this.conditionText + values;
}
},
"containerName": {
get: function() {
var parts = this.conditionText.trim().split(/\s+/);
if (parts.length > 1 && parts[0] !== '(' && !parts[0].startsWith('(')) {
return parts[0];
}
return "";
}
},
"containerQuery": {
get: function() {
var parts = this.conditionText.trim().split(/\s+/);
if (parts.length > 1 && parts[0] !== '(' && !parts[0].startsWith('(')) {
return parts.slice(1).join(' ');
}
return this.conditionText;
}
},
});
//.CommonJS
exports.CSSContainerRule = CSSOM.CSSContainerRule;
///CommonJS

View File

@@ -0,0 +1,57 @@
//.CommonJS
var CSSOM = {
CSSRule: require("./CSSRule").CSSRule
};
///CommonJS
/**
* @constructor
* @see https://drafts.csswg.org/css-counter-styles/#the-csscounterstylerule-interface
*/
CSSOM.CSSCounterStyleRule = function CSSCounterStyleRule() {
CSSOM.CSSRule.call(this);
this.name = "";
this.__props = "";
};
CSSOM.CSSCounterStyleRule.prototype = Object.create(CSSOM.CSSRule.prototype);
CSSOM.CSSCounterStyleRule.prototype.constructor = CSSOM.CSSCounterStyleRule;
Object.setPrototypeOf(CSSOM.CSSCounterStyleRule, CSSOM.CSSRule);
Object.defineProperty(CSSOM.CSSCounterStyleRule.prototype, "type", {
value: 11,
writable: false
});
Object.defineProperty(CSSOM.CSSCounterStyleRule.prototype, "cssText", {
get: function() {
// FIXME : Implement real cssText generation based on properties
return "@counter-style " + this.name + " { " + this.__props + " }";
}
});
/**
* NON-STANDARD
* Rule text parser.
* @param {string} cssText
*/
Object.defineProperty(CSSOM.CSSCounterStyleRule.prototype, "parse", {
value: function(cssText) {
// Extract the name from "@counter-style <name> { ... }"
var match = cssText.match(/@counter-style\s+([^\s{]+)\s*\{([^]*)\}/);
if (match) {
this.name = match[1];
// Get the text inside the brackets and clean it up
var propsText = match[2];
this.__props = propsText.trim().replace(/\n/g, " ").replace(/(['"])(?:\\.|[^\\])*?\1|(\s{2,})/g, function (match, quote) {
return quote ? match : ' ';
});
}
}
});
//.CommonJS
exports.CSSCounterStyleRule = CSSOM.CSSCounterStyleRule;
///CommonJS

View File

@@ -0,0 +1,48 @@
//.CommonJS
var CSSOM = {
CSSRule: require("./CSSRule").CSSRule,
CSSRuleList: require("./CSSRuleList").CSSRuleList,
MatcherList: require("./MatcherList").MatcherList
};
///CommonJS
/**
* @constructor
* @see https://developer.mozilla.org/en/CSS/@-moz-document
* @deprecated This rule is a non-standard Mozilla-specific extension and is not part of any official CSS specification.
*/
CSSOM.CSSDocumentRule = function CSSDocumentRule() {
CSSOM.CSSRule.call(this);
this.matcher = new CSSOM.MatcherList();
this.cssRules = new CSSOM.CSSRuleList();
};
CSSOM.CSSDocumentRule.prototype = Object.create(CSSOM.CSSRule.prototype);
CSSOM.CSSDocumentRule.prototype.constructor = CSSOM.CSSDocumentRule;
Object.setPrototypeOf(CSSOM.CSSDocumentRule, CSSOM.CSSRule);
Object.defineProperty(CSSOM.CSSDocumentRule.prototype, "type", {
value: 10,
writable: false
});
//FIXME
//CSSOM.CSSDocumentRule.prototype.insertRule = CSSStyleSheet.prototype.insertRule;
//CSSOM.CSSDocumentRule.prototype.deleteRule = CSSStyleSheet.prototype.deleteRule;
Object.defineProperty(CSSOM.CSSDocumentRule.prototype, "cssText", {
get: function() {
var cssTexts = [];
for (var i=0, length=this.cssRules.length; i < length; i++) {
cssTexts.push(this.cssRules[i].cssText);
}
return "@-moz-document " + this.matcher.matcherText + " {" + (cssTexts.length ? "\n " + cssTexts.join("\n ") : "") + "\n}";
}
});
//.CommonJS
exports.CSSDocumentRule = CSSOM.CSSDocumentRule;
///CommonJS

View File

@@ -0,0 +1,62 @@
//.CommonJS
var CSSOM = {
CSSStyleDeclaration: require("./CSSStyleDeclaration").CSSStyleDeclaration,
CSSRule: require("./CSSRule").CSSRule
};
// Use cssstyle if available
try {
CSSOM.CSSStyleDeclaration = require("cssstyle").CSSStyleDeclaration;
} catch (e) {
// ignore
}
///CommonJS
/**
* @constructor
* @see http://dev.w3.org/csswg/cssom/#css-font-face-rule
*/
CSSOM.CSSFontFaceRule = function CSSFontFaceRule() {
CSSOM.CSSRule.call(this);
this.__style = new CSSOM.CSSStyleDeclaration();
this.__style.parentRule = this;
};
CSSOM.CSSFontFaceRule.prototype = Object.create(CSSOM.CSSRule.prototype);
CSSOM.CSSFontFaceRule.prototype.constructor = CSSOM.CSSFontFaceRule;
Object.setPrototypeOf(CSSOM.CSSFontFaceRule, CSSOM.CSSRule);
Object.defineProperty(CSSOM.CSSFontFaceRule.prototype, "type", {
value: 5,
writable: false
});
//FIXME
//CSSOM.CSSFontFaceRule.prototype.insertRule = CSSStyleSheet.prototype.insertRule;
//CSSOM.CSSFontFaceRule.prototype.deleteRule = CSSStyleSheet.prototype.deleteRule;
Object.defineProperty(CSSOM.CSSFontFaceRule.prototype, "style", {
get: function() {
return this.__style;
},
set: function(value) {
if (typeof value === "string") {
this.__style.cssText = value;
} else {
this.__style = value;
}
}
});
// http://www.opensource.apple.com/source/WebCore/WebCore-955.66.1/css/WebKitCSSFontFaceRule.cpp
Object.defineProperty(CSSOM.CSSFontFaceRule.prototype, "cssText", {
get: function() {
return "@font-face {" + (this.style.cssText ? " " + this.style.cssText : "") + " }";
}
});
//.CommonJS
exports.CSSFontFaceRule = CSSOM.CSSFontFaceRule;
///CommonJS

View File

@@ -0,0 +1,165 @@
//.CommonJS
var CSSOM = {
CSSRule: require("./CSSRule").CSSRule,
CSSRuleList: require("./CSSRuleList").CSSRuleList,
parse: require('./parse').parse
};
var errorUtils = require("./errorUtils").errorUtils;
///CommonJS
/**
* @constructor
* @see https://drafts.csswg.org/cssom/#the-cssgroupingrule-interface
*/
CSSOM.CSSGroupingRule = function CSSGroupingRule() {
CSSOM.CSSRule.call(this);
this.__cssRules = new CSSOM.CSSRuleList();
};
CSSOM.CSSGroupingRule.prototype = Object.create(CSSOM.CSSRule.prototype);
CSSOM.CSSGroupingRule.prototype.constructor = CSSOM.CSSGroupingRule;
Object.setPrototypeOf(CSSOM.CSSGroupingRule, CSSOM.CSSRule);
Object.defineProperty(CSSOM.CSSGroupingRule.prototype, "cssRules", {
get: function() {
return this.__cssRules;
}
});
/**
* Used to insert a new CSS rule to a list of CSS rules.
*
* @example
* cssGroupingRule.cssText
* -> "body{margin:0;}"
* cssGroupingRule.insertRule("img{border:none;}", 1)
* -> 1
* cssGroupingRule.cssText
* -> "body{margin:0;}img{border:none;}"
*
* @param {string} rule
* @param {number} [index]
* @see https://www.w3.org/TR/cssom-1/#dom-cssgroupingrule-insertrule
* @return {number} The index within the grouping rule's collection of the newly inserted rule.
*/
CSSOM.CSSGroupingRule.prototype.insertRule = function insertRule(rule, index) {
if (rule === undefined && index === undefined) {
errorUtils.throwMissingArguments(this, 'insertRule', this.constructor.name);
}
if (index === void 0) {
index = 0;
}
index = Number(index);
if (index < 0) {
index = 4294967296 + index;
}
if (index > this.cssRules.length) {
errorUtils.throwIndexError(this, 'insertRule', this.constructor.name, index, this.cssRules.length);
}
var ruleToParse = processedRuleToParse = String(rule);
ruleToParse = ruleToParse.trim().replace(/^\/\*[\s\S]*?\*\/\s*/, "");
var isNestedSelector = this.constructor.name === "CSSStyleRule";
if (isNestedSelector === false) {
var currentRule = this;
while (currentRule.parentRule) {
currentRule = currentRule.parentRule;
if (currentRule.constructor.name === "CSSStyleRule") {
isNestedSelector = true;
break;
}
}
}
if (isNestedSelector) {
processedRuleToParse = 's { n { } ' + ruleToParse + '}';
}
var isScopeRule = this.constructor.name === "CSSScopeRule";
if (isScopeRule) {
if (isNestedSelector) {
processedRuleToParse = 's { ' + '@scope {' + ruleToParse + '}}';
} else {
processedRuleToParse = '@scope {' + ruleToParse + '}';
}
}
var parsedRules = new CSSOM.CSSRuleList();
CSSOM.parse(processedRuleToParse, {
styleSheet: this.parentStyleSheet,
cssRules: parsedRules
});
if (isScopeRule) {
if (isNestedSelector) {
parsedRules = parsedRules[0].cssRules[0].cssRules;
} else {
parsedRules = parsedRules[0].cssRules
}
}
if (isNestedSelector) {
parsedRules = parsedRules[0].cssRules.slice(1);
}
if (parsedRules.length !== 1) {
if (isNestedSelector && parsedRules.length === 0 && ruleToParse.indexOf('@font-face') === 0) {
errorUtils.throwError(this, 'DOMException',
"Failed to execute 'insertRule' on '" + this.constructor.name + "': " +
"Only conditional nested group rules, style rules, @scope rules, @apply rules, and nested declaration rules may be nested.",
'HierarchyRequestError');
} else {
errorUtils.throwParseError(this, 'insertRule', this.constructor.name, ruleToParse, 'SyntaxError');
}
}
var cssRule = parsedRules[0];
if (cssRule.constructor.name === 'CSSNestedDeclarations' && cssRule.style.length === 0) {
errorUtils.throwParseError(this, 'insertRule', this.constructor.name, ruleToParse, 'SyntaxError');
}
// Check for rules that cannot be inserted inside a CSSGroupingRule
if (cssRule.constructor.name === 'CSSImportRule' || cssRule.constructor.name === 'CSSNamespaceRule') {
var ruleKeyword = cssRule.constructor.name === 'CSSImportRule' ? '@import' : '@namespace';
errorUtils.throwError(this, 'DOMException',
"Failed to execute 'insertRule' on '" + this.constructor.name + "': " +
"'" + ruleKeyword + "' rules cannot be inserted inside a group rule.",
'HierarchyRequestError');
}
// Check for CSSLayerStatementRule (@layer statement rules)
if (cssRule.constructor.name === 'CSSLayerStatementRule') {
errorUtils.throwParseError(this, 'insertRule', this.constructor.name, ruleToParse, 'SyntaxError');
}
cssRule.__parentRule = this;
this.cssRules.splice(index, 0, cssRule);
return index;
};
/**
* Used to delete a rule from the grouping rule.
*
* cssGroupingRule.cssText
* -> "img{border:none;}body{margin:0;}"
* cssGroupingRule.deleteRule(0)
* cssGroupingRule.cssText
* -> "body{margin:0;}"
*
* @param {number} index within the grouping rule's rule list of the rule to remove.
* @see https://www.w3.org/TR/cssom-1/#dom-cssgroupingrule-deleterule
*/
CSSOM.CSSGroupingRule.prototype.deleteRule = function deleteRule(index) {
if (index === undefined) {
errorUtils.throwMissingArguments(this, 'deleteRule', this.constructor.name);
}
index = Number(index);
if (index < 0) {
index = 4294967296 + index;
}
if (index >= this.cssRules.length) {
errorUtils.throwIndexError(this, 'deleteRule', this.constructor.name, index, this.cssRules.length);
}
this.cssRules[index].__parentRule = null;
this.cssRules[index].__parentStyleSheet = null;
this.cssRules.splice(index, 1);
};
//.CommonJS
exports.CSSGroupingRule = CSSOM.CSSGroupingRule;
///CommonJS

54
server/node_modules/@acemir/cssom/lib/CSSHostRule.js generated vendored Normal file
View File

@@ -0,0 +1,54 @@
//.CommonJS
var CSSOM = {
CSSRule: require("./CSSRule").CSSRule,
CSSRuleList: require("./CSSRuleList").CSSRuleList
};
///CommonJS
/**
* @constructor
* @see http://www.w3.org/TR/shadow-dom/#host-at-rule
* @see http://html5index.org/Shadow%20DOM%20-%20CSSHostRule.html
* @deprecated This rule was part of early Shadow DOM drafts but was removed in favor of the more flexible :host and :host-context() pseudo-classes in modern CSS for Web Components.
*/
CSSOM.CSSHostRule = function CSSHostRule() {
CSSOM.CSSRule.call(this);
this.cssRules = new CSSOM.CSSRuleList();
};
CSSOM.CSSHostRule.prototype = Object.create(CSSOM.CSSRule.prototype);
CSSOM.CSSHostRule.prototype.constructor = CSSOM.CSSHostRule;
Object.setPrototypeOf(CSSOM.CSSHostRule, CSSOM.CSSRule);
Object.defineProperty(CSSOM.CSSHostRule.prototype, "type", {
value: 1001,
writable: false
});
//FIXME
//CSSOM.CSSHostRule.prototype.insertRule = CSSStyleSheet.prototype.insertRule;
//CSSOM.CSSHostRule.prototype.deleteRule = CSSStyleSheet.prototype.deleteRule;
Object.defineProperty(CSSOM.CSSHostRule.prototype, "cssText", {
get: function() {
var values = "";
var valuesArr = [" {"];
if (this.cssRules.length) {
valuesArr.push(this.cssRules.reduce(function(acc, rule){
if (rule.cssText !== "") {
acc.push(rule.cssText);
}
return acc;
}, []).join("\n "));
}
values = valuesArr.join("\n ") + "\n}";
return "@host" + values;
}
});
//.CommonJS
exports.CSSHostRule = CSSOM.CSSHostRule;
///CommonJS

267
server/node_modules/@acemir/cssom/lib/CSSImportRule.js generated vendored Normal file
View File

@@ -0,0 +1,267 @@
//.CommonJS
var CSSOM = {
CSSRule: require("./CSSRule").CSSRule,
CSSStyleSheet: require("./CSSStyleSheet").CSSStyleSheet,
MediaList: require("./MediaList").MediaList
};
var regexPatterns = require("./regexPatterns").regexPatterns;
///CommonJS
/**
* @constructor
* @see http://dev.w3.org/csswg/cssom/#cssimportrule
* @see http://www.w3.org/TR/DOM-Level-2-Style/css.html#CSS-CSSImportRule
*/
CSSOM.CSSImportRule = function CSSImportRule() {
CSSOM.CSSRule.call(this);
this.__href = "";
this.__media = new CSSOM.MediaList();
this.__layerName = null;
this.__supportsText = null;
this.__styleSheet = new CSSOM.CSSStyleSheet();
};
CSSOM.CSSImportRule.prototype = Object.create(CSSOM.CSSRule.prototype);
CSSOM.CSSImportRule.prototype.constructor = CSSOM.CSSImportRule;
Object.setPrototypeOf(CSSOM.CSSImportRule, CSSOM.CSSRule);
Object.defineProperty(CSSOM.CSSImportRule.prototype, "type", {
value: 3,
writable: false
});
Object.defineProperty(CSSOM.CSSImportRule.prototype, "cssText", {
get: function() {
var mediaText = this.media.mediaText;
return "@import url(\"" + this.href.replace(/\\/g, '\\\\').replace(/"/g, '\\"') + "\")" + (this.layerName !== null ? " layer" + (this.layerName && "(" + this.layerName + ")") : "" ) + (this.supportsText ? " supports(" + this.supportsText + ")" : "" ) + (mediaText ? " " + mediaText : "") + ";";
}
});
Object.defineProperty(CSSOM.CSSImportRule.prototype, "href", {
get: function() {
return this.__href;
}
});
Object.defineProperty(CSSOM.CSSImportRule.prototype, "media", {
get: function() {
return this.__media;
},
set: function(value) {
if (typeof value === "string") {
this.__media.mediaText = value;
} else {
this.__media = value;
}
}
});
Object.defineProperty(CSSOM.CSSImportRule.prototype, "layerName", {
get: function() {
return this.__layerName;
}
});
Object.defineProperty(CSSOM.CSSImportRule.prototype, "supportsText", {
get: function() {
return this.__supportsText;
}
});
Object.defineProperty(CSSOM.CSSImportRule.prototype, "styleSheet", {
get: function() {
return this.__styleSheet;
}
});
/**
* NON-STANDARD
* Rule text parser.
* @param {string} cssText
*/
Object.defineProperty(CSSOM.CSSImportRule.prototype, "parse", {
value: function(cssText) {
var i = 0;
/**
* @import url(partial.css) screen, handheld;
* || |
* after-import media
* |
* url
*/
var state = '';
var buffer = '';
var index;
var layerRegExp = regexPatterns.layerRegExp;
var layerRuleNameRegExp = regexPatterns.layerRuleNameRegExp;
var doubleOrMoreSpacesRegExp = regexPatterns.doubleOrMoreSpacesRegExp;
/**
* Extracts the content inside supports() handling nested parentheses.
* @param {string} text - The text to parse
* @returns {object|null} - {content: string, endIndex: number} or null if not found
*/
function extractSupportsContent(text) {
var supportsIndex = text.indexOf('supports(');
if (supportsIndex !== 0) {
return null;
}
var depth = 0;
var start = supportsIndex + 'supports('.length;
var i = start;
for (; i < text.length; i++) {
if (text[i] === '(') {
depth++;
} else if (text[i] === ')') {
if (depth === 0) {
// Found the closing parenthesis for supports()
return {
content: text.slice(start, i),
endIndex: i
};
}
depth--;
}
}
return null; // Unbalanced parentheses
}
for (var character; (character = cssText.charAt(i)); i++) {
switch (character) {
case ' ':
case '\t':
case '\r':
case '\n':
case '\f':
if (state === 'after-import') {
state = 'url';
} else {
buffer += character;
}
break;
case '@':
if (!state && cssText.indexOf('@import', i) === i) {
state = 'after-import';
i += 'import'.length;
buffer = '';
}
break;
case 'u':
if (state === 'media') {
buffer += character;
}
if (state === 'url' && cssText.indexOf('url(', i) === i) {
index = cssText.indexOf(')', i + 1);
if (index === -1) {
throw i + ': ")" not found';
}
i += 'url('.length;
var url = cssText.slice(i, index);
if (url[0] === url[url.length - 1]) {
if (url[0] === '"' || url[0] === "'") {
url = url.slice(1, -1);
}
}
this.__href = url;
i = index;
state = 'media';
}
break;
case '"':
if (state === 'after-import' || state === 'url') {
index = cssText.indexOf('"', i + 1);
if (!index) {
throw i + ": '\"' not found";
}
this.__href = cssText.slice(i + 1, index);
i = index;
state = 'media';
}
break;
case "'":
if (state === 'after-import' || state === 'url') {
index = cssText.indexOf("'", i + 1);
if (!index) {
throw i + ': "\'" not found';
}
this.__href = cssText.slice(i + 1, index);
i = index;
state = 'media';
}
break;
case ';':
if (state === 'media') {
if (buffer) {
var bufferTrimmed = buffer.trim();
if (bufferTrimmed.indexOf('layer') === 0) {
var layerMatch = bufferTrimmed.match(layerRegExp);
if (layerMatch) {
var layerName = layerMatch[1].trim();
if (layerName.match(layerRuleNameRegExp) !== null) {
this.__layerName = layerMatch[1].trim();
bufferTrimmed = bufferTrimmed.replace(layerRegExp, '')
.replace(doubleOrMoreSpacesRegExp, ' ') // Replace double or more spaces with single space
.trim();
} else {
// REVIEW: In the browser, an empty layer() is not processed as a unamed layer
// and treats the rest of the string as mediaText, ignoring the parse of supports()
if (bufferTrimmed) {
this.media.mediaText = bufferTrimmed;
return;
}
}
} else {
this.__layerName = "";
bufferTrimmed = bufferTrimmed.substring('layer'.length).trim()
}
}
var supportsResult = extractSupportsContent(bufferTrimmed);
if (supportsResult) {
// REVIEW: In the browser, an empty supports() invalidates and ignores the entire @import rule
this.__supportsText = supportsResult.content.trim();
// Remove the entire supports(...) from the buffer
bufferTrimmed = bufferTrimmed.slice(0, 0) + bufferTrimmed.slice(supportsResult.endIndex + 1);
bufferTrimmed = bufferTrimmed.replace(doubleOrMoreSpacesRegExp, ' ').trim();
}
// REVIEW: In the browser, any invalid media is replaced with 'not all'
if (bufferTrimmed) {
this.media.mediaText = bufferTrimmed;
}
}
}
break;
default:
if (state === 'media') {
buffer += character;
}
break;
}
}
}
});
//.CommonJS
exports.CSSImportRule = CSSOM.CSSImportRule;
///CommonJS

View File

@@ -0,0 +1,63 @@
//.CommonJS
var CSSOM = {
CSSRule: require("./CSSRule").CSSRule,
CSSStyleDeclaration: require('./CSSStyleDeclaration').CSSStyleDeclaration
};
// Use cssstyle if available
try {
CSSOM.CSSStyleDeclaration = require("cssstyle").CSSStyleDeclaration;
} catch (e) {
// ignore
}
///CommonJS
/**
* @constructor
* @see http://www.w3.org/TR/css3-animations/#DOM-CSSKeyframeRule
*/
CSSOM.CSSKeyframeRule = function CSSKeyframeRule() {
CSSOM.CSSRule.call(this);
this.keyText = '';
this.__style = new CSSOM.CSSStyleDeclaration();
this.__style.parentRule = this;
};
CSSOM.CSSKeyframeRule.prototype = Object.create(CSSOM.CSSRule.prototype);
CSSOM.CSSKeyframeRule.prototype.constructor = CSSOM.CSSKeyframeRule;
Object.setPrototypeOf(CSSOM.CSSKeyframeRule, CSSOM.CSSRule);
Object.defineProperty(CSSOM.CSSKeyframeRule.prototype, "type", {
value: 8,
writable: false
});
//FIXME
//CSSOM.CSSKeyframeRule.prototype.insertRule = CSSStyleSheet.prototype.insertRule;
//CSSOM.CSSKeyframeRule.prototype.deleteRule = CSSStyleSheet.prototype.deleteRule;
Object.defineProperty(CSSOM.CSSKeyframeRule.prototype, "style", {
get: function() {
return this.__style;
},
set: function(value) {
if (typeof value === "string") {
this.__style.cssText = value;
} else {
this.__style = value;
}
}
});
// http://www.opensource.apple.com/source/WebCore/WebCore-955.66.1/css/WebKitCSSKeyframeRule.cpp
Object.defineProperty(CSSOM.CSSKeyframeRule.prototype, "cssText", {
get: function() {
return this.keyText + " {" + (this.style.cssText ? " " + this.style.cssText : "") + " }";
}
});
//.CommonJS
exports.CSSKeyframeRule = CSSOM.CSSKeyframeRule;
///CommonJS

View File

@@ -0,0 +1,247 @@
//.CommonJS
var CSSOM = {
CSSRule: require("./CSSRule").CSSRule,
CSSRuleList: require("./CSSRuleList").CSSRuleList,
parse: require("./parse").parse
};
var errorUtils = require("./errorUtils").errorUtils;
///CommonJS
/**
* @constructor
* @see http://www.w3.org/TR/css3-animations/#DOM-CSSKeyframesRule
*/
CSSOM.CSSKeyframesRule = function CSSKeyframesRule() {
CSSOM.CSSRule.call(this);
this.name = '';
this.cssRules = new CSSOM.CSSRuleList();
// Set up initial indexed access
this._setupIndexedAccess();
// Override cssRules methods after initial setup, store references as non-enumerable properties
var self = this;
var originalPush = this.cssRules.push;
var originalSplice = this.cssRules.splice;
// Create non-enumerable method overrides
Object.defineProperty(this.cssRules, 'push', {
value: function() {
var result = originalPush.apply(this, arguments);
self._setupIndexedAccess();
return result;
},
writable: true,
enumerable: false,
configurable: true
});
Object.defineProperty(this.cssRules, 'splice', {
value: function() {
var result = originalSplice.apply(this, arguments);
self._setupIndexedAccess();
return result;
},
writable: true,
enumerable: false,
configurable: true
});
};
CSSOM.CSSKeyframesRule.prototype = Object.create(CSSOM.CSSRule.prototype);
CSSOM.CSSKeyframesRule.prototype.constructor = CSSOM.CSSKeyframesRule;
Object.setPrototypeOf(CSSOM.CSSKeyframesRule, CSSOM.CSSRule);
Object.defineProperty(CSSOM.CSSKeyframesRule.prototype, "type", {
value: 7,
writable: false
});
// http://www.opensource.apple.com/source/WebCore/WebCore-955.66.1/css/WebKitCSSKeyframesRule.cpp
Object.defineProperty(CSSOM.CSSKeyframesRule.prototype, "cssText", {
get: function() {
var values = "";
var valuesArr = [" {"];
if (this.cssRules.length) {
valuesArr.push(this.cssRules.reduce(function(acc, rule){
if (rule.cssText !== "") {
acc.push(rule.cssText);
}
return acc;
}, []).join("\n "));
}
values = valuesArr.join("\n ") + "\n}";
var cssWideKeywords = ['initial', 'inherit', 'revert', 'revert-layer', 'unset', 'none'];
var processedName = cssWideKeywords.includes(this.name) ? '"' + this.name + '"' : this.name;
return "@" + (this._vendorPrefix || '') + "keyframes " + processedName + values;
}
});
/**
* Appends a new keyframe rule to the list of keyframes.
*
* @param {string} rule - The keyframe rule string to append (e.g., "50% { opacity: 0.5; }")
* @see https://www.w3.org/TR/css-animations-1/#dom-csskeyframesrule-appendrule
*/
CSSOM.CSSKeyframesRule.prototype.appendRule = function appendRule(rule) {
if (arguments.length === 0) {
errorUtils.throwMissingArguments(this, 'appendRule', 'CSSKeyframesRule');
}
var parsedRule;
try {
// Parse the rule string as a keyframe rule
var tempStyleSheet = CSSOM.parse("@keyframes temp { " + rule + " }");
if (tempStyleSheet.cssRules.length > 0 && tempStyleSheet.cssRules[0].cssRules.length > 0) {
parsedRule = tempStyleSheet.cssRules[0].cssRules[0];
} else {
throw new Error("Failed to parse keyframe rule");
}
} catch (e) {
errorUtils.throwParseError(this, 'appendRule', 'CSSKeyframesRule', rule);
}
parsedRule.__parentRule = this;
this.cssRules.push(parsedRule);
};
/**
* Deletes a keyframe rule that matches the specified key.
*
* @param {string} select - The keyframe selector to delete (e.g., "50%", "from", "to")
* @see https://www.w3.org/TR/css-animations-1/#dom-csskeyframesrule-deleterule
*/
CSSOM.CSSKeyframesRule.prototype.deleteRule = function deleteRule(select) {
if (arguments.length === 0) {
errorUtils.throwMissingArguments(this, 'deleteRule', 'CSSKeyframesRule');
}
var normalizedSelect = this._normalizeKeyText(select);
for (var i = 0; i < this.cssRules.length; i++) {
var rule = this.cssRules[i];
if (this._normalizeKeyText(rule.keyText) === normalizedSelect) {
rule.__parentRule = null;
this.cssRules.splice(i, 1);
return;
}
}
};
/**
* Finds and returns the keyframe rule that matches the specified key.
* When multiple rules have the same key, returns the last one.
*
* @param {string} select - The keyframe selector to find (e.g., "50%", "from", "to")
* @return {CSSKeyframeRule|null} The matching keyframe rule, or null if not found
* @see https://www.w3.org/TR/css-animations-1/#dom-csskeyframesrule-findrule
*/
CSSOM.CSSKeyframesRule.prototype.findRule = function findRule(select) {
if (arguments.length === 0) {
errorUtils.throwMissingArguments(this, 'findRule', 'CSSKeyframesRule');
}
var normalizedSelect = this._normalizeKeyText(select);
// Iterate backwards to find the last matching rule
for (var i = this.cssRules.length - 1; i >= 0; i--) {
var rule = this.cssRules[i];
if (this._normalizeKeyText(rule.keyText) === normalizedSelect) {
return rule;
}
}
return null;
};
/**
* Normalizes keyframe selector text for comparison.
* Handles "from" -> "0%" and "to" -> "100%" conversions and trims whitespace.
*
* @private
* @param {string} keyText - The keyframe selector text to normalize
* @return {string} The normalized keyframe selector text
*/
CSSOM.CSSKeyframesRule.prototype._normalizeKeyText = function _normalizeKeyText(keyText) {
if (!keyText) return '';
var normalized = keyText.toString().trim().toLowerCase();
// Convert keywords to percentages for comparison
if (normalized === 'from') {
return '0%';
} else if (normalized === 'to') {
return '100%';
}
return normalized;
};
/**
* Makes CSSKeyframesRule iterable over its cssRules.
* Allows for...of loops and other iterable methods.
*/
if (typeof Symbol !== 'undefined' && Symbol.iterator) {
CSSOM.CSSKeyframesRule.prototype[Symbol.iterator] = function() {
var index = 0;
var cssRules = this.cssRules;
return {
next: function() {
if (index < cssRules.length) {
return { value: cssRules[index++], done: false };
} else {
return { done: true };
}
}
};
};
}
/**
* Adds indexed getters for direct access to cssRules by index.
* This enables rule[0], rule[1], etc. access patterns.
* Works in environments where Proxy is not available (like jsdom).
*/
CSSOM.CSSKeyframesRule.prototype._setupIndexedAccess = function() {
// Remove any existing indexed properties
for (var i = 0; i < 1000; i++) { // reasonable upper limit
if (this.hasOwnProperty(i)) {
delete this[i];
} else {
break;
}
}
// Add indexed getters for current cssRules
for (var i = 0; i < this.cssRules.length; i++) {
(function(index) {
Object.defineProperty(this, index, {
get: function() {
return this.cssRules[index];
},
enumerable: false,
configurable: true
});
}.call(this, i));
}
// Update length property
Object.defineProperty(this, 'length', {
get: function() {
return this.cssRules.length;
},
enumerable: false,
configurable: true
});
};
//.CommonJS
exports.CSSKeyframesRule = CSSOM.CSSKeyframesRule;
///CommonJS

View File

@@ -0,0 +1,49 @@
//.CommonJS
var CSSOM = {
CSSRule: require("./CSSRule").CSSRule,
CSSRuleList: require("./CSSRuleList").CSSRuleList,
CSSGroupingRule: require("./CSSGroupingRule").CSSGroupingRule,
};
///CommonJS
/**
* @constructor
* @see https://drafts.csswg.org/css-cascade-5/#csslayerblockrule
*/
CSSOM.CSSLayerBlockRule = function CSSLayerBlockRule() {
CSSOM.CSSGroupingRule.call(this);
this.name = "";
};
CSSOM.CSSLayerBlockRule.prototype = Object.create(CSSOM.CSSGroupingRule.prototype);
CSSOM.CSSLayerBlockRule.prototype.constructor = CSSOM.CSSLayerBlockRule;
Object.setPrototypeOf(CSSOM.CSSLayerBlockRule, CSSOM.CSSRule);
Object.defineProperty(CSSOM.CSSLayerBlockRule.prototype, "type", {
value: 18,
writable: false
});
Object.defineProperties(CSSOM.CSSLayerBlockRule.prototype, {
cssText: {
get: function () {
var values = "";
var valuesArr = [" {"];
if (this.cssRules.length) {
valuesArr.push(this.cssRules.reduce(function(acc, rule){
if (rule.cssText !== "") {
acc.push(rule.cssText);
}
return acc;
}, []).join("\n "));
}
values = valuesArr.join("\n ") + "\n}";
return "@layer" + (this.name ? " " + this.name : "") + values;
}
},
});
//.CommonJS
exports.CSSLayerBlockRule = CSSOM.CSSLayerBlockRule;
///CommonJS

View File

@@ -0,0 +1,36 @@
//.CommonJS
var CSSOM = {
CSSRule: require("./CSSRule").CSSRule,
};
///CommonJS
/**
* @constructor
* @see https://drafts.csswg.org/css-cascade-5/#csslayerstatementrule
*/
CSSOM.CSSLayerStatementRule = function CSSLayerStatementRule() {
CSSOM.CSSRule.call(this);
this.nameList = [];
};
CSSOM.CSSLayerStatementRule.prototype = Object.create(CSSOM.CSSRule.prototype);
CSSOM.CSSLayerStatementRule.prototype.constructor = CSSOM.CSSLayerStatementRule;
Object.setPrototypeOf(CSSOM.CSSLayerStatementRule, CSSOM.CSSRule);
Object.defineProperty(CSSOM.CSSLayerStatementRule.prototype, "type", {
value: 0,
writable: false
});
Object.defineProperties(CSSOM.CSSLayerStatementRule.prototype, {
cssText: {
get: function () {
return "@layer " + this.nameList.join(", ") + ";";
}
},
});
//.CommonJS
exports.CSSLayerStatementRule = CSSOM.CSSLayerStatementRule;
///CommonJS

74
server/node_modules/@acemir/cssom/lib/CSSMediaRule.js generated vendored Normal file
View File

@@ -0,0 +1,74 @@
//.CommonJS
var CSSOM = {
CSSRule: require("./CSSRule").CSSRule,
CSSRuleList: require("./CSSRuleList").CSSRuleList,
CSSGroupingRule: require("./CSSGroupingRule").CSSGroupingRule,
CSSConditionRule: require("./CSSConditionRule").CSSConditionRule,
MediaList: require("./MediaList").MediaList
};
///CommonJS
/**
* @constructor
* @see http://dev.w3.org/csswg/cssom/#cssmediarule
* @see http://www.w3.org/TR/DOM-Level-2-Style/css.html#CSS-CSSMediaRule
*/
CSSOM.CSSMediaRule = function CSSMediaRule() {
CSSOM.CSSConditionRule.call(this);
this.__media = new CSSOM.MediaList();
};
CSSOM.CSSMediaRule.prototype = Object.create(CSSOM.CSSConditionRule.prototype);
CSSOM.CSSMediaRule.prototype.constructor = CSSOM.CSSMediaRule;
Object.setPrototypeOf(CSSOM.CSSMediaRule, CSSOM.CSSConditionRule);
Object.defineProperty(CSSOM.CSSMediaRule.prototype, "type", {
value: 4,
writable: false
});
// https://opensource.apple.com/source/WebCore/WebCore-7611.1.21.161.3/css/CSSMediaRule.cpp
Object.defineProperties(CSSOM.CSSMediaRule.prototype, {
"media": {
get: function() {
return this.__media;
},
set: function(value) {
if (typeof value === "string") {
this.__media.mediaText = value;
} else {
this.__media = value;
}
},
configurable: true,
enumerable: true
},
"conditionText": {
get: function() {
return this.media.mediaText;
}
},
"cssText": {
get: function() {
var values = "";
var valuesArr = [" {"];
if (this.cssRules.length) {
valuesArr.push(this.cssRules.reduce(function(acc, rule){
if (rule.cssText !== "") {
acc.push(rule.cssText);
}
return acc;
}, []).join("\n "));
}
values = valuesArr.join("\n ") + "\n}";
return "@media " + this.media.mediaText + values;
}
}
});
//.CommonJS
exports.CSSMediaRule = CSSOM.CSSMediaRule;
///CommonJS

View File

@@ -0,0 +1,103 @@
//.CommonJS
var CSSOM = {
CSSRule: require("./CSSRule").CSSRule,
CSSStyleSheet: require("./CSSStyleSheet").CSSStyleSheet
};
///CommonJS
/**
* @constructor
* @see https://drafts.csswg.org/cssom/#the-cssnamespacerule-interface
*/
CSSOM.CSSNamespaceRule = function CSSNamespaceRule() {
CSSOM.CSSRule.call(this);
this.__prefix = "";
this.__namespaceURI = "";
};
CSSOM.CSSNamespaceRule.prototype = Object.create(CSSOM.CSSRule.prototype);
CSSOM.CSSNamespaceRule.prototype.constructor = CSSOM.CSSNamespaceRule;
Object.setPrototypeOf(CSSOM.CSSNamespaceRule, CSSOM.CSSRule);
Object.defineProperty(CSSOM.CSSNamespaceRule.prototype, "type", {
value: 10,
writable: false
});
Object.defineProperty(CSSOM.CSSNamespaceRule.prototype, "cssText", {
get: function() {
return "@namespace" + (this.prefix && " " + this.prefix) + " url(\"" + this.namespaceURI + "\");";
}
});
Object.defineProperty(CSSOM.CSSNamespaceRule.prototype, "prefix", {
get: function() {
return this.__prefix;
}
});
Object.defineProperty(CSSOM.CSSNamespaceRule.prototype, "namespaceURI", {
get: function() {
return this.__namespaceURI;
}
});
/**
* NON-STANDARD
* Rule text parser.
* @param {string} cssText
*/
Object.defineProperty(CSSOM.CSSNamespaceRule.prototype, "parse", {
value: function(cssText) {
var newPrefix = "";
var newNamespaceURI = "";
// Remove @namespace and trim
var text = cssText.trim();
if (text.indexOf('@namespace') === 0) {
text = text.slice('@namespace'.length).trim();
}
// Remove trailing semicolon if present
if (text.charAt(text.length - 1) === ';') {
text = text.slice(0, -1).trim();
}
// Regex to match valid namespace syntax:
// 1. [optional prefix] url("...") or [optional prefix] url('...') or [optional prefix] url() or [optional prefix] url(unquoted)
// 2. [optional prefix] "..." or [optional prefix] '...'
// The prefix must be a valid CSS identifier (letters, digits, hyphens, underscores, starting with letter or underscore)
var re = /^(?:([a-zA-Z_][a-zA-Z0-9_-]*)\s+)?(?:url\(\s*(?:(['"])(.*?)\2\s*|([^)]*?))\s*\)|(['"])(.*?)\5)$/;
var match = text.match(re);
if (match) {
// If prefix is present
if (match[1]) {
newPrefix = match[1];
}
// If url(...) form with quotes
if (typeof match[3] !== "undefined") {
newNamespaceURI = match[3];
}
// If url(...) form without quotes
else if (typeof match[4] !== "undefined") {
newNamespaceURI = match[4].trim();
}
// If quoted string form
else if (typeof match[6] !== "undefined") {
newNamespaceURI = match[6];
}
this.__prefix = newPrefix;
this.__namespaceURI = newNamespaceURI;
} else {
throw new DOMException("Invalid @namespace rule", "InvalidStateError");
}
}
});
//.CommonJS
exports.CSSNamespaceRule = CSSOM.CSSNamespaceRule;
///CommonJS

View File

@@ -0,0 +1,56 @@
//.CommonJS
var CSSOM = {
CSSRule: require("./CSSRule").CSSRule,
CSSStyleDeclaration: require('./CSSStyleDeclaration').CSSStyleDeclaration
};
// Use cssstyle if available
try {
CSSOM.CSSStyleDeclaration = require("cssstyle").CSSStyleDeclaration;
} catch (e) {
// ignore
}
///CommonJS
/**
* @constructor
* @see https://drafts.csswg.org/css-nesting-1/
*/
CSSOM.CSSNestedDeclarations = function CSSNestedDeclarations() {
CSSOM.CSSRule.call(this);
this.__style = new CSSOM.CSSStyleDeclaration();
this.__style.parentRule = this;
};
CSSOM.CSSNestedDeclarations.prototype = Object.create(CSSOM.CSSRule.prototype);
CSSOM.CSSNestedDeclarations.prototype.constructor = CSSOM.CSSNestedDeclarations;
Object.setPrototypeOf(CSSOM.CSSNestedDeclarations, CSSOM.CSSRule);
Object.defineProperty(CSSOM.CSSNestedDeclarations.prototype, "type", {
value: 0,
writable: false
});
Object.defineProperty(CSSOM.CSSNestedDeclarations.prototype, "style", {
get: function() {
return this.__style;
},
set: function(value) {
if (typeof value === "string") {
this.__style.cssText = value;
} else {
this.__style = value;
}
}
});
Object.defineProperty(CSSOM.CSSNestedDeclarations.prototype, "cssText", {
get: function () {
return this.style.cssText;
}
});
//.CommonJS
exports.CSSNestedDeclarations = CSSOM.CSSNestedDeclarations;
///CommonJS

58
server/node_modules/@acemir/cssom/lib/CSSOM.js generated vendored Normal file
View File

@@ -0,0 +1,58 @@
var CSSOM = {
/**
* Creates and configures a new CSSOM instance with the specified options.
*
* @param {Object} opts - Configuration options for the CSSOM instance
* @param {Object} [opts.globalObject] - Optional global object to be assigned to CSSOM objects prototype
* @returns {Object} A new CSSOM instance with the applied configuration
* @description
* This method creates a new instance of CSSOM and optionally
* configures CSSStyleSheet with a global object reference. When a globalObject is provided
* and CSSStyleSheet exists on the instance, it creates a new CSSStyleSheet constructor
* using a factory function and assigns the globalObject to its prototype's __globalObject property.
*/
setup: function (opts) {
var instance = Object.create(this);
if (opts.globalObject) {
if (instance.CSSStyleSheet) {
var factoryCSSStyleSheet = createFunctionFactory(instance.CSSStyleSheet);
var CSSStyleSheet = factoryCSSStyleSheet();
CSSStyleSheet.prototype.__globalObject = opts.globalObject;
instance.CSSStyleSheet = CSSStyleSheet;
}
}
return instance;
}
};
function createFunctionFactory(fn) {
return function() {
// Create a new function that delegates to the original
var newFn = function() {
return fn.apply(this, arguments);
};
// Copy prototype chain
Object.setPrototypeOf(newFn, Object.getPrototypeOf(fn));
// Copy own properties
for (var key in fn) {
if (Object.prototype.hasOwnProperty.call(fn, key)) {
newFn[key] = fn[key];
}
}
// Clone the .prototype object for constructor-like behavior
if (fn.prototype) {
newFn.prototype = Object.create(fn.prototype);
}
return newFn;
};
}
//.CommonJS
module.exports = CSSOM;
///CommonJS

125
server/node_modules/@acemir/cssom/lib/CSSPageRule.js generated vendored Normal file
View File

@@ -0,0 +1,125 @@
//.CommonJS
var CSSOM = {
CSSStyleDeclaration: require("./CSSStyleDeclaration").CSSStyleDeclaration,
CSSRule: require("./CSSRule").CSSRule,
CSSRuleList: require("./CSSRuleList").CSSRuleList,
CSSGroupingRule: require("./CSSGroupingRule").CSSGroupingRule,
};
var regexPatterns = require("./regexPatterns").regexPatterns;
// Use cssstyle if available
try {
CSSOM.CSSStyleDeclaration = require("cssstyle").CSSStyleDeclaration;
} catch (e) {
// ignore
}
///CommonJS
/**
* @constructor
* @see https://drafts.csswg.org/cssom/#the-csspagerule-interface
*/
CSSOM.CSSPageRule = function CSSPageRule() {
CSSOM.CSSGroupingRule.call(this);
this.__style = new CSSOM.CSSStyleDeclaration();
this.__style.parentRule = this;
};
CSSOM.CSSPageRule.prototype = Object.create(CSSOM.CSSGroupingRule.prototype);
CSSOM.CSSPageRule.prototype.constructor = CSSOM.CSSPageRule;
Object.setPrototypeOf(CSSOM.CSSPageRule, CSSOM.CSSGroupingRule);
Object.defineProperty(CSSOM.CSSPageRule.prototype, "type", {
value: 6,
writable: false
});
Object.defineProperty(CSSOM.CSSPageRule.prototype, "selectorText", {
get: function() {
return this.__selectorText;
},
set: function(value) {
if (typeof value === "string") {
var trimmedValue = value.trim();
// Empty selector is valid for @page
if (trimmedValue === '') {
this.__selectorText = '';
return;
}
var atPageRuleSelectorRegExp = regexPatterns.atPageRuleSelectorRegExp;
var cssCustomIdentifierRegExp = regexPatterns.cssCustomIdentifierRegExp;
var match = trimmedValue.match(atPageRuleSelectorRegExp);
if (match) {
var pageName = match[1] || '';
var pseudoPages = match[2] || '';
// Validate page name if present
if (pageName) {
// Page name can be an identifier or a string
if (!cssCustomIdentifierRegExp.test(pageName)) {
return;
}
}
// Validate pseudo-pages if present
if (pseudoPages) {
var pseudos = pseudoPages.split(':').filter(function(p) { return p; });
var validPseudos = ['left', 'right', 'first', 'blank'];
var allValid = true;
for (var j = 0; j < pseudos.length; j++) {
if (validPseudos.indexOf(pseudos[j].toLowerCase()) === -1) {
allValid = false;
break;
}
}
if (!allValid) {
return; // Invalid pseudo-page, do nothing
}
}
this.__selectorText = pageName + pseudoPages.toLowerCase();
}
}
}
});
Object.defineProperty(CSSOM.CSSPageRule.prototype, "style", {
get: function() {
return this.__style;
},
set: function(value) {
if (typeof value === "string") {
this.__style.cssText = value;
} else {
this.__style = value;
}
}
});
Object.defineProperty(CSSOM.CSSPageRule.prototype, "cssText", {
get: function() {
var values = "";
if (this.cssRules.length) {
var valuesArr = [" {"];
this.style.cssText && valuesArr.push(this.style.cssText);
valuesArr.push(this.cssRules.reduce(function(acc, rule){
if (rule.cssText !== "") {
acc.push(rule.cssText);
}
return acc;
}, []).join("\n "));
values = valuesArr.join("\n ") + "\n}";
} else {
values = " {" + (this.style.cssText ? " " + this.style.cssText : "") + " }";
}
return "@page" + (this.selectorText ? " " + this.selectorText : "") + values;
}
});
//.CommonJS
exports.CSSPageRule = CSSOM.CSSPageRule;
///CommonJS

View File

@@ -0,0 +1,122 @@
//.CommonJS
var CSSOM = {
CSSRule: require("./CSSRule").CSSRule
};
///CommonJS
/**
* @constructor
* @see https://drafts.css-houdini.org/css-properties-values-api/#the-css-property-rule-interface
*/
CSSOM.CSSPropertyRule = function CSSPropertyRule() {
CSSOM.CSSRule.call(this);
this.__name = "";
this.__syntax = "";
this.__inherits = false;
this.__initialValue = null;
};
CSSOM.CSSPropertyRule.prototype = Object.create(CSSOM.CSSRule.prototype);
CSSOM.CSSPropertyRule.prototype.constructor = CSSOM.CSSPropertyRule;
Object.setPrototypeOf(CSSOM.CSSPropertyRule, CSSOM.CSSRule);
Object.defineProperty(CSSOM.CSSPropertyRule.prototype, "type", {
value: 0,
writable: false
});
Object.defineProperty(CSSOM.CSSPropertyRule.prototype, "cssText", {
get: function() {
var text = "@property " + this.name + " {";
if (this.syntax !== "") {
text += " syntax: \"" + this.syntax.replace(/\\/g, '\\\\').replace(/"/g, '\\"') + "\";";
}
text += " inherits: " + (this.inherits ? "true" : "false") + ";";
if (this.initialValue !== null) {
text += " initial-value: " + this.initialValue + ";";
}
text += " }";
return text;
}
});
Object.defineProperty(CSSOM.CSSPropertyRule.prototype, "name", {
get: function() {
return this.__name;
}
});
Object.defineProperty(CSSOM.CSSPropertyRule.prototype, "syntax", {
get: function() {
return this.__syntax;
}
});
Object.defineProperty(CSSOM.CSSPropertyRule.prototype, "inherits", {
get: function() {
return this.__inherits;
}
});
Object.defineProperty(CSSOM.CSSPropertyRule.prototype, "initialValue", {
get: function() {
return this.__initialValue;
}
});
/**
* NON-STANDARD
* Rule text parser.
* @param {string} cssText
* @returns {boolean} True if the rule is valid and was parsed successfully
*/
Object.defineProperty(CSSOM.CSSPropertyRule.prototype, "parse", {
value: function(cssText) {
// Extract the name from "@property <name> { ... }"
var match = cssText.match(/@property\s+(--[^\s{]+)\s*\{([^]*)\}/);
if (!match) {
return false;
}
this.__name = match[1];
var bodyText = match[2];
// Parse syntax descriptor (REQUIRED)
var syntaxMatch = bodyText.match(/syntax\s*:\s*(['"])([^]*?)\1\s*;/);
if (!syntaxMatch) {
return false; // syntax is required
}
this.__syntax = syntaxMatch[2];
// Syntax cannot be empty
if (this.__syntax === "") {
return false;
}
// Parse inherits descriptor (REQUIRED)
var inheritsMatch = bodyText.match(/inherits\s*:\s*(true|false)\s*;/);
if (!inheritsMatch) {
return false; // inherits is required
}
this.__inherits = inheritsMatch[1] === "true";
// Parse initial-value descriptor (OPTIONAL, but required if syntax is not "*")
var initialValueMatch = bodyText.match(/initial-value\s*:\s*([^;]+);/);
if (initialValueMatch) {
this.__initialValue = initialValueMatch[1].trim();
} else {
// If syntax is not "*", initial-value is required
if (this.__syntax !== "*") {
return false;
}
}
return true; // Successfully parsed
}
});
//.CommonJS
exports.CSSPropertyRule = CSSOM.CSSPropertyRule;
///CommonJS

92
server/node_modules/@acemir/cssom/lib/CSSRule.js generated vendored Normal file
View File

@@ -0,0 +1,92 @@
//.CommonJS
var CSSOM = {};
///CommonJS
/**
* @constructor
* @see http://dev.w3.org/csswg/cssom/#the-cssrule-interface
* @see http://www.w3.org/TR/DOM-Level-2-Style/css.html#CSS-CSSRule
*/
CSSOM.CSSRule = function CSSRule() {
this.__parentRule = null;
this.__parentStyleSheet = null;
};
CSSOM.CSSRule.UNKNOWN_RULE = 0; // obsolete
CSSOM.CSSRule.STYLE_RULE = 1;
CSSOM.CSSRule.CHARSET_RULE = 2; // obsolete
CSSOM.CSSRule.IMPORT_RULE = 3;
CSSOM.CSSRule.MEDIA_RULE = 4;
CSSOM.CSSRule.FONT_FACE_RULE = 5;
CSSOM.CSSRule.PAGE_RULE = 6;
CSSOM.CSSRule.KEYFRAMES_RULE = 7;
CSSOM.CSSRule.KEYFRAME_RULE = 8;
CSSOM.CSSRule.MARGIN_RULE = 9;
CSSOM.CSSRule.NAMESPACE_RULE = 10;
CSSOM.CSSRule.COUNTER_STYLE_RULE = 11;
CSSOM.CSSRule.SUPPORTS_RULE = 12;
CSSOM.CSSRule.DOCUMENT_RULE = 13;
CSSOM.CSSRule.FONT_FEATURE_VALUES_RULE = 14;
CSSOM.CSSRule.VIEWPORT_RULE = 15;
CSSOM.CSSRule.REGION_STYLE_RULE = 16;
CSSOM.CSSRule.CONTAINER_RULE = 17;
CSSOM.CSSRule.LAYER_BLOCK_RULE = 18;
CSSOM.CSSRule.STARTING_STYLE_RULE = 1002;
Object.defineProperties(CSSOM.CSSRule.prototype, {
constructor: { value: CSSOM.CSSRule },
cssRule: {
value: "",
configurable: true,
enumerable: true
},
cssText: {
get: function() {
// Default getter: subclasses should override this
return "";
},
set: function(cssText) {
return cssText;
}
},
parentRule: {
get: function() {
return this.__parentRule
}
},
parentStyleSheet: {
get: function() {
return this.__parentStyleSheet
}
},
UNKNOWN_RULE: { value: 0, enumerable: true }, // obsolet
STYLE_RULE: { value: 1, enumerable: true },
CHARSET_RULE: { value: 2, enumerable: true }, // obsolet
IMPORT_RULE: { value: 3, enumerable: true },
MEDIA_RULE: { value: 4, enumerable: true },
FONT_FACE_RULE: { value: 5, enumerable: true },
PAGE_RULE: { value: 6, enumerable: true },
KEYFRAMES_RULE: { value: 7, enumerable: true },
KEYFRAME_RULE: { value: 8, enumerable: true },
MARGIN_RULE: { value: 9, enumerable: true },
NAMESPACE_RULE: { value: 10, enumerable: true },
COUNTER_STYLE_RULE: { value: 11, enumerable: true },
SUPPORTS_RULE: { value: 12, enumerable: true },
DOCUMENT_RULE: { value: 13, enumerable: true },
FONT_FEATURE_VALUES_RULE: { value: 14, enumerable: true },
VIEWPORT_RULE: { value: 15, enumerable: true },
REGION_STYLE_RULE: { value: 16, enumerable: true },
CONTAINER_RULE: { value: 17, enumerable: true },
LAYER_BLOCK_RULE: { value: 18, enumerable: true },
STARTING_STYLE_RULE: { value: 1002, enumerable: true },
});
//.CommonJS
exports.CSSRule = CSSOM.CSSRule;
///CommonJS

26
server/node_modules/@acemir/cssom/lib/CSSRuleList.js generated vendored Normal file
View File

@@ -0,0 +1,26 @@
//.CommonJS
var CSSOM = {};
///CommonJS
/**
* @constructor
* @see https://drafts.csswg.org/cssom/#the-cssrulelist-interface
*/
CSSOM.CSSRuleList = function CSSRuleList(){
var arr = new Array();
Object.setPrototypeOf(arr, CSSOM.CSSRuleList.prototype);
return arr;
};
CSSOM.CSSRuleList.prototype = Object.create(Array.prototype);
CSSOM.CSSRuleList.prototype.constructor = CSSOM.CSSRuleList;
CSSOM.CSSRuleList.prototype.item = function(index) {
return this[index] || null;
};
//.CommonJS
exports.CSSRuleList = CSSOM.CSSRuleList;
///CommonJS

61
server/node_modules/@acemir/cssom/lib/CSSScopeRule.js generated vendored Normal file
View File

@@ -0,0 +1,61 @@
//.CommonJS
var CSSOM = {
CSSRule: require("./CSSRule").CSSRule,
CSSRuleList: require("./CSSRuleList").CSSRuleList,
CSSGroupingRule: require("./CSSGroupingRule").CSSGroupingRule,
};
///CommonJS
/**
* @constructor
* @see https://drafts.csswg.org/css-cascade-6/#cssscoperule
*/
CSSOM.CSSScopeRule = function CSSScopeRule() {
CSSOM.CSSGroupingRule.call(this);
this.__start = null;
this.__end = null;
};
CSSOM.CSSScopeRule.prototype = Object.create(CSSOM.CSSGroupingRule.prototype);
CSSOM.CSSScopeRule.prototype.constructor = CSSOM.CSSScopeRule;
Object.setPrototypeOf(CSSOM.CSSScopeRule, CSSOM.CSSGroupingRule);
Object.defineProperties(CSSOM.CSSScopeRule.prototype, {
type: {
value: 0,
writable: false,
},
cssText: {
get: function () {
var values = "";
var valuesArr = [" {"];
if (this.cssRules.length) {
valuesArr.push(this.cssRules.reduce(function(acc, rule){
if (rule.cssText !== "") {
acc.push(rule.cssText);
}
return acc;
}, []).join("\n "));
}
values = valuesArr.join("\n ") + "\n}";
return "@scope" + (this.start ? " (" + this.start + ")" : "") + (this.end ? " to (" + this.end + ")" : "") + values;
},
configurable: true,
enumerable: true,
},
start: {
get: function () {
return this.__start;
}
},
end: {
get: function () {
return this.__end;
}
}
});
//.CommonJS
exports.CSSScopeRule = CSSOM.CSSScopeRule;
///CommonJS

View File

@@ -0,0 +1,52 @@
//.CommonJS
var CSSOM = {
CSSRule: require("./CSSRule").CSSRule,
CSSRuleList: require("./CSSRuleList").CSSRuleList,
CSSGroupingRule: require("./CSSGroupingRule").CSSGroupingRule
};
///CommonJS
/**
* @constructor
* @see http://www.w3.org/TR/shadow-dom/#host-at-rule
*/
CSSOM.CSSStartingStyleRule = function CSSStartingStyleRule() {
CSSOM.CSSGroupingRule.call(this);
};
CSSOM.CSSStartingStyleRule.prototype = Object.create(CSSOM.CSSGroupingRule.prototype);
CSSOM.CSSStartingStyleRule.prototype.constructor = CSSOM.CSSStartingStyleRule;
Object.setPrototypeOf(CSSOM.CSSStartingStyleRule, CSSOM.CSSGroupingRule);
Object.defineProperty(CSSOM.CSSStartingStyleRule.prototype, "type", {
value: 1002,
writable: false
});
//FIXME
//CSSOM.CSSStartingStyleRule.prototype.insertRule = CSSStyleSheet.prototype.insertRule;
//CSSOM.CSSStartingStyleRule.prototype.deleteRule = CSSStyleSheet.prototype.deleteRule;
Object.defineProperty(CSSOM.CSSStartingStyleRule.prototype, "cssText", {
get: function() {
var values = "";
var valuesArr = [" {"];
if (this.cssRules.length) {
valuesArr.push(this.cssRules.reduce(function(acc, rule){
if (rule.cssText !== "") {
acc.push(rule.cssText);
}
return acc;
}, []).join("\n "));
}
values = valuesArr.join("\n ") + "\n}";
return "@starting-style" + values;
}
});
//.CommonJS
exports.CSSStartingStyleRule = CSSOM.CSSStartingStyleRule;
///CommonJS

View File

@@ -0,0 +1,164 @@
//.CommonJS
var CSSOM = {};
var regexPatterns = require("./regexPatterns").regexPatterns;
///CommonJS
/**
* @constructor
* @see http://www.w3.org/TR/DOM-Level-2-Style/css.html#CSS-CSSStyleDeclaration
*/
CSSOM.CSSStyleDeclaration = function CSSStyleDeclaration(){
this.length = 0;
this.parentRule = null;
// NON-STANDARD
this._importants = {};
};
CSSOM.CSSStyleDeclaration.prototype = {
constructor: CSSOM.CSSStyleDeclaration,
/**
*
* @param {string} name
* @see http://www.w3.org/TR/DOM-Level-2-Style/css.html#CSS-CSSStyleDeclaration-getPropertyValue
* @return {string} the value of the property if it has been explicitly set for this declaration block.
* Returns the empty string if the property has not been set.
*/
getPropertyValue: function(name) {
return this[name] || "";
},
/**
*
* @param {string} name
* @param {string} value
* @param {string} [priority=null] "important" or null
* @see http://www.w3.org/TR/DOM-Level-2-Style/css.html#CSS-CSSStyleDeclaration-setProperty
*/
setProperty: function(name, value, priority, parseErrorHandler)
{
// NOTE: Check viability to add a validation for css values or use a dependency like csstree-validator
var basicStylePropertyValueValidationRegExp = regexPatterns.basicStylePropertyValueValidationRegExp
if (basicStylePropertyValueValidationRegExp.test(value)) {
parseErrorHandler && parseErrorHandler('Invalid CSSStyleDeclaration property (name = "' + name + '", value = "' + value + '")');
} else if (this[name]) {
// Property already exist. Overwrite it.
var index = Array.prototype.indexOf.call(this, name);
if (index < 0) {
this[this.length] = name;
this.length++;
}
// If the priority value of the incoming property is "important",
// or the value of the existing property is not "important",
// then remove the existing property and rewrite it.
if (priority || !this._importants[name]) {
this.removeProperty(name);
this[this.length] = name;
this.length++;
this[name] = value + '';
this._importants[name] = priority;
}
} else {
// New property.
this[this.length] = name;
this.length++;
this[name] = value + '';
this._importants[name] = priority;
}
},
/**
*
* @param {string} name
* @see http://www.w3.org/TR/DOM-Level-2-Style/css.html#CSS-CSSStyleDeclaration-removeProperty
* @return {string} the value of the property if it has been explicitly set for this declaration block.
* Returns the empty string if the property has not been set or the property name does not correspond to a known CSS property.
*/
removeProperty: function(name) {
if (!(name in this)) {
return "";
}
var index = Array.prototype.indexOf.call(this, name);
if (index < 0) {
return "";
}
var prevValue = this[name];
this[name] = "";
// That's what WebKit and Opera do
Array.prototype.splice.call(this, index, 1);
// That's what Firefox does
//this[index] = ""
return prevValue;
},
getPropertyCSSValue: function() {
//FIXME
},
/**
*
* @param {String} name
*/
getPropertyPriority: function(name) {
return this._importants[name] || "";
},
/**
* element.style.overflow = "auto"
* element.style.getPropertyShorthand("overflow-x")
* -> "overflow"
*/
getPropertyShorthand: function() {
//FIXME
},
isPropertyImplicit: function() {
//FIXME
},
// Doesn't work in IE < 9
get cssText(){
var properties = [];
for (var i=0, length=this.length; i < length; ++i) {
var name = this[i];
var value = this.getPropertyValue(name);
var priority = this.getPropertyPriority(name);
if (priority) {
priority = " !" + priority;
}
properties[i] = name + ": " + value + priority + ";";
}
return properties.join(" ");
},
set cssText(text){
var i, name;
for (i = this.length; i--;) {
name = this[i];
this[name] = "";
}
Array.prototype.splice.call(this, 0, this.length);
this._importants = {};
var dummyRule = CSSOM.parse('#bogus{' + text + '}').cssRules[0].style;
var length = dummyRule.length;
for (i = 0; i < length; ++i) {
name = dummyRule[i];
this.setProperty(dummyRule[i], dummyRule.getPropertyValue(name), dummyRule.getPropertyPriority(name));
}
}
};
//.CommonJS
exports.CSSStyleDeclaration = CSSOM.CSSStyleDeclaration;
CSSOM.parse = require('./parse').parse; // Cannot be included sooner due to the mutual dependency between parse.js and CSSStyleDeclaration.js
///CommonJS

109
server/node_modules/@acemir/cssom/lib/CSSStyleRule.js generated vendored Normal file
View File

@@ -0,0 +1,109 @@
//.CommonJS
var CSSOM = {
CSSStyleDeclaration: require("./CSSStyleDeclaration").CSSStyleDeclaration,
CSSRule: require("./CSSRule").CSSRule,
CSSRuleList: require("./CSSRuleList").CSSRuleList,
CSSGroupingRule: require("./CSSGroupingRule").CSSGroupingRule,
};
var regexPatterns = require("./regexPatterns").regexPatterns;
// Use cssstyle if available
try {
CSSOM.CSSStyleDeclaration = require("cssstyle").CSSStyleDeclaration;
} catch (e) {
// ignore
}
///CommonJS
/**
* @constructor
* @see http://dev.w3.org/csswg/cssom/#cssstylerule
* @see http://www.w3.org/TR/DOM-Level-2-Style/css.html#CSS-CSSStyleRule
*/
CSSOM.CSSStyleRule = function CSSStyleRule() {
CSSOM.CSSGroupingRule.call(this);
this.__selectorText = "";
this.__style = new CSSOM.CSSStyleDeclaration();
this.__style.parentRule = this;
};
CSSOM.CSSStyleRule.prototype = Object.create(CSSOM.CSSGroupingRule.prototype);
CSSOM.CSSStyleRule.prototype.constructor = CSSOM.CSSStyleRule;
Object.setPrototypeOf(CSSOM.CSSStyleRule, CSSOM.CSSGroupingRule);
Object.defineProperty(CSSOM.CSSStyleRule.prototype, "type", {
value: 1,
writable: false
});
Object.defineProperty(CSSOM.CSSStyleRule.prototype, "selectorText", {
get: function() {
return this.__selectorText;
},
set: function(value) {
if (typeof value === "string") {
// Don't trim if the value ends with a hex escape sequence followed by space
// (e.g., ".\31 " where the space is part of the escape terminator)
var endsWithHexEscapeRegExp = regexPatterns.endsWithHexEscapeRegExp;
var endsWithEscape = endsWithHexEscapeRegExp.test(value);
var trimmedValue = endsWithEscape ? value.replace(/\s+$/, ' ').trimStart() : value.trim();
if (trimmedValue === '') {
return;
}
// TODO: Setting invalid selectorText should be ignored
// There are some validations already on lib/parse.js
// but the same validations should be applied here.
// Check if we can move these validation logic to a shared function.
this.__selectorText = trimmedValue;
}
},
configurable: true
});
Object.defineProperty(CSSOM.CSSStyleRule.prototype, "style", {
get: function() {
return this.__style;
},
set: function(value) {
if (typeof value === "string") {
this.__style.cssText = value;
} else {
this.__style = value;
}
},
configurable: true
});
Object.defineProperty(CSSOM.CSSStyleRule.prototype, "cssText", {
get: function() {
var text;
if (this.selectorText) {
var values = "";
if (this.cssRules.length) {
var valuesArr = [" {"];
this.style.cssText && valuesArr.push(this.style.cssText);
valuesArr.push(this.cssRules.reduce(function(acc, rule){
if (rule.cssText !== "") {
acc.push(rule.cssText);
}
return acc;
}, []).join("\n "));
values = valuesArr.join("\n ") + "\n}";
} else {
values = " {" + (this.style.cssText ? " " + this.style.cssText : "") + " }";
}
text = this.selectorText + values;
} else {
text = "";
}
return text;
}
});
//.CommonJS
exports.CSSStyleRule = CSSOM.CSSStyleRule;
///CommonJS

371
server/node_modules/@acemir/cssom/lib/CSSStyleSheet.js generated vendored Normal file
View File

@@ -0,0 +1,371 @@
//.CommonJS
var CSSOM = {
MediaList: require("./MediaList").MediaList,
StyleSheet: require("./StyleSheet").StyleSheet,
CSSRuleList: require("./CSSRuleList").CSSRuleList,
CSSStyleRule: require("./CSSStyleRule").CSSStyleRule,
};
var errorUtils = require("./errorUtils").errorUtils;
///CommonJS
/**
* @constructor
* @param {CSSStyleSheetInit} [opts] - CSSStyleSheetInit options.
* @param {string} [opts.baseURL] - The base URL of the stylesheet.
* @param {boolean} [opts.disabled] - The disabled attribute of the stylesheet.
* @param {MediaList | string} [opts.media] - The media attribute of the stylesheet.
* @see http://www.w3.org/TR/DOM-Level-2-Style/css.html#CSS-CSSStyleSheet
*/
CSSOM.CSSStyleSheet = function CSSStyleSheet(opts) {
CSSOM.StyleSheet.call(this);
this.__constructed = true;
this.__cssRules = new CSSOM.CSSRuleList();
this.__ownerRule = null;
if (opts && typeof opts === "object") {
if (opts.baseURL && typeof opts.baseURL === "string") {
this.__baseURL = opts.baseURL;
}
if (opts.media && typeof opts.media === "string") {
this.media.mediaText = opts.media;
}
if (typeof opts.disabled === "boolean") {
this.disabled = opts.disabled;
}
}
};
CSSOM.CSSStyleSheet.prototype = Object.create(CSSOM.StyleSheet.prototype);
CSSOM.CSSStyleSheet.prototype.constructor = CSSOM.CSSStyleSheet;
Object.setPrototypeOf(CSSOM.CSSStyleSheet, CSSOM.StyleSheet);
Object.defineProperty(CSSOM.CSSStyleSheet.prototype, "cssRules", {
get: function() {
return this.__cssRules;
}
});
Object.defineProperty(CSSOM.CSSStyleSheet.prototype, "rules", {
get: function() {
return this.__cssRules;
}
});
Object.defineProperty(CSSOM.CSSStyleSheet.prototype, "ownerRule", {
get: function() {
return this.__ownerRule;
}
});
/**
* Used to insert a new rule into the style sheet. The new rule now becomes part of the cascade.
*
* sheet = new Sheet("body {margin: 0}")
* sheet.toString()
* -> "body{margin:0;}"
* sheet.insertRule("img {border: none}", 0)
* -> 0
* sheet.toString()
* -> "img{border:none;}body{margin:0;}"
*
* @param {string} rule
* @param {number} [index=0]
* @see http://www.w3.org/TR/DOM-Level-2-Style/css.html#CSS-CSSStyleSheet-insertRule
* @return {number} The index within the style sheet's rule collection of the newly inserted rule.
*/
CSSOM.CSSStyleSheet.prototype.insertRule = function(rule, index) {
if (rule === undefined && index === undefined) {
errorUtils.throwMissingArguments(this, 'insertRule', this.constructor.name);
}
if (index === void 0) {
index = 0;
}
index = Number(index);
if (index < 0) {
index = 4294967296 + index;
}
if (index > this.cssRules.length) {
errorUtils.throwIndexError(this, 'insertRule', this.constructor.name, index, this.cssRules.length);
}
var ruleToParse = String(rule);
var parseErrors = [];
var parsedSheet = CSSOM.parse(ruleToParse, undefined, function(err) {
parseErrors.push(err);
} );
if (parsedSheet.cssRules.length !== 1) {
errorUtils.throwParseError(this, 'insertRule', this.constructor.name, ruleToParse, 'SyntaxError');
}
var cssRule = parsedSheet.cssRules[0];
// Helper function to find the last index of a specific rule constructor
function findLastIndexOfConstructor(rules, constructorName) {
for (var i = rules.length - 1; i >= 0; i--) {
if (rules[i].constructor.name === constructorName) {
return i;
}
}
return -1;
}
// Helper function to find the first index of a rule that's NOT of specified constructors
function findFirstNonConstructorIndex(rules, constructorNames) {
for (var i = 0; i < rules.length; i++) {
if (constructorNames.indexOf(rules[i].constructor.name) === -1) {
return i;
}
}
return rules.length;
}
// Validate rule ordering based on CSS specification
if (cssRule.constructor.name === 'CSSImportRule') {
if (this.__constructed === true) {
errorUtils.throwError(this, 'DOMException',
"Failed to execute 'insertRule' on '" + this.constructor.name + "': Can't insert @import rules into a constructed stylesheet.",
'SyntaxError');
}
// @import rules cannot be inserted after @layer rules that already exist
// They can only be inserted at the beginning or after other @import rules
var firstLayerIndex = findFirstNonConstructorIndex(this.cssRules, ['CSSImportRule']);
if (firstLayerIndex < this.cssRules.length && this.cssRules[firstLayerIndex].constructor.name === 'CSSLayerStatementRule' && index > firstLayerIndex) {
errorUtils.throwError(this, 'DOMException',
"Failed to execute 'insertRule' on '" + this.constructor.name + "': Failed to insert the rule.",
'HierarchyRequestError');
}
// Also cannot insert after @namespace or other rules
var firstNonImportIndex = findFirstNonConstructorIndex(this.cssRules, ['CSSImportRule']);
if (index > firstNonImportIndex && firstNonImportIndex < this.cssRules.length &&
this.cssRules[firstNonImportIndex].constructor.name !== 'CSSLayerStatementRule') {
errorUtils.throwError(this, 'DOMException',
"Failed to execute 'insertRule' on '" + this.constructor.name + "': Failed to insert the rule.",
'HierarchyRequestError');
}
} else if (cssRule.constructor.name === 'CSSNamespaceRule') {
// @namespace rules can come after @layer and @import, but before any other rules
// They cannot come before @import rules
var firstImportIndex = -1;
for (var i = 0; i < this.cssRules.length; i++) {
if (this.cssRules[i].constructor.name === 'CSSImportRule') {
firstImportIndex = i;
break;
}
}
var firstNonImportNamespaceIndex = findFirstNonConstructorIndex(this.cssRules, [
'CSSLayerStatementRule',
'CSSImportRule',
'CSSNamespaceRule'
]);
// Cannot insert before @import rules
if (firstImportIndex !== -1 && index <= firstImportIndex) {
errorUtils.throwError(this, 'DOMException',
"Failed to execute 'insertRule' on '" + this.constructor.name + "': Failed to insert the rule.",
'HierarchyRequestError');
}
// Cannot insert if there are already non-special rules
if (firstNonImportNamespaceIndex < this.cssRules.length) {
errorUtils.throwError(this, 'DOMException',
"Failed to execute 'insertRule' on '" + this.constructor.name + "': Failed to insert the rule.",
'InvalidStateError');
}
// Cannot insert after other types of rules
if (index > firstNonImportNamespaceIndex) {
errorUtils.throwError(this, 'DOMException',
"Failed to execute 'insertRule' on '" + this.constructor.name + "': Failed to insert the rule.",
'HierarchyRequestError');
}
} else if (cssRule.constructor.name === 'CSSLayerStatementRule') {
// @layer statement rules can be inserted anywhere before @import and @namespace
// No additional restrictions beyond what's already handled
} else {
// Any other rule cannot be inserted before @import and @namespace
var firstNonSpecialRuleIndex = findFirstNonConstructorIndex(this.cssRules, [
'CSSLayerStatementRule',
'CSSImportRule',
'CSSNamespaceRule'
]);
if (index < firstNonSpecialRuleIndex) {
errorUtils.throwError(this, 'DOMException',
"Failed to execute 'insertRule' on '" + this.constructor.name + "': Failed to insert the rule.",
'HierarchyRequestError');
}
if (parseErrors.filter(function(error) { return !error.isNested; }).length !== 0) {
errorUtils.throwParseError(this, 'insertRule', this.constructor.name, ruleToParse, 'SyntaxError');
}
}
cssRule.__parentStyleSheet = this;
this.cssRules.splice(index, 0, cssRule);
return index;
};
CSSOM.CSSStyleSheet.prototype.addRule = function(selector, styleBlock, index) {
if (index === void 0) {
index = this.cssRules.length;
}
this.insertRule(selector + "{" + styleBlock + "}", index);
return -1;
};
/**
* Used to delete a rule from the style sheet.
*
* sheet = new Sheet("img{border:none} body{margin:0}")
* sheet.toString()
* -> "img{border:none;}body{margin:0;}"
* sheet.deleteRule(0)
* sheet.toString()
* -> "body{margin:0;}"
*
* @param {number} index within the style sheet's rule list of the rule to remove.
* @see http://www.w3.org/TR/DOM-Level-2-Style/css.html#CSS-CSSStyleSheet-deleteRule
*/
CSSOM.CSSStyleSheet.prototype.deleteRule = function(index) {
if (index === undefined) {
errorUtils.throwMissingArguments(this, 'deleteRule', this.constructor.name);
}
index = Number(index);
if (index < 0) {
index = 4294967296 + index;
}
if (index >= this.cssRules.length) {
errorUtils.throwIndexError(this, 'deleteRule', this.constructor.name, index, this.cssRules.length);
}
if (this.cssRules[index]) {
if (this.cssRules[index].constructor.name == "CSSNamespaceRule") {
var shouldContinue = this.cssRules.every(function (rule) {
return ['CSSImportRule','CSSLayerStatementRule','CSSNamespaceRule'].indexOf(rule.constructor.name) !== -1
});
if (!shouldContinue) {
errorUtils.throwError(this, 'DOMException', "Failed to execute 'deleteRule' on '" + this.constructor.name + "': Failed to delete rule.", "InvalidStateError");
}
}
if (this.cssRules[index].constructor.name == "CSSImportRule") {
this.cssRules[index].styleSheet.__parentStyleSheet = null;
}
this.cssRules[index].__parentStyleSheet = null;
}
this.cssRules.splice(index, 1);
};
CSSOM.CSSStyleSheet.prototype.removeRule = function(index) {
if (index === void 0) {
index = 0;
}
this.deleteRule(index);
};
/**
* Replaces the rules of a {@link CSSStyleSheet}
*
* @returns a promise
* @see https://www.w3.org/TR/cssom-1/#dom-cssstylesheet-replace
*/
CSSOM.CSSStyleSheet.prototype.replace = function(text) {
var _Promise;
if (this.__globalObject && this.__globalObject['Promise']) {
_Promise = this.__globalObject['Promise'];
} else {
_Promise = Promise;
}
var _setTimeout;
if (this.__globalObject && this.__globalObject['setTimeout']) {
_setTimeout = this.__globalObject['setTimeout'];
} else {
_setTimeout = setTimeout;
}
var sheet = this;
return new _Promise(function (resolve, reject) {
// If the constructed flag is not set, or the disallow modification flag is set, throw a NotAllowedError DOMException.
if (!sheet.__constructed || sheet.__disallowModification) {
reject(errorUtils.createError(sheet, 'DOMException',
"Failed to execute 'replaceSync' on '" + sheet.constructor.name + "': Not allowed.",
'NotAllowedError'));
}
// Set the disallow modification flag.
sheet.__disallowModification = true;
// In parallel, do these steps:
_setTimeout(function() {
// Let rules be the result of running parse a stylesheet's contents from text.
var rules = new CSSOM.CSSRuleList();
CSSOM.parse(text, { styleSheet: sheet, cssRules: rules });
// If rules contains one or more @import rules, remove those rules from rules.
var i = 0;
while (i < rules.length) {
if (rules[i].constructor.name === 'CSSImportRule') {
rules.splice(i, 1);
} else {
i++;
}
}
// Set sheet's CSS rules to rules.
sheet.__cssRules.splice.apply(sheet.__cssRules, [0, sheet.__cssRules.length].concat(rules));
// Unset sheets disallow modification flag.
delete sheet.__disallowModification;
// Resolve promise with sheet.
resolve(sheet);
})
});
}
/**
* Synchronously replaces the rules of a {@link CSSStyleSheet}
*
* @see https://www.w3.org/TR/cssom-1/#dom-cssstylesheet-replacesync
*/
CSSOM.CSSStyleSheet.prototype.replaceSync = function(text) {
var sheet = this;
// If the constructed flag is not set, or the disallow modification flag is set, throw a NotAllowedError DOMException.
if (!sheet.__constructed || sheet.__disallowModification) {
errorUtils.throwError(sheet, 'DOMException',
"Failed to execute 'replaceSync' on '" + sheet.constructor.name + "': Not allowed.",
'NotAllowedError');
}
// Let rules be the result of running parse a stylesheet's contents from text.
var rules = new CSSOM.CSSRuleList();
CSSOM.parse(text, { styleSheet: sheet, cssRules: rules });
// If rules contains one or more @import rules, remove those rules from rules.
var i = 0;
while (i < rules.length) {
if (rules[i].constructor.name === 'CSSImportRule') {
rules.splice(i, 1);
} else {
i++;
}
}
// Set sheet's CSS rules to rules.
sheet.__cssRules.splice.apply(sheet.__cssRules, [0, sheet.__cssRules.length].concat(rules));
}
/**
* NON-STANDARD
* @return {string} serialize stylesheet
*/
CSSOM.CSSStyleSheet.prototype.toString = function() {
var result = "";
var rules = this.cssRules;
for (var i=0; i<rules.length; i++) {
result += rules[i].cssText + "\n";
}
return result;
};
//.CommonJS
exports.CSSStyleSheet = CSSOM.CSSStyleSheet;
CSSOM.parse = require('./parse').parse; // Cannot be included sooner due to the mutual dependency between parse.js and CSSStyleSheet.js
///CommonJS

View File

@@ -0,0 +1,48 @@
//.CommonJS
var CSSOM = {
CSSRule: require("./CSSRule").CSSRule,
CSSRuleList: require("./CSSRuleList").CSSRuleList,
CSSGroupingRule: require("./CSSGroupingRule").CSSGroupingRule,
CSSConditionRule: require("./CSSConditionRule").CSSConditionRule
};
///CommonJS
/**
* @constructor
* @see https://drafts.csswg.org/css-conditional-3/#the-csssupportsrule-interface
*/
CSSOM.CSSSupportsRule = function CSSSupportsRule() {
CSSOM.CSSConditionRule.call(this);
};
CSSOM.CSSSupportsRule.prototype = Object.create(CSSOM.CSSConditionRule.prototype);
CSSOM.CSSSupportsRule.prototype.constructor = CSSOM.CSSSupportsRule;
Object.setPrototypeOf(CSSOM.CSSSupportsRule, CSSOM.CSSConditionRule);
Object.defineProperty(CSSOM.CSSSupportsRule.prototype, "type", {
value: 12,
writable: false
});
Object.defineProperty(CSSOM.CSSSupportsRule.prototype, "cssText", {
get: function() {
var values = "";
var valuesArr = [" {"];
if (this.cssRules.length) {
valuesArr.push(this.cssRules.reduce(function(acc, rule){
if (rule.cssText !== "") {
acc.push(rule.cssText);
}
return acc;
}, []).join("\n "));
}
values = valuesArr.join("\n ") + "\n}";
return "@supports " + this.conditionText + values;
}
});
//.CommonJS
exports.CSSSupportsRule = CSSOM.CSSSupportsRule;
///CommonJS

43
server/node_modules/@acemir/cssom/lib/CSSValue.js generated vendored Normal file
View File

@@ -0,0 +1,43 @@
//.CommonJS
var CSSOM = {};
///CommonJS
/**
* @constructor
* @see http://www.w3.org/TR/DOM-Level-2-Style/css.html#CSS-CSSValue
*
* TODO: add if needed
*/
CSSOM.CSSValue = function CSSValue() {
};
CSSOM.CSSValue.prototype = {
constructor: CSSOM.CSSValue,
// @see: http://www.w3.org/TR/DOM-Level-2-Style/css.html#CSS-CSSValue
set cssText(text) {
var name = this._getConstructorName();
throw new Error('DOMException: property "cssText" of "' + name + '" is readonly and can not be replaced with "' + text + '"!');
},
get cssText() {
var name = this._getConstructorName();
throw new Error('getter "cssText" of "' + name + '" is not implemented!');
},
_getConstructorName: function() {
var s = this.constructor.toString(),
c = s.match(/function\s([^\(]+)/),
name = c[1];
return name;
}
};
//.CommonJS
exports.CSSValue = CSSOM.CSSValue;
///CommonJS

View File

@@ -0,0 +1,346 @@
//.CommonJS
var CSSOM = {
CSSValue: require('./CSSValue').CSSValue
};
///CommonJS
/**
* @constructor
* @see http://msdn.microsoft.com/en-us/library/ms537634(v=vs.85).aspx
*
*/
CSSOM.CSSValueExpression = function CSSValueExpression(token, idx) {
this._token = token;
this._idx = idx;
};
CSSOM.CSSValueExpression.prototype = Object.create(CSSOM.CSSValue.prototype);
CSSOM.CSSValueExpression.prototype.constructor = CSSOM.CSSValueExpression;
Object.setPrototypeOf(CSSOM.CSSValueExpression, CSSOM.CSSValue);
/**
* parse css expression() value
*
* @return {Object}
* - error:
* or
* - idx:
* - expression:
*
* Example:
*
* .selector {
* zoom: expression(documentElement.clientWidth > 1000 ? '1000px' : 'auto');
* }
*/
CSSOM.CSSValueExpression.prototype.parse = function() {
var token = this._token,
idx = this._idx;
var character = '',
expression = '',
error = '',
info,
paren = [];
for (; ; ++idx) {
character = token.charAt(idx);
// end of token
if (character === '') {
error = 'css expression error: unfinished expression!';
break;
}
switch(character) {
case '(':
paren.push(character);
expression += character;
break;
case ')':
paren.pop(character);
expression += character;
break;
case '/':
if ((info = this._parseJSComment(token, idx))) { // comment?
if (info.error) {
error = 'css expression error: unfinished comment in expression!';
} else {
idx = info.idx;
// ignore the comment
}
} else if ((info = this._parseJSRexExp(token, idx))) { // regexp
idx = info.idx;
expression += info.text;
} else { // other
expression += character;
}
break;
case "'":
case '"':
info = this._parseJSString(token, idx, character);
if (info) { // string
idx = info.idx;
expression += info.text;
} else {
expression += character;
}
break;
default:
expression += character;
break;
}
if (error) {
break;
}
// end of expression
if (paren.length === 0) {
break;
}
}
var ret;
if (error) {
ret = {
error: error
};
} else {
ret = {
idx: idx,
expression: expression
};
}
return ret;
};
/**
*
* @return {Object|false}
* - idx:
* - text:
* or
* - error:
* or
* false
*
*/
CSSOM.CSSValueExpression.prototype._parseJSComment = function(token, idx) {
var nextChar = token.charAt(idx + 1),
text;
if (nextChar === '/' || nextChar === '*') {
var startIdx = idx,
endIdx,
commentEndChar;
if (nextChar === '/') { // line comment
commentEndChar = '\n';
} else if (nextChar === '*') { // block comment
commentEndChar = '*/';
}
endIdx = token.indexOf(commentEndChar, startIdx + 1 + 1);
if (endIdx !== -1) {
endIdx = endIdx + commentEndChar.length - 1;
text = token.substring(idx, endIdx + 1);
return {
idx: endIdx,
text: text
};
} else {
var error = 'css expression error: unfinished comment in expression!';
return {
error: error
};
}
} else {
return false;
}
};
/**
*
* @return {Object|false}
* - idx:
* - text:
* or
* false
*
*/
CSSOM.CSSValueExpression.prototype._parseJSString = function(token, idx, sep) {
var endIdx = this._findMatchedIdx(token, idx, sep),
text;
if (endIdx === -1) {
return false;
} else {
text = token.substring(idx, endIdx + sep.length);
return {
idx: endIdx,
text: text
};
}
};
/**
* parse regexp in css expression
*
* @return {Object|false}
* - idx:
* - regExp:
* or
* false
*/
/*
all legal RegExp
/a/
(/a/)
[/a/]
[12, /a/]
!/a/
+/a/
-/a/
* /a/
/ /a/
%/a/
===/a/
!==/a/
==/a/
!=/a/
>/a/
>=/a/
</a/
<=/a/
&/a/
|/a/
^/a/
~/a/
<</a/
>>/a/
>>>/a/
&&/a/
||/a/
?/a/
=/a/
,/a/
delete /a/
in /a/
instanceof /a/
new /a/
typeof /a/
void /a/
*/
CSSOM.CSSValueExpression.prototype._parseJSRexExp = function(token, idx) {
var before = token.substring(0, idx).replace(/\s+$/, ""),
legalRegx = [
/^$/,
/\($/,
/\[$/,
/\!$/,
/\+$/,
/\-$/,
/\*$/,
/\/\s+/,
/\%$/,
/\=$/,
/\>$/,
/<$/,
/\&$/,
/\|$/,
/\^$/,
/\~$/,
/\?$/,
/\,$/,
/delete$/,
/in$/,
/instanceof$/,
/new$/,
/typeof$/,
/void$/
];
var isLegal = legalRegx.some(function(reg) {
return reg.test(before);
});
if (!isLegal) {
return false;
} else {
var sep = '/';
// same logic as string
return this._parseJSString(token, idx, sep);
}
};
/**
*
* find next sep(same line) index in `token`
*
* @return {Number}
*
*/
CSSOM.CSSValueExpression.prototype._findMatchedIdx = function(token, idx, sep) {
var startIdx = idx,
endIdx;
var NOT_FOUND = -1;
while(true) {
endIdx = token.indexOf(sep, startIdx + 1);
if (endIdx === -1) { // not found
endIdx = NOT_FOUND;
break;
} else {
var text = token.substring(idx + 1, endIdx),
matched = text.match(/\\+$/);
if (!matched || matched[0] % 2 === 0) { // not escaped
break;
} else {
startIdx = endIdx;
}
}
}
// boundary must be in the same line(js sting or regexp)
var nextNewLineIdx = token.indexOf('\n', idx + 1);
if (nextNewLineIdx < endIdx) {
endIdx = NOT_FOUND;
}
return endIdx;
};
//.CommonJS
exports.CSSValueExpression = CSSOM.CSSValueExpression;
///CommonJS

62
server/node_modules/@acemir/cssom/lib/MatcherList.js generated vendored Normal file
View File

@@ -0,0 +1,62 @@
//.CommonJS
var CSSOM = {};
///CommonJS
/**
* @constructor
* @see https://developer.mozilla.org/en/CSS/@-moz-document
*/
CSSOM.MatcherList = function MatcherList(){
this.length = 0;
};
CSSOM.MatcherList.prototype = {
constructor: CSSOM.MatcherList,
/**
* @return {string}
*/
get matcherText() {
return Array.prototype.join.call(this, ", ");
},
/**
* @param {string} value
*/
set matcherText(value) {
// just a temporary solution, actually it may be wrong by just split the value with ',', because a url can include ','.
var values = value.split(",");
var length = this.length = values.length;
for (var i=0; i<length; i++) {
this[i] = values[i].trim();
}
},
/**
* @param {string} matcher
*/
appendMatcher: function(matcher) {
if (Array.prototype.indexOf.call(this, matcher) === -1) {
this[this.length] = matcher;
this.length++;
}
},
/**
* @param {string} matcher
*/
deleteMatcher: function(matcher) {
var index = Array.prototype.indexOf.call(this, matcher);
if (index !== -1) {
Array.prototype.splice.call(this, index, 1);
}
}
};
//.CommonJS
exports.MatcherList = CSSOM.MatcherList;
///CommonJS

78
server/node_modules/@acemir/cssom/lib/MediaList.js generated vendored Normal file
View File

@@ -0,0 +1,78 @@
//.CommonJS
var CSSOM = {};
///CommonJS
/**
* @constructor
* @see http://dev.w3.org/csswg/cssom/#the-medialist-interface
*/
CSSOM.MediaList = function MediaList(){
this.length = 0;
};
CSSOM.MediaList.prototype = {
constructor: CSSOM.MediaList,
/**
* @return {string}
*/
get mediaText() {
return Array.prototype.join.call(this, ", ");
},
/**
* @param {string} value
*/
set mediaText(value) {
if (typeof value === "string") {
var values = value.split(",").filter(function(text){
return !!text;
});
var length = this.length = values.length;
for (var i=0; i<length; i++) {
this[i] = values[i].trim();
}
} else if (value === null) {
var length = this.length;
for (var i = 0; i < length; i++) {
delete this[i];
}
this.length = 0;
}
},
/**
* @param {string} medium
*/
appendMedium: function(medium) {
if (Array.prototype.indexOf.call(this, medium) === -1) {
this[this.length] = medium;
this.length++;
}
},
/**
* @param {string} medium
*/
deleteMedium: function(medium) {
var index = Array.prototype.indexOf.call(this, medium);
if (index !== -1) {
Array.prototype.splice.call(this, index, 1);
}
},
item: function(index) {
return this[index] || null;
},
toString: function() {
return this.mediaText;
}
};
//.CommonJS
exports.MediaList = CSSOM.MediaList;
///CommonJS

62
server/node_modules/@acemir/cssom/lib/StyleSheet.js generated vendored Normal file
View File

@@ -0,0 +1,62 @@
//.CommonJS
var CSSOM = {
MediaList: require("./MediaList").MediaList
};
///CommonJS
/**
* @see http://dev.w3.org/csswg/cssom/#the-stylesheet-interface
*/
CSSOM.StyleSheet = function StyleSheet() {
this.__href = null;
this.__ownerNode = null;
this.__title = null;
this.__media = new CSSOM.MediaList();
this.__parentStyleSheet = null;
this.disabled = false;
};
Object.defineProperties(CSSOM.StyleSheet.prototype, {
type: {
get: function() {
return "text/css";
}
},
href: {
get: function() {
return this.__href;
}
},
ownerNode: {
get: function() {
return this.__ownerNode;
}
},
title: {
get: function() {
return this.__title;
}
},
media: {
get: function() {
return this.__media;
},
set: function(value) {
if (typeof value === "string") {
this.__media.mediaText = value;
} else {
this.__media = value;
}
}
},
parentStyleSheet: {
get: function() {
return this.__parentStyleSheet;
}
}
});
//.CommonJS
exports.StyleSheet = CSSOM.StyleSheet;
///CommonJS

105
server/node_modules/@acemir/cssom/lib/clone.js generated vendored Normal file
View File

@@ -0,0 +1,105 @@
//.CommonJS
var CSSOM = {
CSSStyleSheet: require("./CSSStyleSheet").CSSStyleSheet,
CSSRule: require("./CSSRule").CSSRule,
CSSNestedDeclarations: require("./CSSNestedDeclarations").CSSNestedDeclarations,
CSSStyleRule: require("./CSSStyleRule").CSSStyleRule,
CSSGroupingRule: require("./CSSGroupingRule").CSSGroupingRule,
CSSConditionRule: require("./CSSConditionRule").CSSConditionRule,
CSSMediaRule: require("./CSSMediaRule").CSSMediaRule,
CSSContainerRule: require("./CSSContainerRule").CSSContainerRule,
CSSSupportsRule: require("./CSSSupportsRule").CSSSupportsRule,
CSSStyleDeclaration: require("./CSSStyleDeclaration").CSSStyleDeclaration,
CSSKeyframeRule: require('./CSSKeyframeRule').CSSKeyframeRule,
CSSKeyframesRule: require('./CSSKeyframesRule').CSSKeyframesRule,
CSSScopeRule: require('./CSSScopeRule').CSSScopeRule,
CSSLayerBlockRule: require('./CSSLayerBlockRule').CSSLayerBlockRule,
CSSLayerStatementRule: require('./CSSLayerStatementRule').CSSLayerStatementRule
};
// Use cssstyle if available
try {
CSSOM.CSSStyleDeclaration = require("cssstyle").CSSStyleDeclaration;
} catch (e) {
// ignore
}
///CommonJS
/**
* Produces a deep copy of stylesheet — the instance variables of stylesheet are copied recursively.
* @param {CSSStyleSheet|CSSOM.CSSStyleSheet} stylesheet
* @nosideeffects
* @return {CSSOM.CSSStyleSheet}
*/
CSSOM.clone = function clone(stylesheet) {
var cloned = new CSSOM.CSSStyleSheet();
var rules = stylesheet.cssRules;
if (!rules) {
return cloned;
}
for (var i = 0, rulesLength = rules.length; i < rulesLength; i++) {
var rule = rules[i];
var ruleClone = cloned.cssRules[i] = new rule.constructor();
var style = rule.style;
if (style) {
var styleClone = ruleClone.style = new CSSOM.CSSStyleDeclaration();
for (var j = 0, styleLength = style.length; j < styleLength; j++) {
var name = styleClone[j] = style[j];
styleClone[name] = style[name];
styleClone._importants[name] = style.getPropertyPriority(name);
}
styleClone.length = style.length;
}
if (rule.hasOwnProperty('keyText')) {
ruleClone.keyText = rule.keyText;
}
if (rule.hasOwnProperty('selectorText')) {
ruleClone.selectorText = rule.selectorText;
}
if (rule.hasOwnProperty('mediaText')) {
ruleClone.mediaText = rule.mediaText;
}
if (rule.hasOwnProperty('supportsText')) {
ruleClone.supports = rule.supports;
}
if (rule.hasOwnProperty('conditionText')) {
ruleClone.conditionText = rule.conditionText;
}
if (rule.hasOwnProperty('layerName')) {
ruleClone.layerName = rule.layerName;
}
if (rule.hasOwnProperty('href')) {
ruleClone.href = rule.href;
}
if (rule.hasOwnProperty('name')) {
ruleClone.name = rule.name;
}
if (rule.hasOwnProperty('nameList')) {
ruleClone.nameList = rule.nameList;
}
if (rule.hasOwnProperty('cssRules')) {
ruleClone.cssRules = clone(rule).cssRules;
}
}
return cloned;
};
//.CommonJS
exports.clone = CSSOM.clone;
///CommonJS

View File

@@ -0,0 +1,5 @@
try {
CSSOM.CSSStyleDeclaration = require("cssstyle").CSSStyleDeclaration;
} catch (e) {
// ignore
}

119
server/node_modules/@acemir/cssom/lib/errorUtils.js generated vendored Normal file
View File

@@ -0,0 +1,119 @@
// Utility functions for CSSOM error handling
/**
* Gets the appropriate error constructor from the global object context.
* Tries to find the error constructor from parentStyleSheet.__globalObject,
* then from __globalObject, then falls back to the native constructor.
*
* @param {Object} context - The CSSOM object (rule, stylesheet, etc.)
* @param {string} errorType - The error type ('TypeError', 'RangeError', 'DOMException', etc.)
* @return {Function} The error constructor
*/
function getErrorConstructor(context, errorType) {
// Try parentStyleSheet.__globalObject first
if (context.parentStyleSheet && context.parentStyleSheet.__globalObject && context.parentStyleSheet.__globalObject[errorType]) {
return context.parentStyleSheet.__globalObject[errorType];
}
// Try __parentStyleSheet (alternative naming)
if (context.__parentStyleSheet && context.__parentStyleSheet.__globalObject && context.__parentStyleSheet.__globalObject[errorType]) {
return context.__parentStyleSheet.__globalObject[errorType];
}
// Try __globalObject on the context itself
if (context.__globalObject && context.__globalObject[errorType]) {
return context.__globalObject[errorType];
}
// Fall back to native constructor
return (typeof global !== 'undefined' && global[errorType]) ||
(typeof window !== 'undefined' && window[errorType]) ||
eval(errorType);
}
/**
* Creates an appropriate error with context-aware constructor.
*
* @param {Object} context - The CSSOM object (rule, stylesheet, etc.)
* @param {string} errorType - The error type ('TypeError', 'RangeError', 'DOMException', etc.)
* @param {string} message - The error message
* @param {string} [name] - Optional name for DOMException
*/
function createError(context, errorType, message, name) {
var ErrorConstructor = getErrorConstructor(context, errorType);
return new ErrorConstructor(message, name);
}
/**
* Creates and throws an appropriate error with context-aware constructor.
*
* @param {Object} context - The CSSOM object (rule, stylesheet, etc.)
* @param {string} errorType - The error type ('TypeError', 'RangeError', 'DOMException', etc.)
* @param {string} message - The error message
* @param {string} [name] - Optional name for DOMException
*/
function throwError(context, errorType, message, name) {
throw createError(context, errorType, message, name);
}
/**
* Throws a TypeError for missing required arguments.
*
* @param {Object} context - The CSSOM object
* @param {string} methodName - The method name (e.g., 'appendRule')
* @param {string} objectName - The object name (e.g., 'CSSKeyframesRule')
* @param {number} [required=1] - Number of required arguments
* @param {number} [provided=0] - Number of provided arguments
*/
function throwMissingArguments(context, methodName, objectName, required, provided) {
required = required || 1;
provided = provided || 0;
var message = "Failed to execute '" + methodName + "' on '" + objectName + "': " +
required + " argument" + (required > 1 ? "s" : "") + " required, but only " +
provided + " present.";
throwError(context, 'TypeError', message);
}
/**
* Throws a DOMException for parse errors.
*
* @param {Object} context - The CSSOM object
* @param {string} methodName - The method name
* @param {string} objectName - The object name
* @param {string} rule - The rule that failed to parse
* @param {string} [name='SyntaxError'] - The DOMException name
*/
function throwParseError(context, methodName, objectName, rule, name) {
var message = "Failed to execute '" + methodName + "' on '" + objectName + "': " +
"Failed to parse the rule '" + rule + "'.";
throwError(context, 'DOMException', message, name || 'SyntaxError');
}
/**
* Throws a DOMException for index errors.
*
* @param {Object} context - The CSSOM object
* @param {string} methodName - The method name
* @param {string} objectName - The object name
* @param {number} index - The invalid index
* @param {number} maxIndex - The maximum valid index
* @param {string} [name='IndexSizeError'] - The DOMException name
*/
function throwIndexError(context, methodName, objectName, index, maxIndex, name) {
var message = "Failed to execute '" + methodName + "' on '" + objectName + "': " +
"The index provided (" + index + ") is larger than the maximum index (" + maxIndex + ").";
throwError(context, 'DOMException', message, name || 'IndexSizeError');
}
var errorUtils = {
createError: createError,
getErrorConstructor: getErrorConstructor,
throwError: throwError,
throwMissingArguments: throwMissingArguments,
throwParseError: throwParseError,
throwIndexError: throwIndexError
};
//.CommonJS
exports.errorUtils = errorUtils;
///CommonJS

42
server/node_modules/@acemir/cssom/lib/index.js generated vendored Normal file
View File

@@ -0,0 +1,42 @@
'use strict';
exports.setup = require('./CSSOM').setup;
require('./errorUtils');
require("./regexPatterns")
exports.CSSStyleDeclaration = require('./CSSStyleDeclaration').CSSStyleDeclaration;
require('./cssstyleTryCatchBlock');
exports.CSSRule = require('./CSSRule').CSSRule;
exports.CSSRuleList = require('./CSSRuleList').CSSRuleList;
exports.CSSNestedDeclarations = require('./CSSNestedDeclarations').CSSNestedDeclarations;
exports.CSSGroupingRule = require('./CSSGroupingRule').CSSGroupingRule;
exports.CSSCounterStyleRule = require('./CSSCounterStyleRule').CSSCounterStyleRule;
exports.CSSPropertyRule = require('./CSSPropertyRule').CSSPropertyRule;
exports.CSSConditionRule = require('./CSSConditionRule').CSSConditionRule;
exports.CSSStyleRule = require('./CSSStyleRule').CSSStyleRule;
exports.MediaList = require('./MediaList').MediaList;
exports.CSSMediaRule = require('./CSSMediaRule').CSSMediaRule;
exports.CSSContainerRule = require('./CSSContainerRule').CSSContainerRule;
exports.CSSSupportsRule = require('./CSSSupportsRule').CSSSupportsRule;
exports.CSSImportRule = require('./CSSImportRule').CSSImportRule;
exports.CSSNamespaceRule = require('./CSSNamespaceRule').CSSNamespaceRule;
exports.CSSFontFaceRule = require('./CSSFontFaceRule').CSSFontFaceRule;
exports.CSSHostRule = require('./CSSHostRule').CSSHostRule;
exports.CSSStartingStyleRule = require('./CSSStartingStyleRule').CSSStartingStyleRule;
exports.StyleSheet = require('./StyleSheet').StyleSheet;
exports.CSSStyleSheet = require('./CSSStyleSheet').CSSStyleSheet;
exports.CSSKeyframesRule = require('./CSSKeyframesRule').CSSKeyframesRule;
exports.CSSKeyframeRule = require('./CSSKeyframeRule').CSSKeyframeRule;
exports.MatcherList = require('./MatcherList').MatcherList;
exports.CSSDocumentRule = require('./CSSDocumentRule').CSSDocumentRule;
exports.CSSValue = require('./CSSValue').CSSValue;
exports.CSSValueExpression = require('./CSSValueExpression').CSSValueExpression;
exports.CSSScopeRule = require('./CSSScopeRule').CSSScopeRule;
exports.CSSLayerBlockRule = require('./CSSLayerBlockRule').CSSLayerBlockRule;
exports.CSSLayerStatementRule = require('./CSSLayerStatementRule').CSSLayerStatementRule;
exports.CSSPageRule = require('./CSSPageRule').CSSPageRule;
exports.parse = require('./parse').parse;
exports.clone = require('./clone').clone;

3332
server/node_modules/@acemir/cssom/lib/parse.js generated vendored Normal file

File diff suppressed because it is too large Load Diff

162
server/node_modules/@acemir/cssom/lib/regexPatterns.js generated vendored Normal file
View File

@@ -0,0 +1,162 @@
// Shared regex patterns for CSS parsing and validation
// These patterns are compiled once and reused across multiple files for better performance
// Regex patterns for CSS parsing
var atKeyframesRegExp = /@(-(?:\w+-)+)?keyframes/g; // Match @keyframes and vendor-prefixed @keyframes
var beforeRulePortionRegExp = /{(?!.*{)|}(?!.*})|;(?!.*;)|\*\/(?!.*\*\/)/g; // Match the closest allowed character (a opening or closing brace, a semicolon or a comment ending) before the rule
var beforeRuleValidationRegExp = /^[\s{};]*(\*\/\s*)?$/; // Match that the portion before the rule is empty or contains only whitespace, semicolons, opening/closing braces, and optionally a comment ending (*/) followed by whitespace
var forwardRuleValidationRegExp = /(?:\s|\/\*|\{|\()/; // Match that the rule is followed by any whitespace, a opening comment, a condition opening parenthesis or a opening brace
var forwardImportRuleValidationRegExp = /(?:\s|\/\*|'|")/; // Match that the rule is followed by any whitespace, an opening comment, a single quote or double quote
var forwardRuleClosingBraceRegExp = /{[^{}]*}|}/; // Finds the next closing brace of a rule block
var forwardRuleSemicolonAndOpeningBraceRegExp = /^.*?({|;)/; // Finds the next semicolon or opening brace after the at-rule
// Regex patterns for CSS selector validation and parsing
var cssCustomIdentifierRegExp = /^(-?[_a-zA-Z]+(\.[_a-zA-Z]+)*[_a-zA-Z0-9-]*)$/; // Validates a css custom identifier
var startsWithCombinatorRegExp = /^\s*[>+~]/; // Checks if a selector starts with a CSS combinator (>, +, ~)
/**
* Parse `@page` selectorText for page name and pseudo-pages
* Valid formats:
* - (empty - no name, no pseudo-page)
* - `:left`, `:right`, `:first`, `:blank` (pseudo-page only)
* - `named` (named page only)
* - `named:first` (named page with single pseudo-page)
* - `named:first:left` (named page with multiple pseudo-pages)
*/
var atPageRuleSelectorRegExp = /^([^\s:]+)?((?::\w+)*)$/; // Validates @page rule selectors
// Regex patterns for CSSImportRule parsing
var layerRegExp = /layer\(([^)]*)\)/; // Matches layer() function in @import
var layerRuleNameRegExp = /^(-?[_a-zA-Z]+(\.[_a-zA-Z]+)*[_a-zA-Z0-9-]*)$/; // Validates layer name (same as custom identifier)
var doubleOrMoreSpacesRegExp = /\s{2,}/g; // Matches two or more consecutive whitespace characters
// Regex patterns for CSS escape sequences and identifiers
var startsWithHexEscapeRegExp = /^\\[0-9a-fA-F]/; // Checks if escape sequence starts with hex escape
var identStartCharRegExp = /[a-zA-Z_\u00A0-\uFFFF]/; // Valid identifier start character
var identCharRegExp = /^[a-zA-Z0-9_\-\u00A0-\uFFFF\\]/; // Valid identifier character
var specialCharsNeedEscapeRegExp = /[!"#$%&'()*+,./:;<=>?@\[\\\]^`{|}~\s]/; // Characters that need escaping
var combinatorOrSeparatorRegExp = /[\s>+~,()]/; // Selector boundaries and combinators
var afterHexEscapeSeparatorRegExp = /[\s>+~,(){}\[\]]/; // Characters that separate after hex escape
var trailingSpaceSeparatorRegExp = /[\s>+~,(){}]/; // Characters that allow trailing space
var endsWithHexEscapeRegExp = /\\[0-9a-fA-F]{1,6}\s+$/; // Matches selector ending with hex escape + space(s)
/**
* Regular expression to detect invalid characters in the value portion of a CSS style declaration.
*
* This regex matches a colon (:) that is not inside parentheses and not inside single or double quotes.
* It is used to ensure that the value part of a CSS property does not contain unexpected colons,
* which would indicate a malformed declaration (e.g., "color: foo:bar;" is invalid).
*
* The negative lookahead `(?![^(]*\))` ensures that the colon is not followed by a closing
* parenthesis without encountering an opening parenthesis, effectively ignoring colons inside
* function-like values (e.g., `url(data:image/png;base64,...)`).
*
* The lookahead `(?=(?:[^'"]|'[^']*'|"[^"]*")*$)` ensures that the colon is not inside single or double quotes,
* allowing colons within quoted strings (e.g., `content: ":";` or `background: url("foo:bar.png");`).
*
* Example:
* - `color: red;` // valid, does not match
* - `background: url(data:image/png;base64,...);` // valid, does not match
* - `content: ':';` // valid, does not match
* - `color: foo:bar;` // invalid, matches
*/
var basicStylePropertyValueValidationRegExp = /:(?![^(]*\))(?=(?:[^'"]|'[^']*'|"[^"]*")*$)/;
// Attribute selector pattern: matches attribute-name operator value
// Operators: =, ~=, |=, ^=, $=, *=
// Rewritten to avoid ReDoS by using greedy match and trimming in JavaScript
var attributeSelectorContentRegExp = /^([^\s=~|^$*]+)\s*(~=|\|=|\^=|\$=|\*=|=)\s*(.+)$/;
// Selector validation patterns
var pseudoElementRegExp = /::[a-zA-Z][\w-]*|:(before|after|first-line|first-letter)(?![a-zA-Z0-9_-])/; // Matches pseudo-elements
var invalidCombinatorLtGtRegExp = /<>/; // Invalid <> combinator
var invalidCombinatorDoubleGtRegExp = />>/; // Invalid >> combinator
var consecutiveCombinatorsRegExp = /[>+~]\s*[>+~]/; // Invalid consecutive combinators
var invalidSlottedRegExp = /(?:^|[\s>+~,\[])slotted\s*\(/i; // Invalid slotted() without ::
var invalidPartRegExp = /(?:^|[\s>+~,\[])part\s*\(/i; // Invalid part() without ::
var invalidCueRegExp = /(?:^|[\s>+~,\[])cue\s*\(/i; // Invalid cue() without ::
var invalidCueRegionRegExp = /(?:^|[\s>+~,\[])cue-region\s*\(/i; // Invalid cue-region() without ::
var invalidNestingPattern = /&(?![.\#\[:>\+~\s])[a-zA-Z]/; // Invalid & followed by type selector
var emptyPseudoClassRegExp = /:(?:is|not|where|has)\(\s*\)/; // Empty pseudo-class like :is()
var whitespaceNormalizationRegExp = /(['"])(?:\\.|[^\\])*?\1|(\r\n|\r|\n)/g; // Normalize newlines outside quotes
var newlineRemovalRegExp = /\n/g; // Remove all newlines
var whitespaceAndDotRegExp = /[\s.]/; // Matches whitespace or dot
var declarationOrOpenBraceRegExp = /[{;}]/; // Matches declaration separator or open brace
var ampersandRegExp = /&/; // Matches nesting selector
var hexEscapeSequenceRegExp = /^([0-9a-fA-F]{1,6})[ \t\r\n\f]?/; // Matches hex escape sequence (1-6 hex digits optionally followed by whitespace)
var attributeCaseFlagRegExp = /^(.+?)\s+([is])$/i; // Matches case-sensitivity flag at end of attribute value
var prependedAmpersandRegExp = /^&\s+[:\\.]/; // Matches prepended ampersand pattern (& followed by space and : or .)
var openBraceGlobalRegExp = /{/g; // Matches opening braces (global)
var closeBraceGlobalRegExp = /}/g; // Matches closing braces (global)
var scopePreludeSplitRegExp = /\s*\)\s*to\s+\(/; // Splits scope prelude by ") to ("
var leadingWhitespaceRegExp = /^\s+/; // Matches leading whitespace (used to implement a ES5-compliant alternative to trimStart())
var doubleQuoteRegExp = /"/g; // Match all double quotes (for escaping in attribute values)
var backslashRegExp = /\\/g; // Match all backslashes (for escaping in attribute values)
var regexPatterns = {
// Parsing patterns
atKeyframesRegExp: atKeyframesRegExp,
beforeRulePortionRegExp: beforeRulePortionRegExp,
beforeRuleValidationRegExp: beforeRuleValidationRegExp,
forwardRuleValidationRegExp: forwardRuleValidationRegExp,
forwardImportRuleValidationRegExp: forwardImportRuleValidationRegExp,
forwardRuleClosingBraceRegExp: forwardRuleClosingBraceRegExp,
forwardRuleSemicolonAndOpeningBraceRegExp: forwardRuleSemicolonAndOpeningBraceRegExp,
// Selector validation patterns
cssCustomIdentifierRegExp: cssCustomIdentifierRegExp,
startsWithCombinatorRegExp: startsWithCombinatorRegExp,
atPageRuleSelectorRegExp: atPageRuleSelectorRegExp,
// Parsing patterns used in CSSImportRule
layerRegExp: layerRegExp,
layerRuleNameRegExp: layerRuleNameRegExp,
doubleOrMoreSpacesRegExp: doubleOrMoreSpacesRegExp,
// Escape sequence and identifier patterns
startsWithHexEscapeRegExp: startsWithHexEscapeRegExp,
identStartCharRegExp: identStartCharRegExp,
identCharRegExp: identCharRegExp,
specialCharsNeedEscapeRegExp: specialCharsNeedEscapeRegExp,
combinatorOrSeparatorRegExp: combinatorOrSeparatorRegExp,
afterHexEscapeSeparatorRegExp: afterHexEscapeSeparatorRegExp,
trailingSpaceSeparatorRegExp: trailingSpaceSeparatorRegExp,
endsWithHexEscapeRegExp: endsWithHexEscapeRegExp,
// Basic style property value validation
basicStylePropertyValueValidationRegExp: basicStylePropertyValueValidationRegExp,
// Attribute selector patterns
attributeSelectorContentRegExp: attributeSelectorContentRegExp,
// Selector validation patterns
pseudoElementRegExp: pseudoElementRegExp,
invalidCombinatorLtGtRegExp: invalidCombinatorLtGtRegExp,
invalidCombinatorDoubleGtRegExp: invalidCombinatorDoubleGtRegExp,
consecutiveCombinatorsRegExp: consecutiveCombinatorsRegExp,
invalidSlottedRegExp: invalidSlottedRegExp,
invalidPartRegExp: invalidPartRegExp,
invalidCueRegExp: invalidCueRegExp,
invalidCueRegionRegExp: invalidCueRegionRegExp,
invalidNestingPattern: invalidNestingPattern,
emptyPseudoClassRegExp: emptyPseudoClassRegExp,
whitespaceNormalizationRegExp: whitespaceNormalizationRegExp,
newlineRemovalRegExp: newlineRemovalRegExp,
whitespaceAndDotRegExp: whitespaceAndDotRegExp,
declarationOrOpenBraceRegExp: declarationOrOpenBraceRegExp,
ampersandRegExp: ampersandRegExp,
hexEscapeSequenceRegExp: hexEscapeSequenceRegExp,
attributeCaseFlagRegExp: attributeCaseFlagRegExp,
prependedAmpersandRegExp: prependedAmpersandRegExp,
openBraceGlobalRegExp: openBraceGlobalRegExp,
closeBraceGlobalRegExp: closeBraceGlobalRegExp,
scopePreludeSplitRegExp: scopePreludeSplitRegExp,
leadingWhitespaceRegExp: leadingWhitespaceRegExp,
doubleQuoteRegExp: doubleQuoteRegExp,
backslashRegExp: backslashRegExp
};
//.CommonJS
exports.regexPatterns = regexPatterns;
///CommonJS

32
server/node_modules/@acemir/cssom/package.json generated vendored Normal file
View File

@@ -0,0 +1,32 @@
{
"name": "@acemir/cssom",
"description": "CSS Object Model implementation and CSS parser",
"keywords": [
"CSS",
"CSSOM",
"parser",
"styleSheet"
],
"version": "0.9.31",
"author": "Nikita Vasilyev <me@elv1s.ru>",
"contributors": [
"Acemir Sousa Mendes <acemirsm@gmail.com>"
],
"repository": "acemir/CSSOM",
"files": [
"lib/",
"build/"
],
"browser": "./build/CSSOM.js",
"main": "./lib/index.js",
"license": "MIT",
"scripts": {
"build": "node build.js",
"release": "npm run build && changeset publish"
},
"devDependencies": {
"@changesets/changelog-github": "^0.5.2",
"@changesets/cli": "^2.29.8",
"@changesets/get-release-plan": "^4.0.14"
}
}

21
server/node_modules/@asamuzakjp/css-color/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2024 asamuzaK (Kazz)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

316
server/node_modules/@asamuzakjp/css-color/README.md generated vendored Normal file
View File

@@ -0,0 +1,316 @@
# CSS color
[![build](https://github.com/asamuzaK/cssColor/actions/workflows/node.js.yml/badge.svg)](https://github.com/asamuzaK/cssColor/actions/workflows/node.js.yml)
[![CodeQL](https://github.com/asamuzaK/cssColor/actions/workflows/github-code-scanning/codeql/badge.svg)](https://github.com/asamuzaK/cssColor/actions/workflows/github-code-scanning/codeql)
[![npm (scoped)](https://img.shields.io/npm/v/@asamuzakjp/css-color)](https://www.npmjs.com/package/@asamuzakjp/css-color)
Resolve and convert CSS colors.
## Install
```console
npm i @asamuzakjp/css-color
```
## Usage
```javascript
import { convert, resolve, utils } from '@asamuzakjp/css-color';
const resolvedValue = resolve(
'color-mix(in oklab, lch(67.5345 42.5 258.2), color(srgb 0 0.5 0))'
);
// 'oklab(0.620754 -0.0931934 -0.00374881)'
const convertedValue = convert.colorToHex('lab(46.2775% -47.5621 48.5837)');
// '#008000'
const result = utils.isColor('green');
// true
```
<!-- Generated by documentation.js. Update this documentation by updating the source code. -->
### resolve(color, opt)
resolves CSS color
#### Parameters
- `color` **[string][133]** color value
- system colors are not supported
- `opt` **[object][135]?** options (optional, default `{}`)
- `opt.currentColor` **[string][133]?**
- color to use for `currentcolor` keyword
- if omitted, it will be treated as a missing color,
i.e. `rgb(none none none / none)`
- `opt.customProperty` **[object][135]?**
- custom properties
- pair of `--` prefixed property name as a key and it's value,
e.g.
```javascript
const opt = {
customProperty: {
'--some-color': '#008000',
'--some-length': '16px'
}
};
```
- and/or `callback` function to get the value of the custom property,
e.g.
```javascript
const node = document.getElementById('foo');
const opt = {
customProperty: {
callback: node.style.getPropertyValue
}
};
```
- `opt.dimension` **[object][135]?**
- dimension, e.g. for converting relative length to pixels
- pair of unit as a key and number in pixels as it's value,
e.g. suppose `1em === 12px`, `1rem === 16px` and `100vw === 1024px`, then
```javascript
const opt = {
dimension: {
em: 12,
rem: 16,
vw: 10.24
}
};
```
- and/or `callback` function to get the value as a number in pixels,
e.g.
```javascript
const opt = {
dimension: {
callback: unit => {
switch (unit) {
case 'em':
return 12;
case 'rem':
return 16;
case 'vw':
return 10.24;
default:
return;
}
}
}
};
```
- `opt.format` **[string][133]?**
- output format, one of below
- `computedValue` (default), [computed value][139] of the color
- `specifiedValue`, [specified value][140] of the color
- `hex`, hex color notation, i.e. `#rrggbb`
- `hexAlpha`, hex color notation with alpha channel, i.e. `#rrggbbaa`
Returns **[string][133]?** one of `rgba?()`, `#rrggbb(aa)?`, `color-name`, `color(color-space r g b / alpha)`, `color(color-space x y z / alpha)`, `(ok)?lab(l a b / alpha)`, `(ok)?lch(l c h / alpha)`, `'(empty-string)'`, `null`
- in `computedValue`, values are numbers, however `rgb()` values are integers
- in `specifiedValue`, returns `empty string` for unknown and/or invalid color
- in `hex`, returns `null` for `transparent`, and also returns `null` if any of `r`, `g`, `b`, `alpha` is not a number
- in `hexAlpha`, returns `#00000000` for `transparent`, however returns `null` if any of `r`, `g`, `b`, `alpha` is not a number
### convert
Contains various color conversion functions.
### convert.numberToHex(value)
convert number to hex string
#### Parameters
- `value` **[number][134]** color value
Returns **[string][133]** hex string: 00..ff
### convert.colorToHex(value, opt)
convert color to hex
#### Parameters
- `value` **[string][133]** color value
- `opt` **[object][135]?** options (optional, default `{}`)
- `opt.alpha` **[boolean][136]?** return in #rrggbbaa notation
- `opt.customProperty` **[object][135]?**
- custom properties, see `resolve()` function above
- `opt.dimension` **[object][135]?**
- dimension, see `resolve()` function above
Returns **[string][133]** #rrggbb(aa)?
### convert.colorToHsl(value, opt)
convert color to hsl
#### Parameters
- `value` **[string][133]** color value
- `opt` **[object][135]?** options (optional, default `{}`)
- `opt.customProperty` **[object][135]?**
- custom properties, see `resolve()` function above
- `opt.dimension` **[object][135]?**
- dimension, see `resolve()` function above
Returns **[Array][137]<[number][134]>** \[h, s, l, alpha]
### convert.colorToHwb(value, opt)
convert color to hwb
#### Parameters
- `value` **[string][133]** color value
- `opt` **[object][135]?** options (optional, default `{}`)
- `opt.customProperty` **[object][135]?**
- custom properties, see `resolve()` function above
- `opt.dimension` **[object][135]?**
- dimension, see `resolve()` function above
Returns **[Array][137]<[number][134]>** \[h, w, b, alpha]
### convert.colorToLab(value, opt)
convert color to lab
#### Parameters
- `value` **[string][133]** color value
- `opt` **[object][135]?** options (optional, default `{}`)
- `opt.customProperty` **[object][135]?**
- custom properties, see `resolve()` function above
- `opt.dimension` **[object][135]?**
- dimension, see `resolve()` function above
Returns **[Array][137]<[number][134]>** \[l, a, b, alpha]
### convert.colorToLch(value, opt)
convert color to lch
#### Parameters
- `value` **[string][133]** color value
- `opt` **[object][135]?** options (optional, default `{}`)
- `opt.customProperty` **[object][135]?**
- custom properties, see `resolve()` function above
- `opt.dimension` **[object][135]?**
- dimension, see `resolve()` function above
Returns **[Array][137]<[number][134]>** \[l, c, h, alpha]
### convert.colorToOklab(value, opt)
convert color to oklab
#### Parameters
- `value` **[string][133]** color value
- `opt` **[object][135]?** options (optional, default `{}`)
- `opt.customProperty` **[object][135]?**
- custom properties, see `resolve()` function above
- `opt.dimension` **[object][135]?**
- dimension, see `resolve()` function above
Returns **[Array][137]<[number][134]>** \[l, a, b, alpha]
### convert.colorToOklch(value, opt)
convert color to oklch
#### Parameters
- `value` **[string][133]** color value
- `opt` **[object][135]?** options (optional, default `{}`)
- `opt.customProperty` **[object][135]?**
- custom properties, see `resolve()` function above
- `opt.dimension` **[object][135]?**
- dimension, see `resolve()` function above
Returns **[Array][137]<[number][134]>** \[l, c, h, alpha]
### convert.colorToRgb(value, opt)
convert color to rgb
#### Parameters
- `value` **[string][133]** color value
- `opt` **[object][135]?** options (optional, default `{}`)
- `opt.customProperty` **[object][135]?**
- custom properties, see `resolve()` function above
- `opt.dimension` **[object][135]?**
- dimension, see `resolve()` function above
Returns **[Array][137]<[number][134]>** \[r, g, b, alpha]
### convert.colorToXyz(value, opt)
convert color to xyz
#### Parameters
- `value` **[string][133]** color value
- `opt` **[object][135]?** options (optional, default `{}`)
- `opt.customProperty` **[object][135]?**
- custom properties, see `resolve()` function above
- `opt.dimension` **[object][135]?**
- dimension, see `resolve()` function above
- `opt.d50` **[boolean][136]?** xyz in d50 white point
Returns **[Array][137]<[number][134]>** \[x, y, z, alpha]
### convert.colorToXyzD50(value, opt)
convert color to xyz-d50
#### Parameters
- `value` **[string][133]** color value
- `opt` **[object][135]?** options (optional, default `{}`)
- `opt.customProperty` **[object][135]?**
- custom properties, see `resolve()` function above
- `opt.dimension` **[object][135]?**
- dimension, see `resolve()` function above
Returns **[Array][137]<[number][134]>** \[x, y, z, alpha]
### utils
Contains utility functions.
### utils.isColor(color)
is valid color type
#### Parameters
- `color` **[string][133]** color value
- system colors are not supported
Returns **[boolean][136]**
## Acknowledgments
The following resources have been of great help in the development of the CSS color.
- [csstools/postcss-plugins](https://github.com/csstools/postcss-plugins)
- [lru-cache](https://github.com/isaacs/node-lru-cache)
---
Copyright (c) 2024 [asamuzaK (Kazz)](https://github.com/asamuzaK/)
[133]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String
[134]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Number
[135]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object
[136]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Boolean
[137]: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array
[138]: https://w3c.github.io/csswg-drafts/css-color-4/#color-conversion-code
[139]: https://developer.mozilla.org/en-US/docs/Web/CSS/computed_value
[140]: https://developer.mozilla.org/en-US/docs/Web/CSS/specified_value
[141]: https://www.npmjs.com/package/@csstools/css-calc

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,110 @@
/**
* typedef
*/
/**
* @typedef Options - options
* @property [alpha] - enable alpha
* @property [colorSpace] - color space
* @property [currentColor] - color for currentcolor
* @property [customProperty] - custom properties
* @property [d50] - white point in d50
* @property [dimension] - dimension
* @property [format] - output format
* @property [key] - key
*/
interface Options {
alpha?: boolean;
colorScheme?: string;
colorSpace?: string;
currentColor?: string;
customProperty?: Record<string, string | ((K: string) => string)>;
d50?: boolean;
delimiter?: string | string[];
dimension?: Record<string, number | ((K: string) => number)>;
format?: string;
nullable?: boolean;
preserveComment?: boolean;
}
/**
* @type ColorChannels - color channels
*/
type ColorChannels = [x: number, y: number, z: number, alpha: number];
/**
* convert
*/
declare const convert: {
colorToHex: (value: string, opt?: Options) => string | null;
colorToHsl: (value: string, opt?: Options) => ColorChannels;
colorToHwb: (value: string, opt?: Options) => ColorChannels;
colorToLab: (value: string, opt?: Options) => ColorChannels;
colorToLch: (value: string, opt?: Options) => ColorChannels;
colorToOklab: (value: string, opt?: Options) => ColorChannels;
colorToOklch: (value: string, opt?: Options) => ColorChannels;
colorToRgb: (value: string, opt?: Options) => ColorChannels;
colorToXyz: (value: string, opt?: Options) => ColorChannels;
colorToXyzD50: (value: string, opt?: Options) => ColorChannels;
numberToHex: (value: number) => string;
};
/**
* resolve
*/
/**
* resolve CSS color
* @param value
* - CSS color value
* - system colors are not supported
* @param [opt] - options
* @param [opt.currentColor]
* - color to use for `currentcolor` keyword
* - if omitted, it will be treated as a missing color
* i.e. `rgb(none none none / none)`
* @param [opt.customProperty]
* - custom properties
* - pair of `--` prefixed property name and value,
* e.g. `customProperty: { '--some-color': '#0000ff' }`
* - and/or `callback` function to get the value of the custom property,
* e.g. `customProperty: { callback: someDeclaration.getPropertyValue }`
* @param [opt.dimension]
* - dimension, convert relative length to pixels
* - pair of unit and it's value as a number in pixels,
* e.g. `dimension: { em: 12, rem: 16, vw: 10.26 }`
* - and/or `callback` function to get the value as a number in pixels,
* e.g. `dimension: { callback: convertUnitToPixel }`
* @param [opt.format]
* - output format, one of below
* - `computedValue` (default), [computed value][139] of the color
* - `specifiedValue`, [specified value][140] of the color
* - `hex`, hex color notation, i.e. `rrggbb`
* - `hexAlpha`, hex color notation with alpha channel, i.e. `#rrggbbaa`
* @returns
* - one of rgba?(), #rrggbb(aa)?, color-name, '(empty-string)',
* color(color-space r g b / alpha), color(color-space x y z / alpha),
* lab(l a b / alpha), lch(l c h / alpha), oklab(l a b / alpha),
* oklch(l c h / alpha), null
* - in `computedValue`, values are numbers, however `rgb()` values are
* integers
* - in `specifiedValue`, returns `empty string` for unknown and/or invalid
* color
* - in `hex`, returns `null` for `transparent`, and also returns `null` if
* any of `r`, `g`, `b`, `alpha` is not a number
* - in `hexAlpha`, returns `#00000000` for `transparent`,
* however returns `null` if any of `r`, `g`, `b`, `alpha` is not a number
*/
declare const resolve: (value: string, opt?: Options) => string | null;
declare const utils: {
cssCalc: (value: string, opt?: Options) => string;
cssVar: (value: string, opt?: Options) => string;
extractDashedIdent: (value: string) => string[];
isColor: (value: unknown, opt?: Options) => boolean;
isGradient: (value: string, opt?: Options) => boolean;
resolveGradient: (value: string, opt?: Options) => string;
resolveLengthInPixels: (value: number | string, unit: string | undefined, opt?: Options) => number;
splitValue: (value: string, opt?: Options) => string[];
};
export { convert, resolve, utils };

View File

@@ -0,0 +1,18 @@
/*!
* CSS color - Resolve, parse, convert CSS color.
* @license MIT
* @copyright asamuzaK (Kazz)
* @see {@link https://github.com/asamuzaK/cssColor/blob/main/LICENSE}
*/
export { convert } from './js/convert.js';
export { resolve } from './js/resolve.js';
export declare const utils: {
cssCalc: (value: string, opt?: import('./js/typedef.js').Options) => string;
cssVar: (value: string, opt?: import('./js/typedef.js').Options) => string;
extractDashedIdent: (value: string) => string[];
isColor: (value: unknown, opt?: import('./js/typedef.js').Options) => boolean;
isGradient: (value: string, opt?: import('./js/typedef.js').Options) => boolean;
resolveGradient: (value: string, opt?: import('./js/typedef.js').Options) => string;
resolveLengthInPixels: (value: number | string, unit: string | undefined, opt?: import('./js/typedef.js').Options) => number;
splitValue: (value: string, opt?: import('./js/typedef.js').Options) => string[];
};

View File

@@ -0,0 +1,22 @@
import { cssCalc } from "./js/css-calc.js";
import { resolveGradient, isGradient } from "./js/css-gradient.js";
import { cssVar } from "./js/css-var.js";
import { splitValue, resolveLengthInPixels, isColor, extractDashedIdent } from "./js/util.js";
import { convert } from "./js/convert.js";
import { resolve } from "./js/resolve.js";
const utils = {
cssCalc,
cssVar,
extractDashedIdent,
isColor,
isGradient,
resolveGradient,
resolveLengthInPixels,
splitValue
};
export {
convert,
resolve,
utils
};
//# sourceMappingURL=index.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"index.js","sources":["../../src/index.ts"],"sourcesContent":["/*!\n * CSS color - Resolve, parse, convert CSS color.\n * @license MIT\n * @copyright asamuzaK (Kazz)\n * @see {@link https://github.com/asamuzaK/cssColor/blob/main/LICENSE}\n */\n\nimport { cssCalc } from './js/css-calc';\nimport { isGradient, resolveGradient } from './js/css-gradient';\nimport { cssVar } from './js/css-var';\nimport {\n extractDashedIdent,\n isColor,\n resolveLengthInPixels,\n splitValue\n} from './js/util';\n\nexport { convert } from './js/convert';\nexport { resolve } from './js/resolve';\n/* utils */\nexport const utils = {\n cssCalc,\n cssVar,\n extractDashedIdent,\n isColor,\n isGradient,\n resolveGradient,\n resolveLengthInPixels,\n splitValue\n};\n"],"names":[],"mappings":";;;;;;AAoBO,MAAM,QAAQ;AAAA,EACnB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;"}

View File

@@ -0,0 +1,44 @@
import { LRUCache } from 'lru-cache';
import { Options } from './typedef.js';
/**
* CacheItem
*/
export declare class CacheItem {
#private;
/**
* constructor
*/
constructor(item: unknown, isNull?: boolean);
get item(): unknown;
get isNull(): boolean;
}
/**
* NullObject
*/
export declare class NullObject extends CacheItem {
/**
* constructor
*/
constructor();
}
export declare const lruCache: LRUCache<{}, {}, unknown>;
/**
* set cache
* @param key - cache key
* @param value - value to cache
* @returns void
*/
export declare const setCache: (key: string, value: unknown) => void;
/**
* get cache
* @param key - cache key
* @returns cached item or false otherwise
*/
export declare const getCache: (key: string) => CacheItem | boolean;
/**
* create cache key
* @param keyData - key data
* @param [opt] - options
* @returns cache key
*/
export declare const createCacheKey: (keyData: Record<string, string>, opt?: Options) => string;

View File

@@ -0,0 +1,72 @@
import { LRUCache } from "lru-cache";
import { valueToJsonString } from "./util.js";
const MAX_CACHE = 4096;
class CacheItem {
/* private */
#isNull;
#item;
/**
* constructor
*/
constructor(item, isNull = false) {
this.#item = item;
this.#isNull = !!isNull;
}
get item() {
return this.#item;
}
get isNull() {
return this.#isNull;
}
}
class NullObject extends CacheItem {
/**
* constructor
*/
constructor() {
super(/* @__PURE__ */ Symbol("null"), true);
}
}
const lruCache = new LRUCache({
max: MAX_CACHE
});
const setCache = (key, value) => {
if (key) {
if (value === null) {
lruCache.set(key, new NullObject());
} else if (value instanceof CacheItem) {
lruCache.set(key, value);
} else {
lruCache.set(key, new CacheItem(value));
}
}
};
const getCache = (key) => {
if (key && lruCache.has(key)) {
const item = lruCache.get(key);
if (item instanceof CacheItem) {
return item;
}
lruCache.delete(key);
return false;
}
return false;
};
const createCacheKey = (keyData, opt = {}) => {
const { customProperty = {}, dimension = {} } = opt;
let cacheKey = "";
if (keyData && Object.keys(keyData).length && typeof customProperty.callback !== "function" && typeof dimension.callback !== "function") {
keyData.opt = valueToJsonString(opt);
cacheKey = valueToJsonString(keyData);
}
return cacheKey;
};
export {
CacheItem,
NullObject,
createCacheKey,
getCache,
lruCache,
setCache
};
//# sourceMappingURL=cache.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"cache.js","sources":["../../../src/js/cache.ts"],"sourcesContent":["/**\n * cache\n */\n\nimport { LRUCache } from 'lru-cache';\nimport { Options } from './typedef';\nimport { valueToJsonString } from './util';\n\n/* numeric constants */\nconst MAX_CACHE = 4096;\n\n/**\n * CacheItem\n */\nexport class CacheItem {\n /* private */\n #isNull: boolean;\n #item: unknown;\n\n /**\n * constructor\n */\n constructor(item: unknown, isNull: boolean = false) {\n this.#item = item;\n this.#isNull = !!isNull;\n }\n\n get item() {\n return this.#item;\n }\n\n get isNull() {\n return this.#isNull;\n }\n}\n\n/**\n * NullObject\n */\nexport class NullObject extends CacheItem {\n /**\n * constructor\n */\n constructor() {\n super(Symbol('null'), true);\n }\n}\n\n/*\n * lru cache\n */\nexport const lruCache = new LRUCache({\n max: MAX_CACHE\n});\n\n/**\n * set cache\n * @param key - cache key\n * @param value - value to cache\n * @returns void\n */\nexport const setCache = (key: string, value: unknown): void => {\n if (key) {\n if (value === null) {\n lruCache.set(key, new NullObject());\n } else if (value instanceof CacheItem) {\n lruCache.set(key, value);\n } else {\n lruCache.set(key, new CacheItem(value));\n }\n }\n};\n\n/**\n * get cache\n * @param key - cache key\n * @returns cached item or false otherwise\n */\nexport const getCache = (key: string): CacheItem | boolean => {\n if (key && lruCache.has(key)) {\n const item = lruCache.get(key);\n if (item instanceof CacheItem) {\n return item;\n }\n // delete unexpected cached item\n lruCache.delete(key);\n return false;\n }\n return false;\n};\n\n/**\n * create cache key\n * @param keyData - key data\n * @param [opt] - options\n * @returns cache key\n */\nexport const createCacheKey = (\n keyData: Record<string, string>,\n opt: Options = {}\n): string => {\n const { customProperty = {}, dimension = {} } = opt;\n let cacheKey = '';\n if (\n keyData &&\n Object.keys(keyData).length &&\n typeof customProperty.callback !== 'function' &&\n typeof dimension.callback !== 'function'\n ) {\n keyData.opt = valueToJsonString(opt);\n cacheKey = valueToJsonString(keyData);\n }\n return cacheKey;\n};\n"],"names":[],"mappings":";;AASA,MAAM,YAAY;AAKX,MAAM,UAAU;AAAA;AAAA,EAErB;AAAA,EACA;AAAA;AAAA;AAAA;AAAA,EAKA,YAAY,MAAe,SAAkB,OAAO;AAClD,SAAK,QAAQ;AACb,SAAK,UAAU,CAAC,CAAC;AAAA,EACnB;AAAA,EAEA,IAAI,OAAO;AACT,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,IAAI,SAAS;AACX,WAAO,KAAK;AAAA,EACd;AACF;AAKO,MAAM,mBAAmB,UAAU;AAAA;AAAA;AAAA;AAAA,EAIxC,cAAc;AACZ,UAAM,uBAAO,MAAM,GAAG,IAAI;AAAA,EAC5B;AACF;AAKO,MAAM,WAAW,IAAI,SAAS;AAAA,EACnC,KAAK;AACP,CAAC;AAQM,MAAM,WAAW,CAAC,KAAa,UAAyB;AAC7D,MAAI,KAAK;AACP,QAAI,UAAU,MAAM;AAClB,eAAS,IAAI,KAAK,IAAI,WAAA,CAAY;AAAA,IACpC,WAAW,iBAAiB,WAAW;AACrC,eAAS,IAAI,KAAK,KAAK;AAAA,IACzB,OAAO;AACL,eAAS,IAAI,KAAK,IAAI,UAAU,KAAK,CAAC;AAAA,IACxC;AAAA,EACF;AACF;AAOO,MAAM,WAAW,CAAC,QAAqC;AAC5D,MAAI,OAAO,SAAS,IAAI,GAAG,GAAG;AAC5B,UAAM,OAAO,SAAS,IAAI,GAAG;AAC7B,QAAI,gBAAgB,WAAW;AAC7B,aAAO;AAAA,IACT;AAEA,aAAS,OAAO,GAAG;AACnB,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAQO,MAAM,iBAAiB,CAC5B,SACA,MAAe,OACJ;AACX,QAAM,EAAE,iBAAiB,CAAA,GAAI,YAAY,CAAA,MAAO;AAChD,MAAI,WAAW;AACf,MACE,WACA,OAAO,KAAK,OAAO,EAAE,UACrB,OAAO,eAAe,aAAa,cACnC,OAAO,UAAU,aAAa,YAC9B;AACA,YAAQ,MAAM,kBAAkB,GAAG;AACnC,eAAW,kBAAkB,OAAO;AAAA,EACtC;AACA,SAAO;AACT;"}

View File

@@ -0,0 +1,537 @@
import { NullObject } from './cache.js';
import { ColorChannels, Options, SpecifiedColorChannels } from './typedef.js';
/**
* @type TriColorChannels - color channels without alpha
*/
type TriColorChannels = [x: number, y: number, z: number];
/**
* @type ColorMatrix - color matrix
*/
type ColorMatrix = [
r1: TriColorChannels,
r2: TriColorChannels,
r3: TriColorChannels
];
/**
* named colors
*/
export declare const NAMED_COLORS: {
readonly aliceblue: [240, 248, 255];
readonly antiquewhite: [250, 235, 215];
readonly aqua: [0, 255, 255];
readonly aquamarine: [127, 255, 212];
readonly azure: [240, 255, 255];
readonly beige: [245, 245, 220];
readonly bisque: [255, 228, 196];
readonly black: [0, 0, 0];
readonly blanchedalmond: [255, 235, 205];
readonly blue: [0, 0, 255];
readonly blueviolet: [138, 43, 226];
readonly brown: [165, 42, 42];
readonly burlywood: [222, 184, 135];
readonly cadetblue: [95, 158, 160];
readonly chartreuse: [127, 255, 0];
readonly chocolate: [210, 105, 30];
readonly coral: [255, 127, 80];
readonly cornflowerblue: [100, 149, 237];
readonly cornsilk: [255, 248, 220];
readonly crimson: [220, 20, 60];
readonly cyan: [0, 255, 255];
readonly darkblue: [0, 0, 139];
readonly darkcyan: [0, 139, 139];
readonly darkgoldenrod: [184, 134, 11];
readonly darkgray: [169, 169, 169];
readonly darkgreen: [0, 100, 0];
readonly darkgrey: [169, 169, 169];
readonly darkkhaki: [189, 183, 107];
readonly darkmagenta: [139, 0, 139];
readonly darkolivegreen: [85, 107, 47];
readonly darkorange: [255, 140, 0];
readonly darkorchid: [153, 50, 204];
readonly darkred: [139, 0, 0];
readonly darksalmon: [233, 150, 122];
readonly darkseagreen: [143, 188, 143];
readonly darkslateblue: [72, 61, 139];
readonly darkslategray: [47, 79, 79];
readonly darkslategrey: [47, 79, 79];
readonly darkturquoise: [0, 206, 209];
readonly darkviolet: [148, 0, 211];
readonly deeppink: [255, 20, 147];
readonly deepskyblue: [0, 191, 255];
readonly dimgray: [105, 105, 105];
readonly dimgrey: [105, 105, 105];
readonly dodgerblue: [30, 144, 255];
readonly firebrick: [178, 34, 34];
readonly floralwhite: [255, 250, 240];
readonly forestgreen: [34, 139, 34];
readonly fuchsia: [255, 0, 255];
readonly gainsboro: [220, 220, 220];
readonly ghostwhite: [248, 248, 255];
readonly gold: [255, 215, 0];
readonly goldenrod: [218, 165, 32];
readonly gray: [128, 128, 128];
readonly green: [0, 128, 0];
readonly greenyellow: [173, 255, 47];
readonly grey: [128, 128, 128];
readonly honeydew: [240, 255, 240];
readonly hotpink: [255, 105, 180];
readonly indianred: [205, 92, 92];
readonly indigo: [75, 0, 130];
readonly ivory: [255, 255, 240];
readonly khaki: [240, 230, 140];
readonly lavender: [230, 230, 250];
readonly lavenderblush: [255, 240, 245];
readonly lawngreen: [124, 252, 0];
readonly lemonchiffon: [255, 250, 205];
readonly lightblue: [173, 216, 230];
readonly lightcoral: [240, 128, 128];
readonly lightcyan: [224, 255, 255];
readonly lightgoldenrodyellow: [250, 250, 210];
readonly lightgray: [211, 211, 211];
readonly lightgreen: [144, 238, 144];
readonly lightgrey: [211, 211, 211];
readonly lightpink: [255, 182, 193];
readonly lightsalmon: [255, 160, 122];
readonly lightseagreen: [32, 178, 170];
readonly lightskyblue: [135, 206, 250];
readonly lightslategray: [119, 136, 153];
readonly lightslategrey: [119, 136, 153];
readonly lightsteelblue: [176, 196, 222];
readonly lightyellow: [255, 255, 224];
readonly lime: [0, 255, 0];
readonly limegreen: [50, 205, 50];
readonly linen: [250, 240, 230];
readonly magenta: [255, 0, 255];
readonly maroon: [128, 0, 0];
readonly mediumaquamarine: [102, 205, 170];
readonly mediumblue: [0, 0, 205];
readonly mediumorchid: [186, 85, 211];
readonly mediumpurple: [147, 112, 219];
readonly mediumseagreen: [60, 179, 113];
readonly mediumslateblue: [123, 104, 238];
readonly mediumspringgreen: [0, 250, 154];
readonly mediumturquoise: [72, 209, 204];
readonly mediumvioletred: [199, 21, 133];
readonly midnightblue: [25, 25, 112];
readonly mintcream: [245, 255, 250];
readonly mistyrose: [255, 228, 225];
readonly moccasin: [255, 228, 181];
readonly navajowhite: [255, 222, 173];
readonly navy: [0, 0, 128];
readonly oldlace: [253, 245, 230];
readonly olive: [128, 128, 0];
readonly olivedrab: [107, 142, 35];
readonly orange: [255, 165, 0];
readonly orangered: [255, 69, 0];
readonly orchid: [218, 112, 214];
readonly palegoldenrod: [238, 232, 170];
readonly palegreen: [152, 251, 152];
readonly paleturquoise: [175, 238, 238];
readonly palevioletred: [219, 112, 147];
readonly papayawhip: [255, 239, 213];
readonly peachpuff: [255, 218, 185];
readonly peru: [205, 133, 63];
readonly pink: [255, 192, 203];
readonly plum: [221, 160, 221];
readonly powderblue: [176, 224, 230];
readonly purple: [128, 0, 128];
readonly rebeccapurple: [102, 51, 153];
readonly red: [255, 0, 0];
readonly rosybrown: [188, 143, 143];
readonly royalblue: [65, 105, 225];
readonly saddlebrown: [139, 69, 19];
readonly salmon: [250, 128, 114];
readonly sandybrown: [244, 164, 96];
readonly seagreen: [46, 139, 87];
readonly seashell: [255, 245, 238];
readonly sienna: [160, 82, 45];
readonly silver: [192, 192, 192];
readonly skyblue: [135, 206, 235];
readonly slateblue: [106, 90, 205];
readonly slategray: [112, 128, 144];
readonly slategrey: [112, 128, 144];
readonly snow: [255, 250, 250];
readonly springgreen: [0, 255, 127];
readonly steelblue: [70, 130, 180];
readonly tan: [210, 180, 140];
readonly teal: [0, 128, 128];
readonly thistle: [216, 191, 216];
readonly tomato: [255, 99, 71];
readonly turquoise: [64, 224, 208];
readonly violet: [238, 130, 238];
readonly wheat: [245, 222, 179];
readonly white: [255, 255, 255];
readonly whitesmoke: [245, 245, 245];
readonly yellow: [255, 255, 0];
readonly yellowgreen: [154, 205, 50];
};
/**
* cache invalid color value
* @param key - cache key
* @param nullable - is nullable
* @returns cached value
*/
export declare const cacheInvalidColorValue: (cacheKey: string, format: string, nullable?: boolean) => SpecifiedColorChannels | string | NullObject;
/**
* resolve invalid color value
* @param format - output format
* @param nullable - is nullable
* @returns resolved value
*/
export declare const resolveInvalidColorValue: (format: string, nullable?: boolean) => SpecifiedColorChannels | string | NullObject;
/**
* validate color components
* @param arr - color components
* @param [opt] - options
* @param [opt.alpha] - alpha channel
* @param [opt.minLength] - min length
* @param [opt.maxLength] - max length
* @param [opt.minRange] - min range
* @param [opt.maxRange] - max range
* @param [opt.validateRange] - validate range
* @returns result - validated color components
*/
export declare const validateColorComponents: (arr: ColorChannels | TriColorChannels, opt?: {
alpha?: boolean;
minLength?: number;
maxLength?: number;
minRange?: number;
maxRange?: number;
validateRange?: boolean;
}) => ColorChannels | TriColorChannels;
/**
* transform matrix
* @param mtx - 3 * 3 matrix
* @param vct - vector
* @param [skip] - skip validate
* @returns TriColorChannels - [p1, p2, p3]
*/
export declare const transformMatrix: (mtx: ColorMatrix, vct: TriColorChannels, skip?: boolean) => TriColorChannels;
/**
* normalize color components
* @param colorA - color components [v1, v2, v3, v4]
* @param colorB - color components [v1, v2, v3, v4]
* @param [skip] - skip validate
* @returns result - [colorA, colorB]
*/
export declare const normalizeColorComponents: (colorA: [number | string, number | string, number | string, number | string], colorB: [number | string, number | string, number | string, number | string], skip?: boolean) => [ColorChannels, ColorChannels];
/**
* number to hex string
* @param value - numeric value
* @returns hex string
*/
export declare const numberToHexString: (value: number) => string;
/**
* angle to deg
* @param angle
* @returns deg: 0..360
*/
export declare const angleToDeg: (angle: string) => number;
/**
* parse alpha
* @param [alpha] - alpha value
* @returns alpha: 0..1
*/
export declare const parseAlpha: (alpha?: string) => number;
/**
* parse hex alpha
* @param value - alpha value in hex string
* @returns alpha: 0..1
*/
export declare const parseHexAlpha: (value: string) => number;
/**
* transform rgb to linear rgb
* @param rgb - [r, g, b] r|g|b: 0..255
* @param [skip] - skip validate
* @returns TriColorChannels - [r, g, b] r|g|b: 0..1
*/
export declare const transformRgbToLinearRgb: (rgb: TriColorChannels, skip?: boolean) => TriColorChannels;
/**
* transform rgb to xyz
* @param rgb - [r, g, b] r|g|b: 0..255
* @param [skip] - skip validate
* @returns TriColorChannels - [x, y, z]
*/
export declare const transformRgbToXyz: (rgb: TriColorChannels, skip?: boolean) => TriColorChannels;
/**
* transform rgb to xyz-d50
* @param rgb - [r, g, b] r|g|b: 0..255 alpha: 0..1
* @returns TriColorChannels - [x, y, z]
*/
export declare const transformRgbToXyzD50: (rgb: TriColorChannels) => TriColorChannels;
/**
* transform linear rgb to rgb
* @param rgb - [r, g, b] r|g|b: 0..1
* @param [round] - round result
* @returns TriColorChannels - [r, g, b] r|g|b: 0..255
*/
export declare const transformLinearRgbToRgb: (rgb: TriColorChannels, round?: boolean) => TriColorChannels;
/**
* transform xyz to rgb
* @param xyz - [x, y, z]
* @param [skip] - skip validate
* @returns TriColorChannels - [r, g, b] r|g|b: 0..255
*/
export declare const transformXyzToRgb: (xyz: TriColorChannels, skip?: boolean) => TriColorChannels;
/**
* transform xyz to xyz-d50
* @param xyz - [x, y, z]
* @returns TriColorChannels - [x, y, z]
*/
export declare const transformXyzToXyzD50: (xyz: TriColorChannels) => TriColorChannels;
/**
* transform xyz to hsl
* @param xyz - [x, y, z]
* @param [skip] - skip validate
* @returns TriColorChannels - [h, s, l]
*/
export declare const transformXyzToHsl: (xyz: TriColorChannels, skip?: boolean) => TriColorChannels;
/**
* transform xyz to hwb
* @param xyz - [x, y, z]
* @param [skip] - skip validate
* @returns TriColorChannels - [h, w, b]
*/
export declare const transformXyzToHwb: (xyz: TriColorChannels, skip?: boolean) => TriColorChannels;
/**
* transform xyz to oklab
* @param xyz - [x, y, z]
* @param [skip] - skip validate
* @returns TriColorChannels - [l, a, b]
*/
export declare const transformXyzToOklab: (xyz: TriColorChannels, skip?: boolean) => TriColorChannels;
/**
* transform xyz to oklch
* @param xyz - [x, y, z]
* @param [skip] - skip validate
* @returns TriColorChannels - [l, c, h]
*/
export declare const transformXyzToOklch: (xyz: TriColorChannels, skip?: boolean) => TriColorChannels;
/**
* transform xyz D50 to rgb
* @param xyz - [x, y, z]
* @param [skip] - skip validate
* @returns TriColorChannels - [r, g, b] r|g|b: 0..255
*/
export declare const transformXyzD50ToRgb: (xyz: TriColorChannels, skip?: boolean) => TriColorChannels;
/**
* transform xyz-d50 to lab
* @param xyz - [x, y, z]
* @param [skip] - skip validate
* @returns TriColorChannels - [l, a, b]
*/
export declare const transformXyzD50ToLab: (xyz: TriColorChannels, skip?: boolean) => TriColorChannels;
/**
* transform xyz-d50 to lch
* @param xyz - [x, y, z]
* @param [skip] - skip validate
* @returns TriColorChannels - [l, c, h]
*/
export declare const transformXyzD50ToLch: (xyz: TriColorChannels, skip?: boolean) => TriColorChannels;
/**
* convert rgb to hex color
* @param rgb - [r, g, b, alpha] r|g|b: 0..255 alpha: 0..1
* @returns hex color
*/
export declare const convertRgbToHex: (rgb: ColorChannels) => string;
/**
* convert linear rgb to hex color
* @param rgb - [r, g, b, alpha] r|g|b|alpha: 0..1
* @param [skip] - skip validate
* @returns hex color
*/
export declare const convertLinearRgbToHex: (rgb: ColorChannels, skip?: boolean) => string;
/**
* convert xyz to hex color
* @param xyz - [x, y, z, alpha]
* @returns hex color
*/
export declare const convertXyzToHex: (xyz: ColorChannels) => string;
/**
* convert xyz D50 to hex color
* @param xyz - [x, y, z, alpha]
* @returns hex color
*/
export declare const convertXyzD50ToHex: (xyz: ColorChannels) => string;
/**
* convert hex color to rgb
* @param value - hex color value
* @returns ColorChannels - [r, g, b, alpha] r|g|b: 0..255 alpha: 0..1
*/
export declare const convertHexToRgb: (value: string) => ColorChannels;
/**
* convert hex color to linear rgb
* @param value - hex color value
* @returns ColorChannels - [r, g, b, alpha] r|g|b|alpha: 0..1
*/
export declare const convertHexToLinearRgb: (value: string) => ColorChannels;
/**
* convert hex color to xyz
* @param value - hex color value
* @returns ColorChannels - [x, y, z, alpha]
*/
export declare const convertHexToXyz: (value: string) => ColorChannels;
/**
* parse rgb()
* @param value - rgb color value
* @param [opt] - options
* @returns parsed color - ['rgb', r, g, b, alpha], '(empty)', NullObject
*/
export declare const parseRgb: (value: string, opt?: Options) => SpecifiedColorChannels | string | NullObject;
/**
* parse hsl()
* @param value - hsl color value
* @param [opt] - options
* @returns parsed color - ['rgb', r, g, b, alpha], '(empty)', NullObject
*/
export declare const parseHsl: (value: string, opt?: Options) => SpecifiedColorChannels | string | NullObject;
/**
* parse hwb()
* @param value - hwb color value
* @param [opt] - options
* @returns parsed color - ['rgb', r, g, b, alpha], '(empty)', NullObject
*/
export declare const parseHwb: (value: string, opt?: Options) => SpecifiedColorChannels | string | NullObject;
/**
* parse lab()
* @param value - lab color value
* @param [opt] - options
* @returns parsed color
* - [xyz-d50, x, y, z, alpha], ['lab', l, a, b, alpha], '(empty)', NullObject
*/
export declare const parseLab: (value: string, opt?: Options) => SpecifiedColorChannels | string | NullObject;
/**
* parse lch()
* @param value - lch color value
* @param [opt] - options
* @returns parsed color
* - ['xyz-d50', x, y, z, alpha], ['lch', l, c, h, alpha]
* - '(empty)', NullObject
*/
export declare const parseLch: (value: string, opt?: Options) => SpecifiedColorChannels | string | NullObject;
/**
* parse oklab()
* @param value - oklab color value
* @param [opt] - options
* @returns parsed color
* - ['xyz-d65', x, y, z, alpha], ['oklab', l, a, b, alpha]
* - '(empty)', NullObject
*/
export declare const parseOklab: (value: string, opt?: Options) => SpecifiedColorChannels | string | NullObject;
/**
* parse oklch()
* @param value - oklch color value
* @param [opt] - options
* @returns parsed color
* - ['xyz-d65', x, y, z, alpha], ['oklch', l, c, h, alpha]
* - '(empty)', NullObject
*/
export declare const parseOklch: (value: string, opt?: Options) => SpecifiedColorChannels | string | NullObject;
/**
* parse color()
* @param value - color function value
* @param [opt] - options
* @returns parsed color
* - ['xyz-(d50|d65)', x, y, z, alpha], [cs, r, g, b, alpha]
* - '(empty)', NullObject
*/
export declare const parseColorFunc: (value: string, opt?: Options) => SpecifiedColorChannels | string | NullObject;
/**
* parse color value
* @param value - CSS color value
* @param [opt] - options
* @returns parsed color
* - ['xyz-(d50|d65)', x, y, z, alpha], ['rgb', r, g, b, alpha]
* - value, '(empty)', NullObject
*/
export declare const parseColorValue: (value: string, opt?: Options) => SpecifiedColorChannels | string | NullObject;
/**
* resolve color value
* @param value - CSS color value
* @param [opt] - options
* @returns resolved color
* - [cs, v1, v2, v3, alpha], value, '(empty)', NullObject
*/
export declare const resolveColorValue: (value: string, opt?: Options) => SpecifiedColorChannels | string | NullObject;
/**
* resolve color()
* @param value - color function value
* @param [opt] - options
* @returns resolved color - [cs, v1, v2, v3, alpha], '(empty)', NullObject
*/
export declare const resolveColorFunc: (value: string, opt?: Options) => SpecifiedColorChannels | string | NullObject;
/**
* convert color value to linear rgb
* @param value - CSS color value
* @param [opt] - options
* @returns ColorChannels | NullObject - [r, g, b, alpha] r|g|b|alpha: 0..1
*/
export declare const convertColorToLinearRgb: (value: string, opt?: {
colorSpace?: string;
format?: string;
}) => ColorChannels | NullObject;
/**
* convert color value to rgb
* @param value - CSS color value
* @param [opt] - options
* @returns ColorChannels | NullObject
* - [r, g, b, alpha] r|g|b: 0..255 alpha: 0..1
*/
export declare const convertColorToRgb: (value: string, opt?: Options) => ColorChannels | NullObject;
/**
* convert color value to xyz
* @param value - CSS color value
* @param [opt] - options
* @returns ColorChannels | NullObject - [x, y, z, alpha]
*/
export declare const convertColorToXyz: (value: string, opt?: Options) => ColorChannels | NullObject;
/**
* convert color value to hsl
* @param value - CSS color value
* @param [opt] - options
* @returns ColorChannels | NullObject - [h, s, l, alpha], hue may be powerless
*/
export declare const convertColorToHsl: (value: string, opt?: Options) => ColorChannels | [number | string, number, number, number] | NullObject;
/**
* convert color value to hwb
* @param value - CSS color value
* @param [opt] - options
* @returns ColorChannels | NullObject - [h, w, b, alpha], hue may be powerless
*/
export declare const convertColorToHwb: (value: string, opt?: Options) => ColorChannels | [number | string, number, number, number] | NullObject;
/**
* convert color value to lab
* @param value - CSS color value
* @param [opt] - options
* @returns ColorChannels | NullObject - [l, a, b, alpha]
*/
export declare const convertColorToLab: (value: string, opt?: Options) => ColorChannels | NullObject;
/**
* convert color value to lch
* @param value - CSS color value
* @param [opt] - options
* @returns ColorChannels | NullObject - [l, c, h, alpha], hue may be powerless
*/
export declare const convertColorToLch: (value: string, opt?: Options) => ColorChannels | [number, number, number | string, number] | NullObject;
/**
* convert color value to oklab
* @param value - CSS color value
* @param [opt] - options
* @returns ColorChannels | NullObject - [l, a, b, alpha]
*/
export declare const convertColorToOklab: (value: string, opt?: Options) => ColorChannels | NullObject;
/**
* convert color value to oklch
* @param value - CSS color value
* @param [opt] - options
* @returns ColorChannels | NullObject - [l, c, h, alpha], hue may be powerless
*/
export declare const convertColorToOklch: (value: string, opt?: Options) => ColorChannels | [number, number, number | string, number] | NullObject;
/**
* resolve color-mix()
* @param value - color-mix color value
* @param [opt] - options
* @returns resolved color - [cs, v1, v2, v3, alpha], '(empty)'
*/
export declare const resolveColorMix: (value: string, opt?: Options) => SpecifiedColorChannels | string | NullObject;
export {};

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,21 @@
/**
* common
*/
/**
* get type
* @param o - object to check
* @returns type of object
*/
export declare const getType: (o: unknown) => string;
/**
* is string
* @param o - object to check
* @returns result
*/
export declare const isString: (o: unknown) => o is string;
/**
* is string or number
* @param o - object to check
* @returns result
*/
export declare const isStringOrNumber: (o: unknown) => boolean;

View File

@@ -0,0 +1,7 @@
const isString = (o) => typeof o === "string" || o instanceof String;
const isStringOrNumber = (o) => isString(o) || typeof o === "number";
export {
isString,
isStringOrNumber
};
//# sourceMappingURL=common.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"common.js","sources":["../../../src/js/common.ts"],"sourcesContent":["/**\n * common\n */\n\n/* numeric constants */\nconst TYPE_FROM = 8;\nconst TYPE_TO = -1;\n\n/**\n * get type\n * @param o - object to check\n * @returns type of object\n */\nexport const getType = (o: unknown): string =>\n Object.prototype.toString.call(o).slice(TYPE_FROM, TYPE_TO);\n\n/**\n * is string\n * @param o - object to check\n * @returns result\n */\nexport const isString = (o: unknown): o is string =>\n typeof o === 'string' || o instanceof String;\n\n/**\n * is string or number\n * @param o - object to check\n * @returns result\n */\nexport const isStringOrNumber = (o: unknown): boolean =>\n isString(o) || typeof o === 'number';\n"],"names":[],"mappings":"AAqBO,MAAM,WAAW,CAAC,MACvB,OAAO,MAAM,YAAY,aAAa;AAOjC,MAAM,mBAAmB,CAAC,MAC/B,SAAS,CAAC,KAAK,OAAO,MAAM;"}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,101 @@
const _DIGIT = "(?:0|[1-9]\\d*)";
const _COMPARE = "clamp|max|min";
const _EXPO = "exp|hypot|log|pow|sqrt";
const _SIGN = "abs|sign";
const _STEP = "mod|rem|round";
const _TRIG = "a?(?:cos|sin|tan)|atan2";
const _MATH = `${_COMPARE}|${_EXPO}|${_SIGN}|${_STEP}|${_TRIG}`;
const _CALC = `calc|${_MATH}`;
const _VAR = `var|${_CALC}`;
const ANGLE = "deg|g?rad|turn";
const LENGTH = "[cm]m|[dls]?v(?:[bhiw]|max|min)|in|p[ctx]|q|r?(?:[cl]h|cap|e[mx]|ic)";
const NUM = `[+-]?(?:${_DIGIT}(?:\\.\\d*)?|\\.\\d+)(?:e-?${_DIGIT})?`;
const NUM_POSITIVE = `\\+?(?:${_DIGIT}(?:\\.\\d*)?|\\.\\d+)(?:e-?${_DIGIT})?`;
const NONE = "none";
const PCT = `${NUM}%`;
const SYN_FN_CALC = `^(?:${_CALC})\\(|(?<=[*\\/\\s\\(])(?:${_CALC})\\(`;
const SYN_FN_MATH_START = `^(?:${_MATH})\\($`;
const SYN_FN_VAR = "^var\\(|(?<=[*\\/\\s\\(])var\\(";
const SYN_FN_VAR_START = `^(?:${_VAR})\\(`;
const _ALPHA = `(?:\\s*\\/\\s*(?:${NUM}|${PCT}|${NONE}))?`;
const _ALPHA_LV3 = `(?:\\s*,\\s*(?:${NUM}|${PCT}))?`;
const _COLOR_FUNC = "(?:ok)?l(?:ab|ch)|color|hsla?|hwb|rgba?";
const _COLOR_KEY = "[a-z]+|#[\\da-f]{3}|#[\\da-f]{4}|#[\\da-f]{6}|#[\\da-f]{8}";
const _CS_HUE = "(?:ok)?lch|hsl|hwb";
const _CS_HUE_ARC = "(?:de|in)creasing|longer|shorter";
const _NUM_ANGLE = `${NUM}(?:${ANGLE})?`;
const _NUM_ANGLE_NONE = `(?:${NUM}(?:${ANGLE})?|${NONE})`;
const _NUM_PCT_NONE = `(?:${NUM}|${PCT}|${NONE})`;
const CS_HUE = `(?:${_CS_HUE})(?:\\s(?:${_CS_HUE_ARC})\\shue)?`;
const CS_HUE_CAPT = `(${_CS_HUE})(?:\\s(${_CS_HUE_ARC})\\shue)?`;
const CS_LAB = "(?:ok)?lab";
const CS_LCH = "(?:ok)?lch";
const CS_SRGB = "srgb(?:-linear)?";
const CS_RGB = `(?:a98|prophoto)-rgb|display-p3|rec2020|${CS_SRGB}`;
const CS_XYZ = "xyz(?:-d(?:50|65))?";
const CS_RECT = `${CS_LAB}|${CS_RGB}|${CS_XYZ}`;
const CS_MIX = `${CS_HUE}|${CS_RECT}`;
const FN_COLOR = "color(";
const FN_LIGHT_DARK = "light-dark(";
const FN_MIX = "color-mix(";
const FN_REL = `(?:${_COLOR_FUNC})\\(\\s*from\\s+`;
const FN_REL_CAPT = `(${_COLOR_FUNC})\\(\\s*from\\s+`;
const FN_VAR = "var(";
const SYN_FN_COLOR = `(?:${CS_RGB}|${CS_XYZ})(?:\\s+${_NUM_PCT_NONE}){3}${_ALPHA}`;
const SYN_FN_LIGHT_DARK = "^light-dark\\(";
const SYN_FN_REL = `^${FN_REL}|(?<=[\\s])${FN_REL}`;
const SYN_HSL = `${_NUM_ANGLE_NONE}(?:\\s+${_NUM_PCT_NONE}){2}${_ALPHA}`;
const SYN_HSL_LV3 = `${_NUM_ANGLE}(?:\\s*,\\s*${PCT}){2}${_ALPHA_LV3}`;
const SYN_LCH = `(?:${_NUM_PCT_NONE}\\s+){2}${_NUM_ANGLE_NONE}${_ALPHA}`;
const SYN_MOD = `${_NUM_PCT_NONE}(?:\\s+${_NUM_PCT_NONE}){2}${_ALPHA}`;
const SYN_RGB_LV3 = `(?:${NUM}(?:\\s*,\\s*${NUM}){2}|${PCT}(?:\\s*,\\s*${PCT}){2})${_ALPHA_LV3}`;
const SYN_COLOR_TYPE = `${_COLOR_KEY}|hsla?\\(\\s*${SYN_HSL_LV3}\\s*\\)|rgba?\\(\\s*${SYN_RGB_LV3}\\s*\\)|(?:hsla?|hwb)\\(\\s*${SYN_HSL}\\s*\\)|(?:(?:ok)?lab|rgba?)\\(\\s*${SYN_MOD}\\s*\\)|(?:ok)?lch\\(\\s*${SYN_LCH}\\s*\\)|color\\(\\s*${SYN_FN_COLOR}\\s*\\)`;
const SYN_MIX_PART = `(?:${SYN_COLOR_TYPE})(?:\\s+${PCT})?`;
const SYN_MIX = `color-mix\\(\\s*in\\s+(?:${CS_MIX})\\s*,\\s*${SYN_MIX_PART}\\s*,\\s*${SYN_MIX_PART}\\s*\\)`;
const SYN_MIX_CAPT = `color-mix\\(\\s*in\\s+(${CS_MIX})\\s*,\\s*(${SYN_MIX_PART})\\s*,\\s*(${SYN_MIX_PART})\\s*\\)`;
const VAL_COMP = "computedValue";
const VAL_MIX = "mixValue";
const VAL_SPEC = "specifiedValue";
export {
ANGLE,
CS_HUE,
CS_HUE_CAPT,
CS_LAB,
CS_LCH,
CS_MIX,
CS_RECT,
CS_RGB,
CS_SRGB,
CS_XYZ,
FN_COLOR,
FN_LIGHT_DARK,
FN_MIX,
FN_REL,
FN_REL_CAPT,
FN_VAR,
LENGTH,
NONE,
NUM,
NUM_POSITIVE,
PCT,
SYN_COLOR_TYPE,
SYN_FN_CALC,
SYN_FN_COLOR,
SYN_FN_LIGHT_DARK,
SYN_FN_MATH_START,
SYN_FN_REL,
SYN_FN_VAR,
SYN_FN_VAR_START,
SYN_HSL,
SYN_HSL_LV3,
SYN_LCH,
SYN_MIX,
SYN_MIX_CAPT,
SYN_MIX_PART,
SYN_MOD,
SYN_RGB_LV3,
VAL_COMP,
VAL_MIX,
VAL_SPEC
};
//# sourceMappingURL=constant.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,99 @@
import { NullObject } from './cache.js';
import { ColorChannels, Options } from './typedef.js';
/**
* pre process
* @param value - CSS color value
* @param [opt] - options
* @returns value
*/
export declare const preProcess: (value: string, opt?: Options) => string | NullObject;
/**
* convert number to hex string
* @param value - numeric value
* @returns hex string: 00..ff
*/
export declare const numberToHex: (value: number) => string;
/**
* convert color to hex
* @param value - CSS color value
* @param [opt] - options
* @param [opt.alpha] - enable alpha channel
* @returns #rrggbb | #rrggbbaa | null
*/
export declare const colorToHex: (value: string, opt?: Options) => string | null;
/**
* convert color to hsl
* @param value - CSS color value
* @param [opt] - options
* @returns ColorChannels - [h, s, l, alpha]
*/
export declare const colorToHsl: (value: string, opt?: Options) => ColorChannels;
/**
* convert color to hwb
* @param value - CSS color value
* @param [opt] - options
* @returns ColorChannels - [h, w, b, alpha]
*/
export declare const colorToHwb: (value: string, opt?: Options) => ColorChannels;
/**
* convert color to lab
* @param value - CSS color value
* @param [opt] - options
* @returns ColorChannels - [l, a, b, alpha]
*/
export declare const colorToLab: (value: string, opt?: Options) => ColorChannels;
/**
* convert color to lch
* @param value - CSS color value
* @param [opt] - options
* @returns ColorChannels - [l, c, h, alpha]
*/
export declare const colorToLch: (value: string, opt?: Options) => ColorChannels;
/**
* convert color to oklab
* @param value - CSS color value
* @param [opt] - options
* @returns ColorChannels - [l, a, b, alpha]
*/
export declare const colorToOklab: (value: string, opt?: Options) => ColorChannels;
/**
* convert color to oklch
* @param value - CSS color value
* @param [opt] - options
* @returns ColorChannels - [l, c, h, alpha]
*/
export declare const colorToOklch: (value: string, opt?: Options) => ColorChannels;
/**
* convert color to rgb
* @param value - CSS color value
* @param [opt] - options
* @returns ColorChannels - [r, g, b, alpha]
*/
export declare const colorToRgb: (value: string, opt?: Options) => ColorChannels;
/**
* convert color to xyz
* @param value - CSS color value
* @param [opt] - options
* @returns ColorChannels - [x, y, z, alpha]
*/
export declare const colorToXyz: (value: string, opt?: Options) => ColorChannels;
/**
* convert color to xyz-d50
* @param value - CSS color value
* @param [opt] - options
* @returns ColorChannels - [x, y, z, alpha]
*/
export declare const colorToXyzD50: (value: string, opt?: Options) => ColorChannels;
export declare const convert: {
colorToHex: (value: string, opt?: Options) => string | null;
colorToHsl: (value: string, opt?: Options) => ColorChannels;
colorToHwb: (value: string, opt?: Options) => ColorChannels;
colorToLab: (value: string, opt?: Options) => ColorChannels;
colorToLch: (value: string, opt?: Options) => ColorChannels;
colorToOklab: (value: string, opt?: Options) => ColorChannels;
colorToOklch: (value: string, opt?: Options) => ColorChannels;
colorToRgb: (value: string, opt?: Options) => ColorChannels;
colorToXyz: (value: string, opt?: Options) => ColorChannels;
colorToXyzD50: (value: string, opt?: Options) => ColorChannels;
numberToHex: (value: number) => string;
};

View File

@@ -0,0 +1,361 @@
import { NullObject, createCacheKey, getCache, CacheItem, setCache } from "./cache.js";
import { numberToHexString, parseColorFunc, parseColorValue, convertColorToRgb, convertColorToOklch, convertColorToOklab, convertColorToLch, convertColorToLab, convertColorToHwb, convertColorToHsl } from "./color.js";
import { isString } from "./common.js";
import { cssCalc } from "./css-calc.js";
import { resolveVar } from "./css-var.js";
import { resolveRelativeColor } from "./relative-color.js";
import { resolveColor } from "./resolve.js";
import { VAL_COMP, SYN_FN_VAR, SYN_FN_REL, SYN_FN_CALC } from "./constant.js";
const NAMESPACE = "convert";
const REG_FN_CALC = new RegExp(SYN_FN_CALC);
const REG_FN_REL = new RegExp(SYN_FN_REL);
const REG_FN_VAR = new RegExp(SYN_FN_VAR);
const preProcess = (value, opt = {}) => {
if (isString(value)) {
value = value.trim();
if (!value) {
return new NullObject();
}
} else {
return new NullObject();
}
const cacheKey = createCacheKey(
{
namespace: NAMESPACE,
name: "preProcess",
value
},
opt
);
const cachedResult = getCache(cacheKey);
if (cachedResult instanceof CacheItem) {
if (cachedResult.isNull) {
return cachedResult;
}
return cachedResult.item;
}
if (REG_FN_VAR.test(value)) {
const resolvedValue = resolveVar(value, opt);
if (isString(resolvedValue)) {
value = resolvedValue;
} else {
setCache(cacheKey, null);
return new NullObject();
}
}
if (REG_FN_REL.test(value)) {
const resolvedValue = resolveRelativeColor(value, opt);
if (isString(resolvedValue)) {
value = resolvedValue;
} else {
setCache(cacheKey, null);
return new NullObject();
}
} else if (REG_FN_CALC.test(value)) {
value = cssCalc(value, opt);
}
if (value.startsWith("color-mix")) {
const clonedOpt = structuredClone(opt);
clonedOpt.format = VAL_COMP;
clonedOpt.nullable = true;
const resolvedValue = resolveColor(value, clonedOpt);
setCache(cacheKey, resolvedValue);
return resolvedValue;
}
setCache(cacheKey, value);
return value;
};
const numberToHex = (value) => {
const hex = numberToHexString(value);
return hex;
};
const colorToHex = (value, opt = {}) => {
if (isString(value)) {
const resolvedValue = preProcess(value, opt);
if (resolvedValue instanceof NullObject) {
return null;
}
value = resolvedValue.toLowerCase();
} else {
throw new TypeError(`${value} is not a string.`);
}
const { alpha = false } = opt;
const cacheKey = createCacheKey(
{
namespace: NAMESPACE,
name: "colorToHex",
value
},
opt
);
const cachedResult = getCache(cacheKey);
if (cachedResult instanceof CacheItem) {
if (cachedResult.isNull) {
return null;
}
return cachedResult.item;
}
let hex;
opt.nullable = true;
if (alpha) {
opt.format = "hexAlpha";
hex = resolveColor(value, opt);
} else {
opt.format = "hex";
hex = resolveColor(value, opt);
}
if (isString(hex)) {
setCache(cacheKey, hex);
return hex;
}
setCache(cacheKey, null);
return null;
};
const colorToHsl = (value, opt = {}) => {
if (isString(value)) {
const resolvedValue = preProcess(value, opt);
if (resolvedValue instanceof NullObject) {
return [0, 0, 0, 0];
}
value = resolvedValue.toLowerCase();
} else {
throw new TypeError(`${value} is not a string.`);
}
const cacheKey = createCacheKey(
{
namespace: NAMESPACE,
name: "colorToHsl",
value
},
opt
);
const cachedResult = getCache(cacheKey);
if (cachedResult instanceof CacheItem) {
return cachedResult.item;
}
opt.format = "hsl";
const hsl = convertColorToHsl(value, opt);
setCache(cacheKey, hsl);
return hsl;
};
const colorToHwb = (value, opt = {}) => {
if (isString(value)) {
const resolvedValue = preProcess(value, opt);
if (resolvedValue instanceof NullObject) {
return [0, 0, 0, 0];
}
value = resolvedValue.toLowerCase();
} else {
throw new TypeError(`${value} is not a string.`);
}
const cacheKey = createCacheKey(
{
namespace: NAMESPACE,
name: "colorToHwb",
value
},
opt
);
const cachedResult = getCache(cacheKey);
if (cachedResult instanceof CacheItem) {
return cachedResult.item;
}
opt.format = "hwb";
const hwb = convertColorToHwb(value, opt);
setCache(cacheKey, hwb);
return hwb;
};
const colorToLab = (value, opt = {}) => {
if (isString(value)) {
const resolvedValue = preProcess(value, opt);
if (resolvedValue instanceof NullObject) {
return [0, 0, 0, 0];
}
value = resolvedValue.toLowerCase();
} else {
throw new TypeError(`${value} is not a string.`);
}
const cacheKey = createCacheKey(
{
namespace: NAMESPACE,
name: "colorToLab",
value
},
opt
);
const cachedResult = getCache(cacheKey);
if (cachedResult instanceof CacheItem) {
return cachedResult.item;
}
const lab = convertColorToLab(value, opt);
setCache(cacheKey, lab);
return lab;
};
const colorToLch = (value, opt = {}) => {
if (isString(value)) {
const resolvedValue = preProcess(value, opt);
if (resolvedValue instanceof NullObject) {
return [0, 0, 0, 0];
}
value = resolvedValue.toLowerCase();
} else {
throw new TypeError(`${value} is not a string.`);
}
const cacheKey = createCacheKey(
{
namespace: NAMESPACE,
name: "colorToLch",
value
},
opt
);
const cachedResult = getCache(cacheKey);
if (cachedResult instanceof CacheItem) {
return cachedResult.item;
}
const lch = convertColorToLch(value, opt);
setCache(cacheKey, lch);
return lch;
};
const colorToOklab = (value, opt = {}) => {
if (isString(value)) {
const resolvedValue = preProcess(value, opt);
if (resolvedValue instanceof NullObject) {
return [0, 0, 0, 0];
}
value = resolvedValue.toLowerCase();
} else {
throw new TypeError(`${value} is not a string.`);
}
const cacheKey = createCacheKey(
{
namespace: NAMESPACE,
name: "colorToOklab",
value
},
opt
);
const cachedResult = getCache(cacheKey);
if (cachedResult instanceof CacheItem) {
return cachedResult.item;
}
const lab = convertColorToOklab(value, opt);
setCache(cacheKey, lab);
return lab;
};
const colorToOklch = (value, opt = {}) => {
if (isString(value)) {
const resolvedValue = preProcess(value, opt);
if (resolvedValue instanceof NullObject) {
return [0, 0, 0, 0];
}
value = resolvedValue.toLowerCase();
} else {
throw new TypeError(`${value} is not a string.`);
}
const cacheKey = createCacheKey(
{
namespace: NAMESPACE,
name: "colorToOklch",
value
},
opt
);
const cachedResult = getCache(cacheKey);
if (cachedResult instanceof CacheItem) {
return cachedResult.item;
}
const lch = convertColorToOklch(value, opt);
setCache(cacheKey, lch);
return lch;
};
const colorToRgb = (value, opt = {}) => {
if (isString(value)) {
const resolvedValue = preProcess(value, opt);
if (resolvedValue instanceof NullObject) {
return [0, 0, 0, 0];
}
value = resolvedValue.toLowerCase();
} else {
throw new TypeError(`${value} is not a string.`);
}
const cacheKey = createCacheKey(
{
namespace: NAMESPACE,
name: "colorToRgb",
value
},
opt
);
const cachedResult = getCache(cacheKey);
if (cachedResult instanceof CacheItem) {
return cachedResult.item;
}
const rgb = convertColorToRgb(value, opt);
setCache(cacheKey, rgb);
return rgb;
};
const colorToXyz = (value, opt = {}) => {
if (isString(value)) {
const resolvedValue = preProcess(value, opt);
if (resolvedValue instanceof NullObject) {
return [0, 0, 0, 0];
}
value = resolvedValue.toLowerCase();
} else {
throw new TypeError(`${value} is not a string.`);
}
const cacheKey = createCacheKey(
{
namespace: NAMESPACE,
name: "colorToXyz",
value
},
opt
);
const cachedResult = getCache(cacheKey);
if (cachedResult instanceof CacheItem) {
return cachedResult.item;
}
let xyz;
if (value.startsWith("color(")) {
[, ...xyz] = parseColorFunc(value, opt);
} else {
[, ...xyz] = parseColorValue(value, opt);
}
setCache(cacheKey, xyz);
return xyz;
};
const colorToXyzD50 = (value, opt = {}) => {
opt.d50 = true;
return colorToXyz(value, opt);
};
const convert = {
colorToHex,
colorToHsl,
colorToHwb,
colorToLab,
colorToLch,
colorToOklab,
colorToOklch,
colorToRgb,
colorToXyz,
colorToXyzD50,
numberToHex
};
export {
colorToHex,
colorToHsl,
colorToHwb,
colorToLab,
colorToLch,
colorToOklab,
colorToOklch,
colorToRgb,
colorToXyz,
colorToXyzD50,
convert,
numberToHex,
preProcess
};
//# sourceMappingURL=convert.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,89 @@
import { CSSToken } from '@csstools/css-tokenizer';
import { NullObject } from './cache.js';
import { Options } from './typedef.js';
/**
* Calclator
*/
export declare class Calculator {
#private;
/**
* constructor
*/
constructor();
get hasNum(): boolean;
set hasNum(value: boolean);
get numSum(): number[];
get numMul(): number[];
get hasPct(): boolean;
set hasPct(value: boolean);
get pctSum(): number[];
get pctMul(): number[];
get hasDim(): boolean;
set hasDim(value: boolean);
get dimSum(): string[];
get dimSub(): string[];
get dimMul(): string[];
get dimDiv(): string[];
get hasEtc(): boolean;
set hasEtc(value: boolean);
get etcSum(): string[];
get etcSub(): string[];
get etcMul(): string[];
get etcDiv(): string[];
/**
* clear values
* @returns void
*/
clear(): void;
/**
* sort values
* @param values - values
* @returns sorted values
*/
sort(values?: string[]): string[];
/**
* multiply values
* @returns resolved value
*/
multiply(): string;
/**
* sum values
* @returns resolved value
*/
sum(): string;
}
/**
* sort calc values
* @param values - values to sort
* @param [finalize] - finalize values
* @returns sorted values
*/
export declare const sortCalcValues: (values?: (number | string)[], finalize?: boolean) => string;
/**
* serialize calc
* @param value - CSS value
* @param [opt] - options
* @returns serialized value
*/
export declare const serializeCalc: (value: string, opt?: Options) => string;
/**
* resolve dimension
* @param token - CSS token
* @param [opt] - options
* @returns resolved value
*/
export declare const resolveDimension: (token: CSSToken, opt?: Options) => string | NullObject;
/**
* parse tokens
* @param tokens - CSS tokens
* @param [opt] - options
* @returns parsed tokens
*/
export declare const parseTokens: (tokens: CSSToken[], opt?: Options) => string[];
/**
* CSS calc()
* @param value - CSS value including calc()
* @param [opt] - options
* @returns resolved value
*/
export declare const cssCalc: (value: string, opt?: Options) => string;

View File

@@ -0,0 +1,826 @@
import { calc } from "@csstools/css-calc";
import { TokenType, tokenize } from "@csstools/css-tokenizer";
import { createCacheKey, getCache, CacheItem, setCache, NullObject } from "./cache.js";
import { isString, isStringOrNumber } from "./common.js";
import { resolveVar } from "./css-var.js";
import { roundToPrecision, resolveLengthInPixels } from "./util.js";
import { VAL_SPEC, SYN_FN_VAR, SYN_FN_CALC, SYN_FN_VAR_START, NUM, ANGLE, LENGTH, SYN_FN_MATH_START } from "./constant.js";
const {
CloseParen: PAREN_CLOSE,
Comment: COMMENT,
Dimension: DIM,
EOF,
Function: FUNC,
OpenParen: PAREN_OPEN,
Whitespace: W_SPACE
} = TokenType;
const NAMESPACE = "css-calc";
const TRIA = 3;
const HEX = 16;
const MAX_PCT = 100;
const REG_FN_CALC = new RegExp(SYN_FN_CALC);
const REG_FN_CALC_NUM = new RegExp(`^calc\\((${NUM})\\)$`);
const REG_FN_MATH_START = new RegExp(SYN_FN_MATH_START);
const REG_FN_VAR = new RegExp(SYN_FN_VAR);
const REG_FN_VAR_START = new RegExp(SYN_FN_VAR_START);
const REG_OPERATOR = /\s[*+/-]\s/;
const REG_TYPE_DIM = new RegExp(`^(${NUM})(${ANGLE}|${LENGTH})$`);
const REG_TYPE_DIM_PCT = new RegExp(`^(${NUM})(${ANGLE}|${LENGTH}|%)$`);
const REG_TYPE_PCT = new RegExp(`^(${NUM})%$`);
class Calculator {
/* private */
// number
#hasNum;
#numSum;
#numMul;
// percentage
#hasPct;
#pctSum;
#pctMul;
// dimension
#hasDim;
#dimSum;
#dimSub;
#dimMul;
#dimDiv;
// et cetra
#hasEtc;
#etcSum;
#etcSub;
#etcMul;
#etcDiv;
/**
* constructor
*/
constructor() {
this.#hasNum = false;
this.#numSum = [];
this.#numMul = [];
this.#hasPct = false;
this.#pctSum = [];
this.#pctMul = [];
this.#hasDim = false;
this.#dimSum = [];
this.#dimSub = [];
this.#dimMul = [];
this.#dimDiv = [];
this.#hasEtc = false;
this.#etcSum = [];
this.#etcSub = [];
this.#etcMul = [];
this.#etcDiv = [];
}
get hasNum() {
return this.#hasNum;
}
set hasNum(value) {
this.#hasNum = !!value;
}
get numSum() {
return this.#numSum;
}
get numMul() {
return this.#numMul;
}
get hasPct() {
return this.#hasPct;
}
set hasPct(value) {
this.#hasPct = !!value;
}
get pctSum() {
return this.#pctSum;
}
get pctMul() {
return this.#pctMul;
}
get hasDim() {
return this.#hasDim;
}
set hasDim(value) {
this.#hasDim = !!value;
}
get dimSum() {
return this.#dimSum;
}
get dimSub() {
return this.#dimSub;
}
get dimMul() {
return this.#dimMul;
}
get dimDiv() {
return this.#dimDiv;
}
get hasEtc() {
return this.#hasEtc;
}
set hasEtc(value) {
this.#hasEtc = !!value;
}
get etcSum() {
return this.#etcSum;
}
get etcSub() {
return this.#etcSub;
}
get etcMul() {
return this.#etcMul;
}
get etcDiv() {
return this.#etcDiv;
}
/**
* clear values
* @returns void
*/
clear() {
this.#hasNum = false;
this.#numSum = [];
this.#numMul = [];
this.#hasPct = false;
this.#pctSum = [];
this.#pctMul = [];
this.#hasDim = false;
this.#dimSum = [];
this.#dimSub = [];
this.#dimMul = [];
this.#dimDiv = [];
this.#hasEtc = false;
this.#etcSum = [];
this.#etcSub = [];
this.#etcMul = [];
this.#etcDiv = [];
}
/**
* sort values
* @param values - values
* @returns sorted values
*/
sort(values = []) {
const arr = [...values];
if (arr.length > 1) {
arr.sort((a, b) => {
let res;
if (REG_TYPE_DIM_PCT.test(a) && REG_TYPE_DIM_PCT.test(b)) {
const [, valA, unitA] = a.match(REG_TYPE_DIM_PCT);
const [, valB, unitB] = b.match(REG_TYPE_DIM_PCT);
if (unitA === unitB) {
if (Number(valA) === Number(valB)) {
res = 0;
} else if (Number(valA) > Number(valB)) {
res = 1;
} else {
res = -1;
}
} else if (unitA > unitB) {
res = 1;
} else {
res = -1;
}
} else {
if (a === b) {
res = 0;
} else if (a > b) {
res = 1;
} else {
res = -1;
}
}
return res;
});
}
return arr;
}
/**
* multiply values
* @returns resolved value
*/
multiply() {
const value = [];
let num;
if (this.#hasNum) {
num = 1;
for (const i of this.#numMul) {
num *= i;
if (num === 0 || !Number.isFinite(num) || Number.isNaN(num)) {
break;
}
}
if (!this.#hasPct && !this.#hasDim && !this.hasEtc) {
if (Number.isFinite(num)) {
num = roundToPrecision(num, HEX);
}
value.push(num);
}
}
if (this.#hasPct) {
if (typeof num !== "number") {
num = 1;
}
for (const i of this.#pctMul) {
num *= i;
if (num === 0 || !Number.isFinite(num) || Number.isNaN(num)) {
break;
}
}
if (Number.isFinite(num)) {
num = `${roundToPrecision(num, HEX)}%`;
}
if (!this.#hasDim && !this.hasEtc) {
value.push(num);
}
}
if (this.#hasDim) {
let dim = "";
let mul = "";
let div = "";
if (this.#dimMul.length) {
if (this.#dimMul.length === 1) {
[mul] = this.#dimMul;
} else {
mul = `${this.sort(this.#dimMul).join(" * ")}`;
}
}
if (this.#dimDiv.length) {
if (this.#dimDiv.length === 1) {
[div] = this.#dimDiv;
} else {
div = `${this.sort(this.#dimDiv).join(" * ")}`;
}
}
if (Number.isFinite(num)) {
if (mul) {
if (div) {
if (div.includes("*")) {
dim = calc(`calc(${num} * ${mul} / (${div}))`, {
toCanonicalUnits: true
});
} else {
dim = calc(`calc(${num} * ${mul} / ${div})`, {
toCanonicalUnits: true
});
}
} else {
dim = calc(`calc(${num} * ${mul})`, {
toCanonicalUnits: true
});
}
} else if (div.includes("*")) {
dim = calc(`calc(${num} / (${div}))`, {
toCanonicalUnits: true
});
} else {
dim = calc(`calc(${num} / ${div})`, {
toCanonicalUnits: true
});
}
value.push(dim.replace(/^calc/, ""));
} else {
if (!value.length && num !== void 0) {
value.push(num);
}
if (mul) {
if (div) {
if (div.includes("*")) {
dim = calc(`calc(${mul} / (${div}))`, {
toCanonicalUnits: true
});
} else {
dim = calc(`calc(${mul} / ${div})`, {
toCanonicalUnits: true
});
}
} else {
dim = calc(`calc(${mul})`, {
toCanonicalUnits: true
});
}
if (value.length) {
value.push("*", dim.replace(/^calc/, ""));
} else {
value.push(dim.replace(/^calc/, ""));
}
} else {
dim = calc(`calc(${div})`, {
toCanonicalUnits: true
});
if (value.length) {
value.push("/", dim.replace(/^calc/, ""));
} else {
value.push("1", "/", dim.replace(/^calc/, ""));
}
}
}
}
if (this.#hasEtc) {
if (this.#etcMul.length) {
if (!value.length && num !== void 0) {
value.push(num);
}
const mul = this.sort(this.#etcMul).join(" * ");
if (value.length) {
value.push(`* ${mul}`);
} else {
value.push(`${mul}`);
}
}
if (this.#etcDiv.length) {
const div = this.sort(this.#etcDiv).join(" * ");
if (div.includes("*")) {
if (value.length) {
value.push(`/ (${div})`);
} else {
value.push(`1 / (${div})`);
}
} else if (value.length) {
value.push(`/ ${div}`);
} else {
value.push(`1 / ${div}`);
}
}
}
if (value.length) {
return value.join(" ");
}
return "";
}
/**
* sum values
* @returns resolved value
*/
sum() {
const value = [];
if (this.#hasNum) {
let num = 0;
for (const i of this.#numSum) {
num += i;
if (!Number.isFinite(num) || Number.isNaN(num)) {
break;
}
}
value.push(num);
}
if (this.#hasPct) {
let num = 0;
for (const i of this.#pctSum) {
num += i;
if (!Number.isFinite(num)) {
break;
}
}
if (Number.isFinite(num)) {
num = `${num}%`;
}
if (value.length) {
value.push(`+ ${num}`);
} else {
value.push(num);
}
}
if (this.#hasDim) {
let dim, sum, sub;
if (this.#dimSum.length) {
sum = this.sort(this.#dimSum).join(" + ");
}
if (this.#dimSub.length) {
sub = this.sort(this.#dimSub).join(" + ");
}
if (sum) {
if (sub) {
if (sub.includes("-")) {
dim = calc(`calc(${sum} - (${sub}))`, {
toCanonicalUnits: true
});
} else {
dim = calc(`calc(${sum} - ${sub})`, {
toCanonicalUnits: true
});
}
} else {
dim = calc(`calc(${sum})`, {
toCanonicalUnits: true
});
}
} else {
dim = calc(`calc(-1 * (${sub}))`, {
toCanonicalUnits: true
});
}
if (value.length) {
value.push("+", dim.replace(/^calc/, ""));
} else {
value.push(dim.replace(/^calc/, ""));
}
}
if (this.#hasEtc) {
if (this.#etcSum.length) {
const sum = this.sort(this.#etcSum).map((item) => {
let res;
if (REG_OPERATOR.test(item) && !item.startsWith("(") && !item.endsWith(")")) {
res = `(${item})`;
} else {
res = item;
}
return res;
}).join(" + ");
if (value.length) {
if (this.#etcSum.length > 1) {
value.push(`+ (${sum})`);
} else {
value.push(`+ ${sum}`);
}
} else {
value.push(`${sum}`);
}
}
if (this.#etcSub.length) {
const sub = this.sort(this.#etcSub).map((item) => {
let res;
if (REG_OPERATOR.test(item) && !item.startsWith("(") && !item.endsWith(")")) {
res = `(${item})`;
} else {
res = item;
}
return res;
}).join(" + ");
if (value.length) {
if (this.#etcSub.length > 1) {
value.push(`- (${sub})`);
} else {
value.push(`- ${sub}`);
}
} else if (this.#etcSub.length > 1) {
value.push(`-1 * (${sub})`);
} else {
value.push(`-1 * ${sub}`);
}
}
}
if (value.length) {
return value.join(" ");
}
return "";
}
}
const sortCalcValues = (values = [], finalize = false) => {
if (values.length < TRIA) {
throw new Error(`Unexpected array length ${values.length}.`);
}
const start = values.shift();
if (!isString(start) || !start.endsWith("(")) {
throw new Error(`Unexpected token ${start}.`);
}
const end = values.pop();
if (end !== ")") {
throw new Error(`Unexpected token ${end}.`);
}
if (values.length === 1) {
const [value] = values;
if (!isStringOrNumber(value)) {
throw new Error(`Unexpected token ${value}.`);
}
return `${start}${value}${end}`;
}
const sortedValues = [];
const cal = new Calculator();
let operator = "";
const l = values.length;
for (let i = 0; i < l; i++) {
const value = values[i];
if (!isStringOrNumber(value)) {
throw new Error(`Unexpected token ${value}.`);
}
if (value === "*" || value === "/") {
operator = value;
} else if (value === "+" || value === "-") {
const sortedValue = cal.multiply();
if (sortedValue) {
sortedValues.push(sortedValue, value);
}
cal.clear();
operator = "";
} else {
const numValue = Number(value);
const strValue = `${value}`;
switch (operator) {
case "/": {
if (Number.isFinite(numValue)) {
cal.hasNum = true;
cal.numMul.push(1 / numValue);
} else if (REG_TYPE_PCT.test(strValue)) {
const [, val] = strValue.match(REG_TYPE_PCT);
cal.hasPct = true;
cal.pctMul.push(MAX_PCT * MAX_PCT / Number(val));
} else if (REG_TYPE_DIM.test(strValue)) {
cal.hasDim = true;
cal.dimDiv.push(strValue);
} else {
cal.hasEtc = true;
cal.etcDiv.push(strValue);
}
break;
}
case "*":
default: {
if (Number.isFinite(numValue)) {
cal.hasNum = true;
cal.numMul.push(numValue);
} else if (REG_TYPE_PCT.test(strValue)) {
const [, val] = strValue.match(REG_TYPE_PCT);
cal.hasPct = true;
cal.pctMul.push(Number(val));
} else if (REG_TYPE_DIM.test(strValue)) {
cal.hasDim = true;
cal.dimMul.push(strValue);
} else {
cal.hasEtc = true;
cal.etcMul.push(strValue);
}
}
}
}
if (i === l - 1) {
const sortedValue = cal.multiply();
if (sortedValue) {
sortedValues.push(sortedValue);
}
cal.clear();
operator = "";
}
}
let resolvedValue = "";
if (finalize && (sortedValues.includes("+") || sortedValues.includes("-"))) {
const finalizedValues = [];
cal.clear();
operator = "";
const l2 = sortedValues.length;
for (let i = 0; i < l2; i++) {
const value = sortedValues[i];
if (isStringOrNumber(value)) {
if (value === "+" || value === "-") {
operator = value;
} else {
const numValue = Number(value);
const strValue = `${value}`;
switch (operator) {
case "-": {
if (Number.isFinite(numValue)) {
cal.hasNum = true;
cal.numSum.push(-1 * numValue);
} else if (REG_TYPE_PCT.test(strValue)) {
const [, val] = strValue.match(REG_TYPE_PCT);
cal.hasPct = true;
cal.pctSum.push(-1 * Number(val));
} else if (REG_TYPE_DIM.test(strValue)) {
cal.hasDim = true;
cal.dimSub.push(strValue);
} else {
cal.hasEtc = true;
cal.etcSub.push(strValue);
}
break;
}
case "+":
default: {
if (Number.isFinite(numValue)) {
cal.hasNum = true;
cal.numSum.push(numValue);
} else if (REG_TYPE_PCT.test(strValue)) {
const [, val] = strValue.match(REG_TYPE_PCT);
cal.hasPct = true;
cal.pctSum.push(Number(val));
} else if (REG_TYPE_DIM.test(strValue)) {
cal.hasDim = true;
cal.dimSum.push(strValue);
} else {
cal.hasEtc = true;
cal.etcSum.push(strValue);
}
}
}
}
}
if (i === l2 - 1) {
const sortedValue = cal.sum();
if (sortedValue) {
finalizedValues.push(sortedValue);
}
cal.clear();
operator = "";
}
}
resolvedValue = finalizedValues.join(" ").replace(/\+\s-/g, "- ");
} else {
resolvedValue = sortedValues.join(" ").replace(/\+\s-/g, "- ");
}
if (resolvedValue.startsWith("(") && resolvedValue.endsWith(")") && resolvedValue.lastIndexOf("(") === 0 && resolvedValue.indexOf(")") === resolvedValue.length - 1) {
resolvedValue = resolvedValue.replace(/^\(/, "").replace(/\)$/, "");
}
return `${start}${resolvedValue}${end}`;
};
const serializeCalc = (value, opt = {}) => {
const { format = "" } = opt;
if (isString(value)) {
if (!REG_FN_VAR_START.test(value) || format !== VAL_SPEC) {
return value;
}
value = value.toLowerCase().trim();
} else {
throw new TypeError(`${value} is not a string.`);
}
const cacheKey = createCacheKey(
{
namespace: NAMESPACE,
name: "serializeCalc",
value
},
opt
);
const cachedResult = getCache(cacheKey);
if (cachedResult instanceof CacheItem) {
return cachedResult.item;
}
const items = tokenize({ css: value }).map((token) => {
const [type, value2] = token;
let res = "";
if (type !== W_SPACE && type !== COMMENT) {
res = value2;
}
return res;
}).filter((v) => v);
let startIndex = items.findLastIndex((item) => /\($/.test(item));
while (startIndex) {
const endIndex = items.findIndex((item, index) => {
return item === ")" && index > startIndex;
});
const slicedValues = items.slice(startIndex, endIndex + 1);
let serializedValue = sortCalcValues(slicedValues);
if (REG_FN_VAR_START.test(serializedValue)) {
serializedValue = calc(serializedValue, {
toCanonicalUnits: true
});
}
items.splice(startIndex, endIndex - startIndex + 1, serializedValue);
startIndex = items.findLastIndex((item) => /\($/.test(item));
}
const serializedCalc = sortCalcValues(items, true);
setCache(cacheKey, serializedCalc);
return serializedCalc;
};
const resolveDimension = (token, opt = {}) => {
if (!Array.isArray(token)) {
throw new TypeError(`${token} is not an array.`);
}
const [, , , , detail = {}] = token;
const { unit, value } = detail;
if (unit === "px") {
return `${value}${unit}`;
}
const pixelValue = resolveLengthInPixels(Number(value), unit, opt);
if (Number.isFinite(pixelValue)) {
return `${roundToPrecision(pixelValue, HEX)}px`;
}
return new NullObject();
};
const parseTokens = (tokens, opt = {}) => {
if (!Array.isArray(tokens)) {
throw new TypeError(`${tokens} is not an array.`);
}
const { format = "" } = opt;
const mathFunc = /* @__PURE__ */ new Set();
let nest = 0;
const res = [];
while (tokens.length) {
const token = tokens.shift();
if (!Array.isArray(token)) {
throw new TypeError(`${token} is not an array.`);
}
const [type = "", value = ""] = token;
switch (type) {
case DIM: {
if (format === VAL_SPEC && !mathFunc.has(nest)) {
res.push(value);
} else {
const resolvedValue = resolveDimension(token, opt);
if (isString(resolvedValue)) {
res.push(resolvedValue);
} else {
res.push(value);
}
}
break;
}
case FUNC:
case PAREN_OPEN: {
res.push(value);
nest++;
if (REG_FN_MATH_START.test(value)) {
mathFunc.add(nest);
}
break;
}
case PAREN_CLOSE: {
if (res.length) {
const lastValue = res[res.length - 1];
if (lastValue === " ") {
res.splice(-1, 1, value);
} else {
res.push(value);
}
} else {
res.push(value);
}
if (mathFunc.has(nest)) {
mathFunc.delete(nest);
}
nest--;
break;
}
case W_SPACE: {
if (res.length) {
const lastValue = res[res.length - 1];
if (isString(lastValue) && !lastValue.endsWith("(") && lastValue !== " ") {
res.push(value);
}
}
break;
}
default: {
if (type !== COMMENT && type !== EOF) {
res.push(value);
}
}
}
}
return res;
};
const cssCalc = (value, opt = {}) => {
const { format = "" } = opt;
if (isString(value)) {
if (REG_FN_VAR.test(value)) {
if (format === VAL_SPEC) {
return value;
} else {
const resolvedValue2 = resolveVar(value, opt);
if (isString(resolvedValue2)) {
return resolvedValue2;
} else {
return "";
}
}
} else if (!REG_FN_CALC.test(value)) {
return value;
}
value = value.toLowerCase().trim();
} else {
throw new TypeError(`${value} is not a string.`);
}
const cacheKey = createCacheKey(
{
namespace: NAMESPACE,
name: "cssCalc",
value
},
opt
);
const cachedResult = getCache(cacheKey);
if (cachedResult instanceof CacheItem) {
return cachedResult.item;
}
const tokens = tokenize({ css: value });
const values = parseTokens(tokens, opt);
let resolvedValue = calc(values.join(""), {
toCanonicalUnits: true
});
if (REG_FN_VAR_START.test(value)) {
if (REG_TYPE_DIM_PCT.test(resolvedValue)) {
const [, val, unit] = resolvedValue.match(
REG_TYPE_DIM_PCT
);
resolvedValue = `${roundToPrecision(Number(val), HEX)}${unit}`;
}
if (resolvedValue && !REG_FN_VAR_START.test(resolvedValue) && format === VAL_SPEC) {
resolvedValue = `calc(${resolvedValue})`;
}
}
if (format === VAL_SPEC) {
if (/\s[-+*/]\s/.test(resolvedValue) && !resolvedValue.includes("NaN")) {
resolvedValue = serializeCalc(resolvedValue, opt);
} else if (REG_FN_CALC_NUM.test(resolvedValue)) {
const [, val] = resolvedValue.match(REG_FN_CALC_NUM);
resolvedValue = `calc(${roundToPrecision(Number(val), HEX)})`;
}
}
setCache(cacheKey, resolvedValue);
return resolvedValue;
};
export {
Calculator,
cssCalc,
parseTokens,
resolveDimension,
serializeCalc,
sortCalcValues
};
//# sourceMappingURL=css-calc.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,79 @@
import { Options } from './typedef.js';
/**
* @type ColorStopList - list of color stops
*/
type ColorStopList = [string, string, ...string[]];
/**
* @typedef ValidateGradientLine - validate gradient line
* @property line - gradient line
* @property valid - result
*/
interface ValidateGradientLine {
line: string;
valid: boolean;
}
/**
* @typedef ValidateColorStops - validate color stops
* @property colorStops - list of color stops
* @property valid - result
*/
interface ValidateColorStops {
colorStops: string[];
valid: boolean;
}
/**
* @typedef Gradient - parsed CSS gradient
* @property value - input value
* @property type - gradient type
* @property [gradientLine] - gradient line
* @property colorStopList - list of color stops
*/
interface Gradient {
value: string;
type: string;
gradientLine?: string;
colorStopList: ColorStopList;
}
/**
* get gradient type
* @param value - gradient value
* @returns gradient type
*/
export declare const getGradientType: (value: string) => string;
/**
* validate gradient line
* @param value - gradient line value
* @param type - gradient type
* @returns result
*/
export declare const validateGradientLine: (value: string, type: string) => ValidateGradientLine;
/**
* validate color stop list
* @param list
* @param type
* @param [opt]
* @returns result
*/
export declare const validateColorStopList: (list: string[], type: string, opt?: Options) => ValidateColorStops;
/**
* parse CSS gradient
* @param value - gradient value
* @param [opt] - options
* @returns parsed result
*/
export declare const parseGradient: (value: string, opt?: Options) => Gradient | null;
/**
* resolve CSS gradient
* @param value - CSS value
* @param [opt] - options
* @returns result
*/
export declare const resolveGradient: (value: string, opt?: Options) => string;
/**
* is CSS gradient
* @param value - CSS value
* @param [opt] - options
* @returns result
*/
export declare const isGradient: (value: string, opt?: Options) => boolean;
export {};

View File

@@ -0,0 +1,261 @@
import { createCacheKey, getCache, CacheItem, setCache } from "./cache.js";
import { resolveColor } from "./resolve.js";
import { isString } from "./common.js";
import { splitValue, isColor } from "./util.js";
import { VAL_COMP, VAL_SPEC, NUM, ANGLE, PCT, LENGTH, CS_RECT, CS_HUE, NUM_POSITIVE } from "./constant.js";
const NAMESPACE = "css-gradient";
const DIM_ANGLE = `${NUM}(?:${ANGLE})`;
const DIM_ANGLE_PCT = `${DIM_ANGLE}|${PCT}`;
const DIM_LEN = `${NUM}(?:${LENGTH})|0`;
const DIM_LEN_PCT = `${DIM_LEN}|${PCT}`;
const DIM_LEN_PCT_POSI = `${NUM_POSITIVE}(?:${LENGTH}|%)|0`;
const DIM_LEN_POSI = `${NUM_POSITIVE}(?:${LENGTH})|0`;
const CTR = "center";
const L_R = "left|right";
const T_B = "top|bottom";
const S_E = "start|end";
const AXIS_X = `${L_R}|x-(?:${S_E})`;
const AXIS_Y = `${T_B}|y-(?:${S_E})`;
const BLOCK = `block-(?:${S_E})`;
const INLINE = `inline-(?:${S_E})`;
const POS_1 = `${CTR}|${AXIS_X}|${AXIS_Y}|${BLOCK}|${INLINE}|${DIM_LEN_PCT}`;
const POS_2 = [
`(?:${CTR}|${AXIS_X})\\s+(?:${CTR}|${AXIS_Y})`,
`(?:${CTR}|${AXIS_Y})\\s+(?:${CTR}|${AXIS_X})`,
`(?:${CTR}|${AXIS_X}|${DIM_LEN_PCT})\\s+(?:${CTR}|${AXIS_Y}|${DIM_LEN_PCT})`,
`(?:${CTR}|${BLOCK})\\s+(?:${CTR}|${INLINE})`,
`(?:${CTR}|${INLINE})\\s+(?:${CTR}|${BLOCK})`,
`(?:${CTR}|${S_E})\\s+(?:${CTR}|${S_E})`
].join("|");
const POS_4 = [
`(?:${AXIS_X})\\s+(?:${DIM_LEN_PCT})\\s+(?:${AXIS_Y})\\s+(?:${DIM_LEN_PCT})`,
`(?:${AXIS_Y})\\s+(?:${DIM_LEN_PCT})\\s+(?:${AXIS_X})\\s+(?:${DIM_LEN_PCT})`,
`(?:${BLOCK})\\s+(?:${DIM_LEN_PCT})\\s+(?:${INLINE})\\s+(?:${DIM_LEN_PCT})`,
`(?:${INLINE})\\s+(?:${DIM_LEN_PCT})\\s+(?:${BLOCK})\\s+(?:${DIM_LEN_PCT})`,
`(?:${S_E})\\s+(?:${DIM_LEN_PCT})\\s+(?:${S_E})\\s+(?:${DIM_LEN_PCT})`
].join("|");
const RAD_EXTENT = "(?:clos|farth)est-(?:corner|side)";
const RAD_SIZE = [
`${RAD_EXTENT}(?:\\s+${RAD_EXTENT})?`,
`${DIM_LEN_POSI}`,
`(?:${DIM_LEN_PCT_POSI})\\s+(?:${DIM_LEN_PCT_POSI})`
].join("|");
const RAD_SHAPE = "circle|ellipse";
const FROM_ANGLE = `from\\s+${DIM_ANGLE}`;
const AT_POSITION = `at\\s+(?:${POS_1}|${POS_2}|${POS_4})`;
const TO_SIDE_CORNER = `to\\s+(?:(?:${L_R})(?:\\s(?:${T_B}))?|(?:${T_B})(?:\\s(?:${L_R}))?)`;
const IN_COLOR_SPACE = `in\\s+(?:${CS_RECT}|${CS_HUE})`;
const REG_GRAD = /^(?:repeating-)?(?:conic|linear|radial)-gradient\(/;
const REG_GRAD_CAPT = /^((?:repeating-)?(?:conic|linear|radial)-gradient)\(/;
const getGradientType = (value) => {
if (isString(value)) {
value = value.trim();
if (REG_GRAD.test(value)) {
const [, type] = value.match(REG_GRAD_CAPT);
return type;
}
}
return "";
};
const validateGradientLine = (value, type) => {
if (isString(value) && isString(type)) {
value = value.trim();
type = type.trim();
let lineSyntax = "";
const defaultValues = [];
if (/^(?:repeating-)?linear-gradient$/.test(type)) {
lineSyntax = [
`(?:${DIM_ANGLE}|${TO_SIDE_CORNER})(?:\\s+${IN_COLOR_SPACE})?`,
`${IN_COLOR_SPACE}(?:\\s+(?:${DIM_ANGLE}|${TO_SIDE_CORNER}))?`
].join("|");
defaultValues.push(/to\s+bottom/);
} else if (/^(?:repeating-)?radial-gradient$/.test(type)) {
lineSyntax = [
`(?:${RAD_SHAPE})(?:\\s+(?:${RAD_SIZE}))?(?:\\s+${AT_POSITION})?(?:\\s+${IN_COLOR_SPACE})?`,
`(?:${RAD_SIZE})(?:\\s+(?:${RAD_SHAPE}))?(?:\\s+${AT_POSITION})?(?:\\s+${IN_COLOR_SPACE})?`,
`${AT_POSITION}(?:\\s+${IN_COLOR_SPACE})?`,
`${IN_COLOR_SPACE}(?:\\s+${RAD_SHAPE})(?:\\s+(?:${RAD_SIZE}))?(?:\\s+${AT_POSITION})?`,
`${IN_COLOR_SPACE}(?:\\s+${RAD_SIZE})(?:\\s+(?:${RAD_SHAPE}))?(?:\\s+${AT_POSITION})?`,
`${IN_COLOR_SPACE}(?:\\s+${AT_POSITION})?`
].join("|");
defaultValues.push(/ellipse/, /farthest-corner/, /at\s+center/);
} else if (/^(?:repeating-)?conic-gradient$/.test(type)) {
lineSyntax = [
`${FROM_ANGLE}(?:\\s+${AT_POSITION})?(?:\\s+${IN_COLOR_SPACE})?`,
`${AT_POSITION}(?:\\s+${IN_COLOR_SPACE})?`,
`${IN_COLOR_SPACE}(?:\\s+${FROM_ANGLE})?(?:\\s+${AT_POSITION})?`
].join("|");
defaultValues.push(/at\s+center/);
}
if (lineSyntax) {
const reg = new RegExp(`^(?:${lineSyntax})$`);
const valid = reg.test(value);
if (valid) {
let line = value;
for (const defaultValue of defaultValues) {
line = line.replace(defaultValue, "");
}
line = line.replace(/\s{2,}/g, " ").trim();
return {
line,
valid
};
}
return {
valid,
line: value
};
}
}
return {
line: value,
valid: false
};
};
const validateColorStopList = (list, type, opt = {}) => {
if (Array.isArray(list) && list.length > 1) {
const dimension = /^(?:repeating-)?conic-gradient$/.test(type) ? DIM_ANGLE_PCT : DIM_LEN_PCT;
const regColorHint = new RegExp(`^(?:${dimension})$`);
const regDimension = new RegExp(`(?:\\s+(?:${dimension})){1,2}$`);
const valueTypes = [];
const valueList = [];
for (const item of list) {
if (isString(item)) {
if (regColorHint.test(item)) {
valueTypes.push("hint");
valueList.push(item);
} else {
const itemColor = item.replace(regDimension, "");
if (isColor(itemColor, { format: VAL_SPEC })) {
const resolvedColor = resolveColor(itemColor, opt);
valueTypes.push("color");
valueList.push(item.replace(itemColor, resolvedColor));
} else {
return {
colorStops: list,
valid: false
};
}
}
}
}
const valid = /^color(?:,(?:hint,)?color)+$/.test(valueTypes.join(","));
return {
valid,
colorStops: valueList
};
}
return {
colorStops: list,
valid: false
};
};
const parseGradient = (value, opt = {}) => {
if (isString(value)) {
value = value.trim();
const cacheKey = createCacheKey(
{
namespace: NAMESPACE,
name: "parseGradient",
value
},
opt
);
const cachedResult = getCache(cacheKey);
if (cachedResult instanceof CacheItem) {
if (cachedResult.isNull) {
return null;
}
return cachedResult.item;
}
const type = getGradientType(value);
const gradValue = value.replace(REG_GRAD, "").replace(/\)$/, "");
if (type && gradValue) {
const [lineOrColorStop = "", ...itemList] = splitValue(gradValue, {
delimiter: ","
});
const dimension = /^(?:repeating-)?conic-gradient$/.test(type) ? DIM_ANGLE_PCT : DIM_LEN_PCT;
const regDimension = new RegExp(`(?:\\s+(?:${dimension})){1,2}$`);
let colorStop = "";
if (regDimension.test(lineOrColorStop)) {
const itemColor = lineOrColorStop.replace(regDimension, "");
if (isColor(itemColor, { format: VAL_SPEC })) {
const resolvedColor = resolveColor(itemColor, opt);
colorStop = lineOrColorStop.replace(itemColor, resolvedColor);
}
} else if (isColor(lineOrColorStop, { format: VAL_SPEC })) {
colorStop = resolveColor(lineOrColorStop, opt);
}
if (colorStop) {
itemList.unshift(colorStop);
const { colorStops, valid } = validateColorStopList(
itemList,
type,
opt
);
if (valid) {
const res = {
value,
type,
colorStopList: colorStops
};
setCache(cacheKey, res);
return res;
}
} else if (itemList.length > 1) {
const { line: gradientLine, valid: validLine } = validateGradientLine(
lineOrColorStop,
type
);
const { colorStops, valid: validColorStops } = validateColorStopList(
itemList,
type,
opt
);
if (validLine && validColorStops) {
const res = {
value,
type,
gradientLine,
colorStopList: colorStops
};
setCache(cacheKey, res);
return res;
}
}
}
setCache(cacheKey, null);
return null;
}
return null;
};
const resolveGradient = (value, opt = {}) => {
const { format = VAL_COMP } = opt;
const gradient = parseGradient(value, opt);
if (gradient) {
const { type = "", gradientLine = "", colorStopList = [] } = gradient;
if (type && Array.isArray(colorStopList) && colorStopList.length > 1) {
if (gradientLine) {
return `${type}(${gradientLine}, ${colorStopList.join(", ")})`;
}
return `${type}(${colorStopList.join(", ")})`;
}
}
if (format === VAL_SPEC) {
return "";
}
return "none";
};
const isGradient = (value, opt = {}) => {
const gradient = parseGradient(value, opt);
return gradient !== null;
};
export {
getGradientType,
isGradient,
parseGradient,
resolveGradient,
validateColorStopList,
validateGradientLine
};
//# sourceMappingURL=css-gradient.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,31 @@
import { CSSToken } from '@csstools/css-tokenizer';
import { NullObject } from './cache.js';
import { Options } from './typedef.js';
/**
* resolve custom property
* @param tokens - CSS tokens
* @param [opt] - options
* @returns result - [tokens, resolvedValue]
*/
export declare function resolveCustomProperty(tokens: CSSToken[], opt?: Options): [CSSToken[], string];
/**
* parse tokens
* @param tokens - CSS tokens
* @param [opt] - options
* @returns parsed tokens
*/
export declare function parseTokens(tokens: CSSToken[], opt?: Options): string[] | NullObject;
/**
* resolve CSS var()
* @param value - CSS value including var()
* @param [opt] - options
* @returns resolved value
*/
export declare function resolveVar(value: string, opt?: Options): string | NullObject;
/**
* CSS var()
* @param value - CSS value including var()
* @param [opt] - options
* @returns resolved value
*/
export declare const cssVar: (value: string, opt?: Options) => string;

View File

@@ -0,0 +1,195 @@
import { TokenType, tokenize } from "@csstools/css-tokenizer";
import { createCacheKey, getCache, CacheItem, setCache, NullObject } from "./cache.js";
import { isString } from "./common.js";
import { cssCalc } from "./css-calc.js";
import { isColor } from "./util.js";
import { VAL_SPEC, SYN_FN_VAR, FN_VAR, SYN_FN_CALC } from "./constant.js";
const {
CloseParen: PAREN_CLOSE,
Comment: COMMENT,
EOF,
Ident: IDENT,
Whitespace: W_SPACE
} = TokenType;
const NAMESPACE = "css-var";
const REG_FN_CALC = new RegExp(SYN_FN_CALC);
const REG_FN_VAR = new RegExp(SYN_FN_VAR);
function resolveCustomProperty(tokens, opt = {}) {
if (!Array.isArray(tokens)) {
throw new TypeError(`${tokens} is not an array.`);
}
const { customProperty = {} } = opt;
const items = [];
while (tokens.length) {
const token = tokens.shift();
if (!Array.isArray(token)) {
throw new TypeError(`${token} is not an array.`);
}
const [type, value] = token;
if (type === PAREN_CLOSE) {
break;
}
if (value === FN_VAR) {
const [restTokens, item] = resolveCustomProperty(tokens, opt);
tokens = restTokens;
if (item) {
items.push(item);
}
} else if (type === IDENT) {
if (value.startsWith("--")) {
let item;
if (Object.hasOwn(customProperty, value)) {
item = customProperty[value];
} else if (typeof customProperty.callback === "function") {
item = customProperty.callback(value);
}
if (item) {
items.push(item);
}
} else if (value) {
items.push(value);
}
}
}
let resolveAsColor = false;
if (items.length > 1) {
const lastValue = items[items.length - 1];
resolveAsColor = isColor(lastValue);
}
let resolvedValue = "";
for (let item of items) {
item = item.trim();
if (REG_FN_VAR.test(item)) {
const resolvedItem = resolveVar(item, opt);
if (isString(resolvedItem)) {
if (resolveAsColor) {
if (isColor(resolvedItem)) {
resolvedValue = resolvedItem;
}
} else {
resolvedValue = resolvedItem;
}
}
} else if (REG_FN_CALC.test(item)) {
item = cssCalc(item, opt);
if (resolveAsColor) {
if (isColor(item)) {
resolvedValue = item;
}
} else {
resolvedValue = item;
}
} else if (item && !/^(?:inherit|initial|revert(?:-layer)?|unset)$/.test(item)) {
if (resolveAsColor) {
if (isColor(item)) {
resolvedValue = item;
}
} else {
resolvedValue = item;
}
}
if (resolvedValue) {
break;
}
}
return [tokens, resolvedValue];
}
function parseTokens(tokens, opt = {}) {
const res = [];
while (tokens.length) {
const token = tokens.shift();
const [type = "", value = ""] = token;
if (value === FN_VAR) {
const [restTokens, resolvedValue] = resolveCustomProperty(tokens, opt);
if (!resolvedValue) {
return new NullObject();
}
tokens = restTokens;
res.push(resolvedValue);
} else {
switch (type) {
case PAREN_CLOSE: {
if (res.length) {
const lastValue = res[res.length - 1];
if (lastValue === " ") {
res.splice(-1, 1, value);
} else {
res.push(value);
}
} else {
res.push(value);
}
break;
}
case W_SPACE: {
if (res.length) {
const lastValue = res[res.length - 1];
if (isString(lastValue) && !lastValue.endsWith("(") && lastValue !== " ") {
res.push(value);
}
}
break;
}
default: {
if (type !== COMMENT && type !== EOF) {
res.push(value);
}
}
}
}
}
return res;
}
function resolveVar(value, opt = {}) {
const { format = "" } = opt;
if (isString(value)) {
if (!REG_FN_VAR.test(value) || format === VAL_SPEC) {
return value;
}
value = value.trim();
} else {
throw new TypeError(`${value} is not a string.`);
}
const cacheKey = createCacheKey(
{
namespace: NAMESPACE,
name: "resolveVar",
value
},
opt
);
const cachedResult = getCache(cacheKey);
if (cachedResult instanceof CacheItem) {
if (cachedResult.isNull) {
return cachedResult;
}
return cachedResult.item;
}
const tokens = tokenize({ css: value });
const values = parseTokens(tokens, opt);
if (Array.isArray(values)) {
let color = values.join("");
if (REG_FN_CALC.test(color)) {
color = cssCalc(color, opt);
}
setCache(cacheKey, color);
return color;
} else {
setCache(cacheKey, null);
return new NullObject();
}
}
const cssVar = (value, opt = {}) => {
const resolvedValue = resolveVar(value, opt);
if (isString(resolvedValue)) {
return resolvedValue;
}
return "";
};
export {
cssVar,
parseTokens,
resolveCustomProperty,
resolveVar
};
//# sourceMappingURL=css-var.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,29 @@
import { CSSToken } from '@csstools/css-tokenizer';
import { NullObject } from './cache.js';
import { ColorChannels, Options, StringColorChannels } from './typedef.js';
/**
* @type NumberOrStringColorChannels - color channel
*/
type NumberOrStringColorChannels = ColorChannels & StringColorChannels;
/**
* resolve relative color channels
* @param tokens - CSS tokens
* @param [opt] - options
* @returns resolved color channels
*/
export declare function resolveColorChannels(tokens: CSSToken[], opt?: Options): NumberOrStringColorChannels | NullObject;
/**
* extract origin color
* @param value - CSS color value
* @param [opt] - options
* @returns origin color value
*/
export declare function extractOriginColor(value: string, opt?: Options): string | NullObject;
/**
* resolve relative color
* @param value - CSS relative color value
* @param [opt] - options
* @returns resolved value
*/
export declare function resolveRelativeColor(value: string, opt?: Options): string | NullObject;
export {};

View File

@@ -0,0 +1,535 @@
import { SyntaxFlag, color } from "@csstools/css-color-parser";
import { parseComponentValue } from "@csstools/css-parser-algorithms";
import { TokenType, tokenize } from "@csstools/css-tokenizer";
import { createCacheKey, getCache, CacheItem, NullObject, setCache } from "./cache.js";
import { convertColorToRgb, NAMED_COLORS } from "./color.js";
import { isString, isStringOrNumber } from "./common.js";
import { resolveDimension, serializeCalc } from "./css-calc.js";
import { resolveColor } from "./resolve.js";
import { roundToPrecision, splitValue } from "./util.js";
import { VAL_SPEC, FN_VAR, NONE, SYN_FN_VAR, FN_REL, FN_LIGHT_DARK, CS_LAB, CS_LCH, FN_REL_CAPT, SYN_COLOR_TYPE, SYN_MIX, SYN_FN_MATH_START } from "./constant.js";
const {
CloseParen: PAREN_CLOSE,
Comment: COMMENT,
Delim: DELIM,
Dimension: DIM,
EOF,
Function: FUNC,
Ident: IDENT,
Number: NUM,
OpenParen: PAREN_OPEN,
Percentage: PCT,
Whitespace: W_SPACE
} = TokenType;
const { HasNoneKeywords: KEY_NONE } = SyntaxFlag;
const NAMESPACE = "relative-color";
const OCT = 8;
const DEC = 10;
const HEX = 16;
const MAX_PCT = 100;
const MAX_RGB = 255;
const REG_COLOR_CAPT = new RegExp(
`^${FN_REL}(${SYN_COLOR_TYPE}|${SYN_MIX})\\s+`
);
const REG_CS_HSL = /(?:hsla?|hwb)$/;
const REG_CS_CIE = new RegExp(`^(?:${CS_LAB}|${CS_LCH})$`);
const REG_FN_CALC_SUM = /^(?:abs|sig?n|cos|tan)\(/;
const REG_FN_MATH_START = new RegExp(SYN_FN_MATH_START);
const REG_FN_REL = new RegExp(FN_REL);
const REG_FN_REL_CAPT = new RegExp(`^${FN_REL_CAPT}`);
const REG_FN_REL_START = new RegExp(`^${FN_REL}`);
const REG_FN_VAR = new RegExp(SYN_FN_VAR);
function resolveColorChannels(tokens, opt = {}) {
if (!Array.isArray(tokens)) {
throw new TypeError(`${tokens} is not an array.`);
}
const { colorSpace = "", format = "" } = opt;
const colorChannels = /* @__PURE__ */ new Map([
["color", ["r", "g", "b", "alpha"]],
["hsl", ["h", "s", "l", "alpha"]],
["hsla", ["h", "s", "l", "alpha"]],
["hwb", ["h", "w", "b", "alpha"]],
["lab", ["l", "a", "b", "alpha"]],
["lch", ["l", "c", "h", "alpha"]],
["oklab", ["l", "a", "b", "alpha"]],
["oklch", ["l", "c", "h", "alpha"]],
["rgb", ["r", "g", "b", "alpha"]],
["rgba", ["r", "g", "b", "alpha"]]
]);
const colorChannel = colorChannels.get(colorSpace);
if (!colorChannel) {
return new NullObject();
}
const mathFunc = /* @__PURE__ */ new Set();
const channels = [[], [], [], []];
let i = 0;
let nest = 0;
let func = "";
let precededPct = false;
while (tokens.length) {
const token = tokens.shift();
if (!Array.isArray(token)) {
throw new TypeError(`${token} is not an array.`);
}
const [type, value, , , detail] = token;
const channel = channels[i];
if (Array.isArray(channel)) {
switch (type) {
case DELIM: {
if (func) {
if ((value === "+" || value === "-") && precededPct && !REG_FN_CALC_SUM.test(func)) {
return new NullObject();
}
precededPct = false;
channel.push(value);
}
break;
}
case DIM: {
if (!func || !REG_FN_CALC_SUM.test(func)) {
return new NullObject();
}
const resolvedValue = resolveDimension(token, opt);
if (isString(resolvedValue)) {
channel.push(resolvedValue);
} else {
channel.push(value);
}
break;
}
case FUNC: {
channel.push(value);
func = value;
nest++;
if (REG_FN_MATH_START.test(value)) {
mathFunc.add(nest);
}
break;
}
case IDENT: {
if (!colorChannel.includes(value)) {
return new NullObject();
}
channel.push(value);
if (!func) {
i++;
}
break;
}
case NUM: {
channel.push(Number(detail?.value));
if (!func) {
i++;
}
break;
}
case PAREN_OPEN: {
channel.push(value);
nest++;
break;
}
case PAREN_CLOSE: {
if (func) {
const lastValue = channel[channel.length - 1];
if (lastValue === " ") {
channel.splice(-1, 1, value);
} else {
channel.push(value);
}
if (mathFunc.has(nest)) {
mathFunc.delete(nest);
}
nest--;
if (nest === 0) {
func = "";
i++;
}
}
break;
}
case PCT: {
if (!func) {
return new NullObject();
} else if (!REG_FN_CALC_SUM.test(func)) {
const lastValue = channel.toReversed().find((v) => v !== " ");
if (lastValue === "+" || lastValue === "-") {
return new NullObject();
} else if (lastValue === "*" || lastValue === "/") {
precededPct = false;
} else {
precededPct = true;
}
}
channel.push(Number(detail?.value) / MAX_PCT);
if (!func) {
i++;
}
break;
}
case W_SPACE: {
if (channel.length && func) {
const lastValue = channel[channel.length - 1];
if (typeof lastValue === "number") {
channel.push(value);
} else if (isString(lastValue) && !lastValue.endsWith("(") && lastValue !== " ") {
channel.push(value);
}
}
break;
}
default: {
if (type !== COMMENT && type !== EOF && func) {
channel.push(value);
}
}
}
}
}
const channelValues = [];
for (const channel of channels) {
if (channel.length === 1) {
const [resolvedValue] = channel;
if (isStringOrNumber(resolvedValue)) {
channelValues.push(resolvedValue);
}
} else if (channel.length) {
const resolvedValue = serializeCalc(channel.join(""), {
format
});
channelValues.push(resolvedValue);
}
}
return channelValues;
}
function extractOriginColor(value, opt = {}) {
const { colorScheme = "normal", currentColor = "", format = "" } = opt;
if (isString(value)) {
value = value.toLowerCase().trim();
if (!value) {
return new NullObject();
}
if (!REG_FN_REL_START.test(value)) {
return value;
}
} else {
return new NullObject();
}
const cacheKey = createCacheKey(
{
namespace: NAMESPACE,
name: "extractOriginColor",
value
},
opt
);
const cachedResult = getCache(cacheKey);
if (cachedResult instanceof CacheItem) {
if (cachedResult.isNull) {
return cachedResult;
}
return cachedResult.item;
}
if (/currentcolor/.test(value)) {
if (currentColor) {
value = value.replace(/currentcolor/g, currentColor);
} else {
setCache(cacheKey, null);
return new NullObject();
}
}
let colorSpace = "";
if (REG_FN_REL_CAPT.test(value)) {
[, colorSpace] = value.match(REG_FN_REL_CAPT);
}
opt.colorSpace = colorSpace;
if (value.includes(FN_LIGHT_DARK)) {
const colorParts = value.replace(new RegExp(`^${colorSpace}\\(`), "").replace(/\)$/, "");
const [, originColor = ""] = splitValue(colorParts);
const specifiedOriginColor = resolveColor(originColor, {
colorScheme,
format: VAL_SPEC
});
if (specifiedOriginColor === "") {
setCache(cacheKey, null);
return new NullObject();
}
if (format === VAL_SPEC) {
value = value.replace(originColor, specifiedOriginColor);
} else {
const resolvedOriginColor = resolveColor(specifiedOriginColor, opt);
if (isString(resolvedOriginColor)) {
value = value.replace(originColor, resolvedOriginColor);
}
}
}
if (REG_COLOR_CAPT.test(value)) {
const [, originColor] = value.match(REG_COLOR_CAPT);
const [, restValue] = value.split(originColor);
if (/^[a-z]+$/.test(originColor)) {
if (!/^transparent$/.test(originColor) && !Object.hasOwn(NAMED_COLORS, originColor)) {
setCache(cacheKey, null);
return new NullObject();
}
} else if (format === VAL_SPEC) {
const resolvedOriginColor = resolveColor(originColor, opt);
if (isString(resolvedOriginColor)) {
value = value.replace(originColor, resolvedOriginColor);
}
}
if (format === VAL_SPEC) {
const tokens = tokenize({ css: restValue });
const channelValues = resolveColorChannels(tokens, opt);
if (channelValues instanceof NullObject) {
setCache(cacheKey, null);
return channelValues;
}
const [v1, v2, v3, v4] = channelValues;
let channelValue = "";
if (isStringOrNumber(v4)) {
channelValue = ` ${v1} ${v2} ${v3} / ${v4})`;
} else {
channelValue = ` ${channelValues.join(" ")})`;
}
if (restValue !== channelValue) {
value = value.replace(restValue, channelValue);
}
}
} else {
const [, restValue] = value.split(REG_FN_REL_START);
const tokens = tokenize({ css: restValue });
const originColor = [];
let nest = 0;
while (tokens.length) {
const [type, tokenValue] = tokens.shift();
switch (type) {
case FUNC:
case PAREN_OPEN: {
originColor.push(tokenValue);
nest++;
break;
}
case PAREN_CLOSE: {
const lastValue = originColor[originColor.length - 1];
if (lastValue === " ") {
originColor.splice(-1, 1, tokenValue);
} else if (isString(lastValue)) {
originColor.push(tokenValue);
}
nest--;
break;
}
case W_SPACE: {
const lastValue = originColor[originColor.length - 1];
if (isString(lastValue) && !lastValue.endsWith("(") && lastValue !== " ") {
originColor.push(tokenValue);
}
break;
}
default: {
if (type !== COMMENT && type !== EOF) {
originColor.push(tokenValue);
}
}
}
if (nest === 0) {
break;
}
}
const resolvedOriginColor = resolveRelativeColor(
originColor.join("").trim(),
opt
);
if (resolvedOriginColor instanceof NullObject) {
setCache(cacheKey, null);
return resolvedOriginColor;
}
const channelValues = resolveColorChannels(tokens, opt);
if (channelValues instanceof NullObject) {
setCache(cacheKey, null);
return channelValues;
}
const [v1, v2, v3, v4] = channelValues;
let channelValue = "";
if (isStringOrNumber(v4)) {
channelValue = ` ${v1} ${v2} ${v3} / ${v4})`;
} else {
channelValue = ` ${channelValues.join(" ")})`;
}
value = value.replace(restValue, `${resolvedOriginColor}${channelValue}`);
}
setCache(cacheKey, value);
return value;
}
function resolveRelativeColor(value, opt = {}) {
const { format = "" } = opt;
if (isString(value)) {
if (REG_FN_VAR.test(value)) {
if (format === VAL_SPEC) {
return value;
} else {
throw new SyntaxError(`Unexpected token ${FN_VAR} found.`);
}
} else if (!REG_FN_REL.test(value)) {
return value;
}
value = value.toLowerCase().trim();
} else {
throw new TypeError(`${value} is not a string.`);
}
const cacheKey = createCacheKey(
{
namespace: NAMESPACE,
name: "resolveRelativeColor",
value
},
opt
);
const cachedResult = getCache(cacheKey);
if (cachedResult instanceof CacheItem) {
if (cachedResult.isNull) {
return cachedResult;
}
return cachedResult.item;
}
const originColor = extractOriginColor(value, opt);
if (originColor instanceof NullObject) {
setCache(cacheKey, null);
return originColor;
}
value = originColor;
if (format === VAL_SPEC) {
if (value.startsWith("rgba(")) {
value = value.replace(/^rgba\(/, "rgb(");
} else if (value.startsWith("hsla(")) {
value = value.replace(/^hsla\(/, "hsl(");
}
return value;
}
const tokens = tokenize({ css: value });
const components = parseComponentValue(tokens);
const parsedComponents = color(components);
if (!parsedComponents) {
setCache(cacheKey, null);
return new NullObject();
}
const {
alpha: alphaComponent,
channels: channelsComponent,
colorNotation,
syntaxFlags
} = parsedComponents;
let alpha;
if (Number.isNaN(Number(alphaComponent))) {
if (syntaxFlags instanceof Set && syntaxFlags.has(KEY_NONE)) {
alpha = NONE;
} else {
alpha = 0;
}
} else {
alpha = roundToPrecision(Number(alphaComponent), OCT);
}
let v1;
let v2;
let v3;
[v1, v2, v3] = channelsComponent;
let resolvedValue;
if (REG_CS_CIE.test(colorNotation)) {
const hasNone = syntaxFlags instanceof Set && syntaxFlags.has(KEY_NONE);
if (Number.isNaN(v1)) {
if (hasNone) {
v1 = NONE;
} else {
v1 = 0;
}
} else {
v1 = roundToPrecision(v1, HEX);
}
if (Number.isNaN(v2)) {
if (hasNone) {
v2 = NONE;
} else {
v2 = 0;
}
} else {
v2 = roundToPrecision(v2, HEX);
}
if (Number.isNaN(v3)) {
if (hasNone) {
v3 = NONE;
} else {
v3 = 0;
}
} else {
v3 = roundToPrecision(v3, HEX);
}
if (alpha === 1) {
resolvedValue = `${colorNotation}(${v1} ${v2} ${v3})`;
} else {
resolvedValue = `${colorNotation}(${v1} ${v2} ${v3} / ${alpha})`;
}
} else if (REG_CS_HSL.test(colorNotation)) {
if (Number.isNaN(v1)) {
v1 = 0;
}
if (Number.isNaN(v2)) {
v2 = 0;
}
if (Number.isNaN(v3)) {
v3 = 0;
}
let [r, g, b] = convertColorToRgb(
`${colorNotation}(${v1} ${v2} ${v3} / ${alpha})`
);
r = roundToPrecision(r / MAX_RGB, DEC);
g = roundToPrecision(g / MAX_RGB, DEC);
b = roundToPrecision(b / MAX_RGB, DEC);
if (alpha === 1) {
resolvedValue = `color(srgb ${r} ${g} ${b})`;
} else {
resolvedValue = `color(srgb ${r} ${g} ${b} / ${alpha})`;
}
} else {
const cs = colorNotation === "rgb" ? "srgb" : colorNotation;
const hasNone = syntaxFlags instanceof Set && syntaxFlags.has(KEY_NONE);
if (Number.isNaN(v1)) {
if (hasNone) {
v1 = NONE;
} else {
v1 = 0;
}
} else {
v1 = roundToPrecision(v1, DEC);
}
if (Number.isNaN(v2)) {
if (hasNone) {
v2 = NONE;
} else {
v2 = 0;
}
} else {
v2 = roundToPrecision(v2, DEC);
}
if (Number.isNaN(v3)) {
if (hasNone) {
v3 = NONE;
} else {
v3 = 0;
}
} else {
v3 = roundToPrecision(v3, DEC);
}
if (alpha === 1) {
resolvedValue = `color(${cs} ${v1} ${v2} ${v3})`;
} else {
resolvedValue = `color(${cs} ${v1} ${v2} ${v3} / ${alpha})`;
}
}
setCache(cacheKey, resolvedValue);
return resolvedValue;
}
export {
extractOriginColor,
resolveColorChannels,
resolveRelativeColor
};
//# sourceMappingURL=relative-color.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,52 @@
import { NullObject } from './cache.js';
import { Options } from './typedef.js';
/**
* resolve color
* @param value - CSS color value
* @param [opt] - options
* @returns resolved color
*/
export declare const resolveColor: (value: string, opt?: Options) => string | NullObject;
/**
* resolve CSS color
* @param value
* - CSS color value
* - system colors are not supported
* @param [opt] - options
* @param [opt.currentColor]
* - color to use for `currentcolor` keyword
* - if omitted, it will be treated as a missing color
* i.e. `rgb(none none none / none)`
* @param [opt.customProperty]
* - custom properties
* - pair of `--` prefixed property name and value,
* e.g. `customProperty: { '--some-color': '#0000ff' }`
* - and/or `callback` function to get the value of the custom property,
* e.g. `customProperty: { callback: someDeclaration.getPropertyValue }`
* @param [opt.dimension]
* - dimension, convert relative length to pixels
* - pair of unit and it's value as a number in pixels,
* e.g. `dimension: { em: 12, rem: 16, vw: 10.26 }`
* - and/or `callback` function to get the value as a number in pixels,
* e.g. `dimension: { callback: convertUnitToPixel }`
* @param [opt.format]
* - output format, one of below
* - `computedValue` (default), [computed value][139] of the color
* - `specifiedValue`, [specified value][140] of the color
* - `hex`, hex color notation, i.e. `rrggbb`
* - `hexAlpha`, hex color notation with alpha channel, i.e. `#rrggbbaa`
* @returns
* - one of rgba?(), #rrggbb(aa)?, color-name, '(empty-string)',
* color(color-space r g b / alpha), color(color-space x y z / alpha),
* lab(l a b / alpha), lch(l c h / alpha), oklab(l a b / alpha),
* oklch(l c h / alpha), null
* - in `computedValue`, values are numbers, however `rgb()` values are
* integers
* - in `specifiedValue`, returns `empty string` for unknown and/or invalid
* color
* - in `hex`, returns `null` for `transparent`, and also returns `null` if
* any of `r`, `g`, `b`, `alpha` is not a number
* - in `hexAlpha`, returns `#00000000` for `transparent`,
* however returns `null` if any of `r`, `g`, `b`, `alpha` is not a number
*/
export declare const resolve: (value: string, opt?: Options) => string | null;

View File

@@ -0,0 +1,350 @@
import { NullObject, createCacheKey, getCache, CacheItem, setCache } from "./cache.js";
import { resolveColorMix, resolveColorFunc, resolveColorValue, convertRgbToHex } from "./color.js";
import { isString } from "./common.js";
import { cssCalc } from "./css-calc.js";
import { resolveVar } from "./css-var.js";
import { resolveRelativeColor } from "./relative-color.js";
import { splitValue } from "./util.js";
import { VAL_COMP, VAL_SPEC, FN_MIX, FN_COLOR, SYN_FN_VAR, SYN_FN_LIGHT_DARK, SYN_FN_REL, SYN_FN_CALC } from "./constant.js";
const NAMESPACE = "resolve";
const RGB_TRANSPARENT = "rgba(0, 0, 0, 0)";
const REG_FN_CALC = new RegExp(SYN_FN_CALC);
const REG_FN_LIGHT_DARK = new RegExp(SYN_FN_LIGHT_DARK);
const REG_FN_REL = new RegExp(SYN_FN_REL);
const REG_FN_VAR = new RegExp(SYN_FN_VAR);
const resolveColor = (value, opt = {}) => {
if (isString(value)) {
value = value.trim();
} else {
throw new TypeError(`${value} is not a string.`);
}
const {
colorScheme = "normal",
currentColor = "",
format = VAL_COMP,
nullable = false
} = opt;
const cacheKey = createCacheKey(
{
namespace: NAMESPACE,
name: "resolve",
value
},
opt
);
const cachedResult = getCache(cacheKey);
if (cachedResult instanceof CacheItem) {
if (cachedResult.isNull) {
return cachedResult;
}
return cachedResult.item;
}
if (REG_FN_VAR.test(value)) {
if (format === VAL_SPEC) {
setCache(cacheKey, value);
return value;
}
const resolvedValue = resolveVar(value, opt);
if (resolvedValue instanceof NullObject) {
switch (format) {
case "hex":
case "hexAlpha": {
setCache(cacheKey, resolvedValue);
return resolvedValue;
}
default: {
if (nullable) {
setCache(cacheKey, resolvedValue);
return resolvedValue;
}
const res2 = RGB_TRANSPARENT;
setCache(cacheKey, res2);
return res2;
}
}
} else {
value = resolvedValue;
}
}
if (opt.format !== format) {
opt.format = format;
}
value = value.toLowerCase();
if (REG_FN_LIGHT_DARK.test(value) && value.endsWith(")")) {
const colorParts = value.replace(REG_FN_LIGHT_DARK, "").replace(/\)$/, "");
const [light = "", dark = ""] = splitValue(colorParts, {
delimiter: ","
});
if (light && dark) {
if (format === VAL_SPEC) {
const lightColor = resolveColor(light, opt);
const darkColor = resolveColor(dark, opt);
let res3;
if (lightColor && darkColor) {
res3 = `light-dark(${lightColor}, ${darkColor})`;
} else {
res3 = "";
}
setCache(cacheKey, res3);
return res3;
}
let resolvedValue;
if (colorScheme === "dark") {
resolvedValue = resolveColor(dark, opt);
} else {
resolvedValue = resolveColor(light, opt);
}
let res2;
if (resolvedValue instanceof NullObject) {
if (nullable) {
res2 = resolvedValue;
} else {
res2 = RGB_TRANSPARENT;
}
} else {
res2 = resolvedValue;
}
setCache(cacheKey, res2);
return res2;
}
switch (format) {
case VAL_SPEC: {
setCache(cacheKey, "");
return "";
}
case "hex":
case "hexAlpha": {
setCache(cacheKey, null);
return new NullObject();
}
case VAL_COMP:
default: {
const res2 = RGB_TRANSPARENT;
setCache(cacheKey, res2);
return res2;
}
}
}
if (REG_FN_REL.test(value)) {
const resolvedValue = resolveRelativeColor(value, opt);
if (format === VAL_COMP) {
let res2;
if (resolvedValue instanceof NullObject) {
if (nullable) {
res2 = resolvedValue;
} else {
res2 = RGB_TRANSPARENT;
}
} else {
res2 = resolvedValue;
}
setCache(cacheKey, res2);
return res2;
}
if (format === VAL_SPEC) {
let res2 = "";
if (resolvedValue instanceof NullObject) {
res2 = "";
} else {
res2 = resolvedValue;
}
setCache(cacheKey, res2);
return res2;
}
if (resolvedValue instanceof NullObject) {
value = "";
} else {
value = resolvedValue;
}
}
if (REG_FN_CALC.test(value)) {
value = cssCalc(value, opt);
}
let cs = "";
let r = NaN;
let g = NaN;
let b = NaN;
let alpha = NaN;
if (value === "transparent") {
switch (format) {
case VAL_SPEC: {
setCache(cacheKey, value);
return value;
}
case "hex": {
setCache(cacheKey, null);
return new NullObject();
}
case "hexAlpha": {
const res2 = "#00000000";
setCache(cacheKey, res2);
return res2;
}
case VAL_COMP:
default: {
const res2 = RGB_TRANSPARENT;
setCache(cacheKey, res2);
return res2;
}
}
} else if (value === "currentcolor") {
if (format === VAL_SPEC) {
setCache(cacheKey, value);
return value;
}
if (currentColor) {
let resolvedValue;
if (currentColor.startsWith(FN_MIX)) {
resolvedValue = resolveColorMix(currentColor, opt);
} else if (currentColor.startsWith(FN_COLOR)) {
resolvedValue = resolveColorFunc(currentColor, opt);
} else {
resolvedValue = resolveColorValue(currentColor, opt);
}
if (resolvedValue instanceof NullObject) {
setCache(cacheKey, resolvedValue);
return resolvedValue;
}
[cs, r, g, b, alpha] = resolvedValue;
} else if (format === VAL_COMP) {
const res2 = RGB_TRANSPARENT;
setCache(cacheKey, res2);
return res2;
}
} else if (format === VAL_SPEC) {
if (value.startsWith(FN_MIX)) {
const res2 = resolveColorMix(value, opt);
setCache(cacheKey, res2);
return res2;
} else if (value.startsWith(FN_COLOR)) {
const [scs, rr, gg, bb, aa] = resolveColorFunc(
value,
opt
);
let res2 = "";
if (aa === 1) {
res2 = `color(${scs} ${rr} ${gg} ${bb})`;
} else {
res2 = `color(${scs} ${rr} ${gg} ${bb} / ${aa})`;
}
setCache(cacheKey, res2);
return res2;
} else {
const rgb = resolveColorValue(value, opt);
if (isString(rgb)) {
setCache(cacheKey, rgb);
return rgb;
}
const [scs, rr, gg, bb, aa] = rgb;
let res2 = "";
if (scs === "rgb") {
if (aa === 1) {
res2 = `${scs}(${rr}, ${gg}, ${bb})`;
} else {
res2 = `${scs}a(${rr}, ${gg}, ${bb}, ${aa})`;
}
} else if (aa === 1) {
res2 = `${scs}(${rr} ${gg} ${bb})`;
} else {
res2 = `${scs}(${rr} ${gg} ${bb} / ${aa})`;
}
setCache(cacheKey, res2);
return res2;
}
} else if (value.startsWith(FN_MIX)) {
if (/currentcolor/.test(value)) {
if (currentColor) {
value = value.replace(/currentcolor/g, currentColor);
}
}
if (/transparent/.test(value)) {
value = value.replace(/transparent/g, RGB_TRANSPARENT);
}
const resolvedValue = resolveColorMix(value, opt);
if (resolvedValue instanceof NullObject) {
setCache(cacheKey, resolvedValue);
return resolvedValue;
}
[cs, r, g, b, alpha] = resolvedValue;
} else if (value.startsWith(FN_COLOR)) {
const resolvedValue = resolveColorFunc(value, opt);
if (resolvedValue instanceof NullObject) {
setCache(cacheKey, resolvedValue);
return resolvedValue;
}
[cs, r, g, b, alpha] = resolvedValue;
} else if (value) {
const resolvedValue = resolveColorValue(value, opt);
if (resolvedValue instanceof NullObject) {
setCache(cacheKey, resolvedValue);
return resolvedValue;
}
[cs, r, g, b, alpha] = resolvedValue;
}
let res = "";
switch (format) {
case "hex": {
if (Number.isNaN(r) || Number.isNaN(g) || Number.isNaN(b) || Number.isNaN(alpha) || alpha === 0) {
setCache(cacheKey, null);
return new NullObject();
}
res = convertRgbToHex([r, g, b, 1]);
break;
}
case "hexAlpha": {
if (Number.isNaN(r) || Number.isNaN(g) || Number.isNaN(b) || Number.isNaN(alpha)) {
setCache(cacheKey, null);
return new NullObject();
}
res = convertRgbToHex([r, g, b, alpha]);
break;
}
case VAL_COMP:
default: {
switch (cs) {
case "rgb": {
if (alpha === 1) {
res = `${cs}(${r}, ${g}, ${b})`;
} else {
res = `${cs}a(${r}, ${g}, ${b}, ${alpha})`;
}
break;
}
case "lab":
case "lch":
case "oklab":
case "oklch": {
if (alpha === 1) {
res = `${cs}(${r} ${g} ${b})`;
} else {
res = `${cs}(${r} ${g} ${b} / ${alpha})`;
}
break;
}
// color()
default: {
if (alpha === 1) {
res = `color(${cs} ${r} ${g} ${b})`;
} else {
res = `color(${cs} ${r} ${g} ${b} / ${alpha})`;
}
}
}
}
}
setCache(cacheKey, res);
return res;
};
const resolve = (value, opt = {}) => {
opt.nullable = false;
const resolvedValue = resolveColor(value, opt);
if (resolvedValue instanceof NullObject) {
return null;
}
return resolvedValue;
};
export {
resolve,
resolveColor
};
//# sourceMappingURL=resolve.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,80 @@
/**
* typedef
*/
/**
* @typedef Options - options
* @property [alpha] - enable alpha
* @property [colorSpace] - color space
* @property [currentColor] - color for currentcolor
* @property [customProperty] - custom properties
* @property [d50] - white point in d50
* @property [dimension] - dimension
* @property [format] - output format
* @property [key] - key
*/
export interface Options {
alpha?: boolean;
colorScheme?: string;
colorSpace?: string;
currentColor?: string;
customProperty?: Record<string, string | ((K: string) => string)>;
d50?: boolean;
delimiter?: string | string[];
dimension?: Record<string, number | ((K: string) => number)>;
format?: string;
nullable?: boolean;
preserveComment?: boolean;
}
/**
* @type ColorChannels - color channels
*/
export type ColorChannels = [x: number, y: number, z: number, alpha: number];
/**
* @type StringColorChannels - color channels
*/
export type StringColorChannels = [
x: string,
y: string,
z: string,
alpha: string | undefined
];
/**
* @type StringColorSpacedChannels - specified value
*/
export type StringColorSpacedChannels = [
cs: string,
x: string,
y: string,
z: string,
alpha: string | undefined
];
/**
* @type ComputedColorChannels - computed value
*/
export type ComputedColorChannels = [
cs: string,
x: number,
y: number,
z: number,
alpha: number
];
/**
* @type SpecifiedColorChannels - specified value
*/
export type SpecifiedColorChannels = [
cs: string,
x: number | string,
y: number | string,
z: number | string,
alpha: number | string
];
/**
* @type MatchedRegExp - matched regexp array
*/
export type MatchedRegExp = [
match: string,
gr1: string,
gr2: string,
gr3: string,
gr4: string
];

View File

@@ -0,0 +1,53 @@
import { Options } from './typedef.js';
/**
* split value
* NOTE: comments are stripped, it can be preserved if, in the options param,
* `delimiter` is either ',' or '/' and with `preserveComment` set to `true`
* @param value - CSS value
* @param [opt] - options
* @returns array of values
*/
export declare const splitValue: (value: string, opt?: Options) => string[];
/**
* extract dashed-ident tokens
* @param value - CSS value
* @returns array of dashed-ident tokens
*/
export declare const extractDashedIdent: (value: string) => string[];
/**
* is color
* @param value - CSS value
* @param [opt] - options
* @returns result
*/
export declare const isColor: (value: unknown, opt?: Options) => boolean;
/**
* value to JSON string
* @param value - CSS value
* @param [func] - stringify function
* @returns stringified value in JSON notation
*/
export declare const valueToJsonString: (value: unknown, func?: boolean) => string;
/**
* round to specified precision
* @param value - numeric value
* @param bit - minimum bits
* @returns rounded value
*/
export declare const roundToPrecision: (value: number, bit?: number) => number;
/**
* interpolate hue
* @param hueA - hue value
* @param hueB - hue value
* @param arc - shorter | longer | increasing | decreasing
* @returns result - [hueA, hueB]
*/
export declare const interpolateHue: (hueA: number, hueB: number, arc?: string) => [number, number];
/**
* resolve length in pixels
* @param value - value
* @param unit - unit
* @param [opt] - options
* @returns pixelated value
*/
export declare const resolveLengthInPixels: (value: number | string, unit: string | undefined, opt?: Options) => number;

View File

@@ -0,0 +1,359 @@
import { TokenType, tokenize } from "@csstools/css-tokenizer";
import { createCacheKey, getCache, CacheItem, setCache } from "./cache.js";
import { isString } from "./common.js";
import { resolveColor } from "./resolve.js";
import { NAMED_COLORS } from "./color.js";
import { VAL_SPEC, SYN_COLOR_TYPE, SYN_MIX } from "./constant.js";
const {
CloseParen: PAREN_CLOSE,
Comma: COMMA,
Comment: COMMENT,
Delim: DELIM,
EOF,
Function: FUNC,
Ident: IDENT,
OpenParen: PAREN_OPEN,
Whitespace: W_SPACE
} = TokenType;
const NAMESPACE = "util";
const DEC = 10;
const HEX = 16;
const DEG = 360;
const DEG_HALF = 180;
const REG_COLOR = new RegExp(`^(?:${SYN_COLOR_TYPE})$`);
const REG_FN_COLOR = /^(?:(?:ok)?l(?:ab|ch)|color(?:-mix)?|hsla?|hwb|rgba?|var)\(/;
const REG_MIX = new RegExp(SYN_MIX);
const splitValue = (value, opt = {}) => {
if (isString(value)) {
value = value.trim();
} else {
throw new TypeError(`${value} is not a string.`);
}
const { delimiter = " ", preserveComment = false } = opt;
const cacheKey = createCacheKey(
{
namespace: NAMESPACE,
name: "splitValue",
value
},
{
delimiter,
preserveComment
}
);
const cachedResult = getCache(cacheKey);
if (cachedResult instanceof CacheItem) {
return cachedResult.item;
}
let regDelimiter;
if (delimiter === ",") {
regDelimiter = /^,$/;
} else if (delimiter === "/") {
regDelimiter = /^\/$/;
} else {
regDelimiter = /^\s+$/;
}
const tokens = tokenize({ css: value });
let nest = 0;
let str = "";
const res = [];
while (tokens.length) {
const [type, value2] = tokens.shift();
switch (type) {
case COMMA: {
if (regDelimiter.test(value2)) {
if (nest === 0) {
res.push(str.trim());
str = "";
} else {
str += value2;
}
} else {
str += value2;
}
break;
}
case DELIM: {
if (regDelimiter.test(value2)) {
if (nest === 0) {
res.push(str.trim());
str = "";
} else {
str += value2;
}
} else {
str += value2;
}
break;
}
case COMMENT: {
if (preserveComment && (delimiter === "," || delimiter === "/")) {
str += value2;
}
break;
}
case FUNC:
case PAREN_OPEN: {
str += value2;
nest++;
break;
}
case PAREN_CLOSE: {
str += value2;
nest--;
break;
}
case W_SPACE: {
if (regDelimiter.test(value2)) {
if (nest === 0) {
if (str) {
res.push(str.trim());
str = "";
}
} else {
str += " ";
}
} else if (!str.endsWith(" ")) {
str += " ";
}
break;
}
default: {
if (type === EOF) {
res.push(str.trim());
str = "";
} else {
str += value2;
}
}
}
}
setCache(cacheKey, res);
return res;
};
const extractDashedIdent = (value) => {
if (isString(value)) {
value = value.trim();
} else {
throw new TypeError(`${value} is not a string.`);
}
const cacheKey = createCacheKey({
namespace: NAMESPACE,
name: "extractDashedIdent",
value
});
const cachedResult = getCache(cacheKey);
if (cachedResult instanceof CacheItem) {
return cachedResult.item;
}
const tokens = tokenize({ css: value });
const items = /* @__PURE__ */ new Set();
while (tokens.length) {
const [type, value2] = tokens.shift();
if (type === IDENT && value2.startsWith("--")) {
items.add(value2);
}
}
const res = [...items];
setCache(cacheKey, res);
return res;
};
const isColor = (value, opt = {}) => {
if (isString(value)) {
value = value.toLowerCase().trim();
if (value && isString(value)) {
if (/^[a-z]+$/.test(value)) {
if (/^(?:currentcolor|transparent)$/.test(value) || Object.hasOwn(NAMED_COLORS, value)) {
return true;
}
} else if (REG_COLOR.test(value) || REG_MIX.test(value)) {
return true;
} else if (REG_FN_COLOR.test(value)) {
opt.nullable = true;
if (!opt.format) {
opt.format = VAL_SPEC;
}
const resolvedValue = resolveColor(value, opt);
if (resolvedValue) {
return true;
}
}
}
}
return false;
};
const valueToJsonString = (value, func = false) => {
if (typeof value === "undefined") {
return "";
}
const res = JSON.stringify(value, (_key, val) => {
let replacedValue;
if (typeof val === "undefined") {
replacedValue = null;
} else if (typeof val === "function") {
if (func) {
replacedValue = val.toString().replace(/\s/g, "").substring(0, HEX);
} else {
replacedValue = val.name;
}
} else if (val instanceof Map || val instanceof Set) {
replacedValue = [...val];
} else if (typeof val === "bigint") {
replacedValue = val.toString();
} else {
replacedValue = val;
}
return replacedValue;
});
return res;
};
const roundToPrecision = (value, bit = 0) => {
if (!Number.isFinite(value)) {
throw new TypeError(`${value} is not a finite number.`);
}
if (!Number.isFinite(bit)) {
throw new TypeError(`${bit} is not a finite number.`);
} else if (bit < 0 || bit > HEX) {
throw new RangeError(`${bit} is not between 0 and ${HEX}.`);
}
if (bit === 0) {
return Math.round(value);
}
let val;
if (bit === HEX) {
val = value.toPrecision(6);
} else if (bit < DEC) {
val = value.toPrecision(4);
} else {
val = value.toPrecision(5);
}
return parseFloat(val);
};
const interpolateHue = (hueA, hueB, arc = "shorter") => {
if (!Number.isFinite(hueA)) {
throw new TypeError(`${hueA} is not a finite number.`);
}
if (!Number.isFinite(hueB)) {
throw new TypeError(`${hueB} is not a finite number.`);
}
switch (arc) {
case "decreasing": {
if (hueB > hueA) {
hueA += DEG;
}
break;
}
case "increasing": {
if (hueB < hueA) {
hueB += DEG;
}
break;
}
case "longer": {
if (hueB > hueA && hueB < hueA + DEG_HALF) {
hueA += DEG;
} else if (hueB > hueA + DEG_HALF * -1 && hueB <= hueA) {
hueB += DEG;
}
break;
}
case "shorter":
default: {
if (hueB > hueA + DEG_HALF) {
hueA += DEG;
} else if (hueB < hueA + DEG_HALF * -1) {
hueB += DEG;
}
}
}
return [hueA, hueB];
};
const absoluteFontSize = /* @__PURE__ */ new Map([
["xx-small", 3 / 5],
["x-small", 3 / 4],
["small", 8 / 9],
["medium", 1],
["large", 6 / 5],
["x-large", 3 / 2],
["xx-large", 2],
["xxx-large", 3]
]);
const relativeFontSize = /* @__PURE__ */ new Map([
["smaller", 1 / 1.2],
["larger", 1.2]
]);
const absoluteLength = /* @__PURE__ */ new Map([
["cm", 96 / 2.54],
["mm", 96 / 2.54 / 10],
["q", 96 / 2.54 / 40],
["in", 96],
["pc", 96 / 6],
["pt", 96 / 72],
["px", 1]
]);
const relativeLength = /* @__PURE__ */ new Map([
["rcap", 1],
["rch", 0.5],
["rem", 1],
["rex", 0.5],
["ric", 1],
["rlh", 1.2]
]);
const resolveLengthInPixels = (value, unit, opt = {}) => {
const { dimension = {} } = opt;
const { callback, em, rem, vh, vw } = dimension;
if (isString(value)) {
value = value.toLowerCase().trim();
if (absoluteFontSize.has(value)) {
return Number(absoluteFontSize.get(value)) * rem;
} else if (relativeFontSize.has(value)) {
return Number(relativeFontSize.get(value)) * em;
}
return Number.NaN;
} else if (Number.isFinite(value) && unit) {
if (Object.hasOwn(dimension, unit)) {
return value * Number(dimension[unit]);
} else if (typeof callback === "function") {
return value * callback(unit);
} else if (absoluteLength.has(unit)) {
return value * Number(absoluteLength.get(unit));
} else if (relativeLength.has(unit)) {
return value * Number(relativeLength.get(unit)) * rem;
} else if (relativeLength.has(`r${unit}`)) {
return value * Number(relativeLength.get(`r${unit}`)) * em;
} else {
switch (unit) {
case "vb":
case "vi": {
return value * vw;
}
case "vmax": {
if (vh > vw) {
return value * vh;
}
return value * vw;
}
case "vmin": {
if (vh < vw) {
return value * vh;
}
return value * vw;
}
default: {
return Number.NaN;
}
}
}
}
return Number.NaN;
};
export {
extractDashedIdent,
interpolateHue,
isColor,
resolveLengthInPixels,
roundToPrecision,
splitValue,
valueToJsonString
};
//# sourceMappingURL=util.js.map

File diff suppressed because one or more lines are too long

82
server/node_modules/@asamuzakjp/css-color/package.json generated vendored Normal file
View File

@@ -0,0 +1,82 @@
{
"name": "@asamuzakjp/css-color",
"description": "CSS color - Resolve and convert CSS colors.",
"author": "asamuzaK",
"license": "MIT",
"repository": {
"type": "git",
"url": "git+https://github.com/asamuzaK/cssColor.git"
},
"homepage": "https://github.com/asamuzaK/cssColor#readme",
"bugs": {
"url": "https://github.com/asamuzaK/cssColor/issues"
},
"files": [
"dist",
"src"
],
"type": "module",
"types": "dist/esm/index.d.ts",
"module": "dist/esm/index.js",
"main": "dist/cjs/index.cjs",
"exports": {
".": {
"import": {
"types": "./dist/esm/index.d.ts",
"default": "./dist/esm/index.js"
},
"require": {
"types": "./dist/cjs/index.d.cts",
"default": "./dist/cjs/index.cjs"
}
},
"./package.json": "./package.json"
},
"dependencies": {
"@csstools/css-calc": "^2.1.4",
"@csstools/css-color-parser": "^3.1.0",
"@csstools/css-parser-algorithms": "^3.0.5",
"@csstools/css-tokenizer": "^3.0.4",
"lru-cache": "^11.2.4"
},
"devDependencies": {
"@tanstack/vite-config": "^0.4.3",
"@vitest/coverage-istanbul": "^4.0.15",
"esbuild": "^0.27.1",
"eslint": "^9.39.2",
"eslint-plugin-regexp": "^2.10.0",
"globals": "^16.5.0",
"knip": "^5.74.0",
"neostandard": "^0.12.2",
"prettier": "^3.7.4",
"publint": "^0.3.16",
"rimraf": "^6.1.2",
"tsup": "^8.5.1",
"typescript": "^5.9.3",
"vite": "^7.3.0",
"vitest": "^4.0.15"
},
"packageManager": "pnpm@10.25.0",
"pnpm": {
"onlyBuiltDependencies": [
"esbuild",
"oxc-resolver",
"unrs-resolver"
]
},
"scripts": {
"build": "pnpm run clean && pnpm run test && pnpm run knip && pnpm run build:prod && pnpm run build:cjs && pnpm run build:browser && pnpm run publint",
"build:browser": "vite build -c ./vite.browser.config.ts",
"build:prod": "vite build",
"build:cjs": "tsup ./src/index.ts --format=cjs --platform=node --outDir=./dist/cjs/ --sourcemap --dts",
"clean": "rimraf ./coverage ./dist",
"knip": "knip",
"prettier": "prettier . --ignore-unknown --write",
"publint": "publint --strict",
"test": "pnpm run prettier && pnpm run --stream \"/^test:.*/\"",
"test:eslint": "eslint ./src ./test --fix",
"test:types": "tsc",
"test:unit": "vitest"
},
"version": "4.1.1"
}

30
server/node_modules/@asamuzakjp/css-color/src/index.ts generated vendored Normal file
View File

@@ -0,0 +1,30 @@
/*!
* CSS color - Resolve, parse, convert CSS color.
* @license MIT
* @copyright asamuzaK (Kazz)
* @see {@link https://github.com/asamuzaK/cssColor/blob/main/LICENSE}
*/
import { cssCalc } from './js/css-calc';
import { isGradient, resolveGradient } from './js/css-gradient';
import { cssVar } from './js/css-var';
import {
extractDashedIdent,
isColor,
resolveLengthInPixels,
splitValue
} from './js/util';
export { convert } from './js/convert';
export { resolve } from './js/resolve';
/* utils */
export const utils = {
cssCalc,
cssVar,
extractDashedIdent,
isColor,
isGradient,
resolveGradient,
resolveLengthInPixels,
splitValue
};

View File

@@ -0,0 +1,114 @@
/**
* cache
*/
import { LRUCache } from 'lru-cache';
import { Options } from './typedef';
import { valueToJsonString } from './util';
/* numeric constants */
const MAX_CACHE = 4096;
/**
* CacheItem
*/
export class CacheItem {
/* private */
#isNull: boolean;
#item: unknown;
/**
* constructor
*/
constructor(item: unknown, isNull: boolean = false) {
this.#item = item;
this.#isNull = !!isNull;
}
get item() {
return this.#item;
}
get isNull() {
return this.#isNull;
}
}
/**
* NullObject
*/
export class NullObject extends CacheItem {
/**
* constructor
*/
constructor() {
super(Symbol('null'), true);
}
}
/*
* lru cache
*/
export const lruCache = new LRUCache({
max: MAX_CACHE
});
/**
* set cache
* @param key - cache key
* @param value - value to cache
* @returns void
*/
export const setCache = (key: string, value: unknown): void => {
if (key) {
if (value === null) {
lruCache.set(key, new NullObject());
} else if (value instanceof CacheItem) {
lruCache.set(key, value);
} else {
lruCache.set(key, new CacheItem(value));
}
}
};
/**
* get cache
* @param key - cache key
* @returns cached item or false otherwise
*/
export const getCache = (key: string): CacheItem | boolean => {
if (key && lruCache.has(key)) {
const item = lruCache.get(key);
if (item instanceof CacheItem) {
return item;
}
// delete unexpected cached item
lruCache.delete(key);
return false;
}
return false;
};
/**
* create cache key
* @param keyData - key data
* @param [opt] - options
* @returns cache key
*/
export const createCacheKey = (
keyData: Record<string, string>,
opt: Options = {}
): string => {
const { customProperty = {}, dimension = {} } = opt;
let cacheKey = '';
if (
keyData &&
Object.keys(keyData).length &&
typeof customProperty.callback !== 'function' &&
typeof dimension.callback !== 'function'
) {
keyData.opt = valueToJsonString(opt);
cacheKey = valueToJsonString(keyData);
}
return cacheKey;
};

3511
server/node_modules/@asamuzakjp/css-color/src/js/color.ts generated vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,31 @@
/**
* common
*/
/* numeric constants */
const TYPE_FROM = 8;
const TYPE_TO = -1;
/**
* get type
* @param o - object to check
* @returns type of object
*/
export const getType = (o: unknown): string =>
Object.prototype.toString.call(o).slice(TYPE_FROM, TYPE_TO);
/**
* is string
* @param o - object to check
* @returns result
*/
export const isString = (o: unknown): o is string =>
typeof o === 'string' || o instanceof String;
/**
* is string or number
* @param o - object to check
* @returns result
*/
export const isStringOrNumber = (o: unknown): boolean =>
isString(o) || typeof o === 'number';

View File

@@ -0,0 +1,68 @@
/**
* constant
*/
/* values and units */
const _DIGIT = '(?:0|[1-9]\\d*)';
const _COMPARE = 'clamp|max|min';
const _EXPO = 'exp|hypot|log|pow|sqrt';
const _SIGN = 'abs|sign';
const _STEP = 'mod|rem|round';
const _TRIG = 'a?(?:cos|sin|tan)|atan2';
const _MATH = `${_COMPARE}|${_EXPO}|${_SIGN}|${_STEP}|${_TRIG}`;
const _CALC = `calc|${_MATH}`;
const _VAR = `var|${_CALC}`;
export const ANGLE = 'deg|g?rad|turn';
export const LENGTH =
'[cm]m|[dls]?v(?:[bhiw]|max|min)|in|p[ctx]|q|r?(?:[cl]h|cap|e[mx]|ic)';
export const NUM = `[+-]?(?:${_DIGIT}(?:\\.\\d*)?|\\.\\d+)(?:e-?${_DIGIT})?`;
export const NUM_POSITIVE = `\\+?(?:${_DIGIT}(?:\\.\\d*)?|\\.\\d+)(?:e-?${_DIGIT})?`;
export const NONE = 'none';
export const PCT = `${NUM}%`;
export const SYN_FN_CALC = `^(?:${_CALC})\\(|(?<=[*\\/\\s\\(])(?:${_CALC})\\(`;
export const SYN_FN_MATH_START = `^(?:${_MATH})\\($`;
export const SYN_FN_VAR = '^var\\(|(?<=[*\\/\\s\\(])var\\(';
export const SYN_FN_VAR_START = `^(?:${_VAR})\\(`;
/* colors */
const _ALPHA = `(?:\\s*\\/\\s*(?:${NUM}|${PCT}|${NONE}))?`;
const _ALPHA_LV3 = `(?:\\s*,\\s*(?:${NUM}|${PCT}))?`;
const _COLOR_FUNC = '(?:ok)?l(?:ab|ch)|color|hsla?|hwb|rgba?';
const _COLOR_KEY = '[a-z]+|#[\\da-f]{3}|#[\\da-f]{4}|#[\\da-f]{6}|#[\\da-f]{8}';
const _CS_HUE = '(?:ok)?lch|hsl|hwb';
const _CS_HUE_ARC = '(?:de|in)creasing|longer|shorter';
const _NUM_ANGLE = `${NUM}(?:${ANGLE})?`;
const _NUM_ANGLE_NONE = `(?:${NUM}(?:${ANGLE})?|${NONE})`;
const _NUM_PCT_NONE = `(?:${NUM}|${PCT}|${NONE})`;
export const CS_HUE = `(?:${_CS_HUE})(?:\\s(?:${_CS_HUE_ARC})\\shue)?`;
export const CS_HUE_CAPT = `(${_CS_HUE})(?:\\s(${_CS_HUE_ARC})\\shue)?`;
export const CS_LAB = '(?:ok)?lab';
export const CS_LCH = '(?:ok)?lch';
export const CS_SRGB = 'srgb(?:-linear)?';
export const CS_RGB = `(?:a98|prophoto)-rgb|display-p3|rec2020|${CS_SRGB}`;
export const CS_XYZ = 'xyz(?:-d(?:50|65))?';
export const CS_RECT = `${CS_LAB}|${CS_RGB}|${CS_XYZ}`;
export const CS_MIX = `${CS_HUE}|${CS_RECT}`;
export const FN_COLOR = 'color(';
export const FN_LIGHT_DARK = 'light-dark(';
export const FN_MIX = 'color-mix(';
export const FN_REL = `(?:${_COLOR_FUNC})\\(\\s*from\\s+`;
export const FN_REL_CAPT = `(${_COLOR_FUNC})\\(\\s*from\\s+`;
export const FN_VAR = 'var(';
export const SYN_FN_COLOR = `(?:${CS_RGB}|${CS_XYZ})(?:\\s+${_NUM_PCT_NONE}){3}${_ALPHA}`;
export const SYN_FN_LIGHT_DARK = '^light-dark\\(';
export const SYN_FN_REL = `^${FN_REL}|(?<=[\\s])${FN_REL}`;
export const SYN_HSL = `${_NUM_ANGLE_NONE}(?:\\s+${_NUM_PCT_NONE}){2}${_ALPHA}`;
export const SYN_HSL_LV3 = `${_NUM_ANGLE}(?:\\s*,\\s*${PCT}){2}${_ALPHA_LV3}`;
export const SYN_LCH = `(?:${_NUM_PCT_NONE}\\s+){2}${_NUM_ANGLE_NONE}${_ALPHA}`;
export const SYN_MOD = `${_NUM_PCT_NONE}(?:\\s+${_NUM_PCT_NONE}){2}${_ALPHA}`;
export const SYN_RGB_LV3 = `(?:${NUM}(?:\\s*,\\s*${NUM}){2}|${PCT}(?:\\s*,\\s*${PCT}){2})${_ALPHA_LV3}`;
export const SYN_COLOR_TYPE = `${_COLOR_KEY}|hsla?\\(\\s*${SYN_HSL_LV3}\\s*\\)|rgba?\\(\\s*${SYN_RGB_LV3}\\s*\\)|(?:hsla?|hwb)\\(\\s*${SYN_HSL}\\s*\\)|(?:(?:ok)?lab|rgba?)\\(\\s*${SYN_MOD}\\s*\\)|(?:ok)?lch\\(\\s*${SYN_LCH}\\s*\\)|color\\(\\s*${SYN_FN_COLOR}\\s*\\)`;
export const SYN_MIX_PART = `(?:${SYN_COLOR_TYPE})(?:\\s+${PCT})?`;
export const SYN_MIX = `color-mix\\(\\s*in\\s+(?:${CS_MIX})\\s*,\\s*${SYN_MIX_PART}\\s*,\\s*${SYN_MIX_PART}\\s*\\)`;
export const SYN_MIX_CAPT = `color-mix\\(\\s*in\\s+(${CS_MIX})\\s*,\\s*(${SYN_MIX_PART})\\s*,\\s*(${SYN_MIX_PART})\\s*\\)`;
/* formats */
export const VAL_COMP = 'computedValue';
export const VAL_MIX = 'mixValue';
export const VAL_SPEC = 'specifiedValue';

View File

@@ -0,0 +1,469 @@
/**
* convert
*/
import {
CacheItem,
NullObject,
createCacheKey,
getCache,
setCache
} from './cache';
import {
convertColorToHsl,
convertColorToHwb,
convertColorToLab,
convertColorToLch,
convertColorToOklab,
convertColorToOklch,
convertColorToRgb,
numberToHexString,
parseColorFunc,
parseColorValue
} from './color';
import { isString } from './common';
import { cssCalc } from './css-calc';
import { resolveVar } from './css-var';
import { resolveRelativeColor } from './relative-color';
import { resolveColor } from './resolve';
import { ColorChannels, ComputedColorChannels, Options } from './typedef';
/* constants */
import { SYN_FN_CALC, SYN_FN_REL, SYN_FN_VAR, VAL_COMP } from './constant';
const NAMESPACE = 'convert';
/* regexp */
const REG_FN_CALC = new RegExp(SYN_FN_CALC);
const REG_FN_REL = new RegExp(SYN_FN_REL);
const REG_FN_VAR = new RegExp(SYN_FN_VAR);
/**
* pre process
* @param value - CSS color value
* @param [opt] - options
* @returns value
*/
export const preProcess = (
value: string,
opt: Options = {}
): string | NullObject => {
if (isString(value)) {
value = value.trim();
if (!value) {
return new NullObject();
}
} else {
return new NullObject();
}
const cacheKey: string = createCacheKey(
{
namespace: NAMESPACE,
name: 'preProcess',
value
},
opt
);
const cachedResult = getCache(cacheKey);
if (cachedResult instanceof CacheItem) {
if (cachedResult.isNull) {
return cachedResult as NullObject;
}
return cachedResult.item as string;
}
if (REG_FN_VAR.test(value)) {
const resolvedValue = resolveVar(value, opt);
if (isString(resolvedValue)) {
value = resolvedValue;
} else {
setCache(cacheKey, null);
return new NullObject();
}
}
if (REG_FN_REL.test(value)) {
const resolvedValue = resolveRelativeColor(value, opt);
if (isString(resolvedValue)) {
value = resolvedValue;
} else {
setCache(cacheKey, null);
return new NullObject();
}
} else if (REG_FN_CALC.test(value)) {
value = cssCalc(value, opt);
}
if (value.startsWith('color-mix')) {
const clonedOpt = structuredClone(opt);
clonedOpt.format = VAL_COMP;
clonedOpt.nullable = true;
const resolvedValue = resolveColor(value, clonedOpt);
setCache(cacheKey, resolvedValue);
return resolvedValue;
}
setCache(cacheKey, value);
return value;
};
/**
* convert number to hex string
* @param value - numeric value
* @returns hex string: 00..ff
*/
export const numberToHex = (value: number): string => {
const hex = numberToHexString(value);
return hex;
};
/**
* convert color to hex
* @param value - CSS color value
* @param [opt] - options
* @param [opt.alpha] - enable alpha channel
* @returns #rrggbb | #rrggbbaa | null
*/
export const colorToHex = (value: string, opt: Options = {}): string | null => {
if (isString(value)) {
const resolvedValue = preProcess(value, opt);
if (resolvedValue instanceof NullObject) {
return null;
}
value = resolvedValue.toLowerCase();
} else {
throw new TypeError(`${value} is not a string.`);
}
const { alpha = false } = opt;
const cacheKey: string = createCacheKey(
{
namespace: NAMESPACE,
name: 'colorToHex',
value
},
opt
);
const cachedResult = getCache(cacheKey);
if (cachedResult instanceof CacheItem) {
if (cachedResult.isNull) {
return null;
}
return cachedResult.item as string;
}
let hex;
opt.nullable = true;
if (alpha) {
opt.format = 'hexAlpha';
hex = resolveColor(value, opt);
} else {
opt.format = 'hex';
hex = resolveColor(value, opt);
}
if (isString(hex)) {
setCache(cacheKey, hex);
return hex;
}
setCache(cacheKey, null);
return null;
};
/**
* convert color to hsl
* @param value - CSS color value
* @param [opt] - options
* @returns ColorChannels - [h, s, l, alpha]
*/
export const colorToHsl = (value: string, opt: Options = {}): ColorChannels => {
if (isString(value)) {
const resolvedValue = preProcess(value, opt);
if (resolvedValue instanceof NullObject) {
return [0, 0, 0, 0];
}
value = resolvedValue.toLowerCase();
} else {
throw new TypeError(`${value} is not a string.`);
}
const cacheKey: string = createCacheKey(
{
namespace: NAMESPACE,
name: 'colorToHsl',
value
},
opt
);
const cachedResult = getCache(cacheKey);
if (cachedResult instanceof CacheItem) {
return cachedResult.item as ColorChannels;
}
opt.format = 'hsl';
const hsl = convertColorToHsl(value, opt) as ColorChannels;
setCache(cacheKey, hsl);
return hsl;
};
/**
* convert color to hwb
* @param value - CSS color value
* @param [opt] - options
* @returns ColorChannels - [h, w, b, alpha]
*/
export const colorToHwb = (value: string, opt: Options = {}): ColorChannels => {
if (isString(value)) {
const resolvedValue = preProcess(value, opt);
if (resolvedValue instanceof NullObject) {
return [0, 0, 0, 0];
}
value = resolvedValue.toLowerCase();
} else {
throw new TypeError(`${value} is not a string.`);
}
const cacheKey: string = createCacheKey(
{
namespace: NAMESPACE,
name: 'colorToHwb',
value
},
opt
);
const cachedResult = getCache(cacheKey);
if (cachedResult instanceof CacheItem) {
return cachedResult.item as ColorChannels;
}
opt.format = 'hwb';
const hwb = convertColorToHwb(value, opt) as ColorChannels;
setCache(cacheKey, hwb);
return hwb;
};
/**
* convert color to lab
* @param value - CSS color value
* @param [opt] - options
* @returns ColorChannels - [l, a, b, alpha]
*/
export const colorToLab = (value: string, opt: Options = {}): ColorChannels => {
if (isString(value)) {
const resolvedValue = preProcess(value, opt);
if (resolvedValue instanceof NullObject) {
return [0, 0, 0, 0];
}
value = resolvedValue.toLowerCase();
} else {
throw new TypeError(`${value} is not a string.`);
}
const cacheKey: string = createCacheKey(
{
namespace: NAMESPACE,
name: 'colorToLab',
value
},
opt
);
const cachedResult = getCache(cacheKey);
if (cachedResult instanceof CacheItem) {
return cachedResult.item as ColorChannels;
}
const lab = convertColorToLab(value, opt) as ColorChannels;
setCache(cacheKey, lab);
return lab;
};
/**
* convert color to lch
* @param value - CSS color value
* @param [opt] - options
* @returns ColorChannels - [l, c, h, alpha]
*/
export const colorToLch = (value: string, opt: Options = {}): ColorChannels => {
if (isString(value)) {
const resolvedValue = preProcess(value, opt);
if (resolvedValue instanceof NullObject) {
return [0, 0, 0, 0];
}
value = resolvedValue.toLowerCase();
} else {
throw new TypeError(`${value} is not a string.`);
}
const cacheKey: string = createCacheKey(
{
namespace: NAMESPACE,
name: 'colorToLch',
value
},
opt
);
const cachedResult = getCache(cacheKey);
if (cachedResult instanceof CacheItem) {
return cachedResult.item as ColorChannels;
}
const lch = convertColorToLch(value, opt) as ColorChannels;
setCache(cacheKey, lch);
return lch;
};
/**
* convert color to oklab
* @param value - CSS color value
* @param [opt] - options
* @returns ColorChannels - [l, a, b, alpha]
*/
export const colorToOklab = (
value: string,
opt: Options = {}
): ColorChannels => {
if (isString(value)) {
const resolvedValue = preProcess(value, opt);
if (resolvedValue instanceof NullObject) {
return [0, 0, 0, 0];
}
value = resolvedValue.toLowerCase();
} else {
throw new TypeError(`${value} is not a string.`);
}
const cacheKey: string = createCacheKey(
{
namespace: NAMESPACE,
name: 'colorToOklab',
value
},
opt
);
const cachedResult = getCache(cacheKey);
if (cachedResult instanceof CacheItem) {
return cachedResult.item as ColorChannels;
}
const lab = convertColorToOklab(value, opt) as ColorChannels;
setCache(cacheKey, lab);
return lab;
};
/**
* convert color to oklch
* @param value - CSS color value
* @param [opt] - options
* @returns ColorChannels - [l, c, h, alpha]
*/
export const colorToOklch = (
value: string,
opt: Options = {}
): ColorChannels => {
if (isString(value)) {
const resolvedValue = preProcess(value, opt);
if (resolvedValue instanceof NullObject) {
return [0, 0, 0, 0];
}
value = resolvedValue.toLowerCase();
} else {
throw new TypeError(`${value} is not a string.`);
}
const cacheKey: string = createCacheKey(
{
namespace: NAMESPACE,
name: 'colorToOklch',
value
},
opt
);
const cachedResult = getCache(cacheKey);
if (cachedResult instanceof CacheItem) {
return cachedResult.item as ColorChannels;
}
const lch = convertColorToOklch(value, opt) as ColorChannels;
setCache(cacheKey, lch);
return lch;
};
/**
* convert color to rgb
* @param value - CSS color value
* @param [opt] - options
* @returns ColorChannels - [r, g, b, alpha]
*/
export const colorToRgb = (value: string, opt: Options = {}): ColorChannels => {
if (isString(value)) {
const resolvedValue = preProcess(value, opt);
if (resolvedValue instanceof NullObject) {
return [0, 0, 0, 0];
}
value = resolvedValue.toLowerCase();
} else {
throw new TypeError(`${value} is not a string.`);
}
const cacheKey: string = createCacheKey(
{
namespace: NAMESPACE,
name: 'colorToRgb',
value
},
opt
);
const cachedResult = getCache(cacheKey);
if (cachedResult instanceof CacheItem) {
return cachedResult.item as ColorChannels;
}
const rgb = convertColorToRgb(value, opt) as ColorChannels;
setCache(cacheKey, rgb);
return rgb;
};
/**
* convert color to xyz
* @param value - CSS color value
* @param [opt] - options
* @returns ColorChannels - [x, y, z, alpha]
*/
export const colorToXyz = (value: string, opt: Options = {}): ColorChannels => {
if (isString(value)) {
const resolvedValue = preProcess(value, opt);
if (resolvedValue instanceof NullObject) {
return [0, 0, 0, 0];
}
value = resolvedValue.toLowerCase();
} else {
throw new TypeError(`${value} is not a string.`);
}
const cacheKey: string = createCacheKey(
{
namespace: NAMESPACE,
name: 'colorToXyz',
value
},
opt
);
const cachedResult = getCache(cacheKey);
if (cachedResult instanceof CacheItem) {
return cachedResult.item as ColorChannels;
}
let xyz;
if (value.startsWith('color(')) {
[, ...xyz] = parseColorFunc(value, opt) as ComputedColorChannels;
} else {
[, ...xyz] = parseColorValue(value, opt) as ComputedColorChannels;
}
setCache(cacheKey, xyz);
return xyz as ColorChannels;
};
/**
* convert color to xyz-d50
* @param value - CSS color value
* @param [opt] - options
* @returns ColorChannels - [x, y, z, alpha]
*/
export const colorToXyzD50 = (
value: string,
opt: Options = {}
): ColorChannels => {
opt.d50 = true;
return colorToXyz(value, opt);
};
/* convert */
export const convert = {
colorToHex,
colorToHsl,
colorToHwb,
colorToLab,
colorToLch,
colorToOklab,
colorToOklch,
colorToRgb,
colorToXyz,
colorToXyzD50,
numberToHex
};

View File

@@ -0,0 +1,955 @@
/**
* css-calc
*/
import { calc } from '@csstools/css-calc';
import { CSSToken, TokenType, tokenize } from '@csstools/css-tokenizer';
import {
CacheItem,
NullObject,
createCacheKey,
getCache,
setCache
} from './cache';
import { isString, isStringOrNumber } from './common';
import { resolveVar } from './css-var';
import { resolveLengthInPixels, roundToPrecision } from './util';
import { MatchedRegExp, Options } from './typedef';
/* constants */
import {
ANGLE,
LENGTH,
NUM,
SYN_FN_CALC,
SYN_FN_MATH_START,
SYN_FN_VAR,
SYN_FN_VAR_START,
VAL_SPEC
} from './constant';
const {
CloseParen: PAREN_CLOSE,
Comment: COMMENT,
Dimension: DIM,
EOF,
Function: FUNC,
OpenParen: PAREN_OPEN,
Whitespace: W_SPACE
} = TokenType;
const NAMESPACE = 'css-calc';
/* numeric constants */
const TRIA = 3;
const HEX = 16;
const MAX_PCT = 100;
/* regexp */
const REG_FN_CALC = new RegExp(SYN_FN_CALC);
const REG_FN_CALC_NUM = new RegExp(`^calc\\((${NUM})\\)$`);
const REG_FN_MATH_START = new RegExp(SYN_FN_MATH_START);
const REG_FN_VAR = new RegExp(SYN_FN_VAR);
const REG_FN_VAR_START = new RegExp(SYN_FN_VAR_START);
const REG_OPERATOR = /\s[*+/-]\s/;
const REG_TYPE_DIM = new RegExp(`^(${NUM})(${ANGLE}|${LENGTH})$`);
const REG_TYPE_DIM_PCT = new RegExp(`^(${NUM})(${ANGLE}|${LENGTH}|%)$`);
const REG_TYPE_PCT = new RegExp(`^(${NUM})%$`);
/**
* Calclator
*/
export class Calculator {
/* private */
// number
#hasNum: boolean;
#numSum: number[];
#numMul: number[];
// percentage
#hasPct: boolean;
#pctSum: number[];
#pctMul: number[];
// dimension
#hasDim: boolean;
#dimSum: string[];
#dimSub: string[];
#dimMul: string[];
#dimDiv: string[];
// et cetra
#hasEtc: boolean;
#etcSum: string[];
#etcSub: string[];
#etcMul: string[];
#etcDiv: string[];
/**
* constructor
*/
constructor() {
// number
this.#hasNum = false;
this.#numSum = [];
this.#numMul = [];
// percentage
this.#hasPct = false;
this.#pctSum = [];
this.#pctMul = [];
// dimension
this.#hasDim = false;
this.#dimSum = [];
this.#dimSub = [];
this.#dimMul = [];
this.#dimDiv = [];
// et cetra
this.#hasEtc = false;
this.#etcSum = [];
this.#etcSub = [];
this.#etcMul = [];
this.#etcDiv = [];
}
get hasNum() {
return this.#hasNum;
}
set hasNum(value: boolean) {
this.#hasNum = !!value;
}
get numSum() {
return this.#numSum;
}
get numMul() {
return this.#numMul;
}
get hasPct() {
return this.#hasPct;
}
set hasPct(value: boolean) {
this.#hasPct = !!value;
}
get pctSum() {
return this.#pctSum;
}
get pctMul() {
return this.#pctMul;
}
get hasDim() {
return this.#hasDim;
}
set hasDim(value: boolean) {
this.#hasDim = !!value;
}
get dimSum() {
return this.#dimSum;
}
get dimSub() {
return this.#dimSub;
}
get dimMul() {
return this.#dimMul;
}
get dimDiv() {
return this.#dimDiv;
}
get hasEtc() {
return this.#hasEtc;
}
set hasEtc(value: boolean) {
this.#hasEtc = !!value;
}
get etcSum() {
return this.#etcSum;
}
get etcSub() {
return this.#etcSub;
}
get etcMul() {
return this.#etcMul;
}
get etcDiv() {
return this.#etcDiv;
}
/**
* clear values
* @returns void
*/
clear() {
// number
this.#hasNum = false;
this.#numSum = [];
this.#numMul = [];
// percentage
this.#hasPct = false;
this.#pctSum = [];
this.#pctMul = [];
// dimension
this.#hasDim = false;
this.#dimSum = [];
this.#dimSub = [];
this.#dimMul = [];
this.#dimDiv = [];
// et cetra
this.#hasEtc = false;
this.#etcSum = [];
this.#etcSub = [];
this.#etcMul = [];
this.#etcDiv = [];
}
/**
* sort values
* @param values - values
* @returns sorted values
*/
sort(values: string[] = []): string[] {
const arr = [...values];
if (arr.length > 1) {
arr.sort((a, b) => {
let res;
if (REG_TYPE_DIM_PCT.test(a) && REG_TYPE_DIM_PCT.test(b)) {
const [, valA, unitA] = a.match(REG_TYPE_DIM_PCT) as MatchedRegExp;
const [, valB, unitB] = b.match(REG_TYPE_DIM_PCT) as MatchedRegExp;
if (unitA === unitB) {
if (Number(valA) === Number(valB)) {
res = 0;
} else if (Number(valA) > Number(valB)) {
res = 1;
} else {
res = -1;
}
} else if (unitA > unitB) {
res = 1;
} else {
res = -1;
}
} else {
if (a === b) {
res = 0;
} else if (a > b) {
res = 1;
} else {
res = -1;
}
}
return res;
});
}
return arr;
}
/**
* multiply values
* @returns resolved value
*/
multiply(): string {
const value = [];
let num;
if (this.#hasNum) {
num = 1;
for (const i of this.#numMul) {
num *= i;
if (num === 0 || !Number.isFinite(num) || Number.isNaN(num)) {
break;
}
}
if (!this.#hasPct && !this.#hasDim && !this.hasEtc) {
if (Number.isFinite(num)) {
num = roundToPrecision(num, HEX);
}
value.push(num);
}
}
if (this.#hasPct) {
if (typeof num !== 'number') {
num = 1;
}
for (const i of this.#pctMul) {
num *= i;
if (num === 0 || !Number.isFinite(num) || Number.isNaN(num)) {
break;
}
}
if (Number.isFinite(num)) {
num = `${roundToPrecision(num, HEX)}%`;
}
if (!this.#hasDim && !this.hasEtc) {
value.push(num);
}
}
if (this.#hasDim) {
let dim = '';
let mul = '';
let div = '';
if (this.#dimMul.length) {
if (this.#dimMul.length === 1) {
[mul] = this.#dimMul as [string];
} else {
mul = `${this.sort(this.#dimMul).join(' * ')}`;
}
}
if (this.#dimDiv.length) {
if (this.#dimDiv.length === 1) {
[div] = this.#dimDiv as [string];
} else {
div = `${this.sort(this.#dimDiv).join(' * ')}`;
}
}
if (Number.isFinite(num)) {
if (mul) {
if (div) {
if (div.includes('*')) {
dim = calc(`calc(${num} * ${mul} / (${div}))`, {
toCanonicalUnits: true
});
} else {
dim = calc(`calc(${num} * ${mul} / ${div})`, {
toCanonicalUnits: true
});
}
} else {
dim = calc(`calc(${num} * ${mul})`, {
toCanonicalUnits: true
});
}
} else if (div.includes('*')) {
dim = calc(`calc(${num} / (${div}))`, {
toCanonicalUnits: true
});
} else {
dim = calc(`calc(${num} / ${div})`, {
toCanonicalUnits: true
});
}
value.push(dim.replace(/^calc/, ''));
} else {
if (!value.length && num !== undefined) {
value.push(num);
}
if (mul) {
if (div) {
if (div.includes('*')) {
dim = calc(`calc(${mul} / (${div}))`, {
toCanonicalUnits: true
});
} else {
dim = calc(`calc(${mul} / ${div})`, {
toCanonicalUnits: true
});
}
} else {
dim = calc(`calc(${mul})`, {
toCanonicalUnits: true
});
}
if (value.length) {
value.push('*', dim.replace(/^calc/, ''));
} else {
value.push(dim.replace(/^calc/, ''));
}
} else {
dim = calc(`calc(${div})`, {
toCanonicalUnits: true
});
if (value.length) {
value.push('/', dim.replace(/^calc/, ''));
} else {
value.push('1', '/', dim.replace(/^calc/, ''));
}
}
}
}
if (this.#hasEtc) {
if (this.#etcMul.length) {
if (!value.length && num !== undefined) {
value.push(num);
}
const mul = this.sort(this.#etcMul).join(' * ');
if (value.length) {
value.push(`* ${mul}`);
} else {
value.push(`${mul}`);
}
}
if (this.#etcDiv.length) {
const div = this.sort(this.#etcDiv).join(' * ');
if (div.includes('*')) {
if (value.length) {
value.push(`/ (${div})`);
} else {
value.push(`1 / (${div})`);
}
} else if (value.length) {
value.push(`/ ${div}`);
} else {
value.push(`1 / ${div}`);
}
}
}
if (value.length) {
return value.join(' ');
}
return '';
}
/**
* sum values
* @returns resolved value
*/
sum(): string {
const value = [];
if (this.#hasNum) {
let num = 0;
for (const i of this.#numSum) {
num += i;
if (!Number.isFinite(num) || Number.isNaN(num)) {
break;
}
}
value.push(num);
}
if (this.#hasPct) {
let num: number | string = 0;
for (const i of this.#pctSum) {
num += i;
if (!Number.isFinite(num)) {
break;
}
}
if (Number.isFinite(num)) {
num = `${num}%`;
}
if (value.length) {
value.push(`+ ${num}`);
} else {
value.push(num);
}
}
if (this.#hasDim) {
let dim, sum, sub;
if (this.#dimSum.length) {
sum = this.sort(this.#dimSum).join(' + ');
}
if (this.#dimSub.length) {
sub = this.sort(this.#dimSub).join(' + ');
}
if (sum) {
if (sub) {
if (sub.includes('-')) {
dim = calc(`calc(${sum} - (${sub}))`, {
toCanonicalUnits: true
});
} else {
dim = calc(`calc(${sum} - ${sub})`, {
toCanonicalUnits: true
});
}
} else {
dim = calc(`calc(${sum})`, {
toCanonicalUnits: true
});
}
} else {
dim = calc(`calc(-1 * (${sub}))`, {
toCanonicalUnits: true
});
}
if (value.length) {
value.push('+', dim.replace(/^calc/, ''));
} else {
value.push(dim.replace(/^calc/, ''));
}
}
if (this.#hasEtc) {
if (this.#etcSum.length) {
const sum = this.sort(this.#etcSum)
.map(item => {
let res;
if (
REG_OPERATOR.test(item) &&
!item.startsWith('(') &&
!item.endsWith(')')
) {
res = `(${item})`;
} else {
res = item;
}
return res;
})
.join(' + ');
if (value.length) {
if (this.#etcSum.length > 1) {
value.push(`+ (${sum})`);
} else {
value.push(`+ ${sum}`);
}
} else {
value.push(`${sum}`);
}
}
if (this.#etcSub.length) {
const sub = this.sort(this.#etcSub)
.map(item => {
let res;
if (
REG_OPERATOR.test(item) &&
!item.startsWith('(') &&
!item.endsWith(')')
) {
res = `(${item})`;
} else {
res = item;
}
return res;
})
.join(' + ');
if (value.length) {
if (this.#etcSub.length > 1) {
value.push(`- (${sub})`);
} else {
value.push(`- ${sub}`);
}
} else if (this.#etcSub.length > 1) {
value.push(`-1 * (${sub})`);
} else {
value.push(`-1 * ${sub}`);
}
}
}
if (value.length) {
return value.join(' ');
}
return '';
}
}
/**
* sort calc values
* @param values - values to sort
* @param [finalize] - finalize values
* @returns sorted values
*/
export const sortCalcValues = (
values: (number | string)[] = [],
finalize: boolean = false
): string => {
if (values.length < TRIA) {
throw new Error(`Unexpected array length ${values.length}.`);
}
const start = values.shift();
if (!isString(start) || !start.endsWith('(')) {
throw new Error(`Unexpected token ${start}.`);
}
const end = values.pop();
if (end !== ')') {
throw new Error(`Unexpected token ${end}.`);
}
if (values.length === 1) {
const [value] = values;
if (!isStringOrNumber(value)) {
throw new Error(`Unexpected token ${value}.`);
}
return `${start}${value}${end}`;
}
const sortedValues = [];
const cal = new Calculator();
let operator: string = '';
const l = values.length;
for (let i = 0; i < l; i++) {
const value = values[i];
if (!isStringOrNumber(value)) {
throw new Error(`Unexpected token ${value}.`);
}
if (value === '*' || value === '/') {
operator = value;
} else if (value === '+' || value === '-') {
const sortedValue = cal.multiply();
if (sortedValue) {
sortedValues.push(sortedValue, value);
}
cal.clear();
operator = '';
} else {
const numValue = Number(value);
const strValue = `${value}`;
switch (operator) {
case '/': {
if (Number.isFinite(numValue)) {
cal.hasNum = true;
cal.numMul.push(1 / numValue);
} else if (REG_TYPE_PCT.test(strValue)) {
const [, val] = strValue.match(REG_TYPE_PCT) as MatchedRegExp;
cal.hasPct = true;
cal.pctMul.push((MAX_PCT * MAX_PCT) / Number(val));
} else if (REG_TYPE_DIM.test(strValue)) {
cal.hasDim = true;
cal.dimDiv.push(strValue);
} else {
cal.hasEtc = true;
cal.etcDiv.push(strValue);
}
break;
}
case '*':
default: {
if (Number.isFinite(numValue)) {
cal.hasNum = true;
cal.numMul.push(numValue);
} else if (REG_TYPE_PCT.test(strValue)) {
const [, val] = strValue.match(REG_TYPE_PCT) as MatchedRegExp;
cal.hasPct = true;
cal.pctMul.push(Number(val));
} else if (REG_TYPE_DIM.test(strValue)) {
cal.hasDim = true;
cal.dimMul.push(strValue);
} else {
cal.hasEtc = true;
cal.etcMul.push(strValue);
}
}
}
}
if (i === l - 1) {
const sortedValue = cal.multiply();
if (sortedValue) {
sortedValues.push(sortedValue);
}
cal.clear();
operator = '';
}
}
let resolvedValue = '';
if (finalize && (sortedValues.includes('+') || sortedValues.includes('-'))) {
const finalizedValues = [];
cal.clear();
operator = '';
const l = sortedValues.length;
for (let i = 0; i < l; i++) {
const value = sortedValues[i];
if (isStringOrNumber(value)) {
if (value === '+' || value === '-') {
operator = value;
} else {
const numValue = Number(value);
const strValue = `${value}`;
switch (operator) {
case '-': {
if (Number.isFinite(numValue)) {
cal.hasNum = true;
cal.numSum.push(-1 * numValue);
} else if (REG_TYPE_PCT.test(strValue)) {
const [, val] = strValue.match(REG_TYPE_PCT) as MatchedRegExp;
cal.hasPct = true;
cal.pctSum.push(-1 * Number(val));
} else if (REG_TYPE_DIM.test(strValue)) {
cal.hasDim = true;
cal.dimSub.push(strValue);
} else {
cal.hasEtc = true;
cal.etcSub.push(strValue);
}
break;
}
case '+':
default: {
if (Number.isFinite(numValue)) {
cal.hasNum = true;
cal.numSum.push(numValue);
} else if (REG_TYPE_PCT.test(strValue)) {
const [, val] = strValue.match(REG_TYPE_PCT) as MatchedRegExp;
cal.hasPct = true;
cal.pctSum.push(Number(val));
} else if (REG_TYPE_DIM.test(strValue)) {
cal.hasDim = true;
cal.dimSum.push(strValue);
} else {
cal.hasEtc = true;
cal.etcSum.push(strValue);
}
}
}
}
}
if (i === l - 1) {
const sortedValue = cal.sum();
if (sortedValue) {
finalizedValues.push(sortedValue);
}
cal.clear();
operator = '';
}
}
resolvedValue = finalizedValues.join(' ').replace(/\+\s-/g, '- ');
} else {
resolvedValue = sortedValues.join(' ').replace(/\+\s-/g, '- ');
}
if (
resolvedValue.startsWith('(') &&
resolvedValue.endsWith(')') &&
resolvedValue.lastIndexOf('(') === 0 &&
resolvedValue.indexOf(')') === resolvedValue.length - 1
) {
resolvedValue = resolvedValue.replace(/^\(/, '').replace(/\)$/, '');
}
return `${start}${resolvedValue}${end}`;
};
/**
* serialize calc
* @param value - CSS value
* @param [opt] - options
* @returns serialized value
*/
export const serializeCalc = (value: string, opt: Options = {}): string => {
const { format = '' } = opt;
if (isString(value)) {
if (!REG_FN_VAR_START.test(value) || format !== VAL_SPEC) {
return value;
}
value = value.toLowerCase().trim();
} else {
throw new TypeError(`${value} is not a string.`);
}
const cacheKey: string = createCacheKey(
{
namespace: NAMESPACE,
name: 'serializeCalc',
value
},
opt
);
const cachedResult = getCache(cacheKey);
if (cachedResult instanceof CacheItem) {
return cachedResult.item as string;
}
const items: string[] = tokenize({ css: value })
.map((token: CSSToken): string => {
const [type, value] = token as [TokenType, string];
let res = '';
if (type !== W_SPACE && type !== COMMENT) {
res = value;
}
return res;
})
.filter(v => v);
let startIndex = items.findLastIndex((item: string) => /\($/.test(item));
while (startIndex) {
const endIndex = items.findIndex((item: unknown, index: number) => {
return item === ')' && index > startIndex;
});
const slicedValues: string[] = items.slice(startIndex, endIndex + 1);
let serializedValue: string = sortCalcValues(slicedValues);
if (REG_FN_VAR_START.test(serializedValue)) {
serializedValue = calc(serializedValue, {
toCanonicalUnits: true
});
}
items.splice(startIndex, endIndex - startIndex + 1, serializedValue);
startIndex = items.findLastIndex((item: string) => /\($/.test(item));
}
const serializedCalc = sortCalcValues(items, true);
setCache(cacheKey, serializedCalc);
return serializedCalc;
};
/**
* resolve dimension
* @param token - CSS token
* @param [opt] - options
* @returns resolved value
*/
export const resolveDimension = (
token: CSSToken,
opt: Options = {}
): string | NullObject => {
if (!Array.isArray(token)) {
throw new TypeError(`${token} is not an array.`);
}
const [, , , , detail = {}] = token;
const { unit, value } = detail as {
unit: string;
value: number;
};
if (unit === 'px') {
return `${value}${unit}`;
}
const pixelValue = resolveLengthInPixels(Number(value), unit, opt);
if (Number.isFinite(pixelValue)) {
return `${roundToPrecision(pixelValue, HEX)}px`;
}
return new NullObject();
};
/**
* parse tokens
* @param tokens - CSS tokens
* @param [opt] - options
* @returns parsed tokens
*/
export const parseTokens = (
tokens: CSSToken[],
opt: Options = {}
): string[] => {
if (!Array.isArray(tokens)) {
throw new TypeError(`${tokens} is not an array.`);
}
const { format = '' } = opt;
const mathFunc = new Set();
let nest = 0;
const res: string[] = [];
while (tokens.length) {
const token = tokens.shift();
if (!Array.isArray(token)) {
throw new TypeError(`${token} is not an array.`);
}
const [type = '', value = ''] = token as [TokenType, string];
switch (type) {
case DIM: {
if (format === VAL_SPEC && !mathFunc.has(nest)) {
res.push(value);
} else {
const resolvedValue = resolveDimension(token, opt);
if (isString(resolvedValue)) {
res.push(resolvedValue);
} else {
res.push(value);
}
}
break;
}
case FUNC:
case PAREN_OPEN: {
res.push(value);
nest++;
if (REG_FN_MATH_START.test(value)) {
mathFunc.add(nest);
}
break;
}
case PAREN_CLOSE: {
if (res.length) {
const lastValue = res[res.length - 1];
if (lastValue === ' ') {
res.splice(-1, 1, value);
} else {
res.push(value);
}
} else {
res.push(value);
}
if (mathFunc.has(nest)) {
mathFunc.delete(nest);
}
nest--;
break;
}
case W_SPACE: {
if (res.length) {
const lastValue = res[res.length - 1];
if (
isString(lastValue) &&
!lastValue.endsWith('(') &&
lastValue !== ' '
) {
res.push(value);
}
}
break;
}
default: {
if (type !== COMMENT && type !== EOF) {
res.push(value);
}
}
}
}
return res;
};
/**
* CSS calc()
* @param value - CSS value including calc()
* @param [opt] - options
* @returns resolved value
*/
export const cssCalc = (value: string, opt: Options = {}): string => {
const { format = '' } = opt;
if (isString(value)) {
if (REG_FN_VAR.test(value)) {
if (format === VAL_SPEC) {
return value;
} else {
const resolvedValue = resolveVar(value, opt);
if (isString(resolvedValue)) {
return resolvedValue;
} else {
return '';
}
}
} else if (!REG_FN_CALC.test(value)) {
return value;
}
value = value.toLowerCase().trim();
} else {
throw new TypeError(`${value} is not a string.`);
}
const cacheKey: string = createCacheKey(
{
namespace: NAMESPACE,
name: 'cssCalc',
value
},
opt
);
const cachedResult = getCache(cacheKey);
if (cachedResult instanceof CacheItem) {
return cachedResult.item as string;
}
const tokens = tokenize({ css: value });
const values = parseTokens(tokens, opt);
let resolvedValue: string = calc(values.join(''), {
toCanonicalUnits: true
});
if (REG_FN_VAR_START.test(value)) {
if (REG_TYPE_DIM_PCT.test(resolvedValue)) {
const [, val, unit] = resolvedValue.match(
REG_TYPE_DIM_PCT
) as MatchedRegExp;
resolvedValue = `${roundToPrecision(Number(val), HEX)}${unit}`;
}
// wrap with `calc()`
if (
resolvedValue &&
!REG_FN_VAR_START.test(resolvedValue) &&
format === VAL_SPEC
) {
resolvedValue = `calc(${resolvedValue})`;
}
}
if (format === VAL_SPEC) {
if (/\s[-+*/]\s/.test(resolvedValue) && !resolvedValue.includes('NaN')) {
resolvedValue = serializeCalc(resolvedValue, opt);
} else if (REG_FN_CALC_NUM.test(resolvedValue)) {
const [, val] = resolvedValue.match(REG_FN_CALC_NUM) as MatchedRegExp;
resolvedValue = `calc(${roundToPrecision(Number(val), HEX)})`;
}
}
setCache(cacheKey, resolvedValue);
return resolvedValue;
};

Some files were not shown because too many files have changed in this diff Show More