123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167 |
- // 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) => {
- 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) => {
- 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;
- };
|