parse-entities
Advanced tools
Comparing version 2.0.0 to 3.0.0
@@ -1,24 +0,26 @@ | ||
'use strict' | ||
/* eslint-env browser */ | ||
var el | ||
var semicolon = 59 // `;` | ||
/** @type {HTMLElement} */ | ||
var element | ||
var semicolon = 59 // ';' | ||
module.exports = decodeEntity | ||
function decodeEntity(characters) { | ||
/** | ||
* @param {string} characters | ||
* @returns {string|false} | ||
*/ | ||
export function decodeEntity(characters) { | ||
var entity = '&' + characters + ';' | ||
/** @type {string} */ | ||
var char | ||
el = el || document.createElement('i') | ||
el.innerHTML = entity | ||
char = el.textContent | ||
element = element || document.createElement('i') | ||
element.innerHTML = entity | ||
char = element.textContent | ||
// Some entities do not require the closing semicolon (`¬` - for instance), | ||
// which leads to situations where parsing the assumed entity of ¬it; will | ||
// result in the string `¬it;`. When we encounter a trailing semicolon after | ||
// parsing and the entity to decode was not a semicolon (`;`), we can | ||
// assume that the matching was incomplete | ||
// which leads to situations where parsing the assumed entity of `¬it;` | ||
// will result in the string `¬it;`. | ||
// When we encounter a trailing semicolon after parsing and the entity to | ||
// decode was not a semicolon (`;`), we can assume that the matching was | ||
// incomplete | ||
if (char.charCodeAt(char.length - 1) === semicolon && characters !== 'semi') { | ||
@@ -25,0 +27,0 @@ return false |
@@ -1,10 +0,10 @@ | ||
'use strict' | ||
import {characterEntities} from 'character-entities' | ||
var characterEntities = require('character-entities') | ||
module.exports = decodeEntity | ||
var own = {}.hasOwnProperty | ||
function decodeEntity(characters) { | ||
/** | ||
* @param {string} characters | ||
* @returns {string|false} | ||
*/ | ||
export function decodeEntity(characters) { | ||
return own.call(characterEntities, characters) | ||
@@ -11,0 +11,0 @@ ? characterEntities[characters] |
483
index.js
@@ -1,172 +0,178 @@ | ||
'use strict' | ||
import {characterEntitiesLegacy} from 'character-entities-legacy' | ||
import {characterReferenceInvalid} from 'character-reference-invalid' | ||
import {isDecimal} from 'is-decimal' | ||
import {isHexadecimal} from 'is-hexadecimal' | ||
import {isAlphanumerical} from 'is-alphanumerical' | ||
import {decodeEntity} from './decode-entity.js' | ||
var legacy = require('character-entities-legacy') | ||
var invalid = require('character-reference-invalid') | ||
var decimal = require('is-decimal') | ||
var hexadecimal = require('is-hexadecimal') | ||
var alphanumerical = require('is-alphanumerical') | ||
var decodeEntity = require('./decode-entity') | ||
/** | ||
* @template {typeof globalThis} WarningContext | ||
* @template {typeof globalThis} ReferenceContext | ||
* @template {typeof globalThis} TextContext | ||
* @typedef {Object} ParseEntitiesOptions | ||
* @property {string} [additional=''] Additional character to accept. This allows other characters, without error, when following an ampersand | ||
* @property {boolean} [attribute=false] Whether to parse `value` as an attribute value | ||
* @property {boolean} [nonTerminated=true] Whether to allow non-terminated entities. For example, `©cat` for `©cat`. This behaviour is spec-compliant but can lead to unexpected results | ||
* @property {Position | Point} [position] Starting `position` of `value` (`Point` or `Position`). Useful when dealing with values nested in some sort of syntax tree | ||
* @property {WarningContext} warningContext Context used when calling `warning` | ||
* @property {WarningHandler<WarningContext>} warning Warning handler | ||
* @property {ReferenceContext} referenceContext Context used when calling `reference` | ||
* @property {ReferenceHandler<ReferenceContext>} reference Reference handler | ||
* @property {TextContext} textContext Context used when calling `text` | ||
* @property {TextHandler<TextContext>} text Text handler | ||
*/ | ||
module.exports = parseEntities | ||
/** | ||
* @typedef {Object} Position | ||
* @property {Point} start | ||
* @property {Point} [end] | ||
* @property {number[]} [indent] | ||
*/ | ||
var own = {}.hasOwnProperty | ||
var fromCharCode = String.fromCharCode | ||
var noop = Function.prototype | ||
/** | ||
* @typedef {Object} Point | ||
* @property {number} line | ||
* @property {number} column | ||
* @property {number} offset | ||
*/ | ||
// Default settings. | ||
var defaults = { | ||
warning: null, | ||
reference: null, | ||
text: null, | ||
warningContext: null, | ||
referenceContext: null, | ||
textContext: null, | ||
position: {}, | ||
additional: null, | ||
attribute: false, | ||
nonTerminated: true | ||
} | ||
/** | ||
* @template {typeof globalThis} Context | ||
* @callback WarningHandler | ||
* @this {Context} `this` refers to `warningContext` given to `parseEntities` | ||
* @param {string} reason Human-readable reason for triggering a parse error. | ||
* @param {Point} point Place at which the parse error occurred. | ||
* @param {number} code Identifier of reason for triggering a parse error. | ||
* @returns {void} | ||
*/ | ||
// Characters. | ||
var tab = 9 // '\t' | ||
var lineFeed = 10 // '\n' | ||
var formFeed = 12 // '\f' | ||
var space = 32 // ' ' | ||
var ampersand = 38 // '&' | ||
var semicolon = 59 // ';' | ||
var lessThan = 60 // '<' | ||
var equalsTo = 61 // '=' | ||
var numberSign = 35 // '#' | ||
var uppercaseX = 88 // 'X' | ||
var lowercaseX = 120 // 'x' | ||
var replacementCharacter = 65533 // '�' | ||
/** | ||
* @template {typeof globalThis} Context | ||
* @callback ReferenceHandler | ||
* @this {Context} `this` refers to `referenceContext` given to `parseEntities`. | ||
* @param {string} value String of content. | ||
* @param {Position} position Place at which `value` starts and ends. | ||
* @param {string} source Source of character reference. | ||
* @returns {void} | ||
*/ | ||
// Reference types. | ||
var name = 'named' | ||
var hexa = 'hexadecimal' | ||
var deci = 'decimal' | ||
/** | ||
* @template {typeof globalThis} Context | ||
* @callback TextHandler | ||
* @this {Context} `this` refers to `textContext` given to `parseEntities`. | ||
* @param {string} value String of content. | ||
* @param {Position} position Place at which `value` starts and ends. | ||
* @returns {void} | ||
*/ | ||
// Map of bases. | ||
var bases = {} | ||
var own = {}.hasOwnProperty | ||
var fromCharCode = String.fromCharCode | ||
bases[hexa] = 16 | ||
bases[deci] = 10 | ||
// Map of types to tests. | ||
// Each type of character reference accepts different characters. | ||
// This test is used to detect whether a reference has ended (as the semicolon | ||
// is not strictly needed). | ||
var tests = {} | ||
tests[name] = alphanumerical | ||
tests[deci] = decimal | ||
tests[hexa] = hexadecimal | ||
// Warning types. | ||
var namedNotTerminated = 1 | ||
var numericNotTerminated = 2 | ||
var namedEmpty = 3 | ||
var numericEmpty = 4 | ||
var namedUnknown = 5 | ||
var numericDisallowed = 6 | ||
var numericProhibited = 7 | ||
// Warning messages. | ||
var messages = {} | ||
messages[namedNotTerminated] = | ||
'Named character references must be terminated by a semicolon' | ||
messages[numericNotTerminated] = | ||
'Numeric character references must be terminated by a semicolon' | ||
messages[namedEmpty] = 'Named character references cannot be empty' | ||
messages[numericEmpty] = 'Numeric character references cannot be empty' | ||
messages[namedUnknown] = 'Named character references must be known' | ||
messages[numericDisallowed] = | ||
'Numeric character references cannot be disallowed' | ||
messages[numericProhibited] = | ||
var messages = [ | ||
undefined, | ||
/* 1: Non terminated (named) */ | ||
'Named character references must be terminated by a semicolon', | ||
/* 2: Non terminated (numeric) */ | ||
'Numeric character references must be terminated by a semicolon', | ||
/* 3: Empty (named) */ | ||
'Named character references cannot be empty', | ||
/* 4: Empty (numeric) */ | ||
'Numeric character references cannot be empty', | ||
/* 5: Unknown (named) */ | ||
'Named character references must be known', | ||
/* 6: Disallowed (numeric) */ | ||
'Numeric character references cannot be disallowed', | ||
/* 7: Prohibited (numeric) */ | ||
'Numeric character references cannot be outside the permissible Unicode range' | ||
] | ||
// Wrap to ensure clean parameters are given to `parse`. | ||
function parseEntities(value, options) { | ||
var settings = {} | ||
var option | ||
var key | ||
if (!options) { | ||
options = {} | ||
} | ||
for (key in defaults) { | ||
option = options[key] | ||
settings[key] = | ||
option === null || option === undefined ? defaults[key] : option | ||
} | ||
if (settings.position.indent || settings.position.start) { | ||
settings.indent = settings.position.indent || [] | ||
settings.position = settings.position.start | ||
} | ||
return parse(value, settings) | ||
} | ||
// Parse entities. | ||
// eslint-disable-next-line complexity | ||
function parse(value, settings) { | ||
var additional = settings.additional | ||
var nonTerminated = settings.nonTerminated | ||
var handleText = settings.text | ||
var handleReference = settings.reference | ||
var handleWarning = settings.warning | ||
var textContext = settings.textContext | ||
var referenceContext = settings.referenceContext | ||
var warningContext = settings.warningContext | ||
var pos = settings.position | ||
var indent = settings.indent || [] | ||
var length = value.length | ||
/** | ||
* Parse entities. | ||
* | ||
* @template {typeof globalThis} WarningContext | ||
* @template {typeof globalThis} ReferenceContext | ||
* @template {typeof globalThis} TextContext | ||
* @param {string} value | ||
* @param {Partial<ParseEntitiesOptions<WarningContext, ReferenceContext, TextContext>>} [options={}] | ||
*/ | ||
export function parseEntities(value, options = {}) { | ||
var additional = | ||
typeof options.additional === 'string' | ||
? options.additional.charCodeAt(0) | ||
: options.additional | ||
var index = 0 | ||
var lines = -1 | ||
var column = pos.column || 1 | ||
var line = pos.line || 1 | ||
var queue = '' | ||
/** @type {string[]} */ | ||
var result = [] | ||
/** @type {Point?} */ | ||
var pos | ||
/** @type {number[]?} */ | ||
var indent | ||
/** @type {number} */ | ||
var line | ||
/** @type {number} */ | ||
var column | ||
/** @type {string} */ | ||
var entityCharacters | ||
/** @type {string|false} */ | ||
var namedEntity | ||
/** @type {boolean} */ | ||
var terminated | ||
/** @type {string} */ | ||
var characters | ||
/** @type {number} */ | ||
var character | ||
/** @type {string} */ | ||
var reference | ||
/** @type {number} */ | ||
var referenceCode | ||
/** @type {number} */ | ||
var following | ||
var warning | ||
/** @type {number} */ | ||
var reason | ||
/** @type {string} */ | ||
var output | ||
/** @type {string} */ | ||
var entity | ||
/** @type {number} */ | ||
var begin | ||
/** @type {number} */ | ||
var start | ||
/** @type {string} */ | ||
var type | ||
/** @type {(code: number) => boolean} */ | ||
var test | ||
var prev | ||
/** @type {Point} */ | ||
var previous | ||
/** @type {Point} */ | ||
var next | ||
/** @type {number} */ | ||
var diff | ||
/** @type {number} */ | ||
var end | ||
if (typeof additional === 'string') { | ||
additional = additional.charCodeAt(0) | ||
if (options.position) { | ||
if ('start' in options.position || 'indent' in options.position) { | ||
indent = options.position.indent | ||
pos = options.position.start | ||
} else { | ||
pos = options.position | ||
} | ||
} | ||
line = (pos && pos.line) || 1 | ||
column = (pos && pos.column) || 1 | ||
// Cache the current point. | ||
prev = now() | ||
previous = now() | ||
// Wrap `handleWarning`. | ||
warning = handleWarning ? parseError : noop | ||
// Ensure the algorithm walks over the first character and the end | ||
// (inclusive). | ||
// Ensure the algorithm walks over the first character (inclusive). | ||
index-- | ||
length++ | ||
while (++index < length) { | ||
while (++index <= value.length) { | ||
// If the previous character was a newline. | ||
if (character === lineFeed) { | ||
column = indent[lines] || 1 | ||
if (character === 10 /* `\n` */) { | ||
column = (indent && indent[lines]) || 1 | ||
} | ||
@@ -176,14 +182,14 @@ | ||
if (character === ampersand) { | ||
if (character === 38 /* `&` */) { | ||
following = value.charCodeAt(index + 1) | ||
// The behaviour depends on the identity of the next character. | ||
// The behavior depends on the identity of the next character. | ||
if ( | ||
following === tab || | ||
following === lineFeed || | ||
following === formFeed || | ||
following === space || | ||
following === ampersand || | ||
following === lessThan || | ||
following !== following || | ||
following === 9 /* `\t` */ || | ||
following === 10 /* `\n` */ || | ||
following === 12 /* `\f` */ || | ||
following === 32 /* ` ` */ || | ||
following === 38 /* `&` */ || | ||
following === 60 /* `<` */ || | ||
Number.isNaN(following) || | ||
(additional && following === additional) | ||
@@ -196,3 +202,2 @@ ) { | ||
column++ | ||
continue | ||
@@ -205,20 +210,20 @@ } | ||
if (following === numberSign) { | ||
// Numerical entity. | ||
if (following === 35 /* `#` */) { | ||
// Numerical reference. | ||
end = ++begin | ||
// The behaviour further depends on the next character. | ||
// The behavior further depends on the next character. | ||
following = value.charCodeAt(end) | ||
if (following === uppercaseX || following === lowercaseX) { | ||
// ASCII hex digits. | ||
type = hexa | ||
if (following === 88 /* `X` */ || following === 120 /* `x` */) { | ||
// ASCII hexadecimal digits. | ||
type = 'hexadecimal' | ||
end = ++begin | ||
} else { | ||
// ASCII digits. | ||
type = deci | ||
// ASCII decimal digits. | ||
type = 'decimal' | ||
} | ||
} else { | ||
// Named entity. | ||
type = name | ||
type = 'named' | ||
} | ||
@@ -229,6 +234,15 @@ | ||
characters = '' | ||
test = tests[type] | ||
// Each type of character reference accepts different characters. | ||
// This test is used to detect whether a reference has ended (as the semicolon | ||
// is not strictly needed). | ||
test = | ||
type === 'named' | ||
? isAlphanumerical | ||
: type === 'decimal' | ||
? isDecimal | ||
: isHexadecimal | ||
end-- | ||
while (++end < length) { | ||
while (++end <= value.length) { | ||
following = value.charCodeAt(end) | ||
@@ -245,9 +259,9 @@ | ||
// This ensures we do not need to walk backwards later. | ||
if (type === name && own.call(legacy, characters)) { | ||
if (type === 'named' && own.call(characterEntitiesLegacy, characters)) { | ||
entityCharacters = characters | ||
entity = legacy[characters] | ||
entity = characterEntitiesLegacy[characters] | ||
} | ||
} | ||
terminated = value.charCodeAt(end) === semicolon | ||
terminated = value.charCodeAt(end) === 59 /* `;` */ | ||
@@ -257,3 +271,3 @@ if (terminated) { | ||
namedEntity = type === name ? decodeEntity(characters) : false | ||
namedEntity = type === 'named' ? decodeEntity(characters) : false | ||
@@ -268,15 +282,15 @@ if (namedEntity) { | ||
if (!terminated && !nonTerminated) { | ||
if (!terminated && options.nonTerminated === false) { | ||
// Empty. | ||
} else if (!characters) { | ||
// An empty (possible) entity is valid, unless it’s numeric (thus an | ||
// An empty (possible) reference is valid, unless it’s numeric (thus an | ||
// ampersand followed by an octothorp). | ||
if (type !== name) { | ||
warning(numericEmpty, diff) | ||
if (type !== 'named') { | ||
warning(4 /* Empty (numeric) */, diff) | ||
} | ||
} else if (type === name) { | ||
} else if (type === 'named') { | ||
// An ampersand followed by anything unknown, and not terminated, is | ||
// invalid. | ||
if (terminated && !entity) { | ||
warning(namedUnknown, 1) | ||
warning(5 /* Unknown (named) */, 1) | ||
} else { | ||
@@ -293,11 +307,13 @@ // If theres something after an entity name which is not known, cap | ||
if (!terminated) { | ||
reason = entityCharacters ? namedNotTerminated : namedEmpty | ||
reason = entityCharacters | ||
? 1 /* Non terminated (named) */ | ||
: 3 /* Empty (named) */ | ||
if (settings.attribute) { | ||
if (options.attribute) { | ||
following = value.charCodeAt(end) | ||
if (following === equalsTo) { | ||
if (following === 61 /* `=` */) { | ||
warning(reason, diff) | ||
entity = null | ||
} else if (alphanumerical(following)) { | ||
} else if (isAlphanumerical(following)) { | ||
entity = null | ||
@@ -316,20 +332,24 @@ } else { | ||
if (!terminated) { | ||
// All non-terminated numeric entities are not rendered, and trigger a | ||
// All non-terminated numeric references are not rendered, and emit a | ||
// warning. | ||
warning(numericNotTerminated, diff) | ||
warning(2 /* Non terminated (numeric) */, diff) | ||
} | ||
// When terminated and number, parse as either hexadecimal or decimal. | ||
reference = parseInt(characters, bases[type]) | ||
// When terminated and numerical, parse as either hexadecimal or | ||
// decimal. | ||
referenceCode = Number.parseInt( | ||
characters, | ||
type === 'hexadecimal' ? 16 : 10 | ||
) | ||
// Trigger a warning when the parsed number is prohibited, and replace | ||
// with replacement character. | ||
if (prohibited(reference)) { | ||
warning(numericProhibited, diff) | ||
reference = fromCharCode(replacementCharacter) | ||
} else if (reference in invalid) { | ||
// Trigger a warning when the parsed number is disallowed, and replace | ||
// by an alternative. | ||
warning(numericDisallowed, diff) | ||
reference = invalid[reference] | ||
// Emit a warning when the parsed number is prohibited, and replace with | ||
// replacement character. | ||
if (prohibited(referenceCode)) { | ||
warning(7 /* Prohibited (numeric) */, diff) | ||
reference = fromCharCode(65533 /* `�` */) | ||
} else if (referenceCode in characterReferenceInvalid) { | ||
// Emit a warning when the parsed number is disallowed, and replace by | ||
// an alternative. | ||
warning(6 /* Disallowed (numeric) */, diff) | ||
reference = characterReferenceInvalid[referenceCode] | ||
} else { | ||
@@ -339,15 +359,15 @@ // Parse the number. | ||
// Trigger a warning when the parsed number should not be used. | ||
if (disallowed(reference)) { | ||
warning(numericDisallowed, diff) | ||
// Emit a warning when the parsed number should not be used. | ||
if (disallowed(referenceCode)) { | ||
warning(6 /* Disallowed (numeric) */, diff) | ||
} | ||
// Stringify the number. | ||
if (reference > 0xffff) { | ||
reference -= 0x10000 | ||
output += fromCharCode((reference >>> (10 & 0x3ff)) | 0xd800) | ||
reference = 0xdc00 | (reference & 0x3ff) | ||
// Serialize the number. | ||
if (referenceCode > 0xffff) { | ||
referenceCode -= 0x10000 | ||
output += fromCharCode((referenceCode >>> (10 & 0x3ff)) | 0xd800) | ||
referenceCode = 0xdc00 | (referenceCode & 0x3ff) | ||
} | ||
reference = output + fromCharCode(reference) | ||
reference = output + fromCharCode(referenceCode) | ||
} | ||
@@ -357,7 +377,7 @@ } | ||
// Found it! | ||
// First eat the queued characters as normal text, then eat an entity. | ||
// First eat the queued characters as normal text, then eat a reference. | ||
if (reference) { | ||
flush() | ||
prev = now() | ||
previous = now() | ||
index = end - 1 | ||
@@ -369,7 +389,7 @@ column += end - start + 1 | ||
if (handleReference) { | ||
handleReference.call( | ||
referenceContext, | ||
if (options.reference) { | ||
options.reference.call( | ||
options.referenceContext, | ||
reference, | ||
{start: prev, end: next}, | ||
{start: previous, end: next}, | ||
value.slice(start - 1, end) | ||
@@ -379,3 +399,3 @@ ) | ||
prev = next | ||
previous = next | ||
} else { | ||
@@ -393,5 +413,3 @@ // If we could not find a reference, queue the checked characters (as | ||
// Handle anything other than an ampersand, including newlines and EOF. | ||
if ( | ||
character === 10 // Line feed | ||
) { | ||
if (character === 10 /* `\n` */) { | ||
line++ | ||
@@ -402,7 +420,7 @@ lines++ | ||
if (character === character) { | ||
if (Number.isNaN(character)) { | ||
flush() | ||
} else { | ||
queue += fromCharCode(character) | ||
column++ | ||
} else { | ||
flush() | ||
} | ||
@@ -418,21 +436,37 @@ } | ||
return { | ||
line: line, | ||
column: column, | ||
offset: index + (pos.offset || 0) | ||
line, | ||
column, | ||
offset: index + ((pos && pos.offset) || 0) | ||
} | ||
} | ||
// “Throw” a parse-error: a warning. | ||
function parseError(code, offset) { | ||
var position = now() | ||
/** | ||
* Handle the warning. | ||
* | ||
* @param {number} code | ||
* @param {number} offset | ||
*/ | ||
function warning(code, offset) { | ||
/** @type {Point} */ | ||
var position | ||
position.column += offset | ||
position.offset += offset | ||
if (options.warning) { | ||
position = now() | ||
position.column += offset | ||
position.offset += offset | ||
handleWarning.call(warningContext, messages[code], position, code) | ||
options.warning.call( | ||
options.warningContext, | ||
messages[code], | ||
position, | ||
code | ||
) | ||
} | ||
} | ||
// Flush `queue` (normal text). | ||
// Macro invoked before each entity and at the end of `value`. | ||
// Does nothing when `queue` is empty. | ||
/** | ||
* Flush `queue` (normal text). | ||
* Macro invoked before each reference and at the end of `value`. | ||
* Does nothing when `queue` is empty. | ||
*/ | ||
function flush() { | ||
@@ -442,4 +476,7 @@ if (queue) { | ||
if (handleText) { | ||
handleText.call(textContext, queue, {start: prev, end: now()}) | ||
if (options.text) { | ||
options.text.call(options.textContext, queue, { | ||
start: previous, | ||
end: now() | ||
}) | ||
} | ||
@@ -452,3 +489,8 @@ | ||
// Check if `character` is outside the permissible unicode range. | ||
/** | ||
* Check if `character` is outside the permissible unicode range. | ||
* | ||
* @param {number} code | ||
* @returns {boolean} | ||
*/ | ||
function prohibited(code) { | ||
@@ -458,3 +500,8 @@ return (code >= 0xd800 && code <= 0xdfff) || code > 0x10ffff | ||
// Check if `character` is disallowed. | ||
/** | ||
* Check if `character` is disallowed. | ||
* | ||
* @param {number} code | ||
* @returns {boolean} | ||
*/ | ||
function disallowed(code) { | ||
@@ -461,0 +508,0 @@ return ( |
{ | ||
"name": "parse-entities", | ||
"version": "2.0.0", | ||
"version": "3.0.0", | ||
"description": "Parse HTML character references: fast, spec-compliant, positional information", | ||
@@ -17,5 +17,5 @@ "license": "MIT", | ||
"funding": { | ||
"type": "github", | ||
"url": "https://github.com/sponsors/wooorm" | ||
}, | ||
"type": "github", | ||
"url": "https://github.com/sponsors/wooorm" | ||
}, | ||
"author": "Titus Wormer <tituswormer@gmail.com> (https://wooorm.com)", | ||
@@ -25,2 +25,6 @@ "contributors": [ | ||
], | ||
"sideEffects": false, | ||
"type": "module", | ||
"main": "index.js", | ||
"types": "types/index.d.ts", | ||
"browser": { | ||
@@ -34,44 +38,36 @@ "./decode-entity.js": "./decode-entity.browser.js" | ||
"index.js", | ||
"index.d.ts", | ||
"decode-entity.js", | ||
"decode-entity.d.ts", | ||
"decode-entity.browser.js", | ||
"types/index.d.ts" | ||
"decode-entity.browser.d.ts" | ||
], | ||
"types": "types/index.d.ts", | ||
"dependencies": { | ||
"character-entities": "^1.0.0", | ||
"character-entities-legacy": "^1.0.0", | ||
"character-reference-invalid": "^1.0.0", | ||
"is-alphanumerical": "^1.0.0", | ||
"is-decimal": "^1.0.0", | ||
"is-hexadecimal": "^1.0.0" | ||
"character-entities": "^2.0.0", | ||
"character-entities-legacy": "^2.0.0", | ||
"character-reference-invalid": "^2.0.0", | ||
"is-alphanumerical": "^2.0.0", | ||
"is-decimal": "^2.0.0", | ||
"is-hexadecimal": "^2.0.0" | ||
}, | ||
"devDependencies": { | ||
"browserify": "^16.0.0", | ||
"dtslint": "^2.0.0", | ||
"nyc": "^15.0.0", | ||
"prettier": "^1.0.0", | ||
"remark-cli": "^7.0.0", | ||
"remark-preset-wooorm": "^6.0.0", | ||
"tape": "^4.0.0", | ||
"tape-run": "^6.0.0", | ||
"tinyify": "^2.0.0", | ||
"xo": "^0.25.0" | ||
"@types/tape": "^4.0.0", | ||
"c8": "^7.0.0", | ||
"prettier": "^2.0.0", | ||
"remark-cli": "^9.0.0", | ||
"remark-preset-wooorm": "^8.0.0", | ||
"rimraf": "^3.0.0", | ||
"tape": "^5.0.0", | ||
"type-coverage": "^2.0.0", | ||
"typescript": "^4.0.0", | ||
"xo": "^0.38.0" | ||
}, | ||
"scripts": { | ||
"format": "remark . -qfo && prettier --write \"**/*.{js,ts}\" && xo --fix", | ||
"build-bundle": "browserify . -s parseEntities > parse-entities.js", | ||
"build-mangle": "browserify . -s parseEntities -p tinyify > parse-entities.min.js", | ||
"build": "npm run build-bundle && npm run build-mangle", | ||
"test-api": "node test", | ||
"test-coverage": "nyc --reporter lcov tape test.js", | ||
"test-browser": "browserify test.js | tape-run", | ||
"test-types": "dtslint types", | ||
"test": "npm run format && npm run build && npm run test-coverage && npm run test-types" | ||
"prepack": "npm run build && npm run format", | ||
"build": "rimraf \"*.d.ts\" && tsc && type-coverage", | ||
"format": "remark . -qfo && prettier . -w --loglevel warn && xo --fix", | ||
"test-api": "node test.js", | ||
"test-coverage": "c8 --check-coverage --branches 100 --functions 100 --lines 100 --statements 100 --reporter lcov node test.js", | ||
"test": "npm run build && npm run format && npm run test-coverage" | ||
}, | ||
"nyc": { | ||
"check-coverage": true, | ||
"lines": 100, | ||
"functions": 100, | ||
"branches": 100 | ||
}, | ||
"prettier": { | ||
@@ -87,11 +83,8 @@ "tabWidth": 2, | ||
"prettier": true, | ||
"esnext": false, | ||
"rules": { | ||
"no-self-compare": "off", | ||
"guard-for-in": "off", | ||
"max-depth": "off" | ||
}, | ||
"ignores": [ | ||
"parse-entities.js" | ||
] | ||
"complexity": "off", | ||
"max-depth": "off", | ||
"no-var": "off", | ||
"prefer-arrow-callback": "off" | ||
} | ||
}, | ||
@@ -102,3 +95,8 @@ "remarkConfig": { | ||
] | ||
}, | ||
"typeCoverage": { | ||
"atLeast": 100, | ||
"detail": true, | ||
"strict": true | ||
} | ||
} |
@@ -8,7 +8,9 @@ # parse-entities | ||
Parse HTML character references: fast, spec-compliant, positional | ||
information. | ||
Parse HTML character references: fast, spec-compliant, positional information. | ||
## Install | ||
This package is ESM only: Node 12+ is needed to use it and it must be `import`ed | ||
instead of `require`d. | ||
[npm][]: | ||
@@ -23,11 +25,11 @@ | ||
```js | ||
var decode = require('parse-entities') | ||
import {parseEntities} from 'parse-entities' | ||
decode('alpha & bravo') | ||
parseEntities('alpha & bravo') | ||
// => alpha & bravo | ||
decode('charlie ©cat; delta') | ||
parseEntities('charlie ©cat; delta') | ||
// => charlie ©cat; delta | ||
decode('echo © foxtrot ≠ golf 𝌆 hotel') | ||
parseEntities('echo © foxtrot ≠ golf 𝌆 hotel') | ||
// => echo © foxtrot ≠ golf 𝌆 hotel | ||
@@ -38,6 +40,7 @@ ``` | ||
This package exports the following identifiers: `parseEntities`. | ||
There is no default export. | ||
## `parseEntities(value[, options])` | ||
##### `options` | ||
###### `options.additional` | ||
@@ -50,4 +53,3 @@ | ||
Whether to parse `value` as an attribute value (`boolean?`, default: | ||
`false`). | ||
Whether to parse `value` as an attribute value (`boolean?`, default: `false`). | ||
@@ -57,4 +59,4 @@ ###### `options.nonTerminated` | ||
Whether to allow non-terminated entities (`boolean`, default: `true`). | ||
For example, `©cat` for `©cat`. This behaviour is spec-compliant but | ||
can lead to unexpected results. | ||
For example, `©cat` for `©cat`. | ||
This behavior is spec-compliant but can lead to unexpected results. | ||
@@ -87,10 +89,8 @@ ###### `options.warning` | ||
Starting `position` of `value` (`Location` or `Position`, optional). Useful | ||
when dealing with values nested in some sort of syntax tree. The default is: | ||
Starting `position` of `value` (`Position` or `Point`, optional). | ||
Useful when dealing with values nested in some sort of syntax tree. | ||
The default is: | ||
```js | ||
{ | ||
start: {line: 1, column: 1, offset: 0}, | ||
indent: [] | ||
} | ||
{line: 1, column: 1, offset: 0} | ||
``` | ||
@@ -102,3 +102,3 @@ | ||
### `function warning(reason, position, code)` | ||
### `function warning(reason, point, code)` | ||
@@ -115,11 +115,11 @@ Error handler. | ||
Human-readable reason for triggering a parse error (`string`). | ||
Human-readable reason the error (`string`). | ||
###### `position` | ||
###### `point` | ||
Place at which the parse error occurred (`Position`). | ||
Place at which the parse error occurred (`Point`). | ||
###### `code` | ||
Identifier of reason for triggering a parse error (`number`). | ||
Machine-readable code for the error (`number`). | ||
@@ -138,3 +138,3 @@ The following codes are used: | ||
### `function text(value, location)` | ||
### `function text(value, position)` | ||
@@ -153,7 +153,7 @@ Text handler. | ||
###### `location` | ||
###### `position` | ||
Location at which `value` starts and ends (`Location`). | ||
Location at which `value` starts and ends (`Position`). | ||
### `function reference(value, location, source)` | ||
### `function reference(value, position, source)` | ||
@@ -172,9 +172,9 @@ Character reference handler. | ||
###### `location` | ||
###### `position` | ||
Location at which `value` starts and ends (`Location`). | ||
Location at which `value` starts and ends (`Position`). | ||
###### `source` | ||
Source of character reference (`Location`). | ||
Source of character reference (`string`). | ||
@@ -200,5 +200,5 @@ ## Related | ||
[build-badge]: https://img.shields.io/travis/wooorm/parse-entities.svg | ||
[build-badge]: https://github.com/wooorm/parse-entities/workflows/main/badge.svg | ||
[build]: https://travis-ci.org/wooorm/parse-entities | ||
[build]: https://github.com/wooorm/parse-entities/actions | ||
@@ -223,8 +223,8 @@ [coverage-badge]: https://img.shields.io/codecov/c/github/wooorm/parse-entities.svg | ||
[warning]: #function-warningreason-position-code | ||
[warning]: #function-warningreason-point-code | ||
[text]: #function-textvalue-location | ||
[text]: #function-textvalue-position | ||
[reference]: #function-referencevalue-location-source | ||
[reference]: #function-referencevalue-position-source | ||
[invalid]: https://github.com/wooorm/character-reference-invalid |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
27058
9
567
Yes
1
+ Addedcharacter-entities@2.0.2(transitive)
+ Addedcharacter-entities-legacy@2.0.0(transitive)
+ Addedcharacter-reference-invalid@2.0.1(transitive)
+ Addedis-alphabetical@2.0.1(transitive)
+ Addedis-alphanumerical@2.0.1(transitive)
+ Addedis-decimal@2.0.1(transitive)
+ Addedis-hexadecimal@2.0.1(transitive)
- Removedcharacter-entities@1.2.4(transitive)
- Removedcharacter-entities-legacy@1.1.4(transitive)
- Removedcharacter-reference-invalid@1.1.4(transitive)
- Removedis-alphabetical@1.0.4(transitive)
- Removedis-alphanumerical@1.0.4(transitive)
- Removedis-decimal@1.0.4(transitive)
- Removedis-hexadecimal@1.0.4(transitive)
Updatedcharacter-entities@^2.0.0
Updatedis-alphanumerical@^2.0.0
Updatedis-decimal@^2.0.0
Updatedis-hexadecimal@^2.0.0