aboutsummaryrefslogtreecommitdiffstats
path: root/vanilla/node_modules/cssstyle/lib/utils/strings.js
diff options
context:
space:
mode:
authorAdam Mathes <adam@adammathes.com>2026-02-13 21:34:48 -0800
committerAdam Mathes <adam@adammathes.com>2026-02-13 21:34:48 -0800
commit76cb9c2a39d477a64824a985ade40507e3bbade1 (patch)
tree41e997aa9c6f538d3a136af61dae9424db2005a9 /vanilla/node_modules/cssstyle/lib/utils/strings.js
parent819a39a21ac992b1393244a4c283bbb125208c69 (diff)
downloadneko-76cb9c2a39d477a64824a985ade40507e3bbade1.tar.gz
neko-76cb9c2a39d477a64824a985ade40507e3bbade1.tar.bz2
neko-76cb9c2a39d477a64824a985ade40507e3bbade1.zip
feat(vanilla): add testing infrastructure and tests (NK-wjnczv)
Diffstat (limited to 'vanilla/node_modules/cssstyle/lib/utils/strings.js')
-rw-r--r--vanilla/node_modules/cssstyle/lib/utils/strings.js173
1 files changed, 173 insertions, 0 deletions
diff --git a/vanilla/node_modules/cssstyle/lib/utils/strings.js b/vanilla/node_modules/cssstyle/lib/utils/strings.js
new file mode 100644
index 0000000..c0227e0
--- /dev/null
+++ b/vanilla/node_modules/cssstyle/lib/utils/strings.js
@@ -0,0 +1,173 @@
+// Forked from https://github.com/jsdom/jsdom/blob/main/lib/jsdom/living/helpers/strings.js
+
+"use strict";
+
+// https://infra.spec.whatwg.org/#ascii-whitespace
+const asciiWhitespaceRe = /^[\t\n\f\r ]$/;
+exports.asciiWhitespaceRe = asciiWhitespaceRe;
+
+// https://infra.spec.whatwg.org/#ascii-lowercase
+exports.asciiLowercase = (s) => {
+ if (!/[^\x00-\x7f]/.test(s)) {
+ return s.toLowerCase();
+ }
+ const len = s.length;
+ const out = new Array(len);
+ for (let i = 0; i < len; i++) {
+ const code = s.charCodeAt(i);
+ // If the character is between 'A' (65) and 'Z' (90), convert using bitwise OR with 32
+ out[i] = code >= 65 && code <= 90 ? String.fromCharCode(code | 32) : s[i];
+ }
+ return out.join("");
+};
+
+// https://infra.spec.whatwg.org/#ascii-uppercase
+exports.asciiUppercase = (s) => {
+ if (!/[^\x00-\x7f]/.test(s)) {
+ return s.toUpperCase();
+ }
+ const len = s.length;
+ const out = new Array(len);
+ for (let i = 0; i < len; i++) {
+ const code = s.charCodeAt(i);
+ // If the character is between 'a' (97) and 'z' (122), convert using bitwise AND with ~32
+ out[i] = code >= 97 && code <= 122 ? String.fromCharCode(code & ~32) : s[i];
+ }
+ return out.join("");
+};
+
+// https://infra.spec.whatwg.org/#strip-newlines
+exports.stripNewlines = (s) => {
+ return s.replace(/[\n\r]+/g, "");
+};
+
+// https://infra.spec.whatwg.org/#strip-leading-and-trailing-ascii-whitespace
+exports.stripLeadingAndTrailingASCIIWhitespace = (s) => {
+ return s.replace(/^[ \t\n\f\r]+/, "").replace(/[ \t\n\f\r]+$/, "");
+};
+
+// https://infra.spec.whatwg.org/#strip-and-collapse-ascii-whitespace
+exports.stripAndCollapseASCIIWhitespace = (s) => {
+ return s
+ .replace(/[ \t\n\f\r]+/g, " ")
+ .replace(/^[ \t\n\f\r]+/, "")
+ .replace(/[ \t\n\f\r]+$/, "");
+};
+
+// https://html.spec.whatwg.org/multipage/infrastructure.html#valid-simple-colour
+exports.isValidSimpleColor = (s) => {
+ return /^#[a-fA-F\d]{6}$/.test(s);
+};
+
+// https://infra.spec.whatwg.org/#ascii-case-insensitive
+exports.asciiCaseInsensitiveMatch = (a, b) => {
+ if (a.length !== b.length) {
+ return false;
+ }
+
+ for (let i = 0; i < a.length; ++i) {
+ if ((a.charCodeAt(i) | 32) !== (b.charCodeAt(i) | 32)) {
+ return false;
+ }
+ }
+
+ return true;
+};
+
+// https://html.spec.whatwg.org/multipage/common-microsyntaxes.html#rules-for-parsing-integers
+// Error is represented as null.
+const parseInteger = (exports.parseInteger = (input) => {
+ // The implementation here is slightly different from the spec's. We want to use parseInt(), but parseInt() trims
+ // Unicode whitespace in addition to just ASCII ones, so we make sure that the trimmed prefix contains only ASCII
+ // whitespace ourselves.
+ const numWhitespace = input.length - input.trimStart().length;
+ if (/[^\t\n\f\r ]/.test(input.slice(0, numWhitespace))) {
+ return null;
+ }
+ // We don't allow hexadecimal numbers here.
+ // eslint-disable-next-line radix
+ const value = parseInt(input, 10);
+ if (Number.isNaN(value)) {
+ return null;
+ }
+ // parseInt() returns -0 for "-0". Normalize that here.
+ return value === 0 ? 0 : value;
+});
+
+// https://html.spec.whatwg.org/multipage/common-microsyntaxes.html#rules-for-parsing-non-negative-integers
+// Error is represented as null.
+exports.parseNonNegativeInteger = (input) => {
+ const value = parseInteger(input);
+ if (value === null) {
+ return null;
+ }
+ if (value < 0) {
+ return null;
+ }
+ return value;
+};
+
+// https://html.spec.whatwg.org/multipage/common-microsyntaxes.html#valid-floating-point-number
+const floatingPointNumRe = /^-?(?:\d+|\d*\.\d+)(?:[eE][-+]?\d+)?$/;
+exports.isValidFloatingPointNumber = (str) => floatingPointNumRe.test(str);
+
+// https://html.spec.whatwg.org/multipage/common-microsyntaxes.html#rules-for-parsing-floating-point-number-values
+// Error is represented as null.
+exports.parseFloatingPointNumber = (str) => {
+ // The implementation here is slightly different from the spec's. We need to use parseFloat() in order to retain
+ // accuracy, but parseFloat() trims Unicode whitespace in addition to just ASCII ones, so we make sure that the
+ // trimmed prefix contains only ASCII whitespace ourselves.
+ const numWhitespace = str.length - str.trimStart().length;
+ if (/[^\t\n\f\r ]/.test(str.slice(0, numWhitespace))) {
+ return null;
+ }
+ const parsed = parseFloat(str);
+ return isFinite(parsed) ? parsed : null;
+};
+
+// https://infra.spec.whatwg.org/#split-on-ascii-whitespace
+exports.splitOnASCIIWhitespace = (str) => {
+ let position = 0;
+ const tokens = [];
+ while (position < str.length && asciiWhitespaceRe.test(str[position])) {
+ position++;
+ }
+ if (position === str.length) {
+ return tokens;
+ }
+ while (position < str.length) {
+ const start = position;
+ while (position < str.length && !asciiWhitespaceRe.test(str[position])) {
+ position++;
+ }
+ tokens.push(str.slice(start, position));
+ while (position < str.length && asciiWhitespaceRe.test(str[position])) {
+ position++;
+ }
+ }
+ return tokens;
+};
+
+// https://infra.spec.whatwg.org/#split-on-commas
+exports.splitOnCommas = (str) => {
+ let position = 0;
+ const tokens = [];
+ while (position < str.length) {
+ let start = position;
+ while (position < str.length && str[position] !== ",") {
+ position++;
+ }
+ let end = position;
+ while (start < str.length && asciiWhitespaceRe.test(str[start])) {
+ start++;
+ }
+ while (end > start && asciiWhitespaceRe.test(str[end - 1])) {
+ end--;
+ }
+ tokens.push(str.slice(start, end));
+ if (position < str.length) {
+ position++;
+ }
+ }
+ return tokens;
+};