Skip to content

Commit

Permalink
feat: Add escapeAttribute and escapeText (#770)
Browse files Browse the repository at this point in the history
  • Loading branch information
fb55 authored Mar 30, 2022
1 parent e186f5b commit 3720a28
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 0 deletions.
12 changes: 12 additions & 0 deletions src/encode.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,3 +71,15 @@ describe("encodeNonAsciiHTML", () => {
"♒️♓️♈️♉️♊️♋️♌️♍️♎️♏️♐️♑️"
));
});

describe("escape HTML", () => {
it("should escape HTML attribute values", () =>
expect(entities.escapeAttribute('<a " attr > & value \u00a0!')).toBe(
"<a &quot; attr > &amp; value &nbsp;!"
));

it("should escape HTML text", () =>
expect(entities.escapeText('<a " text > & value \u00a0!')).toBe(
'&lt;a " text &gt; &amp; value &nbsp;!'
));
});
37 changes: 37 additions & 0 deletions src/encode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ const htmlReplacer = /[\t\n!-,./:-@[-`\f{-}$\x80-\uFFFF]/g;
const xmlReplacer = /["&'<>$\x80-\uFFFF]/g;
const xmlInvalidChars = /[&<>'"]/g;

const textReplacer = /[&<>\u00A0]/g;
const attrReplacer = /["&\u00A0]/g;

const xmlCodeMap = new Map([
[34, "&quot;"],
[38, "&amp;"],
Expand All @@ -12,6 +15,14 @@ const xmlCodeMap = new Map([
[62, "&gt;"],
]);

const htmlEscapeCodeMap = new Map([
[34, "&quot;"],
[38, "&amp;"],
[60, "&lt;"],
[62, "&gt;"],
[160, "&nbsp;"],
]);

/**
* Encodes all non-ASCII characters, as well as characters not valid in XML
* documents using XML entities.
Expand Down Expand Up @@ -108,3 +119,29 @@ export function escapeUTF8(data: string): string {

return result + data.substring(lastIdx);
}

/**
* Encodes all characters that have to be escaped in HTML attributes,
* following {@link https://html.spec.whatwg.org/multipage/parsing.html#escapingString}.
*
* @param data String to escape.
*/
export function escapeAttribute(data: string): string {
return data.replace(
attrReplacer,
(match) => htmlEscapeCodeMap.get(match.charCodeAt(0))!
);
}

/**
* Encodes all characters that have to be escaped in HTML text,
* following {@link https://html.spec.whatwg.org/multipage/parsing.html#escapingString}.
*
* @param data String to escape.
*/
export function escapeText(data: string): string {
return data.replace(
textReplacer,
(match) => htmlEscapeCodeMap.get(match.charCodeAt(0))!
);
}
16 changes: 16 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import {
escapeUTF8,
encodeHTML,
encodeNonAsciiHTML,
escapeAttribute,
escapeText,
} from "./encode";

/** The level of entities to support. */
Expand Down Expand Up @@ -39,6 +41,16 @@ export enum EncodingMode {
* characters that are not ASCII characters.
*/
Extensive,
/**
* Encode all characters that have to be escaped in HTML attributes,
* following {@link https://html.spec.whatwg.org/multipage/parsing.html#escapingString}.
*/
Attribute,
/**
* Encode all characters that have to be escaped in HTML text,
* following {@link https://html.spec.whatwg.org/multipage/parsing.html#escapingString}.
*/
Text,
}

export interface DecodingOptions {
Expand Down Expand Up @@ -136,6 +148,8 @@ export function encode(

// Mode `UTF8` just escapes XML entities
if (opts.mode === EncodingMode.UTF8) return escapeUTF8(data);
if (opts.mode === EncodingMode.Attribute) return escapeAttribute(data);
if (opts.mode === EncodingMode.Text) return escapeText(data);

if (opts.level === EntityLevel.HTML) {
if (opts.mode === EncodingMode.ASCII) {
Expand All @@ -155,6 +169,8 @@ export {
encodeNonAsciiHTML,
escape,
escapeUTF8,
escapeAttribute,
escapeText,
// Legacy aliases (deprecated)
encodeHTML as encodeHTML4,
encodeHTML as encodeHTML5,
Expand Down

0 comments on commit 3720a28

Please sign in to comment.