{"bugs":{"url":"https://github.com/Khan/simple-markdown/issues"},"dist":{"shasum":"7945033cdd1b0ef91d8136327e80aeb550f26e3c","tarball":"https://registry.npmjs.org/simple-markdown/-/simple-markdown-0.7.0.tgz","fileCount":7,"integrity":"sha512-B6HF1jMPBoDFeZ+BhHJnrQGpJCCQxp/1fDDD7sp1SEtwIXhWUZ8+ZbOUruPwmorzlEzv7QtbpAoCbrzVFa8ZZA==","signatures":[{"sig":"MEYCIQC+Pnc8rVyeGsWuz6z6YPTBfxFymnhke7TgAqfekF4O2QIhAM5KTGAGfZNwMkX+sH3xPxk0gz1C2W9yqxwtWRN+r68E","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":112839,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJdsjO5CRA9TVsSAnZWagAAPMcP/3+gp5MOipVqc5JolsXZ\nHi6i0Qtb0XQfRDxLuqsCg32J1eghTp3oI4ZNuzlskE8i56ryHFtrT+V5+wxj\n3zr4Lk8iG/DsaERGT6YJnPu+qai09FFvqIGL37aC7VmC7BXUTSKm1/UXAcxg\nczO1G0ta0KsVjjQzyFvYBSeG16fZ5cJPiVLLNyLd6uhCGftf8JVtlrRYSgtP\nytUW7ybtuH+xxnWn+0CboU4JA/jMCaj2nLT+JFyekiKKpDn30ifNPkBdnsqB\naO+5HkLEcN67kbQllln7oC4WH7Lolq8ljMj1RS+4iLF3KaoNDDA8pE4AbpdZ\nczUOQQ+NRwonJ3kNbjkyV6AkNTXC77wMGdO3+b6C41ZeqCSKjLUkpaQDhaSz\n8juIcY3SwMLkQenSUv2ZeqIau3wOIwXhvWnJImXKwwFbtdIJeFHLjGWWdZdP\nlvYfJVZwWYbP+0IRLA17jKFx8o1nXUfp/+tW0ZY8F9GFBMO4HU5xaD1H/J9H\n/JglJMHX98lXPHDK2ec4s5aE3zWbzFuqY5wFN6qzoQzzZOB/xX/7EaSw7mr4\nhQAE+aD8IXvVt/LlTuamJK/4dGT5ktjNtN7bFAA0QCq+mTevIGqzNS/RlNbI\nqbHWv/yogrtbI0BmiaunvZqgXDhc420ILrbvBfOIbFBLb5ld3GdVGmFRaK/4\neSeb\r\n=Ncgz\r\n-----END PGP SIGNATURE-----\r\n"},"main":"simple-markdown.js","name":"simple-markdown","types":"simple-markdown.d.ts","author":{"name":"Aria Buckles"},"readme":"simple-markdown\n===============\n\nsimple-markdown is a markdown-like parser designed for simplicity\nand extensibility.\n\n[Change log](https://github.com/Khan/simple-markdown/releases)\n\nPhilosophy\n----------\n\nMost markdown-like parsers aim for [speed][marked] or\n[edge case handling][CommonMark].\nsimple-markdown aims for extensibility and simplicity.\n\n[marked]: https://github.com/chjj/marked\n[CommonMark]: https://github.com/jgm/CommonMark\n\nWhat does this mean?\nMany websites using markdown-like languages have custom extensions,\nsuch as `@`mentions or issue number linking. Unfortunately, most\nmarkdown-like parsers don't allow extension without\nforking, and can be difficult to modify even when forked.\nsimple-markdown is designed to allow simple addition of\ncustom extensions without needing to be forked.\n\nAt Khan Academy, we use simple-markdown to format\nover half of our math exercises, because we need\n[markdown extensions][PerseusMarkdown] for math text and\ninteractive widgets.\n\n[PerseusMarkdown]: https://github.com/Khan/perseus/blob/master/src/perseus-markdown.jsx\n\nsimple-markdown is [MIT licensed][LICENSE].\n\n[LICENSE]: https://github.com/Khan/simple-markdown/blob/master/LICENSE\n\nGetting started\n---------------\n\nFirst, let's parse and output some generic markdown using\nsimple-markdown.\n\nIf you want to run these examples in\nnode, you should run `npm install` in the simple-markdown\nfolder or `npm install simple-markdown` in your project's\nfolder. Then you can acquire the `SimpleMarkdown` variable\nwith:\n\n```javascript\n    var SimpleMarkdown = require(\"simple-markdown\");\n```\n\nThen let's get a basic markdown parser and outputter.\n`SimpleMarkdown` provides default parsers/outputters for\ngeneric markdown:\n\n```javascript\n    var mdParse = SimpleMarkdown.defaultBlockParse;\n    var mdOutput = SimpleMarkdown.defaultOutput;\n```\n\n`mdParse` can give us a syntax tree:\n\n```javascript\n    var syntaxTree = mdParse(\"Here is a paragraph and an *em tag*.\");\n```\n\nLet's inspect our syntax tree:\n\n```javascript\n    // pretty-print this with 4-space indentation:\n    console.log(JSON.stringify(syntaxTree, null, 4));\n    => [\n        {\n            \"content\": [\n                {\n                    \"content\": \"Here is a paragraph and an \",\n                    \"type\": \"text\"\n                },\n                {\n                    \"content\": [\n                        {\n                            \"content\": \"em tag\",\n                            \"type\": \"text\"\n                        }\n                    ],\n                    \"type\": \"em\"\n                },\n                {\n                    \"content\": \".\",\n                    \"type\": \"text\"\n                }\n            ],\n            \"type\": \"paragraph\"\n        }\n    ]\n```\n\nThen to turn that into an array of React elements, we can\ncall `mdOutput`:\n\n```javascript\n    mdOutput(syntaxTree)\n    => [ { type: 'div',\n        key: null,\n        ref: null,\n        _owner: null,\n        _context: {},\n        _store: { validated: false, props: [Object] } } ]\n```\n\n\nAdding a simple extension\n-------------------------\n\nLet's add an underline extension! To do this, we'll need to create\na new rule and then make a new parser/outputter. The next section\nwill explain how all of these steps work in greater detail. (To\nfollow along with these examples, you'll also need\n[underscore][underscore].)\n\n[underscore]: http://underscorejs.org/\n\nFirst, we create a new rule. We'll look for double underscores\nsurrounding text.\n\nWe'll put underlines right\nbefore `em`s, so that `__` will be parsed before `_`\nfor emphasis/italics.\n\nA regex to capture this would look something\nlike `/^__([\\s\\S]+?)__(?!_)/`. This matches `__`, followed by\nany content until it finds another `__` not followed by a\nthird `_`.\n\n```javascript\n    var underlineRule = {\n        // Specify the order in which this rule is to be run\n        order: SimpleMarkdown.defaultRules.em.order - 0.5,\n        \n        // First we check whether a string matches\n        match: function(source) {\n            return /^__([\\s\\S]+?)__(?!_)/.exec(source);\n        },\n        \n        // Then parse this string into a syntax node\n        parse: function(capture, parse, state) {\n            return {\n                content: parse(capture[1], state)\n            };\n        },\n        \n        // Finally transform this syntax node into a\n        // React element\n        react: function(node, output) {\n            return React.DOM.u(null, output(node.content));\n        },\n\n        // Or an html element:\n        // (Note: you may only need to make one of `react:` or\n        // `html:`, as long as you never ask for an outputter\n        // for the other type.)\n        html: function(node, output) {\n            return '<u>' + output(node.content) + '</u>';\n        },\n    };\n```\n\nThen, we need to add this rule to the other rules:\n\n```javascript\n    var rules = _.extend({}, SimpleMarkdown.defaultRules, {\n        underline: underlineRule\n    });\n```\n\nFinally, we need to build our parser and outputters:\n\n```javascript\n    var rawBuiltParser = SimpleMarkdown.parserFor(rules);\n    var parse = function(source) {\n        var blockSource = source + \"\\n\\n\";\n        return rawBuiltParser(blockSource, {inline: false});\n    };\n    // You probably only need one of these: choose depending on\n    // whether you want react nodes or an html string:\n    var reactOutput = SimpleMarkdown.reactFor(SimpleMarkdown.ruleOutput(rules, 'react'));\n    var htmlOutput = SimpleMarkdown.htmlFor(SimpleMarkdown.ruleOutput(rules, 'html'));\n```\n\nNow we can use our custom `parse` and `output` functions to parse\nmarkdown with underlines!\n\n```javascript\n    var syntaxTree = parse(\"__hello underlines__\");\n    console.log(JSON.stringify(syntaxTree, null, 4));\n    => [\n        {\n            \"content\": [\n                {\n                    \"content\": [\n                        {\n                            \"content\": \"hello underlines\",\n                            \"type\": \"text\"\n                        }\n                    ],\n                    \"type\": \"underline\"\n                }\n            ],\n            \"type\": \"paragraph\"\n        }\n    ]\n    \n    reactOutput(syntaxTree)\n    => [ { type: 'div',\n        key: null,\n        ref: null,\n        _owner: null,\n        _context: {},\n        _store: { validated: false, props: [Object] } } ]\n\n    htmlOutput(syntaxTree)\n\n    => '<div class=\"paragraph\"><u>hello underlines</u></div>'\n```\n\n\nBasic parsing/output API\n------------------------\n\n#### `SimpleMarkdown.defaultBlockParse(source)`\n\nReturns a syntax tree of the result of parsing `source` with the\ndefault markdown rules. Assumes a block scope.\n\n#### `SimpleMarkdown.defaultInlineParse(source)`\n\nReturns a syntax tree of the result of parsing `source` with the\ndefault markdown rules, where `source` is assumed to be inline text.\nDoes not emit `<p>` elements. Useful for allowing inline markdown\nformatting in one-line fields where paragraphs, lists, etc. are\ndisallowed.\n\n#### `SimpleMarkdown.defaultImplicitParse(source)`\n\nParses `source` as block if it ends with `\\n\\n`, or inline if not.\n\n#### `SimpleMarkdown.defaultOutput(syntaxTree)`\n\nReturns React-renderable output for `syntaxTree`.\n\n*Note: raw html output will be coming soon*\n\n\nExtension Overview\n------------------\n\nElements in simple-markdown are generally created from rules.\nFor parsing, rules must specify `match` and `parse` methods.\nFor output, rules must specify a `react` or `html` method\n(or both), depending on which outputter you create afterwards.\n\nHere is an example rule, a slightly modified version of what\nsimple-markdown uses for parsing **strong** (**bold**) text:\n\n```javascript\n    strong: {\n        match: function(source, state, lookbehind) {\n            return /^\\*\\*([\\s\\S]+?)\\*\\*(?!\\*)/.exec(source);\n        },\n        parse: function(capture, recurseParse, state) {\n            return {\n                content: recurseParse(capture[1], state)\n            };\n        },\n        react: function(node, recurseOutput) {\n            return React.DOM.strong(null, recurseOutput(node.content));\n        },\n        html: function(node, recurseOutput) {\n            return '<strong>' + recurseOutput(node.content) + '</strong>';\n        },\n    },\n```\n\nLet's look at those three methods in more detail.\n\n#### `match(source, state, lookbehind)`\n\nsimple-markdown calls your `match` function to determine whether the\nupcoming markdown source matches this rule or not.\n\n`source` is the upcoming source, beginning at the current position of\nparsing (source[0] is the next character).\n\n`state` is a mutable state object to allow for more complicated matching\nand parsing. The most common field on `state` is `inline`, which all of\nthe default rules set to true when we are in an inline scope, and false\nor undefined when we are in a block scope.\n\n**DEPRECATED - use `state.prevCapture` instead.** `lookbehind` is the string previously captured at this parsing level, to\nallow for lookbehind. For example, lists check that lookbehind ends with\n`/^$|\\n *$/` to ensure that lists only match at the beginning of a new\nline.\n\nIf this rule matches, `match` should return an object, array, or\narray-like object, which we'll call `capture`, where `capture[0]`\nis the full matched source, and any other fields can be used in the\nrule's `parse` function. The return value from `Regexp.prototype.exec`\nfits this requirement, and the common use case is to return the result\nof `someRegex.exec(source)`.\n\nIf this rule does not match, `match` should return null.\n\nNOTE: If you are using regexes in your match function, your regex\nshould always begin with `^`. Regexes without leading `^`s can\ncause unexpected output or infinite loops.\n\n#### `parse(capture, recurseParse, state)`\n\n`parse` takes the output of `match` and transforms it into a syntax\ntree node object, which we'll call `node` here.\n\n`capture` is the non-null result returned from match.\n\n`recurseParse` is a function that can be called on sub-content and\nstate to recursively parse the sub-content. This returns an array.\n\n`state` is the mutable state threading object, which can be examined\nor modified, and should be passed as the third argument to any\n`recurseParse` calls.\n\nFor example, to parse inline sub-content, you can add `inline: true`\nto state, or `inline: false` to force block parsing (to leave the\nparsing scope alone, you can just pass `state` with no modifications).\nFor example:\n\n```javascript\n    var innerText = capture[1];\n    recurseParse(innerText, _.defaults({\n        inline: true\n    }, state));\n```\n    \n`parse` should return a `node` object, which can have custom fields\nthat will be passed to `output`, below. The one reserved field is\n`type`, which designates the type of the node, which will be used\nfor output. If no type is specified, simple-markdown will use the\ncurrent rule's type (the common case). If you have multiple ways\nto parse a single element, it can be useful to have multiple rules\nthat all return nodes of the same type.\n\n#### `react(node, recurseOutput, state)`\n\n`react` takes a syntax tree `node` and transforms it into\nReact-renderable output.\n\n`node` is the return value from `parse`, which has a type\nfield of the same type as the current rule, as well as any\ncustom fields created by `parse`.\n\n`recurseOutput` is a function to recursively output sub-tree\nnodes created by using `recurseParse` in `parse`.\n\n`state` is the mutable state threading object, which can be\nexamined or modified, and should be passed as the second\nargument to any recurseOutput calls.\n\nThe simple-markdown API contains several helper methods for\ncreating rules, as well as methods for creating parsers and\noutputters from rules.\n\nExtension API\n-------------\n\nsimple-markdown includes access to the default list of rules,\nas well as several functions to allow you to create parsers and\noutputters from modifications of those default rules, or even\nfrom a totally custom rule list.\n\nThese functions are separated so that you can customize\nintermediate steps in the parsing/output process, if necessary.\n\n#### `SimpleMarkdown.defaultRules`\n\nThe default rules, specified as an object, where the keys are\nthe rule types, and the values are objects containing `order`,\n`match`, `parse`, `react`, and `html` fields (these rules can\nbe used for both parsing and outputting).\n\n#### `SimpleMarkdown.parserFor(rules)`\n\nTakes a `rules` object and returns a parser for the rule types\nin the rules object, in order of increasing `order` fields,\nwhich must be present and a finite number for each rule.\nIn the case of order field ties, rules are ordered\nlexicographically by rule name. Each of the rules in the `rules`\nobject must contain a `match` and a `parse` function.\n\n#### `SimpleMarkdown.ruleOutput(rules, key)`\n\nTakes a `rules` object, containing an `output` function for\neach rule, and a `key` into individual elements in that rules\nrules argument (either `'react'` or `'html'`, unless you are\ndefining a custom output type), and returns a function that can\noutput a single syntax tree node of any type that is in the\n`rules` object, given a node and a recursive output function.\nThis is not the final output function because it doesn't handle\narrays of nodes or recursion (see `reactFor` and `htmlFor`).\n\n#### `SimpleMarkdown.reactFor(singleNodeOutputFunction)`\n\nTakes a function that can output react-renderable output for\nany single syntax tree node and returns a function that maps\nover syntax tree arrays correctly.\n\nThe most common use case is to pass the output of\n`ruleOutput` as the parameter to `reactFor`:\n\n```javascript\n    var output = SimpleMarkdown.reactFor(SimpleMarkdown.ruleOutput(rules, 'react'));\n```\n\n#### `SimpleMarkdown.htmlFor(singleNodeOutputFunction)`\n\nTakes a function that can output an html string for\nany single syntax tree node and returns a function that maps\nover syntax tree arrays correctly.\n\nThe most common use case is to pass the output of\n`ruleOutput` as the parameter to `htmlFor`:\n\n```javascript\n    var output = SimpleMarkdown.htmlFor(SimpleMarkdown.ruleOutput(rules, 'html'));\n```\n\n#### Putting it all together\n\nGiven a set of rules, one can create a single function\nthat takes an input content string and outputs a\nReact-renderable as follows. Note that since many rules\nexpect blocks to end in `\"\\n\\n\"`, we append that to source\ninput manually, in addition to specifying `inline: false`\n(`inline: false` is technically optional for all of the\ndefault rules, which assume `inline` is false if it is\nundefined).\n\n```javascript\nvar rules = {\n    ...SimpleMarkdown.defaultRules,\n    paragraph: {\n        ...SimpleMarkdown.defaultRules.paragraph,\n        react: (node, output, state) => {\n            return <p key={state.key}>{output(node.content, state)}</p>;\n        }\n    }\n};\n\nvar parser = SimpleMarkdown.parserFor(rules);\nvar reactOutput = SimpleMarkdown.reactFor(SimpleMarkdown.ruleOutput(rules, 'react'));\nvar htmlOutput = SimpleMarkdown.reactFor(SimpleMarkdown.ruleOutput(rules, 'html'));\n\nvar blockParseAndOutput = function(source) {\n    // Many rules require content to end in \\n\\n to be interpreted\n    // as a block.\n    var blockSource = source + \"\\n\\n\";\n    var parseTree = parser(blockSource, {inline: false});\n    var outputResult = htmlOutput(parseTree);\n    // Or for react output, use:\n    // var outputResult = reactOutput(parseTree);\n    return outputResult;\n};\n```\n\nExtension rules helper functions\n--------------------------------\n\n*Coming soon*\n\nLICENSE\n-------\nMIT. See the LICENSE file for text.\n","gitHead":"c1e7ce469287e0e96b37d653946f6aed9efe4165","license":"MIT","scripts":{"size":"size-limit","test":"make test","heroku":"node babelmark.js","prepublishOnly":"make minify"},"_npmUser":{"name":"ariabuckles","email":"aria@toole1.com"},"homepage":"https://github.com/Khan/simple-markdown","keywords":["markdown","simple","react","html","ast","markup","text processing","extension","flow","typescript"],"repository":{"url":"git+https://github.com/Khan/simple-markdown.git","type":"git"},"size-limit":[{"path":"simple-markdown.js","limit":"5 KB"}],"_npmVersion":"6.9.0","description":"Javascript markdown parsing, made simple","directories":{},"maintainers":[{"name":"ariabuckles","email":"aria@magoosh.com"},{"name":"khanacademy","email":"opensource+npm@khanacademy.org"},{"name":"xymostech","email":"xymostech@gmail.com"}],"_nodeVersion":"10.16.3","dependencies":{"@types/node":">=10.0.0","@types/react":">=16.0.0"},"_hasShrinkwrap":false,"readmeFilename":"README.md","devDependencies":{"nyc":"^14.1.1","mocha":"^6.2.0","react":"^16.8.4","express":"^4.16.4","flow-bin":"^0.94.0","react-dom":"^16.8.4","uglify-js":"^3.4.9","flow-typed":"^2.5.1","size-limit":"^0.21.1","typescript":"^3.6.4","underscore":"^1.9.1","@types/mocha":"^5.2.7","@types/react-dom":">=16.0.0","@types/underscore":">=1.4.4"},"_npmOperationalInternal":{"tmp":"tmp/simple-markdown_0.7.0_1571959736869_0.9967692773397925","host":"s3://npm-registry-packages"},"_id":"simple-markdown@0.7.0","version":"0.7.0"}