2017-10-12 01:46:44 +03:00
|
|
|
"use strict";
|
|
|
|
|
|
|
|
const remarkParse = require("remark-parse");
|
|
|
|
const unified = require("unified");
|
2018-05-24 21:30:45 +03:00
|
|
|
const pragma = require("./pragma");
|
2018-05-21 17:02:09 +03:00
|
|
|
const parseFrontMatter = require("../utils/front-matter");
|
2018-09-03 18:27:50 +03:00
|
|
|
const { mapAst } = require("./utils");
|
2018-08-13 17:23:09 +03:00
|
|
|
const mdx = require("./mdx");
|
2018-09-05 16:07:37 +03:00
|
|
|
const remarkMath = require("remark-math");
|
2017-10-12 01:46:44 +03:00
|
|
|
|
|
|
|
/**
|
|
|
|
* based on [MDAST](https://github.com/syntax-tree/mdast) with following modifications:
|
2017-11-07 11:42:38 +03:00
|
|
|
*
|
2017-10-12 01:46:44 +03:00
|
|
|
* 1. restore unescaped character (Text)
|
|
|
|
* 2. merge continuous Texts
|
2017-11-11 19:29:59 +03:00
|
|
|
* 3. replace whitespaces in InlineCode#value with one whitespace
|
|
|
|
* reference: http://spec.commonmark.org/0.25/#example-605
|
2017-10-12 01:46:44 +03:00
|
|
|
* 4. split Text into Sentence
|
2017-11-07 11:42:38 +03:00
|
|
|
*
|
2017-10-12 01:46:44 +03:00
|
|
|
* interface Word { value: string }
|
|
|
|
* interface Whitespace { value: string }
|
|
|
|
* interface Sentence { children: Array<Word | Whitespace> }
|
|
|
|
* interface InlineCode { children: Array<Sentence> }
|
|
|
|
*/
|
2018-08-13 17:23:09 +03:00
|
|
|
function createParse({ isMDX }) {
|
2018-09-03 18:27:50 +03:00
|
|
|
return text => {
|
2018-08-13 17:23:09 +03:00
|
|
|
const processor = unified()
|
|
|
|
.use(
|
|
|
|
remarkParse,
|
|
|
|
Object.assign(
|
|
|
|
{
|
|
|
|
footnotes: true,
|
|
|
|
commonmark: true
|
|
|
|
},
|
|
|
|
isMDX && { blocks: [mdx.BLOCKS_REGEX] }
|
|
|
|
)
|
|
|
|
)
|
|
|
|
.use(frontMatter)
|
2018-09-05 16:07:37 +03:00
|
|
|
.use(remarkMath)
|
2018-08-13 17:23:09 +03:00
|
|
|
.use(isMDX ? mdx.esSyntax : identity)
|
|
|
|
.use(liquid)
|
2018-09-03 18:27:50 +03:00
|
|
|
.use(isMDX ? htmlToJsx : identity);
|
2018-08-13 17:23:09 +03:00
|
|
|
return processor.runSync(processor.parse(text));
|
|
|
|
};
|
2017-10-12 01:46:44 +03:00
|
|
|
}
|
|
|
|
|
2018-08-13 17:23:09 +03:00
|
|
|
function identity(x) {
|
|
|
|
return x;
|
|
|
|
}
|
|
|
|
|
|
|
|
function htmlToJsx() {
|
|
|
|
return ast =>
|
2018-09-03 18:27:50 +03:00
|
|
|
mapAst(ast, (node, index, [parent]) => {
|
2018-08-13 17:23:09 +03:00
|
|
|
if (
|
|
|
|
node.type !== "html" ||
|
|
|
|
/^<!--[\s\S]*-->$/.test(node.value) ||
|
|
|
|
// inline html
|
|
|
|
parent.type === "paragraph"
|
|
|
|
) {
|
|
|
|
return node;
|
|
|
|
}
|
|
|
|
|
|
|
|
return Object.assign({}, node, { type: "jsx" });
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2018-05-21 17:02:09 +03:00
|
|
|
function frontMatter() {
|
2018-05-15 04:17:15 +03:00
|
|
|
const proto = this.Parser.prototype;
|
2018-05-21 17:02:09 +03:00
|
|
|
proto.blockMethods = ["frontMatter"].concat(proto.blockMethods);
|
|
|
|
proto.blockTokenizers.frontMatter = tokenizer;
|
2018-05-15 04:17:15 +03:00
|
|
|
|
|
|
|
function tokenizer(eat, value) {
|
2018-05-21 17:02:09 +03:00
|
|
|
const parsed = parseFrontMatter(value);
|
2018-05-15 04:17:15 +03:00
|
|
|
|
2018-05-21 17:02:09 +03:00
|
|
|
if (parsed.frontMatter) {
|
2018-07-03 04:54:40 +03:00
|
|
|
return eat(parsed.frontMatter.raw)(parsed.frontMatter);
|
2018-05-15 04:17:15 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
tokenizer.onlyAtStart = true;
|
|
|
|
}
|
|
|
|
|
2018-05-15 20:22:41 +03:00
|
|
|
function liquid() {
|
|
|
|
const proto = this.Parser.prototype;
|
|
|
|
const methods = proto.inlineMethods;
|
|
|
|
methods.splice(methods.indexOf("text"), 0, "liquid");
|
|
|
|
proto.inlineTokenizers.liquid = tokenizer;
|
|
|
|
|
|
|
|
function tokenizer(eat, value) {
|
|
|
|
const match = value.match(/^({%[\s\S]*?%}|{{[\s\S]*?}})/);
|
|
|
|
|
|
|
|
if (match) {
|
|
|
|
return eat(match[0])({
|
|
|
|
type: "liquidNode",
|
|
|
|
value: match[0]
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
tokenizer.locator = function(value, fromIndex) {
|
|
|
|
return value.indexOf("{", fromIndex);
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2018-08-13 17:23:09 +03:00
|
|
|
const baseParser = {
|
2018-05-24 21:30:45 +03:00
|
|
|
astFormat: "mdast",
|
|
|
|
hasPragma: pragma.hasPragma,
|
|
|
|
locStart: node => node.position.start.offset,
|
2018-09-01 07:14:53 +03:00
|
|
|
locEnd: node => node.position.end.offset,
|
|
|
|
preprocess: text => text.replace(/\n\s+$/, "\n") // workaround for https://github.com/remarkjs/remark/issues/350
|
2018-05-24 21:30:45 +03:00
|
|
|
};
|
|
|
|
|
2018-08-13 17:23:09 +03:00
|
|
|
const markdownParser = Object.assign({}, baseParser, {
|
|
|
|
parse: createParse({ isMDX: false })
|
|
|
|
});
|
|
|
|
|
|
|
|
const mdxParser = Object.assign({}, baseParser, {
|
|
|
|
parse: createParse({ isMDX: true })
|
|
|
|
});
|
|
|
|
|
2018-05-24 21:30:45 +03:00
|
|
|
module.exports = {
|
|
|
|
parsers: {
|
2018-08-13 17:23:09 +03:00
|
|
|
remark: markdownParser,
|
2018-05-24 21:30:45 +03:00
|
|
|
// TODO: Delete this in 2.0
|
2018-08-13 17:23:09 +03:00
|
|
|
markdown: markdownParser,
|
|
|
|
mdx: mdxParser
|
2018-05-24 21:30:45 +03:00
|
|
|
}
|
|
|
|
};
|