Add WhitespaceUtils (#13923)
This commit is contained in:
1 parent
3662619f6f
commit
595a2beebc
8 files changed
+298
-69
No files matched your search
@@ -1,3 +1,5 @@
|
||||
import htmlWhitespaceUtils from "../utils/html-whitespace-utils.js";
|
||||
|
||||
function clean(ast, newNode /*, parent*/) {
|
||||
// (Glimmer/HTML) ignore TextNode
|
||||
if (ast.type === "TextNode") {
|
||||
@@ -5,7 +7,7 @@ function clean(ast, newNode /*, parent*/) {
|
||||
if (!trimmed) {
|
||||
return null;
|
||||
}
|
||||
newNode.chars = trimmed.replaceAll(/[\t\n\f\r ]+/g, " ");
|
||||
newNode.chars = htmlWhitespaceUtils.split(trimmed).join(" ");
|
||||
}
|
||||
|
||||
// `class` is reformatted
|
||||
|
||||
@@ -13,6 +13,7 @@ import { replaceEndOfLine } from "../document/utils.js";
|
||||
import getPreferredQuote from "../utils/get-preferred-quote.js";
|
||||
import isNonEmptyArray from "../utils/is-non-empty-array.js";
|
||||
import UnexpectedNodeError from "../utils/unexpected-node-error.js";
|
||||
import htmlWhitespaceUtils from "../utils/html-whitespace-utils.js";
|
||||
import { locStart, locEnd } from "./loc.js";
|
||||
import clean from "./clean.js";
|
||||
import { hasPrettierIgnore, isVoidElement, isWhitespaceNode } from "./utils.js";
|
||||
@@ -199,15 +200,10 @@ function print(path, options, print) {
|
||||
return replaceEndOfLine(text);
|
||||
}
|
||||
|
||||
const whitespacesOnlyRE = /^[\t\n\f\r ]*$/;
|
||||
const isWhitespaceOnly = whitespacesOnlyRE.test(text);
|
||||
const isWhitespaceOnly = htmlWhitespaceUtils.isWhitespaceOnly(text);
|
||||
const { isFirst, isLast } = path;
|
||||
|
||||
if (options.htmlWhitespaceSensitivity !== "ignore") {
|
||||
// https://infra.spec.whatwg.org/#ascii-whitespace
|
||||
const leadingWhitespacesRE = /^[\t\n\f\r ]*/;
|
||||
const trailingWhitespacesRE = /[\t\n\f\r ]*$/;
|
||||
|
||||
// let's remove the file's final newline
|
||||
// https://github.com/ember-cli/ember-new-output/blob/1a04c67ddd02ccb35e0ff41bb5cbce34b31173ef/.editorconfig#L16
|
||||
const shouldTrimTrailingNewlines =
|
||||
@@ -234,27 +230,29 @@ function print(path, options, print) {
|
||||
return breaks;
|
||||
}
|
||||
|
||||
const [lead] = text.match(leadingWhitespacesRE);
|
||||
const [tail] = text.match(trailingWhitespacesRE);
|
||||
const leadingWhitespace =
|
||||
htmlWhitespaceUtils.getLeadingWhitespace(text);
|
||||
|
||||
let leadBreaks = [];
|
||||
if (lead) {
|
||||
if (leadingWhitespace) {
|
||||
leadBreaks = [line];
|
||||
|
||||
const leadingNewlines = countNewLines(lead);
|
||||
const leadingNewlines = countNewLines(leadingWhitespace);
|
||||
if (leadingNewlines) {
|
||||
leadBreaks = generateHardlines(leadingNewlines);
|
||||
}
|
||||
|
||||
text = text.replace(leadingWhitespacesRE, "");
|
||||
text = text.slice(leadingWhitespace.length);
|
||||
}
|
||||
|
||||
const tailingWhitespace =
|
||||
htmlWhitespaceUtils.getTrailingWhitespace(text);
|
||||
let trailBreaks = [];
|
||||
if (tail) {
|
||||
if (tailingWhitespace) {
|
||||
if (!shouldTrimTrailingNewlines) {
|
||||
trailBreaks = [line];
|
||||
|
||||
const trailingNewlines = countNewLines(tail);
|
||||
const trailingNewlines = countNewLines(tailingWhitespace);
|
||||
if (trailingNewlines) {
|
||||
trailBreaks = generateHardlines(trailingNewlines);
|
||||
}
|
||||
@@ -264,7 +262,7 @@ function print(path, options, print) {
|
||||
}
|
||||
}
|
||||
|
||||
text = text.replace(trailingWhitespacesRE, "");
|
||||
text = text.slice(0, -tailingWhitespace.length);
|
||||
}
|
||||
|
||||
return [...leadBreaks, fill(getTextValueParts(text)), ...trailBreaks];
|
||||
@@ -334,9 +332,13 @@ function print(path, options, print) {
|
||||
trailingSpace = "";
|
||||
}
|
||||
|
||||
text = text
|
||||
.replaceAll(/^[\t\n\f\r ]+/g, leadingSpace)
|
||||
.replace(/[\t\n\f\r ]+$/, trailingSpace);
|
||||
if (htmlWhitespaceUtils.hasLeadingWhitespace(text)) {
|
||||
text = leadingSpace + htmlWhitespaceUtils.trimStart(text);
|
||||
}
|
||||
|
||||
if (htmlWhitespaceUtils.hasTrailingWhitespace(text)) {
|
||||
text = htmlWhitespaceUtils.trimEnd(text) + trailingSpace;
|
||||
}
|
||||
|
||||
return [
|
||||
...generateHardlines(leadingLineBreaksCount),
|
||||
@@ -643,11 +645,7 @@ function printInverse(path, print, options) {
|
||||
/* TextNode print helpers */
|
||||
|
||||
function getTextValueParts(value) {
|
||||
return join(line, splitByHtmlWhitespace(value));
|
||||
}
|
||||
|
||||
function splitByHtmlWhitespace(string) {
|
||||
return string.split(/[\t\n\f\r ]+/);
|
||||
return join(line, htmlWhitespaceUtils.split(value));
|
||||
}
|
||||
|
||||
function getCurrentAttributeName(path) {
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import { ParseSourceSpan } from "angular-html-parser/lib/compiler/src/parse_util.js";
|
||||
import htmlWhitespaceUtils from "../utils/html-whitespace-utils.js";
|
||||
import {
|
||||
htmlTrim,
|
||||
getLeadingAndTrailingHtmlWhitespace,
|
||||
hasHtmlWhitespace,
|
||||
canHaveInterpolation,
|
||||
getNodeCssStyleDisplay,
|
||||
isDanglingSpaceSensitiveNode,
|
||||
@@ -145,7 +144,7 @@ function mergeSimpleElementIntoText(ast /*, options */) {
|
||||
node.attrs.length === 0 &&
|
||||
node.children.length === 1 &&
|
||||
node.firstChild.type === "text" &&
|
||||
!hasHtmlWhitespace(node.children[0].value) &&
|
||||
!htmlWhitespaceUtils.hasWhitespaceCharacter(node.children[0].value) &&
|
||||
!node.firstChild.hasLeadingSpaces &&
|
||||
!node.firstChild.hasTrailingSpaces &&
|
||||
node.isLeadingSpaceSensitive &&
|
||||
@@ -264,7 +263,7 @@ function extractWhitespaces(ast /*, options*/) {
|
||||
node.children.length === 0 ||
|
||||
(node.children.length === 1 &&
|
||||
node.children[0].type === "text" &&
|
||||
htmlTrim(node.children[0].value).length === 0)
|
||||
htmlWhitespaceUtils.trim(node.children[0].value).length === 0)
|
||||
) {
|
||||
node.hasDanglingSpaces = node.children.length > 0;
|
||||
node.children = [];
|
||||
|
||||
@@ -12,30 +12,30 @@ import {
|
||||
CSS_WHITE_SPACE_TAGS,
|
||||
CSS_WHITE_SPACE_DEFAULT,
|
||||
} from "../constants.evaluate.js";
|
||||
import htmlWhitespaceUtils from "../../utils/html-whitespace-utils.js";
|
||||
import isUnknownNamespace from "./is-unknown-namespace.js";
|
||||
|
||||
// https://infra.spec.whatwg.org/#ascii-whitespace
|
||||
const HTML_WHITESPACE = new Set(["\t", "\n", "\f", "\r", " "]);
|
||||
const htmlTrimStart = (string) => string.replace(/^[\t\n\f\r ]+/, "");
|
||||
const htmlTrimEnd = (string) => string.replace(/[\t\n\f\r ]+$/, "");
|
||||
const htmlTrim = (string) => htmlTrimStart(htmlTrimEnd(string));
|
||||
const htmlTrimLeadingBlankLines = (string) =>
|
||||
string.replaceAll(/^[\t\f\r ]*\n/g, "");
|
||||
const htmlTrimPreserveIndentation = (string) =>
|
||||
htmlTrimLeadingBlankLines(htmlTrimEnd(string));
|
||||
const splitByHtmlWhitespace = (string) => string.split(/[\t\n\f\r ]+/);
|
||||
const getLeadingHtmlWhitespace = (string) => string.match(/^[\t\n\f\r ]*/)[0];
|
||||
htmlTrimLeadingBlankLines(htmlWhitespaceUtils.trimEnd(string));
|
||||
const getLeadingAndTrailingHtmlWhitespace = (string) => {
|
||||
const [, leadingWhitespace, text, trailingWhitespace] = string.match(
|
||||
/^([\t\n\f\r ]*)(.*?)([\t\n\f\r ]*)$/s
|
||||
);
|
||||
let text = string;
|
||||
const leadingWhitespace = htmlWhitespaceUtils.getLeadingWhitespace(text);
|
||||
if (leadingWhitespace) {
|
||||
text = text.slice(leadingWhitespace.length);
|
||||
}
|
||||
const trailingWhitespace = htmlWhitespaceUtils.getTrailingWhitespace(text);
|
||||
if (trailingWhitespace) {
|
||||
text = text.slice(0, -trailingWhitespace.length);
|
||||
}
|
||||
|
||||
return {
|
||||
leadingWhitespace,
|
||||
trailingWhitespace,
|
||||
text,
|
||||
};
|
||||
};
|
||||
const hasHtmlWhitespace = (string) => /[\t\n\f\r ]/.test(string);
|
||||
|
||||
function shouldPreserveContent(node, options) {
|
||||
// unterminated node in ie conditional comment
|
||||
@@ -513,12 +513,11 @@ function getMinIndentation(text) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!HTML_WHITESPACE.has(lineText[0])) {
|
||||
const indentation = htmlWhitespaceUtils.getLeadingWhitespaceCount(lineText);
|
||||
if (indentation === 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const indentation = getLeadingHtmlWhitespace(lineText).length;
|
||||
|
||||
if (lineText.length === indentation) {
|
||||
continue;
|
||||
}
|
||||
@@ -612,7 +611,7 @@ function getTextValueParts(node, value = node.value) {
|
||||
dedentString(htmlTrimPreserveIndentation(value)),
|
||||
hardline
|
||||
)
|
||||
: join(line, splitByHtmlWhitespace(value));
|
||||
: join(line, htmlWhitespaceUtils.split(value));
|
||||
}
|
||||
|
||||
function isVueScriptTag(node, options) {
|
||||
@@ -620,9 +619,7 @@ function isVueScriptTag(node, options) {
|
||||
}
|
||||
|
||||
export {
|
||||
htmlTrim,
|
||||
htmlTrimPreserveIndentation,
|
||||
hasHtmlWhitespace,
|
||||
getLeadingAndTrailingHtmlWhitespace,
|
||||
canHaveInterpolation,
|
||||
countChars,
|
||||
@@ -655,4 +652,5 @@ export {
|
||||
shouldPreserveContent,
|
||||
unescapeQuoteEntities,
|
||||
getTextValueParts,
|
||||
htmlWhitespaceUtils,
|
||||
};
|
||||
@@ -17,6 +17,7 @@ import {
|
||||
import { willBreak, replaceEndOfLine } from "../../document/utils.js";
|
||||
import UnexpectedNodeError from "../../utils/unexpected-node-error.js";
|
||||
import getPreferredQuote from "../../utils/get-preferred-quote.js";
|
||||
import WhitespaceUtils from "../../utils/whitespace-utils.js";
|
||||
import {
|
||||
isJsxElement,
|
||||
rawText,
|
||||
@@ -32,6 +33,16 @@ import {
|
||||
import pathNeedsParens from "../needs-parens.js";
|
||||
import { willPrintOwnComments } from "../comments/printer-methods.js";
|
||||
|
||||
/*
|
||||
Only the following are treated as whitespace inside JSX.
|
||||
|
||||
- U+0020 SPACE
|
||||
- U+000A LF
|
||||
- U+000D CR
|
||||
- U+0009 TAB
|
||||
*/
|
||||
const jsxWhitespaceUtils = new WhitespaceUtils(" \n\r\t");
|
||||
|
||||
const isEmptyStringOrAnyLine = (doc) =>
|
||||
doc === "" || doc === line || doc === hardline || doc === softline;
|
||||
|
||||
@@ -276,7 +287,10 @@ function printJsxChildren(
|
||||
|
||||
// Contains a non-whitespace character
|
||||
if (isMeaningfulJsxText(node)) {
|
||||
const words = text.split(matchJsxWhitespaceRegex);
|
||||
const words = jsxWhitespaceUtils.split(
|
||||
text,
|
||||
/* captureWhitespace */ true
|
||||
);
|
||||
|
||||
// Starts with whitespace
|
||||
if (words[0] === "") {
|
||||
@@ -356,9 +370,8 @@ function printJsxChildren(
|
||||
const directlyFollowedByMeaningfulText =
|
||||
next && isMeaningfulJsxText(next);
|
||||
if (directlyFollowedByMeaningfulText) {
|
||||
const firstWord = trimJsxWhitespace(rawText(next)).split(
|
||||
matchJsxWhitespaceRegex
|
||||
)[0];
|
||||
const trimmed = jsxWhitespaceUtils.trim(rawText(next));
|
||||
const [firstWord] = jsxWhitespaceUtils.split(trimmed);
|
||||
parts.push(
|
||||
separatorNoWhitespace(isFacebookTranslationTag, firstWord, node, next)
|
||||
);
|
||||
@@ -751,25 +764,6 @@ function printJsx(path, options, print) {
|
||||
}
|
||||
}
|
||||
|
||||
// Only space, newline, carriage return, and tab are treated as whitespace
|
||||
// inside JSX.
|
||||
const jsxWhitespaceChars = " \n\r\t";
|
||||
const matchJsxWhitespaceRegex = new RegExp("([" + jsxWhitespaceChars + "]+)");
|
||||
const containsNonJsxWhitespaceRegex = new RegExp(
|
||||
"[^" + jsxWhitespaceChars + "]"
|
||||
);
|
||||
const trimJsxWhitespace = (text) =>
|
||||
text.replace(
|
||||
new RegExp(
|
||||
"^" +
|
||||
matchJsxWhitespaceRegex.source +
|
||||
"|" +
|
||||
matchJsxWhitespaceRegex.source +
|
||||
"$"
|
||||
),
|
||||
""
|
||||
);
|
||||
|
||||
/**
|
||||
* @param {JSXElement} node
|
||||
* @returns {boolean}
|
||||
@@ -797,7 +791,7 @@ function isEmptyJsxElement(node) {
|
||||
function isMeaningfulJsxText(node) {
|
||||
return (
|
||||
node.type === "JSXText" &&
|
||||
(containsNonJsxWhitespaceRegex.test(rawText(node)) ||
|
||||
(jsxWhitespaceUtils.hasNonWhitespaceCharacter(rawText(node)) ||
|
||||
!/\n/.test(rawText(node)))
|
||||
);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
import WhitespaceUtils from "./whitespace-utils.js";
|
||||
|
||||
// https://infra.spec.whatwg.org/#ascii-whitespace
|
||||
const HTML_WHITESPACE_CHARACTERS = ["\t", "\n", "\f", "\r", " "];
|
||||
const htmlWhitespaceUtils = new WhitespaceUtils(HTML_WHITESPACE_CHARACTERS);
|
||||
|
||||
export default htmlWhitespaceUtils;
|
||||
@@ -0,0 +1,116 @@
|
||||
import escapeStringRegexp from "escape-string-regexp";
|
||||
|
||||
class WhitespaceUtils {
|
||||
#whitespaceCharacters;
|
||||
|
||||
constructor(whitespaceCharacters) {
|
||||
this.#whitespaceCharacters = new Set(whitespaceCharacters);
|
||||
|
||||
if (
|
||||
process.env.NODE_ENV !== "production" &&
|
||||
(this.#whitespaceCharacters.size === 0 ||
|
||||
Array.prototype.some.call(
|
||||
whitespaceCharacters,
|
||||
(character) => !/^\s$/.test(character)
|
||||
))
|
||||
) {
|
||||
throw new TypeError(
|
||||
`Invalid characters: ${JSON.stringify(whitespaceCharacters)}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
getLeadingWhitespaceCount(text) {
|
||||
const whitespaceCharacters = this.#whitespaceCharacters;
|
||||
let count = 0;
|
||||
|
||||
for (
|
||||
let index = 0;
|
||||
index < text.length && whitespaceCharacters.has(text.charAt(index));
|
||||
index++
|
||||
) {
|
||||
count++;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
getTrailingWhitespaceCount(text) {
|
||||
const whitespaceCharacters = this.#whitespaceCharacters;
|
||||
let count = 0;
|
||||
|
||||
for (
|
||||
let index = text.length - 1;
|
||||
index >= 0 && whitespaceCharacters.has(text.charAt(index));
|
||||
index--
|
||||
) {
|
||||
count++;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
getLeadingWhitespace(text) {
|
||||
const count = this.getLeadingWhitespaceCount(text);
|
||||
return text.slice(0, count);
|
||||
}
|
||||
|
||||
getTrailingWhitespace(text) {
|
||||
const count = this.getTrailingWhitespaceCount(text);
|
||||
return text.slice(text.length - count);
|
||||
}
|
||||
|
||||
hasLeadingWhitespace(text) {
|
||||
return this.#whitespaceCharacters.has(text.charAt(0));
|
||||
}
|
||||
|
||||
hasTrailingWhitespace(text) {
|
||||
return this.#whitespaceCharacters.has(text.at(-1));
|
||||
}
|
||||
|
||||
trimStart(text) {
|
||||
const count = this.getLeadingWhitespaceCount(text);
|
||||
return text.slice(count);
|
||||
}
|
||||
|
||||
trimEnd(text) {
|
||||
const count = this.getTrailingWhitespaceCount(text);
|
||||
return text.slice(0, text.length - count);
|
||||
}
|
||||
|
||||
trim(text) {
|
||||
return this.trimEnd(this.trimStart(text));
|
||||
}
|
||||
|
||||
split(text, captureWhitespace = false) {
|
||||
const pattern = `[${escapeStringRegexp(
|
||||
[...this.#whitespaceCharacters].join("")
|
||||
)}]+`;
|
||||
const regexp = new RegExp(captureWhitespace ? `(${pattern})` : pattern);
|
||||
return text.split(regexp);
|
||||
}
|
||||
|
||||
hasWhitespaceCharacter(text) {
|
||||
const whitespaceCharacters = this.#whitespaceCharacters;
|
||||
return Array.prototype.some.call(text, (character) =>
|
||||
whitespaceCharacters.has(character)
|
||||
);
|
||||
}
|
||||
|
||||
hasNonWhitespaceCharacter(text) {
|
||||
const whitespaceCharacters = this.#whitespaceCharacters;
|
||||
return Array.prototype.some.call(
|
||||
text,
|
||||
(character) => !whitespaceCharacters.has(character)
|
||||
);
|
||||
}
|
||||
|
||||
isWhitespaceOnly(text) {
|
||||
const whitespaceCharacters = this.#whitespaceCharacters;
|
||||
return Array.prototype.every.call(text, (character) =>
|
||||
whitespaceCharacters.has(character)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default WhitespaceUtils;
|
||||
@@ -0,0 +1,115 @@
|
||||
import WhitespaceUtils from "../../src/utils/whitespace-utils.js";
|
||||
|
||||
it("constructor", () => {
|
||||
expect(() => new WhitespaceUtils()).toThrow(TypeError);
|
||||
expect(() => new WhitespaceUtils(1)).toThrow(TypeError);
|
||||
expect(() => new WhitespaceUtils("")).toThrow(TypeError);
|
||||
expect(() => new WhitespaceUtils([])).toThrow(TypeError);
|
||||
expect(() => new WhitespaceUtils([""])).toThrow(TypeError);
|
||||
expect(() => new WhitespaceUtils(["a"])).toThrow(TypeError);
|
||||
expect(() => new WhitespaceUtils("a")).toThrow(TypeError);
|
||||
expect(() => new WhitespaceUtils(["\r\n"])).toThrow(TypeError);
|
||||
|
||||
expect(new WhitespaceUtils("\r\n")).toBeInstanceOf(WhitespaceUtils);
|
||||
expect(new WhitespaceUtils(["\r", "\n"])).toBeInstanceOf(WhitespaceUtils);
|
||||
});
|
||||
|
||||
const utils = new WhitespaceUtils(" ");
|
||||
describe("trimStart", () => {
|
||||
for (const [string, expected] of [
|
||||
["", ""],
|
||||
[" ", ""],
|
||||
[" ".repeat(3), ""],
|
||||
["a", "a"],
|
||||
["a" + " ".repeat(3), "a "],
|
||||
[" ".repeat(3) + "a", "a"],
|
||||
[" ".repeat(3) + "a" + " ".repeat(3), "a "],
|
||||
]) {
|
||||
it(JSON.stringify(string), () => {
|
||||
expect(utils.trimStart(string)).toBe(expected);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
describe("trimEnd", () => {
|
||||
for (const [string, expected] of [
|
||||
["", ""],
|
||||
[" ", ""],
|
||||
[" ".repeat(3), ""],
|
||||
["a", "a"],
|
||||
["a" + " ".repeat(3), "a"],
|
||||
[" ".repeat(3) + "a", " a"],
|
||||
[" ".repeat(3) + "a" + " ".repeat(3), " a"],
|
||||
]) {
|
||||
it(JSON.stringify(string), () => {
|
||||
expect(utils.trimEnd(string)).toBe(expected);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
describe("trim", () => {
|
||||
for (const [string, expected] of [
|
||||
["", ""],
|
||||
[" ", ""],
|
||||
[" ".repeat(3), ""],
|
||||
["a", "a"],
|
||||
["a" + " ".repeat(3), "a"],
|
||||
[" ".repeat(3) + "a", "a"],
|
||||
[" ".repeat(3) + "a" + " ".repeat(3), "a"],
|
||||
]) {
|
||||
it(JSON.stringify(string), () => {
|
||||
expect(utils.trim(string)).toBe(expected);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
describe("getLeadingWhitespaceCount", () => {
|
||||
for (const [string, expected] of [
|
||||
["", 0],
|
||||
[" ", 1],
|
||||
[" ".repeat(3), 3],
|
||||
["a", 0],
|
||||
["a" + " ".repeat(3), 0],
|
||||
[" ".repeat(3) + "a", 3],
|
||||
[" ".repeat(3) + "a" + " ".repeat(3), 3],
|
||||
]) {
|
||||
it(JSON.stringify(string), () => {
|
||||
expect(utils.getLeadingWhitespaceCount(string)).toBe(expected);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
describe("getTrailingWhitespaceCount", () => {
|
||||
for (const [string, expected] of [
|
||||
["", 0],
|
||||
[" ", 1],
|
||||
[" ".repeat(3), 3],
|
||||
["a", 0],
|
||||
["a" + " ".repeat(3), 3],
|
||||
[" ".repeat(3) + "a", 0],
|
||||
[" ".repeat(3) + "a" + " ".repeat(3), 3],
|
||||
]) {
|
||||
it(JSON.stringify(string), () => {
|
||||
expect(utils.getTrailingWhitespaceCount(string)).toBe(expected);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
describe("split", () => {
|
||||
for (const string of [
|
||||
"",
|
||||
" ",
|
||||
" ".repeat(3),
|
||||
" a",
|
||||
" ".repeat(3) + "a",
|
||||
"a ",
|
||||
"a" + " ".repeat(3),
|
||||
" a ",
|
||||
" ".repeat(3) + "a" + " ".repeat(3),
|
||||
" a a a ",
|
||||
]) {
|
||||
it(JSON.stringify(string), () => {
|
||||
expect(utils.split(string)).toEqual(string.split(/ +/));
|
||||
});
|
||||
}
|
||||
});
|
||||
Reference in new issue
Block a user