diff --git a/.gitignore b/.gitignore index c6f6fff..84e96ae 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ node_modules/ coverage/ demo/ +apidoc/ *.log diff --git a/.ndocrc b/.ndocrc new file mode 100644 index 0000000..047f632 --- /dev/null +++ b/.ndocrc @@ -0,0 +1,25 @@ +# +# Common nodeca config +################################################################################ + +--index "./README.md" +--package "./package.json" +--gh-ribbon "{package.homepage}" +--output "apidoc" +--render "html" +--link-format "{package.homepage}/blob/master/{file}#L{line}" +--broken-links "show" + + +# +# Paths with sources +################################################################################ + +lib + + +# +# Project specific configuration +################################################################################ + +--show-all diff --git a/.npmignore b/.npmignore index f109ac6..7535526 100644 --- a/.npmignore +++ b/.npmignore @@ -2,6 +2,7 @@ benchmark/ coverage/ demo/ docs/ +apidoc/ support/ test/ Makefile diff --git a/Makefile b/Makefile index fd21fb1..fd42f98 100644 --- a/Makefile +++ b/Makefile @@ -44,7 +44,7 @@ lint: eslint --reset . test: lint - NODE_ENV=test mocha -R spec + mocha -R spec echo "CommonMark stat:\n" ./support/specsplit.js test/fixtures/commonmark/spec.txt @@ -55,6 +55,15 @@ coverage: test-ci: lint istanbul cover ./node_modules/mocha/bin/_mocha --report lcovonly -- -R spec && cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js && rm -rf ./coverage +apidoc: + @if test ! `which ndoc` ; then \ + echo "You need 'ndoc' installed in order to generate docs." >&2 ; \ + echo " $ npm install -g ndoc" >&2 ; \ + exit 128 ; \ + fi + rm -rf ./apidoc + ndoc --link-format "{package.homepage}/blob/${CURR_HEAD}/{file}#L{line}" + publish: @if test 0 -ne `git status --porcelain | wc -l` ; then \ echo "Unclean working tree. Commit or stash changes first." >&2 ; \ @@ -87,5 +96,5 @@ todo: grep 'TODO' -n -r ./lib 2>/dev/null || test true -.PHONY: publish lint test gh-pages todo demo coverage +.PHONY: publish lint test gh-pages todo demo coverage apidoc .SILENT: help lint test todo diff --git a/README.md b/README.md index bdfd43e..8efcacf 100644 --- a/README.md +++ b/README.md @@ -62,7 +62,7 @@ var md = window.markdownit(); console.log(md.render('# markdown-it rulezz!')); ``` -Single lines rendering, without paragraph wrap: +Single line rendering, without paragraph wrap: ```js var md = require('markdown-it')(); @@ -88,7 +88,7 @@ active syntax rules and options for common use cases. all rules enabled, but still without html, typographer & autolinker. - [default](https://github.com/markdown-it/markdown-it/blob/master/lib/presets/default.js) - when no preset name given. -- [zero](https://github.com/markdown-it/markdown-it/blob/master/lib/presets/zero.js) - +- ["zero"](https://github.com/markdown-it/markdown-it/blob/master/lib/presets/zero.js) - all rules disabled (useful to quickly setup your config via `.enable()`). diff --git a/bower.json b/bower.json index 98b4822..6ce438b 100644 --- a/bower.json +++ b/bower.json @@ -17,6 +17,7 @@ "coverage", "demo", "docs", + "apidoc", "lib", "node_modules", "support", diff --git a/lib/index.js b/lib/index.js index 6dc8355..640db2e 100644 --- a/lib/index.js +++ b/lib/index.js @@ -5,13 +5,10 @@ var utils = require('./common/utils'); var helpers = require('./helpers'); -var assign = require('./common/utils').assign; -var isString = require('./common/utils').isString; var Renderer = require('./renderer'); var ParserCore = require('./parser_core'); var ParserBlock = require('./parser_block'); var ParserInline = require('./parser_inline'); -var Ruler = require('./ruler'); var config = { 'default': require('./presets/default'), @@ -34,30 +31,178 @@ function StateCore(self, src, env) { this.typographer = self.typographer; } -// Main class -// +/** + * class MarkdownIt + * + * Main parser/renderer class. + * + * ##### Usage + * + * ```javascript + * // node.js, "classic" way: + * var MarkdownIt = require('markdown-it'), + * md = new MarkdownIt(); + * console.log(md.render('# markdown-it rulezz!')); + * + * // node.js, the same, but with sugar: + * var md = require('markdown-it')(); + * console.log(md.render('# markdown-it rulezz!')); + * + * // browser without AMD, added to "window" on script load + * // Note, there are no dash. + * var md = window.markdownit(); + * console.log(md.render('# markdown-it rulezz!')); + * ``` + * + * Single line rendering, without paragraph wrap: + * + * ```javascript + * var md = require('markdown-it')(); + * console.log(md.renderInline('__markdown-it__ rulezz!')); + * ``` + **/ + +/** + * new MarkdownIt([presetName, options]) + * - presetName (String): optional, `commonmark` / `full` / `zero` + * - options (Object) + * + * Creates parser instanse with given config. Can be called without `new`. + * + * ##### presetName + * + * MarkdownIt provides named presets as a convenience to quickly + * enable/disable active syntax rules and options for common use cases. + * + * - ["commonmark"](https://github.com/markdown-it/markdown-it/blob/master/lib/presets/commonmark.js) - + * configures parser to strict [CommonMark](http://commonmark.org/) mode. + * - ["full"](https://github.com/markdown-it/markdown-it/blob/master/lib/presets/full.js) - + * enables all available rules, but still without html, typographer & autolinker. + * - [default](https://github.com/markdown-it/markdown-it/blob/master/lib/presets/default.js) - + * similar to GFM, used when no preset name given. + * - ["zero"](https://github.com/markdown-it/markdown-it/blob/master/lib/presets/zero.js) - + * all rules disabled. Useful to quickly setup your config via `.enable()`. + * For example, when you need only `bold` and `italic` markup and nothing else. + * + * ##### options: + * + * - __html__ - `false`. Set `true` to enable HTML tags in source. Be careful! + * That's not safe! You may need external sanitizer to protect output from XSS. + * It's better to extend features via plugins, instead of enabling HTML. + * - __xhtmlOut__ - `false`. Set `true` to add '/' when closing single tags + * (`
`). This is needed only for full CommonMark compatibility. In real + * world you will need HTML output. + * - __breaks__ - `false`. Set `true` to convert `\n` in paragraphs into `
`. + * - __langPrefix__ - `language-`. CSS language class prefix for fenced blocks. + * Can be useful for external highlighters. + * - __linkify__ - `false`. Set `true` to autoconvert URL-like text to links. + * - __typographer__ - `false`. Set `true` to enable some language-neutral + * replacement + quotes beautification (smartquotes). + * - __quotes__ - `“”‘’`, string. Double + single quotes replacement pairs, when + * typographer enabled and smartquotes on. Set doubles to '«»' for Russian, + * '„“' for German. + * - __highlight__ - `null`. Highlighter function for fenced code blocks. + * Highlighter `function (str, lang)` should return escaped HTML. It can also + * return empty string if the source was not changed and should be escaped externaly. + * + * ##### Example + * + * ```javascript + * // commonmark mode + * var md = require('markdown-it')('commonmark'); + * + * // default mode + * var md = require('markdown-it')(); + * + * // enable everything + * var md = require('markdown-it')('full', { + * html: true, + * linkify: true, + * typographer: true + * }); + * ``` + **/ function MarkdownIt(presetName, options) { if (!(this instanceof MarkdownIt)) { return new MarkdownIt(presetName, options); } if (!options) { - if (!isString(presetName)) { + if (!utils.isString(presetName)) { options = presetName || {}; presetName = 'default'; } } - this.inline = new ParserInline(); - this.block = new ParserBlock(); - this.core = new ParserCore(); + /** + * MarkdownIt#inline -> ParserInline + * + * Instance of inline parser. You may need it to add new rules when + * writing plugins. For simple rules control use [[MarkdownIt.disable]] and + * [[MarkdownIt.enable]]. + **/ + this.inline = new ParserInline(); + + /** + * MarkdownIt#block -> ParserBlock + * + * Instance of block parser. You may need it to add new rules when + * writing plugins. For simple rules control use [[MarkdownIt.disable]] and + * [[MarkdownIt.enable]]. + **/ + this.block = new ParserBlock(); + + /** + * MarkdownIt#core -> ParserCore + * + * Instance of core chain executor. You may need it to add new rules when + * writing plugins. For simple rules control use [[MarkdownIt.disable]] and + * [[MarkdownIt.enable]]. + **/ + this.core = new ParserCore(); + + /** + * MarkdownIt#renderer -> Renderer + * + * Instance of Renderer. Use it to modify output look. Or to add rendering + * rules for new token types, generated by plugins. + * + * ##### Example + * + * ```javascript + * var md = require('markdown-it')(); + * + * function myToken(tokens, idx, options, env, self) { + * //... + * return result; + * }; + * + * md.renderer.rules['my_token'] = myToken + * ``` + * + * See [[Renderer]] docs and [source code](https://github.com/markdown-it/markdown-it/blob/master/lib/renderer.js). + **/ this.renderer = new Renderer(); - this.ruler = new Ruler(); // Expose utils & helpers for easy acces from plugins + + /** + * MarkdownIt#utils -> utils + * + * Assorted utility functions, useful to write plugins. See details + * [here](https://github.com/markdown-it/markdown-it/blob/master/lib/common/utils.js). + **/ this.utils = utils; + + /** + * MarkdownIt#helpers -> helpers + * + * Link components parser functions, useful to write plugins. See details + * [here](https://github.com/markdown-it/markdown-it/blob/master/lib/helpers). + **/ this.helpers = helpers; + this.options = {}; this.configure(config[presetName]); @@ -65,16 +210,38 @@ function MarkdownIt(presetName, options) { } -// Set options, if you did not passed those to constructor -// +/** chainable + * MarkdownIt.set(options) + * + * Set parser options (in the same format as in constructor). Probably, you + * will never need it, but you can change options after constructor call. + * + * ##### Example + * + * ```javascript + * var md = require('markdown-it')() + * .set({ html: true, breaks: true }) + * .set({ typographer, true }); + * ``` + * + * __Note:__ To achieve the best possible performance, don't modify a + * `markdown-it` instance options on the fly. If you need multiple configurations + * it's best to create multiple instances and initialize each with separate + * config. + **/ MarkdownIt.prototype.set = function (options) { - assign(this.options, options); + utils.assign(this.options, options); return this; }; -// Batch loader for components rules states & options -// +/** chainable, internal + * MarkdownIt.configure(presets) + * + * Batch load of all options and compenent settings. This is internal method, + * and you probably will not need it. But if you with - see available presets + * and data structure [here](https://github.com/markdown-it/markdown-it/tree/master/lib/presets) + **/ MarkdownIt.prototype.configure = function (presets) { var self = this; @@ -93,8 +260,21 @@ MarkdownIt.prototype.configure = function (presets) { }; -// Sugar to enable rules by names in all chains at once -// +/** chainable + * MarkdownIt.enable(list) + * - list (String|Array): rule name or list of rule names to enable + * + * Enable list or rules. It will automatically find appropriate components, + * containing rules with given names. + * + * ##### Example + * + * ```javascript + * var md = require('markdown-it')() + * .enable(['sub', 'sup']) + * .disable('smartquotes'); + * ``` + **/ MarkdownIt.prototype.enable = function (list) { [ 'core', 'block', 'inline' ].forEach(function (chain) { this[chain].ruler.enable(list, true); @@ -103,8 +283,12 @@ MarkdownIt.prototype.enable = function (list) { }; -// Sugar to disable rules by names in all chains at once -// +/** chainable + * MarkdownIt.disable(list) + * - list (String|Array): rule name or list of rule names to disable. + * + * The same as [[MarkdownIt.enable]], but turn specified rules off. + **/ MarkdownIt.prototype.disable = function (list) { [ 'core', 'block', 'inline' ].forEach(function (chain) { this[chain].ruler.disable(list, true); @@ -113,23 +297,37 @@ MarkdownIt.prototype.disable = function (list) { }; -// Sugar for curried plugins init: -// -// var md = new MarkdownIt(); -// -// md.use(plugin1) -// .use(plugin2, opts) -// .use(plugin3); -// -MarkdownIt.prototype.use = function (plugin, opts) { - plugin(this, opts); +/** chainable + * MarkdownIt.use(plugin, options) + * + * Load specified plugin with given options into current parser instance. + * + * ##### Example + * + * ```javascript + * var md = require('markdown-it')() + * .use(require('makkdown-it-emoji')); + * ``` + **/ +MarkdownIt.prototype.use = function (plugin, options) { + plugin(this, options); return this; }; -// Parse input string, returns tokens array. Modify `env` with -// definitions data. -// +/** internal + * MarkdownIt.parse(src, env) -> Array + * - src (String): source string + * - env (Object): enviroment variables + * + * Parse input string and returns list of block tokens (special token type + * "inline" will contain list of inline tokens). You should not call this + * method directly, until you write custom renderer (for example, to produce + * AST). + * + * `env` is modified with additional info. For example, with references data. + * Also `env` can be used to pass external info to plugins. + **/ MarkdownIt.prototype.parse = function (src, env) { var state = new StateCore(this, src, env); @@ -139,8 +337,16 @@ MarkdownIt.prototype.parse = function (src, env) { }; -// Main method that does all magic :) -// +/** + * MarkdownIt.render(src [, env]) -> String + * - src (String): source string + * - env (Object): optional, enviroment variables + * + * Render markdown string into html. It does all magic for you :). + * + * `env` is `{}` by default. It's not used now directly, but you can pass + * with it any additional data to plugins. + **/ MarkdownIt.prototype.render = function (src, env) { env = env || {}; @@ -148,8 +354,13 @@ MarkdownIt.prototype.render = function (src, env) { }; -// Parse content as single string -// +/** internal + * MarkdownIt.parseInline(src, env) -> Array + * - src (String): source string + * - env (Object): enviroment variables + * + * The same as [[MarkdownIt.parse]] but skip all block rules. + **/ MarkdownIt.prototype.parseInline = function (src, env) { var state = new StateCore(this, src, env); @@ -160,8 +371,14 @@ MarkdownIt.prototype.parseInline = function (src, env) { }; -// Render single string, without wrapping it to paragraphs -// +/** + * MarkdownIt.renderInline(src [, env]) -> String + * - src (String): source string + * - env (Object): optional, enviroment variables + * + * Similar to [[MarkdownIt.render]] but for single paragraph content. Result + * will NOT be wrapped into `

` tags. + **/ MarkdownIt.prototype.renderInline = function (src, env) { env = env || {};