Skip to content

Commit

Permalink
Update @types/mdast, mdast utilities
Browse files Browse the repository at this point in the history
  • Loading branch information
wooorm committed Jul 11, 2023
1 parent 66fb90e commit 8e0233e
Show file tree
Hide file tree
Showing 4 changed files with 102 additions and 63 deletions.
39 changes: 38 additions & 1 deletion index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,27 @@ declare module 'mdast-util-to-markdown' {
// Add nodes to content.
declare module 'mdast' {
// eslint-disable-next-line @typescript-eslint/consistent-type-definitions
interface StaticPhrasingContentMap {
interface RootContentMap {
/**
* Directive in flow content (such as in the root document, or block
* quotes), which contains further flow content.
*/
containerDirective: ContainerDirective

/**
* Directive in flow content (such as in the root document, or block
* quotes), which contains nothing.
*/
leafDirective: LeafDirective

/**
* Directive in phrasing content (such as in paragraphs, headings).
*/
textDirective: TextDirective
}

// eslint-disable-next-line @typescript-eslint/consistent-type-definitions
interface PhrasingContentMap {
/**
* Directive in phrasing content (such as in paragraphs, headings).
*/
Expand All @@ -180,4 +200,21 @@ declare module 'mdast' {
*/
leafDirective: LeafDirective
}

// eslint-disable-next-line @typescript-eslint/consistent-type-definitions
interface ParagraphData {
/**
* Field set on the first paragraph which is a child of a container
* directive.
* When this is `true`, that means the paragraph represents the *label*:
*
* ```markdown
* :::a[This is the label]
* This is further things.
* :::
* ```
*/
// eslint-disable-next-line @typescript-eslint/ban-types
directiveLabel?: boolean | null | undefined
}
}
34 changes: 16 additions & 18 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,7 @@
import {parseEntities} from 'parse-entities'
import {stringifyEntitiesLight} from 'stringify-entities'
import {visitParents} from 'unist-util-visit-parents'
import {containerFlow} from 'mdast-util-to-markdown/lib/util/container-flow.js'
import {containerPhrasing} from 'mdast-util-to-markdown/lib/util/container-phrasing.js'
import {checkQuote} from 'mdast-util-to-markdown/lib/util/check-quote.js'
import {track} from 'mdast-util-to-markdown/lib/util/track.js'

// To do: next major: replace `containerFlow`, `containerPhrasing`, `track`
// with `state` methods.
// To do: next major: expose functions.

const own = {}.hasOwnProperty
Expand Down Expand Up @@ -178,7 +172,7 @@ function exitContainerLabel(token) {
* @type {FromMarkdownHandle}
*/
function enterAttributes() {
this.setData('directiveAttributes', [])
this.data.directiveAttributes = []
this.buffer() // Capture EOLs
}

Expand All @@ -188,7 +182,7 @@ function enterAttributes() {
*/
function exitAttributeIdValue(token) {
const list = /** @type {Array<[string, string]>} */ (
this.getData('directiveAttributes')
this.data.directiveAttributes
)
list.push([
'id',
Expand All @@ -204,7 +198,7 @@ function exitAttributeIdValue(token) {
*/
function exitAttributeClassValue(token) {
const list = /** @type {Array<[string, string]>} */ (
this.getData('directiveAttributes')
this.data.directiveAttributes
)
list.push([
'class',
Expand All @@ -220,7 +214,7 @@ function exitAttributeClassValue(token) {
*/
function exitAttributeValue(token) {
const list = /** @type {Array<[string, string]>} */ (
this.getData('directiveAttributes')
this.data.directiveAttributes
)
list[list.length - 1][1] = parseEntities(this.sliceSerialize(token), {
attribute: true
Expand All @@ -233,7 +227,7 @@ function exitAttributeValue(token) {
*/
function exitAttributeName(token) {
const list = /** @type {Array<[string, string]>} */ (
this.getData('directiveAttributes')
this.data.directiveAttributes
)

// Attribute names in CommonMark are significantly limited, so character
Expand All @@ -247,7 +241,7 @@ function exitAttributeName(token) {
*/
function exitAttributes() {
const list = /** @type {Array<[string, string]>} */ (
this.getData('directiveAttributes')
this.data.directiveAttributes
)
/** @type {Record<string, string>} */
const cleaned = {}
Expand All @@ -263,7 +257,7 @@ function exitAttributes() {
}
}

this.setData('directiveAttributes')
this.data.directiveAttributes = undefined
this.resume() // Drop EOLs
const node = /** @type {Directive} */ (this.stack[this.stack.length - 1])
node.attributes = cleaned
Expand All @@ -282,7 +276,7 @@ function exit(token) {
* @param {Directive} node
*/
function handleDirective(node, _, state, safeOptions) {
const tracker = track(safeOptions)
const tracker = state.createTracker(safeOptions)
const sequence = fence(node)
const exit = state.enter(node.type)
let value = tracker.move(sequence + (node.name || ''))
Expand All @@ -303,7 +297,11 @@ function handleDirective(node, _, state, safeOptions) {
const subexit = state.enter(labelType)
value += tracker.move('[')
value += tracker.move(
containerPhrasing(label, state, {
// @ts-expect-error: `containerPhrasing` is typed correctly, but TS
// generates *hardcoded* types, which means that our dynamically added
// directives are not present.
// At some point, TS should fix that, and `from-markdown` should be fine.
state.containerPhrasing(label, {
...tracker.current(),
before: value,
after: ']'
Expand All @@ -326,7 +324,7 @@ function handleDirective(node, _, state, safeOptions) {

if (shallow && shallow.children && shallow.children.length > 0) {
value += tracker.move('\n')
value += tracker.move(containerFlow(shallow, state, tracker.current()))
value += tracker.move(state.containerFlow(shallow, tracker.current()))
}

value += tracker.move('\n' + sequence)
Expand All @@ -347,7 +345,7 @@ function peekDirective() {
* @returns {string}
*/
function attributes(node, state) {
const quote = checkQuote(state)
const quote = state.options.quote || '"'
const subset = node.type === 'textDirective' ? [quote] : [quote, '\n', '\r']
const attrs = node.attributes || {}
/** @type {Array<string>} */
Expand Down Expand Up @@ -427,7 +425,7 @@ function attributes(node, state) {

/**
* @param {BlockContent | DefinitionContent} node
* @returns {node is Paragraph & {data: {directiveLabel: boolean}}}
* @returns {node is Paragraph & {data: {directiveLabel: true}}}
*/
function inlineDirectiveLabel(node) {
return Boolean(
Expand Down
17 changes: 8 additions & 9 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,25 +37,24 @@
"index.js"
],
"dependencies": {
"@types/mdast": "^3.0.0",
"@types/unist": "^2.0.0",
"mdast-util-from-markdown": "^1.3.0",
"mdast-util-to-markdown": "^1.5.0",
"@types/mdast": "^4.0.0",
"@types/unist": "^3.0.0",
"mdast-util-from-markdown": "^2.0.0",
"mdast-util-to-markdown": "^2.0.0",
"parse-entities": "^4.0.0",
"stringify-entities": "^4.0.0",
"unist-util-visit-parents": "^5.0.0"
"unist-util-visit-parents": "^6.0.0"
},
"devDependencies": {
"@types/node": "^20.0.0",
"c8": "^7.0.0",
"mdast-util-from-markdown": "^1.0.0",
"micromark-extension-directive": "^2.0.0",
"c8": "^8.0.0",
"micromark-extension-directive": "^3.0.0",
"prettier": "^2.0.0",
"remark-cli": "^11.0.0",
"remark-preset-wooorm": "^9.0.0",
"type-coverage": "^2.0.0",
"typescript": "^5.0.0",
"unist-util-remove-position": "^4.0.0",
"unist-util-remove-position": "^5.0.0",
"xo": "^0.54.0"
},
"scripts": {
Expand Down
75 changes: 40 additions & 35 deletions test.js
Original file line number Diff line number Diff line change
Expand Up @@ -149,14 +149,15 @@ test('directiveFromMarkdown', () => {
'should support directives (container)'
)

let tree = fromMarkdown(':a[b *c*\nd]', {
extensions: [directive()],
mdastExtensions: [directiveFromMarkdown]
})

removePosition(tree, {force: true})

assert.deepEqual(
removePosition(
fromMarkdown(':a[b *c*\nd]', {
extensions: [directive()],
mdastExtensions: [directiveFromMarkdown]
}),
true
),
tree,
{
type: 'root',
children: [
Expand All @@ -180,14 +181,15 @@ test('directiveFromMarkdown', () => {
'should support content in a label'
)

tree = fromMarkdown(':a{#b.c.d e=f g="h&amp;i&unknown;j"}', {
extensions: [directive()],
mdastExtensions: [directiveFromMarkdown]
})

removePosition(tree, {force: true})

assert.deepEqual(
removePosition(
fromMarkdown(':a{#b.c.d e=f g="h&amp;i&unknown;j"}', {
extensions: [directive()],
mdastExtensions: [directiveFromMarkdown]
}),
true
),
tree,
{
type: 'root',
children: [
Expand All @@ -207,14 +209,15 @@ test('directiveFromMarkdown', () => {
'should support attributes'
)

tree = fromMarkdown(':a{b=&param c="&param" d=\'&param\'}', {
extensions: [directive()],
mdastExtensions: [directiveFromMarkdown]
})

removePosition(tree, {force: true})

assert.deepEqual(
removePosition(
fromMarkdown(':a{b=&param c="&param" d=\'&param\'}', {
extensions: [directive()],
mdastExtensions: [directiveFromMarkdown]
}),
true
),
tree,
{
type: 'root',
children: [
Expand All @@ -234,14 +237,15 @@ test('directiveFromMarkdown', () => {
'should not support non-terminated character references'
)

tree = fromMarkdown(':a{b\nc="d\ne"}', {
extensions: [directive()],
mdastExtensions: [directiveFromMarkdown]
})

removePosition(tree, {force: true})

assert.deepEqual(
removePosition(
fromMarkdown(':a{b\nc="d\ne"}', {
extensions: [directive()],
mdastExtensions: [directiveFromMarkdown]
}),
true
),
tree,
{
type: 'root',
children: [
Expand All @@ -261,14 +265,15 @@ test('directiveFromMarkdown', () => {
'should support EOLs in attributes'
)

tree = fromMarkdown('::::a\n:::b\n:c\n:::\n::::', {
extensions: [directive()],
mdastExtensions: [directiveFromMarkdown]
})

removePosition(tree, {force: true})

assert.deepEqual(
removePosition(
fromMarkdown('::::a\n:::b\n:c\n:::\n::::', {
extensions: [directive()],
mdastExtensions: [directiveFromMarkdown]
}),
true
),
tree,
{
type: 'root',
children: [
Expand Down

0 comments on commit 8e0233e

Please sign in to comment.