Skip to content

Commit

Permalink
[remark-iframes] Migrate to micromark
Browse files Browse the repository at this point in the history
  • Loading branch information
StaloneLab committed Aug 2, 2024
1 parent 1aa2ea3 commit c33d90c
Show file tree
Hide file tree
Showing 19 changed files with 2,021 additions and 913 deletions.
1,252 changes: 1,132 additions & 120 deletions package-lock.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@
},
"scripts": {
"pretest": "lerna run pretest --scope zmarkdown",
"test": "cross-env NODE_OPTIONS=--experimental-vm-modules DEST=/tmp jest packages/remark-kbd packages/micromark-extension-kbd",
"test": "cross-env NODE_OPTIONS=--experimental-vm-modules DEST=/tmp jest packages/remark-kbd packages/remark-iframes packages/micromark-extension-kbd packages/micromark-extension-iframes",
"lint": "eslint .",
"posttest": "lerna run posttest --scope zmarkdown",
"build": "lerna run build",
Expand Down
3 changes: 3 additions & 0 deletions packages/micromark-extension-iframes/.npmignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
__tests__/
specs/
.npmignore
58 changes: 58 additions & 0 deletions packages/micromark-extension-iframes/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# `micromark-extension-iframes`

**[micromark][]** extension that parses custom Markdown syntax to handle
external content frames (i.e. iframes).
This syntax extension follows a [specification][spec]; in short, the syntax is the
same as the one used for embedding images.
For instance, use `!(https://www.youtube.com/embed/{yid})` to embed a Youtube video.

This package provides the low-level modules for integrating with the micromark
tokenizer and the micromark HTML compiler. Please note that the HTML compiler is currently not very advanced. Especially, it **does not** transform the embed link in any way, nor does it add attributes to the generated `iframe` element. For more advanced options, including oEmbed integration, please see the [remark-iframe][] package.

## Install

[npm][]:

```sh
npm install micromark-extension-iframes
```

## API

### `html`

### `syntax(options?)`

> Note: `syntax` is the default export of this module, `html` is available at
> `micromark-extension-iframes/lib/html`.
Support custom syntax to handle external content frames.
The export of `syntax` is a function that can be called with options and returns
an extension for the micromark parser (to tokenize iframes; can be passed
in `extensions`).
The export of `html` is an extension for the default HTML compiler (to compile
as `<iframe>` elements; can be passed in `htmlExtensions`).

##### `options`

- `options.exclamationChar`: the character indicating the potential start of an iframe. Defaults to `!`, hence it's name.
- `options.openingChar`: the opening character for an iframe link. Defaults to `(`.
- `options.closingChar`: the closing character for an iframe link. Defaults to `)`.

## License

[MIT][license] © [Zeste de Savoir][zds]

<!-- Definitions -->

[license]: LICENCE

[micromark]: https://github.com/micromark/micromark

[npm]: https://docs.npmjs.com/cli/install

[remark-iframe]: https://www.npmjs.com/package/remark-iframes

[spec]: specs/extension.md

[zds]: https://zestedesavoir.com
17 changes: 17 additions & 0 deletions packages/micromark-extension-iframes/__tests__/plugin.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { micromark } from 'micromark'
import micromarkIframes from '../lib/index'
import micromarkIframesHtml from '../lib/html'

test('can take custom characters', () => {
const input = ':[https://www.youtube.com/watch?v=eLdiWe_HJv4]'
const output = micromark(input, {
extensions: [micromarkIframes({
exclamationChar: 58,
openingChar: 91,
closingChar: 93
})],
htmlExtensions: [micromarkIframesHtml]
})

expect(output).toEqual('<iframe src="https://www.youtube.com/watch?v=eLdiWe_HJv4"></iframe>')
})
37 changes: 37 additions & 0 deletions packages/micromark-extension-iframes/__tests__/spec.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { micromark } from 'micromark'
import micromarkIframes from '../lib/index'
import micromarkIframesHtml from '../lib/html'

const specificationTests = {
'works': ['!(https://www.youtube.com/watch?v=eLdiWe_HJv4)', '<iframe src="https://www.youtube.com/watch?v=eLdiWe_HJv4"></iframe>'],
'no space after exclamation': ['! (https://www.youtube.com/watch?v=eLdiWe_HJv4)', '<p>! (https://www.youtube.com/watch?v=eLdiWe_HJv4)</p>'],
'starts on line break': ['abab !(https://www.youtube.com/watch?v=eLdiWe_HJv4)', '<p>abab !(https://www.youtube.com/watch?v=eLdiWe_HJv4)</p>'],
'ends on line break': ['!(https://www.youtube.com/watch?v=eLdiWe_HJv4)ono', '<p>!(https://www.youtube.com/watch?v=eLdiWe_HJv4)ono</p>'],
'escape exclamation': ['\\!(https://www.youtube.com/watch?v=eLdiWe_HJv4)', '<p>!(https://www.youtube.com/watch?v=eLdiWe_HJv4)</p>'],
'escape parenthesis': ['!\\(https://www.youtube.com/watch?v=eLdiWe_HJv4)', '<p>!(https://www.youtube.com/watch?v=eLdiWe_HJv4)</p>'],
'no line breaks inside': ['!(link\nmultilines)', '<p>!(link\nmultilines)</p>'],
'no autoframe': ['https://jsfiddle.net/zgjhjv9j/', '<p>https://jsfiddle.net/zgjhjv9j/</p>'],
'no closing parenthesis inside': ['!(https://www.youtube.com/watch?v=eLd)We_HJv4)', '<p>!(https://www.youtube.com/watch?v=eLd)We_HJv4)</p>'],
'no escaped closing parenthesis inside': ['!(https://www.youtube.com/watch?v=eLd\\)We_HJv4)', '<p>!(https://www.youtube.com/watch?v=eLd)We_HJv4)</p>'],
'frame in frame': ['!(https://www.youtube.com/watch?v=eLdWe_HJv4!(http://jsfiddle.net/zgjhjv9j/))', '<p>!(https://www.youtube.com/watch?v=eLdWe_HJv4!(http://jsfiddle.net/zgjhjv9j/))</p>'],
'is leaf block': ['### !(https://www.youtube.com/watch?v=eLdWe_HJv4)', '<h3>!(https://www.youtube.com/watch?v=eLdWe_HJv4)</h3>']
}

const renderString = (fixture) =>
micromark(fixture, {
extensions: [micromarkIframes()],
htmlExtensions: [micromarkIframesHtml]
})

describe('conforms to the specification', () => {
for (const test in specificationTests) {
const jestFunction = (!specificationTests[test][2]) ? it : it.skip

jestFunction(test, () => {
const [input, expectedOutput] = specificationTests[test]
const output = renderString(input)

expect(output).toEqual(expectedOutput)
})
}
})
22 changes: 22 additions & 0 deletions packages/micromark-extension-iframes/lib/html.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { sanitizeUri } from 'micromark-util-sanitize-uri'

export default {
enter: {
iframeLink: enterIframeLink
},
exit: {
iframeLink: exitIframeLink
}
}

function enterIframeLink () {
this.buffer()
}

function exitIframeLink () {
const iframeUrl = this.resume()
const sanitizedUrl = sanitizeUri(iframeUrl)

this.tag(`<iframe src="${sanitizedUrl}">`)
this.tag('</iframe>')
}
92 changes: 92 additions & 0 deletions packages/micromark-extension-iframes/lib/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import { markdownLineEnding } from 'micromark-util-character'
import { codes } from 'micromark-util-symbol'

export default function micromarkIframes (options = {}) {
// Character definitions, see specification, part 1
const exclamationChar = options.exclamationChar || 33
const openingChar = options.openingChar || 40
const closingChar = options.closingChar || 41

const call = {
name: 'iframe',
tokenize: tokenizeFactory({
exclamationChar,
openingChar,
closingChar
})
}

// Inject a hook on the exclamation mark
return {
flow: { [exclamationChar]: call }
}
}

function tokenizeFactory (charCodes) {
// Extract character code
const {
exclamationChar,
openingChar,
closingChar
} = charCodes

return tokenizeIframe

function tokenizeIframe (effects, ok, nok) {
return start

// Define a state `iframeStart` that consumes the exclamation mark
function start (code) {
// Discard invalid characters
if (code !== exclamationChar) return nok(code)

effects.enter('iframeLinkDelimiter')
effects.consume(code)

return openingParens
}

function openingParens (code) {
if (code !== openingChar) return nok(code)

effects.consume(code)
const endToken = effects.exit('iframeLinkDelimiter')
endToken._type = 'start'
effects.enter('iframeLink')
effects.enter('data')

return link
}

function link (code) {
if (code === closingChar) return closingParens

// Forbid EOL and EOF
if (code === codes.eof || markdownLineEnding(code)) {
return nok(code)
}

effects.consume(code)

return link
}

function closingParens (code) {
if (code !== closingChar) return link

effects.exit('data')
effects.exit('iframeLink')

effects.enter('iframeLinkDelimiter')
effects.consume(code)
const endToken = effects.exit('iframeLinkDelimiter')
endToken._type = 'end'

return finalBreak
}

function finalBreak (code) {
return (code === codes.eof || markdownLineEnding(code)) ? ok(code) : nok(code)
}
}
}
44 changes: 44 additions & 0 deletions packages/micromark-extension-iframes/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
{
"name": "micromark-extension-iframes",
"version": "0.0.0",
"description": "Add Markdown syntax to handle iframes",
"type": "module",
"keywords": [
"micromark",
"iframes",
"plugin",
"extension"
],
"author": "Stalone <[email protected]>",
"homepage": "https://github.com/zestedesavoir/zmarkdown/tree/master/packages/micromark-extension-iframes",
"license": "MIT",
"main": "lib/index.js",
"module": "lib/index.js",
"directories": {
"lib": "lib",
"test": "__tests__"
},
"files": [
"lib"
],
"repository": {
"type": "git",
"url": "git+https://github.com/zestedesavoir/zmarkdown.git#master"
},
"scripts": {
"pretest": "eslint .",
"test": "cross-env NODE_OPTIONS=--experimental-vm-modules jest",
"coverage": "cross-env NODE_OPTIONS=--experimental-vm-modules jest --coverage"
},
"bugs": {
"url": "https://github.com/zestedesavoir/zmarkdown/issues"
},
"dependencies": {
"micromark-util-character": "^2.1.0",
"micromark-util-sanitize-uri": "^2.0.0",
"micromark-util-symbol": "^2.0.0"
},
"devDependencies": {
"micromark": "^4.0.0"
}
}
Loading

0 comments on commit c33d90c

Please sign in to comment.