diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0160678 --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +node_modules +.idea +dist +test.md +test.html +testchapter.md +git diff --git a/README.md b/README.md index 19d4402..3bfe8be 100644 --- a/README.md +++ b/README.md @@ -1 +1,45 @@ -markdown-super +# markdown-super + +Markdown-Super is a markkdown-parser using markdown it that allows including other markdown-documents and manage markdown-it plugins inside the document itself. + +## Including other markdown documents + +A document can be included by using + +```markdown +[!include]: path/to/file +``` + +## Managing markdown-it plugins + +The usage of a markdown-it plugin inside a document can be decleared by using + +```markdown +[!use]: plugin1, plugin2, plugin3 +``` + +The plugin names are listed in the following table. Basically it is just the package name with the markdown-it removed: + +| module | import name | +|----------------------|-------------| +| markdown-it-footnote | footnote +| markdown-it-anchor | anchor +| markdown-it-mark | mark +| markdown-it-sub | sub +| markdown-it-attrs | attrs +| markdown-it-abbr | abbr +| markdown-it-checkbox | checkbox +| markdown-it-imsize | imsize +| markdown-it-highlightjs | highlightjs +| markdown-it-prism | prism +| markdown-it-toc-done-right | toc-done-right +| markdown-it-smartarrows | smartarrows +| markdown-it-plantuml | plantuml +| markdown-it-mathjax | mathjax +| markdown-it-math | math + +For example you can declare the use of `markdown-it-emoji` the following: + +```markdown +[!use]: emoji +``` diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..59a1fc0 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,429 @@ +{ + "name": "markdown-super", + "version": "1.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@types/chokidar": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@types/chokidar/-/chokidar-2.1.3.tgz", + "integrity": "sha512-6qK3xoLLAhQVTucQGHTySwOVA1crHRXnJeLwqK6KIFkkKa2aoMFXh+WEi8PotxDtvN6MQJLyYN9ag9P6NLV81w==", + "requires": { + "chokidar": "*" + } + }, + "@types/fs-extra": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-8.0.0.tgz", + "integrity": "sha512-bCtL5v9zdbQW86yexOlXWTEGvLNqWxMFyi7gQA7Gcthbezr2cPSOb8SkESVKA937QD5cIwOFLDFt0MQoXOEr9Q==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/linkify-it": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-2.1.0.tgz", + "integrity": "sha512-Q7DYAOi9O/+cLLhdaSvKdaumWyHbm7HAk/bFwwyTuU0arR5yyCeW5GOoqt4tJTpDRxhpx9Q8kQL6vMpuw9hDSw==", + "dev": true + }, + "@types/markdown-it": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-0.0.8.tgz", + "integrity": "sha512-ouaTOi5kAdkTPl97u6uDkth9od4pQffPF9STcjYVZKFrEwLYf15s7Z772WxWE3IOcYBJglaT0XqdyNEiEfGgYg==", + "dev": true, + "requires": { + "@types/linkify-it": "*" + } + }, + "@types/node": { + "version": "12.6.8", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.6.8.tgz", + "integrity": "sha512-aX+gFgA5GHcDi89KG5keey2zf0WfZk/HAQotEamsK2kbey+8yGKcson0hbK8E+v0NArlCJQCqMP161YhV6ZXLg==", + "dev": true + }, + "anymatch": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.0.3.tgz", + "integrity": "sha512-c6IvoeBECQlMVuYUjSwimnhmztImpErfxJzWZhIQinIvQWoGOnB0dLIgifbPHQt5heS6mNlaZG16f06H3C8t1g==", + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "ascii2mathml": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/ascii2mathml/-/ascii2mathml-0.6.2.tgz", + "integrity": "sha512-tkPONh2Y7ZpuGQw6AiRnExX/CSYf5C2T/rF+UMJq5n0Us7+QjL8VY5ZE16xo9wcXhdqPkl/F7lzEzU9HX0YKng==", + "optional": true, + "requires": { + "minimist": "^1.2.0" + } + }, + "binary-extensions": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.0.0.tgz", + "integrity": "sha512-Phlt0plgpIIBOGTT/ehfFnbNlfsDEiqmzE2KRXoX1bLIlir4X/MR+zSyBEkL05ffWgnRSf/DXv+WrUAVr93/ow==" + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "requires": { + "fill-range": "^7.0.1" + } + }, + "chokidar": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.0.2.tgz", + "integrity": "sha512-c4PR2egjNjI1um6bamCQ6bUNPDiyofNQruHvKgHQ4gDUP/ITSVSzNsiI5OWtHOsX323i5ha/kk4YmOZ1Ktg7KA==", + "requires": { + "anymatch": "^3.0.1", + "braces": "^3.0.2", + "fsevents": "^2.0.6", + "glob-parent": "^5.0.0", + "is-binary-path": "^2.1.0", + "is-glob": "^4.0.1", + "normalize-path": "^3.0.0", + "readdirp": "^3.1.1" + } + }, + "clipboard": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/clipboard/-/clipboard-2.0.4.tgz", + "integrity": "sha512-Vw26VSLRpJfBofiVaFb/I8PVfdI1OxKcYShe6fm0sP/DtmiWQNCjhM/okTvdCo0G+lMMm1rMYbk4IK4x1X+kgQ==", + "optional": true, + "requires": { + "good-listener": "^1.2.2", + "select": "^1.1.2", + "tiny-emitter": "^2.0.0" + } + }, + "delegate": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/delegate/-/delegate-3.2.0.tgz", + "integrity": "sha512-IofjkYBZaZivn0V8nnsMJGBr4jVLxHDheKSW88PyxS5QC4Vo9ZbZVvhzlSxY87fVq3STR6r+4cGepyHkcWOQSw==", + "optional": true + }, + "entities": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz", + "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==" + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "fsevents": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.0.7.tgz", + "integrity": "sha512-a7YT0SV3RB+DjYcppwVDLtn13UQnmg0SWZS7ezZD0UjnLwXmy8Zm21GMVGLaFGimIqcvyMQaOJBrop8MyOp1kQ==", + "optional": true + }, + "glob-parent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.0.0.tgz", + "integrity": "sha512-Z2RwiujPRGluePM6j699ktJYxmPpJKCfpGA13jz2hmFZC7gKetzrWvg5KN3+OsIFmydGyZ1AVwERCq1w/ZZwRg==", + "requires": { + "is-glob": "^4.0.1" + } + }, + "good-listener": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/good-listener/-/good-listener-1.2.2.tgz", + "integrity": "sha1-1TswzfkxPf+33JoNR3CWqm0UXFA=", + "optional": true, + "requires": { + "delegate": "^3.1.2" + } + }, + "graceful-fs": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.0.tgz", + "integrity": "sha512-jpSvDPV4Cq/bgtpndIWbI5hmYxhQGHPC4d4cqBPb4DLniCfhJokdXhwhaDuLBGLQdvvRum/UiX6ECVIPvDXqdg==" + }, + "highlight.js": { + "version": "9.15.8", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-9.15.8.tgz", + "integrity": "sha512-RrapkKQWwE+wKdF73VsOa2RQdIoO3mxwJ4P8mhbI6KYJUraUHRKM5w5zQQKXNk0xNL4UVRdulV9SBJcmzJNzVA==" + }, + "is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "requires": { + "binary-extensions": "^2.0.0" + } + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=" + }, + "is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" + }, + "jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "requires": { + "graceful-fs": "^4.1.6" + } + }, + "line-by-line": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/line-by-line/-/line-by-line-0.1.6.tgz", + "integrity": "sha512-MmwVPfOyp0lWnEZ3fBA8Ah4pMFvxO6WgWovqZNu7Y4J0TNnGcsV4S1LzECHbdgqk1hoHc2mFP1Axc37YUqwafg==" + }, + "linkify-it": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-2.2.0.tgz", + "integrity": "sha512-GnAl/knGn+i1U/wjBz3akz2stz+HrHLsxMwHQGofCDfPvlf+gDKN58UtfmUquTY4/MXeE2x7k19KQmeoZi94Iw==", + "requires": { + "uc.micro": "^1.0.1" + } + }, + "lodash.flow": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/lodash.flow/-/lodash.flow-3.5.0.tgz", + "integrity": "sha1-h79AKSuM+D5OjOGjrkIJ4gBxZ1o=" + }, + "markdown-it": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-9.0.1.tgz", + "integrity": "sha512-XC9dMBHg28Xi7y5dPuLjM61upIGPJG8AiHNHYqIaXER2KNnn7eKnM5/sF0ImNnyoV224Ogn9b1Pck8VH4k0bxw==", + "requires": { + "argparse": "^1.0.7", + "entities": "~1.1.1", + "linkify-it": "^2.0.0", + "mdurl": "^1.0.1", + "uc.micro": "^1.0.5" + } + }, + "markdown-it-abbr": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/markdown-it-abbr/-/markdown-it-abbr-1.0.4.tgz", + "integrity": "sha1-1mtTZFIcuz3Yqlna37ovtoZcj9g=" + }, + "markdown-it-anchor": { + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/markdown-it-anchor/-/markdown-it-anchor-5.2.4.tgz", + "integrity": "sha512-n8zCGjxA3T+Mx1pG8HEgbJbkB8JFUuRkeTZQuIM8iPY6oQ8sWOPRZJDFC9a/pNg2QkHEjjGkhBEl/RSyzaDZ3A==" + }, + "markdown-it-attrs": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/markdown-it-attrs/-/markdown-it-attrs-2.4.1.tgz", + "integrity": "sha512-BASnIYS+JLpjlhDf7jLV8VOuccxjfDDnQcz5dLfgPsYw8OsgbASexADdIkF7tIdGn+jaQSA4qOZXM3v3W3JBCg==" + }, + "markdown-it-checkbox": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/markdown-it-checkbox/-/markdown-it-checkbox-1.1.0.tgz", + "integrity": "sha1-IM/5fzPXfRcvnc8bz8ks7MUzD6w=", + "requires": { + "underscore": "^1.8.2" + } + }, + "markdown-it-emoji": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/markdown-it-emoji/-/markdown-it-emoji-1.4.0.tgz", + "integrity": "sha1-m+4OmpkKljupbfaYDE/dsF37Tcw=" + }, + "markdown-it-footnote": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/markdown-it-footnote/-/markdown-it-footnote-3.0.2.tgz", + "integrity": "sha512-JVW6fCmZWjvMdDQSbOT3nnOQtd9iAXmw7hTSh26+v42BnvXeVyGMDBm5b/EZocMed2MbCAHiTX632vY0FyGB8A==" + }, + "markdown-it-highlightjs": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/markdown-it-highlightjs/-/markdown-it-highlightjs-3.0.0.tgz", + "integrity": "sha1-7T3WGcormOa/IRLRY79EQEM0AhA=", + "requires": { + "highlight.js": "^9.9.0", + "lodash.flow": "^3.1.0" + } + }, + "markdown-it-imsize": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/markdown-it-imsize/-/markdown-it-imsize-2.0.1.tgz", + "integrity": "sha1-zKBCeQXQUziiR8ucqdloxc3dUXA=" + }, + "markdown-it-ins": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/markdown-it-ins/-/markdown-it-ins-2.0.0.tgz", + "integrity": "sha1-papqMPHi9x6Ul1Z8/f9A8f3mdIM=" + }, + "markdown-it-mark": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/markdown-it-mark/-/markdown-it-mark-2.0.0.tgz", + "integrity": "sha1-RqGqlHEFrtgYiXjgoBYXnkBPQsc=" + }, + "markdown-it-math": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/markdown-it-math/-/markdown-it-math-4.1.1.tgz", + "integrity": "sha512-LQ0hREgMgN4tNcy2PGyw1XypjmKJjc+ZzATMuDIVD/Bagr5SGL198uHleVdiFDrNdXpqVmL4N1KD1GYyftMakQ==", + "requires": { + "ascii2mathml": "^0.6.2" + } + }, + "markdown-it-mathjax": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/markdown-it-mathjax/-/markdown-it-mathjax-2.0.0.tgz", + "integrity": "sha1-ritPTFxxmgP55HXGZPeyaFIx2ek=" + }, + "markdown-it-plantuml": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/markdown-it-plantuml/-/markdown-it-plantuml-1.4.1.tgz", + "integrity": "sha512-13KgnZaGYTHBp4iUmGofzZSBz+Zj6cyqfR0SXUIc9wgWTto5Xhn7NjaXYxY0z7uBeTUMlc9LMQq5uP4OM5xCHg==" + }, + "markdown-it-prism": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/markdown-it-prism/-/markdown-it-prism-2.0.2.tgz", + "integrity": "sha512-tBRK+L36D2m4NauUr9teyFYJXBtw6XtuCdCJJWeNabSBwKlgI3oil4TfHHWd0bunwSf8zkmXEZkJzDVgVkfp+g==", + "requires": { + "prismjs": "^1.16.0" + } + }, + "markdown-it-smartarrows": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/markdown-it-smartarrows/-/markdown-it-smartarrows-1.0.1.tgz", + "integrity": "sha1-tXDpwP+YEuDbas4Zr6W6ErZLuac=" + }, + "markdown-it-sub": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/markdown-it-sub/-/markdown-it-sub-1.0.0.tgz", + "integrity": "sha1-N1/WAm6ufdywEkl/ZBEZXqHjr+g=" + }, + "markdown-it-toc-done-right": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/markdown-it-toc-done-right/-/markdown-it-toc-done-right-4.0.2.tgz", + "integrity": "sha512-LIdwU8coEdBa6JxhMmcst5Qc9/ptVDmUB6dJuJzlxaV75Dry+AziKpQRgZ42SMQ5m7hpb7z6b0erIRoYk+bMWA==" + }, + "mdurl": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", + "integrity": "sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4=" + }, + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "optional": true + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==" + }, + "picomatch": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.0.7.tgz", + "integrity": "sha512-oLHIdio3tZ0qH76NybpeneBhYVj0QFTfXEFTc/B3zKQspYfYYkWYgFsmzo+4kvId/bQRcNkVeguI3y+CD22BtA==" + }, + "prismjs": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.17.1.tgz", + "integrity": "sha512-PrEDJAFdUGbOP6xK/UsfkC5ghJsPJviKgnQOoxaDbBjwc8op68Quupwt1DeAFoG8GImPhiKXAvvsH7wDSLsu1Q==", + "requires": { + "clipboard": "^2.0.0" + } + }, + "readdirp": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.1.1.tgz", + "integrity": "sha512-XXdSXZrQuvqoETj50+JAitxz1UPdt5dupjT6T5nVB+WvjMv2XKYj+s7hPeAVCXvmJrL36O4YYyWlIC3an2ePiQ==", + "requires": { + "picomatch": "^2.0.4" + } + }, + "select": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/select/-/select-1.1.2.tgz", + "integrity": "sha1-DnNQrN7ICxEIUoeG7B1EGNEbOW0=", + "optional": true + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" + }, + "tiny-emitter": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tiny-emitter/-/tiny-emitter-2.1.0.tgz", + "integrity": "sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q==", + "optional": true + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "requires": { + "is-number": "^7.0.0" + } + }, + "tsc": { + "version": "1.20150623.0", + "resolved": "https://registry.npmjs.org/tsc/-/tsc-1.20150623.0.tgz", + "integrity": "sha1-Trw8d04WkUjLx2inNCUz8ILHpuU=", + "dev": true + }, + "typescript": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.5.3.tgz", + "integrity": "sha512-ACzBtm/PhXBDId6a6sDJfroT2pOWt/oOnk4/dElG5G33ZL776N3Y6/6bKZJBFpd+b05F3Ct9qDjMeJmRWtE2/g==", + "dev": true + }, + "uc.micro": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", + "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==" + }, + "underscore": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.9.1.tgz", + "integrity": "sha512-5/4etnCkd9c8gwgowi5/om/mYO5ajCaOgdzj/oW+0eQV9WxKBDZw5+ycmKmeaTXjInS/W0BzpGLo2xR2aBwZdg==" + }, + "uninstall": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/uninstall/-/uninstall-0.0.0.tgz", + "integrity": "sha1-ED5uN+nFLshXVCzSWQI9ccej+ys=" + }, + "universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==" + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..36efc0f --- /dev/null +++ b/package.json @@ -0,0 +1,44 @@ +{ + "name": "markdown-super", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC", + "devDependencies": { + "@types/fs-extra": "^8.0.0", + "@types/markdown-it": "0.0.8", + "@types/node": "^12.6.8", + "tsc": "^1.20150623.0", + "typescript": "^3.5.3" + }, + "dependencies": { + "@types/chokidar": "^2.1.3", + "chokidar": "^3.0.2", + "fs-extra": "^8.1.0", + "line-by-line": "^0.1.6", + "markdown-it": "^9.0.1", + "markdown-it-abbr": "^1.0.4", + "markdown-it-anchor": "^5.2.4", + "markdown-it-attrs": "^2.4.1", + "markdown-it-checkbox": "^1.1.0", + "markdown-it-emoji": "^1.4.0", + "markdown-it-footnote": "^3.0.2", + "markdown-it-highlightjs": "^3.0.0", + "markdown-it-imsize": "^2.0.1", + "markdown-it-ins": "^2.0.0", + "markdown-it-mark": "^2.0.0", + "markdown-it-math": "^4.1.1", + "markdown-it-mathjax": "^2.0.0", + "markdown-it-plantuml": "^1.4.1", + "markdown-it-prism": "^2.0.2", + "markdown-it-smartarrows": "^1.0.1", + "markdown-it-sub": "^1.0.0", + "markdown-it-toc-done-right": "^4.0.2", + "uninstall": "0.0.0" + } +} diff --git a/src/CommandParser.ts b/src/CommandParser.ts new file mode 100644 index 0000000..2a40532 --- /dev/null +++ b/src/CommandParser.ts @@ -0,0 +1,100 @@ +import * as path from "path"; +import * as fsx from "fs-extra"; +import {Renderer} from "./Renderer"; +import {markdownPlugins} from './plugins'; + +namespace Matchers { + export const commandMatcher: RegExp = /\[ *!(\w+) *]: *(.*)/g; +} + +export class CommandParser { + public projectFiles: string[]; + + constructor() { + this.projectFiles = []; + } + + async processCommands(doc: string, docpath: string, renderer: Renderer) { + const inputLines: string[] = doc.split('\n'); + let outputLines: string[] = []; + let mainDir: string = path.dirname(docpath); + this.projectFiles = []; + this.projectFiles.push(docpath); + + while (inputLines.length > 0) { + let inputLine = inputLines.shift(); + let match: RegExpExecArray = Matchers.commandMatcher.exec(inputLine); + + if (match != null && match[0]) { + switch(match[1]) { + case 'use': + let plugins = match[2].split(','); + for (let mdPlugin of plugins) { + this.addMarkdownPlugin(mdPlugin.replace(/^ *| *$/g, ''), renderer); + } + break; + case 'include': + try { + let included = await this.getInclude(match[2], mainDir); + inputLines.unshift(...included); + } catch (err) { + console.error(err.message); + outputLines.push(inputLine); + } + break; + default: + outputLines.push(inputLine); + } + } else { + outputLines.push(inputLine); + } + } + + return outputLines.join('\n'); + } + + /** + * Adds a markdown-it plugin to the renderer + * @param pluginName + * @param renderer + */ + private addMarkdownPlugin(pluginName: string, renderer: Renderer): void { + try { + // @ts-ignore + let moduleName = markdownPlugins[pluginName]; + if (moduleName) { + let plugin: any = require(moduleName); + if (plugin) { + renderer.addPlugin(plugin); + } + } else { + console.error(`Plugin "${pluginName}" not found.`); + } + } catch (err) { + console.error(err); + } + } + + /** + * Imports a file into the markdown. + * @param filepath + * @param mainDir + */ + private async getInclude(filepath: string, mainDir: string): Promise { + let importPath: string; + + if (path.isAbsolute(filepath)) { + importPath = filepath; + } else { + importPath = path.join(mainDir, filepath); + } + this.projectFiles.push(importPath); + if ((await fsx.pathExists(importPath))) { + let importDoc = await fsx.readFile(importPath, 'utf-8'); + importDoc = importDoc.replace(/\r\n/g, '\n'); + return importDoc.split('\n'); + } else { + throw new Error(`The file ${filepath} can not be included (not found).`); + } + } +} diff --git a/src/Renderer.ts b/src/Renderer.ts new file mode 100644 index 0000000..2c62e21 --- /dev/null +++ b/src/Renderer.ts @@ -0,0 +1,93 @@ +import * as MarkdownIt from 'markdown-it'; +import * as fsx from 'fs-extra'; +import * as path from 'path'; +import * as chokidar from 'chokidar'; +import {CommandParser} from "./CommandParser"; +import {EventEmitter} from "events"; + +export class Renderer extends EventEmitter { + private md: MarkdownIt; + private beforeRendering: Function[]; + private afterRendering: Function[]; + private commandParser: CommandParser; + + constructor() { + super(); + this.md = new MarkdownIt(); + this.beforeRendering = []; + this.afterRendering = []; + this.commandParser = new CommandParser(); + this.configure(); + } + + /** + * Assign a function that should be used before rendering. + * @param func + */ + public useBefore(func: Function) { + this.beforeRendering.push(func); + } + + /** + * Assign a function that shold be applied after rendering. + * @param func + */ + public useAfter(func: Function) { + this.afterRendering.push(func); + } + + /** + * Adds a plugin to markdown-it + * @param mdPlugin + */ + public addPlugin(mdPlugin: any) { + this.md.use(mdPlugin); + } + + /** + * Applies all before rendering functions, then renders using markdown-it, then applies all after rendering functions. + * @param filename + */ + public async render(filename: string) { + filename = path.resolve(filename); + let document = await fsx.readFile(filename, 'utf-8'); + document = document.replace(/\r\n/g, '\n'); + for (let func of this.beforeRendering) { + document = await func(document, filename, this); + } + let result: string = this.md.render(document); + + for (let func of this.afterRendering) { + result = await func(result, filename, this); + } + this.emit('rendered', result); + return result; + } + + /** + * Watches for changes. + * @param filename + */ + public watch(filename: string) { + const watcher = chokidar.watch(filename); + watcher.on('change', async () => { + console.log('Change detected. Rerendering'); + let start = Date.now(); + this.md = new MarkdownIt(); + await this.render(filename); + console.log(`Rendering took ${Date.now() - start} ms.`); + }); + this.on('rendered', () => { + watcher.add(this.commandParser.projectFiles); + }); + this.render(filename); + return watcher; + } + + /** + * Default pre and post rendering modules to use. + */ + private configure() { + this.useBefore((a: string, b: string, c: Renderer) => this.commandParser.processCommands(a, b, c)); + } +} diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 0000000..0162c50 --- /dev/null +++ b/src/index.ts @@ -0,0 +1,20 @@ +import {Renderer} from "./Renderer"; +import {writeFile} from 'fs-extra'; +import {extname} from 'path'; + +async function main() { + const args = process.argv.slice(2); + let renderer = new Renderer(); + + if (args[1] && args[1] === '--watch') { + renderer.on('rendered', async (html) => { + await writeFile(args[0].replace(extname(args[0]), '') + '.html', html); + }); + renderer.watch(args[0]); + } else { + let html = await renderer.render(args[0]); + await writeFile(args[0].replace(extname(args[0]), '') + '.html', html); + } +} + +main() diff --git a/src/plugins.ts b/src/plugins.ts new file mode 100644 index 0000000..380a864 --- /dev/null +++ b/src/plugins.ts @@ -0,0 +1,18 @@ +export const markdownPlugins: object = { + emoji: 'markdown-it-emoji', + footnote: 'markdown-it-footnote', + anchor: 'markdown-it-anchor', + mark: 'markdown-it-mark', + sub: 'markdown-it-sub', + attrs: 'markdown-it-attrs', + abbr: 'markdown-it-abbr', + checkbox: 'markdown-it-checkbox', + imsize: 'markdown-it-imsize', + highlightjs: 'markdown-it-highlightjs', + prism: 'markdown-it-prism', + smartarrows: 'markdown-it-smartarrows', + plantuml: 'markdown-it-plantuml', + mathjax: 'markdown-it-mathjax', + math: 'markdown-it-math', + 'toc-done-right': 'markdown-it-toc-done-right' +}; diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..33b06d3 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,21 @@ +{ + "compileOnSave": true, + "compilerOptions": { + "noImplicitAny": true, + "removeComments": true, + "preserveConstEnums": true, + "outDir": "./dist", + "sourceMap": true, + "target": "es2018", + "allowJs": true, + "moduleResolution": "node", + "module": "commonjs" + }, + "include": [ + "src/**/*" + ], + "exclude": [ + "node_modules", + "**/*.spec.ts" + ] +}