diff --git a/.eslintrc b/.eslintrc index 59f9f06e8baa0d..ffb768217805b9 100644 --- a/.eslintrc +++ b/.eslintrc @@ -57,6 +57,7 @@ rules: comma-spacing: 2 eol-last: 2 indent: [2, 2, {SwitchCase: 1}] + key-spacing: [2, {mode: "minimum"}] keyword-spacing: 2 max-len: [2, 80, 2] new-parens: 2 diff --git a/BUILDING.md b/BUILDING.md index fa5fbe2c050c81..b634d34b6d1cca 100644 --- a/BUILDING.md +++ b/BUILDING.md @@ -67,10 +67,20 @@ $ make test-npm To build the documentation: +This will build Node.js first (if necessary) and then use it to build the docs: + ```text $ make doc ``` +If you have an existing Node.js you can build just the docs with: + +```text +$ NODE=node make doc-only +``` + +(Where `node` is the path to your executable.) + To read the documentation: ```text diff --git a/Makefile b/Makefile index 091dca717b5757..28f8f808808123 100644 --- a/Makefile +++ b/Makefile @@ -32,8 +32,8 @@ BUILDTYPE_LOWER := $(shell echo $(BUILDTYPE) | tr '[A-Z]' '[a-z]') EXEEXT := $(shell $(PYTHON) -c \ "import sys; print('.exe' if sys.platform == 'win32' else '')") -NODE ?= ./node$(EXEEXT) NODE_EXE = node$(EXEEXT) +NODE ?= ./$(NODE_EXE) NODE_G_EXE = node_g$(EXEEXT) # Flags for packaging. @@ -128,9 +128,9 @@ test/gc/node_modules/weak/build/Release/weakref.node: $(NODE_EXE) --nodedir="$(shell pwd)" # Implicitly depends on $(NODE_EXE), see the build-addons rule for rationale. -test/addons/.docbuildstamp: doc/api/addons.md +test/addons/.docbuildstamp: tools/doc/addon-verify.js doc/api/addons.md $(RM) -r test/addons/??_*/ - $(NODE) tools/doc/addon-verify.js + $(NODE) $< touch $@ ADDONS_BINDING_GYPS := \ @@ -138,7 +138,7 @@ ADDONS_BINDING_GYPS := \ $(wildcard test/addons/*/binding.gyp)) # Implicitly depends on $(NODE_EXE), see the build-addons rule for rationale. -test/addons/.buildstamp: $(ADDONS_BINDING_GYPS) | test/addons/.docbuildstamp +test/addons/.buildstamp: $(ADDONS_BINDING_GYPS) test/addons/.docbuildstamp # Cannot use $(wildcard test/addons/*/) here, it's evaluated before # embedded addons have been generated from the documentation. for dirname in test/addons/*/; do \ @@ -259,7 +259,9 @@ apidoc_dirs = out/doc out/doc/api/ out/doc/api/assets apiassets = $(subst api_assets,api/assets,$(addprefix out/,$(wildcard doc/api_assets/*))) -doc: $(apidoc_dirs) $(apiassets) $(apidocs) tools/doc/ $(NODE_EXE) +doc-only: $(apidoc_dirs) $(apiassets) $(apidocs) tools/doc/ + +doc: $(NODE_EXE) doc-only $(apidoc_dirs): mkdir -p $@ @@ -270,11 +272,15 @@ out/doc/api/assets/%: doc/api_assets/% out/doc/api/assets/ out/doc/%: doc/% cp -r $< $@ -out/doc/api/%.json: doc/api/%.md $(NODE_EXE) - $(NODE) tools/doc/generate.js --format=json $< > $@ +# check if ./node is actually set, else use user pre-installed binary +gen-json = tools/doc/generate.js --format=json $< > $@ +out/doc/api/%.json: doc/api/%.md + [ -x $(NODE) ] && $(NODE) $(gen-json) || node $(gen-json) -out/doc/api/%.html: doc/api/%.md $(NODE_EXE) - $(NODE) tools/doc/generate.js --format=html --template=doc/template.html $< > $@ +# check if ./node is actually set, else use user pre-installed binary +gen-html = tools/doc/generate.js --node-version=$(FULLVERSION) --format=html --template=doc/template.html $< > $@ +out/doc/api/%.html: doc/api/%.md + [ -x $(NODE) ] && $(NODE) $(gen-html) || node $(gen-html) docopen: out/doc/api/all.html -google-chrome out/doc/api/all.html @@ -423,6 +429,10 @@ PACKAGEMAKER ?= /Developer/Applications/Utilities/PackageMaker.app/Contents/MacO PKGDIR=out/dist-osx release-only: + @if `grep -q REPLACEME doc/api/*.md`; then \ + echo 'Please update Added: tags in the documentation first.' ; \ + exit 1 ; \ + fi @if [ "$(shell git status --porcelain | egrep -v '^\?\? ')" = "" ]; then \ exit 0 ; \ else \ @@ -664,4 +674,4 @@ lint-ci: lint bench-all bench bench-misc bench-array bench-buffer bench-net \ bench-http bench-fs bench-tls cctest run-ci lint-ci bench-ci \ test-v8 test-v8-intl test-v8-benchmarks test-v8-all v8 \ - $(TARBALL)-headers test-ci test-ci-native test-ci-js build-ci + $(TARBALL)-headers test-ci test-ci-native test-ci-js build-ci doc-only diff --git a/benchmark/path/format.js b/benchmark/path/format.js index 478a30cbaedbd2..6c6f2106dd3fb7 100644 --- a/benchmark/path/format.js +++ b/benchmark/path/format.js @@ -18,11 +18,11 @@ function main(conf) { ext: '.html', name: 'index' } : { - root : '/', - dir : '/home/user/dir', - base : 'index.html', - ext : '.html', - name : 'index' + root: '/', + dir: '/home/user/dir', + base: 'index.html', + ext: '.html', + name: 'index' }; // Force optimization before starting the benchmark diff --git a/doc/api/addons.md b/doc/api/addons.md index 9650329b0a5604..a4041637f2fcea 100644 --- a/doc/api/addons.md +++ b/doc/api/addons.md @@ -549,6 +549,7 @@ prototype: namespace demo { +using v8::Context; using v8::Function; using v8::FunctionCallbackInfo; using v8::FunctionTemplate; @@ -597,8 +598,11 @@ void MyObject::New(const FunctionCallbackInfo& args) { // Invoked as plain function `MyObject(...)`, turn into construct call. const int argc = 1; Local argv[argc] = { args[0] }; + Local context = isolate->GetCurrentContext(); Local cons = Local::New(isolate, constructor); - args.GetReturnValue().Set(cons->NewInstance(argc, argv)); + Local result = + cons->NewInstance(context, argc, argv).ToLocalChecked(); + args.GetReturnValue().Set(result); } } @@ -728,6 +732,7 @@ The implementation in `myobject.cc` is similar to the previous example: namespace demo { +using v8::Context; using v8::Function; using v8::FunctionCallbackInfo; using v8::FunctionTemplate; @@ -773,7 +778,10 @@ void MyObject::New(const FunctionCallbackInfo& args) { const int argc = 1; Local argv[argc] = { args[0] }; Local cons = Local::New(isolate, constructor); - args.GetReturnValue().Set(cons->NewInstance(argc, argv)); + Local context = isolate->GetCurrentContext(); + Local instance = + cons->NewInstance(context, argc, argv).ToLocalChecked(); + args.GetReturnValue().Set(instance); } } @@ -783,7 +791,9 @@ void MyObject::NewInstance(const FunctionCallbackInfo& args) { const unsigned argc = 1; Local argv[argc] = { args[0] }; Local cons = Local::New(isolate, constructor); - Local instance = cons->NewInstance(argc, argv); + Local context = isolate->GetCurrentContext(); + Local instance = + cons->NewInstance(context, argc, argv).ToLocalChecked(); args.GetReturnValue().Set(instance); } @@ -928,6 +938,7 @@ The implementation of `myobject.cc` is similar to before: namespace demo { +using v8::Context; using v8::Function; using v8::FunctionCallbackInfo; using v8::FunctionTemplate; @@ -968,8 +979,11 @@ void MyObject::New(const FunctionCallbackInfo& args) { // Invoked as plain function `MyObject(...)`, turn into construct call. const int argc = 1; Local argv[argc] = { args[0] }; + Local context = isolate->GetCurrentContext(); Local cons = Local::New(isolate, constructor); - args.GetReturnValue().Set(cons->NewInstance(argc, argv)); + Local instance = + cons->NewInstance(context, argc, argv).ToLocalChecked(); + args.GetReturnValue().Set(instance); } } @@ -979,7 +993,9 @@ void MyObject::NewInstance(const FunctionCallbackInfo& args) { const unsigned argc = 1; Local argv[argc] = { args[0] }; Local cons = Local::New(isolate, constructor); - Local instance = cons->NewInstance(argc, argv); + Local context = isolate->GetCurrentContext(); + Local instance = + cons->NewInstance(context, argc, argv).ToLocalChecked(); args.GetReturnValue().Set(instance); } diff --git a/doc/api_assets/style.css b/doc/api_assets/style.css index a8e4b32611164b..a9dec759fa85df 100644 --- a/doc/api_assets/style.css +++ b/doc/api_assets/style.css @@ -103,6 +103,19 @@ em code { background-color: #0084B6; } +.api_metadata { + font-size: .75em; + margin-bottom: 1em; +} + +.api_metadata span { + margin-right: 1em; +} + +.api_metadata span:last-child { + margin-right: 0px; +} + ul.plain { list-style: none; } diff --git a/lib/_http_server.js b/lib/_http_server.js index 399f9d49e1d4b0..827c9c346cb708 100644 --- a/lib/_http_server.js +++ b/lib/_http_server.js @@ -16,67 +16,67 @@ const httpSocketSetup = common.httpSocketSetup; const OutgoingMessage = require('_http_outgoing').OutgoingMessage; const STATUS_CODES = exports.STATUS_CODES = { - 100 : 'Continue', - 101 : 'Switching Protocols', - 102 : 'Processing', // RFC 2518, obsoleted by RFC 4918 - 200 : 'OK', - 201 : 'Created', - 202 : 'Accepted', - 203 : 'Non-Authoritative Information', - 204 : 'No Content', - 205 : 'Reset Content', - 206 : 'Partial Content', - 207 : 'Multi-Status', // RFC 4918 - 208 : 'Already Reported', - 226 : 'IM Used', - 300 : 'Multiple Choices', - 301 : 'Moved Permanently', - 302 : 'Found', - 303 : 'See Other', - 304 : 'Not Modified', - 305 : 'Use Proxy', - 307 : 'Temporary Redirect', - 308 : 'Permanent Redirect', // RFC 7238 - 400 : 'Bad Request', - 401 : 'Unauthorized', - 402 : 'Payment Required', - 403 : 'Forbidden', - 404 : 'Not Found', - 405 : 'Method Not Allowed', - 406 : 'Not Acceptable', - 407 : 'Proxy Authentication Required', - 408 : 'Request Timeout', - 409 : 'Conflict', - 410 : 'Gone', - 411 : 'Length Required', - 412 : 'Precondition Failed', - 413 : 'Payload Too Large', - 414 : 'URI Too Long', - 415 : 'Unsupported Media Type', - 416 : 'Range Not Satisfiable', - 417 : 'Expectation Failed', - 418 : 'I\'m a teapot', // RFC 2324 - 421 : 'Misdirected Request', - 422 : 'Unprocessable Entity', // RFC 4918 - 423 : 'Locked', // RFC 4918 - 424 : 'Failed Dependency', // RFC 4918 - 425 : 'Unordered Collection', // RFC 4918 - 426 : 'Upgrade Required', // RFC 2817 - 428 : 'Precondition Required', // RFC 6585 - 429 : 'Too Many Requests', // RFC 6585 - 431 : 'Request Header Fields Too Large', // RFC 6585 - 500 : 'Internal Server Error', - 501 : 'Not Implemented', - 502 : 'Bad Gateway', - 503 : 'Service Unavailable', - 504 : 'Gateway Timeout', - 505 : 'HTTP Version Not Supported', - 506 : 'Variant Also Negotiates', // RFC 2295 - 507 : 'Insufficient Storage', // RFC 4918 - 508 : 'Loop Detected', - 509 : 'Bandwidth Limit Exceeded', - 510 : 'Not Extended', // RFC 2774 - 511 : 'Network Authentication Required' // RFC 6585 + 100: 'Continue', + 101: 'Switching Protocols', + 102: 'Processing', // RFC 2518, obsoleted by RFC 4918 + 200: 'OK', + 201: 'Created', + 202: 'Accepted', + 203: 'Non-Authoritative Information', + 204: 'No Content', + 205: 'Reset Content', + 206: 'Partial Content', + 207: 'Multi-Status', // RFC 4918 + 208: 'Already Reported', + 226: 'IM Used', + 300: 'Multiple Choices', + 301: 'Moved Permanently', + 302: 'Found', + 303: 'See Other', + 304: 'Not Modified', + 305: 'Use Proxy', + 307: 'Temporary Redirect', + 308: 'Permanent Redirect', // RFC 7238 + 400: 'Bad Request', + 401: 'Unauthorized', + 402: 'Payment Required', + 403: 'Forbidden', + 404: 'Not Found', + 405: 'Method Not Allowed', + 406: 'Not Acceptable', + 407: 'Proxy Authentication Required', + 408: 'Request Timeout', + 409: 'Conflict', + 410: 'Gone', + 411: 'Length Required', + 412: 'Precondition Failed', + 413: 'Payload Too Large', + 414: 'URI Too Long', + 415: 'Unsupported Media Type', + 416: 'Range Not Satisfiable', + 417: 'Expectation Failed', + 418: 'I\'m a teapot', // RFC 2324 + 421: 'Misdirected Request', + 422: 'Unprocessable Entity', // RFC 4918 + 423: 'Locked', // RFC 4918 + 424: 'Failed Dependency', // RFC 4918 + 425: 'Unordered Collection', // RFC 4918 + 426: 'Upgrade Required', // RFC 2817 + 428: 'Precondition Required', // RFC 6585 + 429: 'Too Many Requests', // RFC 6585 + 431: 'Request Header Fields Too Large', // RFC 6585 + 500: 'Internal Server Error', + 501: 'Not Implemented', + 502: 'Bad Gateway', + 503: 'Service Unavailable', + 504: 'Gateway Timeout', + 505: 'HTTP Version Not Supported', + 506: 'Variant Also Negotiates', // RFC 2295 + 507: 'Insufficient Storage', // RFC 4918 + 508: 'Loop Detected', + 509: 'Bandwidth Limit Exceeded', + 510: 'Not Extended', // RFC 2774 + 511: 'Network Authentication Required' // RFC 6585 }; const kOnExecute = HTTPParser.kOnExecute | 0; diff --git a/lib/util.js b/lib/util.js index 79fdb33326ebc9..cd643c3120714a 100644 --- a/lib/util.js +++ b/lib/util.js @@ -147,19 +147,19 @@ exports.inspect = inspect; // http://en.wikipedia.org/wiki/ANSI_escape_code#graphics inspect.colors = { - 'bold' : [1, 22], - 'italic' : [3, 23], - 'underline' : [4, 24], - 'inverse' : [7, 27], - 'white' : [37, 39], - 'grey' : [90, 39], - 'black' : [30, 39], - 'blue' : [34, 39], - 'cyan' : [36, 39], - 'green' : [32, 39], - 'magenta' : [35, 39], - 'red' : [31, 39], - 'yellow' : [33, 39] + 'bold': [1, 22], + 'italic': [3, 23], + 'underline': [4, 24], + 'inverse': [7, 27], + 'white': [37, 39], + 'grey': [90, 39], + 'black': [30, 39], + 'blue': [34, 39], + 'cyan': [36, 39], + 'green': [32, 39], + 'magenta': [35, 39], + 'red': [31, 39], + 'yellow': [33, 39] }; // Don't use 'blue' not visible on cmd.exe diff --git a/test/addons/async-hello-world/binding.gyp b/test/addons/async-hello-world/binding.gyp index 3bfb84493f3e87..7ede63d94a0d77 100644 --- a/test/addons/async-hello-world/binding.gyp +++ b/test/addons/async-hello-world/binding.gyp @@ -2,6 +2,7 @@ 'targets': [ { 'target_name': 'binding', + 'defines': [ 'V8_DEPRECATION_WARNINGS=1' ], 'sources': [ 'binding.cc' ] } ] diff --git a/test/addons/at-exit/binding.gyp b/test/addons/at-exit/binding.gyp index 3bfb84493f3e87..7ede63d94a0d77 100644 --- a/test/addons/at-exit/binding.gyp +++ b/test/addons/at-exit/binding.gyp @@ -2,6 +2,7 @@ 'targets': [ { 'target_name': 'binding', + 'defines': [ 'V8_DEPRECATION_WARNINGS=1' ], 'sources': [ 'binding.cc' ] } ] diff --git a/test/addons/buffer-free-callback/binding.gyp b/test/addons/buffer-free-callback/binding.gyp index 3bfb84493f3e87..7ede63d94a0d77 100644 --- a/test/addons/buffer-free-callback/binding.gyp +++ b/test/addons/buffer-free-callback/binding.gyp @@ -2,6 +2,7 @@ 'targets': [ { 'target_name': 'binding', + 'defines': [ 'V8_DEPRECATION_WARNINGS=1' ], 'sources': [ 'binding.cc' ] } ] diff --git a/test/addons/heap-profiler/binding.gyp b/test/addons/heap-profiler/binding.gyp index b75f68fe3a4e84..ceb1d3e73415de 100644 --- a/test/addons/heap-profiler/binding.gyp +++ b/test/addons/heap-profiler/binding.gyp @@ -2,6 +2,7 @@ 'targets': [ { 'target_name': 'binding', + 'defines': [ 'V8_DEPRECATION_WARNINGS=1' ], 'sources': [ 'binding.cc' ], 'win_delay_load_hook': 'false' } diff --git a/test/addons/hello-world-function-export/binding.gyp b/test/addons/hello-world-function-export/binding.gyp index 3bfb84493f3e87..7ede63d94a0d77 100644 --- a/test/addons/hello-world-function-export/binding.gyp +++ b/test/addons/hello-world-function-export/binding.gyp @@ -2,6 +2,7 @@ 'targets': [ { 'target_name': 'binding', + 'defines': [ 'V8_DEPRECATION_WARNINGS=1' ], 'sources': [ 'binding.cc' ] } ] diff --git a/test/addons/hello-world/binding.gyp b/test/addons/hello-world/binding.gyp index 3bfb84493f3e87..7ede63d94a0d77 100644 --- a/test/addons/hello-world/binding.gyp +++ b/test/addons/hello-world/binding.gyp @@ -2,6 +2,7 @@ 'targets': [ { 'target_name': 'binding', + 'defines': [ 'V8_DEPRECATION_WARNINGS=1' ], 'sources': [ 'binding.cc' ] } ] diff --git a/test/addons/load-long-path/binding.gyp b/test/addons/load-long-path/binding.gyp index 3bfb84493f3e87..7ede63d94a0d77 100644 --- a/test/addons/load-long-path/binding.gyp +++ b/test/addons/load-long-path/binding.gyp @@ -2,6 +2,7 @@ 'targets': [ { 'target_name': 'binding', + 'defines': [ 'V8_DEPRECATION_WARNINGS=1' ], 'sources': [ 'binding.cc' ] } ] diff --git a/test/addons/make-callback-recurse/binding.gyp b/test/addons/make-callback-recurse/binding.gyp index 3bfb84493f3e87..7ede63d94a0d77 100644 --- a/test/addons/make-callback-recurse/binding.gyp +++ b/test/addons/make-callback-recurse/binding.gyp @@ -2,6 +2,7 @@ 'targets': [ { 'target_name': 'binding', + 'defines': [ 'V8_DEPRECATION_WARNINGS=1' ], 'sources': [ 'binding.cc' ] } ] diff --git a/test/addons/make-callback/binding.gyp b/test/addons/make-callback/binding.gyp index 3bfb84493f3e87..7ede63d94a0d77 100644 --- a/test/addons/make-callback/binding.gyp +++ b/test/addons/make-callback/binding.gyp @@ -2,6 +2,7 @@ 'targets': [ { 'target_name': 'binding', + 'defines': [ 'V8_DEPRECATION_WARNINGS=1' ], 'sources': [ 'binding.cc' ] } ] diff --git a/test/addons/repl-domain-abort/binding.gyp b/test/addons/repl-domain-abort/binding.gyp index 3bfb84493f3e87..7ede63d94a0d77 100644 --- a/test/addons/repl-domain-abort/binding.gyp +++ b/test/addons/repl-domain-abort/binding.gyp @@ -2,6 +2,7 @@ 'targets': [ { 'target_name': 'binding', + 'defines': [ 'V8_DEPRECATION_WARNINGS=1' ], 'sources': [ 'binding.cc' ] } ] diff --git a/test/addons/stringbytes-external-exceed-max/binding.gyp b/test/addons/stringbytes-external-exceed-max/binding.gyp index 3bfb84493f3e87..7ede63d94a0d77 100644 --- a/test/addons/stringbytes-external-exceed-max/binding.gyp +++ b/test/addons/stringbytes-external-exceed-max/binding.gyp @@ -2,6 +2,7 @@ 'targets': [ { 'target_name': 'binding', + 'defines': [ 'V8_DEPRECATION_WARNINGS=1' ], 'sources': [ 'binding.cc' ] } ] diff --git a/test/doctool/test-doctool-html.js b/test/doctool/test-doctool-html.js index afd89489f11ed4..bd21e21d9563d2 100644 --- a/test/doctool/test-doctool-html.js +++ b/test/doctool/test-doctool-html.js @@ -3,7 +3,16 @@ const common = require('../common'); const assert = require('assert'); const fs = require('fs'); +const path = require('path'); +// The doctool currently uses js-yaml from the tool/eslint/ tree. +try { + require('../../tools/eslint/node_modules/js-yaml'); +} catch (e) { + return common.skip('missing js-yaml (eslint not present)'); +} + +const processIncludes = require('../../tools/doc/preprocess.js'); const html = require('../../tools/doc/html.js'); // Test data is a list of objects with two properties. @@ -13,13 +22,13 @@ const html = require('../../tools/doc/html.js'); // have an html parser. const testData = [ { - 'file': common.fixturesDir + '/sample_document.md', - 'html': '
  1. fish
  2. fish

  3. Redfish

  4. ' + + file: path.join(common.fixturesDir, 'sample_document.md'), + html: '
    1. fish
    2. fish

    3. Redfish

    4. ' + '
    5. Bluefish
    ' }, { - 'file': common.fixturesDir + '/order_of_end_tags_5873.md', - 'html': '

    ClassMethod: Buffer.from(array) ' + + file: path.join(common.fixturesDir, 'order_of_end_tags_5873.md'), + html: '

    ClassMethod: Buffer.from(array) ' + '#

    ' }, + { + file: path.join(common.fixturesDir, 'doc_with_yaml.md'), + html: '

    Sample Markdown with YAML info' + + '#

    ' + + '

    Foobar#

    ' + + ' ' + + '

    Describe Foobar in more detail here.

    ' + + '

    Foobar II#

    ' + + ' ' + + '

    Describe Foobar II in more detail here.

    ' + + '

    Deprecated thingy#' + + '

    ' + + '

    Describe ' + + 'Deprecated thingy in more detail here.

    ' + + '

    Something#

    ' + + ' ' + + '

    Describe Something in more detail here. ' + + '

    ' + }, + { + file: path.join(common.fixturesDir, 'doc_with_includes.md'), + html: '' + + '

    Look here!

    ' + + '' + + '' + + '

    foobar#

    ' + + '

    I exist and am being linked to.

    ' + + '' + }, ]; testData.forEach(function(item) { // Normalize expected data by stripping whitespace const expected = item.html.replace(/\s/g, ''); - fs.readFile(item.file, 'utf8', common.mustCall(function(err, input) { + fs.readFile(item.file, 'utf8', common.mustCall((err, input) => { assert.ifError(err); - html(input, 'foo', 'doc/template.html', - common.mustCall(function(err, output) { - assert.ifError(err); - - const actual = output.replace(/\s/g, ''); - // Assert that the input stripped of all whitespace contains the - // expected list - assert.notEqual(actual.indexOf(expected), -1); - })); + processIncludes(item.file, input, common.mustCall((err, preprocessed) => { + assert.ifError(err); + + html( + { + input: preprocessed, + filename: 'foo', + template: 'doc/template.html', + nodeVersion: process.version, + }, + common.mustCall((err, output) => { + assert.ifError(err); + + const actual = output.replace(/\s/g, ''); + // Assert that the input stripped of all whitespace contains the + // expected list + assert.notEqual(actual.indexOf(expected), -1); + })); + })); })); }); diff --git a/test/doctool/test-doctool-json.js b/test/doctool/test-doctool-json.js index 31e260fcb02d43..520c79bef8bcda 100644 --- a/test/doctool/test-doctool-json.js +++ b/test/doctool/test-doctool-json.js @@ -3,6 +3,14 @@ const common = require('../common'); const assert = require('assert'); const fs = require('fs'); +const path = require('path'); + +// The doctool currently uses js-yaml from the tool/eslint/ tree. +try { + require('../../tools/eslint/node_modules/js-yaml'); +} catch (e) { + return common.skip('missing js-yaml (eslint not present)'); +} const json = require('../../tools/doc/json.js'); @@ -12,57 +20,118 @@ const json = require('../../tools/doc/json.js'); // The json property is some json which will be generated by the doctool. var testData = [ { - 'file': common.fixturesDir + '/sample_document.md', - 'json': { - 'source': 'foo', - 'modules': [ { 'textRaw': 'Sample Markdown', - 'name': 'sample_markdown', - 'modules': [ { 'textRaw':'Seussian Rhymes', - 'name': 'seussian_rhymes', - 'desc': '
      \n
    1. fish
    2. \n
    3. fish

      \n
    4. \n
    5. ' + + file: path.join(common.fixturesDir, 'sample_document.md'), + json: { + source: 'foo', + modules: [{ + textRaw: 'Sample Markdown', + name: 'sample_markdown', + modules: [{ + textRaw: 'Seussian Rhymes', + name: 'seussian_rhymes', + desc: '
        \n
      1. fish
      2. \n
      3. fish

        \n
      4. \n
      5. ' + '

        Red fish

        \n
      6. \n
      7. Blue fish
      8. \n
      \n', - 'type': 'module', - 'displayName': 'Seussian Rhymes' - } ], - 'type': 'module', - 'displayName': 'Sample Markdown' - } ] + type: 'module', + displayName: 'Seussian Rhymes' + }], + type: 'module', + displayName: 'Sample Markdown' + }] } }, { - 'file': common.fixturesDir + '/order_of_end_tags_5873.md', - 'json': { - 'source':'foo', - 'modules': [ { - 'textRaw': 'Title', - 'name': 'title', - 'modules': [ { - 'textRaw': 'Subsection', - 'name': 'subsection', - 'classMethods': [ { - 'textRaw': 'Class Method: Buffer.from(array)', - 'type':'classMethod', - 'name':'from', - 'signatures': [ { - 'params': [ { - 'textRaw': '`array` {Array} ', - 'name': 'array', - 'type': 'Array' - } ] - }, + file: path.join(common.fixturesDir, 'order_of_end_tags_5873.md'), + json: { + source: 'foo', + modules: [{ + textRaw: 'Title', + name: 'title', + modules: [{ + textRaw: 'Subsection', + name: 'subsection', + classMethods: [{ + textRaw: 'Class Method: Buffer.from(array)', + type: 'classMethod', + name: 'from', + signatures: [ + { + params: [{ + textRaw: '`array` {Array} ', + name: 'array', + type: 'Array' + }] + }, { - 'params' : [ { - 'name': 'array' - } ] + params: [{ + name: 'array' + }] } ] - } ], - 'type': 'module', - 'displayName': 'Subsection' - } ], - 'type': 'module', - 'displayName': 'Title' - } ] + }], + type: 'module', + displayName: 'Subsection' + }], + type: 'module', + displayName: 'Title' + }] + } + }, + { + file: path.join(common.fixturesDir, 'doc_with_yaml.md'), + json: { + source: 'foo', + modules: [ + { + textRaw: 'Sample Markdown with YAML info', + name: 'sample_markdown_with_yaml_info', + modules: [ + { + textRaw: 'Foobar', + name: 'foobar', + meta: { + added: ['v1.0.0'] + }, + desc: '

      Describe Foobar in more detail ' + + 'here.

      \n', + type: 'module', + displayName: 'Foobar' + }, + { + textRaw: 'Foobar II', + name: 'foobar_ii', + meta: { + added: ['v5.3.0', 'v4.2.0'] + }, + desc: '

      Describe Foobar II in more detail ' + + 'here.

      \n', + type: 'module', + displayName: 'Foobar II' + }, + { + textRaw: 'Deprecated thingy', + name: 'deprecated_thingy', + meta: { + added: ['v1.0.0'], + deprecated: ['v2.0.0'] + }, + desc: '

      Describe Deprecated thingy in more ' + + 'detail here.

      \n', + type: 'module', + displayName: 'Deprecated thingy' + }, + { + textRaw: 'Something', + name: 'something', + desc: '\n

      ' + + 'Describe Something in more detail here.

      \n', + type: 'module', + displayName: 'Something' + } + ], + type: 'module', + displayName: 'Sample Markdown with YAML info' + } + ] } } ]; diff --git a/test/fixtures/doc_inc_1.md b/test/fixtures/doc_inc_1.md new file mode 100644 index 00000000000000..92858d0200c237 --- /dev/null +++ b/test/fixtures/doc_inc_1.md @@ -0,0 +1,3 @@ +Look [here][]! + +[here]: doc_inc_2.html#doc_inc_2_foobar diff --git a/test/fixtures/doc_inc_2.md b/test/fixtures/doc_inc_2.md new file mode 100644 index 00000000000000..17d0b86a0cc51f --- /dev/null +++ b/test/fixtures/doc_inc_2.md @@ -0,0 +1,3 @@ +# foobar + +I exist and am being linked to. diff --git a/test/fixtures/doc_with_includes.md b/test/fixtures/doc_with_includes.md new file mode 100644 index 00000000000000..901bf0f1b0bf3b --- /dev/null +++ b/test/fixtures/doc_with_includes.md @@ -0,0 +1,2 @@ +@include doc_inc_1 +@include doc_inc_2.md diff --git a/test/fixtures/doc_with_yaml.md b/test/fixtures/doc_with_yaml.md new file mode 100644 index 00000000000000..493c2e7e4268b2 --- /dev/null +++ b/test/fixtures/doc_with_yaml.md @@ -0,0 +1,30 @@ +# Sample Markdown with YAML info + +## Foobar + + +Describe `Foobar` in more detail here. + +## Foobar II + + +Describe `Foobar II` in more detail here. + +## Deprecated thingy + + +Describe `Deprecated thingy` in more detail here. + +## Something + + +Describe `Something` in more detail here. diff --git a/test/parallel/test-console.js b/test/parallel/test-console.js index 5f908442339e03..a396bda8cd3350 100644 --- a/test/parallel/test-console.js +++ b/test/parallel/test-console.js @@ -37,8 +37,8 @@ console.log(custom_inspect); // test console.dir() console.dir(custom_inspect); console.dir(custom_inspect, { showHidden: false }); -console.dir({ foo : { bar : { baz : true } } }, { depth: 0 }); -console.dir({ foo : { bar : { baz : true } } }, { depth: 1 }); +console.dir({ foo: { bar: { baz: true } } }, { depth: 0 }); +console.dir({ foo: { bar: { baz: true } } }, { depth: 1 }); // test console.trace() console.trace('This is a %j %d', { formatted: 'trace' }, 10, 'foo'); diff --git a/test/parallel/test-crypto-binary-default.js b/test/parallel/test-crypto-binary-default.js index 129bbcacef151e..da29d690645683 100644 --- a/test/parallel/test-crypto-binary-default.js +++ b/test/parallel/test-crypto-binary-default.js @@ -30,19 +30,19 @@ var rsaKeyPem = fs.readFileSync(common.fixturesDir + '/test_rsa_privkey.pem', // PFX tests assert.doesNotThrow(function() { - tls.createSecureContext({pfx:certPfx, passphrase:'sample'}); + tls.createSecureContext({pfx: certPfx, passphrase: 'sample'}); }); assert.throws(function() { - tls.createSecureContext({pfx:certPfx}); + tls.createSecureContext({pfx: certPfx}); }, 'mac verify failure'); assert.throws(function() { - tls.createSecureContext({pfx:certPfx, passphrase:'test'}); + tls.createSecureContext({pfx: certPfx, passphrase: 'test'}); }, 'mac verify failure'); assert.throws(function() { - tls.createSecureContext({pfx:'sample', passphrase:'test'}); + tls.createSecureContext({pfx: 'sample', passphrase: 'test'}); }, 'not enough data'); // Test HMAC diff --git a/test/parallel/test-crypto.js b/test/parallel/test-crypto.js index 271541d54a242d..bf87900875b7c4 100644 --- a/test/parallel/test-crypto.js +++ b/test/parallel/test-crypto.js @@ -32,19 +32,19 @@ assert.throws(function() { // PFX tests assert.doesNotThrow(function() { - tls.createSecureContext({pfx:certPfx, passphrase:'sample'}); + tls.createSecureContext({pfx: certPfx, passphrase: 'sample'}); }); assert.throws(function() { - tls.createSecureContext({pfx:certPfx}); + tls.createSecureContext({pfx: certPfx}); }, 'mac verify failure'); assert.throws(function() { - tls.createSecureContext({pfx:certPfx, passphrase:'test'}); + tls.createSecureContext({pfx: certPfx, passphrase: 'test'}); }, 'mac verify failure'); assert.throws(function() { - tls.createSecureContext({pfx:'sample', passphrase:'test'}); + tls.createSecureContext({pfx: 'sample', passphrase: 'test'}); }, 'not enough data'); diff --git a/test/parallel/test-domain-http-server.js b/test/parallel/test-domain-http-server.js index 37dbc30f4234d7..594c34aae8d201 100644 --- a/test/parallel/test-domain-http-server.js +++ b/test/parallel/test-domain-http-server.js @@ -20,7 +20,7 @@ var server = http.createServer(function(req, res) { serverCaught++; console.log('horray! got a server error', er); // try to send a 500. If that fails, oh well. - res.writeHead(500, {'content-type':'text/plain'}); + res.writeHead(500, {'content-type': 'text/plain'}); res.end(er.stack || er.message || 'Unknown error'); }); diff --git a/test/parallel/test-domain-top-level-error-handler-throw.js b/test/parallel/test-domain-top-level-error-handler-throw.js index 4bde30d17cb8c8..7933c5d052fe11 100644 --- a/test/parallel/test-domain-top-level-error-handler-throw.js +++ b/test/parallel/test-domain-top-level-error-handler-throw.js @@ -29,7 +29,7 @@ if (process.argv[2] === 'child') { var fork = require('child_process').fork; var assert = require('assert'); - var child = fork(process.argv[1], ['child'], {silent:true}); + var child = fork(process.argv[1], ['child'], {silent: true}); var stderrOutput = ''; if (child) { child.stderr.on('data', function onStderrData(data) { diff --git a/test/parallel/test-fs-realpath.js b/test/parallel/test-fs-realpath.js index d627c01487c2c2..46fbbd85877a81 100644 --- a/test/parallel/test-fs-realpath.js +++ b/test/parallel/test-fs-realpath.js @@ -464,12 +464,12 @@ function test_lying_cache_liar(cb) { // this should not require *any* stat calls, since everything // checked by realpath will be found in the cache. console.log('test_lying_cache_liar'); - var cache = { '/foo/bar/baz/bluff' : '/foo/bar/bluff', - '/1/2/3/4/5/6/7' : '/1', - '/a' : '/a', - '/a/b' : '/a/b', - '/a/b/c' : '/a/b', - '/a/b/d' : '/a/b/d' }; + var cache = { '/foo/bar/baz/bluff': '/foo/bar/bluff', + '/1/2/3/4/5/6/7': '/1', + '/a': '/a', + '/a/b': '/a/b', + '/a/b/c': '/a/b', + '/a/b/d': '/a/b/d' }; if (common.isWindows) { var wc = {}; Object.keys(cache).forEach(function(k) { diff --git a/test/parallel/test-http-chunk-problem.js b/test/parallel/test-http-chunk-problem.js index 26df0b95e29572..23ec2d0263fa94 100644 --- a/test/parallel/test-http-chunk-problem.js +++ b/test/parallel/test-http-chunk-problem.js @@ -11,7 +11,7 @@ if (process.argv[2] === 'request') { const http = require('http'); const options = { port: common.PORT, - path : '/' + path: '/' }; http.get(options, (res) => { diff --git a/test/parallel/test-http-client-pipe-end.js b/test/parallel/test-http-client-pipe-end.js index 715f8ccf79df92..5b2db49435a1b6 100644 --- a/test/parallel/test-http-client-pipe-end.js +++ b/test/parallel/test-http-client-pipe-end.js @@ -18,7 +18,7 @@ common.refreshTmpDir(); server.listen(common.PIPE, function() { var req = http.request({ socketPath: common.PIPE, - headers: {'Content-Length':'1'}, + headers: {'Content-Length': '1'}, method: 'POST', path: '/' }); diff --git a/test/parallel/test-http-client-reject-chunked-with-content-length.js b/test/parallel/test-http-client-reject-chunked-with-content-length.js index a6639c90690da3..400a1d0ddbb991 100644 --- a/test/parallel/test-http-client-reject-chunked-with-content-length.js +++ b/test/parallel/test-http-client-reject-chunked-with-content-length.js @@ -17,7 +17,7 @@ server.listen(common.PORT, () => { // The callback should not be called because the server is sending // both a Content-Length header and a Transfer-Encoding: chunked // header, which is a violation of the HTTP spec. - const req = http.get({port:common.PORT}, (res) => { + const req = http.get({port: common.PORT}, (res) => { assert.fail(null, null, 'callback should not be called'); }); req.on('error', common.mustCall((err) => { diff --git a/test/parallel/test-http-client-reject-cr-no-lf.js b/test/parallel/test-http-client-reject-cr-no-lf.js index b60220cbb629b3..350d7f40e95b9b 100644 --- a/test/parallel/test-http-client-reject-cr-no-lf.js +++ b/test/parallel/test-http-client-reject-cr-no-lf.js @@ -16,7 +16,7 @@ const server = net.createServer((socket) => { server.listen(common.PORT, () => { // The callback should not be called because the server is sending a // header field that ends only in \r with no following \n - const req = http.get({port:common.PORT}, (res) => { + const req = http.get({port: common.PORT}, (res) => { assert.fail(null, null, 'callback should not be called'); }); req.on('error', common.mustCall((err) => { diff --git a/test/parallel/test-http-client-response-domain.js b/test/parallel/test-http-client-response-domain.js index 59b95144867538..3034b1087e4d33 100644 --- a/test/parallel/test-http-client-response-domain.js +++ b/test/parallel/test-http-client-response-domain.js @@ -34,7 +34,7 @@ function test() { var req = http.get({ socketPath: common.PIPE, - headers: {'Content-Length':'1'}, + headers: {'Content-Length': '1'}, method: 'POST', path: '/' }); diff --git a/test/parallel/test-http-client-timeout-with-data.js b/test/parallel/test-http-client-timeout-with-data.js index 673908fe6d465f..2fff91227d1984 100644 --- a/test/parallel/test-http-client-timeout-with-data.js +++ b/test/parallel/test-http-client-timeout-with-data.js @@ -19,7 +19,7 @@ const options = { }; const server = http.createServer(function(req, res) { - res.writeHead(200, {'Content-Length':'2'}); + res.writeHead(200, {'Content-Length': '2'}); res.write('*'); setTimeout(function() { res.end('*'); }, common.platformTimeout(100)); }); diff --git a/test/parallel/test-http-expect-continue.js b/test/parallel/test-http-expect-continue.js index 84c7d473efa108..247346a9ec81a4 100644 --- a/test/parallel/test-http-expect-continue.js +++ b/test/parallel/test-http-expect-continue.js @@ -13,8 +13,8 @@ function handler(req, res) { assert.equal(sent_continue, true, 'Full response sent before 100 Continue'); console.error('Server sending full response...'); res.writeHead(200, { - 'Content-Type' : 'text/plain', - 'ABCD' : '1' + 'Content-Type': 'text/plain', + 'ABCD': '1' }); res.end(test_res_body); } diff --git a/test/parallel/test-http-remove-header-stays-removed.js b/test/parallel/test-http-remove-header-stays-removed.js index 904b8210103ebf..20390ffb2060d6 100644 --- a/test/parallel/test-http-remove-header-stays-removed.js +++ b/test/parallel/test-http-remove-header-stays-removed.js @@ -30,7 +30,7 @@ process.on('exit', function() { server.listen(common.PORT, function() { http.get({ port: common.PORT }, function(res) { assert.equal(200, res.statusCode); - assert.deepEqual(res.headers, { date : 'coffee o clock' }); + assert.deepStrictEqual(res.headers, { date: 'coffee o clock' }); res.setEncoding('ascii'); res.on('data', function(chunk) { diff --git a/test/parallel/test-http-response-multi-content-length.js b/test/parallel/test-http-response-multi-content-length.js index 4b0f2c11e3e901..8c03332fb2b7d2 100644 --- a/test/parallel/test-http-response-multi-content-length.js +++ b/test/parallel/test-http-response-multi-content-length.js @@ -33,7 +33,7 @@ server.listen(common.PORT, common.mustCall(() => { // case, the error handler must be called because the client // is not allowed to accept multiple content-length headers. http.get( - {port:common.PORT, headers:{'x-num': n}}, + {port: common.PORT, headers: {'x-num': n}}, (res) => { assert(false, 'client allowed multiple content-length headers.'); } diff --git a/test/parallel/test-http-response-splitting.js b/test/parallel/test-http-response-splitting.js index 4c954bf90acc7e..3675f8182d21a5 100644 --- a/test/parallel/test-http-response-splitting.js +++ b/test/parallel/test-http-response-splitting.js @@ -29,12 +29,12 @@ const server = http.createServer((req, res) => { break; case 1: assert.throws(common.mustCall(() => { - res.writeHead(200, {'foo' : x}); + res.writeHead(200, {'foo': x}); })); break; case 2: assert.throws(common.mustCall(() => { - res.writeHead(200, {'foo' : y}); + res.writeHead(200, {'foo': y}); })); break; default: diff --git a/test/parallel/test-http-server-multiheaders.js b/test/parallel/test-http-server-multiheaders.js index 99d72988479928..132f3fc1ea047f 100644 --- a/test/parallel/test-http-server-multiheaders.js +++ b/test/parallel/test-http-server-multiheaders.js @@ -18,7 +18,7 @@ var srv = http.createServer(function(req, res) { assert.equal(req.headers['sec-websocket-extensions'], 'foo; 1, bar; 2, baz'); assert.equal(req.headers['constructor'], 'foo, bar, baz'); - res.writeHead(200, {'Content-Type' : 'text/plain'}); + res.writeHead(200, {'Content-Type': 'text/plain'}); res.end('EOF'); srv.close(); diff --git a/test/parallel/test-http-server-multiheaders2.js b/test/parallel/test-http-server-multiheaders2.js index bf54af3465319e..80cc3416d60dae 100644 --- a/test/parallel/test-http-server-multiheaders2.js +++ b/test/parallel/test-http-server-multiheaders2.js @@ -58,7 +58,7 @@ var srv = http.createServer(function(req, res) { 'foo, bar', 'header parsed incorrectly: ' + header); }); - res.writeHead(200, {'Content-Type' : 'text/plain'}); + res.writeHead(200, {'Content-Type': 'text/plain'}); res.end('EOF'); srv.close(); diff --git a/test/parallel/test-http-server-reject-cr-no-lf.js b/test/parallel/test-http-server-reject-cr-no-lf.js index fbb89f0ff3004d..9245dc2de54999 100644 --- a/test/parallel/test-http-server-reject-cr-no-lf.js +++ b/test/parallel/test-http-server-reject-cr-no-lf.js @@ -20,7 +20,7 @@ server.on('clientError', common.mustCall((err) => { server.close(); })); server.listen(common.PORT, () => { - const client = net.connect({port:common.PORT}, () => { + const client = net.connect({port: common.PORT}, () => { client.on('data', (chunk) => { assert.fail(null, null, 'this should not be called'); }); diff --git a/test/parallel/test-listen-fd-ebadf.js b/test/parallel/test-listen-fd-ebadf.js index 51e09a7907f18e..452eb7e14046d5 100644 --- a/test/parallel/test-listen-fd-ebadf.js +++ b/test/parallel/test-listen-fd-ebadf.js @@ -9,8 +9,8 @@ process.on('exit', function() { assert.equal(gotError, 2); }); -net.createServer(common.fail).listen({fd:2}).on('error', onError); -net.createServer(common.fail).listen({fd:42}).on('error', onError); +net.createServer(common.fail).listen({fd: 2}).on('error', onError); +net.createServer(common.fail).listen({fd: 42}).on('error', onError); function onError(ex) { assert.equal(ex.code, 'EINVAL'); diff --git a/test/parallel/test-net-listen-fd0.js b/test/parallel/test-net-listen-fd0.js index 1a6c4716eb6178..b484c6306f8463 100644 --- a/test/parallel/test-net-listen-fd0.js +++ b/test/parallel/test-net-listen-fd0.js @@ -10,7 +10,7 @@ process.on('exit', function() { }); // this should fail with an async EINVAL error, not throw an exception -net.createServer(common.fail).listen({fd:0}).on('error', function(e) { +net.createServer(common.fail).listen({fd: 0}).on('error', function(e) { switch (e.code) { case 'EINVAL': case 'ENOTSOCK': diff --git a/test/parallel/test-stream-transform-split-objectmode.js b/test/parallel/test-stream-transform-split-objectmode.js index 4e33028da2f7de..9d1b01c01b5f47 100644 --- a/test/parallel/test-stream-transform-split-objectmode.js +++ b/test/parallel/test-stream-transform-split-objectmode.js @@ -4,7 +4,7 @@ var assert = require('assert'); var Transform = require('stream').Transform; -var parser = new Transform({ readableObjectMode : true }); +var parser = new Transform({ readableObjectMode: true }); assert(parser._readableState.objectMode); assert(!parser._writableState.objectMode); @@ -12,7 +12,7 @@ assert(parser._readableState.highWaterMark === 16); assert(parser._writableState.highWaterMark === (16 * 1024)); parser._transform = function(chunk, enc, callback) { - callback(null, { val : chunk[0] }); + callback(null, { val: chunk[0] }); }; var parsed; @@ -28,7 +28,7 @@ process.on('exit', function() { }); -var serializer = new Transform({ writableObjectMode : true }); +var serializer = new Transform({ writableObjectMode: true }); assert(!serializer._readableState.objectMode); assert(serializer._writableState.objectMode); @@ -45,7 +45,7 @@ serializer.on('data', function(chunk) { serialized = chunk; }); -serializer.write({ val : 42 }); +serializer.write({ val: 42 }); process.on('exit', function() { assert(serialized[0] === 42); diff --git a/test/parallel/test-stream2-transform.js b/test/parallel/test-stream2-transform.js index 11ee45915c8395..8554c965e9481b 100644 --- a/test/parallel/test-stream2-transform.js +++ b/test/parallel/test-stream2-transform.js @@ -268,7 +268,7 @@ test('assymetric transform (compress)', function(t) { test('complex transform', function(t) { var count = 0; var saved = null; - var pt = new Transform({highWaterMark:3}); + var pt = new Transform({highWaterMark: 3}); pt._transform = function(c, e, cb) { if (count++ === 1) saved = c; diff --git a/test/parallel/test-tls-alert.js b/test/parallel/test-tls-alert.js index 6ebb1e9e0d704b..20e77afda4a4be 100644 --- a/test/parallel/test-tls-alert.js +++ b/test/parallel/test-tls-alert.js @@ -29,7 +29,7 @@ function loadPEM(n) { var server = tls.Server({ secureProtocol: 'TLSv1_2_server_method', key: loadPEM('agent2-key'), - cert:loadPEM('agent2-cert') + cert: loadPEM('agent2-cert') }, null).listen(common.PORT, function() { var args = ['s_client', '-quiet', '-tls1_1', '-connect', '127.0.0.1:' + common.PORT]; diff --git a/test/parallel/test-url.js b/test/parallel/test-url.js index 9aa2682cbcb523..08f13c809df51e 100644 --- a/test/parallel/test-url.js +++ b/test/parallel/test-url.js @@ -822,7 +822,7 @@ var parseTests = { query: '@c' }, - 'http://a\r" \t\n<\'b:b@c\r\nd/e?f':{ + 'http://a\r" \t\n<\'b:b@c\r\nd/e?f': { protocol: 'http:', slashes: true, auth: 'a\r" \t\n<\'b:b', @@ -912,7 +912,7 @@ var parseTestsWithQueryString = { path: '/example', href: '/example' }, - '/example?query=value':{ + '/example?query=value': { protocol: null, slashes: null, auth: null, @@ -1091,7 +1091,7 @@ var formatTests = { // `#`,`?` in path '/path/to/%%23%3F+=&.txt?foo=theA1#bar': { - href : '/path/to/%%23%3F+=&.txt?foo=theA1#bar', + href: '/path/to/%%23%3F+=&.txt?foo=theA1#bar', pathname: '/path/to/%#?+=&.txt', query: { foo: 'theA1' @@ -1101,7 +1101,7 @@ var formatTests = { // `#`,`?` in path + `#` in query '/path/to/%%23%3F+=&.txt?foo=the%231#bar': { - href : '/path/to/%%23%3F+=&.txt?foo=the%231#bar', + href: '/path/to/%%23%3F+=&.txt?foo=the%231#bar', pathname: '/path/to/%#?+=&.txt', query: { foo: 'the#1' diff --git a/test/parallel/test-util.js b/test/parallel/test-util.js index 864361d80a6dfa..84cd058714df02 100644 --- a/test/parallel/test-util.js +++ b/test/parallel/test-util.js @@ -76,10 +76,10 @@ assert.equal(false, util.isBuffer('foo')); assert.equal(true, util.isBuffer(new Buffer('foo'))); // _extend -assert.deepEqual(util._extend({a:1}), {a:1}); -assert.deepEqual(util._extend({a:1}, []), {a:1}); -assert.deepEqual(util._extend({a:1}, null), {a:1}); -assert.deepEqual(util._extend({a:1}, true), {a:1}); -assert.deepEqual(util._extend({a:1}, false), {a:1}); -assert.deepEqual(util._extend({a:1}, {b:2}), {a:1, b:2}); -assert.deepEqual(util._extend({a:1, b:2}, {b:3}), {a:1, b:3}); +assert.deepStrictEqual(util._extend({a: 1}), {a: 1}); +assert.deepStrictEqual(util._extend({a: 1}, []), {a: 1}); +assert.deepStrictEqual(util._extend({a: 1}, null), {a: 1}); +assert.deepStrictEqual(util._extend({a: 1}, true), {a: 1}); +assert.deepStrictEqual(util._extend({a: 1}, false), {a: 1}); +assert.deepStrictEqual(util._extend({a: 1}, {b: 2}), {a: 1, b: 2}); +assert.deepStrictEqual(util._extend({a: 1, b: 2}, {b: 3}), {a: 1, b: 3}); diff --git a/test/parallel/test-vm-context.js b/test/parallel/test-vm-context.js index 3fe3cf1b66a88e..48bceb14593679 100644 --- a/test/parallel/test-vm-context.js +++ b/test/parallel/test-vm-context.js @@ -52,7 +52,7 @@ console.error('test RegExp as argument to assert.throws'); script = vm.createScript('var assert = require(\'assert\'); assert.throws(' + 'function() { throw "hello world"; }, /hello/);', 'some.js'); -script.runInNewContext({ require : require }); +script.runInNewContext({ require: require }); // Issue GH-7529 script = vm.createScript('delete b'); diff --git a/test/pummel/test-crypto-dh.js b/test/pummel/test-crypto-dh.js index dfef8c6a657cf2..302b645bdd52f2 100644 --- a/test/pummel/test-crypto-dh.js +++ b/test/pummel/test-crypto-dh.js @@ -20,14 +20,14 @@ assert.throws(function() { }); var hashes = { - modp1 : '630e9acd2cc63f7e80d8507624ba60ac0757201a', - modp2 : '18f7aa964484137f57bca64b21917a385b6a0b60', - modp5 : 'c0a8eec0c2c8a5ec2f9c26f9661eb339a010ec61', - modp14 : 'af5455606fe74cec49782bb374e4c63c9b1d132c', - modp15 : '7bdd39e5cdbb9748113933e5c2623b559c534e74', - modp16 : 'daea5277a7ad0116e734a8e0d2f297ef759d1161', - modp17 : '3b62aaf0142c2720f0bf26a9589b0432c00eadc1', - modp18 : 'a870b491bbbec9b131ae9878d07449d32e54f160' + modp1: '630e9acd2cc63f7e80d8507624ba60ac0757201a', + modp2: '18f7aa964484137f57bca64b21917a385b6a0b60', + modp5: 'c0a8eec0c2c8a5ec2f9c26f9661eb339a010ec61', + modp14: 'af5455606fe74cec49782bb374e4c63c9b1d132c', + modp15: '7bdd39e5cdbb9748113933e5c2623b559c534e74', + modp16: 'daea5277a7ad0116e734a8e0d2f297ef759d1161', + modp17: '3b62aaf0142c2720f0bf26a9589b0432c00eadc1', + modp18: 'a870b491bbbec9b131ae9878d07449d32e54f160' }; for (const name in hashes) { diff --git a/test/pummel/test-fs-watch-file-slow.js b/test/pummel/test-fs-watch-file-slow.js index c21785f233c58f..cb3bc5e579b86b 100644 --- a/test/pummel/test-fs-watch-file-slow.js +++ b/test/pummel/test-fs-watch-file-slow.js @@ -16,7 +16,7 @@ catch (e) { // swallow } -fs.watchFile(FILENAME, {interval:TIMEOUT - 250}, function(curr, prev) { +fs.watchFile(FILENAME, {interval: TIMEOUT - 250}, function(curr, prev) { console.log([curr, prev]); switch (++nevents) { case 1: diff --git a/test/sequential/test-fs-watch.js b/test/sequential/test-fs-watch.js index 51d737ddbeede8..249164c7e4e991 100644 --- a/test/sequential/test-fs-watch.js +++ b/test/sequential/test-fs-watch.js @@ -119,7 +119,7 @@ assert.throws(function() { oldhandle.close(); // clean up assert.throws(function() { - var w = fs.watchFile(__filename, {persistent:false}, function() {}); + var w = fs.watchFile(__filename, {persistent: false}, function() {}); oldhandle = w._handle; w._handle = { stop: w._handle.stop }; w.stop(); diff --git a/tools/doc/README.md b/tools/doc/README.md index fd041f001e6931..1620d6c25acbc9 100644 --- a/tools/doc/README.md +++ b/tools/doc/README.md @@ -6,18 +6,27 @@ Each type of heading has a description block. ## module + Stability: 3 - Stable description and examples. ### module.property + * Type description of the property. ### module.someFunction(x, y, [z=100]) + * `x` {String} the description of the string * `y` {Boolean} Should I stay or should I go? @@ -25,7 +34,19 @@ Each type of heading has a description block. A description of the function. + ### module.someNewFunction(x) + + + * `x` {String} the description of the string + + This feature is not in a release yet. + ### Event: 'blerg' + * Argument: SomeClass object. @@ -33,10 +54,16 @@ Each type of heading has a description block. only exception. ## Class: SomeClass + description of the class. ### Class Method: SomeClass.classMethod(anArg) + * `anArg` {Object} Just an argument * `field` {String} anArg can have this field. @@ -46,16 +73,25 @@ Each type of heading has a description block. Description of the method for humans. ### someClass.nextSibling() + * Return: {SomeClass object | null} The next someClass in line. ### someClass.someProperty + * String The indication of what someProperty is. ### Event: 'grelb' + * `isBlerg` {Boolean} diff --git a/tools/doc/addon-verify.js b/tools/doc/addon-verify.js index 2abd3574cffd7f..299d4847ef3eb3 100644 --- a/tools/doc/addon-verify.js +++ b/tools/doc/addon-verify.js @@ -10,7 +10,7 @@ const verifyDir = path.resolve(rootDir, 'test', 'addons'); const contents = fs.readFileSync(doc).toString(); -const tokens = marked.lexer(contents, {}); +const tokens = marked.lexer(contents); let files = null; let id = 0; @@ -82,6 +82,7 @@ ${files[name]} targets: [ { target_name: 'addon', + defines: [ 'V8_DEPRECATION_WARNINGS=1' ], sources: files.map(function(file) { return file.name; }) diff --git a/tools/doc/common.js b/tools/doc/common.js new file mode 100644 index 00000000000000..c2f561da806577 --- /dev/null +++ b/tools/doc/common.js @@ -0,0 +1,40 @@ +'use strict'; + +const yaml = require('js-yaml'); + +function isYAMLBlock(text) { + return !!text.match(/^$/, ''); + + // js-yaml.safeLoad() throws on error + const meta = yaml.safeLoad(text); + + const added = meta.added || meta.Added; + if (added) { + // Since semver-minors can trickle down to previous major versions, + // features may have been added in multiple versions. + meta.added = arrify(added); + } + + const deprecated = meta.deprecated || meta.Deprecated; + if (deprecated) { + // Treat deprecated like added for consistency. + meta.deprecated = arrify(deprecated); + } + + return meta; +} + +exports.extractAndParseYAML = extractAndParseYAML; diff --git a/tools/doc/generate.js b/tools/doc/generate.js index ff14cbd5e8979b..077e740432c837 100644 --- a/tools/doc/generate.js +++ b/tools/doc/generate.js @@ -1,15 +1,16 @@ 'use strict'; -var processIncludes = require('./preprocess.js'); -var fs = require('fs'); +const processIncludes = require('./preprocess.js'); +const fs = require('fs'); // parse the args. // Don't use nopt or whatever for this. It's simple enough. -var args = process.argv.slice(2); -var format = 'json'; -var template = null; -var inputFile = null; +const args = process.argv.slice(2); +let format = 'json'; +let template = null; +let inputFile = null; +let nodeVersion = null; args.forEach(function(arg) { if (!arg.match(/^\-\-/)) { @@ -18,15 +19,17 @@ args.forEach(function(arg) { format = arg.replace(/^\-\-format=/, ''); } else if (arg.match(/^\-\-template=/)) { template = arg.replace(/^\-\-template=/, ''); + } else if (arg.match(/^\-\-node\-version=/)) { + nodeVersion = arg.replace(/^\-\-node\-version=/, ''); } }); +nodeVersion = nodeVersion || process.version; if (!inputFile) { throw new Error('No input file specified'); } - console.error('Input file = %s', inputFile); fs.readFile(inputFile, 'utf8', function(er, input) { if (er) throw er; @@ -34,7 +37,6 @@ fs.readFile(inputFile, 'utf8', function(er, input) { processIncludes(inputFile, input, next); }); - function next(er, input) { if (er) throw er; switch (format) { @@ -46,10 +48,19 @@ function next(er, input) { break; case 'html': - require('./html.js')(input, inputFile, template, function(er, html) { - if (er) throw er; - console.log(html); - }); + require('./html.js')( + { + input: input, + filename: inputFile, + template: template, + nodeVersion: nodeVersion, + }, + + function(er, html) { + if (er) throw er; + console.log(html); + } + ); break; default: diff --git a/tools/doc/html.js b/tools/doc/html.js index 68ccf976b6c1f8..769d601e26c800 100644 --- a/tools/doc/html.js +++ b/tools/doc/html.js @@ -1,13 +1,23 @@ 'use strict'; -var fs = require('fs'); -var marked = require('marked'); -var path = require('path'); -var preprocess = require('./preprocess.js'); -var typeParser = require('./type-parser.js'); +const common = require('./common.js'); +const fs = require('fs'); +const marked = require('marked'); +const path = require('path'); +const preprocess = require('./preprocess.js'); +const typeParser = require('./type-parser.js'); module.exports = toHTML; +// customized heading without id attribute +var renderer = new marked.Renderer(); +renderer.heading = function(text, level) { + return '' + text + '\n'; +}; +marked.setOptions({ + renderer: renderer +}); + // TODO(chrisdickinson): never stop vomitting / fix this. var gtocPath = path.resolve(path.join( __dirname, @@ -20,7 +30,13 @@ var gtocPath = path.resolve(path.join( var gtocLoading = null; var gtocData = null; -function toHTML(input, filename, template, cb) { +/** + * opts: input, filename, template, nodeVersion. + */ +function toHTML(opts, cb) { + var template = opts.template; + var nodeVersion = opts.nodeVersion || process.version; + if (gtocData) { return onGtocLoaded(); } @@ -41,10 +57,15 @@ function toHTML(input, filename, template, cb) { } function onGtocLoaded() { - var lexed = marked.lexer(input); + var lexed = marked.lexer(opts.input); fs.readFile(template, 'utf8', function(er, template) { if (er) return cb(er); - render(lexed, filename, template, cb); + render({ + lexed: lexed, + filename: opts.filename, + template: template, + nodeVersion: nodeVersion, + }, cb); }); } } @@ -71,7 +92,15 @@ function toID(filename) { .replace(/-+/g, '-'); } -function render(lexed, filename, template, cb) { +/** + * opts: lexed, filename, template, nodeVersion. + */ +function render(opts, cb) { + var lexed = opts.lexed; + var filename = opts.filename; + var template = opts.template; + var nodeVersion = opts.nodeVersion || process.version; + // get the section var section = getSection(lexed); @@ -90,7 +119,7 @@ function render(lexed, filename, template, cb) { template = template.replace(/__ID__/g, id); template = template.replace(/__FILENAME__/g, filename); template = template.replace(/__SECTION__/g, section); - template = template.replace(/__VERSION__/g, process.version); + template = template.replace(/__VERSION__/g, nodeVersion); template = template.replace(/__TOC__/g, toc); template = template.replace( /__GTOC__/g, @@ -142,12 +171,15 @@ function parseLists(input) { if (tok.type === 'list_start') { state = 'LIST'; if (depth === 0) { - output.push({ type:'html', text: '
      ' }); + output.push({ type: 'html', text: '
      ' }); } depth++; output.push(tok); return; } + if (tok.type === 'html' && common.isYAMLBlock(tok.text)) { + tok.text = parseYAML(tok.text); + } state = null; output.push(tok); return; @@ -163,7 +195,7 @@ function parseLists(input) { output.push(tok); if (depth === 0) { state = null; - output.push({ type:'html', text: '
      ' }); + output.push({ type: 'html', text: '
      ' }); } return; } @@ -174,6 +206,21 @@ function parseLists(input) { return output; } +function parseYAML(text) { + const meta = common.extractAndParseYAML(text); + const html = [''); + return html.join('\n'); +} // Syscalls which appear in the docs, but which only exist in BSD / OSX var BSD_ONLY_SYSCALLS = new Set(['lchmod']); @@ -236,7 +283,21 @@ function getSection(lexed) { function buildToc(lexed, filename, cb) { var toc = []; var depth = 0; + + const startIncludeRefRE = /^\s*\s*$/; + const endIncludeRefRE = /^\s*\s*$/; + const realFilenames = [filename]; + lexed.forEach(function(tok) { + // Keep track of the current filename along @include directives. + if (tok.type === 'html') { + let match; + if ((match = tok.text.match(startIncludeRefRE)) !== null) + realFilenames.unshift(match[1]); + else if (tok.text.match(endIncludeRefRE)) + realFilenames.shift(); + } + if (tok.type !== 'heading') return; if (tok.depth - depth > 1) { return cb(new Error('Inappropriate heading level\n' + @@ -244,7 +305,8 @@ function buildToc(lexed, filename, cb) { } depth = tok.depth; - var id = getId(filename + '_' + tok.text.trim()); + const realFilename = path.basename(realFilenames[0], '.md'); + const id = getId(realFilename + '_' + tok.text.trim()); toc.push(new Array((depth - 1) * 2 + 1).join(' ') + '* ' + tok.text + ''); diff --git a/tools/doc/json.js b/tools/doc/json.js index 3d08026daaabd8..33bde6515b1235 100644 --- a/tools/doc/json.js +++ b/tools/doc/json.js @@ -5,7 +5,17 @@ module.exports = doJSON; // Take the lexed input, and return a JSON-encoded object // A module looks like this: https://gist.github.com/1777387 -var marked = require('marked'); +const common = require('./common.js'); +const marked = require('marked'); + +// customized heading without id attribute +var renderer = new marked.Renderer(); +renderer.heading = function(text, level) { + return '' + text + '\n'; +}; +marked.setOptions({ + renderer: renderer +}); function doJSON(input, filename, cb) { var root = {source: filename}; @@ -91,6 +101,8 @@ function doJSON(input, filename, cb) { current.list = current.list || []; current.list.push(tok); current.list.level = 1; + } else if (type === 'html' && common.isYAMLBlock(tok.text)) { + current.meta = parseYAML(tok.text); } else { current.desc = current.desc || []; if (!Array.isArray(current.desc)) { @@ -274,6 +286,9 @@ function processList(section) { delete section.list; } +function parseYAML(text) { + return common.extractAndParseYAML(text); +} // textRaw = "someobject.someMethod(a[, b=100][, c])" function parseSignature(text, sig) { diff --git a/tools/doc/node_modules/js-yaml/index.js b/tools/doc/node_modules/js-yaml/index.js new file mode 100644 index 00000000000000..620bc293ffe032 --- /dev/null +++ b/tools/doc/node_modules/js-yaml/index.js @@ -0,0 +1,15 @@ +'use strict'; + +// Hack to load the js-yaml module from eslint. +// No other reason than that it’s huge. + +const path = require('path'); + +const realJSYaml = path.resolve( + __dirname, '..', '..', '..', // tools/ + 'eslint', + 'node_modules', + 'js-yaml' +); + +module.exports = require(realJSYaml); diff --git a/tools/doc/node_modules/marked/.travis.yml b/tools/doc/node_modules/marked/.travis.yml new file mode 100644 index 00000000000000..60d00ce140f37d --- /dev/null +++ b/tools/doc/node_modules/marked/.travis.yml @@ -0,0 +1,5 @@ +language: node_js +node_js: + - "0.10" + - "0.8" + - "0.6" diff --git a/tools/doc/node_modules/marked/Gulpfile.js b/tools/doc/node_modules/marked/Gulpfile.js new file mode 100644 index 00000000000000..cebc16a650b0e9 --- /dev/null +++ b/tools/doc/node_modules/marked/Gulpfile.js @@ -0,0 +1,22 @@ +var gulp = require('gulp'); +var uglify = require('gulp-uglify'); +var concat = require('gulp-concat'); + +var preserveFirstComment = function() { + var set = false; + + return function() { + if (set) return false; + set = true; + return true; + }; +}; + +gulp.task('uglify', function() { + gulp.src('lib/marked.js') + .pipe(uglify({preserveComments: preserveFirstComment()})) + .pipe(concat('marked.min.js')) + .pipe(gulp.dest('.')); +}); + +gulp.task('default', ['uglify']); diff --git a/tools/doc/node_modules/marked/LICENSE b/tools/doc/node_modules/marked/LICENSE index 40597477c63bea..a7b812ed618f11 100644 --- a/tools/doc/node_modules/marked/LICENSE +++ b/tools/doc/node_modules/marked/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2011-2012, Christopher Jeffrey (https://github.com/chjj/) +Copyright (c) 2011-2014, Christopher Jeffrey (https://github.com/chjj/) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/tools/doc/node_modules/marked/Makefile b/tools/doc/node_modules/marked/Makefile index 76904000b5ee98..d9349f07996d34 100644 --- a/tools/doc/node_modules/marked/Makefile +++ b/tools/doc/node_modules/marked/Makefile @@ -1,9 +1,12 @@ all: @cp lib/marked.js marked.js - @uglifyjs -o marked.min.js marked.js + @uglifyjs --comments '/\*[^\0]+?Copyright[^\0]+?\*/' -o marked.min.js lib/marked.js clean: @rm marked.js @rm marked.min.js +bench: + @node test --bench + .PHONY: clean all diff --git a/tools/doc/node_modules/marked/README.md b/tools/doc/node_modules/marked/README.md index 1a0747c0d7e879..efa71aaaabc849 100644 --- a/tools/doc/node_modules/marked/README.md +++ b/tools/doc/node_modules/marked/README.md @@ -1,47 +1,299 @@ # marked -A full-featured markdown parser and compiler. -Built for speed. +> A full-featured markdown parser and compiler, written in JavaScript. Built +> for speed. -## Benchmarks +[![NPM version](https://badge.fury.io/js/marked.png)][badge] -node v0.4.x +## Install ``` bash -$ node test --bench -marked completed in 12071ms. -showdown (reuse converter) completed in 27387ms. -showdown (new converter) completed in 75617ms. -markdown-js completed in 70069ms. +npm install marked --save ``` -node v0.6.x +## Usage + +Minimal usage: -``` bash -$ node test --bench -marked completed in 6485ms. -marked (with gfm) completed in 7466ms. -discount completed in 7169ms. -showdown (reuse converter) completed in 15937ms. -showdown (new converter) completed in 18279ms. -markdown-js completed in 23572ms. +```js +var marked = require('marked'); +console.log(marked('I am using __markdown__.')); +// Outputs:

      I am using markdown.

      ``` -__Marked is now faster than Discount, which is written in C.__ +Example setting options with default values: + +```js +var marked = require('marked'); +marked.setOptions({ + renderer: new marked.Renderer(), + gfm: true, + tables: true, + breaks: false, + pedantic: false, + sanitize: true, + smartLists: true, + smartypants: false +}); + +console.log(marked('I am using __markdown__.')); +``` -For those feeling skeptical: These benchmarks run the entire markdown test suite -1000 times. The test suite tests every feature. It doesn't cater to specific -aspects. +### Browser + +```html + + + + + Marked in the browser + + + +
      + + + +``` -Benchmarks for other engines to come (?). +## marked(markdownString [,options] [,callback]) -## Install +### markdownString + +Type: `string` + +String of markdown source to be compiled. + +### options + +Type: `object` + +Hash of options. Can also be set using the `marked.setOptions` method as seen +above. + +### callback + +Type: `function` + +Function called when the `markdownString` has been fully parsed when using +async highlighting. If the `options` argument is omitted, this can be used as +the second argument. + +## Options + +### highlight + +Type: `function` + +A function to highlight code blocks. The first example below uses async highlighting with +[node-pygmentize-bundled][pygmentize], and the second is a synchronous example using +[highlight.js][highlight]: + +```js +var marked = require('marked'); + +var markdownString = '```js\n console.log("hello"); \n```'; + +// Async highlighting with pygmentize-bundled +marked.setOptions({ + highlight: function (code, lang, callback) { + require('pygmentize-bundled')({ lang: lang, format: 'html' }, code, function (err, result) { + callback(err, result.toString()); + }); + } +}); + +// Using async version of marked +marked(markdownString, function (err, content) { + if (err) throw err; + console.log(content); +}); + +// Synchronous highlighting with highlight.js +marked.setOptions({ + highlight: function (code) { + return require('highlight.js').highlightAuto(code).value; + } +}); + +console.log(marked(markdownString)); +``` + +#### highlight arguments + +`code` + +Type: `string` + +The section of code to pass to the highlighter. + +`lang` + +Type: `string` + +The programming language specified in the code block. + +`callback` + +Type: `function` + +The callback function to call when using an async highlighter. + +### renderer + +Type: `object` +Default: `new Renderer()` + +An object containing functions to render tokens to HTML. + +#### Overriding renderer methods + +The renderer option allows you to render tokens in a custom manner. Here is an +example of overriding the default heading token rendering by adding an embedded anchor tag like on GitHub: + +```javascript +var marked = require('marked'); +var renderer = new marked.Renderer(); + +renderer.heading = function (text, level) { + var escapedText = text.toLowerCase().replace(/[^\w]+/g, '-'); + + return '' + + text + ''; +}, + +console.log(marked('# heading+', { renderer: renderer })); +``` +This code will output the following HTML: +```html +

      + + + + heading+ +

      +``` + +#### Block level renderer methods + +- code(*string* code, *string* language) +- blockquote(*string* quote) +- html(*string* html) +- heading(*string* text, *number* level) +- hr() +- list(*string* body, *boolean* ordered) +- listitem(*string* text) +- paragraph(*string* text) +- table(*string* header, *string* body) +- tablerow(*string* content) +- tablecell(*string* content, *object* flags) + +`flags` has the following properties: + +```js +{ + header: true || false, + align: 'center' || 'left' || 'right' +} +``` + +#### Inline level renderer methods + +- strong(*string* text) +- em(*string* text) +- codespan(*string* code) +- br() +- del(*string* text) +- link(*string* href, *string* title, *string* text) +- image(*string* href, *string* title, *string* text) + +### gfm + +Type: `boolean` +Default: `true` + +Enable [GitHub flavored markdown][gfm]. + +### tables + +Type: `boolean` +Default: `true` + +Enable GFM [tables][tables]. +This option requires the `gfm` option to be true. + +### breaks + +Type: `boolean` +Default: `false` + +Enable GFM [line breaks][breaks]. +This option requires the `gfm` option to be true. + +### pedantic + +Type: `boolean` +Default: `false` + +Conform to obscure parts of `markdown.pl` as much as possible. Don't fix any of +the original markdown bugs or poor behavior. + +### sanitize + +Type: `boolean` +Default: `false` + +Sanitize the output. Ignore any HTML that has been input. + +### smartLists + +Type: `boolean` +Default: `true` + +Use smarter list behavior than the original markdown. May eventually be +default with the old behavior moved into `pedantic`. + +### smartypants + +Type: `boolean` +Default: `false` + +Use "smart" typograhic punctuation for things like quotes and dashes. + +## Access to lexer and parser + +You also have direct access to the lexer and parser if you so desire. + +``` js +var tokens = marked.lexer(text, options); +console.log(marked.parser(tokens)); +``` + +``` js +var lexer = new marked.Lexer(options); +var tokens = lexer.lex(text); +console.log(tokens); +console.log(lexer.rules); +``` + +## CLI ``` bash -$ npm install marked +$ marked -o hello.html +hello world +^D +$ cat hello.html +

      hello world

      ``` -## Another javascript markdown parser +## Philosophy behind marked The point of marked was to create a markdown compiler where it was possible to frequently parse huge chunks of markdown without having to worry about @@ -58,78 +310,97 @@ of performance, but did not in order to be exactly what you expect in terms of a markdown rendering. In fact, this is why marked could be considered at a disadvantage in the benchmarks above. -Along with implementing every markdown feature, marked also implements -[GFM features](http://github.github.com/github-flavored-markdown/). +Along with implementing every markdown feature, marked also implements [GFM +features][gfmf]. -## Usage +## Benchmarks -``` js -var marked = require('marked'); -console.log(marked('i am using __markdown__.')); +node v0.8.x + +``` bash +$ node test --bench +marked completed in 3411ms. +marked (gfm) completed in 3727ms. +marked (pedantic) completed in 3201ms. +robotskirt completed in 808ms. +showdown (reuse converter) completed in 11954ms. +showdown (new converter) completed in 17774ms. +markdown-js completed in 17191ms. ``` +__Marked is now faster than Discount, which is written in C.__ + +For those feeling skeptical: These benchmarks run the entire markdown test suite 1000 times. The test suite tests every feature. It doesn't cater to specific aspects. + +### Pro level + You also have direct access to the lexer and parser if you so desire. ``` js -var tokens = marked.lexer(str); +var tokens = marked.lexer(text, options); console.log(marked.parser(tokens)); ``` +``` js +var lexer = new marked.Lexer(options); +var tokens = lexer.lex(text); +console.log(tokens); +console.log(lexer.rules); +``` + ``` bash $ node > require('marked').lexer('> i am using marked.') [ { type: 'blockquote_start' }, - { type: 'text', text: ' i am using marked.' }, + { type: 'paragraph', + text: 'i am using marked.' }, { type: 'blockquote_end' }, links: {} ] ``` -## CLI +## Running Tests & Contributing -``` bash -$ marked -o hello.html -hello world -^D -$ cat hello.html -

      hello world

      -``` +If you want to submit a pull request, make sure your changes pass the test +suite. If you're adding a new feature, be sure to add your own test. -## Syntax Highlighting +The marked test suite is set up slightly strangely: `test/new` is for all tests +that are not part of the original markdown.pl test suite (this is where your +test should go if you make one). `test/original` is only for the original +markdown.pl tests. `test/tests` houses both types of tests after they have been +combined and moved/generated by running `node test --fix` or `marked --test +--fix`. -Marked has an interface that allows for a syntax highlighter to highlight code -blocks before they're output. +In other words, if you have a test to add, add it to `test/new/` and then +regenerate the tests with `node test --fix`. Commit the result. If your test +uses a certain feature, for example, maybe it assumes GFM is *not* enabled, you +can add `.nogfm` to the filename. So, `my-test.text` becomes +`my-test.nogfm.text`. You can do this with any marked option. Say you want +line breaks and smartypants enabled, your filename should be: +`my-test.breaks.smartypants.text`. -Example implementation: +To run the tests: -``` js -var highlight = require('my-syntax-highlighter') - , marked_ = require('marked'); - -var marked = function(text) { - var tokens = marked_.lexer(text) - , l = tokens.length - , i = 0 - , token; - - for (; i < l; i++) { - token = tokens[i]; - if (token.type === 'code') { - token.text = highlight(token.text, token.lang); - // marked should not escape this - token.escaped = true; - } - } - - text = marked_.parser(tokens); +``` bash +cd marked/ +node test +``` - return text; -}; +### Contribution and License Agreement -module.exports = marked; -``` +If you contribute code to this project, you are implicitly allowing your code +to be distributed under the MIT license. You are also implicitly verifying that +all code is your original work. `` ## License -Copyright (c) 2011-2012, Christopher Jeffrey. (MIT License) +Copyright (c) 2011-2014, Christopher Jeffrey. (MIT License) See LICENSE for more info. + +[gfm]: https://help.github.com/articles/github-flavored-markdown +[gfmf]: http://github.github.com/github-flavored-markdown/ +[pygmentize]: https://github.com/rvagg/node-pygmentize-bundled +[highlight]: https://github.com/isagalaev/highlight.js +[badge]: http://badge.fury.io/js/marked +[tables]: https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet#wiki-tables +[breaks]: https://help.github.com/articles/github-flavored-markdown#newlines diff --git a/tools/doc/node_modules/marked/bin/marked b/tools/doc/node_modules/marked/bin/marked index 7d00504ed16803..64254fc3eb2e08 100755 --- a/tools/doc/node_modules/marked/bin/marked +++ b/tools/doc/node_modules/marked/bin/marked @@ -2,7 +2,7 @@ /** * Marked CLI - * Copyright (c) 2011-2012, Christopher Jeffrey (MIT License) + * Copyright (c) 2011-2013, Christopher Jeffrey (MIT License) */ var fs = require('fs') @@ -13,7 +13,7 @@ var fs = require('fs') * Man Page */ -var help = function() { +function help() { var spawn = require('child_process').spawn; var options = { @@ -26,32 +26,54 @@ var help = function() { spawn('man', [__dirname + '/../man/marked.1'], options); -}; +} /** * Main */ -var main = function(argv) { +function main(argv, callback) { var files = [] - , data = '' + , options = {} , input , output , arg - , tokens; + , tokens + , opt; - var getarg = function() { + function getarg() { var arg = argv.shift(); - arg = arg.split('='); - if (arg.length > 1) { - argv.unshift(arg.slice(1).join('=')); + + if (arg.indexOf('--') === 0) { + // e.g. --opt + arg = arg.split('='); + if (arg.length > 1) { + // e.g. --opt=val + argv.unshift(arg.slice(1).join('=')); + } + arg = arg[0]; + } else if (arg[0] === '-') { + if (arg.length > 2) { + // e.g. -abc + argv = arg.substring(1).split('').map(function(ch) { + return '-' + ch; + }).concat(argv); + arg = argv.shift(); + } else { + // e.g. -a + } + } else { + // e.g. foo } - return arg[0]; - }; + + return arg; + } while (argv.length) { arg = getarg(); switch (arg) { + case '--test': + return require('../test').main(process.argv.slice()); case '-o': case '--output': output = argv.shift(); @@ -68,48 +90,98 @@ var main = function(argv) { case '--help': return help(); default: - files.push(arg); + if (arg.indexOf('--') === 0) { + opt = camelize(arg.replace(/^--(no-)?/, '')); + if (!marked.defaults.hasOwnProperty(opt)) { + continue; + } + if (arg.indexOf('--no-') === 0) { + options[opt] = typeof marked.defaults[opt] !== 'boolean' + ? null + : false; + } else { + options[opt] = typeof marked.defaults[opt] !== 'boolean' + ? argv.shift() + : true; + } + } else { + files.push(arg); + } break; } } - if (!input) { - if (files.length <= 2) { - var stdin = process.stdin; - - stdin.setEncoding('utf8'); - stdin.resume(); - - stdin.on('data', function(text) { - data += text; - }); - - stdin.on('end', write); - - return; + function getData(callback) { + if (!input) { + if (files.length <= 2) { + return getStdin(callback); + } + input = files.pop(); } - input = files.pop(); + return fs.readFile(input, 'utf8', callback); } - data = fs.readFileSync(input, 'utf8'); - write(); + return getData(function(err, data) { + if (err) return callback(err); - function write() { data = tokens - ? JSON.stringify(marked.lexer(data), null, 2) - : marked(data); + ? JSON.stringify(marked.lexer(data, options), null, 2) + : marked(data, options); if (!output) { process.stdout.write(data + '\n'); - } else { - fs.writeFileSync(output, data); + return callback(); } + + return fs.writeFile(output, data, callback); + }); +} + +/** + * Helpers + */ + +function getStdin(callback) { + var stdin = process.stdin + , buff = ''; + + stdin.setEncoding('utf8'); + + stdin.on('data', function(data) { + buff += data; + }); + + stdin.on('error', function(err) { + return callback(err); + }); + + stdin.on('end', function() { + return callback(null, buff); + }); + + try { + stdin.resume(); + } catch (e) { + callback(e); } -}; +} + +function camelize(text) { + return text.replace(/(\w)-(\w)/g, function(_, a, b) { + return a + b.toUpperCase(); + }); +} + +/** + * Expose / Entry Point + */ if (!module.parent) { process.title = 'marked'; - main(process.argv.slice()); + main(process.argv.slice(), function(err, code) { + if (err) throw err; + return process.exit(code || 0); + }); } else { module.exports = main; } diff --git a/tools/doc/node_modules/marked/bower.json b/tools/doc/node_modules/marked/bower.json new file mode 100644 index 00000000000000..a2a8187759f7c9 --- /dev/null +++ b/tools/doc/node_modules/marked/bower.json @@ -0,0 +1,24 @@ +{ + "name": "marked", + "version": "0.3.4", + "homepage": "https://github.com/chjj/marked", + "authors": [ + "Christopher Jeffrey " + ], + "description": "A markdown parser built for speed", + "keywords": [ + "markdown", + "markup", + "html" + ], + "main": "lib/marked.js", + "license": "MIT", + "ignore": [ + "**/.*", + "node_modules", + "bower_components", + "app/bower_components", + "test", + "tests" + ] +} diff --git a/tools/doc/node_modules/marked/component.json b/tools/doc/node_modules/marked/component.json new file mode 100644 index 00000000000000..1d672877f6e712 --- /dev/null +++ b/tools/doc/node_modules/marked/component.json @@ -0,0 +1,10 @@ +{ + "name": "marked", + "version": "0.3.4", + "repo": "chjj/marked", + "description": "A markdown parser built for speed", + "keywords": ["markdown", "markup", "html"], + "scripts": ["lib/marked.js"], + "main": "lib/marked.js", + "license": "MIT" +} diff --git a/tools/doc/node_modules/marked/doc/broken.md b/tools/doc/node_modules/marked/doc/broken.md new file mode 100644 index 00000000000000..7bfa49e8a9adf9 --- /dev/null +++ b/tools/doc/node_modules/marked/doc/broken.md @@ -0,0 +1,426 @@ +# Markdown is broken + +I have a lot of scraps of markdown engine oddities that I've collected over the +years. What you see below is slightly messy, but it's what I've managed to +cobble together to illustrate the differences between markdown engines, and +why, if there ever is a markdown specification, it has to be absolutely +thorough. There are a lot more of these little differences I have documented +elsewhere. I know I will find them lingering on my disk one day, but until +then, I'll continue to add whatever strange nonsensical things I find. + +Some of these examples may only mention a particular engine compared to marked. +However, the examples with markdown.pl could easily be swapped out for +discount, upskirt, or markdown.js, and you would very easily see even more +inconsistencies. + +A lot of this was written when I was very unsatisfied with the inconsistencies +between markdown engines. Please excuse the frustration noticeable in my +writing. + +## Examples of markdown's "stupid" list parsing + +``` +$ markdown.pl + + * item1 + + * item2 + + text +^D +
        +
      • item1

        + +
          +
        • item2
        • +
        + +

        text

      • +

      +``` + + +``` +$ marked + * item1 + + * item2 + + text +^D +
        +
      • item1

        +
          +
        • item2
        • +
        +

        text

        +
      • +
      +``` + +Which looks correct to you? + +- - - + +``` +$ markdown.pl +* hello + > world +^D +

        +
      • hello

        + +
        +

        world

      • +

      + +``` + +``` +$ marked +* hello + > world +^D +
        +
      • hello
        +

        world

        +
        +
      • +
      +``` + +Again, which looks correct to you? + +- - - + +EXAMPLE: + +``` +$ markdown.pl +* hello + * world + * hi + code +^D +
        +
      • hello +
          +
        • world
        • +
        • hi + code
        • +
      • +
      +``` + +The code isn't a code block even though it's after the bullet margin. I know, +lets give it two more spaces, effectively making it 8 spaces past the bullet. + +``` +$ markdown.pl +* hello + * world + * hi + code +^D +
        +
      • hello +
          +
        • world
        • +
        • hi + code
        • +
      • +
      +``` + +And, it's still not a code block. Did you also notice that the 3rd item isn't +even its own list? Markdown screws that up too because of its indentation +unaware parsing. + +- - - + +Let's look at some more examples of markdown's list parsing: + +``` +$ markdown.pl + + * item1 + + * item2 + + text +^D +
        +
      • item1

        + +
          +
        • item2
        • +
        + +

        text

      • +

      +``` + +Misnested tags. + + +``` +$ marked + * item1 + + * item2 + + text +^D +
        +
      • item1

        +
          +
        • item2
        • +
        +

        text

        +
      • +
      +``` + +Which looks correct to you? + +- - - + +``` +$ markdown.pl +* hello + > world +^D +

        +
      • hello

        + +
        +

        world

      • +

      + +``` + +More misnested tags. + + +``` +$ marked +* hello + > world +^D +
        +
      • hello
        +

        world

        +
        +
      • +
      +``` + +Again, which looks correct to you? + +- - - + +# Why quality matters - Part 2 + +``` bash +$ markdown.pl +* hello + > world +^D +

        +
      • hello

        + +
        +

        world

      • +

      + +``` + +``` bash +$ sundown # upskirt +* hello + > world +^D +
        +
      • hello +> world
      • +
      +``` + +``` bash +$ marked +* hello + > world +^D +
      • hello

        world

      +``` + +Which looks correct to you? + +- - - + +See: https://github.com/evilstreak/markdown-js/issues/23 + +``` bash +$ markdown.pl # upskirt/markdown.js/discount +* hello + var a = 1; +* world +^D +
        +
      • hello +var a = 1;
      • +
      • world
      • +
      +``` + +``` bash +$ marked +* hello + var a = 1; +* world +^D +
      • hello +
        code>var a = 1;
      • +
      • world
      +``` + +Which looks more reasonable? Why shouldn't code blocks be able to appear in +list items in a sane way? + +- - - + +``` bash +$ markdown.js +
      hello
      + +hello +^D +

      <div>hello</div>

      + +

      <span>hello</span>

      +``` + +``` bash +$ marked +
      hello
      + +hello +^D +
      hello
      + + +

      hello +

      +``` + +- - - + +See: https://github.com/evilstreak/markdown-js/issues/27 + +``` bash +$ markdown.js +[![an image](/image)](/link) +^D +

      ![an image

      +``` + +``` bash +$ marked +[![an image](/image)](/link) +^D +

      an image +

      +``` + +- - - + +See: https://github.com/evilstreak/markdown-js/issues/24 + +``` bash +$ markdown.js +> a + +> b + +> c +^D +

      a

      bundefined> c

      +``` + +``` bash +$ marked +> a + +> b + +> c +^D +

      a + +

      +

      b + +

      +

      c +

      +``` + +- - - + +``` bash +$ markdown.pl +* hello + * world + how + + are + you + + * today +* hi +^D +
        +
      • hello

        + +
          +
        • world +how
        • +
        + +

        are +you

        + +
          +
        • today
        • +
      • +
      • hi
      • +
      +``` + +``` bash +$ marked +* hello + * world + how + + are + you + + * today +* hi +^D +
        +
      • hello

        +
          +
        • world +how

          +

          are +you

          +
        • +
        • today

          +
        • +
        +
      • +
      • hi
      • +
      +``` diff --git a/tools/doc/node_modules/marked/doc/todo.md b/tools/doc/node_modules/marked/doc/todo.md new file mode 100644 index 00000000000000..2e60b162aef82d --- /dev/null +++ b/tools/doc/node_modules/marked/doc/todo.md @@ -0,0 +1,2 @@ +# Todo + diff --git a/tools/doc/node_modules/marked/lib/marked.js b/tools/doc/node_modules/marked/lib/marked.js index e76178471a15bb..03251f3c58a761 100644 --- a/tools/doc/node_modules/marked/lib/marked.js +++ b/tools/doc/node_modules/marked/lib/marked.js @@ -1,6 +1,7 @@ /** - * marked - A markdown parser (https://github.com/chjj/marked) - * Copyright (c) 2011-2012, Christopher Jeffrey. (MIT Licensed) + * marked - a markdown parser + * Copyright (c) 2011-2014, Christopher Jeffrey. (MIT Licensed) + * https://github.com/chjj/marked */ ;(function() { @@ -11,82 +12,148 @@ var block = { newline: /^\n+/, - code: /^ {4,}[^\n]*(?:\n {4,}[^\n]*|\n)*(?:\n+|$)/, - gfm_code: /^ *``` *(\w+)? *\n([^\0]+?)\s*``` *(?:\n+|$)/, - hr: /^( *[\-*_]){3,} *(?:\n+|$)/, + code: /^( {4}[^\n]+\n*)+/, + fences: noop, + hr: /^( *[-*_]){3,} *(?:\n+|$)/, heading: /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/, - lheading: /^([^\n]+)\n *(=|-){3,} *\n*/, - blockquote: /^( *>[^\n]+(\n[^\n]+)*\n*)+/, - list: /^( *)([*+-]|\d+\.) [^\0]+?(?:\n{2,}(?! )|\s*$)(?!\1bullet)\n*/, - html: /^ *(?:comment|closed|closing) *(?:\n{2,}|\s*$)/, - def: /^ *\[([^\]]+)\]: *([^\s]+)(?: +["(]([^\n]+)[")])? *(?:\n+|$)/, - paragraph: /^([^\n]+\n?(?!body))+\n*/, + nptable: noop, + lheading: /^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/, + blockquote: /^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/, + list: /^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/, + html: /^ *(?:comment *(?:\n|\s*$)|closed *(?:\n{2,}|\s*$)|closing *(?:\n{2,}|\s*$))/, + def: /^ *\[([^\]]+)\]: *]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/, + table: noop, + paragraph: /^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/, text: /^[^\n]+/ }; -block.list = (function() { - var list = block.list.source; +block.bullet = /(?:[*+-]|\d+\.)/; +block.item = /^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/; +block.item = replace(block.item, 'gm') + (/bull/g, block.bullet) + (); + +block.list = replace(block.list) + (/bull/g, block.bullet) + ('hr', '\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))') + ('def', '\\n+(?=' + block.def.source + ')') + (); + +block.blockquote = replace(block.blockquote) + ('def', block.def) + (); + +block._tag = '(?!(?:' + + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code' + + '|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo' + + '|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b'; + +block.html = replace(block.html) + ('comment', //) + ('closed', /<(tag)[\s\S]+?<\/\1>/) + ('closing', /])*?>/) + (/tag/g, block._tag) + (); + +block.paragraph = replace(block.paragraph) + ('hr', block.hr) + ('heading', block.heading) + ('lheading', block.lheading) + ('blockquote', block.blockquote) + ('tag', '<' + block._tag) + ('def', block.def) + (); - list = list - .replace('bullet', /(?:[*+-](?!(?: *[-*]){2,})|\d+\.)/.source); - - return new RegExp(list); -})(); +/** + * Normal Block Grammar + */ -block.html = (function() { - var html = block.html.source; +block.normal = merge({}, block); - html = html - .replace('comment', //.source) - .replace('closed', /<(tag)[^\0]+?<\/\1>/.source) - .replace('closing', /])*?>/.source) - .replace(/tag/g, tag()); +/** + * GFM Block Grammar + */ - return new RegExp(html); -})(); +block.gfm = merge({}, block.normal, { + fences: /^ *(`{3,}|~{3,})[ \.]*(\S+)? *\n([\s\S]*?)\s*\1 *(?:\n+|$)/, + paragraph: /^/, + heading: /^ *(#{1,6}) +([^\n]+?) *#* *(?:\n+|$)/ +}); -block.paragraph = (function() { - var paragraph = block.paragraph.source - , body = []; +block.gfm.paragraph = replace(block.paragraph) + ('(?!', '(?!' + + block.gfm.fences.source.replace('\\1', '\\2') + '|' + + block.list.source.replace('\\1', '\\3') + '|') + (); - (function push(rule) { - rule = block[rule] ? block[rule].source : rule; - body.push(rule.replace(/(^|[^\[])\^/g, '$1')); - return push; - }) - ('gfm_code') - ('hr') - ('heading') - ('lheading') - ('blockquote') - ('<' + tag()) - ('def'); +/** + * GFM + Tables Block Grammar + */ - return new - RegExp(paragraph.replace('body', body.join('|'))); -})(); +block.tables = merge({}, block.gfm, { + nptable: /^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/, + table: /^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/ +}); /** * Block Lexer */ -block.lexer = function(src) { - var tokens = []; +function Lexer(options) { + this.tokens = []; + this.tokens.links = {}; + this.options = options || marked.defaults; + this.rules = block.normal; + + if (this.options.gfm) { + if (this.options.tables) { + this.rules = block.tables; + } else { + this.rules = block.gfm; + } + } +} + +/** + * Expose Block Rules + */ + +Lexer.rules = block; + +/** + * Static Lex Method + */ - tokens.links = {}; +Lexer.lex = function(src, options) { + var lexer = new Lexer(options); + return lexer.lex(src); +}; +/** + * Preprocessing + */ + +Lexer.prototype.lex = function(src) { src = src .replace(/\r\n|\r/g, '\n') - .replace(/\t/g, ' '); + .replace(/\t/g, ' ') + .replace(/\u00a0/g, ' ') + .replace(/\u2424/g, '\n'); - return block.token(src, tokens, true); + return this.token(src, true); }; -block.token = function(src, tokens, top) { +/** + * Lexing + */ + +Lexer.prototype.token = function(src, top, bq) { var src = src.replace(/^ +$/gm, '') , next , loose , cap + , bull + , b , item , space , i @@ -94,41 +161,43 @@ block.token = function(src, tokens, top) { while (src) { // newline - if (cap = block.newline.exec(src)) { + if (cap = this.rules.newline.exec(src)) { src = src.substring(cap[0].length); if (cap[0].length > 1) { - tokens.push({ + this.tokens.push({ type: 'space' }); } } // code - if (cap = block.code.exec(src)) { + if (cap = this.rules.code.exec(src)) { src = src.substring(cap[0].length); cap = cap[0].replace(/^ {4}/gm, ''); - tokens.push({ + this.tokens.push({ type: 'code', - text: cap.replace(/\n+$/, '') + text: !this.options.pedantic + ? cap.replace(/\n+$/, '') + : cap }); continue; } - // gfm_code - if (cap = block.gfm_code.exec(src)) { + // fences (gfm) + if (cap = this.rules.fences.exec(src)) { src = src.substring(cap[0].length); - tokens.push({ + this.tokens.push({ type: 'code', - lang: cap[1], - text: cap[2] + lang: cap[2], + text: cap[3] || '' }); continue; } // heading - if (cap = block.heading.exec(src)) { + if (cap = this.rules.heading.exec(src)) { src = src.substring(cap[0].length); - tokens.push({ + this.tokens.push({ type: 'heading', depth: cap[1].length, text: cap[2] @@ -136,10 +205,42 @@ block.token = function(src, tokens, top) { continue; } + // table no leading pipe (gfm) + if (top && (cap = this.rules.nptable.exec(src))) { + src = src.substring(cap[0].length); + + item = { + type: 'table', + header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */), + align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */), + cells: cap[3].replace(/\n$/, '').split('\n') + }; + + for (i = 0; i < item.align.length; i++) { + if (/^ *-+: *$/.test(item.align[i])) { + item.align[i] = 'right'; + } else if (/^ *:-+: *$/.test(item.align[i])) { + item.align[i] = 'center'; + } else if (/^ *:-+ *$/.test(item.align[i])) { + item.align[i] = 'left'; + } else { + item.align[i] = null; + } + } + + for (i = 0; i < item.cells.length; i++) { + item.cells[i] = item.cells[i].split(/ *\| */); + } + + this.tokens.push(item); + + continue; + } + // lheading - if (cap = block.lheading.exec(src)) { + if (cap = this.rules.lheading.exec(src)) { src = src.substring(cap[0].length); - tokens.push({ + this.tokens.push({ type: 'heading', depth: cap[2] === '=' ? 1 : 2, text: cap[1] @@ -148,18 +249,19 @@ block.token = function(src, tokens, top) { } // hr - if (cap = block.hr.exec(src)) { + if (cap = this.rules.hr.exec(src)) { src = src.substring(cap[0].length); - tokens.push({ + this.tokens.push({ type: 'hr' }); continue; } // blockquote - if (cap = block.blockquote.exec(src)) { + if (cap = this.rules.blockquote.exec(src)) { src = src.substring(cap[0].length); - tokens.push({ + + this.tokens.push({ type: 'blockquote_start' }); @@ -168,27 +270,27 @@ block.token = function(src, tokens, top) { // Pass `top` to keep the current // "toplevel" state. This is exactly // how markdown.pl works. - block.token(cap, tokens, top); + this.token(cap, top, true); - tokens.push({ + this.tokens.push({ type: 'blockquote_end' }); + continue; } // list - if (cap = block.list.exec(src)) { + if (cap = this.rules.list.exec(src)) { src = src.substring(cap[0].length); + bull = cap[2]; - tokens.push({ + this.tokens.push({ type: 'list_start', - ordered: isFinite(cap[2]) + ordered: bull.length > 1 }); // Get each top-level item. - cap = cap[0].match( - /^( *)([*+-]|\d+\.)[^\n]*(?:\n(?!\1(?:[*+-]|\d+\.))[^\n]*)*/gm - ); + cap = cap[0].match(this.rules.item); next = false; l = cap.length; @@ -200,13 +302,25 @@ block.token = function(src, tokens, top) { // Remove the list item's bullet // so it is seen as the next token. space = item.length; - item = item.replace(/^ *([*+-]|\d+\.) */, ''); + item = item.replace(/^ *([*+-]|\d+\.) +/, ''); // Outdent whatever the // list item contains. Hacky. if (~item.indexOf('\n ')) { space -= item.length; - item = item.replace(new RegExp('^ {1,' + space + '}', 'gm'), ''); + item = !this.options.pedantic + ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '') + : item.replace(/^ {1,4}/gm, ''); + } + + // Determine whether the next list item belongs here. + // Backpedal if it does not belong in this list. + if (this.options.smartLists && i !== l - 1) { + b = block.bullet.exec(cap[i + 1])[0]; + if (bull !== b && !(bull.length > 1 && b.length > 1)) { + src = cap.slice(i + 1).join('\n') + src; + i = l - 1; + } } // Determine whether item is loose or not. @@ -214,25 +328,25 @@ block.token = function(src, tokens, top) { // for discount behavior. loose = next || /\n\n(?!\s*$)/.test(item); if (i !== l - 1) { - next = item[item.length-1] === '\n'; + next = item.charAt(item.length - 1) === '\n'; if (!loose) loose = next; } - tokens.push({ + this.tokens.push({ type: loose ? 'loose_item_start' : 'list_item_start' }); // Recurse. - block.token(item, tokens); + this.token(item, false, bq); - tokens.push({ + this.tokens.push({ type: 'list_item_end' }); } - tokens.push({ + this.tokens.push({ type: 'list_end' }); @@ -240,76 +354,213 @@ block.token = function(src, tokens, top) { } // html - if (cap = block.html.exec(src)) { + if (cap = this.rules.html.exec(src)) { src = src.substring(cap[0].length); - tokens.push({ - type: 'html', + this.tokens.push({ + type: this.options.sanitize + ? 'paragraph' + : 'html', + pre: !this.options.sanitizer + && (cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style'), text: cap[0] }); continue; } // def - if (top && (cap = block.def.exec(src))) { + if ((!bq && top) && (cap = this.rules.def.exec(src))) { src = src.substring(cap[0].length); - tokens.links[cap[1].toLowerCase()] = { + this.tokens.links[cap[1].toLowerCase()] = { href: cap[2], title: cap[3] }; continue; } + // table (gfm) + if (top && (cap = this.rules.table.exec(src))) { + src = src.substring(cap[0].length); + + item = { + type: 'table', + header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */), + align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */), + cells: cap[3].replace(/(?: *\| *)?\n$/, '').split('\n') + }; + + for (i = 0; i < item.align.length; i++) { + if (/^ *-+: *$/.test(item.align[i])) { + item.align[i] = 'right'; + } else if (/^ *:-+: *$/.test(item.align[i])) { + item.align[i] = 'center'; + } else if (/^ *:-+ *$/.test(item.align[i])) { + item.align[i] = 'left'; + } else { + item.align[i] = null; + } + } + + for (i = 0; i < item.cells.length; i++) { + item.cells[i] = item.cells[i] + .replace(/^ *\| *| *\| *$/g, '') + .split(/ *\| */); + } + + this.tokens.push(item); + + continue; + } + // top-level paragraph - if (top && (cap = block.paragraph.exec(src))) { + if (top && (cap = this.rules.paragraph.exec(src))) { src = src.substring(cap[0].length); - tokens.push({ + this.tokens.push({ type: 'paragraph', - text: cap[0] + text: cap[1].charAt(cap[1].length - 1) === '\n' + ? cap[1].slice(0, -1) + : cap[1] }); continue; } // text - if (cap = block.text.exec(src)) { + if (cap = this.rules.text.exec(src)) { // Top-level should never reach here. src = src.substring(cap[0].length); - tokens.push({ + this.tokens.push({ type: 'text', text: cap[0] }); continue; } + + if (src) { + throw new + Error('Infinite loop on byte: ' + src.charCodeAt(0)); + } } - return tokens; + return this.tokens; }; /** - * Inline Processing + * Inline-Level Grammar */ var inline = { escape: /^\\([\\`*{}\[\]()#+\-.!_>])/, autolink: /^<([^ >]+(@|:\/)[^ >]+)>/, - gfm_autolink: /^(\w+:\/\/[^\s]+[^.,:;"')\]\s])/, - tag: /^|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/, - link: /^!?\[((?:\[[^\]]*\]|[^\[\]]|\[|\](?=[^[\]]*\]))*)\]\(([^\)]*)\)/, - reflink: /^!?\[((?:\[[^\]]*\]|[^\[\]]|\[|\](?=[^[\]]*\]))*)\]\s*\[([^\]]*)\]/, + url: noop, + tag: /^|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/, + link: /^!?\[(inside)\]\(href\)/, + reflink: /^!?\[(inside)\]\s*\[([^\]]*)\]/, nolink: /^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/, - strong: /^__([^\0]+?)__(?!_)|^\*\*([^\0]+?)\*\*(?!\*)/, - em: /^\b_([^\0]+?)_\b|^\*((?:\*\*|[^\0])+?)\*(?!\*)/, - code: /^(`+)([^\0]*?[^`])\1(?!`)/, + strong: /^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/, + em: /^\b_((?:[^_]|__)+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/, + code: /^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/, br: /^ {2,}\n(?!\s*$)/, - text: /^[^\0]+?(?=[\\?(?:\s+['"]([\s\S]*?)['"])?\s*/; + +inline.link = replace(inline.link) + ('inside', inline._inside) + ('href', inline._href) + (); + +inline.reflink = replace(inline.reflink) + ('inside', inline._inside) + (); + +/** + * Normal Inline Grammar + */ + +inline.normal = merge({}, inline); + +/** + * Pedantic Inline Grammar + */ + +inline.pedantic = merge({}, inline.normal, { + strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/, + em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/ +}); + +/** + * GFM Inline Grammar + */ + +inline.gfm = merge({}, inline.normal, { + escape: replace(inline.escape)('])', '~|])')(), + url: /^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/, + del: /^~~(?=\S)([\s\S]*?\S)~~/, + text: replace(inline.text) + (']|', '~]|') + ('|', '|https?://|') + () +}); + +/** + * GFM + Line Breaks Inline Grammar + */ + +inline.breaks = merge({}, inline.gfm, { + br: replace(inline.br)('{2,}', '*')(), + text: replace(inline.gfm.text)('{2,}', '*')() +}); + /** - * Inline Lexer + * Inline Lexer & Compiler */ -inline.lexer = function(src) { +function InlineLexer(links, options) { + this.options = options || marked.defaults; + this.links = links; + this.rules = inline.normal; + this.renderer = this.options.renderer || new Renderer; + this.renderer.options = this.options; + + if (!this.links) { + throw new + Error('Tokens array requires a `links` property.'); + } + + if (this.options.gfm) { + if (this.options.breaks) { + this.rules = inline.breaks; + } else { + this.rules = inline.gfm; + } + } else if (this.options.pedantic) { + this.rules = inline.pedantic; + } +} + +/** + * Expose Inline Rules + */ + +InlineLexer.rules = inline; + +/** + * Static Lexing/Compiling Method + */ + +InlineLexer.output = function(src, links, options) { + var inline = new InlineLexer(links, options); + return inline.output(src); +}; + +/** + * Lexing/Compiling + */ + +InlineLexer.prototype.output = function(src) { var out = '' - , links = tokens.links , link , text , href @@ -317,346 +568,718 @@ inline.lexer = function(src) { while (src) { // escape - if (cap = inline.escape.exec(src)) { + if (cap = this.rules.escape.exec(src)) { src = src.substring(cap[0].length); out += cap[1]; continue; } // autolink - if (cap = inline.autolink.exec(src)) { + if (cap = this.rules.autolink.exec(src)) { src = src.substring(cap[0].length); if (cap[2] === '@') { - text = cap[1][6] === ':' - ? mangle(cap[1].substring(7)) - : mangle(cap[1]); - href = mangle('mailto:') + text; + text = cap[1].charAt(6) === ':' + ? this.mangle(cap[1].substring(7)) + : this.mangle(cap[1]); + href = this.mangle('mailto:') + text; } else { text = escape(cap[1]); href = text; } - out += '' - + text - + ''; + out += this.renderer.link(href, null, text); continue; } - // gfm_autolink - if (cap = inline.gfm_autolink.exec(src)) { + // url (gfm) + if (!this.inLink && (cap = this.rules.url.exec(src))) { src = src.substring(cap[0].length); text = escape(cap[1]); href = text; - out += '' - + text - + ''; + out += this.renderer.link(href, null, text); continue; } // tag - if (cap = inline.tag.exec(src)) { + if (cap = this.rules.tag.exec(src)) { + if (!this.inLink && /^/i.test(cap[0])) { + this.inLink = false; + } src = src.substring(cap[0].length); - out += cap[0]; + out += this.options.sanitize + ? this.options.sanitizer + ? this.options.sanitizer(cap[0]) + : escape(cap[0]) + : cap[0] continue; } // link - if (cap = inline.link.exec(src)) { + if (cap = this.rules.link.exec(src)) { src = src.substring(cap[0].length); - text = /^\s*?(?:\s+"([^\n]+)")?\s*$/.exec(cap[2]); - if (!text) { - out += cap[0][0]; - src = cap[0].substring(1) + src; - continue; - } - out += outputLink(cap, { - href: text[1], - title: text[2] + this.inLink = true; + out += this.outputLink(cap, { + href: cap[2], + title: cap[3] }); + this.inLink = false; continue; } // reflink, nolink - if ((cap = inline.reflink.exec(src)) - || (cap = inline.nolink.exec(src))) { + if ((cap = this.rules.reflink.exec(src)) + || (cap = this.rules.nolink.exec(src))) { src = src.substring(cap[0].length); link = (cap[2] || cap[1]).replace(/\s+/g, ' '); - link = links[link.toLowerCase()]; + link = this.links[link.toLowerCase()]; if (!link || !link.href) { - out += cap[0][0]; + out += cap[0].charAt(0); src = cap[0].substring(1) + src; continue; } - out += outputLink(cap, link); + this.inLink = true; + out += this.outputLink(cap, link); + this.inLink = false; continue; } // strong - if (cap = inline.strong.exec(src)) { + if (cap = this.rules.strong.exec(src)) { src = src.substring(cap[0].length); - out += '' - + inline.lexer(cap[2] || cap[1]) - + ''; + out += this.renderer.strong(this.output(cap[2] || cap[1])); continue; } // em - if (cap = inline.em.exec(src)) { + if (cap = this.rules.em.exec(src)) { src = src.substring(cap[0].length); - out += '' - + inline.lexer(cap[2] || cap[1]) - + ''; + out += this.renderer.em(this.output(cap[2] || cap[1])); continue; } // code - if (cap = inline.code.exec(src)) { + if (cap = this.rules.code.exec(src)) { src = src.substring(cap[0].length); - out += '' - + escape(cap[2], true) - + ''; + out += this.renderer.codespan(escape(cap[2], true)); continue; } // br - if (cap = inline.br.exec(src)) { + if (cap = this.rules.br.exec(src)) { + src = src.substring(cap[0].length); + out += this.renderer.br(); + continue; + } + + // del (gfm) + if (cap = this.rules.del.exec(src)) { src = src.substring(cap[0].length); - out += '
      '; + out += this.renderer.del(this.output(cap[1])); continue; } // text - if (cap = inline.text.exec(src)) { + if (cap = this.rules.text.exec(src)) { src = src.substring(cap[0].length); - out += escape(cap[0]); + out += this.renderer.text(escape(this.smartypants(cap[0]))); continue; } + + if (src) { + throw new + Error('Infinite loop on byte: ' + src.charCodeAt(0)); + } + } + + return out; +}; + +/** + * Compile Link + */ + +InlineLexer.prototype.outputLink = function(cap, link) { + var href = escape(link.href) + , title = link.title ? escape(link.title) : null; + + return cap[0].charAt(0) !== '!' + ? this.renderer.link(href, title, this.output(cap[1])) + : this.renderer.image(href, title, escape(cap[1])); +}; + +/** + * Smartypants Transformations + */ + +InlineLexer.prototype.smartypants = function(text) { + if (!this.options.smartypants) return text; + return text + // em-dashes + .replace(/---/g, '\u2014') + // en-dashes + .replace(/--/g, '\u2013') + // opening singles + .replace(/(^|[-\u2014/(\[{"\s])'/g, '$1\u2018') + // closing singles & apostrophes + .replace(/'/g, '\u2019') + // opening doubles + .replace(/(^|[-\u2014/(\[{\u2018\s])"/g, '$1\u201c') + // closing doubles + .replace(/"/g, '\u201d') + // ellipses + .replace(/\.{3}/g, '\u2026'); +}; + +/** + * Mangle Links + */ + +InlineLexer.prototype.mangle = function(text) { + if (!this.options.mangle) return text; + var out = '' + , l = text.length + , i = 0 + , ch; + + for (; i < l; i++) { + ch = text.charCodeAt(i); + if (Math.random() > 0.5) { + ch = 'x' + ch.toString(16); + } + out += '&#' + ch + ';'; + } + + return out; +}; + +/** + * Renderer + */ + +function Renderer(options) { + this.options = options || {}; +} + +Renderer.prototype.code = function(code, lang, escaped) { + if (this.options.highlight) { + var out = this.options.highlight(code, lang); + if (out != null && out !== code) { + escaped = true; + code = out; + } + } + + if (!lang) { + return '
      '
      +      + (escaped ? code : escape(code, true))
      +      + '\n
      '; + } + + return '
      '
      +    + (escaped ? code : escape(code, true))
      +    + '\n
      \n'; +}; + +Renderer.prototype.blockquote = function(quote) { + return '
      \n' + quote + '
      \n'; +}; + +Renderer.prototype.html = function(html) { + return html; +}; + +Renderer.prototype.heading = function(text, level, raw) { + return '' + + text + + '\n'; +}; + +Renderer.prototype.hr = function() { + return this.options.xhtml ? '
      \n' : '
      \n'; +}; + +Renderer.prototype.list = function(body, ordered) { + var type = ordered ? 'ol' : 'ul'; + return '<' + type + '>\n' + body + '\n'; +}; + +Renderer.prototype.listitem = function(text) { + return '
    6. ' + text + '
    7. \n'; +}; + +Renderer.prototype.paragraph = function(text) { + return '

      ' + text + '

      \n'; +}; + +Renderer.prototype.table = function(header, body) { + return '\n' + + '\n' + + header + + '\n' + + '\n' + + body + + '\n' + + '
      \n'; +}; + +Renderer.prototype.tablerow = function(content) { + return '\n' + content + '\n'; +}; + +Renderer.prototype.tablecell = function(content, flags) { + var type = flags.header ? 'th' : 'td'; + var tag = flags.align + ? '<' + type + ' style="text-align:' + flags.align + '">' + : '<' + type + '>'; + return tag + content + '\n'; +}; + +// span level renderer +Renderer.prototype.strong = function(text) { + return '' + text + ''; +}; + +Renderer.prototype.em = function(text) { + return '' + text + ''; +}; + +Renderer.prototype.codespan = function(text) { + return '' + text + ''; +}; + +Renderer.prototype.br = function() { + return this.options.xhtml ? '
      ' : '
      '; +}; + +Renderer.prototype.del = function(text) { + return '' + text + ''; +}; + +Renderer.prototype.link = function(href, title, text) { + if (this.options.sanitize) { + try { + var prot = decodeURIComponent(unescape(href)) + .replace(/[^\w:]/g, '') + .toLowerCase(); + } catch (e) { + return ''; + } + if (prot.indexOf('javascript:') === 0 || prot.indexOf('vbscript:') === 0) { + return ''; + } + } + var out = '
      '; + return out; +}; +Renderer.prototype.image = function(href, title, text) { + var out = '' + text + '' : '>'; return out; }; -var outputLink = function(cap, link) { - if (cap[0][0] !== '!') { - return '' - + inline.lexer(cap[1]) - + ''; - } else { - return ''
-      + escape(cap[1])
-      + ''; +Renderer.prototype.text = function(text) { + return text; +}; + +/** + * Parsing & Compiling + */ + +function Parser(options) { + this.tokens = []; + this.token = null; + this.options = options || marked.defaults; + this.options.renderer = this.options.renderer || new Renderer; + this.renderer = this.options.renderer; + this.renderer.options = this.options; +} + +/** + * Static Parse Method + */ + +Parser.parse = function(src, options, renderer) { + var parser = new Parser(options, renderer); + return parser.parse(src); +}; + +/** + * Parse Loop + */ + +Parser.prototype.parse = function(src) { + this.inline = new InlineLexer(src.links, this.options, this.renderer); + this.tokens = src.reverse(); + + var out = ''; + while (this.next()) { + out += this.tok(); } + + return out; }; /** - * Parsing + * Next Token */ -var tokens - , token; +Parser.prototype.next = function() { + return this.token = this.tokens.pop(); +}; + +/** + * Preview Next Token + */ -var next = function() { - return token = tokens.pop(); +Parser.prototype.peek = function() { + return this.tokens[this.tokens.length - 1] || 0; }; -var tok = function() { - switch (token.type) { +/** + * Parse Text Tokens + */ + +Parser.prototype.parseText = function() { + var body = this.token.text; + + while (this.peek().type === 'text') { + body += '\n' + this.next().text; + } + + return this.inline.output(body); +}; + +/** + * Parse Current Token + */ + +Parser.prototype.tok = function() { + switch (this.token.type) { case 'space': { return ''; } case 'hr': { - return '
      \n'; + return this.renderer.hr(); } case 'heading': { - return '' - + inline.lexer(token.text) - + '\n'; + return this.renderer.heading( + this.inline.output(this.token.text), + this.token.depth, + this.token.text); } case 'code': { - return '
      '
      -        + (token.escaped
      -        ? token.text
      -        : escape(token.text, true))
      -        + '
      \n'; + return this.renderer.code(this.token.text, + this.token.lang, + this.token.escaped); + } + case 'table': { + var header = '' + , body = '' + , i + , row + , cell + , flags + , j; + + // header + cell = ''; + for (i = 0; i < this.token.header.length; i++) { + flags = { header: true, align: this.token.align[i] }; + cell += this.renderer.tablecell( + this.inline.output(this.token.header[i]), + { header: true, align: this.token.align[i] } + ); + } + header += this.renderer.tablerow(cell); + + for (i = 0; i < this.token.cells.length; i++) { + row = this.token.cells[i]; + + cell = ''; + for (j = 0; j < row.length; j++) { + cell += this.renderer.tablecell( + this.inline.output(row[j]), + { header: false, align: this.token.align[j] } + ); + } + + body += this.renderer.tablerow(cell); + } + return this.renderer.table(header, body); } case 'blockquote_start': { var body = ''; - while (next().type !== 'blockquote_end') { - body += tok(); + while (this.next().type !== 'blockquote_end') { + body += this.tok(); } - return '
      \n' - + body - + '
      \n'; + return this.renderer.blockquote(body); } case 'list_start': { - var type = token.ordered ? 'ol' : 'ul' - , body = ''; + var body = '' + , ordered = this.token.ordered; - while (next().type !== 'list_end') { - body += tok(); + while (this.next().type !== 'list_end') { + body += this.tok(); } - return '<' - + type - + '>\n' - + body - + '\n'; + return this.renderer.list(body, ordered); } case 'list_item_start': { var body = ''; - while (next().type !== 'list_item_end') { - body += token.type === 'text' - ? parseText() - : tok(); + while (this.next().type !== 'list_item_end') { + body += this.token.type === 'text' + ? this.parseText() + : this.tok(); } - return '
    8. ' - + body - + '
    9. \n'; + return this.renderer.listitem(body); } case 'loose_item_start': { var body = ''; - while (next().type !== 'list_item_end') { - body += tok(); + while (this.next().type !== 'list_item_end') { + body += this.tok(); } - return '
    10. ' - + body - + '
    11. \n'; + return this.renderer.listitem(body); } case 'html': { - return inline.lexer(token.text); + var html = !this.token.pre && !this.options.pedantic + ? this.inline.output(this.token.text) + : this.token.text; + return this.renderer.html(html); } case 'paragraph': { - return '

      ' - + inline.lexer(token.text) - + '

      \n'; + return this.renderer.paragraph(this.inline.output(this.token.text)); } case 'text': { - return '

      ' - + parseText() - + '

      \n'; + return this.renderer.paragraph(this.parseText()); } } }; -var parseText = function() { - var body = token.text - , top; - - while ((top = tokens[tokens.length-1]) - && top.type === 'text') { - body += '\n' + next().text; - } - - return inline.lexer(body); -}; - -var parse = function(src) { - tokens = src.reverse(); - - var out = ''; - while (next()) { - out += tok(); - } - - tokens = null; - token = null; - - return out; -}; - /** * Helpers */ -var escape = function(html, encode) { +function escape(html, encode) { return html .replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&') .replace(//g, '>') .replace(/"/g, '"') .replace(/'/g, '''); -}; +} -var mangle = function(text) { - var out = '' - , l = text.length - , i = 0 - , ch; +function unescape(html) { + return html.replace(/&([#\w]+);/g, function(_, n) { + n = n.toLowerCase(); + if (n === 'colon') return ':'; + if (n.charAt(0) === '#') { + return n.charAt(1) === 'x' + ? String.fromCharCode(parseInt(n.substring(2), 16)) + : String.fromCharCode(+n.substring(1)); + } + return ''; + }); +} - for (; i < l; i++) { - ch = text.charCodeAt(i); - if (Math.random() > 0.5) { - ch = 'x' + ch.toString(16); +function replace(regex, opt) { + regex = regex.source; + opt = opt || ''; + return function self(name, val) { + if (!name) return new RegExp(regex, opt); + val = val.source || val; + val = val.replace(/(^|[^\[])\^/g, '$1'); + regex = regex.replace(name, val); + return self; + }; +} + +function noop() {} +noop.exec = noop; + +function merge(obj) { + var i = 1 + , target + , key; + + for (; i < arguments.length; i++) { + target = arguments[i]; + for (key in target) { + if (Object.prototype.hasOwnProperty.call(target, key)) { + obj[key] = target[key]; + } } - out += '&#' + ch + ';'; } - return out; -}; + return obj; +} -function tag() { - var tag = '(?!(?:' - + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code' - + '|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo' - + '|span|br|wbr|ins|del|img)\\b)\\w+'; - return tag; +/** + * Marked + */ + +function marked(src, opt, callback) { + if (callback || typeof opt === 'function') { + if (!callback) { + callback = opt; + opt = null; + } + + opt = merge({}, marked.defaults, opt || {}); + + var highlight = opt.highlight + , tokens + , pending + , i = 0; + + try { + tokens = Lexer.lex(src, opt) + } catch (e) { + return callback(e); + } + + pending = tokens.length; + + var done = function(err) { + if (err) { + opt.highlight = highlight; + return callback(err); + } + + var out; + + try { + out = Parser.parse(tokens, opt); + } catch (e) { + err = e; + } + + opt.highlight = highlight; + + return err + ? callback(err) + : callback(null, out); + }; + + if (!highlight || highlight.length < 3) { + return done(); + } + + delete opt.highlight; + + if (!pending) return done(); + + for (; i < tokens.length; i++) { + (function(token) { + if (token.type !== 'code') { + return --pending || done(); + } + return highlight(token.text, token.lang, function(err, code) { + if (err) return done(err); + if (code == null || code === token.text) { + return --pending || done(); + } + token.text = code; + token.escaped = true; + --pending || done(); + }); + })(tokens[i]); + } + + return; + } + try { + if (opt) opt = merge({}, marked.defaults, opt); + return Parser.parse(Lexer.lex(src, opt), opt); + } catch (e) { + e.message += '\nPlease report this to https://github.com/chjj/marked.'; + if ((opt || marked.defaults).silent) { + return '

      An error occured:

      '
      +        + escape(e.message + '', true)
      +        + '
      '; + } + throw e; + } } /** - * Expose + * Options */ -var marked = function(src) { - return parse(block.lexer(src)); +marked.options = +marked.setOptions = function(opt) { + merge(marked.defaults, opt); + return marked; }; -marked.parser = parse; -marked.lexer = block.lexer; +marked.defaults = { + gfm: true, + tables: true, + breaks: false, + pedantic: false, + sanitize: false, + sanitizer: null, + mangle: true, + smartLists: false, + silent: false, + highlight: null, + langPrefix: 'lang-', + smartypants: false, + headerPrefix: '', + renderer: new Renderer, + xhtml: false +}; + +/** + * Expose + */ + +marked.Parser = Parser; +marked.parser = Parser.parse; + +marked.Renderer = Renderer; + +marked.Lexer = Lexer; +marked.lexer = Lexer.lex; + +marked.InlineLexer = InlineLexer; +marked.inlineLexer = InlineLexer.output; marked.parse = marked; -if (typeof module !== 'undefined') { +if (typeof module !== 'undefined' && typeof exports === 'object') { module.exports = marked; +} else if (typeof define === 'function' && define.amd) { + define(function() { return marked; }); } else { this.marked = marked; } -}).call(this); +}).call(function() { + return this || (typeof window !== 'undefined' ? window : global); +}()); diff --git a/tools/doc/node_modules/marked/man/marked.1 b/tools/doc/node_modules/marked/man/marked.1 index 214533390ce41a..b9bdc8c2123e3b 100644 --- a/tools/doc/node_modules/marked/man/marked.1 +++ b/tools/doc/node_modules/marked/man/marked.1 @@ -1,39 +1,91 @@ .ds q \N'34' -.TH marked 1 +.TH marked 1 "2014-01-31" "v0.3.1" "marked.js" + .SH NAME marked \- a javascript markdown parser + .SH SYNOPSIS -.nf -.B marked [\-o output] [\-i input] [\-th] -.fi +.B marked +[\-o \fI\fP] [\-i \fI\fP] [\-\-help] +[\-\-tokens] [\-\-pedantic] [\-\-gfm] +[\-\-breaks] [\-\-tables] [\-\-sanitize] +[\-\-smart\-lists] [\-\-lang\-prefix \fI\fP] +[\-\-no\-etc...] [\-\-silent] [\fIfilename\fP] + .SH DESCRIPTION .B marked is a full-featured javascript markdown parser, built for speed. It also includes multiple GFM features. + +.SH EXAMPLES +.TP +cat in.md | marked > out.html +.TP +echo "hello *world*" | marked +.TP +marked \-o out.html in.md \-\-gfm +.TP +marked \-\-output="hello world.html" \-i in.md \-\-no-breaks + .SH OPTIONS .TP -.BI \-o,\ \-\-output\ [output] +.BI \-o,\ \-\-output\ [\fIoutput\fP] Specify file output. If none is specified, write to stdout. .TP -.BI \-i,\ \-\-input\ [input] +.BI \-i,\ \-\-input\ [\fIinput\fP] Specify file input, otherwise use last argument as input file. If no input file is specified, read from stdin. .TP .BI \-t,\ \-\-tokens Output a token stream instead of html. .TP -.BI \-h,\ \-\-help -Display help information. -.SH EXAMPLES +.BI \-\-pedantic +Conform to obscure parts of markdown.pl as much as possible. Don't fix original +markdown bugs. .TP -cat in.md | marked > out.html +.BI \-\-gfm +Enable github flavored markdown. .TP -echo "hello *world*" | marked +.BI \-\-breaks +Enable GFM line breaks. Only works with the gfm option. +.TP +.BI \-\-tables +Enable GFM tables. Only works with the gfm option. +.TP +.BI \-\-sanitize +Sanitize output. Ignore any HTML input. +.TP +.BI \-\-smart\-lists +Use smarter list behavior than the original markdown. .TP -marked -o out.html in.md +.BI \-\-lang\-prefix\ [\fIprefix\fP] +Set the prefix for code block classes. .TP -marked --output="hello world.html" -i in.md +.BI \-\-mangle +Mangle email addresses. +.TP +.BI \-\-no\-sanitize,\ \-no-etc... +The inverse of any of the marked options above. +.TP +.BI \-\-silent +Silence error output. +.TP +.BI \-h,\ \-\-help +Display help information. + +.SH CONFIGURATION +For configuring and running programmatically. + +.B Example + + require('marked')('*foo*', { gfm: true }); + .SH BUGS Please report any bugs to https://github.com/chjj/marked. + .SH LICENSE -Copyright (c) 2011-2012, Christopher Jeffrey (MIT License) +Copyright (c) 2011-2014, Christopher Jeffrey (MIT License). + +.SH "SEE ALSO" +.BR markdown(1), +.BR node.js(1) diff --git a/tools/doc/node_modules/marked/marked.min.js b/tools/doc/node_modules/marked/marked.min.js new file mode 100644 index 00000000000000..555c1dc1d9da18 --- /dev/null +++ b/tools/doc/node_modules/marked/marked.min.js @@ -0,0 +1,6 @@ +/** + * marked - a markdown parser + * Copyright (c) 2011-2014, Christopher Jeffrey. (MIT Licensed) + * https://github.com/chjj/marked + */ +(function(){var block={newline:/^\n+/,code:/^( {4}[^\n]+\n*)+/,fences:noop,hr:/^( *[-*_]){3,} *(?:\n+|$)/,heading:/^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,nptable:noop,lheading:/^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,blockquote:/^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/,list:/^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,html:/^ *(?:comment *(?:\n|\s*$)|closed *(?:\n{2,}|\s*$)|closing *(?:\n{2,}|\s*$))/,def:/^ *\[([^\]]+)\]: *]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,table:noop,paragraph:/^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,text:/^[^\n]+/};block.bullet=/(?:[*+-]|\d+\.)/;block.item=/^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;block.item=replace(block.item,"gm")(/bull/g,block.bullet)();block.list=replace(block.list)(/bull/g,block.bullet)("hr","\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))")("def","\\n+(?="+block.def.source+")")();block.blockquote=replace(block.blockquote)("def",block.def)();block._tag="(?!(?:"+"a|em|strong|small|s|cite|q|dfn|abbr|data|time|code"+"|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo"+"|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b";block.html=replace(block.html)("comment",//)("closed",/<(tag)[\s\S]+?<\/\1>/)("closing",/])*?>/)(/tag/g,block._tag)();block.paragraph=replace(block.paragraph)("hr",block.hr)("heading",block.heading)("lheading",block.lheading)("blockquote",block.blockquote)("tag","<"+block._tag)("def",block.def)();block.normal=merge({},block);block.gfm=merge({},block.normal,{fences:/^ *(`{3,}|~{3,})[ \.]*(\S+)? *\n([\s\S]*?)\s*\1 *(?:\n+|$)/,paragraph:/^/,heading:/^ *(#{1,6}) +([^\n]+?) *#* *(?:\n+|$)/});block.gfm.paragraph=replace(block.paragraph)("(?!","(?!"+block.gfm.fences.source.replace("\\1","\\2")+"|"+block.list.source.replace("\\1","\\3")+"|")();block.tables=merge({},block.gfm,{nptable:/^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,table:/^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/});function Lexer(options){this.tokens=[];this.tokens.links={};this.options=options||marked.defaults;this.rules=block.normal;if(this.options.gfm){if(this.options.tables){this.rules=block.tables}else{this.rules=block.gfm}}}Lexer.rules=block;Lexer.lex=function(src,options){var lexer=new Lexer(options);return lexer.lex(src)};Lexer.prototype.lex=function(src){src=src.replace(/\r\n|\r/g,"\n").replace(/\t/g," ").replace(/\u00a0/g," ").replace(/\u2424/g,"\n");return this.token(src,true)};Lexer.prototype.token=function(src,top,bq){var src=src.replace(/^ +$/gm,""),next,loose,cap,bull,b,item,space,i,l;while(src){if(cap=this.rules.newline.exec(src)){src=src.substring(cap[0].length);if(cap[0].length>1){this.tokens.push({type:"space"})}}if(cap=this.rules.code.exec(src)){src=src.substring(cap[0].length);cap=cap[0].replace(/^ {4}/gm,"");this.tokens.push({type:"code",text:!this.options.pedantic?cap.replace(/\n+$/,""):cap});continue}if(cap=this.rules.fences.exec(src)){src=src.substring(cap[0].length);this.tokens.push({type:"code",lang:cap[2],text:cap[3]||""});continue}if(cap=this.rules.heading.exec(src)){src=src.substring(cap[0].length);this.tokens.push({type:"heading",depth:cap[1].length,text:cap[2]});continue}if(top&&(cap=this.rules.nptable.exec(src))){src=src.substring(cap[0].length);item={type:"table",header:cap[1].replace(/^ *| *\| *$/g,"").split(/ *\| */),align:cap[2].replace(/^ *|\| *$/g,"").split(/ *\| */),cells:cap[3].replace(/\n$/,"").split("\n")};for(i=0;i ?/gm,"");this.token(cap,top,true);this.tokens.push({type:"blockquote_end"});continue}if(cap=this.rules.list.exec(src)){src=src.substring(cap[0].length);bull=cap[2];this.tokens.push({type:"list_start",ordered:bull.length>1});cap=cap[0].match(this.rules.item);next=false;l=cap.length;i=0;for(;i1&&b.length>1)){src=cap.slice(i+1).join("\n")+src;i=l-1}}loose=next||/\n\n(?!\s*$)/.test(item);if(i!==l-1){next=item.charAt(item.length-1)==="\n";if(!loose)loose=next}this.tokens.push({type:loose?"loose_item_start":"list_item_start"});this.token(item,false,bq);this.tokens.push({type:"list_item_end"})}this.tokens.push({type:"list_end"});continue}if(cap=this.rules.html.exec(src)){src=src.substring(cap[0].length);this.tokens.push({type:this.options.sanitize?"paragraph":"html",pre:!this.options.sanitizer&&(cap[1]==="pre"||cap[1]==="script"||cap[1]==="style"),text:cap[0]});continue}if(!bq&&top&&(cap=this.rules.def.exec(src))){src=src.substring(cap[0].length);this.tokens.links[cap[1].toLowerCase()]={href:cap[2],title:cap[3]};continue}if(top&&(cap=this.rules.table.exec(src))){src=src.substring(cap[0].length);item={type:"table",header:cap[1].replace(/^ *| *\| *$/g,"").split(/ *\| */),align:cap[2].replace(/^ *|\| *$/g,"").split(/ *\| */),cells:cap[3].replace(/(?: *\| *)?\n$/,"").split("\n")};for(i=0;i])/,autolink:/^<([^ >]+(@|:\/)[^ >]+)>/,url:noop,tag:/^|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,link:/^!?\[(inside)\]\(href\)/,reflink:/^!?\[(inside)\]\s*\[([^\]]*)\]/,nolink:/^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,strong:/^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,em:/^\b_((?:[^_]|__)+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,code:/^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,br:/^ {2,}\n(?!\s*$)/,del:noop,text:/^[\s\S]+?(?=[\\?(?:\s+['"]([\s\S]*?)['"])?\s*/;inline.link=replace(inline.link)("inside",inline._inside)("href",inline._href)();inline.reflink=replace(inline.reflink)("inside",inline._inside)();inline.normal=merge({},inline);inline.pedantic=merge({},inline.normal,{strong:/^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,em:/^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/});inline.gfm=merge({},inline.normal,{escape:replace(inline.escape)("])","~|])")(),url:/^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,del:/^~~(?=\S)([\s\S]*?\S)~~/,text:replace(inline.text)("]|","~]|")("|","|https?://|")()});inline.breaks=merge({},inline.gfm,{br:replace(inline.br)("{2,}","*")(),text:replace(inline.gfm.text)("{2,}","*")()});function InlineLexer(links,options){this.options=options||marked.defaults;this.links=links;this.rules=inline.normal;this.renderer=this.options.renderer||new Renderer;this.renderer.options=this.options;if(!this.links){throw new Error("Tokens array requires a `links` property.")}if(this.options.gfm){if(this.options.breaks){this.rules=inline.breaks}else{this.rules=inline.gfm}}else if(this.options.pedantic){this.rules=inline.pedantic}}InlineLexer.rules=inline;InlineLexer.output=function(src,links,options){var inline=new InlineLexer(links,options);return inline.output(src)};InlineLexer.prototype.output=function(src){var out="",link,text,href,cap;while(src){if(cap=this.rules.escape.exec(src)){src=src.substring(cap[0].length);out+=cap[1];continue}if(cap=this.rules.autolink.exec(src)){src=src.substring(cap[0].length);if(cap[2]==="@"){text=cap[1].charAt(6)===":"?this.mangle(cap[1].substring(7)):this.mangle(cap[1]);href=this.mangle("mailto:")+text}else{text=escape(cap[1]);href=text}out+=this.renderer.link(href,null,text);continue}if(!this.inLink&&(cap=this.rules.url.exec(src))){src=src.substring(cap[0].length);text=escape(cap[1]);href=text;out+=this.renderer.link(href,null,text);continue}if(cap=this.rules.tag.exec(src)){if(!this.inLink&&/^/i.test(cap[0])){this.inLink=false}src=src.substring(cap[0].length);out+=this.options.sanitize?this.options.sanitizer?this.options.sanitizer(cap[0]):escape(cap[0]):cap[0];continue}if(cap=this.rules.link.exec(src)){src=src.substring(cap[0].length);this.inLink=true;out+=this.outputLink(cap,{href:cap[2],title:cap[3]});this.inLink=false;continue}if((cap=this.rules.reflink.exec(src))||(cap=this.rules.nolink.exec(src))){src=src.substring(cap[0].length);link=(cap[2]||cap[1]).replace(/\s+/g," ");link=this.links[link.toLowerCase()];if(!link||!link.href){out+=cap[0].charAt(0);src=cap[0].substring(1)+src;continue}this.inLink=true;out+=this.outputLink(cap,link);this.inLink=false;continue}if(cap=this.rules.strong.exec(src)){src=src.substring(cap[0].length);out+=this.renderer.strong(this.output(cap[2]||cap[1]));continue}if(cap=this.rules.em.exec(src)){src=src.substring(cap[0].length);out+=this.renderer.em(this.output(cap[2]||cap[1]));continue}if(cap=this.rules.code.exec(src)){src=src.substring(cap[0].length);out+=this.renderer.codespan(escape(cap[2],true));continue}if(cap=this.rules.br.exec(src)){src=src.substring(cap[0].length);out+=this.renderer.br();continue}if(cap=this.rules.del.exec(src)){src=src.substring(cap[0].length);out+=this.renderer.del(this.output(cap[1]));continue}if(cap=this.rules.text.exec(src)){src=src.substring(cap[0].length);out+=this.renderer.text(escape(this.smartypants(cap[0])));continue}if(src){throw new Error("Infinite loop on byte: "+src.charCodeAt(0))}}return out};InlineLexer.prototype.outputLink=function(cap,link){var href=escape(link.href),title=link.title?escape(link.title):null;return cap[0].charAt(0)!=="!"?this.renderer.link(href,title,this.output(cap[1])):this.renderer.image(href,title,escape(cap[1]))};InlineLexer.prototype.smartypants=function(text){if(!this.options.smartypants)return text;return text.replace(/---/g,"—").replace(/--/g,"–").replace(/(^|[-\u2014/(\[{"\s])'/g,"$1‘").replace(/'/g,"’").replace(/(^|[-\u2014/(\[{\u2018\s])"/g,"$1“").replace(/"/g,"”").replace(/\.{3}/g,"…")};InlineLexer.prototype.mangle=function(text){if(!this.options.mangle)return text;var out="",l=text.length,i=0,ch;for(;i.5){ch="x"+ch.toString(16)}out+="&#"+ch+";"}return out};function Renderer(options){this.options=options||{}}Renderer.prototype.code=function(code,lang,escaped){if(this.options.highlight){var out=this.options.highlight(code,lang);if(out!=null&&out!==code){escaped=true;code=out}}if(!lang){return"
      "+(escaped?code:escape(code,true))+"\n
      "}return'
      '+(escaped?code:escape(code,true))+"\n
      \n"};Renderer.prototype.blockquote=function(quote){return"
      \n"+quote+"
      \n"};Renderer.prototype.html=function(html){return html};Renderer.prototype.heading=function(text,level,raw){return"'+text+"\n"};Renderer.prototype.hr=function(){return this.options.xhtml?"
      \n":"
      \n"};Renderer.prototype.list=function(body,ordered){var type=ordered?"ol":"ul";return"<"+type+">\n"+body+"\n"};Renderer.prototype.listitem=function(text){return"
    12. "+text+"
    13. \n"};Renderer.prototype.paragraph=function(text){return"

      "+text+"

      \n"};Renderer.prototype.table=function(header,body){return"\n"+"\n"+header+"\n"+"\n"+body+"\n"+"
      \n"};Renderer.prototype.tablerow=function(content){return"\n"+content+"\n"};Renderer.prototype.tablecell=function(content,flags){var type=flags.header?"th":"td";var tag=flags.align?"<"+type+' style="text-align:'+flags.align+'">':"<"+type+">";return tag+content+"\n"};Renderer.prototype.strong=function(text){return""+text+""};Renderer.prototype.em=function(text){return""+text+""};Renderer.prototype.codespan=function(text){return""+text+""};Renderer.prototype.br=function(){return this.options.xhtml?"
      ":"
      "};Renderer.prototype.del=function(text){return""+text+""};Renderer.prototype.link=function(href,title,text){if(this.options.sanitize){try{var prot=decodeURIComponent(unescape(href)).replace(/[^\w:]/g,"").toLowerCase()}catch(e){return""}if(prot.indexOf("javascript:")===0||prot.indexOf("vbscript:")===0){return""}}var out='
      ";return out};Renderer.prototype.image=function(href,title,text){var out=''+text+'":">";return out};Renderer.prototype.text=function(text){return text};function Parser(options){this.tokens=[];this.token=null;this.options=options||marked.defaults;this.options.renderer=this.options.renderer||new Renderer;this.renderer=this.options.renderer;this.renderer.options=this.options}Parser.parse=function(src,options,renderer){var parser=new Parser(options,renderer);return parser.parse(src)};Parser.prototype.parse=function(src){this.inline=new InlineLexer(src.links,this.options,this.renderer);this.tokens=src.reverse();var out="";while(this.next()){out+=this.tok()}return out};Parser.prototype.next=function(){return this.token=this.tokens.pop()};Parser.prototype.peek=function(){return this.tokens[this.tokens.length-1]||0};Parser.prototype.parseText=function(){var body=this.token.text;while(this.peek().type==="text"){body+="\n"+this.next().text}return this.inline.output(body)};Parser.prototype.tok=function(){switch(this.token.type){case"space":{return""}case"hr":{return this.renderer.hr()}case"heading":{return this.renderer.heading(this.inline.output(this.token.text),this.token.depth,this.token.text)}case"code":{return this.renderer.code(this.token.text,this.token.lang,this.token.escaped)}case"table":{var header="",body="",i,row,cell,flags,j;cell="";for(i=0;i/g,">").replace(/"/g,""").replace(/'/g,"'")}function unescape(html){return html.replace(/&([#\w]+);/g,function(_,n){n=n.toLowerCase();if(n==="colon")return":";if(n.charAt(0)==="#"){return n.charAt(1)==="x"?String.fromCharCode(parseInt(n.substring(2),16)):String.fromCharCode(+n.substring(1))}return""})}function replace(regex,opt){regex=regex.source;opt=opt||"";return function self(name,val){if(!name)return new RegExp(regex,opt);val=val.source||val;val=val.replace(/(^|[^\[])\^/g,"$1");regex=regex.replace(name,val);return self}}function noop(){}noop.exec=noop;function merge(obj){var i=1,target,key;for(;iAn error occured:

      "+escape(e.message+"",true)+"
      "}throw e}}marked.options=marked.setOptions=function(opt){merge(marked.defaults,opt);return marked};marked.defaults={gfm:true,tables:true,breaks:false,pedantic:false,sanitize:false,sanitizer:null,mangle:true,smartLists:false,silent:false,highlight:null,langPrefix:"lang-",smartypants:false,headerPrefix:"",renderer:new Renderer,xhtml:false};marked.Parser=Parser;marked.parser=Parser.parse;marked.Renderer=Renderer;marked.Lexer=Lexer;marked.lexer=Lexer.lex;marked.InlineLexer=InlineLexer;marked.inlineLexer=InlineLexer.output;marked.parse=marked;if(typeof module!=="undefined"&&typeof exports==="object"){module.exports=marked}else if(typeof define==="function"&&define.amd){define(function(){return marked})}else{this.marked=marked}}).call(function(){return this||(typeof window!=="undefined"?window:global)}()); \ No newline at end of file diff --git a/tools/doc/node_modules/marked/package.json b/tools/doc/node_modules/marked/package.json index f47a9e12530731..d631092cb80f42 100644 --- a/tools/doc/node_modules/marked/package.json +++ b/tools/doc/node_modules/marked/package.json @@ -1,15 +1,95 @@ { - "name": "marked", + "_args": [ + [ + "marked", + "/Users/firedfox/git/node/tools/doc" + ] + ], + "_from": "marked@latest", + "_id": "marked@0.3.5", + "_inCache": true, + "_installable": true, + "_location": "/marked", + "_nodeVersion": "0.12.7", + "_npmUser": { + "email": "chjjeffrey@gmail.com", + "name": "chjj" + }, + "_npmVersion": "2.13.2", + "_phantomChildren": {}, + "_requested": { + "name": "marked", + "raw": "marked", + "rawSpec": "", + "scope": null, + "spec": "latest", + "type": "tag" + }, + "_requiredBy": [ + "/" + ], + "_resolved": "https://registry.npmjs.org/marked/-/marked-0.3.5.tgz", + "_shasum": "4113a15ac5d7bca158a5aae07224587b9fa15b94", + "_shrinkwrap": null, + "_spec": "marked", + "_where": "/Users/firedfox/git/node/tools/doc", + "author": { + "name": "Christopher Jeffrey" + }, + "bin": { + "marked": "./bin/marked" + }, + "bugs": { + "url": "http://github.com/chjj/marked/issues" + }, + "dependencies": {}, "description": "A markdown parser built for speed", - "author": "Christopher Jeffrey", - "version": "0.1.9", - "main": "./lib/marked.js", - "bin": "./bin/marked", - "man": "./man/marked.1", - "preferGlobal": false, - "repository": "git://github.com/chjj/marked.git", + "devDependencies": { + "gulp": "^3.8.11", + "gulp-concat": "^2.5.2", + "gulp-uglify": "^1.1.0", + "markdown": "*", + "showdown": "*" + }, + "directories": {}, + "dist": { + "shasum": "4113a15ac5d7bca158a5aae07224587b9fa15b94", + "tarball": "https://registry.npmjs.org/marked/-/marked-0.3.5.tgz" + }, + "gitHead": "88ce4df47c4d994dc1b1df1477a21fb893e11ddc", "homepage": "https://github.com/chjj/marked", - "bugs": "http://github.com/chjj/marked/issues", - "keywords": [ "markdown", "markup", "html" ], - "tags": [ "markdown", "markup", "html" ] + "keywords": [ + "markdown", + "markup", + "html" + ], + "license": "MIT", + "main": "./lib/marked.js", + "maintainers": [ + { + "email": "chjjeffrey@gmail.com", + "name": "chjj" + } + ], + "man": [ + "./man/marked.1" + ], + "name": "marked", + "optionalDependencies": {}, + "preferGlobal": true, + "readme": "ERROR: No README data found!", + "repository": { + "type": "git", + "url": "git://github.com/chjj/marked.git" + }, + "scripts": { + "bench": "node test --bench", + "test": "node test" + }, + "tags": [ + "markdown", + "markup", + "html" + ], + "version": "0.3.5" } diff --git a/tools/doc/package.json b/tools/doc/package.json index d87c9345b33f2e..41a50ac04ed188 100644 --- a/tools/doc/package.json +++ b/tools/doc/package.json @@ -7,7 +7,8 @@ "node": ">=0.6.10" }, "dependencies": { - "marked": "~0.1.9" + "marked": "^0.3.5", + "js-yaml": "^3.5.2" }, "devDependencies": {}, "optionalDependencies": {}, diff --git a/tools/doc/preprocess.js b/tools/doc/preprocess.js index 295737a2a53aee..55d90996f71c13 100644 --- a/tools/doc/preprocess.js +++ b/tools/doc/preprocess.js @@ -48,7 +48,11 @@ function processIncludes(inputFile, input, cb) { if (errState) return; if (er) return cb(errState = er); incCount--; - includeData[fname] = inc; + + // Add comments to let the HTML generator know how the anchors for + // headings should look like. + includeData[fname] = `\n` + + inc + `\n\n`; input = input.split(include + '\n').join(includeData[fname] + '\n'); if (incCount === 0) { return cb(null, input);