Skip to content

Commit

Permalink
perf: improve sparse escape (#27)
Browse files Browse the repository at this point in the history
* improve escape

* escape

* improve escape

* add sparse escape

* improve branching

* start

* no unnecessary assignment

* use already created var
  • Loading branch information
gurgunday authored Aug 30, 2024
1 parent d7f9f79 commit 04c9b35
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 46 deletions.
4 changes: 4 additions & 0 deletions bench/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,10 @@ bench.add("mixed escaped and unescaped expressions", () => {
`;
});

bench.add("sparse escape", () => {
result = html`<p>${`${"noescape".repeat(250)}<>`.repeat(5)}</p>`;
});

await bench.warmup();
await bench.run();

Expand Down
90 changes: 44 additions & 46 deletions src/html.js
Original file line number Diff line number Diff line change
@@ -1,41 +1,41 @@
const escapeRegExp = /["&'<=>]/;
const escapeRegExp = /["&'<=>]/g;

const escapeFunction = (string) => {
if (!string || !escapeRegExp.test(string)) {
return string;
}

let escaped = "";
let start = 0;

for (let end = 0; end !== string.length; ++end) {
switch (string.charCodeAt(end)) {
do {
const i = escapeRegExp.lastIndex - 1;

switch (string.charCodeAt(i)) {
case 34: // "
escaped += string.slice(start, end) + "&#34;";
start = end + 1;
continue;
escaped += string.slice(start, i) + "&#34;";
break;
case 38: // &
escaped += string.slice(start, end) + "&#38;";
start = end + 1;
continue;
escaped += string.slice(start, i) + "&#38;";
break;
case 39: // '
escaped += string.slice(start, end) + "&#39;";
start = end + 1;
continue;
escaped += string.slice(start, i) + "&#39;";
break;
case 60: // <
escaped += string.slice(start, end) + "&#60;";
start = end + 1;
continue;
escaped += string.slice(start, i) + "&#60;";
break;
case 61: // =
escaped += string.slice(start, end) + "&#61;";
start = end + 1;
continue;
escaped += string.slice(start, i) + "&#61;";
break;
case 62: // >
escaped += string.slice(start, end) + "&#62;";
start = end + 1;
continue;
escaped += string.slice(start, i) + "&#62;";
break;
}
}

escaped += string.slice(start);
start = escapeRegExp.lastIndex;
} while (escapeRegExp.test(string));

return escaped;
return escaped + string.slice(start);
};

/**
Expand All @@ -59,16 +59,14 @@ export const html = ({ raw: literals }, ...expressions) => {

if (literal && literal.charCodeAt(literal.length - 1) === 33) {
literal = literal.slice(0, -1);
} else if (string && escapeRegExp.test(string)) {
} else {
string = escapeFunction(string);
}

accumulator += literal + string;
}

accumulator += literals[expressions.length];

return accumulator;
return accumulator + literals[expressions.length];
};

/**
Expand Down Expand Up @@ -120,11 +118,11 @@ export const htmlGenerator = function* ({ raw: literals }, ...expressions) {
string = `${expression}`;
}

if (string) {
if (!isRaw && escapeRegExp.test(string)) {
string = escapeFunction(string);
}
if (!isRaw) {
string = escapeFunction(string);
}

if (string) {
yield string;
}
}
Expand All @@ -135,11 +133,11 @@ export const htmlGenerator = function* ({ raw: literals }, ...expressions) {
string = `${expression}`;
}

if (string) {
if (!isRaw && escapeRegExp.test(string)) {
string = escapeFunction(string);
}
if (!isRaw) {
string = escapeFunction(string);
}

if (string) {
yield string;
}
}
Expand All @@ -152,7 +150,7 @@ export const htmlGenerator = function* ({ raw: literals }, ...expressions) {

if (literal && literal.charCodeAt(literal.length - 1) === 33) {
literal = literal.slice(0, -1);
} else if (string && escapeRegExp.test(string)) {
} else {
string = escapeFunction(string);
}

Expand Down Expand Up @@ -221,11 +219,11 @@ export const htmlAsyncGenerator = async function* (
string = `${expression}`;
}

if (string) {
if (!isRaw && escapeRegExp.test(string)) {
string = escapeFunction(string);
}
if (!isRaw) {
string = escapeFunction(string);
}

if (string) {
yield string;
}
}
Expand All @@ -236,11 +234,11 @@ export const htmlAsyncGenerator = async function* (
string = `${expression}`;
}

if (string) {
if (!isRaw && escapeRegExp.test(string)) {
string = escapeFunction(string);
}
if (!isRaw) {
string = escapeFunction(string);
}

if (string) {
yield string;
}
}
Expand All @@ -253,7 +251,7 @@ export const htmlAsyncGenerator = async function* (

if (literal && literal.charCodeAt(literal.length - 1) === 33) {
literal = literal.slice(0, -1);
} else if (string && escapeRegExp.test(string)) {
} else {
string = escapeFunction(string);
}

Expand Down

0 comments on commit 04c9b35

Please sign in to comment.