Skip to content

Commit

Permalink
Merge branch 'micromark:main' into pandoc-like-nested-directives
Browse files Browse the repository at this point in the history
  • Loading branch information
ugogon authored Oct 14, 2024
2 parents 1b7e22b + 3be1f50 commit b7d044a
Show file tree
Hide file tree
Showing 14 changed files with 354 additions and 203 deletions.
8 changes: 4 additions & 4 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,15 @@ jobs:
name: ${{matrix.node}}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{matrix.node}}
- run: npm install
- run: npm test
- uses: codecov/codecov-action@v3
- uses: codecov/codecov-action@v4
strategy:
matrix:
node:
- lts/gallium
- lts/hydrogen
- node
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
.DS_Store
*.d.ts
*.log
*.tsbuildinfo
coverage/
node_modules/
/lib/
Expand Down
100 changes: 88 additions & 12 deletions dev/index.d.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,95 @@
import type {Attribute, Directive} from './lib/html.js'
import type {CompileContext} from 'micromark-util-types'

export {directive} from './lib/syntax.js'
export {
directiveHtml,
type Directive,
type Handle,
type HtmlOptions
} from './lib/html.js'
export {directiveHtml} from './lib/html.js'

/**
* Internal tuple representing an attribute.
*/
type AttributeTuple = [key: string, value: string]

/**
* Directive attribute.
*/
interface Attributes {
/**
* Key to value.
*/
[key: string]: string
}

/**
* Structure representing a directive.
*/
export interface Directive {
/**
* Private :)
*/
_fenceCount?: number | undefined
/**
* Object w/ HTML attributes.
*/
attributes?: Attributes | undefined
/**
* Compiled HTML content inside container directive.
*/
content?: string | undefined
/**
* Compiled HTML content that was in `[brackets]`.
*/
label?: string | undefined
/**
* Name of directive.
*/
name: string
/**
* Kind.
*/
type: 'containerDirective' | 'leafDirective' | 'textDirective'
}

/**
* Handle a directive.
*
* @param this
* Current context.
* @param directive
* Directive.
* @returns
* Signal whether the directive was handled.
*
* Yield `false` to let the fallback (a special handle for `'*'`) handle it.
*/
export type Handle = (
this: CompileContext,
directive: Directive
) => boolean | undefined

/**
* Configuration.
*
* > 👉 **Note**: the special field `'*'` can be used to specify a fallback
* > handle to handle all otherwise unhandled directives.
*/
export interface HtmlOptions {
[name: string]: Handle
}

/**
* Augment types.
*/
declare module 'micromark-util-types' {
/**
* Compile data.
*/
interface CompileData {
directiveAttributes?: Array<AttributeTuple>
directiveStack?: Array<Directive>
}

/**
* Token types.
*/
interface TokenTypeMap {
directiveContainer: 'directiveContainer'
directiveContainerAttributes: 'directiveContainerAttributes'
Expand Down Expand Up @@ -72,9 +153,4 @@ declare module 'micromark-util-types' {
directiveTextMarker: 'directiveTextMarker'
directiveTextName: 'directiveTextName'
}

interface CompileData {
directiveAttributes?: Attribute[]
directiveStack?: Directive[]
}
}
79 changes: 47 additions & 32 deletions dev/lib/directive-container.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
/**
* @typedef {import('micromark-util-types').Construct} Construct
* @typedef {import('micromark-util-types').State} State
* @typedef {import('micromark-util-types').Token} Token
* @typedef {import('micromark-util-types').TokenizeContext} TokenizeContext
* @typedef {import('micromark-util-types').Tokenizer} Tokenizer
* @import {Construct, State, Token, TokenizeContext, Tokenizer} from 'micromark-util-types'
*/

import {ok as assert} from 'devlop'
Expand Down Expand Up @@ -97,31 +93,32 @@ function tokenizeDirectiveContainer(effects, ok, nok) {
effects.exit('directiveContainerFence')

if (code === codes.eof) {
return afterOpening(code)
return after(code)
}

if (markdownLineEnding(code)) {
if (self.interrupt) {
return ok(code)
}

return effects.attempt(nonLazyLine, contentStart, afterOpening)(code)
return effects.attempt(nonLazyLine, contentStart, after)(code)
}

return nok(code)
}

/** @type {State} */
function afterOpening(code) {
effects.exit('directiveContainer')
return ok(code)
}

/** @type {State} */
function contentStart(code) {
if (code === codes.eof) {
effects.exit('directiveContainer')
return ok(code)
return after(code)
}

if (markdownLineEnding(code)) {
return effects.check(
nonLazyLine,
emptyContentNonLazyLineAfter,
after
)(code)
}

effects.enter('directiveContainerContent')
Expand All @@ -130,13 +127,9 @@ function tokenizeDirectiveContainer(effects, ok, nok) {

/** @type {State} */
function lineStart(code) {
if (code === codes.eof) {
return after(code)
}

return effects.attempt(
{tokenize: tokenizeClosingFence, partial: true},
after,
afterContent,
initialSize
? factorySpace(effects, chunkStart, types.linePrefix, initialSize + 1)
: chunkStart
Expand All @@ -146,24 +139,22 @@ function tokenizeDirectiveContainer(effects, ok, nok) {
/** @type {State} */
function chunkStart(code) {
if (code === codes.eof) {
return after(code)
return afterContent(code)
}

const token = effects.enter(types.chunkDocument, {
contentType: constants.contentTypeDocument,
previous
})
if (previous) previous.next = token
previous = token
return contentContinue(code)
if (markdownLineEnding(code)) {
return effects.check(nonLazyLine, chunkNonLazyStart, afterContent)(code)
}

return chunkNonLazyStart(code)
}

/** @type {State} */
function contentContinue(code) {
if (code === codes.eof) {
const t = effects.exit(types.chunkDocument)
self.parser.lazy[t.start.line] = false
return after(code)
return afterContent(code)
}

if (markdownLineEnding(code)) {
Expand All @@ -174,6 +165,23 @@ function tokenizeDirectiveContainer(effects, ok, nok) {
return contentContinue
}

/** @type {State} */
function chunkNonLazyStart(code) {
const token = effects.enter(types.chunkDocument, {
contentType: constants.contentTypeDocument,
previous
})
if (previous) previous.next = token
previous = token
return contentContinue(code)
}

/** @type {State} */
function emptyContentNonLazyLineAfter(code) {
effects.enter('directiveContainerContent')
return lineStart(code)
}

/** @type {State} */
function nonLazyLineAfter(code) {
effects.consume(code)
Expand All @@ -186,12 +194,17 @@ function tokenizeDirectiveContainer(effects, ok, nok) {
function lineAfter(code) {
const t = effects.exit(types.chunkDocument)
self.parser.lazy[t.start.line] = false
return afterContent(code)
}

/** @type {State} */
function afterContent(code) {
effects.exit('directiveContainerContent')
return after(code)
}

/** @type {State} */
function after(code) {
effects.exit('directiveContainerContent')
effects.exit('directiveContainer')
return ok(code)
}
Expand All @@ -202,12 +215,14 @@ function tokenizeDirectiveContainer(effects, ok, nok) {
*/
function tokenizeClosingFence(effects, ok, nok) {
let size = 0

assert(self.parser.constructs.disable.null, 'expected `disable.null`')
return factorySpace(
effects,
closingPrefixAfter,
types.linePrefix,
constants.tabSize
self.parser.constructs.disable.null.includes('codeIndented')
? undefined
: constants.tabSize
)

/** @type {State} */
Expand Down
5 changes: 1 addition & 4 deletions dev/lib/directive-leaf.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
/**
* @typedef {import('micromark-util-types').Construct} Construct
* @typedef {import('micromark-util-types').State} State
* @typedef {import('micromark-util-types').TokenizeContext} TokenizeContext
* @typedef {import('micromark-util-types').Tokenizer} Tokenizer
* @import {Construct, State, TokenizeContext, Tokenizer} from 'micromark-util-types'
*/

import {ok as assert} from 'devlop'
Expand Down
6 changes: 1 addition & 5 deletions dev/lib/directive-text.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
/**
* @typedef {import('micromark-util-types').Construct} Construct
* @typedef {import('micromark-util-types').Previous} Previous
* @typedef {import('micromark-util-types').State} State
* @typedef {import('micromark-util-types').TokenizeContext} TokenizeContext
* @typedef {import('micromark-util-types').Tokenizer} Tokenizer
* @import {Construct, Previous, State, TokenizeContext, Tokenizer} from 'micromark-util-types'
*/

import {ok as assert} from 'devlop'
Expand Down
5 changes: 1 addition & 4 deletions dev/lib/factory-attributes.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
/**
* @typedef {import('micromark-util-types').Code} Code
* @typedef {import('micromark-util-types').Effects} Effects
* @typedef {import('micromark-util-types').State} State
* @typedef {import('micromark-util-types').TokenType} TokenType
* @import {Code, Effects, State, TokenType} from 'micromark-util-types'
*/

import {ok as assert} from 'devlop'
Expand Down
5 changes: 1 addition & 4 deletions dev/lib/factory-label.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
/**
* @typedef {import('micromark-util-types').Effects} Effects
* @typedef {import('micromark-util-types').State} State
* @typedef {import('micromark-util-types').Token} Token
* @typedef {import('micromark-util-types').TokenType} TokenType
* @import {Code, Effects, State, Token, TokenType} from 'micromark-util-types'
*/

import {ok as assert} from 'devlop'
Expand Down
5 changes: 1 addition & 4 deletions dev/lib/factory-name.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
/**
* @typedef {import('micromark-util-types').Effects} Effects
* @typedef {import('micromark-util-types').State} State
* @typedef {import('micromark-util-types').TokenizeContext} TokenizeContext
* @typedef {import('micromark-util-types').TokenType} TokenType
* @import {Code, Effects, State, TokenizeContext, TokenType} from 'micromark-util-types'
*/

import {asciiAlpha, asciiAlphanumeric} from 'micromark-util-character'
Expand Down
Loading

0 comments on commit b7d044a

Please sign in to comment.