tools: update ESLint to 7.26.0

Update ESLint to 7.26.0

PR-URL: https://github.com/nodejs/node/pull/38605
Reviewed-By: Rich Trott <rtrott@gmail.com>
Reviewed-By: Yongsheng Zhang <zyszys98@gmail.com>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Reviewed-By: Trivikram Kamat <trivikr.dev@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
This commit is contained in:
cjihrig 2021-05-08 15:35:55 -04:00 committed by Michaël Zasso
parent 6b409cf664
commit a028805f1b
No known key found for this signature in database
GPG Key ID: 770F7A9A5AE15600
116 changed files with 4919 additions and 4657 deletions

View File

@ -1,14 +1,17 @@
'use strict'; 'use strict'
var unherit = require('unherit'); var unherit = require('unherit')
var xtend = require('xtend'); var xtend = require('xtend')
var Parser = require('./lib/parser.js'); var Parser = require('./lib/parser.js')
module.exports = parse; module.exports = parse
parse.Parser = Parser; parse.Parser = Parser
function parse(options) { function parse(options) {
var Local = unherit(Parser); var settings = this.data('settings')
Local.prototype.options = xtend(Local.prototype.options, this.data('settings'), options); var Local = unherit(Parser)
this.Parser = Local;
Local.prototype.options = xtend(Local.prototype.options, settings, options)
this.Parser = Local
} }

View File

@ -0,0 +1,70 @@
'use strict'
module.exports = [
'address',
'article',
'aside',
'base',
'basefont',
'blockquote',
'body',
'caption',
'center',
'col',
'colgroup',
'dd',
'details',
'dialog',
'dir',
'div',
'dl',
'dt',
'fieldset',
'figcaption',
'figure',
'footer',
'form',
'frame',
'frameset',
'h1',
'h2',
'h3',
'h4',
'h5',
'h6',
'head',
'header',
'hgroup',
'hr',
'html',
'iframe',
'legend',
'li',
'link',
'main',
'menu',
'menuitem',
'meta',
'nav',
'noframes',
'ol',
'optgroup',
'option',
'p',
'param',
'pre',
'section',
'source',
'title',
'summary',
'table',
'tbody',
'td',
'tfoot',
'th',
'thead',
'title',
'tr',
'track',
'ul'
]

View File

@ -1,68 +0,0 @@
[
"address",
"article",
"aside",
"base",
"basefont",
"blockquote",
"body",
"caption",
"center",
"col",
"colgroup",
"dd",
"details",
"dialog",
"dir",
"div",
"dl",
"dt",
"fieldset",
"figcaption",
"figure",
"footer",
"form",
"frame",
"frameset",
"h1",
"h2",
"h3",
"h4",
"h5",
"h6",
"head",
"header",
"hgroup",
"hr",
"html",
"iframe",
"legend",
"li",
"link",
"main",
"menu",
"menuitem",
"meta",
"nav",
"noframes",
"ol",
"optgroup",
"option",
"p",
"param",
"pre",
"section",
"source",
"title",
"summary",
"table",
"tbody",
"td",
"tfoot",
"th",
"thead",
"title",
"tr",
"track",
"ul"
]

View File

@ -1,48 +1,34 @@
'use strict'; 'use strict'
var xtend = require('xtend'); var xtend = require('xtend')
var entities = require('parse-entities'); var entities = require('parse-entities')
module.exports = factory; module.exports = factory
/* Factory to create an entity decoder. */ // Factory to create an entity decoder.
function factory(ctx) { function factory(ctx) {
decoder.raw = decodeRaw; decoder.raw = decodeRaw
return decoder; return decoder
/* Normalize `position` to add an `indent`. */ // Normalize `position` to add an `indent`.
function normalize(position) { function normalize(position) {
var offsets = ctx.offset; var offsets = ctx.offset
var line = position.line; var line = position.line
var result = []; var result = []
while (++line) { while (++line) {
if (!(line in offsets)) { if (!(line in offsets)) {
break; break
} }
result.push((offsets[line] || 0) + 1); result.push((offsets[line] || 0) + 1)
} }
return { return {start: position, indent: result}
start: position,
indent: result
};
} }
/* Handle a warning. // Decode `value` (at `position`) into text-nodes.
* See https://github.com/wooorm/parse-entities
* for the warnings. */
function handleWarning(reason, position, code) {
if (code === 3) {
return;
}
ctx.file.message(reason, position);
}
/* Decode `value` (at `position`) into text-nodes. */
function decoder(value, position, handler) { function decoder(value, position, handler) {
entities(value, { entities(value, {
position: normalize(position), position: normalize(position),
@ -51,14 +37,22 @@ function factory(ctx) {
reference: handler, reference: handler,
textContext: ctx, textContext: ctx,
referenceContext: ctx referenceContext: ctx
}); })
} }
/* Decode `value` (at `position`) into a string. */ // Decode `value` (at `position`) into a string.
function decodeRaw(value, position, options) { function decodeRaw(value, position, options) {
return entities(value, xtend(options, { return entities(
position: normalize(position), value,
warning: handleWarning xtend(options, {position: normalize(position), warning: handleWarning})
})); )
}
// Handle a warning.
// See <https://github.com/wooorm/parse-entities> for the warnings.
function handleWarning(reason, position, code) {
if (code !== 3) {
ctx.file.message(reason, position)
}
} }
} }

View File

@ -1,4 +1,4 @@
'use strict'; 'use strict'
module.exports = { module.exports = {
position: true, position: true,
@ -6,5 +6,5 @@ module.exports = {
commonmark: false, commonmark: false,
footnotes: false, footnotes: false,
pedantic: false, pedantic: false,
blocks: require('./block-elements.json') blocks: require('./block-elements')
}; }

View File

@ -1,17 +1,17 @@
'use strict'; 'use strict'
module.exports = locate; module.exports = locate
function locate(value, fromIndex) { function locate(value, fromIndex) {
var index = value.indexOf('\n', fromIndex); var index = value.indexOf('\n', fromIndex)
while (index > fromIndex) { while (index > fromIndex) {
if (value.charAt(index - 1) !== ' ') { if (value.charAt(index - 1) !== ' ') {
break; break
} }
index--; index--
} }
return index; return index
} }

View File

@ -1,7 +1,7 @@
'use strict'; 'use strict'
module.exports = locate; module.exports = locate
function locate(value, fromIndex) { function locate(value, fromIndex) {
return value.indexOf('`', fromIndex); return value.indexOf('`', fromIndex)
} }

View File

@ -1,7 +1,7 @@
'use strict'; 'use strict'
module.exports = locate; module.exports = locate
function locate(value, fromIndex) { function locate(value, fromIndex) {
return value.indexOf('~~', fromIndex); return value.indexOf('~~', fromIndex)
} }

View File

@ -1,18 +1,18 @@
'use strict'; 'use strict'
module.exports = locate; module.exports = locate
function locate(value, fromIndex) { function locate(value, fromIndex) {
var asterisk = value.indexOf('*', fromIndex); var asterisk = value.indexOf('*', fromIndex)
var underscore = value.indexOf('_', fromIndex); var underscore = value.indexOf('_', fromIndex)
if (underscore === -1) { if (underscore === -1) {
return asterisk; return asterisk
} }
if (asterisk === -1) { if (asterisk === -1) {
return underscore; return underscore
} }
return underscore < asterisk ? underscore : asterisk; return underscore < asterisk ? underscore : asterisk
} }

View File

@ -1,7 +1,7 @@
'use strict'; 'use strict'
module.exports = locate; module.exports = locate
function locate(value, fromIndex) { function locate(value, fromIndex) {
return value.indexOf('\\', fromIndex); return value.indexOf('\\', fromIndex)
} }

View File

@ -1,16 +1,16 @@
'use strict'; 'use strict'
module.exports = locate; module.exports = locate
function locate(value, fromIndex) { function locate(value, fromIndex) {
var link = value.indexOf('[', fromIndex); var link = value.indexOf('[', fromIndex)
var image = value.indexOf('![', fromIndex); var image = value.indexOf('![', fromIndex)
if (image === -1) { if (image === -1) {
return link; return link
} }
/* Link can never be `-1` if an image is found, so we dont need // Link can never be `-1` if an image is found, so we dont need to check
* to check for that :) */ // for that :)
return link < image ? link : image; return link < image ? link : image
} }

View File

@ -1,18 +1,18 @@
'use strict'; 'use strict'
module.exports = locate; module.exports = locate
function locate(value, fromIndex) { function locate(value, fromIndex) {
var asterisk = value.indexOf('**', fromIndex); var asterisk = value.indexOf('**', fromIndex)
var underscore = value.indexOf('__', fromIndex); var underscore = value.indexOf('__', fromIndex)
if (underscore === -1) { if (underscore === -1) {
return asterisk; return asterisk
} }
if (asterisk === -1) { if (asterisk === -1) {
return underscore; return underscore
} }
return underscore < asterisk ? underscore : asterisk; return underscore < asterisk ? underscore : asterisk
} }

View File

@ -1,7 +1,7 @@
'use strict'; 'use strict'
module.exports = locate; module.exports = locate
function locate(value, fromIndex) { function locate(value, fromIndex) {
return value.indexOf('<', fromIndex); return value.indexOf('<', fromIndex)
} }

View File

@ -1,26 +1,26 @@
'use strict'; 'use strict'
module.exports = locate; module.exports = locate
var PROTOCOLS = ['https://', 'http://', 'mailto:']; var protocols = ['https://', 'http://', 'mailto:']
function locate(value, fromIndex) { function locate(value, fromIndex) {
var length = PROTOCOLS.length; var length = protocols.length
var index = -1; var index = -1
var min = -1; var min = -1
var position; var position
if (!this.options.gfm) { if (!this.options.gfm) {
return -1; return -1
} }
while (++index < length) { while (++index < length) {
position = value.indexOf(PROTOCOLS[index], fromIndex); position = value.indexOf(protocols[index], fromIndex)
if (position !== -1 && (position < min || min === -1)) { if (position !== -1 && (position < min || min === -1)) {
min = position; min = position
} }
} }
return min; return min
} }

View File

@ -1,45 +1,42 @@
'use strict'; 'use strict'
var xtend = require('xtend'); var xtend = require('xtend')
var removePosition = require('unist-util-remove-position'); var removePosition = require('unist-util-remove-position')
module.exports = parse; module.exports = parse
var C_NEWLINE = '\n'; var lineFeed = '\n'
var EXPRESSION_LINE_BREAKS = /\r\n|\r/g; var lineBreaksExpression = /\r\n|\r/g
/* Parse the bound file. */ // Parse the bound file.
function parse() { function parse() {
var self = this; var self = this
var value = String(self.file); var value = String(self.file)
var start = {line: 1, column: 1, offset: 0}; var start = {line: 1, column: 1, offset: 0}
var content = xtend(start); var content = xtend(start)
var node; var node
/* Clean non-unix newlines: `\r\n` and `\r` are all // Clean non-unix newlines: `\r\n` and `\r` are all changed to `\n`.
* changed to `\n`. This should not affect positional // This should not affect positional information.
* information. */ value = value.replace(lineBreaksExpression, lineFeed)
value = value.replace(EXPRESSION_LINE_BREAKS, C_NEWLINE);
if (value.charCodeAt(0) === 0xFEFF) { // BOM.
value = value.slice(1); if (value.charCodeAt(0) === 0xfeff) {
value = value.slice(1)
content.column++; content.column++
content.offset++; content.offset++
} }
node = { node = {
type: 'root', type: 'root',
children: self.tokenizeBlock(value, content), children: self.tokenizeBlock(value, content),
position: { position: {start: start, end: self.eof || xtend(start)}
start: start,
end: self.eof || xtend(start)
}
};
if (!self.options.position) {
removePosition(node, true);
} }
return node; if (!self.options.position) {
removePosition(node, true)
}
return node
} }

View File

@ -1,54 +1,53 @@
'use strict'; 'use strict'
var xtend = require('xtend'); var xtend = require('xtend')
var toggle = require('state-toggle'); var toggle = require('state-toggle')
var vfileLocation = require('vfile-location'); var vfileLocation = require('vfile-location')
var unescape = require('./unescape'); var unescape = require('./unescape')
var decode = require('./decode'); var decode = require('./decode')
var tokenizer = require('./tokenizer'); var tokenizer = require('./tokenizer')
module.exports = Parser; module.exports = Parser
function Parser(doc, file) { function Parser(doc, file) {
this.file = file; this.file = file
this.offset = {}; this.offset = {}
this.options = xtend(this.options); this.options = xtend(this.options)
this.setOptions({}); this.setOptions({})
this.inList = false; this.inList = false
this.inBlock = false; this.inBlock = false
this.inLink = false; this.inLink = false
this.atStart = true; this.atStart = true
this.toOffset = vfileLocation(file).toOffset; this.toOffset = vfileLocation(file).toOffset
this.unescape = unescape(this, 'escape'); this.unescape = unescape(this, 'escape')
this.decode = decode(this); this.decode = decode(this)
} }
var proto = Parser.prototype; var proto = Parser.prototype
/* Expose core. */ // Expose core.
proto.setOptions = require('./set-options'); proto.setOptions = require('./set-options')
proto.parse = require('./parse'); proto.parse = require('./parse')
/* Expose `defaults`. */ // Expose `defaults`.
proto.options = require('./defaults'); proto.options = require('./defaults')
/* Enter and exit helpers. */ // Enter and exit helpers.
proto.exitStart = toggle('atStart', true); proto.exitStart = toggle('atStart', true)
proto.enterList = toggle('inList', false); proto.enterList = toggle('inList', false)
proto.enterLink = toggle('inLink', false); proto.enterLink = toggle('inLink', false)
proto.enterBlock = toggle('inBlock', false); proto.enterBlock = toggle('inBlock', false)
/* Nodes that can interupt a paragraph: // Nodes that can interupt a paragraph:
* //
* ```markdown // ```markdown
* A paragraph, followed by a thematic break. // A paragraph, followed by a thematic break.
* ___ // ___
* ``` // ```
* //
* In the above example, the thematic break interupts // In the above example, the thematic break “interupts” the paragraph.
* the paragraph. */
proto.interruptParagraph = [ proto.interruptParagraph = [
['thematicBreak'], ['thematicBreak'],
['atxHeading'], ['atxHeading'],
@ -58,34 +57,32 @@ proto.interruptParagraph = [
['setextHeading', {commonmark: false}], ['setextHeading', {commonmark: false}],
['definition', {commonmark: false}], ['definition', {commonmark: false}],
['footnote', {commonmark: false}] ['footnote', {commonmark: false}]
]; ]
/* Nodes that can interupt a list: // Nodes that can interupt a list:
* //
* ```markdown // ```markdown
* - One // - One
* ___ // ___
* ``` // ```
* //
* In the above example, the thematic break interupts // In the above example, the thematic break “interupts” the list.
* the list. */
proto.interruptList = [ proto.interruptList = [
['atxHeading', {pedantic: false}], ['atxHeading', {pedantic: false}],
['fencedCode', {pedantic: false}], ['fencedCode', {pedantic: false}],
['thematicBreak', {pedantic: false}], ['thematicBreak', {pedantic: false}],
['definition', {commonmark: false}], ['definition', {commonmark: false}],
['footnote', {commonmark: false}] ['footnote', {commonmark: false}]
]; ]
/* Nodes that can interupt a blockquote: // Nodes that can interupt a blockquote:
* //
* ```markdown // ```markdown
* > A paragraph. // > A paragraph.
* ___ // ___
* ``` // ```
* //
* In the above example, the thematic break interupts // In the above example, the thematic break “interupts” the blockquote.
* the blockquote. */
proto.interruptBlockquote = [ proto.interruptBlockquote = [
['indentedCode', {commonmark: true}], ['indentedCode', {commonmark: true}],
['fencedCode', {commonmark: true}], ['fencedCode', {commonmark: true}],
@ -96,9 +93,9 @@ proto.interruptBlockquote = [
['list', {commonmark: true}], ['list', {commonmark: true}],
['definition', {commonmark: false}], ['definition', {commonmark: false}],
['footnote', {commonmark: false}] ['footnote', {commonmark: false}]
]; ]
/* Handlers. */ // Handlers.
proto.blockTokenizers = { proto.blockTokenizers = {
newline: require('./tokenize/newline'), newline: require('./tokenize/newline'),
indentedCode: require('./tokenize/code-indented'), indentedCode: require('./tokenize/code-indented'),
@ -113,7 +110,7 @@ proto.blockTokenizers = {
definition: require('./tokenize/definition'), definition: require('./tokenize/definition'),
table: require('./tokenize/table'), table: require('./tokenize/table'),
paragraph: require('./tokenize/paragraph') paragraph: require('./tokenize/paragraph')
}; }
proto.inlineTokenizers = { proto.inlineTokenizers = {
escape: require('./tokenize/escape'), escape: require('./tokenize/escape'),
@ -128,25 +125,25 @@ proto.inlineTokenizers = {
code: require('./tokenize/code-inline'), code: require('./tokenize/code-inline'),
break: require('./tokenize/break'), break: require('./tokenize/break'),
text: require('./tokenize/text') text: require('./tokenize/text')
}; }
/* Expose precedence. */ // Expose precedence.
proto.blockMethods = keys(proto.blockTokenizers); proto.blockMethods = keys(proto.blockTokenizers)
proto.inlineMethods = keys(proto.inlineTokenizers); proto.inlineMethods = keys(proto.inlineTokenizers)
/* Tokenizers. */ // Tokenizers.
proto.tokenizeBlock = tokenizer('block'); proto.tokenizeBlock = tokenizer('block')
proto.tokenizeInline = tokenizer('inline'); proto.tokenizeInline = tokenizer('inline')
proto.tokenizeFactory = tokenizer; proto.tokenizeFactory = tokenizer
/* Get all keys in `value`. */ // Get all keys in `value`.
function keys(value) { function keys(value) {
var result = []; var result = []
var key; var key
for (key in value) { for (key in value) {
result.push(key); result.push(key)
} }
return result; return result
} }

View File

@ -1,47 +1,46 @@
'use strict'; 'use strict'
var xtend = require('xtend'); var xtend = require('xtend')
var escapes = require('markdown-escapes'); var escapes = require('markdown-escapes')
var defaults = require('./defaults'); var defaults = require('./defaults')
module.exports = setOptions; module.exports = setOptions
function setOptions(options) { function setOptions(options) {
var self = this; var self = this
var current = self.options; var current = self.options
var key; var key
var value; var value
if (options == null) { if (options == null) {
options = {}; options = {}
} else if (typeof options === 'object') { } else if (typeof options === 'object') {
options = xtend(options); options = xtend(options)
} else { } else {
throw new Error( throw new Error('Invalid value `' + options + '` for setting `options`')
'Invalid value `' + options + '` ' +
'for setting `options`'
);
} }
for (key in defaults) { for (key in defaults) {
value = options[key]; value = options[key]
if (value == null) { if (value == null) {
value = current[key]; value = current[key]
} }
if ( if (
(key !== 'blocks' && typeof value !== 'boolean') || (key !== 'blocks' && typeof value !== 'boolean') ||
(key === 'blocks' && typeof value !== 'object') (key === 'blocks' && typeof value !== 'object')
) { ) {
throw new Error('Invalid value `' + value + '` for setting `options.' + key + '`'); throw new Error(
'Invalid value `' + value + '` for setting `options.' + key + '`'
)
} }
options[key] = value; options[key] = value
} }
self.options = options; self.options = options
self.escape = escapes(options); self.escape = escapes(options)
return self; return self
} }

View File

@ -1,145 +1,133 @@
'use strict'; 'use strict'
var whitespace = require('is-whitespace-character'); var whitespace = require('is-whitespace-character')
var decode = require('parse-entities'); var decode = require('parse-entities')
var locate = require('../locate/tag'); var locate = require('../locate/tag')
module.exports = autoLink; module.exports = autoLink
autoLink.locator = locate; autoLink.locator = locate
autoLink.notInLink = true; autoLink.notInLink = true
var C_LT = '<'; var lessThan = '<'
var C_GT = '>'; var greaterThan = '>'
var C_AT_SIGN = '@'; var atSign = '@'
var C_SLASH = '/'; var slash = '/'
var MAILTO = 'mailto:'; var mailto = 'mailto:'
var MAILTO_LENGTH = MAILTO.length; var mailtoLength = mailto.length
/* Tokenise a link. */
function autoLink(eat, value, silent) { function autoLink(eat, value, silent) {
var self; var self = this
var subvalue; var subvalue = ''
var length; var length = value.length
var index; var index = 0
var queue; var queue = ''
var character; var hasAtCharacter = false
var hasAtCharacter; var link = ''
var link; var character
var now; var now
var content; var content
var tokenizers; var tokenizers
var exit; var exit
if (value.charAt(0) !== C_LT) { if (value.charAt(0) !== lessThan) {
return; return
} }
self = this; index++
subvalue = ''; subvalue = lessThan
length = value.length;
index = 0;
queue = '';
hasAtCharacter = false;
link = '';
index++;
subvalue = C_LT;
while (index < length) { while (index < length) {
character = value.charAt(index); character = value.charAt(index)
if ( if (
whitespace(character) || whitespace(character) ||
character === C_GT || character === greaterThan ||
character === C_AT_SIGN || character === atSign ||
(character === ':' && value.charAt(index + 1) === C_SLASH) (character === ':' && value.charAt(index + 1) === slash)
) { ) {
break; break
} }
queue += character; queue += character
index++; index++
} }
if (!queue) { if (!queue) {
return; return
} }
link += queue; link += queue
queue = ''; queue = ''
character = value.charAt(index); character = value.charAt(index)
link += character; link += character
index++; index++
if (character === C_AT_SIGN) { if (character === atSign) {
hasAtCharacter = true; hasAtCharacter = true
} else { } else {
if ( if (character !== ':' || value.charAt(index + 1) !== slash) {
character !== ':' || return
value.charAt(index + 1) !== C_SLASH
) {
return;
} }
link += C_SLASH; link += slash
index++; index++
} }
while (index < length) { while (index < length) {
character = value.charAt(index); character = value.charAt(index)
if (whitespace(character) || character === C_GT) { if (whitespace(character) || character === greaterThan) {
break; break
} }
queue += character; queue += character
index++; index++
} }
character = value.charAt(index); character = value.charAt(index)
if (!queue || character !== C_GT) { if (!queue || character !== greaterThan) {
return; return
} }
/* istanbul ignore if - never used (yet) */ /* istanbul ignore if - never used (yet) */
if (silent) { if (silent) {
return true; return true
} }
link += queue; link += queue
content = link; content = link
subvalue += link + character; subvalue += link + character
now = eat.now(); now = eat.now()
now.column++; now.column++
now.offset++; now.offset++
if (hasAtCharacter) { if (hasAtCharacter) {
if (link.slice(0, MAILTO_LENGTH).toLowerCase() === MAILTO) { if (link.slice(0, mailtoLength).toLowerCase() === mailto) {
content = content.substr(MAILTO_LENGTH); content = content.slice(mailtoLength)
now.column += MAILTO_LENGTH; now.column += mailtoLength
now.offset += MAILTO_LENGTH; now.offset += mailtoLength
} else { } else {
link = MAILTO + link; link = mailto + link
} }
} }
/* Temporarily remove all tokenizers except text in autolinks. */ // Temporarily remove all tokenizers except text in autolinks.
tokenizers = self.inlineTokenizers; tokenizers = self.inlineTokenizers
self.inlineTokenizers = {text: tokenizers.text}; self.inlineTokenizers = {text: tokenizers.text}
exit = self.enterLink(); exit = self.enterLink()
content = self.tokenizeInline(content, now); content = self.tokenizeInline(content, now)
self.inlineTokenizers = tokenizers; self.inlineTokenizers = tokenizers
exit(); exit()
return eat(subvalue)({ return eat(subvalue)({
type: 'link', type: 'link',
title: null, title: null,
url: decode(link, {nonTerminated: false}), url: decode(link, {nonTerminated: false}),
children: content children: content
}); })
} }

View File

@ -1,129 +1,124 @@
'use strict'; 'use strict'
var trim = require('trim'); var trim = require('trim')
var interrupt = require('../util/interrupt'); var interrupt = require('../util/interrupt')
module.exports = blockquote; module.exports = blockquote
var C_NEWLINE = '\n'; var lineFeed = '\n'
var C_TAB = '\t'; var tab = '\t'
var C_SPACE = ' '; var space = ' '
var C_GT = '>'; var greaterThan = '>'
/* Tokenise a blockquote. */
function blockquote(eat, value, silent) { function blockquote(eat, value, silent) {
var self = this; var self = this
var offsets = self.offset; var offsets = self.offset
var tokenizers = self.blockTokenizers; var tokenizers = self.blockTokenizers
var interruptors = self.interruptBlockquote; var interruptors = self.interruptBlockquote
var now = eat.now(); var now = eat.now()
var currentLine = now.line; var currentLine = now.line
var length = value.length; var length = value.length
var values = []; var values = []
var contents = []; var contents = []
var indents = []; var indents = []
var add; var add
var index = 0; var index = 0
var character; var character
var rest; var rest
var nextIndex; var nextIndex
var content; var content
var line; var line
var startIndex; var startIndex
var prefixed; var prefixed
var exit; var exit
while (index < length) { while (index < length) {
character = value.charAt(index); character = value.charAt(index)
if (character !== C_SPACE && character !== C_TAB) { if (character !== space && character !== tab) {
break; break
} }
index++; index++
} }
if (value.charAt(index) !== C_GT) { if (value.charAt(index) !== greaterThan) {
return; return
} }
if (silent) { if (silent) {
return true; return true
} }
index = 0; index = 0
while (index < length) { while (index < length) {
nextIndex = value.indexOf(C_NEWLINE, index); nextIndex = value.indexOf(lineFeed, index)
startIndex = index; startIndex = index
prefixed = false; prefixed = false
if (nextIndex === -1) { if (nextIndex === -1) {
nextIndex = length; nextIndex = length
} }
while (index < length) { while (index < length) {
character = value.charAt(index); character = value.charAt(index)
if (character !== C_SPACE && character !== C_TAB) { if (character !== space && character !== tab) {
break; break
} }
index++; index++
} }
if (value.charAt(index) === C_GT) { if (value.charAt(index) === greaterThan) {
index++; index++
prefixed = true; prefixed = true
if (value.charAt(index) === C_SPACE) { if (value.charAt(index) === space) {
index++; index++
} }
} else { } else {
index = startIndex; index = startIndex
} }
content = value.slice(index, nextIndex); content = value.slice(index, nextIndex)
if (!prefixed && !trim(content)) { if (!prefixed && !trim(content)) {
index = startIndex; index = startIndex
break; break
} }
if (!prefixed) { if (!prefixed) {
rest = value.slice(index); rest = value.slice(index)
/* Check if the following code contains a possible // Check if the following code contains a possible block.
* block. */
if (interrupt(interruptors, tokenizers, self, [eat, rest, true])) { if (interrupt(interruptors, tokenizers, self, [eat, rest, true])) {
break; break
} }
} }
line = startIndex === index ? content : value.slice(startIndex, nextIndex); line = startIndex === index ? content : value.slice(startIndex, nextIndex)
indents.push(index - startIndex); indents.push(index - startIndex)
values.push(line); values.push(line)
contents.push(content); contents.push(content)
index = nextIndex + 1; index = nextIndex + 1
} }
index = -1; index = -1
length = indents.length; length = indents.length
add = eat(values.join(C_NEWLINE)); add = eat(values.join(lineFeed))
while (++index < length) { while (++index < length) {
offsets[currentLine] = (offsets[currentLine] || 0) + indents[index]; offsets[currentLine] = (offsets[currentLine] || 0) + indents[index]
currentLine++; currentLine++
} }
exit = self.enterBlock(); exit = self.enterBlock()
contents = self.tokenizeBlock(contents.join(C_NEWLINE), now); contents = self.tokenizeBlock(contents.join(lineFeed), now)
exit(); exit()
return add({ return add({type: 'blockquote', children: contents})
type: 'blockquote',
children: contents
});
} }

View File

@ -1,40 +1,42 @@
'use strict'; 'use strict'
var locate = require('../locate/break'); var locate = require('../locate/break')
module.exports = hardBreak; module.exports = hardBreak
hardBreak.locator = locate; hardBreak.locator = locate
var MIN_BREAK_LENGTH = 2; var space = ' '
var lineFeed = '\n'
var minBreakLength = 2
function hardBreak(eat, value, silent) { function hardBreak(eat, value, silent) {
var length = value.length; var length = value.length
var index = -1; var index = -1
var queue = ''; var queue = ''
var character; var character
while (++index < length) { while (++index < length) {
character = value.charAt(index); character = value.charAt(index)
if (character === '\n') { if (character === lineFeed) {
if (index < MIN_BREAK_LENGTH) { if (index < minBreakLength) {
return; return
} }
/* istanbul ignore if - never used (yet) */ /* istanbul ignore if - never used (yet) */
if (silent) { if (silent) {
return true; return true
} }
queue += character; queue += character
return eat(queue)({type: 'break'}); return eat(queue)({type: 'break'})
} }
if (character !== ' ') { if (character !== space) {
return; return
} }
queue += character; queue += character
} }
} }

View File

@ -1,236 +1,253 @@
'use strict'; 'use strict'
var trim = require('trim-trailing-lines'); module.exports = fencedCode
module.exports = fencedCode; var lineFeed = '\n'
var tab = '\t'
var space = ' '
var tilde = '~'
var graveAccent = '`'
var C_NEWLINE = '\n'; var minFenceCount = 3
var C_TAB = '\t'; var tabSize = 4
var C_SPACE = ' ';
var C_TILDE = '~';
var C_TICK = '`';
var MIN_FENCE_COUNT = 3;
var CODE_INDENT_COUNT = 4;
function fencedCode(eat, value, silent) { function fencedCode(eat, value, silent) {
var self = this; var self = this
var settings = self.options; var gfm = self.options.gfm
var length = value.length + 1; var length = value.length + 1
var index = 0; var index = 0
var subvalue = ''; var subvalue = ''
var fenceCount; var fenceCount
var marker; var marker
var character; var character
var flag; var flag
var queue; var lang
var content; var meta
var exdentedContent; var queue
var closing; var content
var exdentedClosing; var exdentedContent
var indent; var closing
var now; var exdentedClosing
var indent
var now
if (!settings.gfm) { if (!gfm) {
return; return
} }
/* Eat initial spacing. */ // Eat initial spacing.
while (index < length) { while (index < length) {
character = value.charAt(index); character = value.charAt(index)
if (character !== C_SPACE && character !== C_TAB) { if (character !== space && character !== tab) {
break; break
} }
subvalue += character; subvalue += character
index++; index++
} }
indent = index; indent = index
/* Eat the fence. */ // Eat the fence.
character = value.charAt(index); character = value.charAt(index)
if (character !== C_TILDE && character !== C_TICK) { if (character !== tilde && character !== graveAccent) {
return; return
} }
index++; index++
marker = character; marker = character
fenceCount = 1; fenceCount = 1
subvalue += character; subvalue += character
while (index < length) { while (index < length) {
character = value.charAt(index); character = value.charAt(index)
if (character !== marker) { if (character !== marker) {
break; break
} }
subvalue += character; subvalue += character
fenceCount++; fenceCount++
index++; index++
} }
if (fenceCount < MIN_FENCE_COUNT) { if (fenceCount < minFenceCount) {
return; return
} }
/* Eat spacing before flag. */ // Eat spacing before flag.
while (index < length) { while (index < length) {
character = value.charAt(index); character = value.charAt(index)
if (character !== C_SPACE && character !== C_TAB) { if (character !== space && character !== tab) {
break; break
} }
subvalue += character; subvalue += character
index++; index++
} }
/* Eat flag. */ // Eat flag.
flag = ''; flag = ''
queue = ''; queue = ''
while (index < length) { while (index < length) {
character = value.charAt(index); character = value.charAt(index)
if ( if (
character === C_NEWLINE || character === lineFeed ||
character === C_TILDE || (marker === graveAccent && character === marker)
character === C_TICK
) { ) {
break; break
} }
if (character === C_SPACE || character === C_TAB) { if (character === space || character === tab) {
queue += character; queue += character
} else { } else {
flag += queue + character; flag += queue + character
queue = ''; queue = ''
} }
index++; index++
} }
character = value.charAt(index); character = value.charAt(index)
if (character && character !== C_NEWLINE) { if (character && character !== lineFeed) {
return; return
} }
if (silent) { if (silent) {
return true; return true
} }
now = eat.now(); now = eat.now()
now.column += subvalue.length; now.column += subvalue.length
now.offset += subvalue.length; now.offset += subvalue.length
subvalue += flag; subvalue += flag
flag = self.decode.raw(self.unescape(flag), now); flag = self.decode.raw(self.unescape(flag), now)
if (queue) { if (queue) {
subvalue += queue; subvalue += queue
} }
queue = ''; queue = ''
closing = ''; closing = ''
exdentedClosing = ''; exdentedClosing = ''
content = ''; content = ''
exdentedContent = ''; exdentedContent = ''
var skip = true
/* Eat content. */ // Eat content.
while (index < length) { while (index < length) {
character = value.charAt(index); character = value.charAt(index)
content += closing; content += closing
exdentedContent += exdentedClosing; exdentedContent += exdentedClosing
closing = ''; closing = ''
exdentedClosing = ''; exdentedClosing = ''
if (character !== C_NEWLINE) { if (character !== lineFeed) {
content += character; content += character
exdentedClosing += character; exdentedClosing += character
index++; index++
continue; continue
} }
/* Add the newline to `subvalue` if its the first // The first line feed is ignored. Others arent.
* character. Otherwise, add it to the `closing` if (skip) {
* queue. */ subvalue += character
if (content) { skip = false
closing += character;
exdentedClosing += character;
} else { } else {
subvalue += character; closing += character
exdentedClosing += character
} }
queue = ''; queue = ''
index++; index++
while (index < length) { while (index < length) {
character = value.charAt(index); character = value.charAt(index)
if (character !== C_SPACE) { if (character !== space) {
break; break
} }
queue += character; queue += character
index++; index++
} }
closing += queue; closing += queue
exdentedClosing += queue.slice(indent); exdentedClosing += queue.slice(indent)
if (queue.length >= CODE_INDENT_COUNT) { if (queue.length >= tabSize) {
continue; continue
} }
queue = ''; queue = ''
while (index < length) { while (index < length) {
character = value.charAt(index); character = value.charAt(index)
if (character !== marker) { if (character !== marker) {
break; break
} }
queue += character; queue += character
index++; index++
} }
closing += queue; closing += queue
exdentedClosing += queue; exdentedClosing += queue
if (queue.length < fenceCount) { if (queue.length < fenceCount) {
continue; continue
} }
queue = ''; queue = ''
while (index < length) { while (index < length) {
character = value.charAt(index); character = value.charAt(index)
if (character !== C_SPACE && character !== C_TAB) { if (character !== space && character !== tab) {
break; break
} }
closing += character; closing += character
exdentedClosing += character; exdentedClosing += character
index++; index++
} }
if (!character || character === C_NEWLINE) { if (!character || character === lineFeed) {
break; break
} }
} }
subvalue += content + closing; subvalue += content + closing
// Get lang and meta from the flag.
index = -1
length = flag.length
while (++index < length) {
character = flag.charAt(index)
if (character === space || character === tab) {
if (!lang) {
lang = flag.slice(0, index)
}
} else if (lang) {
meta = flag.slice(index)
break
}
}
return eat(subvalue)({ return eat(subvalue)({
type: 'code', type: 'code',
lang: flag || null, lang: lang || flag || null,
value: trim(exdentedContent) meta: meta || null,
}); value: exdentedContent
})
} }

View File

@ -1,98 +1,98 @@
'use strict'; 'use strict'
var repeat = require('repeat-string'); var repeat = require('repeat-string')
var trim = require('trim-trailing-lines'); var trim = require('trim-trailing-lines')
module.exports = indentedCode; module.exports = indentedCode
var C_NEWLINE = '\n'; var lineFeed = '\n'
var C_TAB = '\t'; var tab = '\t'
var C_SPACE = ' '; var space = ' '
var CODE_INDENT_COUNT = 4; var tabSize = 4
var CODE_INDENT = repeat(C_SPACE, CODE_INDENT_COUNT); var codeIndent = repeat(space, tabSize)
/* Tokenise indented code. */
function indentedCode(eat, value, silent) { function indentedCode(eat, value, silent) {
var index = -1; var index = -1
var length = value.length; var length = value.length
var subvalue = ''; var subvalue = ''
var content = ''; var content = ''
var subvalueQueue = ''; var subvalueQueue = ''
var contentQueue = ''; var contentQueue = ''
var character; var character
var blankQueue; var blankQueue
var indent; var indent
while (++index < length) { while (++index < length) {
character = value.charAt(index); character = value.charAt(index)
if (indent) { if (indent) {
indent = false; indent = false
subvalue += subvalueQueue; subvalue += subvalueQueue
content += contentQueue; content += contentQueue
subvalueQueue = ''; subvalueQueue = ''
contentQueue = ''; contentQueue = ''
if (character === C_NEWLINE) { if (character === lineFeed) {
subvalueQueue = character; subvalueQueue = character
contentQueue = character; contentQueue = character
} else { } else {
subvalue += character; subvalue += character
content += character; content += character
while (++index < length) { while (++index < length) {
character = value.charAt(index); character = value.charAt(index)
if (!character || character === C_NEWLINE) { if (!character || character === lineFeed) {
contentQueue = character; contentQueue = character
subvalueQueue = character; subvalueQueue = character
break; break
} }
subvalue += character; subvalue += character
content += character; content += character
} }
} }
} else if ( } else if (
character === C_SPACE && character === space &&
value.charAt(index + 1) === character && value.charAt(index + 1) === character &&
value.charAt(index + 2) === character && value.charAt(index + 2) === character &&
value.charAt(index + 3) === character value.charAt(index + 3) === character
) { ) {
subvalueQueue += CODE_INDENT; subvalueQueue += codeIndent
index += 3; index += 3
indent = true; indent = true
} else if (character === C_TAB) { } else if (character === tab) {
subvalueQueue += character; subvalueQueue += character
indent = true; indent = true
} else { } else {
blankQueue = ''; blankQueue = ''
while (character === C_TAB || character === C_SPACE) { while (character === tab || character === space) {
blankQueue += character; blankQueue += character
character = value.charAt(++index); character = value.charAt(++index)
} }
if (character !== C_NEWLINE) { if (character !== lineFeed) {
break; break
} }
subvalueQueue += blankQueue + character; subvalueQueue += blankQueue + character
contentQueue += character; contentQueue += character
} }
} }
if (content) { if (content) {
if (silent) { if (silent) {
return true; return true
} }
return eat(subvalue)({ return eat(subvalue)({
type: 'code', type: 'code',
lang: null, lang: null,
meta: null,
value: trim(content) value: trim(content)
}); })
} }
} }

View File

@ -1,112 +1,109 @@
'use strict'; 'use strict'
var whitespace = require('is-whitespace-character'); var locate = require('../locate/code-inline')
var locate = require('../locate/code-inline');
module.exports = inlineCode; module.exports = inlineCode
inlineCode.locator = locate; inlineCode.locator = locate
var C_TICK = '`'; var lineFeed = 10 // '\n'
var space = 32 // ' '
var graveAccent = 96 // '`'
/* Tokenise inline code. */
function inlineCode(eat, value, silent) { function inlineCode(eat, value, silent) {
var length = value.length; var length = value.length
var index = 0; var index = 0
var queue = ''; var openingFenceEnd
var tickQueue = ''; var closingFenceStart
var contentQueue; var closingFenceEnd
var subqueue; var code
var count; var next
var openingCount; var found
var subvalue;
var character;
var found;
var next;
while (index < length) { while (index < length) {
if (value.charAt(index) !== C_TICK) { if (value.charCodeAt(index) !== graveAccent) {
break; break
} }
queue += C_TICK; index++
index++;
} }
if (!queue) { if (index === 0 || index === length) {
return; return
} }
subvalue = queue; openingFenceEnd = index
openingCount = index; next = value.charCodeAt(index)
queue = '';
next = value.charAt(index);
count = 0;
while (index < length) { while (index < length) {
character = next; code = next
next = value.charAt(index + 1); next = value.charCodeAt(index + 1)
if (character === C_TICK) { if (code === graveAccent) {
count++; if (closingFenceStart === undefined) {
tickQueue += character; closingFenceStart = index
} else {
count = 0;
queue += character;
}
if (count && next !== C_TICK) {
if (count === openingCount) {
subvalue += queue + tickQueue;
found = true;
break;
} }
queue += tickQueue; closingFenceEnd = index + 1
tickQueue = '';
if (
next !== graveAccent &&
closingFenceEnd - closingFenceStart === openingFenceEnd
) {
found = true
break
}
} else if (closingFenceStart !== undefined) {
closingFenceStart = undefined
closingFenceEnd = undefined
} }
index++; index++
} }
if (!found) { if (!found) {
if (openingCount % 2 !== 0) { return
return;
}
queue = '';
} }
/* istanbul ignore if - never used (yet) */ /* istanbul ignore if - never used (yet) */
if (silent) { if (silent) {
return true; return true
} }
contentQueue = ''; // Remove the initial and final space (or line feed), iff they exist and there
subqueue = ''; // are non-space characters in the content.
length = queue.length; index = openingFenceEnd
index = -1; length = closingFenceStart
code = value.charCodeAt(index)
next = value.charCodeAt(length - 1)
found = false
while (++index < length) { if (
character = queue.charAt(index); length - index > 2 &&
(code === space || code === lineFeed) &&
(next === space || next === lineFeed)
) {
index++
length--
if (whitespace(character)) { while (index < length) {
subqueue += character; code = value.charCodeAt(index)
continue;
}
if (subqueue) { if (code !== space && code !== lineFeed) {
if (contentQueue) { found = true
contentQueue += subqueue; break
} }
subqueue = ''; index++
} }
contentQueue += character; if (found === true) {
openingFenceEnd++
closingFenceStart--
}
} }
return eat(subvalue)({ return eat(value.slice(0, closingFenceEnd))({
type: 'inlineCode', type: 'inlineCode',
value: contentQueue value: value.slice(openingFenceEnd, closingFenceStart)
}); })
} }

View File

@ -1,278 +1,273 @@
'use strict'; 'use strict'
var whitespace = require('is-whitespace-character'); var whitespace = require('is-whitespace-character')
var normalize = require('../util/normalize'); var normalize = require('../util/normalize')
module.exports = definition; module.exports = definition
definition.notInList = true;
definition.notInBlock = true;
var C_DOUBLE_QUOTE = '"'; var quotationMark = '"'
var C_SINGLE_QUOTE = '\''; var apostrophe = "'"
var C_BACKSLASH = '\\'; var backslash = '\\'
var C_NEWLINE = '\n'; var lineFeed = '\n'
var C_TAB = '\t'; var tab = '\t'
var C_SPACE = ' '; var space = ' '
var C_BRACKET_OPEN = '['; var leftSquareBracket = '['
var C_BRACKET_CLOSE = ']'; var rightSquareBracket = ']'
var C_PAREN_OPEN = '('; var leftParenthesis = '('
var C_PAREN_CLOSE = ')'; var rightParenthesis = ')'
var C_COLON = ':'; var colon = ':'
var C_LT = '<'; var lessThan = '<'
var C_GT = '>'; var greaterThan = '>'
function definition(eat, value, silent) { function definition(eat, value, silent) {
var self = this; var self = this
var commonmark = self.options.commonmark; var commonmark = self.options.commonmark
var index = 0; var index = 0
var length = value.length; var length = value.length
var subvalue = ''; var subvalue = ''
var beforeURL; var beforeURL
var beforeTitle; var beforeTitle
var queue; var queue
var character; var character
var test; var test
var identifier; var identifier
var url; var url
var title; var title
while (index < length) { while (index < length) {
character = value.charAt(index); character = value.charAt(index)
if (character !== C_SPACE && character !== C_TAB) { if (character !== space && character !== tab) {
break; break
} }
subvalue += character; subvalue += character
index++; index++
} }
character = value.charAt(index); character = value.charAt(index)
if (character !== C_BRACKET_OPEN) { if (character !== leftSquareBracket) {
return; return
} }
index++; index++
subvalue += character; subvalue += character
queue = ''; queue = ''
while (index < length) { while (index < length) {
character = value.charAt(index); character = value.charAt(index)
if (character === C_BRACKET_CLOSE) { if (character === rightSquareBracket) {
break; break
} else if (character === C_BACKSLASH) { } else if (character === backslash) {
queue += character; queue += character
index++; index++
character = value.charAt(index); character = value.charAt(index)
} }
queue += character; queue += character
index++; index++
} }
if ( if (
!queue || !queue ||
value.charAt(index) !== C_BRACKET_CLOSE || value.charAt(index) !== rightSquareBracket ||
value.charAt(index + 1) !== C_COLON value.charAt(index + 1) !== colon
) { ) {
return; return
} }
identifier = queue; identifier = queue
subvalue += queue + C_BRACKET_CLOSE + C_COLON; subvalue += queue + rightSquareBracket + colon
index = subvalue.length; index = subvalue.length
queue = ''; queue = ''
while (index < length) { while (index < length) {
character = value.charAt(index); character = value.charAt(index)
if ( if (character !== tab && character !== space && character !== lineFeed) {
character !== C_TAB && break
character !== C_SPACE &&
character !== C_NEWLINE
) {
break;
} }
subvalue += character; subvalue += character
index++; index++
} }
character = value.charAt(index); character = value.charAt(index)
queue = ''; queue = ''
beforeURL = subvalue; beforeURL = subvalue
if (character === C_LT) { if (character === lessThan) {
index++; index++
while (index < length) { while (index < length) {
character = value.charAt(index); character = value.charAt(index)
if (!isEnclosedURLCharacter(character)) { if (!isEnclosedURLCharacter(character)) {
break; break
} }
queue += character; queue += character
index++; index++
} }
character = value.charAt(index); character = value.charAt(index)
if (character === isEnclosedURLCharacter.delimiter) { if (character === isEnclosedURLCharacter.delimiter) {
subvalue += C_LT + queue + character; subvalue += lessThan + queue + character
index++; index++
} else { } else {
if (commonmark) { if (commonmark) {
return; return
} }
index -= queue.length + 1; index -= queue.length + 1
queue = ''; queue = ''
} }
} }
if (!queue) { if (!queue) {
while (index < length) { while (index < length) {
character = value.charAt(index); character = value.charAt(index)
if (!isUnclosedURLCharacter(character)) { if (!isUnclosedURLCharacter(character)) {
break; break
} }
queue += character; queue += character
index++; index++
} }
subvalue += queue; subvalue += queue
} }
if (!queue) { if (!queue) {
return; return
} }
url = queue; url = queue
queue = ''; queue = ''
while (index < length) { while (index < length) {
character = value.charAt(index); character = value.charAt(index)
if ( if (character !== tab && character !== space && character !== lineFeed) {
character !== C_TAB && break
character !== C_SPACE &&
character !== C_NEWLINE
) {
break;
} }
queue += character; queue += character
index++; index++
} }
character = value.charAt(index); character = value.charAt(index)
test = null; test = null
if (character === C_DOUBLE_QUOTE) { if (character === quotationMark) {
test = C_DOUBLE_QUOTE; test = quotationMark
} else if (character === C_SINGLE_QUOTE) { } else if (character === apostrophe) {
test = C_SINGLE_QUOTE; test = apostrophe
} else if (character === C_PAREN_OPEN) { } else if (character === leftParenthesis) {
test = C_PAREN_CLOSE; test = rightParenthesis
} }
if (!test) { if (!test) {
queue = ''; queue = ''
index = subvalue.length; index = subvalue.length
} else if (queue) { } else if (queue) {
subvalue += queue + character; subvalue += queue + character
index = subvalue.length; index = subvalue.length
queue = ''; queue = ''
while (index < length) { while (index < length) {
character = value.charAt(index); character = value.charAt(index)
if (character === test) { if (character === test) {
break; break
} }
if (character === C_NEWLINE) { if (character === lineFeed) {
index++; index++
character = value.charAt(index); character = value.charAt(index)
if (character === C_NEWLINE || character === test) { if (character === lineFeed || character === test) {
return; return
} }
queue += C_NEWLINE; queue += lineFeed
} }
queue += character; queue += character
index++; index++
} }
character = value.charAt(index); character = value.charAt(index)
if (character !== test) { if (character !== test) {
return; return
} }
beforeTitle = subvalue; beforeTitle = subvalue
subvalue += queue + character; subvalue += queue + character
index++; index++
title = queue; title = queue
queue = ''; queue = ''
} else { } else {
return; return
} }
while (index < length) { while (index < length) {
character = value.charAt(index); character = value.charAt(index)
if (character !== C_TAB && character !== C_SPACE) { if (character !== tab && character !== space) {
break; break
} }
subvalue += character; subvalue += character
index++; index++
} }
character = value.charAt(index); character = value.charAt(index)
if (!character || character === C_NEWLINE) { if (!character || character === lineFeed) {
if (silent) { if (silent) {
return true; return true
} }
beforeURL = eat(beforeURL).test().end; beforeURL = eat(beforeURL).test().end
url = self.decode.raw(self.unescape(url), beforeURL, {nonTerminated: false}); url = self.decode.raw(self.unescape(url), beforeURL, {nonTerminated: false})
if (title) { if (title) {
beforeTitle = eat(beforeTitle).test().end; beforeTitle = eat(beforeTitle).test().end
title = self.decode.raw(self.unescape(title), beforeTitle); title = self.decode.raw(self.unescape(title), beforeTitle)
} }
return eat(subvalue)({ return eat(subvalue)({
type: 'definition', type: 'definition',
identifier: normalize(identifier), identifier: normalize(identifier),
label: identifier,
title: title || null, title: title || null,
url: url url: url
}); })
} }
} }
/* Check if `character` can be inside an enclosed URI. */ // Check if `character` can be inside an enclosed URI.
function isEnclosedURLCharacter(character) { function isEnclosedURLCharacter(character) {
return character !== C_GT && return (
character !== C_BRACKET_OPEN && character !== greaterThan &&
character !== C_BRACKET_CLOSE; character !== leftSquareBracket &&
character !== rightSquareBracket
)
} }
isEnclosedURLCharacter.delimiter = C_GT; isEnclosedURLCharacter.delimiter = greaterThan
/* Check if `character` can be inside an unclosed URI. */ // Check if `character` can be inside an unclosed URI.
function isUnclosedURLCharacter(character) { function isUnclosedURLCharacter(character) {
return character !== C_BRACKET_OPEN && return (
character !== C_BRACKET_CLOSE && character !== leftSquareBracket &&
!whitespace(character); character !== rightSquareBracket &&
!whitespace(character)
)
} }

View File

@ -1,60 +1,60 @@
'use strict'; 'use strict'
var whitespace = require('is-whitespace-character'); var whitespace = require('is-whitespace-character')
var locate = require('../locate/delete'); var locate = require('../locate/delete')
module.exports = strikethrough; module.exports = strikethrough
strikethrough.locator = locate; strikethrough.locator = locate
var C_TILDE = '~'; var tilde = '~'
var DOUBLE = '~~'; var fence = '~~'
function strikethrough(eat, value, silent) { function strikethrough(eat, value, silent) {
var self = this; var self = this
var character = ''; var character = ''
var previous = ''; var previous = ''
var preceding = ''; var preceding = ''
var subvalue = ''; var subvalue = ''
var index; var index
var length; var length
var now; var now
if ( if (
!self.options.gfm || !self.options.gfm ||
value.charAt(0) !== C_TILDE || value.charAt(0) !== tilde ||
value.charAt(1) !== C_TILDE || value.charAt(1) !== tilde ||
whitespace(value.charAt(2)) whitespace(value.charAt(2))
) { ) {
return; return
} }
index = 1; index = 1
length = value.length; length = value.length
now = eat.now(); now = eat.now()
now.column += 2; now.column += 2
now.offset += 2; now.offset += 2
while (++index < length) { while (++index < length) {
character = value.charAt(index); character = value.charAt(index)
if ( if (
character === C_TILDE && character === tilde &&
previous === C_TILDE && previous === tilde &&
(!preceding || !whitespace(preceding)) (!preceding || !whitespace(preceding))
) { ) {
/* istanbul ignore if - never used (yet) */ /* istanbul ignore if - never used (yet) */
if (silent) { if (silent) {
return true; return true
} }
return eat(DOUBLE + subvalue + DOUBLE)({ return eat(fence + subvalue + fence)({
type: 'delete', type: 'delete',
children: self.tokenizeInline(subvalue, now) children: self.tokenizeInline(subvalue, now)
}); })
} }
subvalue += previous; subvalue += previous
preceding = previous; preceding = previous
previous = character; previous = character
} }
} }

View File

@ -1,85 +1,86 @@
'use strict'; 'use strict'
var trim = require('trim'); var trim = require('trim')
var word = require('is-word-character'); var word = require('is-word-character')
var whitespace = require('is-whitespace-character'); var whitespace = require('is-whitespace-character')
var locate = require('../locate/emphasis'); var locate = require('../locate/emphasis')
module.exports = emphasis; module.exports = emphasis
emphasis.locator = locate; emphasis.locator = locate
var C_ASTERISK = '*'; var asterisk = '*'
var C_UNDERSCORE = '_'; var underscore = '_'
var backslash = '\\'
function emphasis(eat, value, silent) { function emphasis(eat, value, silent) {
var self = this; var self = this
var index = 0; var index = 0
var character = value.charAt(index); var character = value.charAt(index)
var now; var now
var pedantic; var pedantic
var marker; var marker
var queue; var queue
var subvalue; var subvalue
var length; var length
var prev; var prev
if (character !== C_ASTERISK && character !== C_UNDERSCORE) { if (character !== asterisk && character !== underscore) {
return; return
} }
pedantic = self.options.pedantic; pedantic = self.options.pedantic
subvalue = character; subvalue = character
marker = character; marker = character
length = value.length; length = value.length
index++; index++
queue = ''; queue = ''
character = ''; character = ''
if (pedantic && whitespace(value.charAt(index))) { if (pedantic && whitespace(value.charAt(index))) {
return; return
} }
while (index < length) { while (index < length) {
prev = character; prev = character
character = value.charAt(index); character = value.charAt(index)
if (character === marker && (!pedantic || !whitespace(prev))) { if (character === marker && (!pedantic || !whitespace(prev))) {
character = value.charAt(++index); character = value.charAt(++index)
if (character !== marker) { if (character !== marker) {
if (!trim(queue) || prev === marker) { if (!trim(queue) || prev === marker) {
return; return
} }
if (!pedantic && marker === C_UNDERSCORE && word(character)) { if (!pedantic && marker === underscore && word(character)) {
queue += marker; queue += marker
continue; continue
} }
/* istanbul ignore if - never used (yet) */ /* istanbul ignore if - never used (yet) */
if (silent) { if (silent) {
return true; return true
} }
now = eat.now(); now = eat.now()
now.column++; now.column++
now.offset++; now.offset++
return eat(subvalue + queue + marker)({ return eat(subvalue + queue + marker)({
type: 'emphasis', type: 'emphasis',
children: self.tokenizeInline(queue, now) children: self.tokenizeInline(queue, now)
}); })
} }
queue += marker; queue += marker
} }
if (!pedantic && character === '\\') { if (!pedantic && character === backslash) {
queue += character; queue += character
character = value.charAt(++index); character = value.charAt(++index)
} }
queue += character; queue += character
index++; index++
} }
} }

View File

@ -1,34 +1,34 @@
'use strict'; 'use strict'
var locate = require('../locate/escape'); var locate = require('../locate/escape')
module.exports = escape; module.exports = escape
escape.locator = locate; escape.locator = locate
var lineFeed = '\n'
var backslash = '\\'
function escape(eat, value, silent) { function escape(eat, value, silent) {
var self = this; var self = this
var character; var character
var node; var node
if (value.charAt(0) === '\\') { if (value.charAt(0) === backslash) {
character = value.charAt(1); character = value.charAt(1)
if (self.escape.indexOf(character) !== -1) { if (self.escape.indexOf(character) !== -1) {
/* istanbul ignore if - never used (yet) */ /* istanbul ignore if - never used (yet) */
if (silent) { if (silent) {
return true; return true
} }
if (character === '\n') { if (character === lineFeed) {
node = {type: 'break'}; node = {type: 'break'}
} else { } else {
node = { node = {type: 'text', value: character}
type: 'text',
value: character
};
} }
return eat('\\' + character)(node); return eat(backslash + character)(node)
} }
} }
} }

View File

@ -1,185 +1,186 @@
'use strict'; 'use strict'
var whitespace = require('is-whitespace-character'); var whitespace = require('is-whitespace-character')
var normalize = require('../util/normalize'); var normalize = require('../util/normalize')
module.exports = footnoteDefinition; module.exports = footnoteDefinition
footnoteDefinition.notInList = true; footnoteDefinition.notInList = true
footnoteDefinition.notInBlock = true; footnoteDefinition.notInBlock = true
var C_BACKSLASH = '\\'; var backslash = '\\'
var C_NEWLINE = '\n'; var lineFeed = '\n'
var C_TAB = '\t'; var tab = '\t'
var C_SPACE = ' '; var space = ' '
var C_BRACKET_OPEN = '['; var leftSquareBracket = '['
var C_BRACKET_CLOSE = ']'; var rightSquareBracket = ']'
var C_CARET = '^'; var caret = '^'
var C_COLON = ':'; var colon = ':'
var EXPRESSION_INITIAL_TAB = /^( {4}|\t)?/gm; var EXPRESSION_INITIAL_TAB = /^( {4}|\t)?/gm
function footnoteDefinition(eat, value, silent) { function footnoteDefinition(eat, value, silent) {
var self = this; var self = this
var offsets = self.offset; var offsets = self.offset
var index; var index
var length; var length
var subvalue; var subvalue
var now; var now
var currentLine; var currentLine
var content; var content
var queue; var queue
var subqueue; var subqueue
var character; var character
var identifier; var identifier
var add; var add
var exit; var exit
if (!self.options.footnotes) { if (!self.options.footnotes) {
return; return
} }
index = 0; index = 0
length = value.length; length = value.length
subvalue = ''; subvalue = ''
now = eat.now(); now = eat.now()
currentLine = now.line; currentLine = now.line
while (index < length) { while (index < length) {
character = value.charAt(index); character = value.charAt(index)
if (!whitespace(character)) { if (!whitespace(character)) {
break; break
} }
subvalue += character; subvalue += character
index++; index++
} }
if ( if (
value.charAt(index) !== C_BRACKET_OPEN || value.charAt(index) !== leftSquareBracket ||
value.charAt(index + 1) !== C_CARET value.charAt(index + 1) !== caret
) { ) {
return; return
} }
subvalue += C_BRACKET_OPEN + C_CARET; subvalue += leftSquareBracket + caret
index = subvalue.length; index = subvalue.length
queue = ''; queue = ''
while (index < length) { while (index < length) {
character = value.charAt(index); character = value.charAt(index)
if (character === C_BRACKET_CLOSE) { if (character === rightSquareBracket) {
break; break
} else if (character === C_BACKSLASH) { } else if (character === backslash) {
queue += character; queue += character
index++; index++
character = value.charAt(index); character = value.charAt(index)
} }
queue += character; queue += character
index++; index++
} }
if ( if (
!queue || !queue ||
value.charAt(index) !== C_BRACKET_CLOSE || value.charAt(index) !== rightSquareBracket ||
value.charAt(index + 1) !== C_COLON value.charAt(index + 1) !== colon
) { ) {
return; return
} }
if (silent) { if (silent) {
return true; return true
} }
identifier = normalize(queue); identifier = queue
subvalue += queue + C_BRACKET_CLOSE + C_COLON; subvalue += queue + rightSquareBracket + colon
index = subvalue.length; index = subvalue.length
while (index < length) { while (index < length) {
character = value.charAt(index); character = value.charAt(index)
if (character !== C_TAB && character !== C_SPACE) { if (character !== tab && character !== space) {
break; break
} }
subvalue += character; subvalue += character
index++; index++
} }
now.column += subvalue.length; now.column += subvalue.length
now.offset += subvalue.length; now.offset += subvalue.length
queue = ''; queue = ''
content = ''; content = ''
subqueue = ''; subqueue = ''
while (index < length) { while (index < length) {
character = value.charAt(index); character = value.charAt(index)
if (character === C_NEWLINE) { if (character === lineFeed) {
subqueue = character; subqueue = character
index++; index++
while (index < length) { while (index < length) {
character = value.charAt(index); character = value.charAt(index)
if (character !== C_NEWLINE) { if (character !== lineFeed) {
break; break
} }
subqueue += character; subqueue += character
index++; index++
} }
queue += subqueue; queue += subqueue
subqueue = ''; subqueue = ''
while (index < length) { while (index < length) {
character = value.charAt(index); character = value.charAt(index)
if (character !== C_SPACE) { if (character !== space) {
break; break
} }
subqueue += character; subqueue += character
index++; index++
} }
if (subqueue.length === 0) { if (subqueue.length === 0) {
break; break
} }
queue += subqueue; queue += subqueue
} }
if (queue) { if (queue) {
content += queue; content += queue
queue = ''; queue = ''
} }
content += character; content += character
index++; index++
} }
subvalue += content; subvalue += content
content = content.replace(EXPRESSION_INITIAL_TAB, function (line) { content = content.replace(EXPRESSION_INITIAL_TAB, function(line) {
offsets[currentLine] = (offsets[currentLine] || 0) + line.length; offsets[currentLine] = (offsets[currentLine] || 0) + line.length
currentLine++; currentLine++
return ''; return ''
}); })
add = eat(subvalue); add = eat(subvalue)
exit = self.enterBlock(); exit = self.enterBlock()
content = self.tokenizeBlock(content, now); content = self.tokenizeBlock(content, now)
exit(); exit()
return add({ return add({
type: 'footnoteDefinition', type: 'footnoteDefinition',
identifier: identifier, identifier: normalize(identifier),
label: identifier,
children: content children: content
}); })
} }

View File

@ -1,141 +1,135 @@
'use strict'; 'use strict'
module.exports = atxHeading; module.exports = atxHeading
var C_NEWLINE = '\n'; var lineFeed = '\n'
var C_TAB = '\t'; var tab = '\t'
var C_SPACE = ' '; var space = ' '
var C_HASH = '#'; var numberSign = '#'
var MAX_ATX_COUNT = 6; var maxFenceCount = 6
function atxHeading(eat, value, silent) { function atxHeading(eat, value, silent) {
var self = this; var self = this
var settings = self.options; var pedantic = self.options.pedantic
var length = value.length + 1; var length = value.length + 1
var index = -1; var index = -1
var now = eat.now(); var now = eat.now()
var subvalue = ''; var subvalue = ''
var content = ''; var content = ''
var character; var character
var queue; var queue
var depth; var depth
/* Eat initial spacing. */ // Eat initial spacing.
while (++index < length) { while (++index < length) {
character = value.charAt(index); character = value.charAt(index)
if (character !== C_SPACE && character !== C_TAB) { if (character !== space && character !== tab) {
index--; index--
break; break
} }
subvalue += character; subvalue += character
} }
/* Eat hashes. */ // Eat hashes.
depth = 0; depth = 0
while (++index <= length) { while (++index <= length) {
character = value.charAt(index); character = value.charAt(index)
if (character !== C_HASH) { if (character !== numberSign) {
index--; index--
break; break
} }
subvalue += character; subvalue += character
depth++; depth++
} }
if (depth > MAX_ATX_COUNT) { if (depth > maxFenceCount) {
return; return
} }
if ( if (!depth || (!pedantic && value.charAt(index + 1) === numberSign)) {
!depth || return
(!settings.pedantic && value.charAt(index + 1) === C_HASH)
) {
return;
} }
length = value.length + 1; length = value.length + 1
/* Eat intermediate white-space. */ // Eat intermediate white-space.
queue = ''; queue = ''
while (++index < length) { while (++index < length) {
character = value.charAt(index); character = value.charAt(index)
if (character !== C_SPACE && character !== C_TAB) { if (character !== space && character !== tab) {
index--; index--
break; break
} }
queue += character; queue += character
} }
/* Exit when not in pedantic mode without spacing. */ // Exit when not in pedantic mode without spacing.
if ( if (!pedantic && queue.length === 0 && character && character !== lineFeed) {
!settings.pedantic && return
queue.length === 0 &&
character &&
character !== C_NEWLINE
) {
return;
} }
if (silent) { if (silent) {
return true; return true
} }
/* Eat content. */ // Eat content.
subvalue += queue; subvalue += queue
queue = ''; queue = ''
content = ''; content = ''
while (++index < length) { while (++index < length) {
character = value.charAt(index); character = value.charAt(index)
if (!character || character === C_NEWLINE) { if (!character || character === lineFeed) {
break; break
} }
if ( if (character !== space && character !== tab && character !== numberSign) {
character !== C_SPACE && content += queue + character
character !== C_TAB && queue = ''
character !== C_HASH continue
) {
content += queue + character;
queue = '';
continue;
} }
while (character === C_SPACE || character === C_TAB) { while (character === space || character === tab) {
queue += character; queue += character
character = value.charAt(++index); character = value.charAt(++index)
} }
while (character === C_HASH) { // `#` without a queue is part of the content.
queue += character; if (!pedantic && content && !queue && character === numberSign) {
character = value.charAt(++index); content += character
continue
} }
while (character === C_SPACE || character === C_TAB) { while (character === numberSign) {
queue += character; queue += character
character = value.charAt(++index); character = value.charAt(++index)
} }
index--; while (character === space || character === tab) {
queue += character
character = value.charAt(++index)
}
index--
} }
now.column += subvalue.length; now.column += subvalue.length
now.offset += subvalue.length; now.offset += subvalue.length
subvalue += content + queue; subvalue += content + queue
return eat(subvalue)({ return eat(subvalue)({
type: 'heading', type: 'heading',
depth: depth, depth: depth,
children: self.tokenizeInline(content, now) children: self.tokenizeInline(content, now)
}); })
} }

View File

@ -1,107 +1,102 @@
'use strict'; 'use strict'
module.exports = setextHeading; module.exports = setextHeading
var C_NEWLINE = '\n'; var lineFeed = '\n'
var C_TAB = '\t'; var tab = '\t'
var C_SPACE = ' '; var space = ' '
var C_EQUALS = '='; var equalsTo = '='
var C_DASH = '-'; var dash = '-'
var MAX_HEADING_INDENT = 3; var maxIndent = 3
/* Map of characters which can be used to mark setext var equalsToDepth = 1
* headers, mapping to their corresponding depth. */ var dashDepth = 2
var SETEXT_MARKERS = {};
SETEXT_MARKERS[C_EQUALS] = 1;
SETEXT_MARKERS[C_DASH] = 2;
function setextHeading(eat, value, silent) { function setextHeading(eat, value, silent) {
var self = this; var self = this
var now = eat.now(); var now = eat.now()
var length = value.length; var length = value.length
var index = -1; var index = -1
var subvalue = ''; var subvalue = ''
var content; var content
var queue; var queue
var character; var character
var marker; var marker
var depth; var depth
/* Eat initial indentation. */ // Eat initial indentation.
while (++index < length) { while (++index < length) {
character = value.charAt(index); character = value.charAt(index)
if (character !== C_SPACE || index >= MAX_HEADING_INDENT) { if (character !== space || index >= maxIndent) {
index--; index--
break; break
} }
subvalue += character; subvalue += character
} }
/* Eat content. */ // Eat content.
content = ''; content = ''
queue = ''; queue = ''
while (++index < length) { while (++index < length) {
character = value.charAt(index); character = value.charAt(index)
if (character === C_NEWLINE) { if (character === lineFeed) {
index--; index--
break; break
} }
if (character === C_SPACE || character === C_TAB) { if (character === space || character === tab) {
queue += character; queue += character
} else { } else {
content += queue + character; content += queue + character
queue = ''; queue = ''
} }
} }
now.column += subvalue.length; now.column += subvalue.length
now.offset += subvalue.length; now.offset += subvalue.length
subvalue += content + queue; subvalue += content + queue
/* Ensure the content is followed by a newline and a // Ensure the content is followed by a newline and a valid marker.
* valid marker. */ character = value.charAt(++index)
character = value.charAt(++index); marker = value.charAt(++index)
marker = value.charAt(++index);
if (character !== C_NEWLINE || !SETEXT_MARKERS[marker]) { if (character !== lineFeed || (marker !== equalsTo && marker !== dash)) {
return; return
} }
subvalue += character; subvalue += character
/* Eat Setext-line. */ // Eat Setext-line.
queue = marker; queue = marker
depth = SETEXT_MARKERS[marker]; depth = marker === equalsTo ? equalsToDepth : dashDepth
while (++index < length) { while (++index < length) {
character = value.charAt(index); character = value.charAt(index)
if (character !== marker) { if (character !== marker) {
if (character !== C_NEWLINE) { if (character !== lineFeed) {
return; return
} }
index--; index--
break; break
} }
queue += character; queue += character
} }
if (silent) { if (silent) {
return true; return true
} }
return eat(subvalue + queue)({ return eat(subvalue + queue)({
type: 'heading', type: 'heading',
depth: depth, depth: depth,
children: self.tokenizeInline(content, now) children: self.tokenizeInline(content, now)
}); })
} }

View File

@ -1,94 +1,111 @@
'use strict'; 'use strict'
var openCloseTag = require('../util/html').openCloseTag; var openCloseTag = require('../util/html').openCloseTag
module.exports = blockHTML; module.exports = blockHtml
var C_TAB = '\t'; var tab = '\t'
var C_SPACE = ' '; var space = ' '
var C_NEWLINE = '\n'; var lineFeed = '\n'
var C_LT = '<'; var lessThan = '<'
function blockHTML(eat, value, silent) { var rawOpenExpression = /^<(script|pre|style)(?=(\s|>|$))/i
var self = this; var rawCloseExpression = /<\/(script|pre|style)>/i
var blocks = self.options.blocks; var commentOpenExpression = /^<!--/
var length = value.length; var commentCloseExpression = /-->/
var index = 0; var instructionOpenExpression = /^<\?/
var next; var instructionCloseExpression = /\?>/
var line; var directiveOpenExpression = /^<![A-Za-z]/
var offset; var directiveCloseExpression = />/
var character; var cdataOpenExpression = /^<!\[CDATA\[/
var count; var cdataCloseExpression = /\]\]>/
var sequence; var elementCloseExpression = /^$/
var subvalue; var otherElementOpenExpression = new RegExp(openCloseTag.source + '\\s*$')
function blockHtml(eat, value, silent) {
var self = this
var blocks = self.options.blocks.join('|')
var elementOpenExpression = new RegExp(
'^</?(' + blocks + ')(?=(\\s|/?>|$))',
'i'
)
var length = value.length
var index = 0
var next
var line
var offset
var character
var count
var sequence
var subvalue
var sequences = [ var sequences = [
[/^<(script|pre|style)(?=(\s|>|$))/i, /<\/(script|pre|style)>/i, true], [rawOpenExpression, rawCloseExpression, true],
[/^<!--/, /-->/, true], [commentOpenExpression, commentCloseExpression, true],
[/^<\?/, /\?>/, true], [instructionOpenExpression, instructionCloseExpression, true],
[/^<![A-Za-z]/, />/, true], [directiveOpenExpression, directiveCloseExpression, true],
[/^<!\[CDATA\[/, /\]\]>/, true], [cdataOpenExpression, cdataCloseExpression, true],
[new RegExp('^</?(' + blocks.join('|') + ')(?=(\\s|/?>|$))', 'i'), /^$/, true], [elementOpenExpression, elementCloseExpression, true],
[new RegExp(openCloseTag.source + '\\s*$'), /^$/, false] [otherElementOpenExpression, elementCloseExpression, false]
]; ]
/* Eat initial spacing. */ // Eat initial spacing.
while (index < length) { while (index < length) {
character = value.charAt(index); character = value.charAt(index)
if (character !== C_TAB && character !== C_SPACE) { if (character !== tab && character !== space) {
break; break
} }
index++; index++
} }
if (value.charAt(index) !== C_LT) { if (value.charAt(index) !== lessThan) {
return; return
} }
next = value.indexOf(C_NEWLINE, index + 1); next = value.indexOf(lineFeed, index + 1)
next = next === -1 ? length : next; next = next === -1 ? length : next
line = value.slice(index, next); line = value.slice(index, next)
offset = -1; offset = -1
count = sequences.length; count = sequences.length
while (++offset < count) { while (++offset < count) {
if (sequences[offset][0].test(line)) { if (sequences[offset][0].test(line)) {
sequence = sequences[offset]; sequence = sequences[offset]
break; break
} }
} }
if (!sequence) { if (!sequence) {
return; return
} }
if (silent) { if (silent) {
return sequence[2]; return sequence[2]
} }
index = next; index = next
if (!sequence[1].test(line)) { if (!sequence[1].test(line)) {
while (index < length) { while (index < length) {
next = value.indexOf(C_NEWLINE, index + 1); next = value.indexOf(lineFeed, index + 1)
next = next === -1 ? length : next; next = next === -1 ? length : next
line = value.slice(index + 1, next); line = value.slice(index + 1, next)
if (sequence[1].test(line)) { if (sequence[1].test(line)) {
if (line) { if (line) {
index = next; index = next
} }
break; break
} }
index = next; index = next
} }
} }
subvalue = value.slice(0, index); subvalue = value.slice(0, index)
return eat(subvalue)({type: 'html', value: subvalue}); return eat(subvalue)({type: 'html', value: subvalue})
} }

View File

@ -1,54 +1,59 @@
'use strict'; 'use strict'
var alphabetical = require('is-alphabetical'); var alphabetical = require('is-alphabetical')
var locate = require('../locate/tag'); var locate = require('../locate/tag')
var tag = require('../util/html').tag; var tag = require('../util/html').tag
module.exports = inlineHTML; module.exports = inlineHTML
inlineHTML.locator = locate; inlineHTML.locator = locate
var EXPRESSION_HTML_LINK_OPEN = /^<a /i; var lessThan = '<'
var EXPRESSION_HTML_LINK_CLOSE = /^<\/a>/i; var questionMark = '?'
var exclamationMark = '!'
var slash = '/'
var htmlLinkOpenExpression = /^<a /i
var htmlLinkCloseExpression = /^<\/a>/i
function inlineHTML(eat, value, silent) { function inlineHTML(eat, value, silent) {
var self = this; var self = this
var length = value.length; var length = value.length
var character; var character
var subvalue; var subvalue
if (value.charAt(0) !== '<' || length < 3) { if (value.charAt(0) !== lessThan || length < 3) {
return; return
} }
character = value.charAt(1); character = value.charAt(1)
if ( if (
!alphabetical(character) && !alphabetical(character) &&
character !== '?' && character !== questionMark &&
character !== '!' && character !== exclamationMark &&
character !== '/' character !== slash
) { ) {
return; return
} }
subvalue = value.match(tag); subvalue = value.match(tag)
if (!subvalue) { if (!subvalue) {
return; return
} }
/* istanbul ignore if - not used yet. */ /* istanbul ignore if - not used yet. */
if (silent) { if (silent) {
return true; return true
} }
subvalue = subvalue[0]; subvalue = subvalue[0]
if (!self.inLink && EXPRESSION_HTML_LINK_OPEN.test(subvalue)) { if (!self.inLink && htmlLinkOpenExpression.test(subvalue)) {
self.inLink = true; self.inLink = true
} else if (self.inLink && EXPRESSION_HTML_LINK_CLOSE.test(subvalue)) { } else if (self.inLink && htmlLinkCloseExpression.test(subvalue)) {
self.inLink = false; self.inLink = false
} }
return eat(subvalue)({type: 'html', value: subvalue}); return eat(subvalue)({type: 'html', value: subvalue})
} }

View File

@ -1,392 +1,381 @@
'use strict'; 'use strict'
var whitespace = require('is-whitespace-character'); var whitespace = require('is-whitespace-character')
var locate = require('../locate/link'); var locate = require('../locate/link')
module.exports = link; module.exports = link
link.locator = locate; link.locator = locate
var own = {}.hasOwnProperty; var lineFeed = '\n'
var exclamationMark = '!'
var C_BACKSLASH = '\\'; var quotationMark = '"'
var C_BRACKET_OPEN = '['; var apostrophe = "'"
var C_BRACKET_CLOSE = ']'; var leftParenthesis = '('
var C_PAREN_OPEN = '('; var rightParenthesis = ')'
var C_PAREN_CLOSE = ')'; var lessThan = '<'
var C_LT = '<'; var greaterThan = '>'
var C_GT = '>'; var leftSquareBracket = '['
var C_TICK = '`'; var backslash = '\\'
var C_DOUBLE_QUOTE = '"'; var rightSquareBracket = ']'
var C_SINGLE_QUOTE = '\''; var graveAccent = '`'
/* Map of characters, which can be used to mark link
* and image titles. */
var LINK_MARKERS = {};
LINK_MARKERS[C_DOUBLE_QUOTE] = C_DOUBLE_QUOTE;
LINK_MARKERS[C_SINGLE_QUOTE] = C_SINGLE_QUOTE;
/* Map of characters, which can be used to mark link
* and image titles in commonmark-mode. */
var COMMONMARK_LINK_MARKERS = {};
COMMONMARK_LINK_MARKERS[C_DOUBLE_QUOTE] = C_DOUBLE_QUOTE;
COMMONMARK_LINK_MARKERS[C_SINGLE_QUOTE] = C_SINGLE_QUOTE;
COMMONMARK_LINK_MARKERS[C_PAREN_OPEN] = C_PAREN_CLOSE;
function link(eat, value, silent) { function link(eat, value, silent) {
var self = this; var self = this
var subvalue = ''; var subvalue = ''
var index = 0; var index = 0
var character = value.charAt(0); var character = value.charAt(0)
var pedantic = self.options.pedantic; var pedantic = self.options.pedantic
var commonmark = self.options.commonmark; var commonmark = self.options.commonmark
var gfm = self.options.gfm; var gfm = self.options.gfm
var closed; var closed
var count; var count
var opening; var opening
var beforeURL; var beforeURL
var beforeTitle; var beforeTitle
var subqueue; var subqueue
var hasMarker; var hasMarker
var markers; var isImage
var isImage; var content
var content; var marker
var marker; var length
var length; var title
var title; var depth
var depth; var queue
var queue; var url
var url; var now
var now; var exit
var exit; var node
var node;
/* Detect whether this is an image. */ // Detect whether this is an image.
if (character === '!') { if (character === exclamationMark) {
isImage = true; isImage = true
subvalue = character; subvalue = character
character = value.charAt(++index); character = value.charAt(++index)
} }
/* Eat the opening. */ // Eat the opening.
if (character !== C_BRACKET_OPEN) { if (character !== leftSquareBracket) {
return; return
} }
/* Exit when this is a link and were already inside // Exit when this is a link and were already inside a link.
* a link. */
if (!isImage && self.inLink) { if (!isImage && self.inLink) {
return; return
} }
subvalue += character; subvalue += character
queue = ''; queue = ''
index++; index++
/* Eat the content. */ // Eat the content.
length = value.length; length = value.length
now = eat.now(); now = eat.now()
depth = 0; depth = 0
now.column += index; now.column += index
now.offset += index; now.offset += index
while (index < length) { while (index < length) {
character = value.charAt(index); character = value.charAt(index)
subqueue = character; subqueue = character
if (character === C_TICK) { if (character === graveAccent) {
/* Inline-code in link content. */ // Inline-code in link content.
count = 1; count = 1
while (value.charAt(index + 1) === C_TICK) { while (value.charAt(index + 1) === graveAccent) {
subqueue += character; subqueue += character
index++; index++
count++; count++
} }
if (!opening) { if (!opening) {
opening = count; opening = count
} else if (count >= opening) { } else if (count >= opening) {
opening = 0; opening = 0
} }
} else if (character === C_BACKSLASH) { } else if (character === backslash) {
/* Allow brackets to be escaped. */ // Allow brackets to be escaped.
index++; index++
subqueue += value.charAt(index); subqueue += value.charAt(index)
/* In GFM mode, brackets in code still count. } else if ((!opening || gfm) && character === leftSquareBracket) {
* In all other modes, they dont. This empty // In GFM mode, brackets in code still count. In all other modes,
* block prevents the next statements are // they dont.
* entered. */ depth++
} else if ((!opening || gfm) && character === C_BRACKET_OPEN) { } else if ((!opening || gfm) && character === rightSquareBracket) {
depth++;
} else if ((!opening || gfm) && character === C_BRACKET_CLOSE) {
if (depth) { if (depth) {
depth--; depth--
} else { } else {
/* Allow white-space between content and // Allow white-space between content and url in GFM mode.
* url in GFM mode. */
if (!pedantic) { if (!pedantic) {
while (index < length) { while (index < length) {
character = value.charAt(index + 1); character = value.charAt(index + 1)
if (!whitespace(character)) { if (!whitespace(character)) {
break; break
} }
subqueue += character; subqueue += character
index++; index++
} }
} }
if (value.charAt(index + 1) !== C_PAREN_OPEN) { if (value.charAt(index + 1) !== leftParenthesis) {
return; return
} }
subqueue += C_PAREN_OPEN; subqueue += leftParenthesis
closed = true; closed = true
index++; index++
break; break
} }
} }
queue += subqueue; queue += subqueue
subqueue = ''; subqueue = ''
index++; index++
} }
/* Eat the content closing. */ // Eat the content closing.
if (!closed) { if (!closed) {
return; return
} }
content = queue; content = queue
subvalue += queue + subqueue; subvalue += queue + subqueue
index++; index++
/* Eat white-space. */ // Eat white-space.
while (index < length) { while (index < length) {
character = value.charAt(index); character = value.charAt(index)
if (!whitespace(character)) { if (!whitespace(character)) {
break; break
} }
subvalue += character; subvalue += character
index++; index++
} }
/* Eat the URL. */ // Eat the URL.
character = value.charAt(index); character = value.charAt(index)
markers = commonmark ? COMMONMARK_LINK_MARKERS : LINK_MARKERS; queue = ''
queue = ''; beforeURL = subvalue
beforeURL = subvalue;
if (character === C_LT) { if (character === lessThan) {
index++; index++
beforeURL += C_LT; beforeURL += lessThan
while (index < length) { while (index < length) {
character = value.charAt(index); character = value.charAt(index)
if (character === C_GT) { if (character === greaterThan) {
break; break
} }
if (commonmark && character === '\n') { if (commonmark && character === lineFeed) {
return; return
} }
queue += character; queue += character
index++; index++
} }
if (value.charAt(index) !== C_GT) { if (value.charAt(index) !== greaterThan) {
return; return
} }
subvalue += C_LT + queue + C_GT; subvalue += lessThan + queue + greaterThan
url = queue; url = queue
index++; index++
} else { } else {
character = null; character = null
subqueue = ''; subqueue = ''
while (index < length) { while (index < length) {
character = value.charAt(index); character = value.charAt(index)
if (subqueue && own.call(markers, character)) { if (
break; subqueue &&
(character === quotationMark ||
character === apostrophe ||
(commonmark && character === leftParenthesis))
) {
break
} }
if (whitespace(character)) { if (whitespace(character)) {
if (!pedantic) { if (!pedantic) {
break; break
} }
subqueue += character; subqueue += character
} else { } else {
if (character === C_PAREN_OPEN) { if (character === leftParenthesis) {
depth++; depth++
} else if (character === C_PAREN_CLOSE) { } else if (character === rightParenthesis) {
if (depth === 0) { if (depth === 0) {
break; break
} }
depth--; depth--
} }
queue += subqueue; queue += subqueue
subqueue = ''; subqueue = ''
if (character === C_BACKSLASH) { if (character === backslash) {
queue += C_BACKSLASH; queue += backslash
character = value.charAt(++index); character = value.charAt(++index)
} }
queue += character; queue += character
} }
index++; index++
} }
subvalue += queue; subvalue += queue
url = queue; url = queue
index = subvalue.length; index = subvalue.length
} }
/* Eat white-space. */ // Eat white-space.
queue = ''; queue = ''
while (index < length) { while (index < length) {
character = value.charAt(index); character = value.charAt(index)
if (!whitespace(character)) { if (!whitespace(character)) {
break; break
} }
queue += character; queue += character
index++; index++
} }
character = value.charAt(index); character = value.charAt(index)
subvalue += queue; subvalue += queue
/* Eat the title. */ // Eat the title.
if (queue && own.call(markers, character)) { if (
index++; queue &&
subvalue += character; (character === quotationMark ||
queue = ''; character === apostrophe ||
marker = markers[character]; (commonmark && character === leftParenthesis))
beforeTitle = subvalue; ) {
index++
subvalue += character
queue = ''
marker = character === leftParenthesis ? rightParenthesis : character
beforeTitle = subvalue
/* In commonmark-mode, things are pretty easy: the // In commonmark-mode, things are pretty easy: the marker cannot occur
* marker cannot occur inside the title. // inside the title. Non-commonmark does, however, support nested
* // delimiters.
* Non-commonmark does, however, support nested
* delimiters. */
if (commonmark) { if (commonmark) {
while (index < length) { while (index < length) {
character = value.charAt(index); character = value.charAt(index)
if (character === marker) { if (character === marker) {
break; break
} }
if (character === C_BACKSLASH) { if (character === backslash) {
queue += C_BACKSLASH; queue += backslash
character = value.charAt(++index); character = value.charAt(++index)
} }
index++; index++
queue += character; queue += character
} }
character = value.charAt(index); character = value.charAt(index)
if (character !== marker) { if (character !== marker) {
return; return
} }
title = queue; title = queue
subvalue += queue + character; subvalue += queue + character
index++; index++
while (index < length) { while (index < length) {
character = value.charAt(index); character = value.charAt(index)
if (!whitespace(character)) { if (!whitespace(character)) {
break; break
} }
subvalue += character; subvalue += character
index++; index++
} }
} else { } else {
subqueue = ''; subqueue = ''
while (index < length) { while (index < length) {
character = value.charAt(index); character = value.charAt(index)
if (character === marker) { if (character === marker) {
if (hasMarker) { if (hasMarker) {
queue += marker + subqueue; queue += marker + subqueue
subqueue = ''; subqueue = ''
} }
hasMarker = true; hasMarker = true
} else if (!hasMarker) { } else if (!hasMarker) {
queue += character; queue += character
} else if (character === C_PAREN_CLOSE) { } else if (character === rightParenthesis) {
subvalue += queue + marker + subqueue; subvalue += queue + marker + subqueue
title = queue; title = queue
break; break
} else if (whitespace(character)) { } else if (whitespace(character)) {
subqueue += character; subqueue += character
} else { } else {
queue += marker + subqueue + character; queue += marker + subqueue + character
subqueue = ''; subqueue = ''
hasMarker = false; hasMarker = false
} }
index++; index++
} }
} }
} }
if (value.charAt(index) !== C_PAREN_CLOSE) { if (value.charAt(index) !== rightParenthesis) {
return; return
} }
/* istanbul ignore if - never used (yet) */ /* istanbul ignore if - never used (yet) */
if (silent) { if (silent) {
return true; return true
} }
subvalue += C_PAREN_CLOSE; subvalue += rightParenthesis
url = self.decode.raw(self.unescape(url), eat(beforeURL).test().end, {nonTerminated: false}); url = self.decode.raw(self.unescape(url), eat(beforeURL).test().end, {
nonTerminated: false
})
if (title) { if (title) {
beforeTitle = eat(beforeTitle).test().end; beforeTitle = eat(beforeTitle).test().end
title = self.decode.raw(self.unescape(title), beforeTitle); title = self.decode.raw(self.unescape(title), beforeTitle)
} }
node = { node = {
type: isImage ? 'image' : 'link', type: isImage ? 'image' : 'link',
title: title || null, title: title || null,
url: url url: url
};
if (isImage) {
node.alt = self.decode.raw(self.unescape(content), now) || null;
} else {
exit = self.enterLink();
node.children = self.tokenizeInline(content, now);
exit();
} }
return eat(subvalue)(node); if (isImage) {
node.alt = self.decode.raw(self.unescape(content), now) || null
} else {
exit = self.enterLink()
node.children = self.tokenizeInline(content, now)
exit()
}
return eat(subvalue)(node)
} }

View File

@ -1,474 +1,451 @@
'use strict'; 'use strict'
/* eslint-disable max-params */ var trim = require('trim')
var repeat = require('repeat-string')
var decimal = require('is-decimal')
var getIndent = require('../util/get-indentation')
var removeIndent = require('../util/remove-indentation')
var interrupt = require('../util/interrupt')
var trim = require('trim'); module.exports = list
var repeat = require('repeat-string');
var decimal = require('is-decimal');
var getIndent = require('../util/get-indentation');
var removeIndent = require('../util/remove-indentation');
var interrupt = require('../util/interrupt');
module.exports = list; var asterisk = '*'
var underscore = '_'
var plusSign = '+'
var dash = '-'
var dot = '.'
var space = ' '
var lineFeed = '\n'
var tab = '\t'
var rightParenthesis = ')'
var lowercaseX = 'x'
var C_ASTERISK = '*'; var tabSize = 4
var C_UNDERSCORE = '_'; var looseListItemExpression = /\n\n(?!\s*$)/
var C_PLUS = '+'; var taskItemExpression = /^\[([ \t]|x|X)][ \t]/
var C_DASH = '-'; var bulletExpression = /^([ \t]*)([*+-]|\d+[.)])( {1,4}(?! )| |\t|$|(?=\n))([^\n]*)/
var C_DOT = '.'; var pedanticBulletExpression = /^([ \t]*)([*+-]|\d+[.)])([ \t]+)/
var C_SPACE = ' '; var initialIndentExpression = /^( {1,4}|\t)?/gm
var C_NEWLINE = '\n';
var C_TAB = '\t';
var C_PAREN_CLOSE = ')';
var C_X_LOWER = 'x';
var TAB_SIZE = 4;
var EXPRESSION_LOOSE_LIST_ITEM = /\n\n(?!\s*$)/;
var EXPRESSION_TASK_ITEM = /^\[([ \t]|x|X)][ \t]/;
var EXPRESSION_BULLET = /^([ \t]*)([*+-]|\d+[.)])( {1,4}(?! )| |\t|$|(?=\n))([^\n]*)/;
var EXPRESSION_PEDANTIC_BULLET = /^([ \t]*)([*+-]|\d+[.)])([ \t]+)/;
var EXPRESSION_INITIAL_INDENT = /^( {1,4}|\t)?/gm;
/* Map of characters which can be used to mark
* list-items. */
var LIST_UNORDERED_MARKERS = {};
LIST_UNORDERED_MARKERS[C_ASTERISK] = true;
LIST_UNORDERED_MARKERS[C_PLUS] = true;
LIST_UNORDERED_MARKERS[C_DASH] = true;
/* Map of characters which can be used to mark
* list-items after a digit. */
var LIST_ORDERED_MARKERS = {};
LIST_ORDERED_MARKERS[C_DOT] = true;
/* Map of characters which can be used to mark
* list-items after a digit. */
var LIST_ORDERED_COMMONMARK_MARKERS = {};
LIST_ORDERED_COMMONMARK_MARKERS[C_DOT] = true;
LIST_ORDERED_COMMONMARK_MARKERS[C_PAREN_CLOSE] = true;
function list(eat, value, silent) { function list(eat, value, silent) {
var self = this; var self = this
var commonmark = self.options.commonmark; var commonmark = self.options.commonmark
var pedantic = self.options.pedantic; var pedantic = self.options.pedantic
var tokenizers = self.blockTokenizers; var tokenizers = self.blockTokenizers
var interuptors = self.interruptList; var interuptors = self.interruptList
var markers; var index = 0
var index = 0; var length = value.length
var length = value.length; var start = null
var start = null; var size = 0
var size = 0; var queue
var queue; var ordered
var ordered; var character
var character; var marker
var marker; var nextIndex
var nextIndex; var startIndex
var startIndex; var prefixed
var prefixed; var currentMarker
var currentMarker; var content
var content; var line
var line; var prevEmpty
var prevEmpty; var empty
var empty; var items
var items; var allLines
var allLines; var emptyLines
var emptyLines; var item
var item; var enterTop
var enterTop; var exitBlockquote
var exitBlockquote; var spread = false
var isLoose; var node
var node; var now
var now; var end
var end; var indented
var indented;
while (index < length) { while (index < length) {
character = value.charAt(index); character = value.charAt(index)
if (character === C_TAB) { if (character === tab) {
size += TAB_SIZE - (size % TAB_SIZE); size += tabSize - (size % tabSize)
} else if (character === C_SPACE) { } else if (character === space) {
size++; size++
} else { } else {
break; break
} }
index++; index++
} }
if (size >= TAB_SIZE) { if (size >= tabSize) {
return; return
} }
character = value.charAt(index); character = value.charAt(index)
markers = commonmark ? if (character === asterisk || character === plusSign || character === dash) {
LIST_ORDERED_COMMONMARK_MARKERS : marker = character
LIST_ORDERED_MARKERS; ordered = false
if (LIST_UNORDERED_MARKERS[character] === true) {
marker = character;
ordered = false;
} else { } else {
ordered = true; ordered = true
queue = ''; queue = ''
while (index < length) { while (index < length) {
character = value.charAt(index); character = value.charAt(index)
if (!decimal(character)) { if (!decimal(character)) {
break; break
} }
queue += character; queue += character
index++; index++
} }
character = value.charAt(index); character = value.charAt(index)
if (!queue || markers[character] !== true) { if (
return; !queue ||
!(character === dot || (commonmark && character === rightParenthesis))
) {
return
} }
start = parseInt(queue, 10); start = parseInt(queue, 10)
marker = character; marker = character
} }
character = value.charAt(++index); character = value.charAt(++index)
if (character !== C_SPACE && character !== C_TAB) { if (
return; character !== space &&
character !== tab &&
(pedantic || (character !== lineFeed && character !== ''))
) {
return
} }
if (silent) { if (silent) {
return true; return true
} }
index = 0; index = 0
items = []; items = []
allLines = []; allLines = []
emptyLines = []; emptyLines = []
while (index < length) { while (index < length) {
nextIndex = value.indexOf(C_NEWLINE, index); nextIndex = value.indexOf(lineFeed, index)
startIndex = index; startIndex = index
prefixed = false; prefixed = false
indented = false; indented = false
if (nextIndex === -1) { if (nextIndex === -1) {
nextIndex = length; nextIndex = length
} }
end = index + TAB_SIZE; end = index + tabSize
size = 0; size = 0
while (index < length) { while (index < length) {
character = value.charAt(index); character = value.charAt(index)
if (character === C_TAB) { if (character === tab) {
size += TAB_SIZE - (size % TAB_SIZE); size += tabSize - (size % tabSize)
} else if (character === C_SPACE) { } else if (character === space) {
size++; size++
} else { } else {
break; break
} }
index++; index++
} }
if (size >= TAB_SIZE) { if (size >= tabSize) {
indented = true; indented = true
} }
if (item && size >= item.indent) { if (item && size >= item.indent) {
indented = true; indented = true
} }
character = value.charAt(index); character = value.charAt(index)
currentMarker = null; currentMarker = null
if (!indented) { if (!indented) {
if (LIST_UNORDERED_MARKERS[character] === true) { if (
currentMarker = character; character === asterisk ||
index++; character === plusSign ||
size++; character === dash
) {
currentMarker = character
index++
size++
} else { } else {
queue = ''; queue = ''
while (index < length) { while (index < length) {
character = value.charAt(index); character = value.charAt(index)
if (!decimal(character)) { if (!decimal(character)) {
break; break
} }
queue += character; queue += character
index++; index++
} }
character = value.charAt(index); character = value.charAt(index)
index++; index++
if (queue && markers[character] === true) { if (
currentMarker = character; queue &&
size += queue.length + 1; (character === dot || (commonmark && character === rightParenthesis))
) {
currentMarker = character
size += queue.length + 1
} }
} }
if (currentMarker) { if (currentMarker) {
character = value.charAt(index); character = value.charAt(index)
if (character === C_TAB) { if (character === tab) {
size += TAB_SIZE - (size % TAB_SIZE); size += tabSize - (size % tabSize)
index++; index++
} else if (character === C_SPACE) { } else if (character === space) {
end = index + TAB_SIZE; end = index + tabSize
while (index < end) { while (index < end) {
if (value.charAt(index) !== C_SPACE) { if (value.charAt(index) !== space) {
break; break
} }
index++; index++
size++; size++
} }
if (index === end && value.charAt(index) === C_SPACE) { if (index === end && value.charAt(index) === space) {
index -= TAB_SIZE - 1; index -= tabSize - 1
size -= TAB_SIZE - 1; size -= tabSize - 1
} }
} else if (character !== C_NEWLINE && character !== '') { } else if (character !== lineFeed && character !== '') {
currentMarker = null; currentMarker = null
} }
} }
} }
if (currentMarker) { if (currentMarker) {
if (!pedantic && marker !== currentMarker) { if (!pedantic && marker !== currentMarker) {
break; break
} }
prefixed = true; prefixed = true
} else { } else {
if (!commonmark && !indented && value.charAt(startIndex) === C_SPACE) { if (!commonmark && !indented && value.charAt(startIndex) === space) {
indented = true; indented = true
} else if (commonmark && item) { } else if (commonmark && item) {
indented = size >= item.indent || size > TAB_SIZE; indented = size >= item.indent || size > tabSize
} }
prefixed = false; prefixed = false
index = startIndex; index = startIndex
} }
line = value.slice(startIndex, nextIndex); line = value.slice(startIndex, nextIndex)
content = startIndex === index ? line : value.slice(index, nextIndex); content = startIndex === index ? line : value.slice(index, nextIndex)
if ( if (
currentMarker === C_ASTERISK || currentMarker === asterisk ||
currentMarker === C_UNDERSCORE || currentMarker === underscore ||
currentMarker === C_DASH currentMarker === dash
) { ) {
if (tokenizers.thematicBreak.call(self, eat, line, true)) { if (tokenizers.thematicBreak.call(self, eat, line, true)) {
break; break
} }
} }
prevEmpty = empty; prevEmpty = empty
empty = !trim(content).length; empty = !prefixed && !trim(content).length
if (indented && item) { if (indented && item) {
item.value = item.value.concat(emptyLines, line); item.value = item.value.concat(emptyLines, line)
allLines = allLines.concat(emptyLines, line); allLines = allLines.concat(emptyLines, line)
emptyLines = []; emptyLines = []
} else if (prefixed) { } else if (prefixed) {
if (emptyLines.length !== 0) { if (emptyLines.length !== 0) {
item.value.push(''); spread = true
item.trail = emptyLines.concat(); item.value.push('')
item.trail = emptyLines.concat()
} }
item = { item = {
value: [line], value: [line],
indent: size, indent: size,
trail: [] trail: []
};
items.push(item);
allLines = allLines.concat(emptyLines, line);
emptyLines = [];
} else if (empty) {
if (prevEmpty) {
break;
} }
emptyLines.push(line); items.push(item)
allLines = allLines.concat(emptyLines, line)
emptyLines = []
} else if (empty) {
if (prevEmpty && !commonmark) {
break
}
emptyLines.push(line)
} else { } else {
if (prevEmpty) { if (prevEmpty) {
break; break
} }
if (interrupt(interuptors, tokenizers, self, [eat, line, true])) { if (interrupt(interuptors, tokenizers, self, [eat, line, true])) {
break; break
} }
item.value = item.value.concat(emptyLines, line); item.value = item.value.concat(emptyLines, line)
allLines = allLines.concat(emptyLines, line); allLines = allLines.concat(emptyLines, line)
emptyLines = []; emptyLines = []
} }
index = nextIndex + 1; index = nextIndex + 1
} }
node = eat(allLines.join(C_NEWLINE)).reset({ node = eat(allLines.join(lineFeed)).reset({
type: 'list', type: 'list',
ordered: ordered, ordered: ordered,
start: start, start: start,
loose: null, spread: spread,
children: [] children: []
}); })
enterTop = self.enterList(); enterTop = self.enterList()
exitBlockquote = self.enterBlock(); exitBlockquote = self.enterBlock()
isLoose = false; index = -1
index = -1; length = items.length
length = items.length;
while (++index < length) { while (++index < length) {
item = items[index].value.join(C_NEWLINE); item = items[index].value.join(lineFeed)
now = eat.now(); now = eat.now()
item = eat(item)(listItem(self, item, now), node); eat(item)(listItem(self, item, now), node)
if (item.loose) { item = items[index].trail.join(lineFeed)
isLoose = true;
}
item = items[index].trail.join(C_NEWLINE);
if (index !== length - 1) { if (index !== length - 1) {
item += C_NEWLINE; item += lineFeed
} }
eat(item); eat(item)
} }
enterTop(); enterTop()
exitBlockquote(); exitBlockquote()
node.loose = isLoose; return node
return node;
} }
function listItem(ctx, value, position) { function listItem(ctx, value, position) {
var offsets = ctx.offset; var offsets = ctx.offset
var fn = ctx.options.pedantic ? pedanticListItem : normalListItem; var fn = ctx.options.pedantic ? pedanticListItem : normalListItem
var checked = null; var checked = null
var task; var task
var indent; var indent
value = fn.apply(null, arguments); value = fn.apply(null, arguments)
if (ctx.options.gfm) { if (ctx.options.gfm) {
task = value.match(EXPRESSION_TASK_ITEM); task = value.match(taskItemExpression)
if (task) { if (task) {
indent = task[0].length; indent = task[0].length
checked = task[1].toLowerCase() === C_X_LOWER; checked = task[1].toLowerCase() === lowercaseX
offsets[position.line] += indent; offsets[position.line] += indent
value = value.slice(indent); value = value.slice(indent)
} }
} }
return { return {
type: 'listItem', type: 'listItem',
loose: EXPRESSION_LOOSE_LIST_ITEM.test(value) || spread: looseListItemExpression.test(value),
value.charAt(value.length - 1) === C_NEWLINE,
checked: checked, checked: checked,
children: ctx.tokenizeBlock(value, position) children: ctx.tokenizeBlock(value, position)
};
}
/* Create a list-item using overly simple mechanics. */
function pedanticListItem(ctx, value, position) {
var offsets = ctx.offset;
var line = position.line;
/* Remove the list-items bullet. */
value = value.replace(EXPRESSION_PEDANTIC_BULLET, replacer);
/* The initial line was also matched by the below, so
* we reset the `line`. */
line = position.line;
return value.replace(EXPRESSION_INITIAL_INDENT, replacer);
/* A simple replacer which removed all matches,
* and adds their length to `offset`. */
function replacer($0) {
offsets[line] = (offsets[line] || 0) + $0.length;
line++;
return '';
} }
} }
/* Create a list-item using sane mechanics. */ // Create a list-item using overly simple mechanics.
function pedanticListItem(ctx, value, position) {
var offsets = ctx.offset
var line = position.line
// Remove the list-items bullet.
value = value.replace(pedanticBulletExpression, replacer)
// The initial line was also matched by the below, so we reset the `line`.
line = position.line
return value.replace(initialIndentExpression, replacer)
// A simple replacer which removed all matches, and adds their length to
// `offset`.
function replacer($0) {
offsets[line] = (offsets[line] || 0) + $0.length
line++
return ''
}
}
// Create a list-item using sane mechanics.
function normalListItem(ctx, value, position) { function normalListItem(ctx, value, position) {
var offsets = ctx.offset; var offsets = ctx.offset
var line = position.line; var line = position.line
var max; var max
var bullet; var bullet
var rest; var rest
var lines; var lines
var trimmedLines; var trimmedLines
var index; var index
var length; var length
/* Remove the list-items bullet. */ // Remove the list-items bullet.
value = value.replace(EXPRESSION_BULLET, replacer); value = value.replace(bulletExpression, replacer)
lines = value.split(C_NEWLINE); lines = value.split(lineFeed)
trimmedLines = removeIndent(value, getIndent(max).indent).split(C_NEWLINE); trimmedLines = removeIndent(value, getIndent(max).indent).split(lineFeed)
/* We replaced the initial bullet with something // We replaced the initial bullet with something else above, which was used
* else above, which was used to trick // to trick `removeIndentation` into removing some more characters when
* `removeIndentation` into removing some more // possible. However, that could result in the initial line to be stripped
* characters when possible. However, that could // more than it should be.
* result in the initial line to be stripped more trimmedLines[0] = rest
* than it should be. */
trimmedLines[0] = rest;
offsets[line] = (offsets[line] || 0) + bullet.length; offsets[line] = (offsets[line] || 0) + bullet.length
line++; line++
index = 0; index = 0
length = lines.length; length = lines.length
while (++index < length) { while (++index < length) {
offsets[line] = (offsets[line] || 0) + offsets[line] =
lines[index].length - trimmedLines[index].length; (offsets[line] || 0) + lines[index].length - trimmedLines[index].length
line++; line++
} }
return trimmedLines.join(C_NEWLINE); return trimmedLines.join(lineFeed)
/* eslint-disable-next-line max-params */
function replacer($0, $1, $2, $3, $4) { function replacer($0, $1, $2, $3, $4) {
bullet = $1 + $2 + $3; bullet = $1 + $2 + $3
rest = $4; rest = $4
/* Make sure that the first nine numbered list items // Make sure that the first nine numbered list items can indent with an
* can indent with an extra space. That is, when // extra space. That is, when the bullet did not receive an extra final
* the bullet did not receive an extra final space. */ // space.
if (Number($2) < 10 && bullet.length % 2 === 1) { if (Number($2) < 10 && bullet.length % 2 === 1) {
$2 = C_SPACE + $2; $2 = space + $2
} }
max = $1 + repeat(C_SPACE, $2.length) + $3; max = $1 + repeat(space, $2.length) + $3
return max + rest; return max + rest
} }
} }

View File

@ -1,47 +1,48 @@
'use strict'; 'use strict'
var whitespace = require('is-whitespace-character'); var whitespace = require('is-whitespace-character')
module.exports = newline; module.exports = newline
var lineFeed = '\n'
/* Tokenise newline. */
function newline(eat, value, silent) { function newline(eat, value, silent) {
var character = value.charAt(0); var character = value.charAt(0)
var length; var length
var subvalue; var subvalue
var queue; var queue
var index; var index
if (character !== '\n') { if (character !== lineFeed) {
return; return
} }
/* istanbul ignore if - never used (yet) */ /* istanbul ignore if - never used (yet) */
if (silent) { if (silent) {
return true; return true
} }
index = 1; index = 1
length = value.length; length = value.length
subvalue = character; subvalue = character
queue = ''; queue = ''
while (index < length) { while (index < length) {
character = value.charAt(index); character = value.charAt(index)
if (!whitespace(character)) { if (!whitespace(character)) {
break; break
} }
queue += character; queue += character
if (character === '\n') { if (character === lineFeed) {
subvalue += queue; subvalue += queue
queue = ''; queue = ''
} }
index++; index++
} }
eat(subvalue); eat(subvalue)
} }

View File

@ -1,122 +1,117 @@
'use strict'; 'use strict'
var trim = require('trim'); var trim = require('trim')
var decimal = require('is-decimal'); var decimal = require('is-decimal')
var trimTrailingLines = require('trim-trailing-lines'); var trimTrailingLines = require('trim-trailing-lines')
var interrupt = require('../util/interrupt'); var interrupt = require('../util/interrupt')
module.exports = paragraph; module.exports = paragraph
var C_NEWLINE = '\n'; var tab = '\t'
var C_TAB = '\t'; var lineFeed = '\n'
var C_SPACE = ' '; var space = ' '
var TAB_SIZE = 4; var tabSize = 4
/* Tokenise paragraph. */ // Tokenise paragraph.
function paragraph(eat, value, silent) { function paragraph(eat, value, silent) {
var self = this; var self = this
var settings = self.options; var settings = self.options
var commonmark = settings.commonmark; var commonmark = settings.commonmark
var gfm = settings.gfm; var gfm = settings.gfm
var tokenizers = self.blockTokenizers; var tokenizers = self.blockTokenizers
var interruptors = self.interruptParagraph; var interruptors = self.interruptParagraph
var index = value.indexOf(C_NEWLINE); var index = value.indexOf(lineFeed)
var length = value.length; var length = value.length
var position; var position
var subvalue; var subvalue
var character; var character
var size; var size
var now; var now
while (index < length) { while (index < length) {
/* Eat everything if theres no following newline. */ // Eat everything if theres no following newline.
if (index === -1) { if (index === -1) {
index = length; index = length
break; break
} }
/* Stop if the next character is NEWLINE. */ // Stop if the next character is NEWLINE.
if (value.charAt(index + 1) === C_NEWLINE) { if (value.charAt(index + 1) === lineFeed) {
break; break
} }
/* In commonmark-mode, following indented lines // In commonmark-mode, following indented lines are part of the paragraph.
* are part of the paragraph. */
if (commonmark) { if (commonmark) {
size = 0; size = 0
position = index + 1; position = index + 1
while (position < length) { while (position < length) {
character = value.charAt(position); character = value.charAt(position)
if (character === C_TAB) { if (character === tab) {
size = TAB_SIZE; size = tabSize
break; break
} else if (character === C_SPACE) { } else if (character === space) {
size++; size++
} else { } else {
break; break
} }
position++; position++
} }
if (size >= TAB_SIZE) { if (size >= tabSize && character !== lineFeed) {
index = value.indexOf(C_NEWLINE, index + 1); index = value.indexOf(lineFeed, index + 1)
continue; continue
} }
} }
subvalue = value.slice(index + 1); subvalue = value.slice(index + 1)
/* Check if the following code contains a possible // Check if the following code contains a possible block.
* block. */
if (interrupt(interruptors, tokenizers, self, [eat, subvalue, true])) { if (interrupt(interruptors, tokenizers, self, [eat, subvalue, true])) {
break; break
} }
/* Break if the following line starts a list, when // Break if the following line starts a list, when already in a list, or
* already in a list, or when in commonmark, or when // when in commonmark, or when in gfm mode and the bullet is *not* numeric.
* in gfm mode and the bullet is *not* numeric. */
if ( if (
tokenizers.list.call(self, eat, subvalue, true) && tokenizers.list.call(self, eat, subvalue, true) &&
( (self.inList ||
self.inList ||
commonmark || commonmark ||
(gfm && !decimal(trim.left(subvalue).charAt(0))) (gfm && !decimal(trim.left(subvalue).charAt(0))))
)
) { ) {
break; break
} }
position = index; position = index
index = value.indexOf(C_NEWLINE, index + 1); index = value.indexOf(lineFeed, index + 1)
if (index !== -1 && trim(value.slice(position, index)) === '') { if (index !== -1 && trim(value.slice(position, index)) === '') {
index = position; index = position
break; break
} }
} }
subvalue = value.slice(0, index); subvalue = value.slice(0, index)
if (trim(subvalue) === '') { if (trim(subvalue) === '') {
eat(subvalue); eat(subvalue)
return null; return null
} }
/* istanbul ignore if - never used (yet) */ /* istanbul ignore if - never used (yet) */
if (silent) { if (silent) {
return true; return true
} }
now = eat.now(); now = eat.now()
subvalue = trimTrailingLines(subvalue); subvalue = trimTrailingLines(subvalue)
return eat(subvalue)({ return eat(subvalue)({
type: 'paragraph', type: 'paragraph',
children: self.tokenizeInline(subvalue, now) children: self.tokenizeInline(subvalue, now)
}); })
} }

View File

@ -1,206 +1,221 @@
'use strict'; 'use strict'
var whitespace = require('is-whitespace-character'); var whitespace = require('is-whitespace-character')
var locate = require('../locate/link'); var locate = require('../locate/link')
var normalize = require('../util/normalize'); var normalize = require('../util/normalize')
module.exports = reference; module.exports = reference
reference.locator = locate; reference.locator = locate
var T_LINK = 'link'; var link = 'link'
var T_IMAGE = 'image'; var image = 'image'
var T_FOOTNOTE = 'footnote'; var footnote = 'footnote'
var REFERENCE_TYPE_SHORTCUT = 'shortcut'; var shortcut = 'shortcut'
var REFERENCE_TYPE_COLLAPSED = 'collapsed'; var collapsed = 'collapsed'
var REFERENCE_TYPE_FULL = 'full'; var full = 'full'
var C_CARET = '^'; var space = ' '
var C_BACKSLASH = '\\'; var exclamationMark = '!'
var C_BRACKET_OPEN = '['; var leftSquareBracket = '['
var C_BRACKET_CLOSE = ']'; var backslash = '\\'
var rightSquareBracket = ']'
var caret = '^'
function reference(eat, value, silent) { function reference(eat, value, silent) {
var self = this; var self = this
var character = value.charAt(0); var commonmark = self.options.commonmark
var index = 0; var footnotes = self.options.footnotes
var length = value.length; var character = value.charAt(0)
var subvalue = ''; var index = 0
var intro = ''; var length = value.length
var type = T_LINK; var subvalue = ''
var referenceType = REFERENCE_TYPE_SHORTCUT; var intro = ''
var content; var type = link
var identifier; var referenceType = shortcut
var now; var content
var node; var identifier
var exit; var now
var queue; var node
var bracketed; var exit
var depth; var queue
var bracketed
var depth
/* Check whether were eating an image. */ // Check whether were eating an image.
if (character === '!') { if (character === exclamationMark) {
type = T_IMAGE; type = image
intro = character; intro = character
character = value.charAt(++index); character = value.charAt(++index)
} }
if (character !== C_BRACKET_OPEN) { if (character !== leftSquareBracket) {
return; return
} }
index++; index++
intro += character; intro += character
queue = ''; queue = ''
/* Check whether were eating a footnote. */ // Check whether were eating a footnote.
if (self.options.footnotes && value.charAt(index) === C_CARET) { if (footnotes && value.charAt(index) === caret) {
/* Exit if `![^` is found, so the `!` will be seen as text after this, // Exit if `![^` is found, so the `!` will be seen as text after this,
* and well enter this function again when `[^` is found. */ // and well enter this function again when `[^` is found.
if (type === T_IMAGE) { if (type === image) {
return; return
} }
intro += C_CARET; intro += caret
index++; index++
type = T_FOOTNOTE; type = footnote
} }
/* Eat the text. */ // Eat the text.
depth = 0; depth = 0
while (index < length) { while (index < length) {
character = value.charAt(index); character = value.charAt(index)
if (character === C_BRACKET_OPEN) { if (character === leftSquareBracket) {
bracketed = true; bracketed = true
depth++; depth++
} else if (character === C_BRACKET_CLOSE) { } else if (character === rightSquareBracket) {
if (!depth) { if (!depth) {
break; break
} }
depth--; depth--
} }
if (character === C_BACKSLASH) { if (character === backslash) {
queue += C_BACKSLASH; queue += backslash
character = value.charAt(++index); character = value.charAt(++index)
} }
queue += character; queue += character
index++; index++
} }
subvalue = queue; subvalue = queue
content = queue; content = queue
character = value.charAt(index); character = value.charAt(index)
if (character !== C_BRACKET_CLOSE) { if (character !== rightSquareBracket) {
return; return
} }
index++; index++
subvalue += character; subvalue += character
queue = ''; queue = ''
while (index < length) { if (!commonmark) {
character = value.charAt(index); // The original markdown syntax definition explicitly allows for whitespace
// between the link text and link label; commonmark departs from this, in
// part to improve support for shortcut reference links
while (index < length) {
character = value.charAt(index)
if (!whitespace(character)) { if (!whitespace(character)) {
break; break
}
queue += character
index++
} }
queue += character;
index++;
} }
character = value.charAt(index); character = value.charAt(index)
/* Inline footnotes cannot have an identifier. */ // Inline footnotes cannot have a label.
if (type !== T_FOOTNOTE && character === C_BRACKET_OPEN) { // If footnotes are enabled, link labels cannot start with a caret.
identifier = ''; if (
queue += character; type !== footnote &&
index++; character === leftSquareBracket &&
(!footnotes || value.charAt(index + 1) !== caret)
) {
identifier = ''
queue += character
index++
while (index < length) { while (index < length) {
character = value.charAt(index); character = value.charAt(index)
if (character === C_BRACKET_OPEN || character === C_BRACKET_CLOSE) { if (character === leftSquareBracket || character === rightSquareBracket) {
break; break
} }
if (character === C_BACKSLASH) { if (character === backslash) {
identifier += C_BACKSLASH; identifier += backslash
character = value.charAt(++index); character = value.charAt(++index)
} }
identifier += character; identifier += character
index++; index++
} }
character = value.charAt(index); character = value.charAt(index)
if (character === C_BRACKET_CLOSE) { if (character === rightSquareBracket) {
referenceType = identifier ? REFERENCE_TYPE_FULL : REFERENCE_TYPE_COLLAPSED; referenceType = identifier ? full : collapsed
queue += identifier + character; queue += identifier + character
index++; index++
} else { } else {
identifier = ''; identifier = ''
} }
subvalue += queue; subvalue += queue
queue = ''; queue = ''
} else { } else {
if (!content) { if (!content) {
return; return
} }
identifier = content; identifier = content
} }
/* Brackets cannot be inside the identifier. */ // Brackets cannot be inside the identifier.
if (referenceType !== REFERENCE_TYPE_FULL && bracketed) { if (referenceType !== full && bracketed) {
return; return
} }
subvalue = intro + subvalue; subvalue = intro + subvalue
if (type === T_LINK && self.inLink) { if (type === link && self.inLink) {
return null; return null
} }
/* istanbul ignore if - never used (yet) */ /* istanbul ignore if - never used (yet) */
if (silent) { if (silent) {
return true; return true
} }
if (type === T_FOOTNOTE && content.indexOf(' ') !== -1) { if (type === footnote && content.indexOf(space) !== -1) {
return eat(subvalue)({ return eat(subvalue)({
type: 'footnote', type: footnote,
children: this.tokenizeInline(content, eat.now()) children: this.tokenizeInline(content, eat.now())
}); })
} }
now = eat.now(); now = eat.now()
now.column += intro.length; now.column += intro.length
now.offset += intro.length; now.offset += intro.length
identifier = referenceType === REFERENCE_TYPE_FULL ? identifier : content; identifier = referenceType === full ? identifier : content
node = { node = {
type: type + 'Reference', type: type + 'Reference',
identifier: normalize(identifier) identifier: normalize(identifier),
}; label: identifier
if (type === T_LINK || type === T_IMAGE) {
node.referenceType = referenceType;
} }
if (type === T_LINK) { if (type === link || type === image) {
exit = self.enterLink(); node.referenceType = referenceType
node.children = self.tokenizeInline(content, now);
exit();
} else if (type === T_IMAGE) {
node.alt = self.decode.raw(self.unescape(content), now) || null;
} }
return eat(subvalue)(node); if (type === link) {
exit = self.enterLink()
node.children = self.tokenizeInline(content, now)
exit()
} else if (type === image) {
node.alt = self.decode.raw(self.unescape(content), now) || null
}
return eat(subvalue)(node)
} }

View File

@ -1,84 +1,85 @@
'use strict'; 'use strict'
var trim = require('trim'); var trim = require('trim')
var whitespace = require('is-whitespace-character'); var whitespace = require('is-whitespace-character')
var locate = require('../locate/strong'); var locate = require('../locate/strong')
module.exports = strong; module.exports = strong
strong.locator = locate; strong.locator = locate
var C_ASTERISK = '*'; var backslash = '\\'
var C_UNDERSCORE = '_'; var asterisk = '*'
var underscore = '_'
function strong(eat, value, silent) { function strong(eat, value, silent) {
var self = this; var self = this
var index = 0; var index = 0
var character = value.charAt(index); var character = value.charAt(index)
var now; var now
var pedantic; var pedantic
var marker; var marker
var queue; var queue
var subvalue; var subvalue
var length; var length
var prev; var prev
if ( if (
(character !== C_ASTERISK && character !== C_UNDERSCORE) || (character !== asterisk && character !== underscore) ||
value.charAt(++index) !== character value.charAt(++index) !== character
) { ) {
return; return
} }
pedantic = self.options.pedantic; pedantic = self.options.pedantic
marker = character; marker = character
subvalue = marker + marker; subvalue = marker + marker
length = value.length; length = value.length
index++; index++
queue = ''; queue = ''
character = ''; character = ''
if (pedantic && whitespace(value.charAt(index))) { if (pedantic && whitespace(value.charAt(index))) {
return; return
} }
while (index < length) { while (index < length) {
prev = character; prev = character
character = value.charAt(index); character = value.charAt(index)
if ( if (
character === marker && character === marker &&
value.charAt(index + 1) === marker && value.charAt(index + 1) === marker &&
(!pedantic || !whitespace(prev)) (!pedantic || !whitespace(prev))
) { ) {
character = value.charAt(index + 2); character = value.charAt(index + 2)
if (character !== marker) { if (character !== marker) {
if (!trim(queue)) { if (!trim(queue)) {
return; return
} }
/* istanbul ignore if - never used (yet) */ /* istanbul ignore if - never used (yet) */
if (silent) { if (silent) {
return true; return true
} }
now = eat.now(); now = eat.now()
now.column += 2; now.column += 2
now.offset += 2; now.offset += 2
return eat(subvalue + queue + subvalue)({ return eat(subvalue + queue + subvalue)({
type: 'strong', type: 'strong',
children: self.tokenizeInline(queue, now) children: self.tokenizeInline(queue, now)
}); })
} }
} }
if (!pedantic && character === '\\') { if (!pedantic && character === backslash) {
queue += character; queue += character
character = value.charAt(++index); character = value.charAt(++index)
} }
queue += character; queue += character
index++; index++
} }
} }

View File

@ -1,266 +1,232 @@
'use strict'; 'use strict'
var whitespace = require('is-whitespace-character'); var whitespace = require('is-whitespace-character')
module.exports = table; module.exports = table
var C_BACKSLASH = '\\'; var tab = '\t'
var C_TICK = '`'; var lineFeed = '\n'
var C_DASH = '-'; var space = ' '
var C_PIPE = '|'; var dash = '-'
var C_COLON = ':'; var colon = ':'
var C_SPACE = ' '; var backslash = '\\'
var C_NEWLINE = '\n'; var verticalBar = '|'
var C_TAB = '\t';
var MIN_TABLE_COLUMNS = 1; var minColumns = 1
var MIN_TABLE_ROWS = 2; var minRows = 2
var TABLE_ALIGN_LEFT = 'left'; var left = 'left'
var TABLE_ALIGN_CENTER = 'center'; var center = 'center'
var TABLE_ALIGN_RIGHT = 'right'; var right = 'right'
var TABLE_ALIGN_NONE = null;
function table(eat, value, silent) { function table(eat, value, silent) {
var self = this; var self = this
var index; var index
var alignments; var alignments
var alignment; var alignment
var subvalue; var subvalue
var row; var row
var length; var length
var lines; var lines
var queue; var queue
var character; var character
var hasDash; var hasDash
var align; var align
var cell; var cell
var preamble; var preamble
var count; var now
var opening; var position
var now; var lineCount
var position; var line
var lineCount; var rows
var line; var table
var rows; var lineIndex
var table; var pipeIndex
var lineIndex; var first
var pipeIndex;
var first;
/* Exit when not in gfm-mode. */ // Exit when not in gfm-mode.
if (!self.options.gfm) { if (!self.options.gfm) {
return; return
} }
/* Get the rows. // Get the rows.
* Detecting tables soon is hard, so there are some // Detecting tables soon is hard, so there are some checks for performance
* checks for performance here, such as the minimum // here, such as the minimum number of rows, and allowed characters in the
* number of rows, and allowed characters in the // alignment row.
* alignment row. */ index = 0
index = 0; lineCount = 0
lineCount = 0; length = value.length + 1
length = value.length + 1; lines = []
lines = [];
while (index < length) { while (index < length) {
lineIndex = value.indexOf(C_NEWLINE, index); lineIndex = value.indexOf(lineFeed, index)
pipeIndex = value.indexOf(C_PIPE, index + 1); pipeIndex = value.indexOf(verticalBar, index + 1)
if (lineIndex === -1) { if (lineIndex === -1) {
lineIndex = value.length; lineIndex = value.length
} }
if (pipeIndex === -1 || pipeIndex > lineIndex) { if (pipeIndex === -1 || pipeIndex > lineIndex) {
if (lineCount < MIN_TABLE_ROWS) { if (lineCount < minRows) {
return; return
} }
break; break
} }
lines.push(value.slice(index, lineIndex)); lines.push(value.slice(index, lineIndex))
lineCount++; lineCount++
index = lineIndex + 1; index = lineIndex + 1
} }
/* Parse the alignment row. */ // Parse the alignment row.
subvalue = lines.join(C_NEWLINE); subvalue = lines.join(lineFeed)
alignments = lines.splice(1, 1)[0] || []; alignments = lines.splice(1, 1)[0] || []
index = 0; index = 0
length = alignments.length; length = alignments.length
lineCount--; lineCount--
alignment = false; alignment = false
align = []; align = []
while (index < length) { while (index < length) {
character = alignments.charAt(index); character = alignments.charAt(index)
if (character === C_PIPE) { if (character === verticalBar) {
hasDash = null; hasDash = null
if (alignment === false) { if (alignment === false) {
if (first === false) { if (first === false) {
return; return
} }
} else { } else {
align.push(alignment); align.push(alignment)
alignment = false; alignment = false
} }
first = false; first = false
} else if (character === C_DASH) { } else if (character === dash) {
hasDash = true; hasDash = true
alignment = alignment || TABLE_ALIGN_NONE; alignment = alignment || null
} else if (character === C_COLON) { } else if (character === colon) {
if (alignment === TABLE_ALIGN_LEFT) { if (alignment === left) {
alignment = TABLE_ALIGN_CENTER; alignment = center
} else if (hasDash && alignment === TABLE_ALIGN_NONE) { } else if (hasDash && alignment === null) {
alignment = TABLE_ALIGN_RIGHT; alignment = right
} else { } else {
alignment = TABLE_ALIGN_LEFT; alignment = left
} }
} else if (!whitespace(character)) { } else if (!whitespace(character)) {
return; return
} }
index++; index++
} }
if (alignment !== false) { if (alignment !== false) {
align.push(alignment); align.push(alignment)
} }
/* Exit when without enough columns. */ // Exit when without enough columns.
if (align.length < MIN_TABLE_COLUMNS) { if (align.length < minColumns) {
return; return
} }
/* istanbul ignore if - never used (yet) */ /* istanbul ignore if - never used (yet) */
if (silent) { if (silent) {
return true; return true
} }
/* Parse the rows. */ // Parse the rows.
position = -1; position = -1
rows = []; rows = []
table = eat(subvalue).reset({ table = eat(subvalue).reset({type: 'table', align: align, children: rows})
type: 'table',
align: align,
children: rows
});
while (++position < lineCount) { while (++position < lineCount) {
line = lines[position]; line = lines[position]
row = {type: 'tableRow', children: []}; row = {type: 'tableRow', children: []}
/* Eat a newline character when this is not the // Eat a newline character when this is not the first row.
* first row. */
if (position) { if (position) {
eat(C_NEWLINE); eat(lineFeed)
} }
/* Eat the row. */ // Eat the row.
eat(line).reset(row, table); eat(line).reset(row, table)
length = line.length + 1; length = line.length + 1
index = 0; index = 0
queue = ''; queue = ''
cell = ''; cell = ''
preamble = true; preamble = true
count = null;
opening = null;
while (index < length) { while (index < length) {
character = line.charAt(index); character = line.charAt(index)
if (character === C_TAB || character === C_SPACE) { if (character === tab || character === space) {
if (cell) { if (cell) {
queue += character; queue += character
} else { } else {
eat(character); eat(character)
} }
index++; index++
continue; continue
} }
if (character === '' || character === C_PIPE) { if (character === '' || character === verticalBar) {
if (preamble) { if (preamble) {
eat(character); eat(character)
} else { } else {
if (character && opening) {
queue += character;
index++;
continue;
}
if ((cell || character) && !preamble) { if ((cell || character) && !preamble) {
subvalue = cell; subvalue = cell
if (queue.length > 1) { if (queue.length > 1) {
if (character) { if (character) {
subvalue += queue.slice(0, queue.length - 1); subvalue += queue.slice(0, queue.length - 1)
queue = queue.charAt(queue.length - 1); queue = queue.charAt(queue.length - 1)
} else { } else {
subvalue += queue; subvalue += queue
queue = ''; queue = ''
} }
} }
now = eat.now(); now = eat.now()
eat(subvalue)({ eat(subvalue)(
type: 'tableCell', {type: 'tableCell', children: self.tokenizeInline(cell, now)},
children: self.tokenizeInline(cell, now) row
}, row); )
} }
eat(queue + character); eat(queue + character)
queue = ''; queue = ''
cell = ''; cell = ''
} }
} else { } else {
if (queue) { if (queue) {
cell += queue; cell += queue
queue = ''; queue = ''
} }
cell += character; cell += character
if (character === C_BACKSLASH && index !== length - 2) { if (character === backslash && index !== length - 2) {
cell += line.charAt(index + 1); cell += line.charAt(index + 1)
index++; index++
}
if (character === C_TICK) {
count = 1;
while (line.charAt(index + 1) === character) {
cell += character;
index++;
count++;
}
if (!opening) {
opening = count;
} else if (count >= opening) {
opening = 0;
}
} }
} }
preamble = false; preamble = false
index++; index++
} }
/* Eat the alignment row. */ // Eat the alignment row.
if (!position) { if (!position) {
eat(C_NEWLINE + alignments); eat(lineFeed + alignments)
} }
} }
return table; return table
} }

View File

@ -1,58 +1,57 @@
'use strict'; 'use strict'
module.exports = text; module.exports = text
function text(eat, value, silent) { function text(eat, value, silent) {
var self = this; var self = this
var methods; var methods
var tokenizers; var tokenizers
var index; var index
var length; var length
var subvalue; var subvalue
var position; var position
var tokenizer; var tokenizer
var name; var name
var min; var min
var now; var now
/* istanbul ignore if - never used (yet) */ /* istanbul ignore if - never used (yet) */
if (silent) { if (silent) {
return true; return true
} }
methods = self.inlineMethods; methods = self.inlineMethods
length = methods.length; length = methods.length
tokenizers = self.inlineTokenizers; tokenizers = self.inlineTokenizers
index = -1; index = -1
min = value.length; min = value.length
while (++index < length) { while (++index < length) {
name = methods[index]; name = methods[index]
if (name === 'text' || !tokenizers[name]) { if (name === 'text' || !tokenizers[name]) {
continue; continue
} }
tokenizer = tokenizers[name].locator; tokenizer = tokenizers[name].locator
if (!tokenizer) { if (!tokenizer) {
eat.file.fail('Missing locator: `' + name + '`'); eat.file.fail('Missing locator: `' + name + '`')
} }
position = tokenizer.call(self, value, 1); position = tokenizer.call(self, value, 1)
if (position !== -1 && position < min) { if (position !== -1 && position < min) {
min = position; min = position
} }
} }
subvalue = value.slice(0, min); subvalue = value.slice(0, min)
now = eat.now(); now = eat.now()
self.decode(subvalue, now, function (content, position, source) { self.decode(subvalue, now, handler)
eat(source || content)({
type: 'text', function handler(content, position, source) {
value: content eat(source || content)({type: 'text', value: content})
}); }
});
} }

View File

@ -1,70 +1,70 @@
'use strict'; 'use strict'
module.exports = thematicBreak; module.exports = thematicBreak
var C_NEWLINE = '\n'; var tab = '\t'
var C_TAB = '\t'; var lineFeed = '\n'
var C_SPACE = ' '; var space = ' '
var C_ASTERISK = '*'; var asterisk = '*'
var C_UNDERSCORE = '_'; var dash = '-'
var C_DASH = '-'; var underscore = '_'
var THEMATIC_BREAK_MARKER_COUNT = 3; var maxCount = 3
function thematicBreak(eat, value, silent) { function thematicBreak(eat, value, silent) {
var index = -1; var index = -1
var length = value.length + 1; var length = value.length + 1
var subvalue = ''; var subvalue = ''
var character; var character
var marker; var marker
var markerCount; var markerCount
var queue; var queue
while (++index < length) { while (++index < length) {
character = value.charAt(index); character = value.charAt(index)
if (character !== C_TAB && character !== C_SPACE) { if (character !== tab && character !== space) {
break; break
} }
subvalue += character; subvalue += character
} }
if ( if (
character !== C_ASTERISK && character !== asterisk &&
character !== C_DASH && character !== dash &&
character !== C_UNDERSCORE character !== underscore
) { ) {
return; return
} }
marker = character; marker = character
subvalue += character; subvalue += character
markerCount = 1; markerCount = 1
queue = ''; queue = ''
while (++index < length) { while (++index < length) {
character = value.charAt(index); character = value.charAt(index)
if (character === marker) { if (character === marker) {
markerCount++; markerCount++
subvalue += queue + marker; subvalue += queue + marker
queue = ''; queue = ''
} else if (character === C_SPACE) { } else if (character === space) {
queue += character; queue += character
} else if ( } else if (
markerCount >= THEMATIC_BREAK_MARKER_COUNT && markerCount >= maxCount &&
(!character || character === C_NEWLINE) (!character || character === lineFeed)
) { ) {
subvalue += queue; subvalue += queue
if (silent) { if (silent) {
return true; return true
} }
return eat(subvalue)({type: 'thematicBreak'}); return eat(subvalue)({type: 'thematicBreak'})
} else { } else {
return; return
} }
} }
} }

View File

@ -1,144 +1,153 @@
'use strict'; 'use strict'
var decode = require('parse-entities'); var decode = require('parse-entities')
var whitespace = require('is-whitespace-character'); var whitespace = require('is-whitespace-character')
var locate = require('../locate/url'); var locate = require('../locate/url')
module.exports = url; module.exports = url
url.locator = locate; url.locator = locate
url.notInLink = true; url.notInLink = true
var C_BRACKET_OPEN = '['; var quotationMark = '"'
var C_BRACKET_CLOSE = ']'; var apostrophe = "'"
var C_PAREN_OPEN = '('; var leftParenthesis = '('
var C_PAREN_CLOSE = ')'; var rightParenthesis = ')'
var C_LT = '<'; var comma = ','
var C_AT_SIGN = '@'; var dot = '.'
var colon = ':'
var semicolon = ';'
var lessThan = '<'
var atSign = '@'
var leftSquareBracket = '['
var rightSquareBracket = ']'
var HTTP_PROTOCOL = 'http://'; var http = 'http://'
var HTTPS_PROTOCOL = 'https://'; var https = 'https://'
var MAILTO_PROTOCOL = 'mailto:'; var mailto = 'mailto:'
var PROTOCOLS = [ var protocols = [http, https, mailto]
HTTP_PROTOCOL,
HTTPS_PROTOCOL,
MAILTO_PROTOCOL
];
var PROTOCOLS_LENGTH = PROTOCOLS.length; var protocolsLength = protocols.length
function url(eat, value, silent) { function url(eat, value, silent) {
var self = this; var self = this
var subvalue; var subvalue
var content; var content
var character; var character
var index; var index
var position; var position
var protocol; var protocol
var match; var match
var length; var length
var queue; var queue
var parenCount; var parenCount
var nextCharacter; var nextCharacter
var exit; var tokenizers
var exit
if (!self.options.gfm) { if (!self.options.gfm) {
return; return
} }
subvalue = ''; subvalue = ''
index = -1; index = -1
length = PROTOCOLS_LENGTH;
while (++index < length) { while (++index < protocolsLength) {
protocol = PROTOCOLS[index]; protocol = protocols[index]
match = value.slice(0, protocol.length); match = value.slice(0, protocol.length)
if (match.toLowerCase() === protocol) { if (match.toLowerCase() === protocol) {
subvalue = match; subvalue = match
break; break
} }
} }
if (!subvalue) { if (!subvalue) {
return; return
} }
index = subvalue.length; index = subvalue.length
length = value.length; length = value.length
queue = ''; queue = ''
parenCount = 0; parenCount = 0
while (index < length) { while (index < length) {
character = value.charAt(index); character = value.charAt(index)
if (whitespace(character) || character === C_LT) { if (whitespace(character) || character === lessThan) {
break; break
} }
if ( if (
character === '.' || character === dot ||
character === ',' || character === comma ||
character === ':' || character === colon ||
character === ';' || character === semicolon ||
character === '"' || character === quotationMark ||
character === '\'' || character === apostrophe ||
character === ')' || character === rightParenthesis ||
character === ']' character === rightSquareBracket
) { ) {
nextCharacter = value.charAt(index + 1); nextCharacter = value.charAt(index + 1)
if (!nextCharacter || whitespace(nextCharacter)) { if (!nextCharacter || whitespace(nextCharacter)) {
break; break
} }
} }
if (character === C_PAREN_OPEN || character === C_BRACKET_OPEN) { if (character === leftParenthesis || character === leftSquareBracket) {
parenCount++; parenCount++
} }
if (character === C_PAREN_CLOSE || character === C_BRACKET_CLOSE) { if (character === rightParenthesis || character === rightSquareBracket) {
parenCount--; parenCount--
if (parenCount < 0) { if (parenCount < 0) {
break; break
} }
} }
queue += character; queue += character
index++; index++
} }
if (!queue) { if (!queue) {
return; return
} }
subvalue += queue; subvalue += queue
content = subvalue; content = subvalue
if (protocol === MAILTO_PROTOCOL) { if (protocol === mailto) {
position = queue.indexOf(C_AT_SIGN); position = queue.indexOf(atSign)
if (position === -1 || position === length - 1) { if (position === -1 || position === length - 1) {
return; return
} }
content = content.substr(MAILTO_PROTOCOL.length); content = content.slice(mailto.length)
} }
/* istanbul ignore if - never used (yet) */ /* istanbul ignore if - never used (yet) */
if (silent) { if (silent) {
return true; return true
} }
exit = self.enterLink(); exit = self.enterLink()
content = self.tokenizeInline(content, eat.now());
exit(); // Temporarily remove all tokenizers except text in url.
tokenizers = self.inlineTokenizers
self.inlineTokenizers = {text: tokenizers.text}
content = self.tokenizeInline(content, eat.now())
self.inlineTokenizers = tokenizers
exit()
return eat(subvalue)({ return eat(subvalue)({
type: 'link', type: 'link',
title: null, title: null,
url: decode(subvalue, {nonTerminated: false}), url: decode(subvalue, {nonTerminated: false}),
children: content children: content
}); })
} }

View File

@ -1,95 +1,50 @@
'use strict'; 'use strict'
module.exports = factory; module.exports = factory
var MERGEABLE_NODES = { // Construct a tokenizer. This creates both `tokenizeInline` and `tokenizeBlock`.
text: mergeText,
blockquote: mergeBlockquote
};
/* Check whether a node is mergeable with adjacent nodes. */
function mergeable(node) {
var start;
var end;
if (node.type !== 'text' || !node.position) {
return true;
}
start = node.position.start;
end = node.position.end;
/* Only merge nodes which occupy the same size as their
* `value`. */
return start.line !== end.line ||
end.column - start.column === node.value.length;
}
/* Merge two text nodes: `node` into `prev`. */
function mergeText(prev, node) {
prev.value += node.value;
return prev;
}
/* Merge two blockquotes: `node` into `prev`, unless in
* CommonMark mode. */
function mergeBlockquote(prev, node) {
if (this.options.commonmark) {
return node;
}
prev.children = prev.children.concat(node.children);
return prev;
}
/* Construct a tokenizer. This creates both
* `tokenizeInline` and `tokenizeBlock`. */
function factory(type) { function factory(type) {
return tokenize; return tokenize
/* Tokenizer for a bound `type`. */ // Tokenizer for a bound `type`.
function tokenize(value, location) { function tokenize(value, location) {
var self = this; var self = this
var offset = self.offset; var offset = self.offset
var tokens = []; var tokens = []
var methods = self[type + 'Methods']; var methods = self[type + 'Methods']
var tokenizers = self[type + 'Tokenizers']; var tokenizers = self[type + 'Tokenizers']
var line = location.line; var line = location.line
var column = location.column; var column = location.column
var index; var index
var length; var length
var method; var method
var name; var name
var matched; var matched
var valueLength; var valueLength
/* Trim white space only lines. */ // Trim white space only lines.
if (!value) { if (!value) {
return tokens; return tokens
} }
/* Expose on `eat`. */ // Expose on `eat`.
eat.now = now; eat.now = now
eat.file = self.file; eat.file = self.file
/* Sync initial offset. */ // Sync initial offset.
updatePosition(''); updatePosition('')
/* Iterate over `value`, and iterate over all // Iterate over `value`, and iterate over all tokenizers. When one eats
* tokenizers. When one eats something, re-iterate // something, re-iterate with the remaining value. If no tokenizer eats,
* with the remaining value. If no tokenizer eats, // something failed (should not happen) and an exception is thrown.
* something failed (should not happen) and an
* exception is thrown. */
while (value) { while (value) {
index = -1; index = -1
length = methods.length; length = methods.length
matched = false; matched = false
while (++index < length) { while (++index < length) {
name = methods[index]; name = methods[index]
method = tokenizers[name]; method = tokenizers[name]
if ( if (
method && method &&
@ -98,234 +53,262 @@ function factory(type) {
(!method.notInBlock || !self.inBlock) && (!method.notInBlock || !self.inBlock) &&
(!method.notInLink || !self.inLink) (!method.notInLink || !self.inLink)
) { ) {
valueLength = value.length; valueLength = value.length
method.apply(self, [eat, value]); method.apply(self, [eat, value])
matched = valueLength !== value.length; matched = valueLength !== value.length
if (matched) { if (matched) {
break; break
} }
} }
} }
/* istanbul ignore if */ /* istanbul ignore if */
if (!matched) { if (!matched) {
self.file.fail(new Error('Infinite loop'), eat.now()); self.file.fail(new Error('Infinite loop'), eat.now())
} }
} }
self.eof = now(); self.eof = now()
return tokens; return tokens
/* Update line, column, and offset based on // Update line, column, and offset based on `value`.
* `value`. */
function updatePosition(subvalue) { function updatePosition(subvalue) {
var lastIndex = -1; var lastIndex = -1
var index = subvalue.indexOf('\n'); var index = subvalue.indexOf('\n')
while (index !== -1) { while (index !== -1) {
line++; line++
lastIndex = index; lastIndex = index
index = subvalue.indexOf('\n', index + 1); index = subvalue.indexOf('\n', index + 1)
} }
if (lastIndex === -1) { if (lastIndex === -1) {
column += subvalue.length; column += subvalue.length
} else { } else {
column = subvalue.length - lastIndex; column = subvalue.length - lastIndex
} }
if (line in offset) { if (line in offset) {
if (lastIndex !== -1) { if (lastIndex !== -1) {
column += offset[line]; column += offset[line]
} else if (column <= offset[line]) { } else if (column <= offset[line]) {
column = offset[line] + 1; column = offset[line] + 1
} }
} }
} }
/* Get offset. Called before the first character is // Get offset. Called before the first character is eaten to retrieve the
* eaten to retrieve the range's offsets. */ // ranges offsets.
function getOffset() { function getOffset() {
var indentation = []; var indentation = []
var pos = line + 1; var pos = line + 1
/* Done. Called when the last character is // Done. Called when the last character is eaten to retrieve the ranges
* eaten to retrieve the ranges offsets. */ // offsets.
return function () { return function() {
var last = line + 1; var last = line + 1
while (pos < last) { while (pos < last) {
indentation.push((offset[pos] || 0) + 1); indentation.push((offset[pos] || 0) + 1)
pos++; pos++
} }
return indentation; return indentation
};
}
/* Get the current position. */
function now() {
var pos = {line: line, column: column};
pos.offset = self.toOffset(pos);
return pos;
}
/* Store position information for a node. */
function Position(start) {
this.start = start;
this.end = now();
}
/* Throw when a value is incorrectly eaten.
* This shouldnt happen but will throw on new,
* incorrect rules. */
function validateEat(subvalue) {
/* istanbul ignore if */
if (value.substring(0, subvalue.length) !== subvalue) {
/* Capture stack-trace. */
self.file.fail(
new Error(
'Incorrectly eaten value: please report this ' +
'warning on http://git.io/vg5Ft'
),
now()
);
} }
} }
/* Mark position and patch `node.position`. */ // Get the current position.
function now() {
var pos = {line: line, column: column}
pos.offset = self.toOffset(pos)
return pos
}
// Store position information for a node.
function Position(start) {
this.start = start
this.end = now()
}
// Throw when a value is incorrectly eaten. This shouldnt happen but will
// throw on new, incorrect rules.
function validateEat(subvalue) {
/* istanbul ignore if */
if (value.slice(0, subvalue.length) !== subvalue) {
// Capture stack-trace.
self.file.fail(
new Error(
'Incorrectly eaten value: please report this warning on https://git.io/vg5Ft'
),
now()
)
}
}
// Mark position and patch `node.position`.
function position() { function position() {
var before = now(); var before = now()
return update; return update
/* Add the position to a node. */ // Add the position to a node.
function update(node, indent) { function update(node, indent) {
var prev = node.position; var prev = node.position
var start = prev ? prev.start : before; var start = prev ? prev.start : before
var combined = []; var combined = []
var n = prev && prev.end.line; var n = prev && prev.end.line
var l = before.line; var l = before.line
node.position = new Position(start); node.position = new Position(start)
/* If there was already a `position`, this // If there was already a `position`, this node was merged. Fixing
* node was merged. Fixing `start` wasnt // `start` wasnt hard, but the indent is different. Especially
* hard, but the indent is different. // because some information, the indent between `n` and `l` wasnt
* Especially because some information, the // tracked. Luckily, that space is (should be?) empty, so we can
* indent between `n` and `l` wasnt // safely check for it now.
* tracked. Luckily, that space is
* (should be?) empty, so we can safely
* check for it now. */
if (prev && indent && prev.indent) { if (prev && indent && prev.indent) {
combined = prev.indent; combined = prev.indent
if (n < l) { if (n < l) {
while (++n < l) { while (++n < l) {
combined.push((offset[n] || 0) + 1); combined.push((offset[n] || 0) + 1)
} }
combined.push(before.column); combined.push(before.column)
} }
indent = combined.concat(indent); indent = combined.concat(indent)
} }
node.position.indent = indent || []; node.position.indent = indent || []
return node; return node
} }
} }
/* Add `node` to `parent`s children or to `tokens`. // Add `node` to `parent`s children or to `tokens`. Performs merges where
* Performs merges where possible. */ // possible.
function add(node, parent) { function add(node, parent) {
var children = parent ? parent.children : tokens; var children = parent ? parent.children : tokens
var prev = children[children.length - 1]; var prev = children[children.length - 1]
var fn
if ( if (
prev && prev &&
node.type === prev.type && node.type === prev.type &&
node.type in MERGEABLE_NODES && (node.type === 'text' || node.type === 'blockquote') &&
mergeable(prev) && mergeable(prev) &&
mergeable(node) mergeable(node)
) { ) {
node = MERGEABLE_NODES[node.type].call(self, prev, node); fn = node.type === 'text' ? mergeText : mergeBlockquote
node = fn.call(self, prev, node)
} }
if (node !== prev) { if (node !== prev) {
children.push(node); children.push(node)
} }
if (self.atStart && tokens.length !== 0) { if (self.atStart && tokens.length !== 0) {
self.exitStart(); self.exitStart()
} }
return node; return node
} }
/* Remove `subvalue` from `value`. // Remove `subvalue` from `value`. `subvalue` must be at the start of
* `subvalue` must be at the start of `value`. */ // `value`.
function eat(subvalue) { function eat(subvalue) {
var indent = getOffset(); var indent = getOffset()
var pos = position(); var pos = position()
var current = now(); var current = now()
validateEat(subvalue); validateEat(subvalue)
apply.reset = reset; apply.reset = reset
reset.test = test; reset.test = test
apply.test = test; apply.test = test
value = value.substring(subvalue.length); value = value.slice(subvalue.length)
updatePosition(subvalue); updatePosition(subvalue)
indent = indent(); indent = indent()
return apply; return apply
/* Add the given arguments, add `position` to // Add the given arguments, add `position` to the returned node, and
* the returned node, and return the node. */ // return the node.
function apply(node, parent) { function apply(node, parent) {
return pos(add(pos(node), parent), indent); return pos(add(pos(node), parent), indent)
} }
/* Functions just like apply, but resets the // Functions just like apply, but resets the content: the line and
* content: the line and column are reversed, // column are reversed, and the eaten value is re-added. This is
* and the eaten value is re-added. // useful for nodes with a single type of content, such as lists and
* This is useful for nodes with a single // tables. See `apply` above for what parameters are expected.
* type of content, such as lists and tables.
* See `apply` above for what parameters are
* expected. */
function reset() { function reset() {
var node = apply.apply(null, arguments); var node = apply.apply(null, arguments)
line = current.line; line = current.line
column = current.column; column = current.column
value = subvalue + value; value = subvalue + value
return node; return node
} }
/* Test the position, after eating, and reverse // Test the position, after eating, and reverse to a not-eaten state.
* to a not-eaten state. */
function test() { function test() {
var result = pos({}); var result = pos({})
line = current.line; line = current.line
column = current.column; column = current.column
value = subvalue + value; value = subvalue + value
return result.position; return result.position
} }
} }
} }
} }
// Check whether a node is mergeable with adjacent nodes.
function mergeable(node) {
var start
var end
if (node.type !== 'text' || !node.position) {
return true
}
start = node.position.start
end = node.position.end
// Only merge nodes which occupy the same size as their `value`.
return (
start.line !== end.line || end.column - start.column === node.value.length
)
}
// Merge two text nodes: `node` into `prev`.
function mergeText(prev, node) {
prev.value += node.value
return prev
}
// Merge two blockquotes: `node` into `prev`, unless in CommonMark or gfm modes.
function mergeBlockquote(prev, node) {
if (this.options.commonmark || this.options.gfm) {
return node
}
prev.children = prev.children.concat(node.children)
return prev
}

View File

@ -1,37 +1,36 @@
'use strict'; 'use strict'
module.exports = factory; module.exports = factory
/* Factory to de-escape a value, based on a list at `key` var backslash = '\\'
* in `ctx`. */
// Factory to de-escape a value, based on a list at `key` in `ctx`.
function factory(ctx, key) { function factory(ctx, key) {
return unescape; return unescape
/* De-escape a string using the expression at `key` // De-escape a string using the expression at `key` in `ctx`.
* in `ctx`. */
function unescape(value) { function unescape(value) {
var prev = 0; var prev = 0
var index = value.indexOf('\\'); var index = value.indexOf(backslash)
var escape = ctx[key]; var escape = ctx[key]
var queue = []; var queue = []
var character; var character
while (index !== -1) { while (index !== -1) {
queue.push(value.slice(prev, index)); queue.push(value.slice(prev, index))
prev = index + 1; prev = index + 1
character = value.charAt(prev); character = value.charAt(prev)
/* If the following character is not a valid escape, // If the following character is not a valid escape, add the slash.
* add the slash. */
if (!character || escape.indexOf(character) === -1) { if (!character || escape.indexOf(character) === -1) {
queue.push('\\'); queue.push(backslash)
} }
index = value.indexOf('\\', prev); index = value.indexOf(backslash, prev + 1)
} }
queue.push(value.slice(prev)); queue.push(value.slice(prev))
return queue.join(''); return queue.join('')
} }
} }

View File

@ -1,32 +1,33 @@
'use strict'; 'use strict'
module.exports = indentation; module.exports = indentation
/* Map of characters, and their column length, var tab = '\t'
* which can be used as indentation. */ var space = ' '
var characters = {' ': 1, '\t': 4};
/* Gets indentation information for a line. */ var spaceSize = 1
var tabSize = 4
// Gets indentation information for a line.
function indentation(value) { function indentation(value) {
var index = 0; var index = 0
var indent = 0; var indent = 0
var character = value.charAt(index); var character = value.charAt(index)
var stops = {}; var stops = {}
var size; var size
while (character in characters) { while (character === tab || character === space) {
size = characters[character]; size = character === tab ? tabSize : spaceSize
indent += size; indent += size
if (size > 1) { if (size > 1) {
indent = Math.floor(indent / size) * size; indent = Math.floor(indent / size) * size
} }
stops[indent] = index; stops[indent] = index
character = value.charAt(++index)
character = value.charAt(++index);
} }
return {indent: indent, stops: stops}; return {indent: indent, stops: stops}
} }

View File

@ -1,25 +1,34 @@
'use strict'; 'use strict'
var attributeName = '[a-zA-Z_:][a-zA-Z0-9:._-]*'; var attributeName = '[a-zA-Z_:][a-zA-Z0-9:._-]*'
var unquoted = '[^"\'=<>`\\u0000-\\u0020]+'; var unquoted = '[^"\'=<>`\\u0000-\\u0020]+'
var singleQuoted = '\'[^\']*\''; var singleQuoted = "'[^']*'"
var doubleQuoted = '"[^"]*"'; var doubleQuoted = '"[^"]*"'
var attributeValue = '(?:' + unquoted + '|' + singleQuoted + '|' + doubleQuoted + ')'; var attributeValue =
var attribute = '(?:\\s+' + attributeName + '(?:\\s*=\\s*' + attributeValue + ')?)'; '(?:' + unquoted + '|' + singleQuoted + '|' + doubleQuoted + ')'
var openTag = '<[A-Za-z][A-Za-z0-9\\-]*' + attribute + '*\\s*\\/?>'; var attribute =
var closeTag = '<\\/[A-Za-z][A-Za-z0-9\\-]*\\s*>'; '(?:\\s+' + attributeName + '(?:\\s*=\\s*' + attributeValue + ')?)'
var comment = '<!---->|<!--(?:-?[^>-])(?:-?[^-])*-->'; var openTag = '<[A-Za-z][A-Za-z0-9\\-]*' + attribute + '*\\s*\\/?>'
var processing = '<[?].*?[?]>'; var closeTag = '<\\/[A-Za-z][A-Za-z0-9\\-]*\\s*>'
var declaration = '<![A-Za-z]+\\s+[^>]*>'; var comment = '<!---->|<!--(?:-?[^>-])(?:-?[^-])*-->'
var cdata = '<!\\[CDATA\\[[\\s\\S]*?\\]\\]>'; var processing = '<[?].*?[?]>'
var declaration = '<![A-Za-z]+\\s+[^>]*>'
var cdata = '<!\\[CDATA\\[[\\s\\S]*?\\]\\]>'
exports.openCloseTag = new RegExp('^(?:' + openTag + '|' + closeTag + ')'); exports.openCloseTag = new RegExp('^(?:' + openTag + '|' + closeTag + ')')
exports.tag = new RegExp('^(?:' + exports.tag = new RegExp(
openTag + '|' + '^(?:' +
closeTag + '|' + openTag +
comment + '|' + '|' +
processing + '|' + closeTag +
declaration + '|' + '|' +
cdata + comment +
')'); '|' +
processing +
'|' +
declaration +
'|' +
cdata +
')'
)

View File

@ -1,43 +1,35 @@
'use strict'; 'use strict'
module.exports = interrupt; module.exports = interrupt
function interrupt(interruptors, tokenizers, ctx, params) { function interrupt(interruptors, tokenizers, ctx, params) {
var bools = ['pedantic', 'commonmark']; var length = interruptors.length
var count = bools.length; var index = -1
var length = interruptors.length; var interruptor
var index = -1; var config
var interruptor;
var config;
var fn;
var offset;
var bool;
var ignore;
while (++index < length) { while (++index < length) {
interruptor = interruptors[index]; interruptor = interruptors[index]
config = interruptor[1] || {}; config = interruptor[1] || {}
fn = interruptor[0];
offset = -1;
ignore = false;
while (++offset < count) { if (
bool = bools[offset]; config.pedantic !== undefined &&
config.pedantic !== ctx.options.pedantic
if (config[bool] !== undefined && config[bool] !== ctx.options[bool]) { ) {
ignore = true; continue
break;
}
} }
if (ignore) { if (
continue; config.commonmark !== undefined &&
config.commonmark !== ctx.options.commonmark
) {
continue
} }
if (tokenizers[fn].apply(ctx, params)) { if (tokenizers[interruptor[0]].apply(ctx, params)) {
return true; return true
} }
} }
return false; return false
} }

View File

@ -0,0 +1,27 @@
'use strict'
module.exports = whitespace
var tab = 9 // '\t'
var lineFeed = 10 // '\n'
var lineTabulation = 11 // '\v'
var formFeed = 12 // '\f'
var carriageReturn = 13 // '\r'
var space = 32 // ' '
function whitespace(char) {
/* istanbul ignore next - `number` handling for future */
var code = typeof char === 'number' ? char : char.charCodeAt(0)
switch (code) {
case tab:
case lineFeed:
case lineTabulation:
case formFeed:
case carriageReturn:
case space:
return true
default:
return false
}
}

View File

@ -1,11 +1,11 @@
'use strict'; 'use strict'
var collapseWhiteSpace = require('collapse-white-space'); var collapseWhiteSpace = require('collapse-white-space')
module.exports = normalize; module.exports = normalize
/* Normalize an identifier. Collapses multiple white space // Normalize an identifier. Collapses multiple white space characters into a
* characters into a single space, and removes casing. */ // single space, and removes casing.
function normalize(value) { function normalize(value) {
return collapseWhiteSpace(value).toLowerCase(); return collapseWhiteSpace(value).toLowerCase()
} }

View File

@ -1,59 +1,59 @@
'use strict'; 'use strict'
var trim = require('trim'); var trim = require('trim')
var repeat = require('repeat-string'); var repeat = require('repeat-string')
var getIndent = require('./get-indentation'); var getIndent = require('./get-indentation')
module.exports = indentation; module.exports = indentation
var C_SPACE = ' '; var tab = '\t'
var C_NEWLINE = '\n'; var lineFeed = '\n'
var C_TAB = '\t'; var space = ' '
var exclamationMark = '!'
/* Remove the minimum indent from every line in `value`. // Remove the minimum indent from every line in `value`. Supports both tab,
* Supports both tab, spaced, and mixed indentation (as // spaced, and mixed indentation (as well as possible).
* well as possible). */
function indentation(value, maximum) { function indentation(value, maximum) {
var values = value.split(C_NEWLINE); var values = value.split(lineFeed)
var position = values.length + 1; var position = values.length + 1
var minIndent = Infinity; var minIndent = Infinity
var matrix = []; var matrix = []
var index; var index
var indentation; var indentation
var stops; var stops
var padding; var padding
values.unshift(repeat(C_SPACE, maximum) + '!'); values.unshift(repeat(space, maximum) + exclamationMark)
while (position--) { while (position--) {
indentation = getIndent(values[position]); indentation = getIndent(values[position])
matrix[position] = indentation.stops; matrix[position] = indentation.stops
if (trim(values[position]).length === 0) { if (trim(values[position]).length === 0) {
continue; continue
} }
if (indentation.indent) { if (indentation.indent) {
if (indentation.indent > 0 && indentation.indent < minIndent) { if (indentation.indent > 0 && indentation.indent < minIndent) {
minIndent = indentation.indent; minIndent = indentation.indent
} }
} else { } else {
minIndent = Infinity; minIndent = Infinity
break; break
} }
} }
if (minIndent !== Infinity) { if (minIndent !== Infinity) {
position = values.length; position = values.length
while (position--) { while (position--) {
stops = matrix[position]; stops = matrix[position]
index = minIndent; index = minIndent
while (index && !(index in stops)) { while (index && !(index in stops)) {
index--; index--
} }
if ( if (
@ -61,18 +61,17 @@ function indentation(value, maximum) {
minIndent && minIndent &&
index !== minIndent index !== minIndent
) { ) {
padding = C_TAB; padding = tab
} else { } else {
padding = ''; padding = ''
} }
values[position] = padding + values[position].slice( values[position] =
index in stops ? stops[index] + 1 : 0 padding + values[position].slice(index in stops ? stops[index] + 1 : 0)
);
} }
} }
values.shift(); values.shift()
return values.join(C_NEWLINE); return values.join(lineFeed)
} }

View File

@ -1,27 +1,40 @@
{ {
"name": "remark-parse", "name": "remark-parse",
"version": "5.0.0", "version": "7.0.2",
"description": "Markdown parser for remark", "description": "remark plugin to parse Markdown",
"license": "MIT", "license": "MIT",
"keywords": [ "keywords": [
"unified",
"remark",
"plugin",
"markdown", "markdown",
"mdast",
"abstract", "abstract",
"syntax", "syntax",
"tree", "tree",
"ast", "ast",
"parse" "parse"
], ],
"homepage": "http://remark.js.org", "types": "types/index.d.ts",
"homepage": "https://remark.js.org",
"repository": "https://github.com/remarkjs/remark/tree/master/packages/remark-parse", "repository": "https://github.com/remarkjs/remark/tree/master/packages/remark-parse",
"bugs": "https://github.com/remarkjs/remark/issues", "bugs": "https://github.com/remarkjs/remark/issues",
"author": "Titus Wormer <tituswormer@gmail.com> (http://wooorm.com)", "funding": {
"type": "opencollective",
"url": "https://opencollective.com/unified"
},
"author": "Titus Wormer <tituswormer@gmail.com> (https://wooorm.com)",
"contributors": [ "contributors": [
"Titus Wormer <tituswormer@gmail.com> (http://wooorm.com)", "Titus Wormer <tituswormer@gmail.com> (https://wooorm.com)",
"Eugene Sharygin <eush77@gmail.com>" "Eugene Sharygin <eush77@gmail.com>",
"Junyoung Choi <fluke8259@gmail.com>",
"Elijah Hamovitz <elijahhamovitz@gmail.com>",
"Ika <ikatyang@gmail.com>"
], ],
"files": [ "files": [
"index.js", "index.js",
"lib" "lib",
"types/index.d.ts"
], ],
"dependencies": { "dependencies": {
"collapse-white-space": "^1.0.2", "collapse-white-space": "^1.0.2",
@ -40,5 +53,8 @@
"vfile-location": "^2.0.0", "vfile-location": "^2.0.0",
"xtend": "^4.0.1" "xtend": "^4.0.1"
}, },
"scripts": {
"test": "tape test.js"
},
"xo": false "xo": false
} }

View File

@ -1,11 +1,54 @@
# remark-parse [![Build Status][build-badge]][build-status] [![Coverage Status][coverage-badge]][coverage-status] [![Chat][chat-badge]][chat] # remark-parse
[Parser][] for [**unified**][unified]. Parses markdown to an [![Build][build-badge]][build]
[**MDAST**][mdast] syntax tree. Used in the [**remark** [![Coverage][coverage-badge]][coverage]
processor][processor]. Can be [extended][extend] to change how [![Downloads][downloads-badge]][downloads]
markdown is parsed. [![Size][size-badge]][size]
[![Sponsors][sponsors-badge]][collective]
[![Backers][backers-badge]][collective]
[![Chat][chat-badge]][chat]
## Installation [Parser][] for [**unified**][unified].
Parses Markdown to [**mdast**][mdast] syntax trees.
Used in the [**remark** processor][remark] but can be used on its own as well.
Can be [extended][extend] to change how markdown is parsed.
## Sponsors
<!--lint ignore no-html maximum-line-length-->
<table>
<tr valign="top">
<td width="20%" align="center">
<a href="https://zeit.co"><img src="https://avatars1.githubusercontent.com/u/14985020?s=400&v=4"></a>
<br><br>🥇
<a href="https://zeit.co">ZEIT</a>
</td>
<td width="20%" align="center">
<a href="https://www.gatsbyjs.org"><img src="https://avatars1.githubusercontent.com/u/12551863?s=400&v=4"></a>
<br><br>🥇
<a href="https://www.gatsbyjs.org">Gatsby</a>
</td>
<td width="20%" align="center">
<a href="https://www.netlify.com"><img src="https://avatars1.githubusercontent.com/u/7892489?s=400&v=4"></a>
<br><br>🥇
<a href="https://www.netlify.com">Netlify</a>
</td>
<td width="20%" align="center">
<a href="https://www.holloway.com"><img src="https://avatars1.githubusercontent.com/u/35904294?s=400&v=4"></a>
<br><br>
<a href="https://www.holloway.com">Holloway</a>
</td>
<td width="20%" align="center">
<br><br><br><br>
<a href="https://opencollective.com/unified"><strong>You?</strong>
</td>
</tr>
</table>
[**Read more about the unified collective on Medium »**][announcement]
## Install
[npm][]: [npm][]:
@ -13,97 +56,110 @@ markdown is parsed.
npm install remark-parse npm install remark-parse
``` ```
## Usage ## Use
```js ```js
var unified = require('unified'); var unified = require('unified')
var createStream = require('unified-stream'); var createStream = require('unified-stream')
var markdown = require('remark-parse'); var markdown = require('remark-parse')
var html = require('remark-html'); var remark2rehype = require('remark-rehype')
var html = require('rehype-stringify')
var processor = unified() var processor = unified()
.use(markdown, {commonmark: true}) .use(markdown, {commonmark: true})
.use(remark2rehype)
.use(html) .use(html)
process.stdin process.stdin.pipe(createStream(processor)).pipe(process.stdout)
.pipe(createStream(processor))
.pipe(process.stdout);
``` ```
[See **unified** for more examples »][unified]
## Table of Contents ## Table of Contents
* [API](#api) * [API](#api)
* [processor.use(parse\[, options\])](#processoruseparse-options) * [`processor().use(parse[, options])`](#processoruseparse-options)
* [parse.Parser](#parseparser) * [`parse.Parser`](#parseparser)
* [Extending the Parser](#extending-the-parser) * [Extending the Parser](#extending-the-parser)
* [Parser#blockTokenizers](#parserblocktokenizers) * [`Parser#blockTokenizers`](#parserblocktokenizers)
* [Parser#blockMethods](#parserblockmethods) * [`Parser#blockMethods`](#parserblockmethods)
* [Parser#inlineTokenizers](#parserinlinetokenizers) * [`Parser#inlineTokenizers`](#parserinlinetokenizers)
* [Parser#inlineMethods](#parserinlinemethods) * [`Parser#inlineMethods`](#parserinlinemethods)
* [function tokenizer(eat, value, silent)](#function-tokenizereat-value-silent) * [`function tokenizer(eat, value, silent)`](#function-tokenizereat-value-silent)
* [tokenizer.locator(value, fromIndex)](#tokenizerlocatorvalue-fromindex) * [`tokenizer.locator(value, fromIndex)`](#tokenizerlocatorvalue-fromindex)
* [eat(subvalue)](#eatsubvalue) * [`eat(subvalue)`](#eatsubvalue)
* [add(node\[, parent\])](#addnode-parent) * [`add(node[, parent])`](#addnode-parent)
* [add.test()](#addtest) * [`add.test()`](#addtest)
* [add.reset(node\[, parent\])](#addresetnode-parent) * [`add.reset(node[, parent])`](#addresetnode-parent)
* [Turning off a tokenizer](#turning-off-a-tokenizer) * [Turning off a tokenizer](#turning-off-a-tokenizer)
* [Security](#security)
* [Contribute](#contribute)
* [License](#license) * [License](#license)
## API ## API
### `processor.use(parse[, options])` [See **unified** for API docs »][unified]
Configure the `processor` to read markdown as input and process an ### `processor().use(parse[, options])`
[**MDAST**][mdast] syntax tree.
Configure the `processor` to read Markdown as input and process
[**mdast**][mdast] syntax trees.
##### `options` ##### `options`
Options are passed directly, or passed later through [`processor.data()`][data]. Options can be passed directly, or passed later through
[`processor.data()`][data].
##### `options.gfm` ###### `options.gfm`
```md GFM mode (`boolean`, default: `true`).
```markdown
hello ~~hi~~ world hello ~~hi~~ world
``` ```
GFM mode (`boolean`, default: `true`) turns on: Turns on:
* [Fenced code blocks](https://help.github.com/articles/github-flavored-markdown/#fenced-code-blocks) * [Fenced code blocks](https://help.github.com/articles/creating-and-highlighting-code-blocks#fenced-code-blocks)
* [Autolinking of URLs](https://help.github.com/articles/github-flavored-markdown/#url-autolinking) * [Autolinking of URLs](https://help.github.com/articles/autolinked-references-and-urls)
* [Deletions (strikethrough)](https://help.github.com/articles/github-flavored-markdown/#strikethrough) * [Deletions (strikethrough)](https://help.github.com/articles/basic-writing-and-formatting-syntax#styling-text)
* [Task lists](https://help.github.com/articles/writing-on-github/#task-lists) * [Task lists](https://help.github.com/articles/basic-writing-and-formatting-syntax#task-lists)
* [Tables](https://help.github.com/articles/github-flavored-markdown/#tables) * [Tables](https://help.github.com/articles/organizing-information-with-tables)
##### `options.commonmark` ###### `options.commonmark`
```md CommonMark mode (`boolean`, default: `false`).
```markdown
This is a paragraph This is a paragraph
and this is also part of the preceding paragraph. and this is also part of the preceding paragraph.
``` ```
CommonMark mode (`boolean`, default: `false`) allows: Allows:
* Empty lines to split blockquotes * Empty lines to split blockquotes
* Parentheses (`(` and `)`) around for link and image titles * Parentheses (`(` and `)`) around link and image titles
* Any escaped [ASCII-punctuation][escapes] character * Any escaped [ASCII punctuation][escapes] character
* Closing parenthesis (`)`) as an ordered list marker * Closing parenthesis (`)`) as an ordered list marker
* URL definitions (and footnotes, when enabled) in blockquotes * URL definitions (and footnotes, when enabled) in blockquotes
CommonMark mode disallows: Disallows:
* Code directly following a paragraph * Indented code blocks directly following a paragraph
* ATX-headings (`# Hash headings`) without spacing after opening hashes * ATX headings (`# Hash headings`) without spacing after opening hashes or and
or and before closing hashes before closing hashes
* Setext headings (`Underline headings\n---`) when following a paragraph * Setext headings (`Underline headings\n---`) when following a paragraph
* Newlines in link and image titles * Newlines in link and image titles
* White space in link and image URLs in auto-links (links in brackets, * White space in link and image URLs in auto-links (links in brackets, `<` and
`<` and `>`) `>`)
* Lazy blockquote continuation, lines not preceded by a closing angle * Lazy blockquote continuation, lines not preceded by a greater than character
bracket (`>`), for lists, code, and thematicBreak (`>`), for lists, code, and thematic breaks
##### `options.footnotes` ###### `options.footnotes`
```md Footnotes mode (`boolean`, default: `false`).
```markdown
Something something[^or something?]. Something something[^or something?].
And something else[^1]. And something else[^1].
@ -113,35 +169,37 @@ And something else[^1].
* ...and a list * ...and a list
``` ```
Footnotes mode (`boolean`, default: `false`) enables reference footnotes and Enables reference footnotes and inline footnotes.
inline footnotes. Both are wrapped in square brackets and preceded by a caret Both are wrapped in square brackets and preceded by a caret (`^`), and can be
(`^`), and can be referenced from inside other footnotes. referenced from inside other footnotes.
##### `options.blocks` ###### `options.pedantic`
```md Pedantic mode (`boolean`, default: `false`).
```markdown
Check out some_file_name.txt
```
Turns on:
* Emphasis (`_alpha_`) and importance (`__bravo__`) with underscores in words
* Unordered lists with different markers (`*`, `-`, `+`)
* If `commonmark` is also turned on, ordered lists with different markers
(`.`, `)`)
* And removes less spaces in list items (at most four, instead of the whole
indent)
###### `options.blocks`
Blocks (`Array.<string>`, default: list of [block HTML elements][blocks]).
```markdown
<block>foo <block>foo
</block> </block>
``` ```
Blocks (`Array.<string>`, default: list of [block HTML elements][blocks]) Defines which HTML elements are seen as block level.
exposes lets users define block-level HTML elements.
##### `options.pedantic`
```md
Check out some_file_name.txt
```
Pedantic mode (`boolean`, default: `false`) turns on:
* Emphasis (`_alpha_`) and importance (`__bravo__`) with underscores
in words
* Unordered lists with different markers (`*`, `-`, `+`)
* If `commonmark` is also turned on, ordered lists with different
markers (`.`, `)`)
* And pedantic mode removes less spaces in list-items (at most four,
instead of the whole indent)
### `parse.Parser` ### `parse.Parser`
@ -149,46 +207,48 @@ Access to the [parser][], if you need it.
## Extending the Parser ## Extending the Parser
Most often, using transformers to manipulate a syntax tree produces Typically, using [*transformers*][transformer] to manipulate a syntax tree
the desired output. Sometimes, mainly when introducing new syntactic produces the desired output.
entities with a certain level of precedence, interfacing with the parser Sometimes, such as when introducing new syntactic entities with a certain
is necessary. precedence, interfacing with the parser is necessary.
If the `remark-parse` plugin is used, it adds a [`Parser`][parser] constructor If the `remark-parse` plugin is used, it adds a [`Parser`][parser] constructor
to the `processor`. Other plugins can add tokenizers to the parsers prototype function to the `processor`.
to change how markdown is parsed. Other plugins can add tokenizers to its prototype to change how Markdown is
parsed.
The below plugin adds a [tokenizer][] for at-mentions. The below plugin adds a [tokenizer][] for at-mentions.
```js ```js
module.exports = mentions; module.exports = mentions
function mentions() { function mentions() {
var Parser = this.Parser; var Parser = this.Parser
var tokenizers = Parser.prototype.inlineTokenizers; var tokenizers = Parser.prototype.inlineTokenizers
var methods = Parser.prototype.inlineMethods; var methods = Parser.prototype.inlineMethods
/* Add an inline tokenizer (defined in the following example). */ // Add an inline tokenizer (defined in the following example).
tokenizers.mention = tokenizeMention; tokenizers.mention = tokenizeMention
/* Run it just before `text`. */ // Run it just before `text`.
methods.splice(methods.indexOf('text'), 0, 'mention'); methods.splice(methods.indexOf('text'), 0, 'mention')
} }
``` ```
### `Parser#blockTokenizers` ### `Parser#blockTokenizers`
An object mapping tokenizer names to [tokenizer][]s. These Map of names to [tokenizer][]s (`Object.<Function>`).
tokenizers (for example: `fencedCode`, `table`, and `paragraph`) eat These tokenizers (such as `fencedCode`, `table`, and `paragraph`) eat from the
from the start of a value to a line ending. start of a value to a line ending.
See `#blockMethods` below for a list of methods that are included by See `#blockMethods` below for a list of methods that are included by default.
default.
### `Parser#blockMethods` ### `Parser#blockMethods`
Array of `blockTokenizers` names (`string`) specifying the order in List of `blockTokenizers` names (`Array.<string>`).
which they run. Specifies the order in which tokenizers run.
Precedence of default block methods is as follows:
<!--methods-block start--> <!--methods-block start-->
@ -210,17 +270,19 @@ which they run.
### `Parser#inlineTokenizers` ### `Parser#inlineTokenizers`
An object mapping tokenizer names to [tokenizer][]s. These tokenizers Map of names to [tokenizer][]s (`Object.<Function>`).
(for example: `url`, `reference`, and `emphasis`) eat from the start These tokenizers (such as `url`, `reference`, and `emphasis`) eat from the start
of a value. To increase performance, they depend on [locator][]s. of a value.
To increase performance, they depend on [locator][]s.
See `#inlineMethods` below for a list of methods that are included by See `#inlineMethods` below for a list of methods that are included by default.
default.
### `Parser#inlineMethods` ### `Parser#inlineMethods`
Array of `inlineTokenizers` names (`string`) specifying the order in List of `inlineTokenizers` names (`Array.<string>`).
which they run. Specifies the order in which tokenizers run.
Precedence of default inline methods is as follows:
<!--methods-inline start--> <!--methods-inline start-->
@ -241,36 +303,40 @@ which they run.
### `function tokenizer(eat, value, silent)` ### `function tokenizer(eat, value, silent)`
There are two types of tokenizers: block level and inline level.
Both are functions, and work the same, but inline tokenizers must have a
[locator][].
The following example shows an inline tokenizer that is added by the mentions
plugin above.
```js ```js
tokenizeMention.notInLink = true; tokenizeMention.notInLink = true
tokenizeMention.locator = locateMention; tokenizeMention.locator = locateMention
function tokenizeMention(eat, value, silent) { function tokenizeMention(eat, value, silent) {
var match = /^@(\w+)/.exec(value); var match = /^@(\w+)/.exec(value)
if (match) { if (match) {
if (silent) { if (silent) {
return true; return true
} }
return eat(match[0])({ return eat(match[0])({
type: 'link', type: 'link',
url: 'https://social-network/' + match[1], url: 'https://social-network/' + match[1],
children: [{type: 'text', value: match[0]}] children: [{type: 'text', value: match[0]}]
}); })
} }
} }
``` ```
The parser knows two types of tokenizers: block level and inline level. Tokenizers *test* whether a document starts with a certain syntactic entity.
Block level tokenizers are the same as inline level tokenizers, with In *silent* mode, they return whether that test passes.
the exception that the latter must have a [locator][]. In *normal* mode, they consume that token, a process which is called “eating”.
Tokenizers _test_ whether a document starts with a certain syntactic Locators enable inline tokenizers to function faster by providing where the next
entity. In _silent_ mode, they return whether that test passes. entity may occur.
In _normal_ mode, they consume that token, a process which is called
“eating”. Locators enable tokenizers to function faster by providing
information on where the next entity may occur.
###### Signatures ###### Signatures
@ -285,36 +351,39 @@ information on where the next entity may occur.
###### Properties ###### Properties
* `locator` ([`Function`][locator]) * `locator` ([`Function`][locator]) — Required for inline tokenizers
— Required for inline tokenizers * `onlyAtStart` (`boolean`) — Whether nodes can only be found at the beginning
* `onlyAtStart` (`boolean`) of the document
— Whether nodes can only be found at the beginning of the document * `notInBlock` (`boolean`) — Whether nodes cannot be in blockquotes, lists, or
* `notInBlock` (`boolean`) footnote definitions
— Whether nodes cannot be in blockquotes, lists, or footnote * `notInList` (`boolean`) — Whether nodes cannot be in lists
definitions * `notInLink` (`boolean`) — Whether nodes cannot be in links
* `notInList` (`boolean`)
— Whether nodes cannot be in lists
* `notInLink` (`boolean`)
— Whether nodes cannot be in links
###### Returns ###### Returns
* In _silent_ mode, whether a node can be found at the start of `value` * `boolean?`, in *silent* mode — whether a node can be found at the start of
* In _normal_ mode, a node if it can be found at the start of `value` `value`
* [`Node?`][node], In *normal* mode — If it can be found at the start of
`value`
### `tokenizer.locator(value, fromIndex)` ### `tokenizer.locator(value, fromIndex)`
Locators are required for inline tokenizers.
Their role is to keep parsing performant.
The following example shows a locator that is added by the mentions tokenizer
above.
```js ```js
function locateMention(value, fromIndex) { function locateMention(value, fromIndex) {
return value.indexOf('@', fromIndex); return value.indexOf('@', fromIndex)
} }
``` ```
Locators are required for inline tokenization to keep the process Locators enable inline tokenizers to function faster by providing information on
performant. Locators enable inline tokenizers to function faster by where the next entity *may* occur.
providing information on the where the next entity occurs. Locators Locators may be wrong, its OK if there actually isnt a node to be found at the
may be wrong, its OK if there actually isnt a node to be found at index they return.
the index they return, but they must skip any nodes.
###### Parameters ###### Parameters
@ -323,21 +392,20 @@ the index they return, but they must skip any nodes.
###### Returns ###### Returns
Index at which an entity may start, and `-1` otherwise. `number`Index at which an entity may start, and `-1` otherwise.
### `eat(subvalue)` ### `eat(subvalue)`
```js ```js
var add = eat('foo'); var add = eat('foo')
``` ```
Eat `subvalue`, which is a string at the start of the Eat `subvalue`, which is a string at the start of the [tokenized][tokenizer]
[tokenize][tokenizer]d `value` (its tracked to ensure the correct `value`.
value is eaten).
###### Parameters ###### Parameters
* `subvalue` (`string`) - Value to eat. * `subvalue` (`string`) - Value to eat
###### Returns ###### Returns
@ -346,60 +414,96 @@ value is eaten).
### `add(node[, parent])` ### `add(node[, parent])`
```js ```js
var add = eat('foo'); var add = eat('foo')
add({type: 'text', value: 'foo'});
add({type: 'text', value: 'foo'})
``` ```
Add [positional information][location] to `node` and add it to `parent`. Add [positional information][position] to `node` and add `node` to `parent`.
###### Parameters ###### Parameters
* `node` ([`Node`][node]) - Node to patch position on and insert * `node` ([`Node`][node]) - Node to patch position on and to add
* `parent` ([`Node`][node], optional) - Place to add `node` to in * `parent` ([`Parent`][parent], optional) - Place to add `node` to in the
the syntax tree. Defaults to the currently processed node syntax tree.
Defaults to the currently processed node
###### Returns ###### Returns
The given `node`. [`Node`][node] — The given `node`.
### `add.test()` ### `add.test()`
Get the [positional information][location] which would be patched on Get the [positional information][position] that would be patched on `node` by
`node` by `add`. `add`.
###### Returns ###### Returns
[`Location`][location]. [`Position`][position].
### `add.reset(node[, parent])` ### `add.reset(node[, parent])`
`add`, but resets the internal location. Useful for example in `add`, but resets the internal position.
lists, where the same content is first eaten for a list, and later Useful for example in lists, where the same content is first eaten for a list,
for list items and later for list items.
###### Parameters ###### Parameters
* `node` ([`Node`][node]) - Node to patch position on and insert * `node` ([`Node`][node]) - Node to patch position on and insert
* `parent` ([`Node`][node], optional) - Place to add `node` to in * `parent` ([`Node`][node], optional) - Place to add `node` to in
the syntax tree. Defaults to the currently processed node the syntax tree.
Defaults to the currently processed node
###### Returns ###### Returns
The given `node`. [`Node`][node] — The given node.
### Turning off a tokenizer ### Turning off a tokenizer
In rare situations, you may want to turn off a tokenizer to avoid parsing In some situations, you may want to turn off a tokenizer to avoid parsing that
that syntactic feature. This can be done by deleting the tokenizer from syntactic feature.
your Parsers `blockTokenizers` (or `blockMethods`) or `inlineTokenizers`
(or `inlineMethods`). Preferably, use the [`remark-disable-tokenizers`][remark-disable-tokenizers]
plugin to turn off tokenizers.
Alternatively, this can be done by replacing the tokenizer from
`blockTokenizers` (or `blockMethods`) or `inlineTokenizers` (or
`inlineMethods`).
The following example turns off indented code blocks: The following example turns off indented code blocks:
```js ```js
delete remarkParse.Parser.prototype.blockTokenizers.indentedCode; remarkParse.Parser.prototype.blockTokenizers.indentedCode = indentedCode
function indentedCode() {
return true
}
``` ```
## Security
As Markdown is sometimes used for HTML, and improper use of HTML can open you up
to a [cross-site scripting (XSS)][xss] attack, use of remark can also be unsafe.
When going to HTML, use remark in combination with the [**rehype**][rehype]
ecosystem, and use [`rehype-sanitize`][sanitize] to make the tree safe.
Use of remark plugins could also open you up to other attacks.
Carefully assess each plugin and the risks involved in using them.
## Contribute
See [`contributing.md`][contributing] in [`remarkjs/.github`][health] for ways
to get started.
See [`support.md`][support] for ways to get help.
Ideas for new plugins and tools can be posted in [`remarkjs/ideas`][ideas].
A curated list of awesome remark resources can be found in [**awesome
remark**][awesome].
This project has a [Code of Conduct][coc].
By interacting with this repository, organisation, or community you agree to
abide by its terms.
## License ## License
[MIT][license] © [Titus Wormer][author] [MIT][license] © [Titus Wormer][author]
@ -408,19 +512,45 @@ delete remarkParse.Parser.prototype.blockTokenizers.indentedCode;
[build-badge]: https://img.shields.io/travis/remarkjs/remark.svg [build-badge]: https://img.shields.io/travis/remarkjs/remark.svg
[build-status]: https://travis-ci.org/remarkjs/remark [build]: https://travis-ci.org/remarkjs/remark
[coverage-badge]: https://img.shields.io/codecov/c/github/remarkjs/remark.svg [coverage-badge]: https://img.shields.io/codecov/c/github/remarkjs/remark.svg
[coverage-status]: https://codecov.io/github/remarkjs/remark [coverage]: https://codecov.io/github/remarkjs/remark
[chat-badge]: https://img.shields.io/gitter/room/remarkjs/Lobby.svg [downloads-badge]: https://img.shields.io/npm/dm/remark-parse.svg
[chat]: https://gitter.im/remarkjs/Lobby [downloads]: https://www.npmjs.com/package/remark-parse
[license]: https://github.com/remarkjs/remark/blob/master/LICENSE [size-badge]: https://img.shields.io/bundlephobia/minzip/remark-parse.svg
[author]: http://wooorm.com [size]: https://bundlephobia.com/result?p=remark-parse
[sponsors-badge]: https://opencollective.com/unified/sponsors/badge.svg
[backers-badge]: https://opencollective.com/unified/backers/badge.svg
[collective]: https://opencollective.com/unified
[chat-badge]: https://img.shields.io/badge/join%20the%20community-on%20spectrum-7b16ff.svg
[chat]: https://spectrum.chat/unified/remark
[health]: https://github.com/remarkjs/.github
[contributing]: https://github.com/remarkjs/.github/blob/master/contributing.md
[support]: https://github.com/remarkjs/.github/blob/master/support.md
[coc]: https://github.com/remarkjs/.github/blob/master/code-of-conduct.md
[ideas]: https://github.com/remarkjs/ideas
[awesome]: https://github.com/remarkjs/awesome-remark
[license]: https://github.com/remarkjs/remark/blob/master/license
[author]: https://wooorm.com
[npm]: https://docs.npmjs.com/cli/install [npm]: https://docs.npmjs.com/cli/install
@ -428,18 +558,24 @@ delete remarkParse.Parser.prototype.blockTokenizers.indentedCode;
[data]: https://github.com/unifiedjs/unified#processordatakey-value [data]: https://github.com/unifiedjs/unified#processordatakey-value
[processor]: https://github.com/unifiedjs/remark/blob/master/packages/remark [remark]: https://github.com/remarkjs/remark/tree/master/packages/remark
[blocks]: https://github.com/remarkjs/remark/blob/master/packages/remark-parse/lib/block-elements.js
[mdast]: https://github.com/syntax-tree/mdast [mdast]: https://github.com/syntax-tree/mdast
[escapes]: http://spec.commonmark.org/0.25/#backslash-escapes [escapes]: https://spec.commonmark.org/0.29/#backslash-escapes
[node]: https://github.com/syntax-tree/unist#node [node]: https://github.com/syntax-tree/unist#node
[location]: https://github.com/syntax-tree/unist#location [parent]: https://github.com/syntax-tree/unist#parent
[position]: https://github.com/syntax-tree/unist#position
[parser]: https://github.com/unifiedjs/unified#processorparser [parser]: https://github.com/unifiedjs/unified#processorparser
[transformer]: https://github.com/unifiedjs/unified#function-transformernode-file-next
[extend]: #extending-the-parser [extend]: #extending-the-parser
[tokenizer]: #function-tokenizereat-value-silent [tokenizer]: #function-tokenizereat-value-silent
@ -450,4 +586,12 @@ delete remarkParse.Parser.prototype.blockTokenizers.indentedCode;
[add]: #addnode-parent [add]: #addnode-parent
[blocks]: https://github.com/remarkjs/remark/blob/master/packages/remark-parse/lib/block-elements.json [announcement]: https://medium.com/unifiedjs/collectively-evolving-through-crowdsourcing-22c359ea95cc
[remark-disable-tokenizers]: https://github.com/zestedesavoir/zmarkdown/tree/master/packages/remark-disable-tokenizers
[xss]: https://en.wikipedia.org/wiki/Cross-site_scripting
[rehype]: https://github.com/rehypejs/rehype
[sanitize]: https://github.com/rehypejs/rehype-sanitize

View File

@ -1,6 +1,6 @@
{ {
"name": "eslint-plugin-markdown", "name": "eslint-plugin-markdown",
"version": "2.0.1", "version": "2.1.0",
"description": "An ESLint plugin to lint JavaScript in Markdown code fences.", "description": "An ESLint plugin to lint JavaScript in Markdown code fences.",
"license": "MIT", "license": "MIT",
"author": { "author": {
@ -47,7 +47,7 @@
"nyc": "^14.1.1" "nyc": "^14.1.1"
}, },
"dependencies": { "dependencies": {
"remark-parse": "^5.0.0", "remark-parse": "^7.0.0",
"unified": "^6.1.2" "unified": "^6.1.2"
}, },
"peerDependencies": { "peerDependencies": {

View File

@ -281,7 +281,7 @@ The following companies, organizations, and individuals support ESLint's ongoing
<!--sponsorsstart--> <!--sponsorsstart-->
<h3>Platinum Sponsors</h3> <h3>Platinum Sponsors</h3>
<p><a href="https://automattic.com"><img src="https://images.opencollective.com/photomatt/d0ef3e1/logo.png" alt="Automattic" height="undefined"></a></p><h3>Gold Sponsors</h3> <p><a href="https://automattic.com"><img src="https://images.opencollective.com/photomatt/d0ef3e1/logo.png" alt="Automattic" height="undefined"></a></p><h3>Gold Sponsors</h3>
<p><a href="https://nx.dev"><img src="https://images.opencollective.com/nx/0efbe42/logo.png" alt="Nx (by Nrwl)" height="96"></a> <a href="https://google.com/chrome"><img src="https://images.opencollective.com/chrome/dc55bd4/logo.png" alt="Chrome's Web Framework & Tools Performance Fund" height="96"></a> <a href="https://www.shopify.com"><img src="https://images.opencollective.com/shopify/e780cd4/logo.png" alt="Shopify" height="96"></a> <a href="https://www.salesforce.com"><img src="https://images.opencollective.com/salesforce/ca8f997/logo.png" alt="Salesforce" height="96"></a> <a href="https://www.airbnb.com/"><img src="https://images.opencollective.com/airbnb/d327d66/logo.png" alt="Airbnb" height="96"></a> <a href="https://opensource.microsoft.com"><img src="https://avatars.githubusercontent.com/u/6154722?v=4" alt="Microsoft" height="96"></a> <a href="https://substack.com/"><img src="https://avatars.githubusercontent.com/u/53023767?v=4" alt="Substack" height="96"></a></p><h3>Silver Sponsors</h3> <p><a href="https://nx.dev"><img src="https://images.opencollective.com/nx/0efbe42/logo.png" alt="Nx (by Nrwl)" height="96"></a> <a href="https://google.com/chrome"><img src="https://images.opencollective.com/chrome/dc55bd4/logo.png" alt="Chrome's Web Framework & Tools Performance Fund" height="96"></a> <a href="https://www.salesforce.com"><img src="https://images.opencollective.com/salesforce/ca8f997/logo.png" alt="Salesforce" height="96"></a> <a href="https://www.airbnb.com/"><img src="https://images.opencollective.com/airbnb/d327d66/logo.png" alt="Airbnb" height="96"></a> <a href="https://opensource.microsoft.com"><img src="https://avatars.githubusercontent.com/u/6154722?v=4" alt="Microsoft" height="96"></a> <a href="https://substack.com/"><img src="https://avatars.githubusercontent.com/u/53023767?v=4" alt="Substack" height="96"></a></p><h3>Silver Sponsors</h3>
<p><a href="https://retool.com/"><img src="https://images.opencollective.com/retool/98ea68e/logo.png" alt="Retool" height="64"></a> <a href="https://liftoff.io/"><img src="https://images.opencollective.com/liftoff/5c4fa84/logo.png" alt="Liftoff" height="64"></a></p><h3>Bronze Sponsors</h3> <p><a href="https://retool.com/"><img src="https://images.opencollective.com/retool/98ea68e/logo.png" alt="Retool" height="64"></a> <a href="https://liftoff.io/"><img src="https://images.opencollective.com/liftoff/5c4fa84/logo.png" alt="Liftoff" height="64"></a></p><h3>Bronze Sponsors</h3>
<p><a href="https://buy.fineproxy.org/eng/"><img src="https://images.opencollective.com/buy-fineproxy-org/b282e39/logo.png" alt="Buy.Fineproxy.Org" height="32"></a> <a href="https://www.crosswordsolver.org/anagram-solver/"><img src="https://images.opencollective.com/anagram-solver/2666271/logo.png" alt="Anagram Solver" height="32"></a> <a href="null"><img src="https://images.opencollective.com/bugsnag-stability-monitoring/c2cef36/logo.png" alt="Bugsnag Stability Monitoring" height="32"></a> <a href="https://mixpanel.com"><img src="https://images.opencollective.com/mixpanel/cd682f7/logo.png" alt="Mixpanel" height="32"></a> <a href="https://www.vpsserver.com"><img src="https://images.opencollective.com/vpsservercom/logo.png" alt="VPS Server" height="32"></a> <a href="https://icons8.com"><img src="https://images.opencollective.com/icons8/7fa1641/logo.png" alt="Icons8: free icons, photos, illustrations, and music" height="32"></a> <a href="https://discord.com"><img src="https://images.opencollective.com/discordapp/7e3d9a9/logo.png" alt="Discord" height="32"></a> <a href="https://themeisle.com"><img src="https://images.opencollective.com/themeisle/d5592fe/logo.png" alt="ThemeIsle" height="32"></a> <a href="https://www.firesticktricks.com"><img src="https://images.opencollective.com/fire-stick-tricks/b8fbe2c/logo.png" alt="Fire Stick Tricks" height="32"></a></p> <p><a href="https://buy.fineproxy.org/eng/"><img src="https://images.opencollective.com/buy-fineproxy-org/b282e39/logo.png" alt="Buy.Fineproxy.Org" height="32"></a> <a href="https://www.crosswordsolver.org/anagram-solver/"><img src="https://images.opencollective.com/anagram-solver/2666271/logo.png" alt="Anagram Solver" height="32"></a> <a href="null"><img src="https://images.opencollective.com/bugsnag-stability-monitoring/c2cef36/logo.png" alt="Bugsnag Stability Monitoring" height="32"></a> <a href="https://mixpanel.com"><img src="https://images.opencollective.com/mixpanel/cd682f7/logo.png" alt="Mixpanel" height="32"></a> <a href="https://www.vpsserver.com"><img src="https://images.opencollective.com/vpsservercom/logo.png" alt="VPS Server" height="32"></a> <a href="https://icons8.com"><img src="https://images.opencollective.com/icons8/7fa1641/logo.png" alt="Icons8: free icons, photos, illustrations, and music" height="32"></a> <a href="https://discord.com"><img src="https://images.opencollective.com/discordapp/7e3d9a9/logo.png" alt="Discord" height="32"></a> <a href="https://themeisle.com"><img src="https://images.opencollective.com/themeisle/d5592fe/logo.png" alt="ThemeIsle" height="32"></a> <a href="https://www.firesticktricks.com"><img src="https://images.opencollective.com/fire-stick-tricks/b8fbe2c/logo.png" alt="Fire Stick Tricks" height="32"></a></p>
<!--sponsorsend--> <!--sponsorsend-->

View File

@ -27,16 +27,11 @@ const {
naming, naming,
CascadingConfigArrayFactory, CascadingConfigArrayFactory,
IgnorePattern, IgnorePattern,
getUsedExtractedConfigs getUsedExtractedConfigs,
ModuleResolver
} }
} = require("@eslint/eslintrc"); } = require("@eslint/eslintrc");
/*
* For some reason, ModuleResolver must be included via filepath instead of by
* API exports in order to work properly. That's why this is separated out onto
* its own require() statement.
*/
const ModuleResolver = require("@eslint/eslintrc/lib/shared/relative-module-resolver");
const { FileEnumerator } = require("./file-enumerator"); const { FileEnumerator } = require("./file-enumerator");
const { Linter } = require("../linter"); const { Linter } = require("../linter");

View File

@ -117,6 +117,7 @@ function writeJSConfigFile(config, filePath) {
function write(config, filePath) { function write(config, filePath) {
switch (path.extname(filePath)) { switch (path.extname(filePath)) {
case ".js": case ".js":
case ".cjs":
writeJSConfigFile(config, filePath); writeJSConfigFile(config, filePath);
break; break;

View File

@ -12,6 +12,7 @@
const util = require("util"), const util = require("util"),
path = require("path"), path = require("path"),
fs = require("fs"),
enquirer = require("enquirer"), enquirer = require("enquirer"),
ProgressBar = require("progress"), ProgressBar = require("progress"),
semver = require("semver"), semver = require("semver"),
@ -48,6 +49,16 @@ function writeFile(config, format) {
extname = ".yml"; extname = ".yml";
} else if (format === "JSON") { } else if (format === "JSON") {
extname = ".json"; extname = ".json";
} else if (format === "JavaScript") {
const pkgJSONPath = npmUtils.findPackageJson();
if (pkgJSONPath) {
const pkgJSONContents = JSON.parse(fs.readFileSync(pkgJSONPath, "utf8"));
if (pkgJSONContents.type === "module") {
extname = ".cjs";
}
}
} }
const installedESLint = config.installedESLint; const installedESLint = config.installedESLint;
@ -531,7 +542,8 @@ function promptUser() {
choices: [ choices: [
{ message: "Airbnb: https://github.com/airbnb/javascript", name: "airbnb" }, { message: "Airbnb: https://github.com/airbnb/javascript", name: "airbnb" },
{ message: "Standard: https://github.com/standard/standard", name: "standard" }, { message: "Standard: https://github.com/standard/standard", name: "standard" },
{ message: "Google: https://github.com/google/eslint-config-google", name: "google" } { message: "Google: https://github.com/google/eslint-config-google", name: "google" },
{ message: "XO: https://github.com/xojs/eslint-config-xo", name: "xo" }
], ],
skip() { skip() {
this.state.answers.packageJsonExists = npmUtils.checkPackageJson(); this.state.answers.packageJsonExists = npmUtils.checkPackageJson();
@ -683,6 +695,7 @@ const init = {
hasESLintVersionConflict, hasESLintVersionConflict,
installModules, installModules,
processAnswers, processAnswers,
writeFile,
/* istanbul ignore next */initializeConfig() { /* istanbul ignore next */initializeConfig() {
return promptUser(); return promptUser();
} }

View File

@ -172,6 +172,7 @@ function checkPackageJson(startDir) {
module.exports = { module.exports = {
installSyncSaveDev, installSyncSaveDev,
fetchPeerDependencies, fetchPeerDependencies,
findPackageJson,
checkDeps, checkDeps,
checkDevDeps, checkDevDeps,
checkPackageJson checkPackageJson

View File

@ -82,7 +82,8 @@ module.exports = {
description: "enforce the consistent use of the radix argument when using `parseInt()`", description: "enforce the consistent use of the radix argument when using `parseInt()`",
category: "Best Practices", category: "Best Practices",
recommended: false, recommended: false,
url: "https://eslint.org/docs/rules/radix" url: "https://eslint.org/docs/rules/radix",
suggestion: true
}, },
schema: [ schema: [
@ -95,7 +96,8 @@ module.exports = {
missingParameters: "Missing parameters.", missingParameters: "Missing parameters.",
redundantRadix: "Redundant radix parameter.", redundantRadix: "Redundant radix parameter.",
missingRadix: "Missing radix parameter.", missingRadix: "Missing radix parameter.",
invalidRadix: "Invalid radix parameter, must be an integer between 2 and 36." invalidRadix: "Invalid radix parameter, must be an integer between 2 and 36.",
addRadixParameter10: "Add radix parameter `10` for parsing decimal numbers."
} }
}, },
@ -123,7 +125,21 @@ module.exports = {
if (mode === MODE_ALWAYS) { if (mode === MODE_ALWAYS) {
context.report({ context.report({
node, node,
messageId: "missingRadix" messageId: "missingRadix",
suggest: [
{
messageId: "addRadixParameter10",
fix(fixer) {
const sourceCode = context.getSourceCode();
const tokens = sourceCode.getTokens(node);
const lastToken = tokens[tokens.length - 1]; // Parenthesis.
const secondToLastToken = tokens[tokens.length - 2]; // May or may not be a comma.
const hasTrailingComma = secondToLastToken.type === "Punctuator" && secondToLastToken.value === ",";
return fixer.insertTextBefore(lastToken, hasTrailingComma ? " 10," : ", 10");
}
}
]
}); });
} }
break; break;

View File

@ -13,6 +13,10 @@
*/ */
function createReferenceMap(scope, outReferenceMap = new Map()) { function createReferenceMap(scope, outReferenceMap = new Map()) {
for (const reference of scope.references) { for (const reference of scope.references) {
if (reference.resolved === null) {
continue;
}
outReferenceMap.set(reference.identifier, reference); outReferenceMap.set(reference.identifier, reference);
} }
for (const childScope of scope.childScopes) { for (const childScope of scope.childScopes) {
@ -86,42 +90,42 @@ class SegmentInfo {
* @returns {void} * @returns {void}
*/ */
initialize(segment) { initialize(segment) {
const outdatedReadVariableNames = new Set(); const outdatedReadVariables = new Set();
const freshReadVariableNames = new Set(); const freshReadVariables = new Set();
for (const prevSegment of segment.prevSegments) { for (const prevSegment of segment.prevSegments) {
const info = this.info.get(prevSegment); const info = this.info.get(prevSegment);
if (info) { if (info) {
info.outdatedReadVariableNames.forEach(Set.prototype.add, outdatedReadVariableNames); info.outdatedReadVariables.forEach(Set.prototype.add, outdatedReadVariables);
info.freshReadVariableNames.forEach(Set.prototype.add, freshReadVariableNames); info.freshReadVariables.forEach(Set.prototype.add, freshReadVariables);
} }
} }
this.info.set(segment, { outdatedReadVariableNames, freshReadVariableNames }); this.info.set(segment, { outdatedReadVariables, freshReadVariables });
} }
/** /**
* Mark a given variable as read on given segments. * Mark a given variable as read on given segments.
* @param {PathSegment[]} segments The segments that it read the variable on. * @param {PathSegment[]} segments The segments that it read the variable on.
* @param {string} variableName The variable name to be read. * @param {Variable} variable The variable to be read.
* @returns {void} * @returns {void}
*/ */
markAsRead(segments, variableName) { markAsRead(segments, variable) {
for (const segment of segments) { for (const segment of segments) {
const info = this.info.get(segment); const info = this.info.get(segment);
if (info) { if (info) {
info.freshReadVariableNames.add(variableName); info.freshReadVariables.add(variable);
// If a variable is freshly read again, then it's no more out-dated. // If a variable is freshly read again, then it's no more out-dated.
info.outdatedReadVariableNames.delete(variableName); info.outdatedReadVariables.delete(variable);
} }
} }
} }
/** /**
* Move `freshReadVariableNames` to `outdatedReadVariableNames`. * Move `freshReadVariables` to `outdatedReadVariables`.
* @param {PathSegment[]} segments The segments to process. * @param {PathSegment[]} segments The segments to process.
* @returns {void} * @returns {void}
*/ */
@ -130,8 +134,8 @@ class SegmentInfo {
const info = this.info.get(segment); const info = this.info.get(segment);
if (info) { if (info) {
info.freshReadVariableNames.forEach(Set.prototype.add, info.outdatedReadVariableNames); info.freshReadVariables.forEach(Set.prototype.add, info.outdatedReadVariables);
info.freshReadVariableNames.clear(); info.freshReadVariables.clear();
} }
} }
} }
@ -139,14 +143,14 @@ class SegmentInfo {
/** /**
* Check if a given variable is outdated on the current segments. * Check if a given variable is outdated on the current segments.
* @param {PathSegment[]} segments The current segments. * @param {PathSegment[]} segments The current segments.
* @param {string} variableName The variable name to check. * @param {Variable} variable The variable to check.
* @returns {boolean} `true` if the variable is outdated on the segments. * @returns {boolean} `true` if the variable is outdated on the segments.
*/ */
isOutdated(segments, variableName) { isOutdated(segments, variable) {
for (const segment of segments) { for (const segment of segments) {
const info = this.info.get(segment); const info = this.info.get(segment);
if (info && info.outdatedReadVariableNames.has(variableName)) { if (info && info.outdatedReadVariables.has(variable)) {
return true; return true;
} }
} }
@ -214,14 +218,13 @@ module.exports = {
if (!reference) { if (!reference) {
return; return;
} }
const name = reference.identifier.name;
const variable = reference.resolved; const variable = reference.resolved;
const writeExpr = getWriteExpr(reference); const writeExpr = getWriteExpr(reference);
const isMemberAccess = reference.identifier.parent.type === "MemberExpression"; const isMemberAccess = reference.identifier.parent.type === "MemberExpression";
// Add a fresh read variable. // Add a fresh read variable.
if (reference.isRead() && !(writeExpr && writeExpr.parent.operator === "=")) { if (reference.isRead() && !(writeExpr && writeExpr.parent.operator === "=")) {
segmentInfo.markAsRead(codePath.currentSegments, name); segmentInfo.markAsRead(codePath.currentSegments, variable);
} }
/* /*
@ -245,7 +248,7 @@ module.exports = {
/* /*
* Verify assignments. * Verify assignments.
* If the reference exists in `outdatedReadVariableNames` list, report it. * If the reference exists in `outdatedReadVariables` list, report it.
*/ */
":expression:exit"(node) { ":expression:exit"(node) {
const { codePath, referenceMap } = stack; const { codePath, referenceMap } = stack;
@ -267,9 +270,9 @@ module.exports = {
assignmentReferences.delete(node); assignmentReferences.delete(node);
for (const reference of references) { for (const reference of references) {
const name = reference.identifier.name; const variable = reference.resolved;
if (segmentInfo.isOutdated(codePath.currentSegments, name)) { if (segmentInfo.isOutdated(codePath.currentSegments, variable)) {
context.report({ context.report({
node: node.parent, node: node.parent,
messageId: "nonAtomicUpdate", messageId: "nonAtomicUpdate",

View File

@ -58,16 +58,23 @@ function isIdentifierChar(code) {
function isIdentifierName(name) { function isIdentifierName(name) {
let isFirst = true; let isFirst = true;
for (let _i = 0, _Array$from = Array.from(name); _i < _Array$from.length; _i++) { for (let i = 0; i < name.length; i++) {
const char = _Array$from[_i]; let cp = name.charCodeAt(i);
const cp = char.codePointAt(0);
if ((cp & 0xfc00) === 0xd800 && i + 1 < name.length) {
const trail = name.charCodeAt(++i);
if ((trail & 0xfc00) === 0xdc00) {
cp = 0x10000 + ((cp & 0x3ff) << 10) + (trail & 0x3ff);
}
}
if (isFirst) { if (isFirst) {
isFirst = false;
if (!isIdentifierStart(cp)) { if (!isIdentifierStart(cp)) {
return false; return false;
} }
isFirst = false;
} else if (!isIdentifierChar(cp)) { } else if (!isIdentifierChar(cp)) {
return false; return false;
} }

View File

@ -1,6 +1,6 @@
{ {
"name": "@babel/helper-validator-identifier", "name": "@babel/helper-validator-identifier",
"version": "7.12.11", "version": "7.14.0",
"description": "Validate identifier/keywords name", "description": "Validate identifier/keywords name",
"repository": { "repository": {
"type": "git", "type": "git",
@ -14,7 +14,9 @@
"main": "./lib/index.js", "main": "./lib/index.js",
"exports": "./lib/index.js", "exports": "./lib/index.js",
"devDependencies": { "devDependencies": {
"charcodes": "^0.2.0", "@babel/helper-validator-identifier-baseline": "npm:@babel/helper-validator-identifier@7.10.4",
"unicode-13.0.0": "^0.8.0" "@unicode/unicode-13.0.0": "^1.0.6",
"benchmark": "^2.1.4",
"charcodes": "^0.2.0"
} }
} }

View File

@ -4,14 +4,14 @@
// https://tc39.github.io/ecma262/#sec-conformance // https://tc39.github.io/ecma262/#sec-conformance
const version = "13.0.0"; const version = "13.0.0";
const start = require("unicode-" + const start = require("@unicode/unicode-" +
version + version +
"/Binary_Property/ID_Start/code-points.js").filter(function (ch) { "/Binary_Property/ID_Start/code-points.js").filter(function (ch) {
return ch > 0x7f; return ch > 0x7f;
}); });
let last = -1; let last = -1;
const cont = [0x200c, 0x200d].concat( const cont = [0x200c, 0x200d].concat(
require("unicode-" + require("@unicode/unicode-" +
version + version +
"/Binary_Property/ID_Continue/code-points.js").filter(function (ch) { "/Binary_Property/ID_Continue/code-points.js").filter(function (ch) {
return ch > 0x7f && search(start, ch, last + 1) == -1; return ch > 0x7f && search(start, ch, last + 1) == -1;

View File

@ -1,6 +1,6 @@
{ {
"name": "@babel/highlight", "name": "@babel/highlight",
"version": "7.13.10", "version": "7.14.0",
"description": "Syntax highlight JavaScript strings for output in terminals.", "description": "Syntax highlight JavaScript strings for output in terminals.",
"author": "suchipi <me@suchipi.com>", "author": "suchipi <me@suchipi.com>",
"homepage": "https://babel.dev/docs/en/next/babel-highlight", "homepage": "https://babel.dev/docs/en/next/babel-highlight",
@ -15,7 +15,7 @@
}, },
"main": "lib/index.js", "main": "lib/index.js",
"dependencies": { "dependencies": {
"@babel/helper-validator-identifier": "^7.12.11", "@babel/helper-validator-identifier": "^7.14.0",
"chalk": "^2.0.0", "chalk": "^2.0.0",
"js-tokens": "^4.0.0" "js-tokens": "^4.0.0"
}, },

View File

@ -14,7 +14,7 @@ const {
} = require("./config-array-factory"); } = require("./config-array-factory");
const { CascadingConfigArrayFactory } = require("./cascading-config-array-factory"); const { CascadingConfigArrayFactory } = require("./cascading-config-array-factory");
const { ModuleResolver } = require("./shared/relative-module-resolver"); const ModuleResolver = require("./shared/relative-module-resolver");
const { ConfigArray, getUsedExtractedConfigs } = require("./config-array"); const { ConfigArray, getUsedExtractedConfigs } = require("./config-array");
const { ConfigDependency } = require("./config-array/config-dependency"); const { ConfigDependency } = require("./config-array/config-dependency");
const { ExtractedConfig } = require("./config-array/extracted-config"); const { ExtractedConfig } = require("./config-array/extracted-config");

View File

@ -5,6 +5,8 @@
"use strict"; "use strict";
/* eslint class-methods-use-this: "off" */
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// Requirements // Requirements
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------

View File

@ -1,6 +1,6 @@
{ {
"name": "@eslint/eslintrc", "name": "@eslint/eslintrc",
"version": "0.4.0", "version": "0.4.1",
"description": "The legacy ESLintRC config file format for ESLint", "description": "The legacy ESLintRC config file format for ESLint",
"main": "lib/index.js", "main": "lib/index.js",
"files": [ "files": [
@ -12,7 +12,8 @@
"access": "public" "access": "public"
}, },
"scripts": { "scripts": {
"lint": "eslint .", "lint": "eslint . --report-unused-disable-directives",
"fix": "npm run lint -- --fix",
"test": "mocha -R progress -c 'tests/lib/**/*.js'", "test": "mocha -R progress -c 'tests/lib/**/*.js'",
"generate-release": "eslint-generate-release", "generate-release": "eslint-generate-release",
"generate-alpharelease": "eslint-generate-prerelease alpha", "generate-alpharelease": "eslint-generate-prerelease alpha",
@ -34,9 +35,9 @@
"homepage": "https://github.com/eslint/eslintrc#readme", "homepage": "https://github.com/eslint/eslintrc#readme",
"devDependencies": { "devDependencies": {
"chai": "^4.2.0", "chai": "^4.2.0",
"eslint": "^7.7.0", "eslint": "^7.21.0",
"eslint-config-eslint": "^6.0.0", "eslint-config-eslint": "^7.0.0",
"eslint-plugin-jsdoc": "^22.1.0", "eslint-plugin-jsdoc": "^32.2.0",
"eslint-plugin-node": "^11.1.0", "eslint-plugin-node": "^11.1.0",
"eslint-release": "^3.1.2", "eslint-release": "^3.1.2",
"fs-teardown": "^0.1.0", "fs-teardown": "^0.1.0",

View File

@ -17,7 +17,7 @@ $ npm install eslint-visitor-keys
### Requirements ### Requirements
- [Node.js] 4.0.0 or later. - [Node.js] 10.0.0 or later.
## 📖 Usage ## 📖 Usage

View File

@ -211,6 +211,7 @@
"ObjectPattern": [ "ObjectPattern": [
"properties" "properties"
], ],
"PrivateIdentifier": [],
"Program": [ "Program": [
"body" "body"
], ],
@ -218,6 +219,10 @@
"key", "key",
"value" "value"
], ],
"PropertyDefinition": [
"key",
"value"
],
"RestElement": [ "RestElement": [
"argument" "argument"
], ],

View File

@ -1,6 +1,6 @@
{ {
"name": "eslint-visitor-keys", "name": "eslint-visitor-keys",
"version": "2.0.0", "version": "2.1.0",
"description": "Constants and utilities about visitor keys to traverse AST.", "description": "Constants and utilities about visitor keys to traverse AST.",
"main": "lib/index.js", "main": "lib/index.js",
"files": [ "files": [

View File

@ -7,7 +7,7 @@ Match files using the patterns the shell uses, like stars and stuff.
This is a glob implementation in JavaScript. It uses the `minimatch` This is a glob implementation in JavaScript. It uses the `minimatch`
library to do its matching. library to do its matching.
![](logo/glob.png) ![a fun cartoon logo made of glob characters](logo/glob.png)
## Usage ## Usage

View File

@ -1,5 +1,3 @@
exports.alphasort = alphasort
exports.alphasorti = alphasorti
exports.setopts = setopts exports.setopts = setopts
exports.ownProp = ownProp exports.ownProp = ownProp
exports.makeAbs = makeAbs exports.makeAbs = makeAbs
@ -17,12 +15,8 @@ var minimatch = require("minimatch")
var isAbsolute = require("path-is-absolute") var isAbsolute = require("path-is-absolute")
var Minimatch = minimatch.Minimatch var Minimatch = minimatch.Minimatch
function alphasorti (a, b) {
return a.toLowerCase().localeCompare(b.toLowerCase())
}
function alphasort (a, b) { function alphasort (a, b) {
return a.localeCompare(b) return a.localeCompare(b, 'en')
} }
function setupIgnores (self, options) { function setupIgnores (self, options) {
@ -150,7 +144,7 @@ function finish (self) {
all = Object.keys(all) all = Object.keys(all)
if (!self.nosort) if (!self.nosort)
all = all.sort(self.nocase ? alphasorti : alphasort) all = all.sort(alphasort)
// at *some* point we statted all of these // at *some* point we statted all of these
if (self.mark) { if (self.mark) {

View File

@ -51,8 +51,6 @@ var assert = require('assert')
var isAbsolute = require('path-is-absolute') var isAbsolute = require('path-is-absolute')
var globSync = require('./sync.js') var globSync = require('./sync.js')
var common = require('./common.js') var common = require('./common.js')
var alphasort = common.alphasort
var alphasorti = common.alphasorti
var setopts = common.setopts var setopts = common.setopts
var ownProp = common.ownProp var ownProp = common.ownProp
var inflight = require('inflight') var inflight = require('inflight')

View File

@ -2,7 +2,7 @@
"author": "Isaac Z. Schlueter <i@izs.me> (http://blog.izs.me/)", "author": "Isaac Z. Schlueter <i@izs.me> (http://blog.izs.me/)",
"name": "glob", "name": "glob",
"description": "a little globber", "description": "a little globber",
"version": "7.1.6", "version": "7.1.7",
"repository": { "repository": {
"type": "git", "type": "git",
"url": "git://github.com/isaacs/node-glob.git" "url": "git://github.com/isaacs/node-glob.git"
@ -27,13 +27,18 @@
"devDependencies": { "devDependencies": {
"mkdirp": "0", "mkdirp": "0",
"rimraf": "^2.2.8", "rimraf": "^2.2.8",
"tap": "^12.0.1", "tap": "^15.0.6",
"tick": "0.0.6" "tick": "0.0.6"
}, },
"tap": {
"before": "test/00-setup.js",
"after": "test/zz-cleanup.js",
"jobs": 1
},
"scripts": { "scripts": {
"prepublish": "npm run benchclean", "prepublish": "npm run benchclean",
"profclean": "rm -f v8.log profile.txt", "profclean": "rm -f v8.log profile.txt",
"test": "tap test/*.js --cov", "test": "tap",
"test-regen": "npm run profclean && TEST_REGEN=1 node test/00-setup.js", "test-regen": "npm run profclean && TEST_REGEN=1 node test/00-setup.js",
"bench": "bash benchmark.sh", "bench": "bash benchmark.sh",
"prof": "bash prof.sh && cat profile.txt", "prof": "bash prof.sh && cat profile.txt",

View File

@ -11,8 +11,6 @@ var path = require('path')
var assert = require('assert') var assert = require('assert')
var isAbsolute = require('path-is-absolute') var isAbsolute = require('path-is-absolute')
var common = require('./common.js') var common = require('./common.js')
var alphasort = common.alphasort
var alphasorti = common.alphasorti
var setopts = common.setopts var setopts = common.setopts
var ownProp = common.ownProp var ownProp = common.ownProp
var childrenIgnored = common.childrenIgnored var childrenIgnored = common.childrenIgnored

View File

@ -1,47 +0,0 @@
Copyright jQuery Foundation and other contributors <https://jquery.org/>
Based on Underscore.js, copyright Jeremy Ashkenas,
DocumentCloud and Investigative Reporters & Editors <http://underscorejs.org/>
This software consists of voluntary contributions made by many
individuals. For exact contribution history, see the revision history
available at https://github.com/lodash/lodash
The following license applies to all parts of this software except as
documented below:
====
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
====
Copyright and related rights for sample code are waived via CC0. Sample
code is defined as all source code displayed within the prose of the
documentation.
CC0: http://creativecommons.org/publicdomain/zero/1.0/
====
Files located in the node_modules and vendor directories are externally
maintained libraries used by this software which have their own
licenses; we recommend you read them, as their terms may differ from the
terms above.

View File

@ -1,18 +0,0 @@
# lodash.flatten v4.4.0
The [lodash](https://lodash.com/) method `_.flatten` exported as a [Node.js](https://nodejs.org/) module.
## Installation
Using npm:
```bash
$ {sudo -H} npm i -g npm
$ npm i --save lodash.flatten
```
In Node.js:
```js
var flatten = require('lodash.flatten');
```
See the [documentation](https://lodash.com/docs#flatten) or [package source](https://github.com/lodash/lodash/blob/4.4.0-npm-packages/lodash.flatten) for more details.

View File

@ -1,349 +0,0 @@
/**
* lodash (Custom Build) <https://lodash.com/>
* Build: `lodash modularize exports="npm" -o ./`
* Copyright jQuery Foundation and other contributors <https://jquery.org/>
* Released under MIT license <https://lodash.com/license>
* Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
* Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
*/
/** Used as references for various `Number` constants. */
var MAX_SAFE_INTEGER = 9007199254740991;
/** `Object#toString` result references. */
var argsTag = '[object Arguments]',
funcTag = '[object Function]',
genTag = '[object GeneratorFunction]';
/** Detect free variable `global` from Node.js. */
var freeGlobal = typeof global == 'object' && global && global.Object === Object && global;
/** Detect free variable `self`. */
var freeSelf = typeof self == 'object' && self && self.Object === Object && self;
/** Used as a reference to the global object. */
var root = freeGlobal || freeSelf || Function('return this')();
/**
* Appends the elements of `values` to `array`.
*
* @private
* @param {Array} array The array to modify.
* @param {Array} values The values to append.
* @returns {Array} Returns `array`.
*/
function arrayPush(array, values) {
var index = -1,
length = values.length,
offset = array.length;
while (++index < length) {
array[offset + index] = values[index];
}
return array;
}
/** Used for built-in method references. */
var objectProto = Object.prototype;
/** Used to check objects for own properties. */
var hasOwnProperty = objectProto.hasOwnProperty;
/**
* Used to resolve the
* [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)
* of values.
*/
var objectToString = objectProto.toString;
/** Built-in value references. */
var Symbol = root.Symbol,
propertyIsEnumerable = objectProto.propertyIsEnumerable,
spreadableSymbol = Symbol ? Symbol.isConcatSpreadable : undefined;
/**
* The base implementation of `_.flatten` with support for restricting flattening.
*
* @private
* @param {Array} array The array to flatten.
* @param {number} depth The maximum recursion depth.
* @param {boolean} [predicate=isFlattenable] The function invoked per iteration.
* @param {boolean} [isStrict] Restrict to values that pass `predicate` checks.
* @param {Array} [result=[]] The initial result value.
* @returns {Array} Returns the new flattened array.
*/
function baseFlatten(array, depth, predicate, isStrict, result) {
var index = -1,
length = array.length;
predicate || (predicate = isFlattenable);
result || (result = []);
while (++index < length) {
var value = array[index];
if (depth > 0 && predicate(value)) {
if (depth > 1) {
// Recursively flatten arrays (susceptible to call stack limits).
baseFlatten(value, depth - 1, predicate, isStrict, result);
} else {
arrayPush(result, value);
}
} else if (!isStrict) {
result[result.length] = value;
}
}
return result;
}
/**
* Checks if `value` is a flattenable `arguments` object or array.
*
* @private
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is flattenable, else `false`.
*/
function isFlattenable(value) {
return isArray(value) || isArguments(value) ||
!!(spreadableSymbol && value && value[spreadableSymbol]);
}
/**
* Flattens `array` a single level deep.
*
* @static
* @memberOf _
* @since 0.1.0
* @category Array
* @param {Array} array The array to flatten.
* @returns {Array} Returns the new flattened array.
* @example
*
* _.flatten([1, [2, [3, [4]], 5]]);
* // => [1, 2, [3, [4]], 5]
*/
function flatten(array) {
var length = array ? array.length : 0;
return length ? baseFlatten(array, 1) : [];
}
/**
* Checks if `value` is likely an `arguments` object.
*
* @static
* @memberOf _
* @since 0.1.0
* @category Lang
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is an `arguments` object,
* else `false`.
* @example
*
* _.isArguments(function() { return arguments; }());
* // => true
*
* _.isArguments([1, 2, 3]);
* // => false
*/
function isArguments(value) {
// Safari 8.1 makes `arguments.callee` enumerable in strict mode.
return isArrayLikeObject(value) && hasOwnProperty.call(value, 'callee') &&
(!propertyIsEnumerable.call(value, 'callee') || objectToString.call(value) == argsTag);
}
/**
* Checks if `value` is classified as an `Array` object.
*
* @static
* @memberOf _
* @since 0.1.0
* @category Lang
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is an array, else `false`.
* @example
*
* _.isArray([1, 2, 3]);
* // => true
*
* _.isArray(document.body.children);
* // => false
*
* _.isArray('abc');
* // => false
*
* _.isArray(_.noop);
* // => false
*/
var isArray = Array.isArray;
/**
* Checks if `value` is array-like. A value is considered array-like if it's
* not a function and has a `value.length` that's an integer greater than or
* equal to `0` and less than or equal to `Number.MAX_SAFE_INTEGER`.
*
* @static
* @memberOf _
* @since 4.0.0
* @category Lang
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is array-like, else `false`.
* @example
*
* _.isArrayLike([1, 2, 3]);
* // => true
*
* _.isArrayLike(document.body.children);
* // => true
*
* _.isArrayLike('abc');
* // => true
*
* _.isArrayLike(_.noop);
* // => false
*/
function isArrayLike(value) {
return value != null && isLength(value.length) && !isFunction(value);
}
/**
* This method is like `_.isArrayLike` except that it also checks if `value`
* is an object.
*
* @static
* @memberOf _
* @since 4.0.0
* @category Lang
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is an array-like object,
* else `false`.
* @example
*
* _.isArrayLikeObject([1, 2, 3]);
* // => true
*
* _.isArrayLikeObject(document.body.children);
* // => true
*
* _.isArrayLikeObject('abc');
* // => false
*
* _.isArrayLikeObject(_.noop);
* // => false
*/
function isArrayLikeObject(value) {
return isObjectLike(value) && isArrayLike(value);
}
/**
* Checks if `value` is classified as a `Function` object.
*
* @static
* @memberOf _
* @since 0.1.0
* @category Lang
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is a function, else `false`.
* @example
*
* _.isFunction(_);
* // => true
*
* _.isFunction(/abc/);
* // => false
*/
function isFunction(value) {
// The use of `Object#toString` avoids issues with the `typeof` operator
// in Safari 8-9 which returns 'object' for typed array and other constructors.
var tag = isObject(value) ? objectToString.call(value) : '';
return tag == funcTag || tag == genTag;
}
/**
* Checks if `value` is a valid array-like length.
*
* **Note:** This method is loosely based on
* [`ToLength`](http://ecma-international.org/ecma-262/7.0/#sec-tolength).
*
* @static
* @memberOf _
* @since 4.0.0
* @category Lang
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is a valid length, else `false`.
* @example
*
* _.isLength(3);
* // => true
*
* _.isLength(Number.MIN_VALUE);
* // => false
*
* _.isLength(Infinity);
* // => false
*
* _.isLength('3');
* // => false
*/
function isLength(value) {
return typeof value == 'number' &&
value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER;
}
/**
* Checks if `value` is the
* [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types)
* of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
*
* @static
* @memberOf _
* @since 0.1.0
* @category Lang
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is an object, else `false`.
* @example
*
* _.isObject({});
* // => true
*
* _.isObject([1, 2, 3]);
* // => true
*
* _.isObject(_.noop);
* // => true
*
* _.isObject(null);
* // => false
*/
function isObject(value) {
var type = typeof value;
return !!value && (type == 'object' || type == 'function');
}
/**
* Checks if `value` is object-like. A value is object-like if it's not `null`
* and has a `typeof` result of "object".
*
* @static
* @memberOf _
* @since 4.0.0
* @category Lang
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is object-like, else `false`.
* @example
*
* _.isObjectLike({});
* // => true
*
* _.isObjectLike([1, 2, 3]);
* // => true
*
* _.isObjectLike(_.noop);
* // => false
*
* _.isObjectLike(null);
* // => false
*/
function isObjectLike(value) {
return !!value && typeof value == 'object';
}
module.exports = flatten;

View File

@ -1,17 +0,0 @@
{
"name": "lodash.flatten",
"version": "4.4.0",
"description": "The lodash method `_.flatten` exported as a module.",
"homepage": "https://lodash.com/",
"icon": "https://lodash.com/icon.svg",
"license": "MIT",
"keywords": "lodash-modularized, flatten",
"author": "John-David Dalton <john.david.dalton@gmail.com> (http://allyoucanleet.com/)",
"contributors": [
"John-David Dalton <john.david.dalton@gmail.com> (http://allyoucanleet.com/)",
"Blaine Bublitz <blaine.bublitz@gmail.com> (https://github.com/phated)",
"Mathias Bynens <mathias@qiwi.be> (https://mathiasbynens.be/)"
],
"repository": "lodash/lodash",
"scripts": { "test": "echo \"See https://travis-ci.org/lodash/lodash-cli for testing details.\"" }
}

File diff suppressed because it is too large Load Diff

View File

@ -3,7 +3,9 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod }; return (mod && mod.__esModule) ? mod : { "default": mod };
}; };
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
exports.alignString = void 0;
const string_width_1 = __importDefault(require("string-width")); const string_width_1 = __importDefault(require("string-width"));
const utils_1 = require("./utils");
const alignLeft = (subject, width) => { const alignLeft = (subject, width) => {
return subject + ' '.repeat(width); return subject + ' '.repeat(width);
}; };
@ -11,25 +13,31 @@ const alignRight = (subject, width) => {
return ' '.repeat(width) + subject; return ' '.repeat(width) + subject;
}; };
const alignCenter = (subject, width) => { const alignCenter = (subject, width) => {
let halfWidth; return ' '.repeat(Math.floor(width / 2)) + subject + ' '.repeat(Math.ceil(width / 2));
halfWidth = width / 2; };
if (width % 2 === 0) { const alignJustify = (subject, width) => {
return ' '.repeat(halfWidth) + subject + ' '.repeat(halfWidth); const spaceSequenceCount = utils_1.countSpaceSequence(subject);
if (spaceSequenceCount === 0) {
return alignLeft(subject, width);
} }
else { const addingSpaces = utils_1.distributeUnevenly(width, spaceSequenceCount);
halfWidth = Math.floor(halfWidth); if (Math.max(...addingSpaces) > 3) {
return ' '.repeat(halfWidth) + subject + ' '.repeat(halfWidth + 1); return alignLeft(subject, width);
} }
let spaceSequenceIndex = 0;
return subject.replace(/\s+/g, (groupSpace) => {
return groupSpace + ' '.repeat(addingSpaces[spaceSequenceIndex++]);
});
}; };
/** /**
* Pads a string to the left and/or right to position the subject * Pads a string to the left and/or right to position the subject
* text in a desired alignment within a container. * text in a desired alignment within a container.
*/ */
exports.default = (subject, containerWidth, alignment) => { const alignString = (subject, containerWidth, alignment) => {
if (typeof subject !== 'string') {
throw new TypeError('Subject parameter value must be a string.');
}
const subjectWidth = string_width_1.default(subject); const subjectWidth = string_width_1.default(subject);
if (subjectWidth === containerWidth) {
return subject;
}
if (subjectWidth > containerWidth) { if (subjectWidth > containerWidth) {
throw new Error('Subject parameter value width cannot be greater than the container width.'); throw new Error('Subject parameter value width cannot be greater than the container width.');
} }
@ -43,5 +51,9 @@ exports.default = (subject, containerWidth, alignment) => {
if (alignment === 'right') { if (alignment === 'right') {
return alignRight(subject, availableWidth); return alignRight(subject, availableWidth);
} }
if (alignment === 'justify') {
return alignJustify(subject, availableWidth);
}
return alignCenter(subject, availableWidth); return alignCenter(subject, availableWidth);
}; };
exports.alignString = alignString;

View File

@ -1,20 +1,13 @@
"use strict"; "use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
const string_width_1 = __importDefault(require("string-width")); exports.alignTableData = void 0;
const alignString_1 = __importDefault(require("./alignString")); const alignString_1 = require("./alignString");
exports.default = (rows, config) => { const alignTableData = (rows, config) => {
return rows.map((row) => { return rows.map((row) => {
return row.map((cell, index) => { return row.map((cell, cellIndex) => {
const column = config.columns[index]; const { width, alignment } = config.columns[cellIndex];
if (string_width_1.default(cell) === column.width) { return alignString_1.alignString(cell, width, alignment);
return cell;
}
else {
return alignString_1.default(cell, column.width, column.alignment);
}
}); });
}); });
}; };
exports.alignTableData = alignTableData;

View File

@ -1,12 +1,11 @@
"use strict"; "use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
const wrapCell_1 = __importDefault(require("./wrapCell")); exports.calculateCellHeight = void 0;
exports.default = (value, columnWidth, useWrapWord = false) => { const wrapCell_1 = require("./wrapCell");
if (typeof value !== 'string') { /**
throw new TypeError('Value must be a string.'); * Calculates height of cell content in regard to its width and word wrapping.
} */
return wrapCell_1.default(value, columnWidth, useWrapWord).length; const calculateCellHeight = (value, columnWidth, useWrapWord = false) => {
return wrapCell_1.wrapCell(value, columnWidth, useWrapWord).length;
}; };
exports.calculateCellHeight = calculateCellHeight;

View File

@ -3,14 +3,14 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod }; return (mod && mod.__esModule) ? mod : { "default": mod };
}; };
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
exports.calculateCellWidths = void 0;
const string_width_1 = __importDefault(require("string-width")); const string_width_1 = __importDefault(require("string-width"));
/** /**
* Calculates width of each cell contents. * Calculates width of each cell contents in a row.
*/ */
exports.default = (cells) => { const calculateCellWidths = (cells) => {
return cells.map((value) => { return cells.map((cell) => {
return Math.max(...value.split('\n').map((line) => { return Math.max(...cell.split('\n').map(string_width_1.default));
return string_width_1.default(line);
}));
}); });
}; };
exports.calculateCellWidths = calculateCellWidths;

View File

@ -0,0 +1,16 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const calculateCellWidths_1 = require("./calculateCellWidths");
/**
* Produces an array of values that describe the largest value length (width) in every column.
*/
exports.default = (rows) => {
const columnWidths = new Array(rows[0].length).fill(0);
rows.forEach((row) => {
const cellWidths = calculateCellWidths_1.calculateCellWidths(row);
cellWidths.forEach((cellWidth, cellIndex) => {
columnWidths[cellIndex] = Math.max(columnWidths[cellIndex], cellWidth);
});
});
return columnWidths;
};

View File

@ -1,24 +0,0 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const calculateCellWidthIndex_1 = __importDefault(require("./calculateCellWidthIndex"));
/**
* Produces an array of values that describe the largest value length (width) in every column.
*/
exports.default = (rows) => {
if (!rows[0]) {
throw new Error('Dataset must have at least one row.');
}
const columns = new Array(rows[0].length).fill(0);
rows.forEach((row) => {
const columnWidthIndex = calculateCellWidthIndex_1.default(row);
columnWidthIndex.forEach((valueWidth, index0) => {
if (columns[index0] < valueWidth) {
columns[index0] = valueWidth;
}
});
});
return columns;
};

View File

@ -1,21 +0,0 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const calculateCellHeight_1 = __importDefault(require("./calculateCellHeight"));
/**
* Calculates the vertical row span index.
*/
exports.default = (rows, config) => {
const tableWidth = rows[0].length;
const rowSpanIndex = [];
rows.forEach((cells) => {
const cellHeightIndex = new Array(tableWidth).fill(1);
cells.forEach((value, index1) => {
cellHeightIndex[index1] = calculateCellHeight_1.default(value, config.columns[index1].width, config.columns[index1].wrapWord);
});
rowSpanIndex.push(Math.max(...cellHeightIndex));
});
return rowSpanIndex;
};

View File

@ -0,0 +1,18 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.calculateRowHeights = void 0;
const calculateCellHeight_1 = require("./calculateCellHeight");
/**
* Produces an array of values that describe the largest value length (height) in every row.
*/
const calculateRowHeights = (rows, config) => {
return rows.map((row) => {
let rowHeight = 1;
row.forEach((cell, cellIndex) => {
const cellHeight = calculateCellHeight_1.calculateCellHeight(cell, config.columns[cellIndex].width, config.columns[cellIndex].wrapWord);
rowHeight = Math.max(rowHeight, cellHeight);
});
return rowHeight;
});
};
exports.calculateRowHeights = calculateRowHeights;

View File

@ -1,58 +1,56 @@
"use strict"; "use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
const alignTableData_1 = __importDefault(require("./alignTableData")); exports.createStream = void 0;
const calculateRowHeightIndex_1 = __importDefault(require("./calculateRowHeightIndex")); const alignTableData_1 = require("./alignTableData");
const calculateRowHeights_1 = require("./calculateRowHeights");
const drawBorder_1 = require("./drawBorder"); const drawBorder_1 = require("./drawBorder");
const drawRow_1 = __importDefault(require("./drawRow")); const drawRow_1 = require("./drawRow");
const makeStreamConfig_1 = __importDefault(require("./makeStreamConfig")); const makeStreamConfig_1 = require("./makeStreamConfig");
const mapDataUsingRowHeightIndex_1 = __importDefault(require("./mapDataUsingRowHeightIndex")); const mapDataUsingRowHeights_1 = require("./mapDataUsingRowHeights");
const padTableData_1 = __importDefault(require("./padTableData")); const padTableData_1 = require("./padTableData");
const stringifyTableData_1 = __importDefault(require("./stringifyTableData")); const stringifyTableData_1 = require("./stringifyTableData");
const truncateTableData_1 = __importDefault(require("./truncateTableData")); const truncateTableData_1 = require("./truncateTableData");
const prepareData = (data, config) => { const prepareData = (data, config) => {
let rows = stringifyTableData_1.default(data); let rows = stringifyTableData_1.stringifyTableData(data);
rows = truncateTableData_1.default(rows, config); rows = truncateTableData_1.truncateTableData(rows, config);
const rowHeightIndex = calculateRowHeightIndex_1.default(rows, config); const rowHeights = calculateRowHeights_1.calculateRowHeights(rows, config);
rows = mapDataUsingRowHeightIndex_1.default(rows, rowHeightIndex, config); rows = mapDataUsingRowHeights_1.mapDataUsingRowHeights(rows, rowHeights, config);
rows = alignTableData_1.default(rows, config); rows = alignTableData_1.alignTableData(rows, config);
rows = padTableData_1.default(rows, config); rows = padTableData_1.padTableData(rows, config);
return rows; return rows;
}; };
const create = (row, columnWidthIndex, config) => { const create = (row, columnWidths, config) => {
const rows = prepareData([row], config); const rows = prepareData([row], config);
const body = rows.map((literalRow) => { const body = rows.map((literalRow) => {
return drawRow_1.default(literalRow, config); return drawRow_1.drawRow(literalRow, config);
}).join(''); }).join('');
let output; let output;
output = ''; output = '';
output += drawBorder_1.drawBorderTop(columnWidthIndex, config); output += drawBorder_1.drawBorderTop(columnWidths, config);
output += body; output += body;
output += drawBorder_1.drawBorderBottom(columnWidthIndex, config); output += drawBorder_1.drawBorderBottom(columnWidths, config);
output = output.trimEnd(); output = output.trimEnd();
process.stdout.write(output); process.stdout.write(output);
}; };
const append = (row, columnWidthIndex, config) => { const append = (row, columnWidths, config) => {
const rows = prepareData([row], config); const rows = prepareData([row], config);
const body = rows.map((literalRow) => { const body = rows.map((literalRow) => {
return drawRow_1.default(literalRow, config); return drawRow_1.drawRow(literalRow, config);
}).join(''); }).join('');
let output = ''; let output = '';
const bottom = drawBorder_1.drawBorderBottom(columnWidthIndex, config); const bottom = drawBorder_1.drawBorderBottom(columnWidths, config);
if (bottom !== '\n') { if (bottom !== '\n') {
output = '\r\u001B[K'; output = '\r\u001B[K';
} }
output += drawBorder_1.drawBorderJoin(columnWidthIndex, config); output += drawBorder_1.drawBorderJoin(columnWidths, config);
output += body; output += body;
output += bottom; output += bottom;
output = output.trimEnd(); output = output.trimEnd();
process.stdout.write(output); process.stdout.write(output);
}; };
exports.default = (userConfig) => { const createStream = (userConfig) => {
const config = makeStreamConfig_1.default(userConfig); const config = makeStreamConfig_1.makeStreamConfig(userConfig);
const columnWidthIndex = Object.values(config.columns).map((column) => { const columnWidths = Object.values(config.columns).map((column) => {
return column.width + column.paddingLeft + column.paddingRight; return column.width + column.paddingLeft + column.paddingRight;
}); });
let empty = true; let empty = true;
@ -63,11 +61,12 @@ exports.default = (userConfig) => {
} }
if (empty) { if (empty) {
empty = false; empty = false;
create(row, columnWidthIndex, config); create(row, columnWidths, config);
} }
else { else {
append(row, columnWidthIndex, config); append(row, columnWidths, config);
} }
}, },
}; };
}; };
exports.createStream = createStream;

View File

@ -1,19 +1,28 @@
"use strict"; "use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
exports.drawBorderTop = exports.drawBorderJoin = exports.drawBorderBottom = exports.drawBorder = void 0; exports.drawBorderTop = exports.drawBorderJoin = exports.drawBorderBottom = exports.drawBorder = exports.createTableBorderGetter = void 0;
const drawHorizontalContent_1 = __importDefault(require("./drawHorizontalContent")); const drawContent_1 = require("./drawContent");
const drawBorder = (columnSizeIndex, config) => { const drawBorder = (columnWidths, config) => {
const columns = columnSizeIndex.map((size) => { const { separator, drawVerticalLine } = config;
const columns = columnWidths.map((size) => {
return config.separator.body.repeat(size); return config.separator.body.repeat(size);
}); });
return drawHorizontalContent_1.default(columns, config); return drawContent_1.drawContent(columns, {
drawSeparator: drawVerticalLine,
separatorGetter: (index, columnCount) => {
if (index === 0) {
return separator.left;
}
if (index === columnCount) {
return separator.right;
}
return separator.join;
},
}) + '\n';
}; };
exports.drawBorder = drawBorder; exports.drawBorder = drawBorder;
const drawBorderTop = (columnSizeIndex, config) => { const drawBorderTop = (columnWidths, config) => {
const result = drawBorder(columnSizeIndex, { const result = drawBorder(columnWidths, {
...config, ...config,
separator: { separator: {
body: config.border.topBody, body: config.border.topBody,
@ -28,8 +37,8 @@ const drawBorderTop = (columnSizeIndex, config) => {
return result; return result;
}; };
exports.drawBorderTop = drawBorderTop; exports.drawBorderTop = drawBorderTop;
const drawBorderJoin = (columnSizeIndex, config) => { const drawBorderJoin = (columnWidths, config) => {
return drawBorder(columnSizeIndex, { return drawBorder(columnWidths, {
...config, ...config,
separator: { separator: {
body: config.border.joinBody, body: config.border.joinBody,
@ -40,8 +49,8 @@ const drawBorderJoin = (columnSizeIndex, config) => {
}); });
}; };
exports.drawBorderJoin = drawBorderJoin; exports.drawBorderJoin = drawBorderJoin;
const drawBorderBottom = (columnSizeIndex, config) => { const drawBorderBottom = (columnWidths, config) => {
return drawBorder(columnSizeIndex, { return drawBorder(columnWidths, {
...config, ...config,
separator: { separator: {
body: config.border.bottomBody, body: config.border.bottomBody,
@ -52,3 +61,40 @@ const drawBorderBottom = (columnSizeIndex, config) => {
}); });
}; };
exports.drawBorderBottom = drawBorderBottom; exports.drawBorderBottom = drawBorderBottom;
const createTableBorderGetter = (columnWidths, config) => {
return (index, size) => {
if (!config.header) {
if (index === 0) {
return drawBorderTop(columnWidths, config);
}
if (index === size) {
return drawBorderBottom(columnWidths, config);
}
return drawBorderJoin(columnWidths, config);
}
// Deal with the header
if (index === 0) {
return drawBorderTop(columnWidths, {
...config,
border: {
...config.border,
topJoin: config.border.topBody,
},
});
}
if (index === 1) {
return drawBorderJoin(columnWidths, {
...config,
border: {
...config.border,
joinJoin: config.border.headerJoin,
},
});
}
if (index === size) {
return drawBorderBottom(columnWidths, config);
}
return drawBorderJoin(columnWidths, config);
};
};
exports.createTableBorderGetter = createTableBorderGetter;

View File

@ -0,0 +1,26 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.drawContent = void 0;
/**
* Shared function to draw horizontal borders, rows or the entire table
*/
const drawContent = (contents, separatorConfig) => {
const { separatorGetter, drawSeparator } = separatorConfig;
const contentSize = contents.length;
const result = [];
if (drawSeparator(0, contentSize)) {
result.push(separatorGetter(0, contentSize));
}
contents.forEach((content, contentIndex) => {
result.push(content);
// Only append the middle separator if the content is not the last
if (contentIndex + 1 < contentSize && drawSeparator(contentIndex + 1, contentSize)) {
result.push(separatorGetter(contentIndex + 1, contentSize));
}
});
if (drawSeparator(contentSize, contentSize)) {
result.push(separatorGetter(contentSize, contentSize));
}
return result.join('');
};
exports.drawContent = drawContent;

View File

@ -0,0 +1,29 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.drawHeader = void 0;
const alignString_1 = require("./alignString");
const drawRow_1 = require("./drawRow");
const padTableData_1 = require("./padTableData");
const truncateTableData_1 = require("./truncateTableData");
const wrapCell_1 = require("./wrapCell");
const drawHeader = (width, config) => {
if (!config.header) {
throw new Error('Can not draw header without header configuration');
}
const { alignment, paddingRight, paddingLeft, wrapWord } = config.header;
let content = config.header.content;
content = truncateTableData_1.truncateString(content, config.header.truncate);
const headerLines = wrapCell_1.wrapCell(content, width, wrapWord);
return headerLines.map((headerLine) => {
let line = alignString_1.alignString(headerLine, width, alignment);
line = padTableData_1.padString(line, paddingLeft, paddingRight);
return drawRow_1.drawRow([line], {
...config,
drawVerticalLine: (index) => {
const columnCount = config.columns.length;
return config.drawVerticalLine(index === 0 ? 0 : columnCount, columnCount);
},
});
}).join('');
};
exports.drawHeader = drawHeader;

View File

@ -1,18 +0,0 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
function drawHorizontalContent(contents, config) {
const { separator, drawVerticalLine } = config;
const contentSize = contents.length;
const result = [];
result.push(drawVerticalLine(0, contentSize) ? separator.left : '');
contents.forEach((content, index) => {
result.push(content);
// Only append the join separator if it is not the last content
if (index + 1 < contentSize) {
result.push(drawVerticalLine(index + 1, contentSize) ? separator.join : '');
}
});
result.push(drawVerticalLine(contentSize, contentSize) ? separator.right : '');
return result.join('') + '\n';
}
exports.default = drawHorizontalContent;

View File

@ -1,16 +1,20 @@
"use strict"; "use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
const drawHorizontalContent_1 = __importDefault(require("./drawHorizontalContent")); exports.drawRow = void 0;
exports.default = (row, config) => { const drawContent_1 = require("./drawContent");
return drawHorizontalContent_1.default(row, { const drawRow = (row, config) => {
...config, const { border, drawVerticalLine } = config;
separator: { return drawContent_1.drawContent(row, {
join: config.border.bodyJoin, drawSeparator: drawVerticalLine,
left: config.border.bodyLeft, separatorGetter: (index, columnCount) => {
right: config.border.bodyRight, if (index === 0) {
return border.bodyLeft;
}
if (index === columnCount) {
return border.bodyRight;
}
return border.bodyJoin;
}, },
}); }) + '\n';
}; };
exports.drawRow = drawRow;

View File

@ -3,46 +3,36 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod }; return (mod && mod.__esModule) ? mod : { "default": mod };
}; };
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
exports.drawTable = void 0;
const string_width_1 = __importDefault(require("string-width"));
const drawBorder_1 = require("./drawBorder"); const drawBorder_1 = require("./drawBorder");
const drawRow_1 = __importDefault(require("./drawRow")); const drawContent_1 = require("./drawContent");
/** const drawHeader_1 = require("./drawHeader");
* Group the array into sub-arrays by sizes. const drawRow_1 = require("./drawRow");
* const utils_1 = require("./utils");
* @example const drawTable = (rows, columnWidths, rowHeights, config) => {
* chunkBySizes(['a', 'b', 'c', 'd', 'e'], [2, 1, 2]) = [ ['a', 'b'], ['c'], ['d', 'e'] ] const { drawHorizontalLine, singleLine, } = config;
*/ const contents = utils_1.groupBySizes(rows, rowHeights).map((group) => {
const groupBySizes = (array, sizes) => {
let startIndex = 0;
return sizes.map((rowHeight) => {
const chunk = array.slice(startIndex, startIndex + rowHeight);
startIndex += rowHeight;
return chunk;
});
};
const shouldDrawBorderJoin = (rowIndex, rowCount, config) => {
const { singleLine, drawHorizontalLine } = config;
return !singleLine && rowIndex + 1 < rowCount && drawHorizontalLine(rowIndex + 1, rowCount);
};
exports.default = (rows, columnWidths, rowHeights, config) => {
const { drawHorizontalLine, } = config;
const groupedRows = groupBySizes(rows, rowHeights).map((group) => {
return group.map((row) => { return group.map((row) => {
return drawRow_1.default(row, config); return drawRow_1.drawRow(row, config);
}).join(''); }).join('');
}); });
const rowCount = groupedRows.length; if (config.header) {
let output = ''; // assume that topLeft/right border have width = 1
if (drawHorizontalLine(0, rowCount)) { const headerWidth = string_width_1.default(drawRow_1.drawRow(rows[0], config)) - 2 -
output += drawBorder_1.drawBorderTop(columnWidths, config); config.header.paddingLeft - config.header.paddingRight;
const header = drawHeader_1.drawHeader(headerWidth, config);
contents.unshift(header);
} }
groupedRows.forEach((row, rowIndex) => { return drawContent_1.drawContent(contents, {
output += row; drawSeparator: (index, size) => {
if (shouldDrawBorderJoin(rowIndex, rowCount, config)) { // Top/bottom border
output += drawBorder_1.drawBorderJoin(columnWidths, config); if (index === 0 || index === size) {
} return drawHorizontalLine(index, size);
}
return !singleLine && drawHorizontalLine(index, size);
},
separatorGetter: drawBorder_1.createTableBorderGetter(columnWidths, config),
}); });
if (drawHorizontalLine(rowCount, rowCount)) {
output += drawBorder_1.drawBorderBottom(columnWidths, config);
}
return output;
}; };
exports.drawTable = drawTable;

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,8 @@
"use strict"; "use strict";
/* eslint-disable sort-keys-fix/sort-keys-fix */ /* eslint-disable sort-keys-fix/sort-keys-fix */
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
exports.default = (name) => { exports.getBorderCharacters = void 0;
const getBorderCharacters = (name) => {
if (name === 'honeywell') { if (name === 'honeywell') {
return { return {
topBody: '═', topBody: '═',
@ -15,6 +16,7 @@ exports.default = (name) => {
bodyLeft: '║', bodyLeft: '║',
bodyRight: '║', bodyRight: '║',
bodyJoin: '│', bodyJoin: '│',
headerJoin: '┬',
joinBody: '─', joinBody: '─',
joinLeft: '╟', joinLeft: '╟',
joinRight: '╢', joinRight: '╢',
@ -34,6 +36,7 @@ exports.default = (name) => {
bodyLeft: '│', bodyLeft: '│',
bodyRight: '│', bodyRight: '│',
bodyJoin: '│', bodyJoin: '│',
headerJoin: '┬',
joinBody: '─', joinBody: '─',
joinLeft: '├', joinLeft: '├',
joinRight: '┤', joinRight: '┤',
@ -53,6 +56,7 @@ exports.default = (name) => {
bodyLeft: '|', bodyLeft: '|',
bodyRight: '|', bodyRight: '|',
bodyJoin: '|', bodyJoin: '|',
headerJoin: '+',
joinBody: '-', joinBody: '-',
joinLeft: '|', joinLeft: '|',
joinRight: '|', joinRight: '|',
@ -72,6 +76,7 @@ exports.default = (name) => {
bodyLeft: '', bodyLeft: '',
bodyRight: '', bodyRight: '',
bodyJoin: '', bodyJoin: '',
headerJoin: '',
joinBody: '', joinBody: '',
joinLeft: '', joinLeft: '',
joinRight: '', joinRight: '',
@ -80,3 +85,4 @@ exports.default = (name) => {
} }
throw new Error('Unknown border template "' + name + '".'); throw new Error('Unknown border template "' + name + '".');
}; };
exports.getBorderCharacters = getBorderCharacters;

View File

@ -9,15 +9,13 @@ var __createBinding = (this && this.__createBinding) || (Object.create ? (functi
var __exportStar = (this && this.__exportStar) || function(m, exports) { var __exportStar = (this && this.__exportStar) || function(m, exports) {
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p); for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
}; };
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
exports.getBorderCharacters = exports.createStream = exports.table = void 0; exports.getBorderCharacters = exports.createStream = exports.table = void 0;
const createStream_1 = __importDefault(require("./createStream")); // import chalk from 'chalk';
exports.createStream = createStream_1.default; const createStream_1 = require("./createStream");
const getBorderCharacters_1 = __importDefault(require("./getBorderCharacters")); Object.defineProperty(exports, "createStream", { enumerable: true, get: function () { return createStream_1.createStream; } });
exports.getBorderCharacters = getBorderCharacters_1.default; const getBorderCharacters_1 = require("./getBorderCharacters");
const table_1 = __importDefault(require("./table")); Object.defineProperty(exports, "getBorderCharacters", { enumerable: true, get: function () { return getBorderCharacters_1.getBorderCharacters; } });
exports.table = table_1.default; const table_1 = require("./table");
Object.defineProperty(exports, "table", { enumerable: true, get: function () { return table_1.table; } });
__exportStar(require("./types/api"), exports); __exportStar(require("./types/api"), exports);

View File

@ -3,30 +3,22 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod }; return (mod && mod.__esModule) ? mod : { "default": mod };
}; };
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
exports.makeStreamConfig = void 0;
const lodash_clonedeep_1 = __importDefault(require("lodash.clonedeep")); const lodash_clonedeep_1 = __importDefault(require("lodash.clonedeep"));
const getBorderCharacters_1 = __importDefault(require("./getBorderCharacters")); const utils_1 = require("./utils");
const validateConfig_1 = __importDefault(require("./validateConfig")); const validateConfig_1 = require("./validateConfig");
/**
* Merges user provided border characters with the default border ("honeywell") characters.
*
*/
const makeBorder = (border) => {
return {
...getBorderCharacters_1.default('honeywell'),
...border,
};
};
/** /**
* Creates a configuration for every column using default * Creates a configuration for every column using default
* values for the missing configuration properties. * values for the missing configuration properties.
*/ */
const makeColumns = (columnCount, columns = {}, columnDefault) => { const makeColumnsConfig = (columnCount, columns = {}, columnDefault) => {
return Array.from({ length: columnCount }).map((_, index) => { return Array.from({ length: columnCount }).map((_, index) => {
return { return {
alignment: 'left', alignment: 'left',
paddingLeft: 1, paddingLeft: 1,
paddingRight: 1, paddingRight: 1,
truncate: Number.POSITIVE_INFINITY, truncate: Number.POSITIVE_INFINITY,
verticalAlignment: 'top',
wrapWord: false, wrapWord: false,
...columnDefault, ...columnDefault,
...columns[index], ...columns[index],
@ -37,23 +29,19 @@ const makeColumns = (columnCount, columns = {}, columnDefault) => {
* Makes a new configuration object out of the userConfig object * Makes a new configuration object out of the userConfig object
* using default values for the missing configuration properties. * using default values for the missing configuration properties.
*/ */
exports.default = (userConfig) => { const makeStreamConfig = (userConfig) => {
var _a; validateConfig_1.validateConfig('streamConfig.json', userConfig);
validateConfig_1.default('streamConfig.json', userConfig);
const config = lodash_clonedeep_1.default(userConfig); const config = lodash_clonedeep_1.default(userConfig);
if (!config.columnDefault || !config.columnDefault.width) { if (config.columnDefault.width === undefined) {
throw new Error('Must provide config.columnDefault.width when creating a stream.'); throw new Error('Must provide config.columnDefault.width when creating a stream.');
} }
if (!config.columnCount) {
throw new Error('Must provide config.columnCount.');
}
return { return {
...config, drawVerticalLine: () => {
border: makeBorder(config.border),
columnCount: config.columnCount,
columns: makeColumns(config.columnCount, config.columns, config.columnDefault),
drawVerticalLine: (_a = config.drawVerticalLine) !== null && _a !== void 0 ? _a : (() => {
return true; return true;
}), },
...config,
border: utils_1.makeBorderConfig(config.border),
columns: makeColumnsConfig(config.columnCount, config.columns, config.columnDefault),
}; };
}; };
exports.makeStreamConfig = makeStreamConfig;

View File

@ -3,56 +3,64 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod }; return (mod && mod.__esModule) ? mod : { "default": mod };
}; };
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
exports.makeTableConfig = void 0;
const lodash_clonedeep_1 = __importDefault(require("lodash.clonedeep")); const lodash_clonedeep_1 = __importDefault(require("lodash.clonedeep"));
const calculateMaximumColumnWidthIndex_1 = __importDefault(require("./calculateMaximumColumnWidthIndex")); const calculateColumnWidths_1 = __importDefault(require("./calculateColumnWidths"));
const getBorderCharacters_1 = __importDefault(require("./getBorderCharacters")); const utils_1 = require("./utils");
const validateConfig_1 = __importDefault(require("./validateConfig")); const validateConfig_1 = require("./validateConfig");
/**
* Merges user provided border characters with the default border ("honeywell") characters.
*/
const makeBorder = (border) => {
return {
...getBorderCharacters_1.default('honeywell'),
...border,
};
};
/** /**
* Creates a configuration for every column using default * Creates a configuration for every column using default
* values for the missing configuration properties. * values for the missing configuration properties.
*/ */
const makeColumns = (rows, columns, columnDefault) => { const makeColumnsConfig = (rows, columns, columnDefault) => {
const maximumColumnWidthIndex = calculateMaximumColumnWidthIndex_1.default(rows); const columnWidths = calculateColumnWidths_1.default(rows);
return rows[0].map((_cell, index) => { return rows[0].map((_, columnIndex) => {
return { return {
alignment: 'left', alignment: 'left',
paddingLeft: 1, paddingLeft: 1,
paddingRight: 1, paddingRight: 1,
truncate: Number.POSITIVE_INFINITY, truncate: Number.POSITIVE_INFINITY,
width: maximumColumnWidthIndex[index], verticalAlignment: 'top',
width: columnWidths[columnIndex],
wrapWord: false, wrapWord: false,
...columnDefault, ...columnDefault,
...columns === null || columns === void 0 ? void 0 : columns[index], ...columns === null || columns === void 0 ? void 0 : columns[columnIndex],
}; };
}); });
}; };
const makeHeaderConfig = (config) => {
if (!config.header) {
return undefined;
}
return {
alignment: 'center',
paddingLeft: 1,
paddingRight: 1,
truncate: Number.POSITIVE_INFINITY,
wrapWord: false,
...config.header,
};
};
/** /**
* Makes a new configuration object out of the userConfig object * Makes a new configuration object out of the userConfig object
* using default values for the missing configuration properties. * using default values for the missing configuration properties.
*/ */
exports.default = (rows, userConfig = {}) => { const makeTableConfig = (rows, userConfig = {}) => {
var _a, _b, _c; var _a, _b, _c;
validateConfig_1.default('config.json', userConfig); validateConfig_1.validateConfig('config.json', userConfig);
const config = lodash_clonedeep_1.default(userConfig); const config = lodash_clonedeep_1.default(userConfig);
return { return {
...config, ...config,
border: makeBorder(config.border), border: utils_1.makeBorderConfig(config.border),
columns: makeColumns(rows, config.columns, config.columnDefault), columns: makeColumnsConfig(rows, config.columns, config.columnDefault),
drawHorizontalLine: (_a = config.drawHorizontalLine) !== null && _a !== void 0 ? _a : (() => { drawHorizontalLine: (_a = config.drawHorizontalLine) !== null && _a !== void 0 ? _a : (() => {
return true; return true;
}), }),
drawVerticalLine: (_b = config.drawVerticalLine) !== null && _b !== void 0 ? _b : (() => { drawVerticalLine: (_b = config.drawVerticalLine) !== null && _b !== void 0 ? _b : (() => {
return true; return true;
}), }),
header: makeHeaderConfig(config),
singleLine: (_c = config.singleLine) !== null && _c !== void 0 ? _c : false, singleLine: (_c = config.singleLine) !== null && _c !== void 0 ? _c : false,
}; };
}; };
exports.makeTableConfig = makeTableConfig;

Some files were not shown because too many files have changed in this diff Show More