Add JSDoc based types

This commit is contained in:
Titus Wormer 2021-06-08 17:11:30 +02:00
parent 472c259375
commit a0f521746f
No known key found for this signature in database
GPG key ID: E6E581152ED04E2E
14 changed files with 291 additions and 19 deletions

1
.gitignore vendored
View file

@ -1,4 +1,5 @@
.DS_Store
*.d.ts
*.log
coverage/
node_modules/

View file

@ -1,2 +1,7 @@
/**
* @typedef {import('./lib/html.js').Handle} Handle
* @typedef {import('./lib/html.js').Options} Options
*/
export {directive} from './lib/syntax.js'
export {directiveHtml} from './lib/html.js'

View file

@ -1,3 +1,10 @@
/**
* @typedef {import('micromark-util-types').Construct} Construct
* @typedef {import('micromark-util-types').Tokenizer} Tokenizer
* @typedef {import('micromark-util-types').State} State
* @typedef {import('micromark-util-types').Token} Token
*/
import assert from 'assert'
import {factorySpace} from 'micromark-factory-space'
import {markdownLineEnding} from 'micromark-util-character'
@ -8,6 +15,7 @@ import {factoryAttributes} from './factory-attributes.js'
import {factoryLabel} from './factory-label.js'
import {factoryName} from './factory-name.js'
/** @type {Construct} */
export const directiveContainer = {
tokenize: tokenizeDirectiveContainer,
concrete: true
@ -16,6 +24,7 @@ export const directiveContainer = {
const label = {tokenize: tokenizeLabel, partial: true}
const attributes = {tokenize: tokenizeAttributes, partial: true}
/** @type {Tokenizer} */
function tokenizeDirectiveContainer(effects, ok, nok) {
const self = this
const tail = self.events[self.events.length - 1]
@ -24,10 +33,12 @@ function tokenizeDirectiveContainer(effects, ok, nok) {
? tail[2].sliceSerialize(tail[1], true).length
: 0
let sizeOpen = 0
/** @type {Token} */
let previous
return start
/** @type {State} */
function start(code) {
assert(code === codes.colon, 'expected `:`')
effects.enter('directiveContainer')
@ -36,6 +47,7 @@ function tokenizeDirectiveContainer(effects, ok, nok) {
return sequenceOpen(code)
}
/** @type {State} */
function sequenceOpen(code) {
if (code === codes.colon) {
effects.consume(code)
@ -57,22 +69,26 @@ function tokenizeDirectiveContainer(effects, ok, nok) {
)(code)
}
/** @type {State} */
function afterName(code) {
return code === codes.leftSquareBracket
? effects.attempt(label, afterLabel, afterLabel)(code)
: afterLabel(code)
}
/** @type {State} */
function afterLabel(code) {
return code === codes.leftCurlyBrace
? effects.attempt(attributes, afterAttributes, afterAttributes)(code)
: afterAttributes(code)
}
/** @type {State} */
function afterAttributes(code) {
return factorySpace(effects, openAfter, types.whitespace)(code)
}
/** @type {State} */
function openAfter(code) {
effects.exit('directiveContainerFence')
@ -91,6 +107,7 @@ function tokenizeDirectiveContainer(effects, ok, nok) {
return nok(code)
}
/** @type {State} */
function contentStart(code) {
if (code === codes.eof) {
effects.exit('directiveContainer')
@ -101,6 +118,7 @@ function tokenizeDirectiveContainer(effects, ok, nok) {
return lineStart(code)
}
/** @type {State} */
function lineStart(code) {
if (code === codes.eof) {
return after(code)
@ -115,6 +133,7 @@ function tokenizeDirectiveContainer(effects, ok, nok) {
)(code)
}
/** @type {State} */
function chunkStart(code) {
if (code === codes.eof) {
return after(code)
@ -129,6 +148,7 @@ function tokenizeDirectiveContainer(effects, ok, nok) {
return contentContinue(code)
}
/** @type {State} */
function contentContinue(code) {
if (code === codes.eof) {
effects.exit('chunkDocument')
@ -145,12 +165,14 @@ function tokenizeDirectiveContainer(effects, ok, nok) {
return contentContinue
}
/** @type {State} */
function after(code) {
effects.exit('directiveContainerContent')
effects.exit('directiveContainer')
return ok(code)
}
/** @type {Tokenizer} */
function tokenizeClosingFence(effects, ok, nok) {
let size = 0
@ -161,12 +183,14 @@ function tokenizeDirectiveContainer(effects, ok, nok) {
constants.tabSize
)
/** @type {State} */
function closingPrefixAfter(code) {
effects.enter('directiveContainerFence')
effects.enter('directiveContainerSequence')
return closingSequence(code)
}
/** @type {State} */
function closingSequence(code) {
if (code === codes.colon) {
effects.consume(code)
@ -179,6 +203,7 @@ function tokenizeDirectiveContainer(effects, ok, nok) {
return factorySpace(effects, closingSequenceEnd, types.whitespace)(code)
}
/** @type {State} */
function closingSequenceEnd(code) {
if (code === codes.eof || markdownLineEnding(code)) {
effects.exit('directiveContainerFence')
@ -190,6 +215,7 @@ function tokenizeDirectiveContainer(effects, ok, nok) {
}
}
/** @type {Tokenizer} */
function tokenizeLabel(effects, ok, nok) {
// Always a `[`
return factoryLabel(
@ -203,6 +229,7 @@ function tokenizeLabel(effects, ok, nok) {
)
}
/** @type {Tokenizer} */
function tokenizeAttributes(effects, ok, nok) {
// Always a `{`
return factoryAttributes(

View file

@ -1,3 +1,9 @@
/**
* @typedef {import('micromark-util-types').Construct} Construct
* @typedef {import('micromark-util-types').Tokenizer} Tokenizer
* @typedef {import('micromark-util-types').State} State
*/
import assert from 'assert'
import {factorySpace} from 'micromark-factory-space'
import {markdownLineEnding} from 'micromark-util-character'
@ -7,16 +13,19 @@ import {factoryAttributes} from './factory-attributes.js'
import {factoryLabel} from './factory-label.js'
import {factoryName} from './factory-name.js'
/** @type {Construct} */
export const directiveLeaf = {tokenize: tokenizeDirectiveLeaf}
const label = {tokenize: tokenizeLabel, partial: true}
const attributes = {tokenize: tokenizeAttributes, partial: true}
/** @type {Tokenizer} */
function tokenizeDirectiveLeaf(effects, ok, nok) {
const self = this
return start
/** @type {State} */
function start(code) {
assert(code === codes.colon, 'expected `:`')
effects.enter('directiveLeaf')
@ -25,6 +34,7 @@ function tokenizeDirectiveLeaf(effects, ok, nok) {
return inStart
}
/** @type {State} */
function inStart(code) {
if (code === codes.colon) {
effects.consume(code)
@ -41,22 +51,26 @@ function tokenizeDirectiveLeaf(effects, ok, nok) {
return nok(code)
}
/** @type {State} */
function afterName(code) {
return code === codes.leftSquareBracket
? effects.attempt(label, afterLabel, afterLabel)(code)
: afterLabel(code)
}
/** @type {State} */
function afterLabel(code) {
return code === codes.leftCurlyBrace
? effects.attempt(attributes, afterAttributes, afterAttributes)(code)
: afterAttributes(code)
}
/** @type {State} */
function afterAttributes(code) {
return factorySpace(effects, end, types.whitespace)(code)
}
/** @type {State} */
function end(code) {
if (code === codes.eof || markdownLineEnding(code)) {
effects.exit('directiveLeaf')
@ -67,6 +81,7 @@ function tokenizeDirectiveLeaf(effects, ok, nok) {
}
}
/** @type {Tokenizer} */
function tokenizeLabel(effects, ok, nok) {
// Always a `[`
return factoryLabel(
@ -80,6 +95,7 @@ function tokenizeLabel(effects, ok, nok) {
)
}
/** @type {Tokenizer} */
function tokenizeAttributes(effects, ok, nok) {
// Always a `{`
return factoryAttributes(

View file

@ -1,3 +1,10 @@
/**
* @typedef {import('micromark-util-types').Construct} Construct
* @typedef {import('micromark-util-types').Tokenizer} Tokenizer
* @typedef {import('micromark-util-types').Previous} Previous
* @typedef {import('micromark-util-types').State} State
*/
import assert from 'assert'
import {codes} from 'micromark-util-symbol/codes.js'
import {types} from 'micromark-util-symbol/types.js'
@ -5,6 +12,7 @@ import {factoryAttributes} from './factory-attributes.js'
import {factoryLabel} from './factory-label.js'
import {factoryName} from './factory-name.js'
/** @type {Construct} */
export const directiveText = {
tokenize: tokenizeDirectiveText,
previous
@ -13,6 +21,7 @@ export const directiveText = {
const label = {tokenize: tokenizeLabel, partial: true}
const attributes = {tokenize: tokenizeAttributes, partial: true}
/** @type {Previous} */
function previous(code) {
// If there is a previous code, there will always be a tail.
return (
@ -21,11 +30,13 @@ function previous(code) {
)
}
/** @type {Tokenizer} */
function tokenizeDirectiveText(effects, ok, nok) {
const self = this
return start
/** @type {State} */
function start(code) {
assert(code === codes.colon, 'expected `:`')
assert(previous.call(self, self.previous), 'expected correct previous')
@ -36,6 +47,7 @@ function tokenizeDirectiveText(effects, ok, nok) {
return factoryName.call(self, effects, afterName, nok, 'directiveTextName')
}
/** @type {State} */
function afterName(code) {
return code === codes.colon
? nok(code)
@ -44,18 +56,21 @@ function tokenizeDirectiveText(effects, ok, nok) {
: afterLabel(code)
}
/** @type {State} */
function afterLabel(code) {
return code === codes.leftCurlyBrace
? effects.attempt(attributes, afterAttributes, afterAttributes)(code)
: afterAttributes(code)
}
/** @type {State} */
function afterAttributes(code) {
effects.exit('directiveText')
return ok(code)
}
}
/** @type {Tokenizer} */
function tokenizeLabel(effects, ok, nok) {
// Always a `[`
return factoryLabel(
@ -68,6 +83,7 @@ function tokenizeLabel(effects, ok, nok) {
)
}
/** @type {Tokenizer} */
function tokenizeAttributes(effects, ok, nok) {
// Always a `{`
return factoryAttributes(

View file

@ -1,3 +1,9 @@
/**
* @typedef {import('micromark-util-types').Effects} Effects
* @typedef {import('micromark-util-types').State} State
* @typedef {import('micromark-util-types').Code} Code
*/
import assert from 'assert'
import {factorySpace} from 'micromark-factory-space'
import {factoryWhitespace} from 'micromark-factory-whitespace'
@ -11,6 +17,23 @@ import {
import {codes} from 'micromark-util-symbol/codes.js'
import {types} from 'micromark-util-symbol/types.js'
/**
* @param {Effects} effects
* @param {State} ok
* @param {State} nok
* @param {string} attributesType
* @param {string} attributesMarkerType
* @param {string} attributeType
* @param {string} attributeIdType
* @param {string} attributeClassType
* @param {string} attributeNameType
* @param {string} attributeInitializerType
* @param {string} attributeValueLiteralType
* @param {string} attributeValueType
* @param {string} attributeValueMarker
* @param {string} attributeValueData
* @param {boolean} [disallowEol=false]
*/
/* eslint-disable-next-line max-params */
export function factoryAttributes(
effects,
@ -29,11 +52,14 @@ export function factoryAttributes(
attributeValueData,
disallowEol
) {
/** @type {string} */
let type
/** @type {Code|undefined} */
let marker
return start
/** @type {State} */
function start(code) {
assert(code === codes.leftCurlyBrace, 'expected `{`')
effects.enter(attributesType)
@ -43,6 +69,7 @@ export function factoryAttributes(
return between
}
/** @type {State} */
function between(code) {
if (code === codes.numberSign) {
type = attributeIdType
@ -72,6 +99,7 @@ export function factoryAttributes(
return end(code)
}
/** @type {State} */
function shortcutStart(code) {
effects.enter(attributeType)
effects.enter(type)
@ -81,6 +109,7 @@ export function factoryAttributes(
return shortcutStartAfter
}
/** @type {State} */
function shortcutStartAfter(code) {
if (
code === codes.eof ||
@ -103,6 +132,7 @@ export function factoryAttributes(
return shortcut
}
/** @type {State} */
function shortcut(code) {
if (
code === codes.eof ||
@ -132,6 +162,7 @@ export function factoryAttributes(
return shortcut
}
/** @type {State} */
function name(code) {
if (
code === codes.dash ||
@ -157,6 +188,7 @@ export function factoryAttributes(
return nameAfter(code)
}
/** @type {State} */
function nameAfter(code) {
if (code === codes.equalsTo) {
effects.enter(attributeInitializerType)
@ -170,6 +202,7 @@ export function factoryAttributes(
return between(code)
}
/** @type {State} */
function valueBefore(code) {
if (
code === codes.eof ||
@ -207,6 +240,7 @@ export function factoryAttributes(
return valueUnquoted
}
/** @type {State} */
function valueUnquoted(code) {
if (
code === codes.eof ||
@ -231,6 +265,7 @@ export function factoryAttributes(
return valueUnquoted
}
/** @type {State} */
function valueQuotedStart(code) {
if (code === marker) {
effects.enter(attributeValueMarker)
@ -245,6 +280,7 @@ export function factoryAttributes(
return valueQuotedBetween(code)
}
/** @type {State} */
function valueQuotedBetween(code) {
if (code === marker) {
effects.exit(attributeValueType)
@ -267,6 +303,7 @@ export function factoryAttributes(
return valueQuoted
}
/** @type {State} */
function valueQuoted(code) {
if (code === marker || code === codes.eof || markdownLineEnding(code)) {
effects.exit(attributeValueData)
@ -277,12 +314,14 @@ export function factoryAttributes(
return valueQuoted
}
/** @type {State} */
function valueQuotedAfter(code) {
return code === codes.rightCurlyBrace || markdownLineEndingOrSpace(code)
? between(code)
: end(code)
}
/** @type {State} */
function end(code) {
if (code === codes.rightCurlyBrace) {
effects.enter(attributesMarkerType)

View file

@ -1,3 +1,8 @@
/**
* @typedef {import('micromark-util-types').Effects} Effects
* @typedef {import('micromark-util-types').State} State
*/
import assert from 'assert'
import {markdownLineEnding} from 'micromark-util-character'
import {codes} from 'micromark-util-symbol/codes.js'
@ -9,6 +14,15 @@ import {types} from 'micromark-util-symbol/types.js'
// to allow empty labels, balanced brackets (such as for nested directives),
// text instead of strings, and optionally disallows EOLs.
/**
* @param {Effects} effects
* @param {State} ok
* @param {State} nok
* @param {string} type
* @param {string} markerType
* @param {string} stringType
* @param {boolean} [disallowEol=false]
*/
// eslint-disable-next-line max-params
export function factoryLabel(
effects,
@ -24,6 +38,7 @@ export function factoryLabel(
return start
/** @type {State} */
function start(code) {
assert(code === codes.leftSquareBracket, 'expected `[`')
effects.enter(type)
@ -33,6 +48,7 @@ export function factoryLabel(
return afterStart
}
/** @type {State} */
function afterStart(code) {
if (code === codes.rightSquareBracket) {
effects.enter(markerType)
@ -46,6 +62,7 @@ export function factoryLabel(
return atBreak(code)
}
/** @type {State} */
function atBreak(code) {
if (code === codes.eof || size > constants.linkReferenceSizeMax) {
return nok(code)
@ -70,6 +87,7 @@ export function factoryLabel(
return label(code)
}
/** @type {State} */
function label(code) {
if (
code === codes.eof ||
@ -96,6 +114,7 @@ export function factoryLabel(
return code === codes.backslash ? labelEscape : label
}
/** @type {State} */
function atClosingBrace(code) {
effects.exit(stringType)
effects.enter(markerType)
@ -105,6 +124,7 @@ export function factoryLabel(
return ok
}
/** @type {State} */
function labelEscape(code) {
if (
code === codes.leftSquareBracket ||

View file

@ -1,14 +1,28 @@
/**
* @typedef {import('micromark-util-types').TokenizeContext} TokenizeContext
* @typedef {import('micromark-util-types').Effects} Effects
* @typedef {import('micromark-util-types').State} State
*/
import {asciiAlpha, asciiAlphanumeric} from 'micromark-util-character'
import {codes} from 'micromark-util-symbol/codes.js'
export function factoryName(effects, ok, nok, nameType) {
/**
* @this {TokenizeContext}
* @param {Effects} effects
* @param {State} ok
* @param {State} nok
* @param {string} type
*/
export function factoryName(effects, ok, nok, type) {
const self = this
return start
/** @type {State} */
function start(code) {
if (asciiAlpha(code)) {
effects.enter(nameType)
effects.enter(type)
effects.consume(code)
return name
}
@ -16,6 +30,7 @@ export function factoryName(effects, ok, nok, nameType) {
return nok(code)
}
/** @type {State} */
function name(code) {
if (
code === codes.dash ||
@ -26,7 +41,7 @@ export function factoryName(effects, ok, nok, nameType) {
return name
}
effects.exit(nameType)
effects.exit(type)
return self.previous === codes.dash || self.previous === codes.underscore
? nok(code)
: ok(code)

View file

@ -1,7 +1,35 @@
/**
* @typedef {import('micromark-util-types').HtmlExtension} HtmlExtension
* @typedef {import('micromark-util-types').Handle} _Handle
* @typedef {import('micromark-util-types').CompileContext} CompileContext
*/
/**
* @typedef {[string, string]} Attribute
* @typedef {'containerDirective'|'leafDirective'|'textDirective'} DirectiveType
*
* @typedef Directive
* @property {DirectiveType} type
* @property {string} name
* @property {string} [label]
* @property {Record<string, string>} [attributes]
* @property {string} [content]
* @property {number} [_fenceCount]
*
* @typedef {(this: CompileContext, directive: Directive) => boolean|void} Handle
*
* @typedef {Record<string, Handle>} Options
*/
import assert from 'assert'
import {decodeEntity} from 'parse-entities/decode-entity.js'
const own = {}.hasOwnProperty
/**
* @param {Options} [options]
* @returns {HtmlExtension}
*/
export function directiveHtml(options = {}) {
return {
enter: {
@ -58,65 +86,97 @@ export function directiveHtml(options = {}) {
}
}
/**
* @this {CompileContext}
* @param {DirectiveType} type
*/
function enter(type) {
/** @type {Directive[]} */
// @ts-expect-error
let stack = this.getData('directiveStack')
if (!stack) this.setData('directiveStack', (stack = []))
stack.push({type})
stack.push({type, name: ''})
}
/** @type {_Handle} */
function exitName(token) {
/** @type {Directive[]} */
// @ts-expect-error
const stack = this.getData('directiveStack')
stack[stack.length - 1].name = this.sliceSerialize(token)
}
/** @type {_Handle} */
function enterLabel() {
this.buffer()
}
/** @type {_Handle} */
function exitLabel() {
const data = this.resume()
/** @type {Directive[]} */
// @ts-expect-error
const stack = this.getData('directiveStack')
stack[stack.length - 1].label = data
}
/** @type {_Handle} */
function enterAttributes() {
this.buffer()
this.setData('directiveAttributes', [])
}
/** @type {_Handle} */
function exitAttributeIdValue(token) {
this.getData('directiveAttributes').push([
'id',
decodeLight(this.sliceSerialize(token))
])
/** @type {Attribute[]} */
// @ts-expect-error
const attributes = this.getData('directiveAttributes')
attributes.push(['id', decodeLight(this.sliceSerialize(token))])
}
/** @type {_Handle} */
function exitAttributeClassValue(token) {
this.getData('directiveAttributes').push([
'class',
decodeLight(this.sliceSerialize(token))
])
/** @type {Attribute[]} */
// @ts-expect-error
const attributes = this.getData('directiveAttributes')
attributes.push(['class', decodeLight(this.sliceSerialize(token))])
}
/** @type {_Handle} */
function exitAttributeName(token) {
// Attribute names in CommonMark are significantly limited, so character
// references cant exist.
this.getData('directiveAttributes').push([this.sliceSerialize(token), ''])
/** @type {Attribute[]} */
// @ts-expect-error
const attributes = this.getData('directiveAttributes')
attributes.push([this.sliceSerialize(token), ''])
}
/** @type {_Handle} */
function exitAttributeValue(token) {
/** @type {Attribute[]} */
// @ts-expect-error
const attributes = this.getData('directiveAttributes')
attributes[attributes.length - 1][1] = decodeLight(
this.sliceSerialize(token)
)
}
/** @type {_Handle} */
function exitAttributes() {
/** @type {Directive[]} */
// @ts-expect-error
const stack = this.getData('directiveStack')
/** @type {Attribute[]} */
// @ts-expect-error
const attributes = this.getData('directiveAttributes')
/** @type {Directive['attributes']} */
const cleaned = {}
let index = -1
/** @type {Attribute} */
let attribute
let index = -1
while (++index < attributes.length) {
attribute = attributes[index]
@ -133,25 +193,38 @@ export function directiveHtml(options = {}) {
stack[stack.length - 1].attributes = cleaned
}
/** @type {_Handle} */
function exitContainerContent() {
const data = this.resume()
/** @type {Directive[]} */
// @ts-expect-error
const stack = this.getData('directiveStack')
stack[stack.length - 1].content = data
}
/** @type {_Handle} */
function exitContainerFence() {
/** @type {Directive[]} */
// @ts-expect-error
const stack = this.getData('directiveStack')
const directive = stack[stack.length - 1]
if (!directive.fenceCount) directive.fenceCount = 0
directive.fenceCount++
if (directive.fenceCount === 1) this.setData('slurpOneLineEnding', true)
if (!directive._fenceCount) directive._fenceCount = 0
directive._fenceCount++
if (directive._fenceCount === 1) this.setData('slurpOneLineEnding', true)
}
/** @type {_Handle} */
function exit() {
/** @type {Directive} */
// @ts-expect-error
const directive = this.getData('directiveStack').pop()
/** @type {boolean|undefined} */
let found
/** @type {boolean|void} */
let result
assert(directive.name, 'expected `name`')
if (own.call(options, directive.name)) {
result = options[directive.name].call(this, directive)
found = result !== false
@ -168,6 +241,10 @@ export function directiveHtml(options = {}) {
}
}
/**
* @param {string} value
* @returns {string}
*/
function decodeLight(value) {
return value.replace(
/&(#(\d{1,7}|x[\da-f]{1,6})|[\da-z]{1,31});/gi,
@ -175,6 +252,11 @@ function decodeLight(value) {
)
}
/**
* @param {string} $0
* @param {string} $1
* @returns {string}
*/
function decodeIfPossible($0, $1) {
return decodeEntity($1) || $0
}

View file

@ -1,8 +1,15 @@
/**
* @typedef {import('micromark-util-types').Extension} Extension
*/
import {codes} from 'micromark-util-symbol/codes.js'
import {directiveContainer} from './directive-container.js'
import {directiveLeaf} from './directive-leaf.js'
import {directiveText} from './directive-text.js'
/**
* @returns {Extension}
*/
export function directive() {
return {
text: {[codes.colon]: directiveText},

View file

@ -26,9 +26,11 @@
"sideEffects": false,
"type": "module",
"main": "index.js",
"types": "index.d.ts",
"files": [
"dev/",
"lib/",
"index.d.ts",
"index.js"
],
"exports": {
@ -40,9 +42,11 @@
"micromark-factory-whitespace": "^1.0.0-alpha.2",
"micromark-util-character": "^1.0.0-alpha.2",
"micromark-util-symbol": "^1.0.0-alpha.2",
"micromark-util-types": "^1.0.0-alpha.2",
"parse-entities": "^3.0.0"
},
"devDependencies": {
"@types/tape": "^4.0.0",
"c8": "^7.0.0",
"html-void-elements": "^2.0.0",
"micromark": "^3.0.0-alpha.2",
@ -50,11 +54,14 @@
"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.39.0"
},
"scripts": {
"build": "micromark-build",
"build": "rimraf \"dev/**/*.d.ts\" \"test/**/*.d.ts\" && tsc && type-coverage && micromark-build",
"format": "remark . -qfo && prettier . -w --loglevel warn && xo --fix",
"test-api": "node --conditions development test/index.js",
"test-coverage": "c8 --check-coverage --branches 100 --functions 100 --lines 100 --statements 100 --reporter lcov node --conditions development test/index.js",
@ -78,5 +85,11 @@
"plugins": [
"preset-wooorm"
]
},
"typeCoverage": {
"atLeast": 100,
"detail": true,
"strict": true,
"ignoreCatch": true
}
}

View file

@ -103,7 +103,8 @@ None yet, but might be added in the future.
###### `htmlOptions`
An object mapping names of directives to handlers ([`Object.<Handle>`][handle]).
An object mapping names of directives to handlers
([`Record<string, Handle>`][handle]).
The special name `'*'` is the fallback to handle all unhandled directives.
### `function handle(directive)`

View file

@ -1,3 +1,8 @@
/**
* @typedef {import('../dev/index.js').Options} Options
* @typedef {import('../dev/index.js').Handle} Handle
*/
import test from 'tape'
import {micromark} from 'micromark'
import {htmlVoidElements} from 'html-void-elements'
@ -1369,6 +1374,7 @@ test('content', (t) => {
t.end()
})
/** @type {Handle} */
function abbr(d) {
if (d.type !== 'textDirective') return false
@ -1383,9 +1389,11 @@ function abbr(d) {
this.tag('</abbr>')
}
/** @type {Handle} */
function youtube(d) {
const attrs = d.attributes || {}
const v = attrs.v
/** @type {string} */
let prop
if (!v) return false
@ -1416,10 +1424,13 @@ function youtube(d) {
this.tag('</iframe>')
}
/** @type {Handle} */
function h(d) {
const content = d.content || d.label
const attrs = d.attributes || {}
/** @type {Array.<string>} */
const list = []
/** @type {string} */
let prop
for (prop in attrs) {
@ -1441,6 +1452,9 @@ function h(d) {
if (!htmlVoidElements.includes(d.name)) this.tag('</' + d.name + '>')
}
/**
* @param {Options} [options]
*/
function options(options) {
return {
allowDangerousHtml: true,

16
tsconfig.json Normal file
View file

@ -0,0 +1,16 @@
{
"include": ["dev/**/*.js", "test/**/*.js"],
"compilerOptions": {
"target": "ES2020",
"lib": ["ES2020"],
"module": "ES2020",
"moduleResolution": "node",
"allowJs": true,
"checkJs": true,
"declaration": true,
"emitDeclarationOnly": true,
"allowSyntheticDefaultImports": true,
"skipLibCheck": true,
"strict": true
}
}