Skip to content

Commit

Permalink
Refactor types
Browse files Browse the repository at this point in the history
  • Loading branch information
wooorm committed Apr 30, 2024
1 parent 88892ca commit 654d1fa
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 46 deletions.
32 changes: 17 additions & 15 deletions index.d.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import type {Point, Position} from 'unist'

// To do: next major: remove `void` from allowed return types.

/**
* @typeParam Context
* Value used as `this`.
Expand All @@ -17,7 +19,7 @@ export type WarningHandler<Context = undefined> = (
reason: string,
point: Point,
code: number
) => void
) => undefined | void

/**
* @typeParam Context
Expand All @@ -36,7 +38,7 @@ export type ReferenceHandler<Context = undefined> = (
value: string,
position: Position,
source: string
) => void
) => undefined | void

/**
* @typeParam Context
Expand All @@ -52,7 +54,7 @@ export type TextHandler<Context = undefined> = (
this: Context,
value: string,
position: Position
) => void
) => undefined | void

/**
* Configuration.
Expand All @@ -64,61 +66,61 @@ export type TextHandler<Context = undefined> = (
* @typeParam TextContext
* Value used as `this` in the `text` handler.
*/
export type Options<
export interface Options<
WarningContext = undefined,
ReferenceContext = undefined,
TextContext = undefined
> = {
> {
/**
* Additional character to accept.
* This allows other characters, without error, when following an ampersand.
*
* @default ''
*/
additional?: string
additional?: string | null | undefined
/**
* Whether to parse `value` as an attribute value.
* This results in slightly different behavior.
*
* @default false
*/
attribute?: boolean
attribute?: boolean | null | undefined
/**
* Whether to allow nonterminated character references.
* For example, `&copycat` for `©cat`.
* This behavior is compliant to the spec but can lead to unexpected results.
*
* @default true
*/
nonTerminated?: boolean
nonTerminated?: boolean | null | undefined
/**
* Starting `position` of `value` (`Point` or `Position`). Useful when dealing with values nested in some sort of syntax tree.
*/
position?: Position | Point
position?: Readonly<Position> | Readonly<Point> | null | undefined
/**
* Context used when calling `warning`.
*/
warningContext?: WarningContext
warningContext?: WarningContext | null | undefined
/**
* Context used when calling `reference`.
*/
referenceContext?: ReferenceContext
referenceContext?: ReferenceContext | null | undefined
/**
* Context used when calling `text`.
*/
textContext?: TextContext
textContext?: TextContext | null | undefined
/**
* Warning handler.
*/
warning?: WarningHandler<WarningContext>
warning?: WarningHandler<WarningContext> | null | undefined
/**
* Reference handler.
*/
reference?: ReferenceHandler<ReferenceContext>
reference?: ReferenceHandler<ReferenceContext> | null | undefined
/**
* Text handler.
*/
text?: TextHandler<TextContext>
text?: TextHandler<TextContext> | null | undefined
}

export {parseEntities} from './lib/index.js'
62 changes: 32 additions & 30 deletions lib/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/**
* @typedef {import('unist').Point} Point
* @typedef {import('unist').Position} Position
*
* @typedef {import('../index.js').Options} Options
*/

import {characterEntitiesLegacy} from 'character-entities-legacy'
Expand All @@ -10,8 +11,6 @@ import {isHexadecimal} from 'is-hexadecimal'
import {isAlphanumerical} from 'is-alphanumerical'
import {decodeNamedCharacterReference} from 'decode-named-character-reference'

const fromCharCode = String.fromCharCode

// Warning messages.
const messages = [
'',
Expand All @@ -35,31 +34,32 @@ const messages = [
* Parse HTML character references.
*
* @param {string} value
* @param {import('../index.js').Options} [options={}]
* @param {Readonly<Options> | null | undefined} [options]
*/
export function parseEntities(value, options = {}) {
export function parseEntities(value, options) {
const settings = options || {}
const additional =
typeof options.additional === 'string'
? options.additional.charCodeAt(0)
: options.additional
typeof settings.additional === 'string'
? settings.additional.charCodeAt(0)
: settings.additional
/** @type {Array<string>} */
const result = []
let index = 0
let lines = -1
let queue = ''
/** @type {Point|undefined} */
/** @type {Point | undefined} */
let point
/** @type {Array<number>|undefined} */
let indent

if (options.position) {
if ('start' in options.position || 'indent' in options.position) {
if (settings.position) {
if ('start' in settings.position || 'indent' in settings.position) {
// @ts-expect-error: points don’t have indent.
indent = options.position.indent
indent = settings.position.indent
// @ts-expect-error: points don’t have indent.
point = options.position.start
point = settings.position.start
} else {
point = options.position
point = settings.position
}
}

Expand Down Expand Up @@ -99,7 +99,7 @@ export function parseEntities(value, options = {}) {
// Not a character reference.
// No characters are consumed, and nothing is returned.
// This is not an error, either.
queue += fromCharCode(character)
queue += String.fromCharCode(character)
column++
continue
}
Expand Down Expand Up @@ -152,7 +152,7 @@ export function parseEntities(value, options = {}) {
break
}

characters += fromCharCode(following)
characters += String.fromCharCode(following)

// Check if we can match a legacy named reference.
// If so, we cache that as the last viable named reference.
Expand Down Expand Up @@ -181,7 +181,7 @@ export function parseEntities(value, options = {}) {
let diff = 1 + end - start
let reference = ''

if (!terminated && options.nonTerminated === false) {
if (!terminated && settings.nonTerminated === false) {
// Empty.
} else if (!characters) {
// An empty (possible) reference is valid, unless it’s numeric (thus an
Expand Down Expand Up @@ -209,7 +209,7 @@ export function parseEntities(value, options = {}) {
? 1 /* Non terminated (named) */
: 3 /* Empty (named) */

if (options.attribute) {
if (settings.attribute) {
const following = value.charCodeAt(end)

if (following === 61 /* `=` */) {
Expand Down Expand Up @@ -245,7 +245,7 @@ export function parseEntities(value, options = {}) {
// replacement character.
if (prohibited(referenceCode)) {
warning(7 /* Prohibited (numeric) */, diff)
reference = fromCharCode(65533 /* `�` */)
reference = String.fromCharCode(65533 /* `�` */)
} else if (referenceCode in characterReferenceInvalid) {
// Emit a warning when the parsed number is disallowed, and replace by
// an alternative.
Expand All @@ -263,11 +263,13 @@ export function parseEntities(value, options = {}) {
// Serialize the number.
if (referenceCode > 0xffff) {
referenceCode -= 0x10000
output += fromCharCode((referenceCode >>> (10 & 0x3ff)) | 0xd800)
output += String.fromCharCode(
(referenceCode >>> (10 & 0x3ff)) | 0xd800
)
referenceCode = 0xdc00 | (referenceCode & 0x3ff)
}

reference = output + fromCharCode(referenceCode)
reference = output + String.fromCharCode(referenceCode)
}
}

Expand All @@ -283,9 +285,9 @@ export function parseEntities(value, options = {}) {
const next = now()
next.offset++

if (options.reference) {
options.reference.call(
options.referenceContext,
if (settings.reference) {
settings.reference.call(
settings.referenceContext || undefined,
reference,
{start: previous, end: next},
value.slice(start - 1, end)
Expand Down Expand Up @@ -314,7 +316,7 @@ export function parseEntities(value, options = {}) {
if (Number.isNaN(character)) {
flush()
} else {
queue += fromCharCode(character)
queue += String.fromCharCode(character)
column++
}
}
Expand Down Expand Up @@ -342,13 +344,13 @@ export function parseEntities(value, options = {}) {
/** @type {ReturnType<now>} */
let position

if (options.warning) {
if (settings.warning) {
position = now()
position.column += offset
position.offset += offset

options.warning.call(
options.warningContext,
settings.warning.call(
settings.warningContext || undefined,
messages[code],
position,
code
Expand All @@ -365,8 +367,8 @@ export function parseEntities(value, options = {}) {
if (queue) {
result.push(queue)

if (options.text) {
options.text.call(options.textContext, queue, {
if (settings.text) {
settings.text.call(settings.textContext || undefined, queue, {
start: previous,
end: now()
})
Expand Down
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,8 @@
"xo": {
"prettier": true,
"rules": {
"@typescript-eslint/consistent-type-definitions": "off",
"@typescript-eslint/ban-types": "off",
"complexity": "off",
"max-depth": "off",
"no-bitwise": "off",
Expand All @@ -78,7 +80,7 @@
},
"remarkConfig": {
"plugins": [
"preset-wooorm"
"remark-preset-wooorm"
]
},
"typeCoverage": {
Expand Down

0 comments on commit 654d1fa

Please sign in to comment.