Skip to content

Commit

Permalink
refactor: reusable content parser (#838)
Browse files Browse the repository at this point in the history
* refactor: reusable content parser

* chore: prettier

* fix: export type

* update regex

Co-authored-by: Kelly Joseph Price <[email protected]>

---------

Co-authored-by: Kelly Joseph Price <[email protected]>
  • Loading branch information
trishaprile and kellyjosephprice authored Mar 12, 2024
1 parent e6c82db commit c9a1c1b
Show file tree
Hide file tree
Showing 8 changed files with 105 additions and 80 deletions.
81 changes: 32 additions & 49 deletions __tests__/flavored-compilers.test.js
Original file line number Diff line number Diff line change
@@ -1,46 +1,29 @@
const { defaultSchema: sanitize } = require('hast-util-sanitize/lib/schema');
const rehypeSanitize = require('rehype-sanitize');
const remarkParse = require('remark-parse');
const remarkStringify = require('remark-stringify');
const unified = require('unified');

const parsers = Object.values(require('../processor/parse')).map(parser => parser.sanitize?.(sanitize) || parser);
const compilers = Object.values(require('../processor/compile'));
const options = require('../options').options.markdownOptions;

const processor = unified()
.use(remarkParse, options)
.data('settings', { position: false })
.use(parsers)
.use(rehypeSanitize);

const parse = text => text && processor().parse(text);
const compile = tree => tree && processor().use(remarkStringify, options).use(compilers).stringify(tree);
import { mdast, md } from '../index';

describe('ReadMe Flavored Blocks', () => {
it('Embed', () => {
const txt = '[Embedded meta links.](https://nyti.me/s/gzoa2xb2v3 "@nyt")';
const ast = parse(txt);
const out = compile(ast);
const ast = mdast(txt);
const out = md(ast);
expect(out).toMatchSnapshot();
});

it('Variables', () => {
expect(compile(parse('<<variable:user>>'))).toMatchInlineSnapshot(`
expect(md(mdast('<<variable:user>>'))).toMatchInlineSnapshot(`
"<<variable:user>>
"
`);
});

it('Glossary Items', () => {
expect(compile(parse('<<glossary:owl>>'))).toMatchInlineSnapshot(`
expect(md(mdast('<<glossary:owl>>'))).toMatchInlineSnapshot(`
"<<glossary:owl>>
"
`);
});

it('Emojis', () => {
expect(compile(parse(':smiley:'))).toMatchInlineSnapshot(`
expect(md(mdast(':smiley:'))).toMatchInlineSnapshot(`
":smiley:
"
`);
Expand All @@ -56,9 +39,9 @@ describe('ReadMe Flavored Blocks', () => {
}
[/block]
`;
const ast = parse(text);
const ast = mdast(text);

expect(compile(ast)).toMatchInlineSnapshot(`
expect(md(ast)).toMatchInlineSnapshot(`
"[block:html]
{
\\"html\\": \\"<style>\\\\n summary {\\\\n padding-top: 8px;\\\\n outline: none !important;\\\\n user-select: none;\\\\n }\\\\n details[open] + details > summary {\\\\n padding-top: 0;\\\\n }\\\\n details > summary + hr {\\\\n opacity: .66;\\\\n }\\\\n</style>\\"
Expand All @@ -79,8 +62,8 @@ describe('ReadMe Magic Blocks', () => {
"favicon": "https://youtu.be/favicon.ico"
}
[/block]`;
const ast = parse(txt);
const out = compile(ast);
const ast = mdast(txt);
const out = md(ast);
expect(out).toMatchSnapshot();
});

Expand All @@ -101,8 +84,8 @@ describe('ReadMe Magic Blocks', () => {
}
[/block]
`;
const ast = parse(txt);
const out = compile(ast);
const ast = mdast(txt);
const out = md(ast);
expect(out).toMatchSnapshot();
});

Expand All @@ -117,8 +100,8 @@ describe('ReadMe Magic Blocks', () => {
And this is a paragraph!
`;
const ast = parse(txt);
const out = compile(ast);
const ast = mdast(txt);
const out = md(ast);
expect(out).toMatchSnapshot();
});

Expand All @@ -137,8 +120,8 @@ describe('ReadMe Magic Blocks', () => {
]
}
[/block]`;
const ast = parse(txt);
const out = compile(ast);
const ast = mdast(txt);
const out = md(ast);
expect(out).toMatchSnapshot();
});

Expand All @@ -158,8 +141,8 @@ describe('ReadMe Magic Blocks', () => {
]
}
[/block]`;
const ast = parse(txt);
const out = compile(ast);
const ast = mdast(txt);
const out = md(ast);
expect(out).toMatchSnapshot();
});

Expand All @@ -174,8 +157,8 @@ describe('ReadMe Magic Blocks', () => {
}]
}
[/block]`;
const ast = parse(txt);
const out = compile(ast);
const ast = mdast(txt);
const out = md(ast);

expect(out).toMatchSnapshot();
});
Expand All @@ -193,8 +176,8 @@ describe('ReadMe Magic Blocks', () => {
}]
}
[/block]`;
const ast = parse(txt);
const out = compile(ast);
const ast = mdast(txt);
const out = md(ast);

expect(out).toMatchSnapshot();
});
Expand All @@ -212,8 +195,8 @@ describe('ReadMe Magic Blocks', () => {
}]
}
[/block]`;
const ast = parse(txt);
const out = compile(ast);
const ast = mdast(txt);
const out = md(ast);

expect(out).toMatchSnapshot();
});
Expand All @@ -235,24 +218,24 @@ ${JSON.stringify(
`;

const ast = parse(txt);
const out = compile(ast);
const ast = mdast(txt);
const out = md(ast);
expect(out).toMatchSnapshot();
});

it('font-awesome emojis', () => {
const txt = ':fa-rss-square:';

const ast = parse(txt);
const out = compile(ast);
const ast = mdast(txt);
const out = md(ast);
expect(out).toMatchInlineSnapshot(`
":fa-rss-square:
"
`);
});

it('Tables', () => {
const md = `
const text = `
[block:parameters]
${JSON.stringify({
data: {
Expand All @@ -268,11 +251,11 @@ ${JSON.stringify({
[/block]
`;

expect(compile(parse(md))).toMatchSnapshot();
expect(md(mdast(text))).toMatchSnapshot();
});

it('Tables with breaks', () => {
const md = `
const text = `
[block:parameters]
${JSON.stringify({
data: {
Expand All @@ -288,6 +271,6 @@ ${JSON.stringify({
[/block]
`;

expect(compile(parse(md))).toMatchSnapshot();
expect(md(mdast(text))).toMatchSnapshot();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,22 @@ Object {
"type": "paragraph",
},
],
"position": Position {
"end": Object {
"column": 1,
"line": 6,
"offset": 19,
},
"indent": Array [
1,
1,
],
"start": Object {
"column": 1,
"line": 4,
"offset": 9,
},
},
"tag": "Test",
"type": "reusable-content",
}
Expand Down Expand Up @@ -207,6 +223,22 @@ Object {
"type": "paragraph",
},
],
"position": Position {
"end": Object {
"column": 1,
"line": 3,
"offset": 23,
},
"indent": Array [
1,
1,
],
"start": Object {
"column": 1,
"line": 1,
"offset": 0,
},
},
"tag": "MyCustomComponent",
"type": "reusable-content",
}
Expand Down
2 changes: 1 addition & 1 deletion processor/compile/reusable-content.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { type } from '../transform/reusable-content';
import { type } from '../parse/reusable-content-parser';

export default function ReusableContentCompiler() {
const { serialize = true } = this.data('reusableContent') || {};
Expand Down
1 change: 1 addition & 0 deletions processor/parse/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export { default as flavorEmbed } from './flavored/embed';

export { default as escape } from './escape';
export { default as compactHeadings } from './compact-headings';
export { default as reusableContentParser } from './reusable-content-parser';
export { default as variableParser } from './variable-parser';
export { default as gemojiParser } from './gemoji-parser';
export { default as htmlBlockParser } from './html-block';
38 changes: 38 additions & 0 deletions processor/parse/reusable-content-parser.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
const { insertBlockTokenizerBefore } = require('./utils');

export const type = 'reusable-content';

function tokenizeReusableContent(eat, value, silent) {
const { tags, disabled, wrap = true } = this.data('reusableContent');
if (disabled) return false;

// Modifies the regular expression to match from
// the start of the line
const match = /^<(?<tag>[A-Z]\S+)\s*\/>\s*\n/.exec(value);

if (!match || !match.groups.tag) return false;
const { tag } = match.groups;

/* istanbul ignore if */
if (silent) return true;

const node = wrap
? {
type: 'reusable-content',
tag,
children: tag in tags ? tags[tag] : [],
}
: tags[tag];

return eat(match[0])(node);
}

function parser() {
insertBlockTokenizerBefore.call(this, {
name: 'reusableContent',
before: 'html',
tokenizer: tokenizeReusableContent.bind(this),
});
}

export default parser;
3 changes: 1 addition & 2 deletions processor/transform/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import reusableContent from './reusable-content';
import singleCodeTabs from './single-code-tabs';
import tableCellInlineCode from './table-cell-inline-code';

export const remarkTransformers = [singleCodeTabs, reusableContent];
export const remarkTransformers = [singleCodeTabs];
export const rehypeTransformers = [tableCellInlineCode];
28 changes: 0 additions & 28 deletions processor/transform/reusable-content.js

This file was deleted.

0 comments on commit c9a1c1b

Please sign in to comment.