mirror of https://github.com/lukechilds/node.git
Browse Source
* Remove pinning of eslint-plugin-markdown An issue affecting Node.js source has been fixed in eslint-plugin-markdown so we don't need to pin it to beta-4 anymore. Refs: https://github.com/eslint/eslint-plugin-markdown/issues/69 * Update eslint-plugin-markdown up to 1.0.0-beta.7 * Fix docs for eslint-plugin-markdown@1.0.0-beta.7 PR-URL: https://github.com/nodejs/node/pull/14047 Reviewed-By: Rich Trott <rtrott@gmail.com> Reviewed-By: Yuta Hiroto <hello@about-hiroppy.com> Reviewed-By: Refael Ackermann <refack@gmail.com> Reviewed-By: Luigi Pinca <luigipinca@gmail.com> Reviewed-By: Colin Ihrig <cjihrig@gmail.com>v6
169 changed files with 8762 additions and 22351 deletions
@ -1,11 +0,0 @@ |
|||||
<!--remark setext--> |
|
||||
|
|
||||
<!--lint disable no-multiple-toplevel-headings--> |
|
||||
|
|
||||
1.0.1 / 2016-07-23 |
|
||||
================== |
|
||||
|
|
||||
* Rewrite module ([`c3cd494`](https://github.com/wooorm/ccount/commit/c3cd494)) |
|
||||
|
|
||||
1.0.0 / 2015-07-12 |
|
||||
================== |
|
@ -1,46 +0,0 @@ |
|||||
/** |
|
||||
* @author Titus Wormer |
|
||||
* @copyright 2015 Titus Wormer |
|
||||
* @license MIT |
|
||||
* @module ccount |
|
||||
* @fileoverview Count characters. |
|
||||
*/ |
|
||||
|
|
||||
'use strict'; |
|
||||
|
|
||||
/* Expose. */ |
|
||||
module.exports = ccount; |
|
||||
|
|
||||
/** |
|
||||
* Count how many characters `character` occur in `value`. |
|
||||
* |
|
||||
* @example |
|
||||
* ccount('foo(bar(baz)', '(') // 2
|
|
||||
* ccount('foo(bar(baz)', ')') // 1
|
|
||||
* |
|
||||
* @param {string} value - Content, coerced to string. |
|
||||
* @param {string} character - Single character to look |
|
||||
* for. |
|
||||
* @return {number} - Count. |
|
||||
* @throws {Error} - when `character` is not a single |
|
||||
* character. |
|
||||
*/ |
|
||||
function ccount(value, character) { |
|
||||
var count = 0; |
|
||||
var index; |
|
||||
|
|
||||
value = String(value); |
|
||||
|
|
||||
if (typeof character !== 'string' || character.length !== 1) { |
|
||||
throw new Error('Expected character'); |
|
||||
} |
|
||||
|
|
||||
index = value.indexOf(character); |
|
||||
|
|
||||
while (index !== -1) { |
|
||||
count++; |
|
||||
index = value.indexOf(character, index + 1); |
|
||||
} |
|
||||
|
|
||||
return count; |
|
||||
} |
|
@ -1,57 +0,0 @@ |
|||||
# ccount [![Build Status][travis-badge]][travis] [![Coverage Status][codecov-badge]][codecov] |
|
||||
|
|
||||
<!--lint disable heading-increment list-item-spacing--> |
|
||||
|
|
||||
Count characters. |
|
||||
|
|
||||
## Installation |
|
||||
|
|
||||
[npm][npm-install]: |
|
||||
|
|
||||
```bash |
|
||||
npm install ccount |
|
||||
``` |
|
||||
|
|
||||
## Usage |
|
||||
|
|
||||
```javascript |
|
||||
var ccount = require('ccount'); |
|
||||
|
|
||||
ccount('foo(bar(baz)', '(') // 2 |
|
||||
ccount('foo(bar(baz)', ')') // 1 |
|
||||
``` |
|
||||
|
|
||||
## API |
|
||||
|
|
||||
### `ccount(value, character)` |
|
||||
|
|
||||
Get the total count of `character` in `value`. |
|
||||
|
|
||||
###### Parameters |
|
||||
|
|
||||
* `value` (`string`) — Content, coerced to string. |
|
||||
* `character` (`string`) — Single character to look for. |
|
||||
|
|
||||
###### Returns |
|
||||
|
|
||||
`number` — Number of times `character` occurred in `value`. |
|
||||
|
|
||||
## License |
|
||||
|
|
||||
[MIT][license] © [Titus Wormer][author] |
|
||||
|
|
||||
<!-- Definitions --> |
|
||||
|
|
||||
[travis-badge]: https://img.shields.io/travis/wooorm/ccount.svg |
|
||||
|
|
||||
[travis]: https://travis-ci.org/wooorm/ccount |
|
||||
|
|
||||
[codecov-badge]: https://img.shields.io/codecov/c/github/wooorm/ccount.svg |
|
||||
|
|
||||
[codecov]: https://codecov.io/github/wooorm/ccount |
|
||||
|
|
||||
[npm-install]: https://docs.npmjs.com/cli/install |
|
||||
|
|
||||
[license]: LICENSE |
|
||||
|
|
||||
[author]: http://wooorm.com |
|
@ -1,254 +0,0 @@ |
|||||
{ |
|
||||
"nbsp": " ", |
|
||||
"iexcl": "¡", |
|
||||
"cent": "¢", |
|
||||
"pound": "£", |
|
||||
"curren": "¤", |
|
||||
"yen": "¥", |
|
||||
"brvbar": "¦", |
|
||||
"sect": "§", |
|
||||
"uml": "¨", |
|
||||
"copy": "©", |
|
||||
"ordf": "ª", |
|
||||
"laquo": "«", |
|
||||
"not": "¬", |
|
||||
"shy": "", |
|
||||
"reg": "®", |
|
||||
"macr": "¯", |
|
||||
"deg": "°", |
|
||||
"plusmn": "±", |
|
||||
"sup2": "²", |
|
||||
"sup3": "³", |
|
||||
"acute": "´", |
|
||||
"micro": "µ", |
|
||||
"para": "¶", |
|
||||
"middot": "·", |
|
||||
"cedil": "¸", |
|
||||
"sup1": "¹", |
|
||||
"ordm": "º", |
|
||||
"raquo": "»", |
|
||||
"frac14": "¼", |
|
||||
"frac12": "½", |
|
||||
"frac34": "¾", |
|
||||
"iquest": "¿", |
|
||||
"Agrave": "À", |
|
||||
"Aacute": "Á", |
|
||||
"Acirc": "Â", |
|
||||
"Atilde": "Ã", |
|
||||
"Auml": "Ä", |
|
||||
"Aring": "Å", |
|
||||
"AElig": "Æ", |
|
||||
"Ccedil": "Ç", |
|
||||
"Egrave": "È", |
|
||||
"Eacute": "É", |
|
||||
"Ecirc": "Ê", |
|
||||
"Euml": "Ë", |
|
||||
"Igrave": "Ì", |
|
||||
"Iacute": "Í", |
|
||||
"Icirc": "Î", |
|
||||
"Iuml": "Ï", |
|
||||
"ETH": "Ð", |
|
||||
"Ntilde": "Ñ", |
|
||||
"Ograve": "Ò", |
|
||||
"Oacute": "Ó", |
|
||||
"Ocirc": "Ô", |
|
||||
"Otilde": "Õ", |
|
||||
"Ouml": "Ö", |
|
||||
"times": "×", |
|
||||
"Oslash": "Ø", |
|
||||
"Ugrave": "Ù", |
|
||||
"Uacute": "Ú", |
|
||||
"Ucirc": "Û", |
|
||||
"Uuml": "Ü", |
|
||||
"Yacute": "Ý", |
|
||||
"THORN": "Þ", |
|
||||
"szlig": "ß", |
|
||||
"agrave": "à", |
|
||||
"aacute": "á", |
|
||||
"acirc": "â", |
|
||||
"atilde": "ã", |
|
||||
"auml": "ä", |
|
||||
"aring": "å", |
|
||||
"aelig": "æ", |
|
||||
"ccedil": "ç", |
|
||||
"egrave": "è", |
|
||||
"eacute": "é", |
|
||||
"ecirc": "ê", |
|
||||
"euml": "ë", |
|
||||
"igrave": "ì", |
|
||||
"iacute": "í", |
|
||||
"icirc": "î", |
|
||||
"iuml": "ï", |
|
||||
"eth": "ð", |
|
||||
"ntilde": "ñ", |
|
||||
"ograve": "ò", |
|
||||
"oacute": "ó", |
|
||||
"ocirc": "ô", |
|
||||
"otilde": "õ", |
|
||||
"ouml": "ö", |
|
||||
"divide": "÷", |
|
||||
"oslash": "ø", |
|
||||
"ugrave": "ù", |
|
||||
"uacute": "ú", |
|
||||
"ucirc": "û", |
|
||||
"uuml": "ü", |
|
||||
"yacute": "ý", |
|
||||
"thorn": "þ", |
|
||||
"yuml": "ÿ", |
|
||||
"fnof": "ƒ", |
|
||||
"Alpha": "Α", |
|
||||
"Beta": "Β", |
|
||||
"Gamma": "Γ", |
|
||||
"Delta": "Δ", |
|
||||
"Epsilon": "Ε", |
|
||||
"Zeta": "Ζ", |
|
||||
"Eta": "Η", |
|
||||
"Theta": "Θ", |
|
||||
"Iota": "Ι", |
|
||||
"Kappa": "Κ", |
|
||||
"Lambda": "Λ", |
|
||||
"Mu": "Μ", |
|
||||
"Nu": "Ν", |
|
||||
"Xi": "Ξ", |
|
||||
"Omicron": "Ο", |
|
||||
"Pi": "Π", |
|
||||
"Rho": "Ρ", |
|
||||
"Sigma": "Σ", |
|
||||
"Tau": "Τ", |
|
||||
"Upsilon": "Υ", |
|
||||
"Phi": "Φ", |
|
||||
"Chi": "Χ", |
|
||||
"Psi": "Ψ", |
|
||||
"Omega": "Ω", |
|
||||
"alpha": "α", |
|
||||
"beta": "β", |
|
||||
"gamma": "γ", |
|
||||
"delta": "δ", |
|
||||
"epsilon": "ε", |
|
||||
"zeta": "ζ", |
|
||||
"eta": "η", |
|
||||
"theta": "θ", |
|
||||
"iota": "ι", |
|
||||
"kappa": "κ", |
|
||||
"lambda": "λ", |
|
||||
"mu": "μ", |
|
||||
"nu": "ν", |
|
||||
"xi": "ξ", |
|
||||
"omicron": "ο", |
|
||||
"pi": "π", |
|
||||
"rho": "ρ", |
|
||||
"sigmaf": "ς", |
|
||||
"sigma": "σ", |
|
||||
"tau": "τ", |
|
||||
"upsilon": "υ", |
|
||||
"phi": "φ", |
|
||||
"chi": "χ", |
|
||||
"psi": "ψ", |
|
||||
"omega": "ω", |
|
||||
"thetasym": "ϑ", |
|
||||
"upsih": "ϒ", |
|
||||
"piv": "ϖ", |
|
||||
"bull": "•", |
|
||||
"hellip": "…", |
|
||||
"prime": "′", |
|
||||
"Prime": "″", |
|
||||
"oline": "‾", |
|
||||
"frasl": "⁄", |
|
||||
"weierp": "℘", |
|
||||
"image": "ℑ", |
|
||||
"real": "ℜ", |
|
||||
"trade": "™", |
|
||||
"alefsym": "ℵ", |
|
||||
"larr": "←", |
|
||||
"uarr": "↑", |
|
||||
"rarr": "→", |
|
||||
"darr": "↓", |
|
||||
"harr": "↔", |
|
||||
"crarr": "↵", |
|
||||
"lArr": "⇐", |
|
||||
"uArr": "⇑", |
|
||||
"rArr": "⇒", |
|
||||
"dArr": "⇓", |
|
||||
"hArr": "⇔", |
|
||||
"forall": "∀", |
|
||||
"part": "∂", |
|
||||
"exist": "∃", |
|
||||
"empty": "∅", |
|
||||
"nabla": "∇", |
|
||||
"isin": "∈", |
|
||||
"notin": "∉", |
|
||||
"ni": "∋", |
|
||||
"prod": "∏", |
|
||||
"sum": "∑", |
|
||||
"minus": "−", |
|
||||
"lowast": "∗", |
|
||||
"radic": "√", |
|
||||
"prop": "∝", |
|
||||
"infin": "∞", |
|
||||
"ang": "∠", |
|
||||
"and": "∧", |
|
||||
"or": "∨", |
|
||||
"cap": "∩", |
|
||||
"cup": "∪", |
|
||||
"int": "∫", |
|
||||
"there4": "∴", |
|
||||
"sim": "∼", |
|
||||
"cong": "≅", |
|
||||
"asymp": "≈", |
|
||||
"ne": "≠", |
|
||||
"equiv": "≡", |
|
||||
"le": "≤", |
|
||||
"ge": "≥", |
|
||||
"sub": "⊂", |
|
||||
"sup": "⊃", |
|
||||
"nsub": "⊄", |
|
||||
"sube": "⊆", |
|
||||
"supe": "⊇", |
|
||||
"oplus": "⊕", |
|
||||
"otimes": "⊗", |
|
||||
"perp": "⊥", |
|
||||
"sdot": "⋅", |
|
||||
"lceil": "⌈", |
|
||||
"rceil": "⌉", |
|
||||
"lfloor": "⌊", |
|
||||
"rfloor": "⌋", |
|
||||
"lang": "〈", |
|
||||
"rang": "〉", |
|
||||
"loz": "◊", |
|
||||
"spades": "♠", |
|
||||
"clubs": "♣", |
|
||||
"hearts": "♥", |
|
||||
"diams": "♦", |
|
||||
"quot": "\"", |
|
||||
"amp": "&", |
|
||||
"lt": "<", |
|
||||
"gt": ">", |
|
||||
"OElig": "Œ", |
|
||||
"oelig": "œ", |
|
||||
"Scaron": "Š", |
|
||||
"scaron": "š", |
|
||||
"Yuml": "Ÿ", |
|
||||
"circ": "ˆ", |
|
||||
"tilde": "˜", |
|
||||
"ensp": " ", |
|
||||
"emsp": " ", |
|
||||
"thinsp": " ", |
|
||||
"zwnj": "", |
|
||||
"zwj": "", |
|
||||
"lrm": "", |
|
||||
"rlm": "", |
|
||||
"ndash": "–", |
|
||||
"mdash": "—", |
|
||||
"lsquo": "‘", |
|
||||
"rsquo": "’", |
|
||||
"sbquo": "‚", |
|
||||
"ldquo": "“", |
|
||||
"rdquo": "”", |
|
||||
"bdquo": "„", |
|
||||
"dagger": "†", |
|
||||
"Dagger": "‡", |
|
||||
"permil": "‰", |
|
||||
"lsaquo": "‹", |
|
||||
"rsaquo": "›", |
|
||||
"euro": "€" |
|
||||
} |
|
@ -1,98 +0,0 @@ |
|||||
{ |
|
||||
"_from": "character-entities-html4@^1.0.0", |
|
||||
"_id": "character-entities-html4@1.1.0", |
|
||||
"_inBundle": false, |
|
||||
"_integrity": "sha1-GrCFUdPOH6HfCNAPucod77FHoGw=", |
|
||||
"_location": "/character-entities-html4", |
|
||||
"_phantomChildren": {}, |
|
||||
"_requested": { |
|
||||
"type": "range", |
|
||||
"registry": true, |
|
||||
"raw": "character-entities-html4@^1.0.0", |
|
||||
"name": "character-entities-html4", |
|
||||
"escapedName": "character-entities-html4", |
|
||||
"rawSpec": "^1.0.0", |
|
||||
"saveSpec": null, |
|
||||
"fetchSpec": "^1.0.0" |
|
||||
}, |
|
||||
"_requiredBy": [ |
|
||||
"/stringify-entities" |
|
||||
], |
|
||||
"_resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-1.1.0.tgz", |
|
||||
"_shasum": "1ab08551d3ce1fa1df08d00fb9ca1defb147a06c", |
|
||||
"_spec": "character-entities-html4@^1.0.0", |
|
||||
"_where": "/Users/trott/io.js/tools/eslint-tmp/node_modules/eslint/node_modules/stringify-entities", |
|
||||
"author": { |
|
||||
"name": "Titus Wormer", |
|
||||
"email": "tituswormer@gmail.com", |
|
||||
"url": "http://wooorm.com" |
|
||||
}, |
|
||||
"bugs": { |
|
||||
"url": "https://github.com/wooorm/character-entities-html4/issues" |
|
||||
}, |
|
||||
"bundleDependencies": false, |
|
||||
"contributors": [ |
|
||||
{ |
|
||||
"name": "Titus Wormer", |
|
||||
"email": "tituswormer@gmail.com", |
|
||||
"url": "http://wooorm.com" |
|
||||
} |
|
||||
], |
|
||||
"dependencies": {}, |
|
||||
"deprecated": false, |
|
||||
"description": "HTML4 character entity information", |
|
||||
"devDependencies": { |
|
||||
"bail": "^1.0.1", |
|
||||
"browserify": "^13.0.1", |
|
||||
"concat-stream": "^1.5.2", |
|
||||
"esmangle": "^1.0.1", |
|
||||
"nyc": "^8.0.0", |
|
||||
"remark-cli": "^2.0.0", |
|
||||
"remark-preset-wooorm": "^1.0.0", |
|
||||
"tape": "^4.0.0", |
|
||||
"xo": "^0.17.0" |
|
||||
}, |
|
||||
"files": [ |
|
||||
"index.json" |
|
||||
], |
|
||||
"homepage": "https://github.com/wooorm/character-entities-html4#readme", |
|
||||
"keywords": [ |
|
||||
"html", |
|
||||
"html4", |
|
||||
"entity", |
|
||||
"entities", |
|
||||
"character", |
|
||||
"reference", |
|
||||
"name", |
|
||||
"replacement" |
|
||||
], |
|
||||
"license": "MIT", |
|
||||
"main": "index.json", |
|
||||
"name": "character-entities-html4", |
|
||||
"remarkConfig": { |
|
||||
"output": true, |
|
||||
"presets": "wooorm" |
|
||||
}, |
|
||||
"repository": { |
|
||||
"type": "git", |
|
||||
"url": "git+https://github.com/wooorm/character-entities-html4.git" |
|
||||
}, |
|
||||
"scripts": { |
|
||||
"build": "npm run build-md && npm run build-generate && npm run build-bundle && npm run build-mangle", |
|
||||
"build-bundle": "browserify index.json --bare -s characterEntitiesHTML4 > character-entities-html4.js", |
|
||||
"build-generate": "node build", |
|
||||
"build-mangle": "esmangle character-entities-html4.js > character-entities-html4.min.js", |
|
||||
"build-md": "remark . --quiet --frail", |
|
||||
"lint": "xo", |
|
||||
"test": "npm run build && npm run lint && npm run test-coverage", |
|
||||
"test-api": "node test", |
|
||||
"test-coverage": "nyc --reporter lcov tape test.js" |
|
||||
}, |
|
||||
"version": "1.1.0", |
|
||||
"xo": { |
|
||||
"space": true, |
|
||||
"ignores": [ |
|
||||
"character-entities-html4.js" |
|
||||
] |
|
||||
} |
|
||||
} |
|
@ -1,52 +0,0 @@ |
|||||
# character-entities-html4 [![Build Status][travis-badge]][travis] [![Coverage Status][codecov-badge]][codecov] |
|
||||
|
|
||||
HTML4 character entity information. |
|
||||
|
|
||||
## Installation |
|
||||
|
|
||||
[npm][npm-install]: |
|
||||
|
|
||||
```bash |
|
||||
npm install character-entities-html4 |
|
||||
``` |
|
||||
|
|
||||
## Usage |
|
||||
|
|
||||
```js |
|
||||
console.log(characterEntities.AElig); // Æ |
|
||||
console.log(characterEntities.aelig); // æ |
|
||||
console.log(characterEntities.amp); // & |
|
||||
console.log(characterEntities.apos); // undefined |
|
||||
``` |
|
||||
|
|
||||
## API |
|
||||
|
|
||||
### `characterEntitiesHTML4` |
|
||||
|
|
||||
Mapping between (case-sensitive) character entity names to replacements. |
|
||||
|
|
||||
## Support |
|
||||
|
|
||||
See [w3.org][html]. |
|
||||
|
|
||||
## License |
|
||||
|
|
||||
[MIT][license] © [Titus Wormer][author] |
|
||||
|
|
||||
<!-- Definitions --> |
|
||||
|
|
||||
[travis-badge]: https://img.shields.io/travis/wooorm/character-entities-html4.svg |
|
||||
|
|
||||
[travis]: https://travis-ci.org/wooorm/character-entities-html4 |
|
||||
|
|
||||
[codecov-badge]: https://img.shields.io/codecov/c/github/wooorm/character-entities-html4.svg |
|
||||
|
|
||||
[codecov]: https://codecov.io/github/wooorm/character-entities-html4 |
|
||||
|
|
||||
[npm-install]: https://docs.npmjs.com/cli/install |
|
||||
|
|
||||
[license]: LICENSE |
|
||||
|
|
||||
[author]: http://wooorm.com |
|
||||
|
|
||||
[html]: http://www.w3.org/TR/html4/sgml/entities.html |
|
@ -1,4 +1,6 @@ |
|||||
Copyright (c) 2013-2016 Ivan Nikulin (ifaaan@gmail.com, https://github.com/inikulin) |
The MIT License (MIT) |
||||
|
|
||||
|
Copyright (c) Feross Aboukhadijeh |
||||
|
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy |
Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
of this software and associated documentation files (the "Software"), to deal |
of this software and associated documentation files (the "Software"), to deal |
@ -0,0 +1,49 @@ |
|||||
|
# is-buffer [![travis][travis-image]][travis-url] [![npm][npm-image]][npm-url] [![downloads][downloads-image]][npm-url] |
||||
|
|
||||
|
#### Determine if an object is a [`Buffer`](http://nodejs.org/api/buffer.html) (including the [browserify Buffer](https://github.com/feross/buffer)) |
||||
|
|
||||
|
[![saucelabs][saucelabs-image]][saucelabs-url] |
||||
|
|
||||
|
[travis-image]: https://img.shields.io/travis/feross/is-buffer/master.svg |
||||
|
[travis-url]: https://travis-ci.org/feross/is-buffer |
||||
|
[npm-image]: https://img.shields.io/npm/v/is-buffer.svg |
||||
|
[npm-url]: https://npmjs.org/package/is-buffer |
||||
|
[downloads-image]: https://img.shields.io/npm/dm/is-buffer.svg |
||||
|
[saucelabs-image]: https://saucelabs.com/browser-matrix/is-buffer.svg |
||||
|
[saucelabs-url]: https://saucelabs.com/u/is-buffer |
||||
|
|
||||
|
## Why not use `Buffer.isBuffer`? |
||||
|
|
||||
|
This module lets you check if an object is a `Buffer` without using `Buffer.isBuffer` (which includes the whole [buffer](https://github.com/feross/buffer) module in [browserify](http://browserify.org/)). |
||||
|
|
||||
|
It's future-proof and works in node too! |
||||
|
|
||||
|
## install |
||||
|
|
||||
|
```bash |
||||
|
npm install is-buffer |
||||
|
``` |
||||
|
|
||||
|
## usage |
||||
|
|
||||
|
```js |
||||
|
var isBuffer = require('is-buffer') |
||||
|
|
||||
|
isBuffer(new Buffer(4)) // true |
||||
|
|
||||
|
isBuffer(undefined) // false |
||||
|
isBuffer(null) // false |
||||
|
isBuffer('') // false |
||||
|
isBuffer(true) // false |
||||
|
isBuffer(false) // false |
||||
|
isBuffer(0) // false |
||||
|
isBuffer(1) // false |
||||
|
isBuffer(1.0) // false |
||||
|
isBuffer('string') // false |
||||
|
isBuffer({}) // false |
||||
|
isBuffer(function foo () {}) // false |
||||
|
``` |
||||
|
|
||||
|
## license |
||||
|
|
||||
|
MIT. Copyright (C) [Feross Aboukhadijeh](http://feross.org). |
@ -0,0 +1,21 @@ |
|||||
|
/*! |
||||
|
* Determine if an object is a Buffer |
||||
|
* |
||||
|
* @author Feross Aboukhadijeh <feross@feross.org> <http://feross.org>
|
||||
|
* @license MIT |
||||
|
*/ |
||||
|
|
||||
|
// The _isBuffer check is for Safari 5-7 support, because it's missing
|
||||
|
// Object.prototype.constructor. Remove this eventually
|
||||
|
module.exports = function (obj) { |
||||
|
return obj != null && (isBuffer(obj) || isSlowBuffer(obj) || !!obj._isBuffer) |
||||
|
} |
||||
|
|
||||
|
function isBuffer (obj) { |
||||
|
return !!obj.constructor && typeof obj.constructor.isBuffer === 'function' && obj.constructor.isBuffer(obj) |
||||
|
} |
||||
|
|
||||
|
// For Node v0.10 support. Remove this eventually.
|
||||
|
function isSlowBuffer (obj) { |
||||
|
return typeof obj.readFloatLE === 'function' && typeof obj.slice === 'function' && isBuffer(obj.slice(0, 0)) |
||||
|
} |
@ -0,0 +1,77 @@ |
|||||
|
{ |
||||
|
"_from": "is-buffer@^1.1.4", |
||||
|
"_id": "is-buffer@1.1.5", |
||||
|
"_inBundle": false, |
||||
|
"_integrity": "sha1-Hzsm72E7IUuIy8ojzGwB2Hlh7sw=", |
||||
|
"_location": "/is-buffer", |
||||
|
"_phantomChildren": {}, |
||||
|
"_requested": { |
||||
|
"type": "range", |
||||
|
"registry": true, |
||||
|
"raw": "is-buffer@^1.1.4", |
||||
|
"name": "is-buffer", |
||||
|
"escapedName": "is-buffer", |
||||
|
"rawSpec": "^1.1.4", |
||||
|
"saveSpec": null, |
||||
|
"fetchSpec": "^1.1.4" |
||||
|
}, |
||||
|
"_requiredBy": [ |
||||
|
"/eslint-plugin-markdown/vfile" |
||||
|
], |
||||
|
"_resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.5.tgz", |
||||
|
"_shasum": "1f3b26ef613b214b88cbca23cc6c01d87961eecc", |
||||
|
"_spec": "is-buffer@^1.1.4", |
||||
|
"_where": "j:\\temp\\_git\\node-fork\\tools\\eslint\\node_modules\\eslint-plugin-markdown\\node_modules\\vfile", |
||||
|
"author": { |
||||
|
"name": "Feross Aboukhadijeh", |
||||
|
"email": "feross@feross.org", |
||||
|
"url": "http://feross.org/" |
||||
|
}, |
||||
|
"bugs": { |
||||
|
"url": "https://github.com/feross/is-buffer/issues" |
||||
|
}, |
||||
|
"bundleDependencies": false, |
||||
|
"dependencies": {}, |
||||
|
"deprecated": false, |
||||
|
"description": "Determine if an object is a Buffer", |
||||
|
"devDependencies": { |
||||
|
"standard": "*", |
||||
|
"tape": "^4.0.0", |
||||
|
"zuul": "^3.0.0" |
||||
|
}, |
||||
|
"homepage": "https://github.com/feross/is-buffer#readme", |
||||
|
"keywords": [ |
||||
|
"buffer", |
||||
|
"buffers", |
||||
|
"type", |
||||
|
"core buffer", |
||||
|
"browser buffer", |
||||
|
"browserify", |
||||
|
"typed array", |
||||
|
"uint32array", |
||||
|
"int16array", |
||||
|
"int32array", |
||||
|
"float32array", |
||||
|
"float64array", |
||||
|
"browser", |
||||
|
"arraybuffer", |
||||
|
"dataview" |
||||
|
], |
||||
|
"license": "MIT", |
||||
|
"main": "index.js", |
||||
|
"name": "is-buffer", |
||||
|
"repository": { |
||||
|
"type": "git", |
||||
|
"url": "git://github.com/feross/is-buffer.git" |
||||
|
}, |
||||
|
"scripts": { |
||||
|
"test": "standard && npm run test-node && npm run test-browser", |
||||
|
"test-browser": "zuul -- test/*.js", |
||||
|
"test-browser-local": "zuul --local -- test/*.js", |
||||
|
"test-node": "tape test/*.js" |
||||
|
}, |
||||
|
"testling": { |
||||
|
"files": "test/*.js" |
||||
|
}, |
||||
|
"version": "1.1.5" |
||||
|
} |
@ -0,0 +1,7 @@ |
|||||
|
'use strict'; |
||||
|
var toString = Object.prototype.toString; |
||||
|
|
||||
|
module.exports = function (x) { |
||||
|
var prototype; |
||||
|
return toString.call(x) === '[object Object]' && (prototype = Object.getPrototypeOf(x), prototype === null || prototype === Object.getPrototypeOf({})); |
||||
|
}; |
@ -0,0 +1,21 @@ |
|||||
|
The MIT License (MIT) |
||||
|
|
||||
|
Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.com) |
||||
|
|
||||
|
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. |
@ -0,0 +1,68 @@ |
|||||
|
{ |
||||
|
"_from": "is-plain-obj@^1.1.0", |
||||
|
"_id": "is-plain-obj@1.1.0", |
||||
|
"_inBundle": false, |
||||
|
"_integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=", |
||||
|
"_location": "/is-plain-obj", |
||||
|
"_phantomChildren": {}, |
||||
|
"_requested": { |
||||
|
"type": "range", |
||||
|
"registry": true, |
||||
|
"raw": "is-plain-obj@^1.1.0", |
||||
|
"name": "is-plain-obj", |
||||
|
"escapedName": "is-plain-obj", |
||||
|
"rawSpec": "^1.1.0", |
||||
|
"saveSpec": null, |
||||
|
"fetchSpec": "^1.1.0" |
||||
|
}, |
||||
|
"_requiredBy": [ |
||||
|
"/eslint-plugin-markdown/unified" |
||||
|
], |
||||
|
"_resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", |
||||
|
"_shasum": "71a50c8429dfca773c92a390a4a03b39fcd51d3e", |
||||
|
"_spec": "is-plain-obj@^1.1.0", |
||||
|
"_where": "j:\\temp\\_git\\node-fork\\tools\\eslint\\node_modules\\eslint-plugin-markdown\\node_modules\\unified", |
||||
|
"author": { |
||||
|
"name": "Sindre Sorhus", |
||||
|
"email": "sindresorhus@gmail.com", |
||||
|
"url": "sindresorhus.com" |
||||
|
}, |
||||
|
"bugs": { |
||||
|
"url": "https://github.com/sindresorhus/is-plain-obj/issues" |
||||
|
}, |
||||
|
"bundleDependencies": false, |
||||
|
"deprecated": false, |
||||
|
"description": "Check if a value is a plain object", |
||||
|
"devDependencies": { |
||||
|
"ava": "0.0.4" |
||||
|
}, |
||||
|
"engines": { |
||||
|
"node": ">=0.10.0" |
||||
|
}, |
||||
|
"files": [ |
||||
|
"index.js" |
||||
|
], |
||||
|
"homepage": "https://github.com/sindresorhus/is-plain-obj#readme", |
||||
|
"keywords": [ |
||||
|
"obj", |
||||
|
"object", |
||||
|
"is", |
||||
|
"check", |
||||
|
"test", |
||||
|
"type", |
||||
|
"plain", |
||||
|
"vanilla", |
||||
|
"pure", |
||||
|
"simple" |
||||
|
], |
||||
|
"license": "MIT", |
||||
|
"name": "is-plain-obj", |
||||
|
"repository": { |
||||
|
"type": "git", |
||||
|
"url": "git+https://github.com/sindresorhus/is-plain-obj.git" |
||||
|
}, |
||||
|
"scripts": { |
||||
|
"test": "node test.js" |
||||
|
}, |
||||
|
"version": "1.1.0" |
||||
|
} |
@ -0,0 +1,35 @@ |
|||||
|
# is-plain-obj [](https://travis-ci.org/sindresorhus/is-plain-obj) |
||||
|
|
||||
|
> Check if a value is a plain object |
||||
|
|
||||
|
An object is plain if it's created by either `{}`, `new Object()` or `Object.create(null)`. |
||||
|
|
||||
|
|
||||
|
## Install |
||||
|
|
||||
|
``` |
||||
|
$ npm install --save is-plain-obj |
||||
|
``` |
||||
|
|
||||
|
|
||||
|
## Usage |
||||
|
|
||||
|
```js |
||||
|
var isPlainObj = require('is-plain-obj'); |
||||
|
|
||||
|
isPlainObj({foo: 'bar'}); |
||||
|
//=> true |
||||
|
|
||||
|
isPlainObj([1, 2, 3]); |
||||
|
//=> false |
||||
|
``` |
||||
|
|
||||
|
|
||||
|
## Related |
||||
|
|
||||
|
- [is-obj](https://github.com/sindresorhus/is-obj) - Check if a value is an object |
||||
|
|
||||
|
|
||||
|
## License |
||||
|
|
||||
|
MIT © [Sindre Sorhus](http://sindresorhus.com) |
@ -1,6 +1,6 @@ |
|||||
(The MIT License) |
(The MIT License) |
||||
|
|
||||
Copyright (c) 2015 Titus Wormer <tituswormer@gmail.com> |
Copyright (c) 2016 Titus Wormer <tituswormer@gmail.com> |
||||
|
|
||||
Permission is hereby granted, free of charge, to any person obtaining |
Permission is hereby granted, free of charge, to any person obtaining |
||||
a copy of this software and associated documentation files (the |
a copy of this software and associated documentation files (the |
@ -1,9 +1,6 @@ |
|||||
--- |
<!--remark setext--> |
||||
mdast: |
|
||||
setext: true |
|
||||
--- |
|
||||
|
|
||||
<!--lint disable no-multiple-toplevel-headings --> |
<!--lint disable no-multiple-toplevel-headings --> |
||||
|
|
||||
1.0.0 / 2015-07-12 |
1.0.0 / 2016-07-12 |
||||
================== |
================== |
@ -0,0 +1,33 @@ |
|||||
|
/** |
||||
|
* @author Titus Wormer |
||||
|
* @copyright 2016 Titus Wormer |
||||
|
* @license MIT |
||||
|
* @module is-whitespace-character |
||||
|
* @fileoverview Check if a character is a whitespace character. |
||||
|
*/ |
||||
|
|
||||
|
'use strict'; |
||||
|
|
||||
|
/* eslint-env commonjs */ |
||||
|
|
||||
|
/* Expose. */ |
||||
|
module.exports = whitespace; |
||||
|
|
||||
|
/* Methods. */ |
||||
|
var fromCode = String.fromCharCode; |
||||
|
|
||||
|
/* Constants. */ |
||||
|
var re = /\s/; |
||||
|
|
||||
|
/** |
||||
|
* Check whether the given character code, or the character |
||||
|
* code at the first character, is a whitespace character. |
||||
|
* |
||||
|
* @param {string|number} character |
||||
|
* @return {boolean} - Whether `character` is a whitespaces character. |
||||
|
*/ |
||||
|
function whitespace(character) { |
||||
|
return re.test( |
||||
|
typeof character === 'number' ? fromCode(character) : character.charAt(0) |
||||
|
); |
||||
|
} |
@ -0,0 +1,111 @@ |
|||||
|
{ |
||||
|
"_from": "is-whitespace-character@^1.0.0", |
||||
|
"_id": "is-whitespace-character@1.0.0", |
||||
|
"_inBundle": false, |
||||
|
"_integrity": "sha1-u/SoN2Tq0NRRvsKlUhjpGWGtwnU=", |
||||
|
"_location": "/is-whitespace-character", |
||||
|
"_phantomChildren": {}, |
||||
|
"_requested": { |
||||
|
"type": "range", |
||||
|
"registry": true, |
||||
|
"raw": "is-whitespace-character@^1.0.0", |
||||
|
"name": "is-whitespace-character", |
||||
|
"escapedName": "is-whitespace-character", |
||||
|
"rawSpec": "^1.0.0", |
||||
|
"saveSpec": null, |
||||
|
"fetchSpec": "^1.0.0" |
||||
|
}, |
||||
|
"_requiredBy": [ |
||||
|
"/eslint-plugin-markdown/remark-parse" |
||||
|
], |
||||
|
"_resolved": "https://registry.npmjs.org/is-whitespace-character/-/is-whitespace-character-1.0.0.tgz", |
||||
|
"_shasum": "bbf4a83764ead0d451bec2a55218e91961adc275", |
||||
|
"_spec": "is-whitespace-character@^1.0.0", |
||||
|
"_where": "j:\\temp\\_git\\node-fork\\tools\\eslint\\node_modules\\eslint-plugin-markdown\\node_modules\\remark-parse", |
||||
|
"author": { |
||||
|
"name": "Titus Wormer", |
||||
|
"email": "tituswormer@gmail.com", |
||||
|
"url": "http://wooorm.com" |
||||
|
}, |
||||
|
"bugs": { |
||||
|
"url": "https://github.com/wooorm/is-whitespace-character/issues" |
||||
|
}, |
||||
|
"bundleDependencies": false, |
||||
|
"contributors": [ |
||||
|
{ |
||||
|
"name": "Titus Wormer", |
||||
|
"email": "tituswormer@gmail.com", |
||||
|
"url": "http://wooorm.com" |
||||
|
} |
||||
|
], |
||||
|
"dependencies": {}, |
||||
|
"deprecated": false, |
||||
|
"description": "Check if a character is a whitespace character", |
||||
|
"devDependencies": { |
||||
|
"browserify": "^13.0.1", |
||||
|
"esmangle": "^1.0.1", |
||||
|
"nyc": "^7.0.0", |
||||
|
"remark-cli": "^1.0.0", |
||||
|
"remark-comment-config": "^4.0.0", |
||||
|
"remark-github": "^5.0.0", |
||||
|
"remark-lint": "^4.0.0", |
||||
|
"remark-validate-links": "^4.0.0", |
||||
|
"tape": "^4.0.0", |
||||
|
"xo": "^0.16.0" |
||||
|
}, |
||||
|
"files": [ |
||||
|
"index.js" |
||||
|
], |
||||
|
"homepage": "https://github.com/wooorm/is-whitespace-character#readme", |
||||
|
"keywords": [ |
||||
|
"string", |
||||
|
"character", |
||||
|
"char", |
||||
|
"code", |
||||
|
"whitespace", |
||||
|
"white", |
||||
|
"space" |
||||
|
], |
||||
|
"license": "MIT", |
||||
|
"name": "is-whitespace-character", |
||||
|
"nyc": { |
||||
|
"check-coverage": true, |
||||
|
"lines": 100, |
||||
|
"functions": 100, |
||||
|
"branches": 100 |
||||
|
}, |
||||
|
"remarkConfig": { |
||||
|
"output": true, |
||||
|
"plugins": [ |
||||
|
"comment-config", |
||||
|
"github", |
||||
|
"lint", |
||||
|
"validate-links" |
||||
|
], |
||||
|
"settings": { |
||||
|
"bullet": "*" |
||||
|
} |
||||
|
}, |
||||
|
"repository": { |
||||
|
"type": "git", |
||||
|
"url": "git+https://github.com/wooorm/is-whitespace-character.git" |
||||
|
}, |
||||
|
"scripts": { |
||||
|
"build": "npm run build-md && npm run build-bundle && npm run build-mangle", |
||||
|
"build-bundle": "browserify index.js --bare -s isWhitespaceCharacter > is-whitespace-character.js", |
||||
|
"build-mangle": "esmangle < is-whitespace-character.js > is-whitespace-character.min.js", |
||||
|
"build-md": "remark . --quiet --frail", |
||||
|
"lint": "xo", |
||||
|
"test": "npm run build && npm run lint && npm run test-coverage", |
||||
|
"test-api": "node test", |
||||
|
"test-coverage": "nyc --reporter lcov tape test.js" |
||||
|
}, |
||||
|
"version": "1.0.0", |
||||
|
"xo": { |
||||
|
"space": true, |
||||
|
"ignores": [ |
||||
|
"is-whitespace-character.js", |
||||
|
"is-whitespace-character.min.js" |
||||
|
] |
||||
|
} |
||||
|
} |
@ -0,0 +1,63 @@ |
|||||
|
# is-whitespace-character [![Build Status][travis-badge]][travis] [![Coverage Status][codecov-badge]][codecov] |
||||
|
|
||||
|
<!--lint disable heading-increment list-item-spacing--> |
||||
|
|
||||
|
Check if a character is a whitespace character: `\s`, which equals |
||||
|
all Unicode Space Separators (including `[ \t\v\f]`), the BOM |
||||
|
(`\uFEFF`), and line terminator (`[\n\r\u2028\u2029]`). |
||||
|
|
||||
|
## Installation |
||||
|
|
||||
|
[npm][npm-install]: |
||||
|
|
||||
|
```bash |
||||
|
npm install is-whitespace-character |
||||
|
``` |
||||
|
|
||||
|
## Usage |
||||
|
|
||||
|
```javascript |
||||
|
var whitespace = require('is-whitespace-character'); |
||||
|
|
||||
|
whitespace(' '); // true |
||||
|
whitespace('\n'); // true |
||||
|
whitespace('\ufeff'); // true |
||||
|
whitespace('_'); // false |
||||
|
whitespace('a'); // true |
||||
|
whitespace('💩'); // false |
||||
|
``` |
||||
|
|
||||
|
## API |
||||
|
|
||||
|
### `whitespaceCharacter(character)` |
||||
|
|
||||
|
Check whether the given character code (`number`), or the character |
||||
|
code at the first position (`string`), is a whitespace character. |
||||
|
|
||||
|
## Related |
||||
|
|
||||
|
* [`is-alphabetical`](https://github.com/wooorm/is-alphabetical) |
||||
|
* [`is-alphanumerical`](https://github.com/wooorm/is-alphanumerical) |
||||
|
* [`is-decimal`](https://github.com/wooorm/is-decimal) |
||||
|
* [`is-hexadecimal`](https://github.com/wooorm/is-hexadecimal) |
||||
|
* [`is-word-character`](https://github.com/wooorm/is-word-character) |
||||
|
|
||||
|
## License |
||||
|
|
||||
|
[MIT][license] © [Titus Wormer][author] |
||||
|
|
||||
|
<!-- Definitions --> |
||||
|
|
||||
|
[travis-badge]: https://img.shields.io/travis/wooorm/is-whitespace-character.svg |
||||
|
|
||||
|
[travis]: https://travis-ci.org/wooorm/is-whitespace-character |
||||
|
|
||||
|
[codecov-badge]: https://img.shields.io/codecov/c/github/wooorm/is-whitespace-character.svg |
||||
|
|
||||
|
[codecov]: https://codecov.io/github/wooorm/is-whitespace-character |
||||
|
|
||||
|
[npm-install]: https://docs.npmjs.com/cli/install |
||||
|
|
||||
|
[license]: LICENSE |
||||
|
|
||||
|
[author]: http://wooorm.com |
@ -1,6 +1,6 @@ |
|||||
(The MIT License) |
(The MIT License) |
||||
|
|
||||
Copyright (c) 2015 Titus Wormer <tituswormer@gmail.com> |
Copyright (c) 2016 Titus Wormer <tituswormer@gmail.com> |
||||
|
|
||||
Permission is hereby granted, free of charge, to any person obtaining |
Permission is hereby granted, free of charge, to any person obtaining |
||||
a copy of this software and associated documentation files (the |
a copy of this software and associated documentation files (the |
@ -0,0 +1,6 @@ |
|||||
|
<!--remark setext--> |
||||
|
|
||||
|
<!--lint disable no-multiple-toplevel-headings --> |
||||
|
|
||||
|
1.0.0 / 2016-07-12 |
||||
|
================== |
@ -0,0 +1,33 @@ |
|||||
|
/** |
||||
|
* @author Titus Wormer |
||||
|
* @copyright 2016 Titus Wormer |
||||
|
* @license MIT |
||||
|
* @module is-word-character |
||||
|
* @fileoverview Check if a character is a word character. |
||||
|
*/ |
||||
|
|
||||
|
'use strict'; |
||||
|
|
||||
|
/* eslint-env commonjs */ |
||||
|
|
||||
|
/* Expose. */ |
||||
|
module.exports = wordCharacter; |
||||
|
|
||||
|
/* Methods. */ |
||||
|
var fromCode = String.fromCharCode; |
||||
|
|
||||
|
/* Constants. */ |
||||
|
var re = /\w/; |
||||
|
|
||||
|
/** |
||||
|
* Check whether the given character code, or the character |
||||
|
* code at the first character, is a word character. |
||||
|
* |
||||
|
* @param {string|number} character |
||||
|
* @return {boolean} - Whether `character` is a word character. |
||||
|
*/ |
||||
|
function wordCharacter(character) { |
||||
|
return re.test( |
||||
|
typeof character === 'number' ? fromCode(character) : character.charAt(0) |
||||
|
); |
||||
|
} |
@ -0,0 +1,109 @@ |
|||||
|
{ |
||||
|
"_from": "is-word-character@^1.0.0", |
||||
|
"_id": "is-word-character@1.0.0", |
||||
|
"_inBundle": false, |
||||
|
"_integrity": "sha1-o6nl3a1wxcLuNvSpz8mlP0RTUkc=", |
||||
|
"_location": "/is-word-character", |
||||
|
"_phantomChildren": {}, |
||||
|
"_requested": { |
||||
|
"type": "range", |
||||
|
"registry": true, |
||||
|
"raw": "is-word-character@^1.0.0", |
||||
|
"name": "is-word-character", |
||||
|
"escapedName": "is-word-character", |
||||
|
"rawSpec": "^1.0.0", |
||||
|
"saveSpec": null, |
||||
|
"fetchSpec": "^1.0.0" |
||||
|
}, |
||||
|
"_requiredBy": [ |
||||
|
"/eslint-plugin-markdown/remark-parse" |
||||
|
], |
||||
|
"_resolved": "https://registry.npmjs.org/is-word-character/-/is-word-character-1.0.0.tgz", |
||||
|
"_shasum": "a3a9e5ddad70c5c2ee36f4a9cfc9a53f44535247", |
||||
|
"_spec": "is-word-character@^1.0.0", |
||||
|
"_where": "j:\\temp\\_git\\node-fork\\tools\\eslint\\node_modules\\eslint-plugin-markdown\\node_modules\\remark-parse", |
||||
|
"author": { |
||||
|
"name": "Titus Wormer", |
||||
|
"email": "tituswormer@gmail.com", |
||||
|
"url": "http://wooorm.com" |
||||
|
}, |
||||
|
"bugs": { |
||||
|
"url": "https://github.com/wooorm/is-word-character/issues" |
||||
|
}, |
||||
|
"bundleDependencies": false, |
||||
|
"contributors": [ |
||||
|
{ |
||||
|
"name": "Titus Wormer", |
||||
|
"email": "tituswormer@gmail.com", |
||||
|
"url": "http://wooorm.com" |
||||
|
} |
||||
|
], |
||||
|
"dependencies": {}, |
||||
|
"deprecated": false, |
||||
|
"description": "Check if a character is a word character", |
||||
|
"devDependencies": { |
||||
|
"browserify": "^13.0.1", |
||||
|
"esmangle": "^1.0.1", |
||||
|
"nyc": "^7.0.0", |
||||
|
"remark-cli": "^1.0.0", |
||||
|
"remark-comment-config": "^4.0.0", |
||||
|
"remark-github": "^5.0.0", |
||||
|
"remark-lint": "^4.0.0", |
||||
|
"remark-validate-links": "^4.0.0", |
||||
|
"tape": "^4.0.0", |
||||
|
"xo": "^0.16.0" |
||||
|
}, |
||||
|
"files": [ |
||||
|
"index.js" |
||||
|
], |
||||
|
"homepage": "https://github.com/wooorm/is-word-character#readme", |
||||
|
"keywords": [ |
||||
|
"string", |
||||
|
"character", |
||||
|
"char", |
||||
|
"code", |
||||
|
"word" |
||||
|
], |
||||
|
"license": "MIT", |
||||
|
"name": "is-word-character", |
||||
|
"nyc": { |
||||
|
"check-coverage": true, |
||||
|
"lines": 100, |
||||
|
"functions": 100, |
||||
|
"branches": 100 |
||||
|
}, |
||||
|
"remarkConfig": { |
||||
|
"output": true, |
||||
|
"plugins": [ |
||||
|
"comment-config", |
||||
|
"github", |
||||
|
"lint", |
||||
|
"validate-links" |
||||
|
], |
||||
|
"settings": { |
||||
|
"bullet": "*" |
||||
|
} |
||||
|
}, |
||||
|
"repository": { |
||||
|
"type": "git", |
||||
|
"url": "git+https://github.com/wooorm/is-word-character.git" |
||||
|
}, |
||||
|
"scripts": { |
||||
|
"build": "npm run build-md && npm run build-bundle && npm run build-mangle", |
||||
|
"build-bundle": "browserify index.js --bare -s isWordCharacter > is-word-character.js", |
||||
|
"build-mangle": "esmangle < is-word-character.js > is-word-character.min.js", |
||||
|
"build-md": "remark . --quiet --frail", |
||||
|
"lint": "xo", |
||||
|
"test": "npm run build && npm run lint && npm run test-coverage", |
||||
|
"test-api": "node test", |
||||
|
"test-coverage": "nyc --reporter lcov tape test.js" |
||||
|
}, |
||||
|
"version": "1.0.0", |
||||
|
"xo": { |
||||
|
"space": true, |
||||
|
"ignores": [ |
||||
|
"is-word-character.js", |
||||
|
"is-word-character.min.js" |
||||
|
] |
||||
|
} |
||||
|
} |
@ -0,0 +1,62 @@ |
|||||
|
# is-word-character [![Build Status][travis-badge]][travis] [![Coverage Status][codecov-badge]][codecov] |
||||
|
|
||||
|
<!--lint disable heading-increment list-item-spacing--> |
||||
|
|
||||
|
Check if a character is a word character (`\w`, which equals |
||||
|
`[a-zA-Z0-9_]`). |
||||
|
|
||||
|
## Installation |
||||
|
|
||||
|
[npm][npm-install]: |
||||
|
|
||||
|
```bash |
||||
|
npm install is-word-character |
||||
|
``` |
||||
|
|
||||
|
## Usage |
||||
|
|
||||
|
```javascript |
||||
|
var wordCharacter = require('is-word-character'); |
||||
|
|
||||
|
wordCharacter('a'); // true |
||||
|
wordCharacter('Z'); // true |
||||
|
wordCharacter('0'); // true |
||||
|
wordCharacter('_'); // true |
||||
|
wordCharacter(' '); // false |
||||
|
wordCharacter('💩'); // false |
||||
|
``` |
||||
|
|
||||
|
## API |
||||
|
|
||||
|
### `wordCharacter(character)` |
||||
|
|
||||
|
Check whether the given character code (`number`), or the character |
||||
|
code at the first position (`string`), is a word character. |
||||
|
|
||||
|
## Related |
||||
|
|
||||
|
* [`is-alphabetical`](https://github.com/wooorm/is-alphabetical) |
||||
|
* [`is-alphanumerical`](https://github.com/wooorm/is-alphanumerical) |
||||
|
* [`is-decimal`](https://github.com/wooorm/is-decimal) |
||||
|
* [`is-hexadecimal`](https://github.com/wooorm/is-hexadecimal) |
||||
|
* [`is-whitespace-character`](https://github.com/wooorm/is-whitespace-character) |
||||
|
|
||||
|
## License |
||||
|
|
||||
|
[MIT][license] © [Titus Wormer][author] |
||||
|
|
||||
|
<!-- Definitions --> |
||||
|
|
||||
|
[travis-badge]: https://img.shields.io/travis/wooorm/is-word-character.svg |
||||
|
|
||||
|
[travis]: https://travis-ci.org/wooorm/is-word-character |
||||
|
|
||||
|
[codecov-badge]: https://img.shields.io/codecov/c/github/wooorm/is-word-character.svg |
||||
|
|
||||
|
[codecov]: https://codecov.io/github/wooorm/is-word-character |
||||
|
|
||||
|
[npm-install]: https://docs.npmjs.com/cli/install |
||||
|
|
||||
|
[license]: LICENSE |
||||
|
|
||||
|
[author]: http://wooorm.com |
@ -1,51 +0,0 @@ |
|||||
'use strict'; |
|
||||
|
|
||||
/** |
|
||||
* Get the count of the longest repeating streak of |
|
||||
* `character` in `value`. |
|
||||
* |
|
||||
* @example |
|
||||
* longestStreak('` foo `` bar `', '`') // 2
|
|
||||
* |
|
||||
* @param {string} value - Content, coerced to string. |
|
||||
* @param {string} character - Single character to look |
|
||||
* for. |
|
||||
* @return {number} - Number of characters at the place |
|
||||
* where `character` occurs in its longest streak in |
|
||||
* `value`. |
|
||||
* @throws {Error} - when `character` is not a single |
|
||||
* character. |
|
||||
*/ |
|
||||
function longestStreak(value, character) { |
|
||||
var count = 0; |
|
||||
var maximum = 0; |
|
||||
var index = -1; |
|
||||
var length; |
|
||||
|
|
||||
value = String(value); |
|
||||
length = value.length; |
|
||||
|
|
||||
if (typeof character !== 'string' || character.length !== 1) { |
|
||||
throw new Error('Expected character'); |
|
||||
} |
|
||||
|
|
||||
while (++index < length) { |
|
||||
if (value.charAt(index) === character) { |
|
||||
count++; |
|
||||
|
|
||||
if (count > maximum) { |
|
||||
maximum = count; |
|
||||
} |
|
||||
} else { |
|
||||
count = 0; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
return maximum; |
|
||||
} |
|
||||
|
|
||||
/* |
|
||||
* Expose. |
|
||||
*/ |
|
||||
|
|
||||
module.exports = longestStreak; |
|
@ -1,83 +0,0 @@ |
|||||
{ |
|
||||
"_from": "longest-streak@^1.0.0", |
|
||||
"_id": "longest-streak@1.0.0", |
|
||||
"_inBundle": false, |
|
||||
"_integrity": "sha1-0GWXxNTDG1LMsfXY+P5xSOr9aWU=", |
|
||||
"_location": "/longest-streak", |
|
||||
"_phantomChildren": {}, |
|
||||
"_requested": { |
|
||||
"type": "range", |
|
||||
"registry": true, |
|
||||
"raw": "longest-streak@^1.0.0", |
|
||||
"name": "longest-streak", |
|
||||
"escapedName": "longest-streak", |
|
||||
"rawSpec": "^1.0.0", |
|
||||
"saveSpec": null, |
|
||||
"fetchSpec": "^1.0.0" |
|
||||
}, |
|
||||
"_requiredBy": [ |
|
||||
"/remark-stringify" |
|
||||
], |
|
||||
"_resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-1.0.0.tgz", |
|
||||
"_shasum": "d06597c4d4c31b52ccb1f5d8f8fe7148eafd6965", |
|
||||
"_spec": "longest-streak@^1.0.0", |
|
||||
"_where": "/Users/trott/io.js/tools/eslint-tmp/node_modules/eslint/node_modules/remark-stringify", |
|
||||
"author": { |
|
||||
"name": "Titus Wormer", |
|
||||
"email": "tituswormer@gmail.com" |
|
||||
}, |
|
||||
"bugs": { |
|
||||
"url": "https://github.com/wooorm/longest-streak/issues" |
|
||||
}, |
|
||||
"bundleDependencies": false, |
|
||||
"deprecated": false, |
|
||||
"description": "Count the longest repeating streak of a character", |
|
||||
"devDependencies": { |
|
||||
"browserify": "^10.0.0", |
|
||||
"eslint": "^0.24.0", |
|
||||
"esmangle": "^1.0.0", |
|
||||
"istanbul": "^0.3.0", |
|
||||
"jscs": "^1.0.0", |
|
||||
"jscs-jsdoc": "^1.0.0", |
|
||||
"mdast": "^0.26.0", |
|
||||
"mdast-github": "^0.3.1", |
|
||||
"mdast-lint": "^0.4.1", |
|
||||
"mdast-yaml-config": "^0.2.0", |
|
||||
"mocha": "^2.0.0" |
|
||||
}, |
|
||||
"files": [ |
|
||||
"index.js", |
|
||||
"LICENSE" |
|
||||
], |
|
||||
"homepage": "https://github.com/wooorm/longest-streak#readme", |
|
||||
"keywords": [ |
|
||||
"count", |
|
||||
"length", |
|
||||
"longest", |
|
||||
"repeating", |
|
||||
"streak", |
|
||||
"character" |
|
||||
], |
|
||||
"license": "MIT", |
|
||||
"name": "longest-streak", |
|
||||
"repository": { |
|
||||
"type": "git", |
|
||||
"url": "git+https://github.com/wooorm/longest-streak.git" |
|
||||
}, |
|
||||
"scripts": { |
|
||||
"build": "npm run build-md && npm run build-bundle", |
|
||||
"build-bundle": "browserify index.js --bare -s longestStreak > longest-streak.js", |
|
||||
"build-md": "mdast . LICENSE --output --quiet", |
|
||||
"lint": "npm run lint-api && npm run lint-style", |
|
||||
"lint-api": "eslint .", |
|
||||
"lint-style": "jscs --reporter inline .", |
|
||||
"make": "npm run lint && npm run test-coverage", |
|
||||
"postbuild-bundle": "esmangle longest-streak.js > longest-streak.min.js", |
|
||||
"test": "npm run test-api", |
|
||||
"test-api": "mocha --check-leaks test.js", |
|
||||
"test-coverage": "istanbul cover _mocha -- --check-leaks test.js", |
|
||||
"test-coveralls": "istanbul cover _mocha --report lcovonly -- --check-leaks test.js", |
|
||||
"test-travis": "npm run test-coveralls" |
|
||||
}, |
|
||||
"version": "1.0.0" |
|
||||
} |
|
@ -1,52 +0,0 @@ |
|||||
# longest-streak [](https://travis-ci.org/wooorm/longest-streak) [](https://coveralls.io/r/wooorm/longest-streak?branch=master) |
|
||||
|
|
||||
Count the longest repeating streak of a character. |
|
||||
|
|
||||
## Installation |
|
||||
|
|
||||
[npm](https://docs.npmjs.com/cli/install): |
|
||||
|
|
||||
```bash |
|
||||
npm install longest-streak |
|
||||
``` |
|
||||
|
|
||||
**longest-streak** is also available for [bower](http://bower.io/#install-packages), |
|
||||
[component](https://github.com/componentjs/component), [duo](http://duojs.org/#getting-started), |
|
||||
and for AMD, CommonJS, and globals ([uncompressed](longest-streak.js) and |
|
||||
[compressed](longest-streak.min.js)). |
|
||||
|
|
||||
## Usage |
|
||||
|
|
||||
Dependencies. |
|
||||
|
|
||||
```javascript |
|
||||
var longestStreak = require('longest-streak'); |
|
||||
``` |
|
||||
|
|
||||
Process: |
|
||||
|
|
||||
```javascript |
|
||||
longestStreak('` foo `` bar `', '`') // 2 |
|
||||
``` |
|
||||
|
|
||||
## API |
|
||||
|
|
||||
### longestStreak(value, character) |
|
||||
|
|
||||
Get the count of the longest repeating streak of `character` in `value`. |
|
||||
|
|
||||
Parameters: |
|
||||
|
|
||||
* `value` (`string`) — Content, coerced to string. |
|
||||
* `character` (`string`) — Single character to look for. |
|
||||
|
|
||||
Returns: `number` — Number of characters at the place where `character` |
|
||||
occurs in its longest streak in `value`. |
|
||||
|
|
||||
Throws: |
|
||||
|
|
||||
* `Error` — when `character` is not a single character string. |
|
||||
|
|
||||
## License |
|
||||
|
|
||||
[MIT](LICENSE) @ [Titus Wormer](http://wooorm.com) |
|
@ -1,6 +1,6 @@ |
|||||
(The MIT License) |
(The MIT License) |
||||
|
|
||||
Copyright (c) 2014-2015 Titus Wormer <tituswormer@gmail.com> |
Copyright (c) 2016 Titus Wormer <tituswormer@gmail.com> |
||||
|
|
||||
Permission is hereby granted, free of charge, to any person obtaining |
Permission is hereby granted, free of charge, to any person obtaining |
||||
a copy of this software and associated documentation files (the |
a copy of this software and associated documentation files (the |
@ -0,0 +1,6 @@ |
|||||
|
<!--remark setext--> |
||||
|
|
||||
|
<!--lint disable no-multiple-toplevel-headings --> |
||||
|
|
||||
|
1.0.0 / 2016-07-16 |
||||
|
================== |
@ -0,0 +1,75 @@ |
|||||
|
/** |
||||
|
* @author Titus Wormer |
||||
|
* @copyright 2016 Titus Wormer |
||||
|
* @license MIT |
||||
|
* @module markdown-escapes |
||||
|
* @fileoverview List of escapable characters in markdown. |
||||
|
*/ |
||||
|
|
||||
|
'use strict'; |
||||
|
|
||||
|
/* eslint-env commonjs */ |
||||
|
|
||||
|
/* Expose. */ |
||||
|
module.exports = escapes; |
||||
|
|
||||
|
/* Characters. */ |
||||
|
var defaults = [ |
||||
|
'\\', |
||||
|
'`', |
||||
|
'*', |
||||
|
'{', |
||||
|
'}', |
||||
|
'[', |
||||
|
']', |
||||
|
'(', |
||||
|
')', |
||||
|
'#', |
||||
|
'+', |
||||
|
'-', |
||||
|
'.', |
||||
|
'!', |
||||
|
'_', |
||||
|
'>' |
||||
|
]; |
||||
|
|
||||
|
var gfm = defaults.concat(['~', '|']); |
||||
|
|
||||
|
var commonmark = gfm.concat([ |
||||
|
'\n', |
||||
|
'"', |
||||
|
'$', |
||||
|
'%', |
||||
|
'&', |
||||
|
'\'', |
||||
|
',', |
||||
|
'/', |
||||
|
':', |
||||
|
';', |
||||
|
'<', |
||||
|
'=', |
||||
|
'?', |
||||
|
'@', |
||||
|
'^' |
||||
|
]); |
||||
|
|
||||
|
/* Expose characters. */ |
||||
|
escapes.default = defaults; |
||||
|
escapes.gfm = gfm; |
||||
|
escapes.commonmark = commonmark; |
||||
|
|
||||
|
/** |
||||
|
* Get markdown escapes. |
||||
|
* |
||||
|
* @param {Object?} [options] - Configuration. |
||||
|
* @return {Array.<string>} - Escapes. |
||||
|
*/ |
||||
|
function escapes(options) { |
||||
|
var settings = options || {}; |
||||
|
|
||||
|
if (settings.commonmark) { |
||||
|
return commonmark; |
||||
|
} |
||||
|
|
||||
|
return settings.gfm ? gfm : defaults; |
||||
|
} |
@ -0,0 +1,109 @@ |
|||||
|
{ |
||||
|
"_from": "markdown-escapes@^1.0.0", |
||||
|
"_id": "markdown-escapes@1.0.0", |
||||
|
"_inBundle": false, |
||||
|
"_integrity": "sha1-yMoZ8dlNaCRZ4Kk8htsnp+9xayM=", |
||||
|
"_location": "/markdown-escapes", |
||||
|
"_phantomChildren": {}, |
||||
|
"_requested": { |
||||
|
"type": "range", |
||||
|
"registry": true, |
||||
|
"raw": "markdown-escapes@^1.0.0", |
||||
|
"name": "markdown-escapes", |
||||
|
"escapedName": "markdown-escapes", |
||||
|
"rawSpec": "^1.0.0", |
||||
|
"saveSpec": null, |
||||
|
"fetchSpec": "^1.0.0" |
||||
|
}, |
||||
|
"_requiredBy": [ |
||||
|
"/eslint-plugin-markdown/remark-parse" |
||||
|
], |
||||
|
"_resolved": "https://registry.npmjs.org/markdown-escapes/-/markdown-escapes-1.0.0.tgz", |
||||
|
"_shasum": "c8ca19f1d94d682459e0a93c86db27a7ef716b23", |
||||
|
"_spec": "markdown-escapes@^1.0.0", |
||||
|
"_where": "j:\\temp\\_git\\node-fork\\tools\\eslint\\node_modules\\eslint-plugin-markdown\\node_modules\\remark-parse", |
||||
|
"author": { |
||||
|
"name": "Titus Wormer", |
||||
|
"email": "tituswormer@gmail.com", |
||||
|
"url": "http://wooorm.com" |
||||
|
}, |
||||
|
"bugs": { |
||||
|
"url": "https://github.com/wooorm/markdown-escapes/issues" |
||||
|
}, |
||||
|
"bundleDependencies": false, |
||||
|
"contributors": [ |
||||
|
{ |
||||
|
"name": "Titus Wormer", |
||||
|
"email": "tituswormer@gmail.com", |
||||
|
"url": "http://wooorm.com" |
||||
|
} |
||||
|
], |
||||
|
"dependencies": {}, |
||||
|
"deprecated": false, |
||||
|
"description": "List of escapable characters in markdown", |
||||
|
"devDependencies": { |
||||
|
"browserify": "^13.0.1", |
||||
|
"esmangle": "^1.0.1", |
||||
|
"nyc": "^7.0.0", |
||||
|
"remark-cli": "^1.0.0", |
||||
|
"remark-comment-config": "^4.0.0", |
||||
|
"remark-github": "^5.0.0", |
||||
|
"remark-lint": "^4.0.0", |
||||
|
"remark-validate-links": "^4.0.0", |
||||
|
"tape": "^4.0.0", |
||||
|
"xo": "^0.16.0" |
||||
|
}, |
||||
|
"files": [ |
||||
|
"index.js" |
||||
|
], |
||||
|
"homepage": "https://github.com/wooorm/markdown-escapes#readme", |
||||
|
"keywords": [ |
||||
|
"markdown", |
||||
|
"escape", |
||||
|
"pedantic", |
||||
|
"gfm", |
||||
|
"commonmark" |
||||
|
], |
||||
|
"license": "MIT", |
||||
|
"name": "markdown-escapes", |
||||
|
"nyc": { |
||||
|
"check-coverage": true, |
||||
|
"lines": 100, |
||||
|
"functions": 100, |
||||
|
"branches": 100 |
||||
|
}, |
||||
|
"remarkConfig": { |
||||
|
"output": true, |
||||
|
"plugins": [ |
||||
|
"comment-config", |
||||
|
"github", |
||||
|
"lint", |
||||
|
"validate-links" |
||||
|
], |
||||
|
"settings": { |
||||
|
"bullet": "*" |
||||
|
} |
||||
|
}, |
||||
|
"repository": { |
||||
|
"type": "git", |
||||
|
"url": "git+https://github.com/wooorm/markdown-escapes.git" |
||||
|
}, |
||||
|
"scripts": { |
||||
|
"build": "npm run build-md && npm run build-bundle && npm run build-mangle", |
||||
|
"build-bundle": "browserify index.js --bare -s markdownEscapes > markdown-escapes.js", |
||||
|
"build-mangle": "esmangle < markdown-escapes.js > markdown-escapes.min.js", |
||||
|
"build-md": "remark . --quiet --frail", |
||||
|
"lint": "xo", |
||||
|
"test": "npm run build && npm run lint && npm run test-coverage", |
||||
|
"test-api": "node test", |
||||
|
"test-coverage": "nyc --reporter lcov tape test.js" |
||||
|
}, |
||||
|
"version": "1.0.0", |
||||
|
"xo": { |
||||
|
"space": true, |
||||
|
"ignores": [ |
||||
|
"markdown-escapes.js", |
||||
|
"markdown-escapes.min.js" |
||||
|
] |
||||
|
} |
||||
|
} |
@ -0,0 +1,71 @@ |
|||||
|
# markdown-escapes [![Build Status][travis-badge]][travis] [![Coverage Status][codecov-badge]][codecov] |
||||
|
|
||||
|
<!--lint disable heading-increment no-duplicate-headings--> |
||||
|
|
||||
|
List of escapable characters in markdown. |
||||
|
|
||||
|
## Installation |
||||
|
|
||||
|
[npm][npm-install]: |
||||
|
|
||||
|
```bash |
||||
|
npm install markdown-escapes |
||||
|
``` |
||||
|
|
||||
|
## Usage |
||||
|
|
||||
|
```javascript |
||||
|
var escapes = require('markdown-escapes'); |
||||
|
|
||||
|
// Access by property: |
||||
|
escapes.commonmark; |
||||
|
// ['\\', '`', ..., '@', '^'] |
||||
|
|
||||
|
// Access by options object: |
||||
|
escapes({gfm: true}); |
||||
|
// ['\\', '`', ..., '~', '|'] |
||||
|
``` |
||||
|
|
||||
|
## API |
||||
|
|
||||
|
### `escapes([options])` |
||||
|
|
||||
|
Get escapes. Supports `options.commonmark` and `options.gfm`, which |
||||
|
when `true` returns the extra escape characters supported by those |
||||
|
flavours. |
||||
|
|
||||
|
###### Returns |
||||
|
|
||||
|
`Array.<string>`. |
||||
|
|
||||
|
### `escapes.default` |
||||
|
|
||||
|
List of default escapable characters. |
||||
|
|
||||
|
### `escapes.gfm` |
||||
|
|
||||
|
List of escapable characters in GFM (which includes all `default`s). |
||||
|
|
||||
|
### `escapes.commonmark` |
||||
|
|
||||
|
List of escapable characters in CommonMark (which includes all `gfm`s). |
||||
|
|
||||
|
## License |
||||
|
|
||||
|
[MIT][license] © [Titus Wormer][author] |
||||
|
|
||||
|
<!-- Definitions --> |
||||
|
|
||||
|
[travis-badge]: https://img.shields.io/travis/wooorm/markdown-escapes.svg |
||||
|
|
||||
|
[travis]: https://travis-ci.org/wooorm/markdown-escapes |
||||
|
|
||||
|
[codecov-badge]: https://img.shields.io/codecov/c/github/wooorm/markdown-escapes.svg |
||||
|
|
||||
|
[codecov]: https://codecov.io/github/wooorm/markdown-escapes |
||||
|
|
||||
|
[npm-install]: https://docs.npmjs.com/cli/install |
||||
|
|
||||
|
[license]: LICENSE |
||||
|
|
||||
|
[author]: http://wooorm.com |
@ -1,132 +0,0 @@ |
|||||
# markdown-table [](https://travis-ci.org/wooorm/markdown-table) [](https://coveralls.io/r/wooorm/markdown-table?branch=master) |
|
||||
|
|
||||
Generate fancy [Markdown](https://help.github.com/articles/github-flavored-markdown/#tables)/ASCII tables. |
|
||||
|
|
||||
## Installation |
|
||||
|
|
||||
[npm](https://docs.npmjs.com/cli/install): |
|
||||
|
|
||||
```bash |
|
||||
$ npm install markdown-table |
|
||||
``` |
|
||||
|
|
||||
[Component.js](https://github.com/componentjs/component): |
|
||||
|
|
||||
```bash |
|
||||
$ component install wooorm/markdown-table |
|
||||
``` |
|
||||
|
|
||||
[Bower](http://bower.io/#install-packages): |
|
||||
|
|
||||
```bash |
|
||||
$ bower install markdown-table |
|
||||
``` |
|
||||
|
|
||||
[Duo](http://duojs.org/#getting-started): |
|
||||
|
|
||||
```javascript |
|
||||
var table = require('wooorm/markdown-table'); |
|
||||
``` |
|
||||
|
|
||||
## Usage |
|
||||
|
|
||||
```javascript |
|
||||
var table = require('markdown-table'); |
|
||||
|
|
||||
/** |
|
||||
* Normal usage (defaults to left-alignment): |
|
||||
*/ |
|
||||
|
|
||||
table([ |
|
||||
['Branch', 'Commit'], |
|
||||
['master', '0123456789abcdef'], |
|
||||
['staging', 'fedcba9876543210'] |
|
||||
]); |
|
||||
/* |
|
||||
* | Branch | Commit | |
|
||||
* | ------- | ---------------- | |
|
||||
* | master | 0123456789abcdef | |
|
||||
* | staging | fedcba9876543210 | |
|
||||
*/ |
|
||||
|
|
||||
/** |
|
||||
* With alignment: |
|
||||
*/ |
|
||||
|
|
||||
table([ |
|
||||
['Beep', 'No.', 'Boop'], |
|
||||
['beep', '1024', 'xyz'], |
|
||||
['boop', '3388450', 'tuv'], |
|
||||
['foo', '10106', 'qrstuv'], |
|
||||
['bar', '45', 'lmno'] |
|
||||
], { |
|
||||
'align': ['l', 'c', 'r'] |
|
||||
}); |
|
||||
/* |
|
||||
* | Beep | No. | Boop | |
|
||||
* | :--- | :-----: | -----: | |
|
||||
* | beep | 1024 | xyz | |
|
||||
* | boop | 3388450 | tuv | |
|
||||
* | foo | 10106 | qrstuv | |
|
||||
* | bar | 45 | lmno | |
|
||||
*/ |
|
||||
|
|
||||
/** |
|
||||
* Alignment on dots: |
|
||||
*/ |
|
||||
|
|
||||
table([ |
|
||||
['No.'], |
|
||||
['0.1.2'], |
|
||||
['11.22.33'], |
|
||||
['5.6.'], |
|
||||
['1.22222'], |
|
||||
], { |
|
||||
'align': '.' |
|
||||
}); |
|
||||
/* |
|
||||
* | No. | |
|
||||
* | :---------: | |
|
||||
* | 0.1.2 | |
|
||||
* | 11.22.33 | |
|
||||
* | 5.6. | |
|
||||
* | 1.22222 | |
|
||||
*/ |
|
||||
``` |
|
||||
|
|
||||
## API |
|
||||
|
|
||||
### markdownTable(table, options?) |
|
||||
|
|
||||
Turns a given matrix of strings (an array of arrays of strings) into a table. |
|
||||
|
|
||||
The following options are available: |
|
||||
|
|
||||
- `options.align` — String or array of strings, the strings being either `"l"` (left), `"r"` (right), `c` (center), or `.` (dot). Other values are treated as `""`, which doesn’t place the colon but does left align. _Only the lowercased first character is used, so `Right` is fine_; |
|
||||
- `options.delimiter` — Value to insert between cells. Carefull, non-pipe values will break GitHub Flavored Markdown; |
|
||||
- `options.start` — Value to insert at the beginning of every row. |
|
||||
- `options.end` — Value to insert at the end of every row. |
|
||||
- `options.rule` — Whether to display a rule between the header and the body of the table. Carefull, will break GitHub Flavored Markdown when `false`; |
|
||||
- `options.stringLength` — The method to detect the length of a cell (see below). |
|
||||
|
|
||||
### options.stringLength(cell) |
|
||||
|
|
||||
ANSI-sequences mess up tables on terminals. To fix this, you have to pass in a `stringLength` option to detect the “visible” length of a cell. |
|
||||
|
|
||||
```javascript |
|
||||
var chalk = require('chalk'); |
|
||||
|
|
||||
function stringLength(cell) { |
|
||||
return chalk.stripColor(cell).length; |
|
||||
} |
|
||||
``` |
|
||||
|
|
||||
See the [tests for an example](test.js#L368-L375). |
|
||||
|
|
||||
## Inspiration |
|
||||
|
|
||||
The original idea and basic implementation was inspired by James Halliday's [text-table](https://github.com/substack/text-table) library. |
|
||||
|
|
||||
## License |
|
||||
|
|
||||
[MIT](LICENSE) © [Titus Wormer](http://wooorm.com) |
|
@ -1,284 +0,0 @@ |
|||||
'use strict'; |
|
||||
|
|
||||
/* |
|
||||
* Useful expressions. |
|
||||
*/ |
|
||||
|
|
||||
var EXPRESSION_DOT = /\./; |
|
||||
var EXPRESSION_LAST_DOT = /\.[^.]*$/; |
|
||||
|
|
||||
/* |
|
||||
* Allowed alignment values. |
|
||||
*/ |
|
||||
|
|
||||
var LEFT = 'l'; |
|
||||
var RIGHT = 'r'; |
|
||||
var CENTER = 'c'; |
|
||||
var DOT = '.'; |
|
||||
var NULL = ''; |
|
||||
|
|
||||
var ALLIGNMENT = [LEFT, RIGHT, CENTER, DOT, NULL]; |
|
||||
|
|
||||
/* |
|
||||
* Characters. |
|
||||
*/ |
|
||||
|
|
||||
var COLON = ':'; |
|
||||
var DASH = '-'; |
|
||||
var PIPE = '|'; |
|
||||
var SPACE = ' '; |
|
||||
var NEW_LINE = '\n'; |
|
||||
|
|
||||
/** |
|
||||
* Get the length of `value`. |
|
||||
* |
|
||||
* @param {string} value |
|
||||
* @return {number} |
|
||||
*/ |
|
||||
function lengthNoop(value) { |
|
||||
return String(value).length; |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* Get a string consisting of `length` `character`s. |
|
||||
* |
|
||||
* @param {number} length |
|
||||
* @param {string} [character=' '] |
|
||||
* @return {string} |
|
||||
*/ |
|
||||
function pad(length, character) { |
|
||||
return Array(length + 1).join(character || SPACE); |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* Get the position of the last dot in `value`. |
|
||||
* |
|
||||
* @param {string} value |
|
||||
* @return {number} |
|
||||
*/ |
|
||||
function dotindex(value) { |
|
||||
var match = EXPRESSION_LAST_DOT.exec(value); |
|
||||
|
|
||||
return match ? match.index + 1 : value.length; |
|
||||
} |
|
||||
|
|
||||
/** |
|
||||
* Create a table from a matrix of strings. |
|
||||
* |
|
||||
* @param {Array.<Array.<string>>} table |
|
||||
* @param {Object?} options |
|
||||
* @param {boolean?} [options.rule=true] |
|
||||
* @param {string?} [options.delimiter=" | "] |
|
||||
* @param {string?} [options.start="| "] |
|
||||
* @param {string?} [options.end=" |"] |
|
||||
* @param {Array.<string>?} options.align |
|
||||
* @param {function(string)?} options.stringLength |
|
||||
* @return {string} Pretty table |
|
||||
*/ |
|
||||
function markdownTable(table, options) { |
|
||||
var settings = options || {}; |
|
||||
var delimiter = settings.delimiter; |
|
||||
var start = settings.start; |
|
||||
var end = settings.end; |
|
||||
var alignment = settings.align; |
|
||||
var calculateStringLength = settings.stringLength || lengthNoop; |
|
||||
var cellCount = 0; |
|
||||
var rowIndex = -1; |
|
||||
var rowLength = table.length; |
|
||||
var sizes = []; |
|
||||
var align; |
|
||||
var rule; |
|
||||
var rows; |
|
||||
var row; |
|
||||
var cells; |
|
||||
var index; |
|
||||
var position; |
|
||||
var size; |
|
||||
var value; |
|
||||
var spacing; |
|
||||
var before; |
|
||||
var after; |
|
||||
|
|
||||
alignment = alignment ? alignment.concat() : []; |
|
||||
|
|
||||
if (delimiter === null || delimiter === undefined) { |
|
||||
delimiter = SPACE + PIPE + SPACE; |
|
||||
} |
|
||||
|
|
||||
if (start === null || start === undefined) { |
|
||||
start = PIPE + SPACE; |
|
||||
} |
|
||||
|
|
||||
if (end === null || end === undefined) { |
|
||||
end = SPACE + PIPE; |
|
||||
} |
|
||||
|
|
||||
while (++rowIndex < rowLength) { |
|
||||
row = table[rowIndex]; |
|
||||
|
|
||||
index = -1; |
|
||||
|
|
||||
if (row.length > cellCount) { |
|
||||
cellCount = row.length; |
|
||||
} |
|
||||
|
|
||||
while (++index < cellCount) { |
|
||||
position = row[index] ? dotindex(row[index]) : null; |
|
||||
|
|
||||
if (!sizes[index]) { |
|
||||
sizes[index] = 3; |
|
||||
} |
|
||||
|
|
||||
if (position > sizes[index]) { |
|
||||
sizes[index] = position; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
if (typeof alignment === 'string') { |
|
||||
alignment = pad(cellCount, alignment).split(''); |
|
||||
} |
|
||||
|
|
||||
/* |
|
||||
* Make sure only valid alignments are used. |
|
||||
*/ |
|
||||
|
|
||||
index = -1; |
|
||||
|
|
||||
while (++index < cellCount) { |
|
||||
align = alignment[index]; |
|
||||
|
|
||||
if (typeof align === 'string') { |
|
||||
align = align.charAt(0).toLowerCase(); |
|
||||
} |
|
||||
|
|
||||
if (ALLIGNMENT.indexOf(align) === -1) { |
|
||||
align = NULL; |
|
||||
} |
|
||||
|
|
||||
alignment[index] = align; |
|
||||
} |
|
||||
|
|
||||
rowIndex = -1; |
|
||||
rows = []; |
|
||||
|
|
||||
while (++rowIndex < rowLength) { |
|
||||
row = table[rowIndex]; |
|
||||
|
|
||||
index = -1; |
|
||||
cells = []; |
|
||||
|
|
||||
while (++index < cellCount) { |
|
||||
value = row[index]; |
|
||||
|
|
||||
if (value === null || value === undefined) { |
|
||||
value = ''; |
|
||||
} else { |
|
||||
value = String(value); |
|
||||
} |
|
||||
|
|
||||
if (alignment[index] !== DOT) { |
|
||||
cells[index] = value; |
|
||||
} else { |
|
||||
position = dotindex(value); |
|
||||
|
|
||||
size = sizes[index] + |
|
||||
(EXPRESSION_DOT.test(value) ? 0 : 1) - |
|
||||
(calculateStringLength(value) - position); |
|
||||
|
|
||||
cells[index] = value + pad(size - 1); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
rows[rowIndex] = cells; |
|
||||
} |
|
||||
|
|
||||
sizes = []; |
|
||||
rowIndex = -1; |
|
||||
|
|
||||
while (++rowIndex < rowLength) { |
|
||||
cells = rows[rowIndex]; |
|
||||
|
|
||||
index = -1; |
|
||||
|
|
||||
while (++index < cellCount) { |
|
||||
value = cells[index]; |
|
||||
|
|
||||
if (!sizes[index]) { |
|
||||
sizes[index] = 3; |
|
||||
} |
|
||||
|
|
||||
size = calculateStringLength(value); |
|
||||
|
|
||||
if (size > sizes[index]) { |
|
||||
sizes[index] = size; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
rowIndex = -1; |
|
||||
|
|
||||
while (++rowIndex < rowLength) { |
|
||||
cells = rows[rowIndex]; |
|
||||
|
|
||||
index = -1; |
|
||||
|
|
||||
while (++index < cellCount) { |
|
||||
value = cells[index]; |
|
||||
|
|
||||
position = sizes[index] - (calculateStringLength(value) || 0); |
|
||||
spacing = pad(position); |
|
||||
|
|
||||
if (alignment[index] === RIGHT || alignment[index] === DOT) { |
|
||||
value = spacing + value; |
|
||||
} else if (alignment[index] !== CENTER) { |
|
||||
value = value + spacing; |
|
||||
} else { |
|
||||
position = position / 2; |
|
||||
|
|
||||
if (position % 1 === 0) { |
|
||||
before = position; |
|
||||
after = position; |
|
||||
} else { |
|
||||
before = position + 0.5; |
|
||||
after = position - 0.5; |
|
||||
} |
|
||||
|
|
||||
value = pad(before) + value + pad(after); |
|
||||
} |
|
||||
|
|
||||
cells[index] = value; |
|
||||
} |
|
||||
|
|
||||
rows[rowIndex] = cells.join(delimiter); |
|
||||
} |
|
||||
|
|
||||
if (settings.rule !== false) { |
|
||||
index = -1; |
|
||||
rule = []; |
|
||||
|
|
||||
while (++index < cellCount) { |
|
||||
align = alignment[index]; |
|
||||
|
|
||||
/* |
|
||||
* When `align` is left, don't add colons. |
|
||||
*/ |
|
||||
|
|
||||
value = align === RIGHT || align === NULL ? DASH : COLON; |
|
||||
value += pad(sizes[index] - 2, DASH); |
|
||||
value += align !== LEFT && align !== NULL ? COLON : DASH; |
|
||||
|
|
||||
rule[index] = value; |
|
||||
} |
|
||||
|
|
||||
rows.splice(1, 0, rule.join(delimiter)); |
|
||||
} |
|
||||
|
|
||||
return start + rows.join(end + NEW_LINE + start) + end; |
|
||||
} |
|
||||
|
|
||||
/* |
|
||||
* Expose `markdownTable`. |
|
||||
*/ |
|
||||
|
|
||||
module.exports = markdownTable; |
|
@ -1,72 +0,0 @@ |
|||||
{ |
|
||||
"_from": "markdown-table@^0.4.0", |
|
||||
"_id": "markdown-table@0.4.0", |
|
||||
"_inBundle": false, |
|
||||
"_integrity": "sha1-iQwsGzv+g/sA5BKbjkz+ZFJw+dE=", |
|
||||
"_location": "/markdown-table", |
|
||||
"_phantomChildren": {}, |
|
||||
"_requested": { |
|
||||
"type": "range", |
|
||||
"registry": true, |
|
||||
"raw": "markdown-table@^0.4.0", |
|
||||
"name": "markdown-table", |
|
||||
"escapedName": "markdown-table", |
|
||||
"rawSpec": "^0.4.0", |
|
||||
"saveSpec": null, |
|
||||
"fetchSpec": "^0.4.0" |
|
||||
}, |
|
||||
"_requiredBy": [ |
|
||||
"/remark-stringify" |
|
||||
], |
|
||||
"_resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-0.4.0.tgz", |
|
||||
"_shasum": "890c2c1b3bfe83fb00e4129b8e4cfe645270f9d1", |
|
||||
"_spec": "markdown-table@^0.4.0", |
|
||||
"_where": "/Users/trott/io.js/tools/eslint-tmp/node_modules/eslint/node_modules/remark-stringify", |
|
||||
"author": { |
|
||||
"name": "Titus Wormer", |
|
||||
"email": "tituswormer@gmail.com" |
|
||||
}, |
|
||||
"bugs": { |
|
||||
"url": "https://github.com/wooorm/markdown-table/issues" |
|
||||
}, |
|
||||
"bundleDependencies": false, |
|
||||
"deprecated": false, |
|
||||
"description": "Markdown/ASCII tables", |
|
||||
"devDependencies": { |
|
||||
"chalk": "^1.0.0", |
|
||||
"eslint": "^0.18.0", |
|
||||
"istanbul": "^0.3.0", |
|
||||
"jscs": "^1.0.0", |
|
||||
"jscs-jsdoc": "^0.4.0", |
|
||||
"mocha": "^2.0.0" |
|
||||
}, |
|
||||
"homepage": "https://github.com/wooorm/markdown-table#readme", |
|
||||
"keywords": [ |
|
||||
"text", |
|
||||
"markdown", |
|
||||
"table", |
|
||||
"align", |
|
||||
"ascii", |
|
||||
"rows", |
|
||||
"tabular" |
|
||||
], |
|
||||
"license": "MIT", |
|
||||
"name": "markdown-table", |
|
||||
"repository": { |
|
||||
"type": "git", |
|
||||
"url": "git+https://github.com/wooorm/markdown-table.git" |
|
||||
}, |
|
||||
"scripts": { |
|
||||
"lint": "npm run lint-api && npm run lint-test && npm run lint-style", |
|
||||
"lint-api": "eslint index.js", |
|
||||
"lint-style": "jscs --reporter inline index.js test.js", |
|
||||
"lint-test": "eslint --env mocha test.js", |
|
||||
"make": "npm run lint && npm run test-coverage", |
|
||||
"test": "npm run test-api", |
|
||||
"test-api": "_mocha --check-leaks test.js", |
|
||||
"test-coverage": "istanbul cover _mocha -- -- test.js", |
|
||||
"test-coveralls": "istanbul cover _mocha --report lcovonly -- --check-leaks test.js", |
|
||||
"test-travis": "npm run test-coveralls" |
|
||||
}, |
|
||||
"version": "0.4.0" |
|
||||
} |
|
@ -1,40 +0,0 @@ |
|||||
<p align="center"> |
|
||||
<a href="https://github.com/inikulin/parse5"> |
|
||||
<img src="https://raw.github.com/inikulin/parse5/master/docs/logo.png" alt="parse5" /> |
|
||||
</a> |
|
||||
</p> |
|
||||
|
|
||||
<p align="center"> |
|
||||
<i>WHATWG HTML5 specification-compliant, fast and ready for production HTML parsing/serialization toolset for Node.js</i> |
|
||||
</p> |
|
||||
|
|
||||
<p align="center"> |
|
||||
<a href="https://travis-ci.org/inikulin/parse5"><img alt="Build Status" src="https://api.travis-ci.org/inikulin/parse5.svg"></a> |
|
||||
<a href="https://www.npmjs.com/package/parse5"><img alt="NPM Version" src="https://img.shields.io/npm/v/parse5.svg"></a> |
|
||||
<a href="https://npmjs.org/package/parse5"><img alt="Downloads" src="http://img.shields.io/npm/dm/parse5.svg"></a> |
|
||||
<a href="https://npmjs.org/package/parse5"><img alt="Downloads total" src="http://img.shields.io/npm/dt/parse5.svg"></a> |
|
||||
</p> |
|
||||
|
|
||||
<p align="center"> |
|
||||
<b><i>parse5</i></b> provides nearly everything you may need when dealing with HTML. It's the fastest spec-compliant HTML parser |
|
||||
for Node to date. It parses HTML the way the latest version of your browser does. It has proven itself reliable in such projects |
|
||||
as <a href="https://github.com/tmpvar/jsdom">jsdom</a>, <a href="https://github.com/angular/angular">Angular2</a>, <a href="https://www.polymer-project.org">Polymer</a> and many more. |
|
||||
</p> |
|
||||
|
|
||||
---- |
|
||||
|
|
||||
<p align="center"> |
|
||||
<a href="https://github.com/inikulin/parse5/wiki/Documentation">Documentation</a> |
|
||||
</p> |
|
||||
|
|
||||
<p align="center"> |
|
||||
<a href="https://github.com/inikulin/parse5/wiki/Documentation#version-history">Version history</a> |
|
||||
</p> |
|
||||
|
|
||||
<p align="center"> |
|
||||
<a href="http://astexplorer.net/#/1CHlCXc4n4">Online playground</a> |
|
||||
</p> |
|
||||
|
|
||||
<p align="center"> |
|
||||
<a href="https://github.com/inikulin/parse5/issues">Issue tracker</a> |
|
||||
</p> |
|
@ -1,137 +0,0 @@ |
|||||
'use strict'; |
|
||||
|
|
||||
//Const
|
|
||||
var VALID_DOCTYPE_NAME = 'html', |
|
||||
QUIRKS_MODE_SYSTEM_ID = 'http://www.ibm.com/data/dtd/v11/ibmxhtml1-transitional.dtd', |
|
||||
QUIRKS_MODE_PUBLIC_ID_PREFIXES = [ |
|
||||
'+//silmaril//dtd html pro v0r11 19970101//en', |
|
||||
'-//advasoft ltd//dtd html 3.0 aswedit + extensions//en', |
|
||||
'-//as//dtd html 3.0 aswedit + extensions//en', |
|
||||
'-//ietf//dtd html 2.0 level 1//en', |
|
||||
'-//ietf//dtd html 2.0 level 2//en', |
|
||||
'-//ietf//dtd html 2.0 strict level 1//en', |
|
||||
'-//ietf//dtd html 2.0 strict level 2//en', |
|
||||
'-//ietf//dtd html 2.0 strict//en', |
|
||||
'-//ietf//dtd html 2.0//en', |
|
||||
'-//ietf//dtd html 2.1e//en', |
|
||||
'-//ietf//dtd html 3.0//en', |
|
||||
'-//ietf//dtd html 3.0//en//', |
|
||||
'-//ietf//dtd html 3.2 final//en', |
|
||||
'-//ietf//dtd html 3.2//en', |
|
||||
'-//ietf//dtd html 3//en', |
|
||||
'-//ietf//dtd html level 0//en', |
|
||||
'-//ietf//dtd html level 0//en//2.0', |
|
||||
'-//ietf//dtd html level 1//en', |
|
||||
'-//ietf//dtd html level 1//en//2.0', |
|
||||
'-//ietf//dtd html level 2//en', |
|
||||
'-//ietf//dtd html level 2//en//2.0', |
|
||||
'-//ietf//dtd html level 3//en', |
|
||||
'-//ietf//dtd html level 3//en//3.0', |
|
||||
'-//ietf//dtd html strict level 0//en', |
|
||||
'-//ietf//dtd html strict level 0//en//2.0', |
|
||||
'-//ietf//dtd html strict level 1//en', |
|
||||
'-//ietf//dtd html strict level 1//en//2.0', |
|
||||
'-//ietf//dtd html strict level 2//en', |
|
||||
'-//ietf//dtd html strict level 2//en//2.0', |
|
||||
'-//ietf//dtd html strict level 3//en', |
|
||||
'-//ietf//dtd html strict level 3//en//3.0', |
|
||||
'-//ietf//dtd html strict//en', |
|
||||
'-//ietf//dtd html strict//en//2.0', |
|
||||
'-//ietf//dtd html strict//en//3.0', |
|
||||
'-//ietf//dtd html//en', |
|
||||
'-//ietf//dtd html//en//2.0', |
|
||||
'-//ietf//dtd html//en//3.0', |
|
||||
'-//metrius//dtd metrius presentational//en', |
|
||||
'-//microsoft//dtd internet explorer 2.0 html strict//en', |
|
||||
'-//microsoft//dtd internet explorer 2.0 html//en', |
|
||||
'-//microsoft//dtd internet explorer 2.0 tables//en', |
|
||||
'-//microsoft//dtd internet explorer 3.0 html strict//en', |
|
||||
'-//microsoft//dtd internet explorer 3.0 html//en', |
|
||||
'-//microsoft//dtd internet explorer 3.0 tables//en', |
|
||||
'-//netscape comm. corp.//dtd html//en', |
|
||||
'-//netscape comm. corp.//dtd strict html//en', |
|
||||
'-//o\'reilly and associates//dtd html 2.0//en', |
|
||||
'-//o\'reilly and associates//dtd html extended 1.0//en', |
|
||||
'-//spyglass//dtd html 2.0 extended//en', |
|
||||
'-//sq//dtd html 2.0 hotmetal + extensions//en', |
|
||||
'-//sun microsystems corp.//dtd hotjava html//en', |
|
||||
'-//sun microsystems corp.//dtd hotjava strict html//en', |
|
||||
'-//w3c//dtd html 3 1995-03-24//en', |
|
||||
'-//w3c//dtd html 3.2 draft//en', |
|
||||
'-//w3c//dtd html 3.2 final//en', |
|
||||
'-//w3c//dtd html 3.2//en', |
|
||||
'-//w3c//dtd html 3.2s draft//en', |
|
||||
'-//w3c//dtd html 4.0 frameset//en', |
|
||||
'-//w3c//dtd html 4.0 transitional//en', |
|
||||
'-//w3c//dtd html experimental 19960712//en', |
|
||||
'-//w3c//dtd html experimental 970421//en', |
|
||||
'-//w3c//dtd w3 html//en', |
|
||||
'-//w3o//dtd w3 html 3.0//en', |
|
||||
'-//w3o//dtd w3 html 3.0//en//', |
|
||||
'-//webtechs//dtd mozilla html 2.0//en', |
|
||||
'-//webtechs//dtd mozilla html//en' |
|
||||
], |
|
||||
QUIRKS_MODE_NO_SYSTEM_ID_PUBLIC_ID_PREFIXES = [ |
|
||||
'-//w3c//dtd html 4.01 frameset//', |
|
||||
'-//w3c//dtd html 4.01 transitional//' |
|
||||
], |
|
||||
QUIRKS_MODE_PUBLIC_IDS = [ |
|
||||
'-//w3o//dtd w3 html strict 3.0//en//', |
|
||||
'-/w3c/dtd html 4.0 transitional/en', |
|
||||
'html' |
|
||||
]; |
|
||||
|
|
||||
|
|
||||
//Utils
|
|
||||
function enquoteDoctypeId(id) { |
|
||||
var quote = id.indexOf('"') !== -1 ? '\'' : '"'; |
|
||||
|
|
||||
return quote + id + quote; |
|
||||
} |
|
||||
|
|
||||
|
|
||||
//API
|
|
||||
exports.isQuirks = function (name, publicId, systemId) { |
|
||||
if (name !== VALID_DOCTYPE_NAME) |
|
||||
return true; |
|
||||
|
|
||||
if (systemId && systemId.toLowerCase() === QUIRKS_MODE_SYSTEM_ID) |
|
||||
return true; |
|
||||
|
|
||||
if (publicId !== null) { |
|
||||
publicId = publicId.toLowerCase(); |
|
||||
|
|
||||
if (QUIRKS_MODE_PUBLIC_IDS.indexOf(publicId) > -1) |
|
||||
return true; |
|
||||
|
|
||||
var prefixes = QUIRKS_MODE_PUBLIC_ID_PREFIXES; |
|
||||
|
|
||||
if (systemId === null) |
|
||||
prefixes = prefixes.concat(QUIRKS_MODE_NO_SYSTEM_ID_PUBLIC_ID_PREFIXES); |
|
||||
|
|
||||
for (var i = 0; i < prefixes.length; i++) { |
|
||||
if (publicId.indexOf(prefixes[i]) === 0) |
|
||||
return true; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
return false; |
|
||||
}; |
|
||||
|
|
||||
exports.serializeContent = function (name, publicId, systemId) { |
|
||||
var str = '!DOCTYPE '; |
|
||||
|
|
||||
if (name) |
|
||||
str += name; |
|
||||
|
|
||||
if (publicId !== null) |
|
||||
str += ' PUBLIC ' + enquoteDoctypeId(publicId); |
|
||||
|
|
||||
else if (systemId !== null) |
|
||||
str += ' SYSTEM'; |
|
||||
|
|
||||
if (systemId !== null) |
|
||||
str += ' ' + enquoteDoctypeId(systemId); |
|
||||
|
|
||||
return str; |
|
||||
}; |
|
@ -1,260 +0,0 @@ |
|||||
'use strict'; |
|
||||
|
|
||||
var Tokenizer = require('../tokenizer'), |
|
||||
HTML = require('./html'); |
|
||||
|
|
||||
//Aliases
|
|
||||
var $ = HTML.TAG_NAMES, |
|
||||
NS = HTML.NAMESPACES, |
|
||||
ATTRS = HTML.ATTRS; |
|
||||
|
|
||||
|
|
||||
//MIME types
|
|
||||
var MIME_TYPES = { |
|
||||
TEXT_HTML: 'text/html', |
|
||||
APPLICATION_XML: 'application/xhtml+xml' |
|
||||
}; |
|
||||
|
|
||||
//Attributes
|
|
||||
var DEFINITION_URL_ATTR = 'definitionurl', |
|
||||
ADJUSTED_DEFINITION_URL_ATTR = 'definitionURL', |
|
||||
SVG_ATTRS_ADJUSTMENT_MAP = { |
|
||||
'attributename': 'attributeName', |
|
||||
'attributetype': 'attributeType', |
|
||||
'basefrequency': 'baseFrequency', |
|
||||
'baseprofile': 'baseProfile', |
|
||||
'calcmode': 'calcMode', |
|
||||
'clippathunits': 'clipPathUnits', |
|
||||
'diffuseconstant': 'diffuseConstant', |
|
||||
'edgemode': 'edgeMode', |
|
||||
'filterunits': 'filterUnits', |
|
||||
'glyphref': 'glyphRef', |
|
||||
'gradienttransform': 'gradientTransform', |
|
||||
'gradientunits': 'gradientUnits', |
|
||||
'kernelmatrix': 'kernelMatrix', |
|
||||
'kernelunitlength': 'kernelUnitLength', |
|
||||
'keypoints': 'keyPoints', |
|
||||
'keysplines': 'keySplines', |
|
||||
'keytimes': 'keyTimes', |
|
||||
'lengthadjust': 'lengthAdjust', |
|
||||
'limitingconeangle': 'limitingConeAngle', |
|
||||
'markerheight': 'markerHeight', |
|
||||
'markerunits': 'markerUnits', |
|
||||
'markerwidth': 'markerWidth', |
|
||||
'maskcontentunits': 'maskContentUnits', |
|
||||
'maskunits': 'maskUnits', |
|
||||
'numoctaves': 'numOctaves', |
|
||||
'pathlength': 'pathLength', |
|
||||
'patterncontentunits': 'patternContentUnits', |
|
||||
'patterntransform': 'patternTransform', |
|
||||
'patternunits': 'patternUnits', |
|
||||
'pointsatx': 'pointsAtX', |
|
||||
'pointsaty': 'pointsAtY', |
|
||||
'pointsatz': 'pointsAtZ', |
|
||||
'preservealpha': 'preserveAlpha', |
|
||||
'preserveaspectratio': 'preserveAspectRatio', |
|
||||
'primitiveunits': 'primitiveUnits', |
|
||||
'refx': 'refX', |
|
||||
'refy': 'refY', |
|
||||
'repeatcount': 'repeatCount', |
|
||||
'repeatdur': 'repeatDur', |
|
||||
'requiredextensions': 'requiredExtensions', |
|
||||
'requiredfeatures': 'requiredFeatures', |
|
||||
'specularconstant': 'specularConstant', |
|
||||
'specularexponent': 'specularExponent', |
|
||||
'spreadmethod': 'spreadMethod', |
|
||||
'startoffset': 'startOffset', |
|
||||
'stddeviation': 'stdDeviation', |
|
||||
'stitchtiles': 'stitchTiles', |
|
||||
'surfacescale': 'surfaceScale', |
|
||||
'systemlanguage': 'systemLanguage', |
|
||||
'tablevalues': 'tableValues', |
|
||||
'targetx': 'targetX', |
|
||||
'targety': 'targetY', |
|
||||
'textlength': 'textLength', |
|
||||
'viewbox': 'viewBox', |
|
||||
'viewtarget': 'viewTarget', |
|
||||
'xchannelselector': 'xChannelSelector', |
|
||||
'ychannelselector': 'yChannelSelector', |
|
||||
'zoomandpan': 'zoomAndPan' |
|
||||
}, |
|
||||
XML_ATTRS_ADJUSTMENT_MAP = { |
|
||||
'xlink:actuate': {prefix: 'xlink', name: 'actuate', namespace: NS.XLINK}, |
|
||||
'xlink:arcrole': {prefix: 'xlink', name: 'arcrole', namespace: NS.XLINK}, |
|
||||
'xlink:href': {prefix: 'xlink', name: 'href', namespace: NS.XLINK}, |
|
||||
'xlink:role': {prefix: 'xlink', name: 'role', namespace: NS.XLINK}, |
|
||||
'xlink:show': {prefix: 'xlink', name: 'show', namespace: NS.XLINK}, |
|
||||
'xlink:title': {prefix: 'xlink', name: 'title', namespace: NS.XLINK}, |
|
||||
'xlink:type': {prefix: 'xlink', name: 'type', namespace: NS.XLINK}, |
|
||||
'xml:base': {prefix: 'xml', name: 'base', namespace: NS.XML}, |
|
||||
'xml:lang': {prefix: 'xml', name: 'lang', namespace: NS.XML}, |
|
||||
'xml:space': {prefix: 'xml', name: 'space', namespace: NS.XML}, |
|
||||
'xmlns': {prefix: '', name: 'xmlns', namespace: NS.XMLNS}, |
|
||||
'xmlns:xlink': {prefix: 'xmlns', name: 'xlink', namespace: NS.XMLNS} |
|
||||
|
|
||||
}; |
|
||||
|
|
||||
//SVG tag names adjustment map
|
|
||||
var SVG_TAG_NAMES_ADJUSTMENT_MAP = exports.SVG_TAG_NAMES_ADJUSTMENT_MAP = { |
|
||||
'altglyph': 'altGlyph', |
|
||||
'altglyphdef': 'altGlyphDef', |
|
||||
'altglyphitem': 'altGlyphItem', |
|
||||
'animatecolor': 'animateColor', |
|
||||
'animatemotion': 'animateMotion', |
|
||||
'animatetransform': 'animateTransform', |
|
||||
'clippath': 'clipPath', |
|
||||
'feblend': 'feBlend', |
|
||||
'fecolormatrix': 'feColorMatrix', |
|
||||
'fecomponenttransfer': 'feComponentTransfer', |
|
||||
'fecomposite': 'feComposite', |
|
||||
'feconvolvematrix': 'feConvolveMatrix', |
|
||||
'fediffuselighting': 'feDiffuseLighting', |
|
||||
'fedisplacementmap': 'feDisplacementMap', |
|
||||
'fedistantlight': 'feDistantLight', |
|
||||
'feflood': 'feFlood', |
|
||||
'fefunca': 'feFuncA', |
|
||||
'fefuncb': 'feFuncB', |
|
||||
'fefuncg': 'feFuncG', |
|
||||
'fefuncr': 'feFuncR', |
|
||||
'fegaussianblur': 'feGaussianBlur', |
|
||||
'feimage': 'feImage', |
|
||||
'femerge': 'feMerge', |
|
||||
'femergenode': 'feMergeNode', |
|
||||
'femorphology': 'feMorphology', |
|
||||
'feoffset': 'feOffset', |
|
||||
'fepointlight': 'fePointLight', |
|
||||
'fespecularlighting': 'feSpecularLighting', |
|
||||
'fespotlight': 'feSpotLight', |
|
||||
'fetile': 'feTile', |
|
||||
'feturbulence': 'feTurbulence', |
|
||||
'foreignobject': 'foreignObject', |
|
||||
'glyphref': 'glyphRef', |
|
||||
'lineargradient': 'linearGradient', |
|
||||
'radialgradient': 'radialGradient', |
|
||||
'textpath': 'textPath' |
|
||||
}; |
|
||||
|
|
||||
//Tags that causes exit from foreign content
|
|
||||
var EXITS_FOREIGN_CONTENT = {}; |
|
||||
|
|
||||
EXITS_FOREIGN_CONTENT[$.B] = true; |
|
||||
EXITS_FOREIGN_CONTENT[$.BIG] = true; |
|
||||
EXITS_FOREIGN_CONTENT[$.BLOCKQUOTE] = true; |
|
||||
EXITS_FOREIGN_CONTENT[$.BODY] = true; |
|
||||
EXITS_FOREIGN_CONTENT[$.BR] = true; |
|
||||
EXITS_FOREIGN_CONTENT[$.CENTER] = true; |
|
||||
EXITS_FOREIGN_CONTENT[$.CODE] = true; |
|
||||
EXITS_FOREIGN_CONTENT[$.DD] = true; |
|
||||
EXITS_FOREIGN_CONTENT[$.DIV] = true; |
|
||||
EXITS_FOREIGN_CONTENT[$.DL] = true; |
|
||||
EXITS_FOREIGN_CONTENT[$.DT] = true; |
|
||||
EXITS_FOREIGN_CONTENT[$.EM] = true; |
|
||||
EXITS_FOREIGN_CONTENT[$.EMBED] = true; |
|
||||
EXITS_FOREIGN_CONTENT[$.H1] = true; |
|
||||
EXITS_FOREIGN_CONTENT[$.H2] = true; |
|
||||
EXITS_FOREIGN_CONTENT[$.H3] = true; |
|
||||
EXITS_FOREIGN_CONTENT[$.H4] = true; |
|
||||
EXITS_FOREIGN_CONTENT[$.H5] = true; |
|
||||
EXITS_FOREIGN_CONTENT[$.H6] = true; |
|
||||
EXITS_FOREIGN_CONTENT[$.HEAD] = true; |
|
||||
EXITS_FOREIGN_CONTENT[$.HR] = true; |
|
||||
EXITS_FOREIGN_CONTENT[$.I] = true; |
|
||||
EXITS_FOREIGN_CONTENT[$.IMG] = true; |
|
||||
EXITS_FOREIGN_CONTENT[$.LI] = true; |
|
||||
EXITS_FOREIGN_CONTENT[$.LISTING] = true; |
|
||||
EXITS_FOREIGN_CONTENT[$.MENU] = true; |
|
||||
EXITS_FOREIGN_CONTENT[$.META] = true; |
|
||||
EXITS_FOREIGN_CONTENT[$.NOBR] = true; |
|
||||
EXITS_FOREIGN_CONTENT[$.OL] = true; |
|
||||
EXITS_FOREIGN_CONTENT[$.P] = true; |
|
||||
EXITS_FOREIGN_CONTENT[$.PRE] = true; |
|
||||
EXITS_FOREIGN_CONTENT[$.RUBY] = true; |
|
||||
EXITS_FOREIGN_CONTENT[$.S] = true; |
|
||||
EXITS_FOREIGN_CONTENT[$.SMALL] = true; |
|
||||
EXITS_FOREIGN_CONTENT[$.SPAN] = true; |
|
||||
EXITS_FOREIGN_CONTENT[$.STRONG] = true; |
|
||||
EXITS_FOREIGN_CONTENT[$.STRIKE] = true; |
|
||||
EXITS_FOREIGN_CONTENT[$.SUB] = true; |
|
||||
EXITS_FOREIGN_CONTENT[$.SUP] = true; |
|
||||
EXITS_FOREIGN_CONTENT[$.TABLE] = true; |
|
||||
EXITS_FOREIGN_CONTENT[$.TT] = true; |
|
||||
EXITS_FOREIGN_CONTENT[$.U] = true; |
|
||||
EXITS_FOREIGN_CONTENT[$.UL] = true; |
|
||||
EXITS_FOREIGN_CONTENT[$.VAR] = true; |
|
||||
|
|
||||
//Check exit from foreign content
|
|
||||
exports.causesExit = function (startTagToken) { |
|
||||
var tn = startTagToken.tagName; |
|
||||
var isFontWithAttrs = tn === $.FONT && (Tokenizer.getTokenAttr(startTagToken, ATTRS.COLOR) !== null || |
|
||||
Tokenizer.getTokenAttr(startTagToken, ATTRS.SIZE) !== null || |
|
||||
Tokenizer.getTokenAttr(startTagToken, ATTRS.FACE) !== null); |
|
||||
|
|
||||
return isFontWithAttrs ? true : EXITS_FOREIGN_CONTENT[tn]; |
|
||||
}; |
|
||||
|
|
||||
//Token adjustments
|
|
||||
exports.adjustTokenMathMLAttrs = function (token) { |
|
||||
for (var i = 0; i < token.attrs.length; i++) { |
|
||||
if (token.attrs[i].name === DEFINITION_URL_ATTR) { |
|
||||
token.attrs[i].name = ADJUSTED_DEFINITION_URL_ATTR; |
|
||||
break; |
|
||||
} |
|
||||
} |
|
||||
}; |
|
||||
|
|
||||
exports.adjustTokenSVGAttrs = function (token) { |
|
||||
for (var i = 0; i < token.attrs.length; i++) { |
|
||||
var adjustedAttrName = SVG_ATTRS_ADJUSTMENT_MAP[token.attrs[i].name]; |
|
||||
|
|
||||
if (adjustedAttrName) |
|
||||
token.attrs[i].name = adjustedAttrName; |
|
||||
} |
|
||||
}; |
|
||||
|
|
||||
exports.adjustTokenXMLAttrs = function (token) { |
|
||||
for (var i = 0; i < token.attrs.length; i++) { |
|
||||
var adjustedAttrEntry = XML_ATTRS_ADJUSTMENT_MAP[token.attrs[i].name]; |
|
||||
|
|
||||
if (adjustedAttrEntry) { |
|
||||
token.attrs[i].prefix = adjustedAttrEntry.prefix; |
|
||||
token.attrs[i].name = adjustedAttrEntry.name; |
|
||||
token.attrs[i].namespace = adjustedAttrEntry.namespace; |
|
||||
} |
|
||||
} |
|
||||
}; |
|
||||
|
|
||||
exports.adjustTokenSVGTagName = function (token) { |
|
||||
var adjustedTagName = SVG_TAG_NAMES_ADJUSTMENT_MAP[token.tagName]; |
|
||||
|
|
||||
if (adjustedTagName) |
|
||||
token.tagName = adjustedTagName; |
|
||||
}; |
|
||||
|
|
||||
//Integration points
|
|
||||
function isMathMLTextIntegrationPoint(tn, ns) { |
|
||||
return ns === NS.MATHML && (tn === $.MI || tn === $.MO || tn === $.MN || tn === $.MS || tn === $.MTEXT); |
|
||||
} |
|
||||
|
|
||||
function isHtmlIntegrationPoint(tn, ns, attrs) { |
|
||||
if (ns === NS.MATHML && tn === $.ANNOTATION_XML) { |
|
||||
for (var i = 0; i < attrs.length; i++) { |
|
||||
if (attrs[i].name === ATTRS.ENCODING) { |
|
||||
var value = attrs[i].value.toLowerCase(); |
|
||||
|
|
||||
return value === MIME_TYPES.TEXT_HTML || value === MIME_TYPES.APPLICATION_XML; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
return ns === NS.SVG && (tn === $.FOREIGN_OBJECT || tn === $.DESC || tn === $.TITLE); |
|
||||
} |
|
||||
|
|
||||
exports.isIntegrationPoint = function (tn, ns, attrs, foreignNS) { |
|
||||
if ((!foreignNS || foreignNS === NS.HTML) && isHtmlIntegrationPoint(tn, ns, attrs)) |
|
||||
return true; |
|
||||
|
|
||||
if ((!foreignNS || foreignNS === NS.MATHML) && isMathMLTextIntegrationPoint(tn, ns)) |
|
||||
return true; |
|
||||
|
|
||||
return false; |
|
||||
}; |
|
@ -1,266 +0,0 @@ |
|||||
'use strict'; |
|
||||
|
|
||||
var NS = exports.NAMESPACES = { |
|
||||
HTML: 'http://www.w3.org/1999/xhtml', |
|
||||
MATHML: 'http://www.w3.org/1998/Math/MathML', |
|
||||
SVG: 'http://www.w3.org/2000/svg', |
|
||||
XLINK: 'http://www.w3.org/1999/xlink', |
|
||||
XML: 'http://www.w3.org/XML/1998/namespace', |
|
||||
XMLNS: 'http://www.w3.org/2000/xmlns/' |
|
||||
}; |
|
||||
|
|
||||
exports.ATTRS = { |
|
||||
TYPE: 'type', |
|
||||
ACTION: 'action', |
|
||||
ENCODING: 'encoding', |
|
||||
PROMPT: 'prompt', |
|
||||
NAME: 'name', |
|
||||
COLOR: 'color', |
|
||||
FACE: 'face', |
|
||||
SIZE: 'size' |
|
||||
}; |
|
||||
|
|
||||
var $ = exports.TAG_NAMES = { |
|
||||
A: 'a', |
|
||||
ADDRESS: 'address', |
|
||||
ANNOTATION_XML: 'annotation-xml', |
|
||||
APPLET: 'applet', |
|
||||
AREA: 'area', |
|
||||
ARTICLE: 'article', |
|
||||
ASIDE: 'aside', |
|
||||
|
|
||||
B: 'b', |
|
||||
BASE: 'base', |
|
||||
BASEFONT: 'basefont', |
|
||||
BGSOUND: 'bgsound', |
|
||||
BIG: 'big', |
|
||||
BLOCKQUOTE: 'blockquote', |
|
||||
BODY: 'body', |
|
||||
BR: 'br', |
|
||||
BUTTON: 'button', |
|
||||
|
|
||||
CAPTION: 'caption', |
|
||||
CENTER: 'center', |
|
||||
CODE: 'code', |
|
||||
COL: 'col', |
|
||||
COLGROUP: 'colgroup', |
|
||||
|
|
||||
DD: 'dd', |
|
||||
DESC: 'desc', |
|
||||
DETAILS: 'details', |
|
||||
DIALOG: 'dialog', |
|
||||
DIR: 'dir', |
|
||||
DIV: 'div', |
|
||||
DL: 'dl', |
|
||||
DT: 'dt', |
|
||||
|
|
||||
EM: 'em', |
|
||||
EMBED: 'embed', |
|
||||
|
|
||||
FIELDSET: 'fieldset', |
|
||||
FIGCAPTION: 'figcaption', |
|
||||
FIGURE: 'figure', |
|
||||
FONT: 'font', |
|
||||
FOOTER: 'footer', |
|
||||
FOREIGN_OBJECT: 'foreignObject', |
|
||||
FORM: 'form', |
|
||||
FRAME: 'frame', |
|
||||
FRAMESET: 'frameset', |
|
||||
|
|
||||
H1: 'h1', |
|
||||
H2: 'h2', |
|
||||
H3: 'h3', |
|
||||
H4: 'h4', |
|
||||
H5: 'h5', |
|
||||
H6: 'h6', |
|
||||
HEAD: 'head', |
|
||||
HEADER: 'header', |
|
||||
HGROUP: 'hgroup', |
|
||||
HR: 'hr', |
|
||||
HTML: 'html', |
|
||||
|
|
||||
I: 'i', |
|
||||
IMG: 'img', |
|
||||
IMAGE: 'image', |
|
||||
INPUT: 'input', |
|
||||
IFRAME: 'iframe', |
|
||||
|
|
||||
KEYGEN: 'keygen', |
|
||||
|
|
||||
LABEL: 'label', |
|
||||
LI: 'li', |
|
||||
LINK: 'link', |
|
||||
LISTING: 'listing', |
|
||||
|
|
||||
MAIN: 'main', |
|
||||
MALIGNMARK: 'malignmark', |
|
||||
MARQUEE: 'marquee', |
|
||||
MATH: 'math', |
|
||||
MENU: 'menu', |
|
||||
MENUITEM: 'menuitem', |
|
||||
META: 'meta', |
|
||||
MGLYPH: 'mglyph', |
|
||||
MI: 'mi', |
|
||||
MO: 'mo', |
|
||||
MN: 'mn', |
|
||||
MS: 'ms', |
|
||||
MTEXT: 'mtext', |
|
||||
|
|
||||
NAV: 'nav', |
|
||||
NOBR: 'nobr', |
|
||||
NOFRAMES: 'noframes', |
|
||||
NOEMBED: 'noembed', |
|
||||
NOSCRIPT: 'noscript', |
|
||||
|
|
||||
OBJECT: 'object', |
|
||||
OL: 'ol', |
|
||||
OPTGROUP: 'optgroup', |
|
||||
OPTION: 'option', |
|
||||
|
|
||||
P: 'p', |
|
||||
PARAM: 'param', |
|
||||
PLAINTEXT: 'plaintext', |
|
||||
PRE: 'pre', |
|
||||
|
|
||||
RB: 'rb', |
|
||||
RP: 'rp', |
|
||||
RT: 'rt', |
|
||||
RTC: 'rtc', |
|
||||
RUBY: 'ruby', |
|
||||
|
|
||||
S: 's', |
|
||||
SCRIPT: 'script', |
|
||||
SECTION: 'section', |
|
||||
SELECT: 'select', |
|
||||
SOURCE: 'source', |
|
||||
SMALL: 'small', |
|
||||
SPAN: 'span', |
|
||||
STRIKE: 'strike', |
|
||||
STRONG: 'strong', |
|
||||
STYLE: 'style', |
|
||||
SUB: 'sub', |
|
||||
SUMMARY: 'summary', |
|
||||
SUP: 'sup', |
|
||||
|
|
||||
TABLE: 'table', |
|
||||
TBODY: 'tbody', |
|
||||
TEMPLATE: 'template', |
|
||||
TEXTAREA: 'textarea', |
|
||||
TFOOT: 'tfoot', |
|
||||
TD: 'td', |
|
||||
TH: 'th', |
|
||||
THEAD: 'thead', |
|
||||
TITLE: 'title', |
|
||||
TR: 'tr', |
|
||||
TRACK: 'track', |
|
||||
TT: 'tt', |
|
||||
|
|
||||
U: 'u', |
|
||||
UL: 'ul', |
|
||||
|
|
||||
SVG: 'svg', |
|
||||
|
|
||||
VAR: 'var', |
|
||||
|
|
||||
WBR: 'wbr', |
|
||||
|
|
||||
XMP: 'xmp' |
|
||||
}; |
|
||||
|
|
||||
var SPECIAL_ELEMENTS = exports.SPECIAL_ELEMENTS = {}; |
|
||||
|
|
||||
SPECIAL_ELEMENTS[NS.HTML] = {}; |
|
||||
SPECIAL_ELEMENTS[NS.HTML][$.ADDRESS] = true; |
|
||||
SPECIAL_ELEMENTS[NS.HTML][$.APPLET] = true; |
|
||||
SPECIAL_ELEMENTS[NS.HTML][$.AREA] = true; |
|
||||
SPECIAL_ELEMENTS[NS.HTML][$.ARTICLE] = true; |
|
||||
SPECIAL_ELEMENTS[NS.HTML][$.ASIDE] = true; |
|
||||
SPECIAL_ELEMENTS[NS.HTML][$.BASE] = true; |
|
||||
SPECIAL_ELEMENTS[NS.HTML][$.BASEFONT] = true; |
|
||||
SPECIAL_ELEMENTS[NS.HTML][$.BGSOUND] = true; |
|
||||
SPECIAL_ELEMENTS[NS.HTML][$.BLOCKQUOTE] = true; |
|
||||
SPECIAL_ELEMENTS[NS.HTML][$.BODY] = true; |
|
||||
SPECIAL_ELEMENTS[NS.HTML][$.BR] = true; |
|
||||
SPECIAL_ELEMENTS[NS.HTML][$.BUTTON] = true; |
|
||||
SPECIAL_ELEMENTS[NS.HTML][$.CAPTION] = true; |
|
||||
SPECIAL_ELEMENTS[NS.HTML][$.CENTER] = true; |
|
||||
SPECIAL_ELEMENTS[NS.HTML][$.COL] = true; |
|
||||
SPECIAL_ELEMENTS[NS.HTML][$.COLGROUP] = true; |
|
||||
SPECIAL_ELEMENTS[NS.HTML][$.DD] = true; |
|
||||
SPECIAL_ELEMENTS[NS.HTML][$.DETAILS] = true; |
|
||||
SPECIAL_ELEMENTS[NS.HTML][$.DIR] = true; |
|
||||
SPECIAL_ELEMENTS[NS.HTML][$.DIV] = true; |
|
||||
SPECIAL_ELEMENTS[NS.HTML][$.DL] = true; |
|
||||
SPECIAL_ELEMENTS[NS.HTML][$.DT] = true; |
|
||||
SPECIAL_ELEMENTS[NS.HTML][$.EMBED] = true; |
|
||||
SPECIAL_ELEMENTS[NS.HTML][$.FIELDSET] = true; |
|
||||
SPECIAL_ELEMENTS[NS.HTML][$.FIGCAPTION] = true; |
|
||||
SPECIAL_ELEMENTS[NS.HTML][$.FIGURE] = true; |
|
||||
SPECIAL_ELEMENTS[NS.HTML][$.FOOTER] = true; |
|
||||
SPECIAL_ELEMENTS[NS.HTML][$.FORM] = true; |
|
||||
SPECIAL_ELEMENTS[NS.HTML][$.FRAME] = true; |
|
||||
SPECIAL_ELEMENTS[NS.HTML][$.FRAMESET] = true; |
|
||||
SPECIAL_ELEMENTS[NS.HTML][$.H1] = true; |
|
||||
SPECIAL_ELEMENTS[NS.HTML][$.H2] = true; |
|
||||
SPECIAL_ELEMENTS[NS.HTML][$.H3] = true; |
|
||||
SPECIAL_ELEMENTS[NS.HTML][$.H4] = true; |
|
||||
SPECIAL_ELEMENTS[NS.HTML][$.H5] = true; |
|
||||
SPECIAL_ELEMENTS[NS.HTML][$.H6] = true; |
|
||||
SPECIAL_ELEMENTS[NS.HTML][$.HEAD] = true; |
|
||||
SPECIAL_ELEMENTS[NS.HTML][$.HEADER] = true; |
|
||||
SPECIAL_ELEMENTS[NS.HTML][$.HGROUP] = true; |
|
||||
SPECIAL_ELEMENTS[NS.HTML][$.HR] = true; |
|
||||
SPECIAL_ELEMENTS[NS.HTML][$.HTML] = true; |
|
||||
SPECIAL_ELEMENTS[NS.HTML][$.IFRAME] = true; |
|
||||
SPECIAL_ELEMENTS[NS.HTML][$.IMG] = true; |
|
||||
SPECIAL_ELEMENTS[NS.HTML][$.INPUT] = true; |
|
||||
SPECIAL_ELEMENTS[NS.HTML][$.LI] = true; |
|
||||
SPECIAL_ELEMENTS[NS.HTML][$.LINK] = true; |
|
||||
SPECIAL_ELEMENTS[NS.HTML][$.LISTING] = true; |
|
||||
SPECIAL_ELEMENTS[NS.HTML][$.MAIN] = true; |
|
||||
SPECIAL_ELEMENTS[NS.HTML][$.MARQUEE] = true; |
|
||||
SPECIAL_ELEMENTS[NS.HTML][$.MENU] = true; |
|
||||
SPECIAL_ELEMENTS[NS.HTML][$.META] = true; |
|
||||
SPECIAL_ELEMENTS[NS.HTML][$.NAV] = true; |
|
||||
SPECIAL_ELEMENTS[NS.HTML][$.NOEMBED] = true; |
|
||||
SPECIAL_ELEMENTS[NS.HTML][$.NOFRAMES] = true; |
|
||||
SPECIAL_ELEMENTS[NS.HTML][$.NOSCRIPT] = true; |
|
||||
SPECIAL_ELEMENTS[NS.HTML][$.OBJECT] = true; |
|
||||
SPECIAL_ELEMENTS[NS.HTML][$.OL] = true; |
|
||||
SPECIAL_ELEMENTS[NS.HTML][$.P] = true; |
|
||||
SPECIAL_ELEMENTS[NS.HTML][$.PARAM] = true; |
|
||||
SPECIAL_ELEMENTS[NS.HTML][$.PLAINTEXT] = true; |
|
||||
SPECIAL_ELEMENTS[NS.HTML][$.PRE] = true; |
|
||||
SPECIAL_ELEMENTS[NS.HTML][$.SCRIPT] = true; |
|
||||
SPECIAL_ELEMENTS[NS.HTML][$.SECTION] = true; |
|
||||
SPECIAL_ELEMENTS[NS.HTML][$.SELECT] = true; |
|
||||
SPECIAL_ELEMENTS[NS.HTML][$.SOURCE] = true; |
|
||||
SPECIAL_ELEMENTS[NS.HTML][$.STYLE] = true; |
|
||||
SPECIAL_ELEMENTS[NS.HTML][$.SUMMARY] = true; |
|
||||
SPECIAL_ELEMENTS[NS.HTML][$.TABLE] = true; |
|
||||
SPECIAL_ELEMENTS[NS.HTML][$.TBODY] = true; |
|
||||
SPECIAL_ELEMENTS[NS.HTML][$.TD] = true; |
|
||||
SPECIAL_ELEMENTS[NS.HTML][$.TEMPLATE] = true; |
|
||||
SPECIAL_ELEMENTS[NS.HTML][$.TEXTAREA] = true; |
|
||||
SPECIAL_ELEMENTS[NS.HTML][$.TFOOT] = true; |
|
||||
SPECIAL_ELEMENTS[NS.HTML][$.TH] = true; |
|
||||
SPECIAL_ELEMENTS[NS.HTML][$.THEAD] = true; |
|
||||
SPECIAL_ELEMENTS[NS.HTML][$.TITLE] = true; |
|
||||
SPECIAL_ELEMENTS[NS.HTML][$.TR] = true; |
|
||||
SPECIAL_ELEMENTS[NS.HTML][$.TRACK] = true; |
|
||||
SPECIAL_ELEMENTS[NS.HTML][$.UL] = true; |
|
||||
SPECIAL_ELEMENTS[NS.HTML][$.WBR] = true; |
|
||||
SPECIAL_ELEMENTS[NS.HTML][$.XMP] = true; |
|
||||
|
|
||||
SPECIAL_ELEMENTS[NS.MATHML] = {}; |
|
||||
SPECIAL_ELEMENTS[NS.MATHML][$.MI] = true; |
|
||||
SPECIAL_ELEMENTS[NS.MATHML][$.MO] = true; |
|
||||
SPECIAL_ELEMENTS[NS.MATHML][$.MN] = true; |
|
||||
SPECIAL_ELEMENTS[NS.MATHML][$.MS] = true; |
|
||||
SPECIAL_ELEMENTS[NS.MATHML][$.MTEXT] = true; |
|
||||
SPECIAL_ELEMENTS[NS.MATHML][$.ANNOTATION_XML] = true; |
|
||||
|
|
||||
SPECIAL_ELEMENTS[NS.SVG] = {}; |
|
||||
SPECIAL_ELEMENTS[NS.SVG][$.TITLE] = true; |
|
||||
SPECIAL_ELEMENTS[NS.SVG][$.FOREIGN_OBJECT] = true; |
|
||||
SPECIAL_ELEMENTS[NS.SVG][$.DESC] = true; |
|
@ -1,13 +0,0 @@ |
|||||
'use strict'; |
|
||||
|
|
||||
module.exports = function mergeOptions(defaults, options) { |
|
||||
options = options || {}; |
|
||||
|
|
||||
return [defaults, options].reduce(function (merged, optObj) { |
|
||||
Object.keys(optObj).forEach(function (key) { |
|
||||
merged[key] = optObj[key]; |
|
||||
}); |
|
||||
|
|
||||
return merged; |
|
||||
}, {}); |
|
||||
}; |
|
@ -1,47 +0,0 @@ |
|||||
'use strict'; |
|
||||
|
|
||||
exports.REPLACEMENT_CHARACTER = '\uFFFD'; |
|
||||
|
|
||||
exports.CODE_POINTS = { |
|
||||
EOF: -1, |
|
||||
NULL: 0x00, |
|
||||
TABULATION: 0x09, |
|
||||
CARRIAGE_RETURN: 0x0D, |
|
||||
LINE_FEED: 0x0A, |
|
||||
FORM_FEED: 0x0C, |
|
||||
SPACE: 0x20, |
|
||||
EXCLAMATION_MARK: 0x21, |
|
||||
QUOTATION_MARK: 0x22, |
|
||||
NUMBER_SIGN: 0x23, |
|
||||
AMPERSAND: 0x26, |
|
||||
APOSTROPHE: 0x27, |
|
||||
HYPHEN_MINUS: 0x2D, |
|
||||
SOLIDUS: 0x2F, |
|
||||
DIGIT_0: 0x30, |
|
||||
DIGIT_9: 0x39, |
|
||||
SEMICOLON: 0x3B, |
|
||||
LESS_THAN_SIGN: 0x3C, |
|
||||
EQUALS_SIGN: 0x3D, |
|
||||
GREATER_THAN_SIGN: 0x3E, |
|
||||
QUESTION_MARK: 0x3F, |
|
||||
LATIN_CAPITAL_A: 0x41, |
|
||||
LATIN_CAPITAL_F: 0x46, |
|
||||
LATIN_CAPITAL_X: 0x58, |
|
||||
LATIN_CAPITAL_Z: 0x5A, |
|
||||
GRAVE_ACCENT: 0x60, |
|
||||
LATIN_SMALL_A: 0x61, |
|
||||
LATIN_SMALL_F: 0x66, |
|
||||
LATIN_SMALL_X: 0x78, |
|
||||
LATIN_SMALL_Z: 0x7A, |
|
||||
REPLACEMENT_CHARACTER: 0xFFFD |
|
||||
}; |
|
||||
|
|
||||
exports.CODE_POINT_SEQUENCES = { |
|
||||
DASH_DASH_STRING: [0x2D, 0x2D], //--
|
|
||||
DOCTYPE_STRING: [0x44, 0x4F, 0x43, 0x54, 0x59, 0x50, 0x45], //DOCTYPE
|
|
||||
CDATA_START_STRING: [0x5B, 0x43, 0x44, 0x41, 0x54, 0x41, 0x5B], //[CDATA[
|
|
||||
CDATA_END_STRING: [0x5D, 0x5D, 0x3E], //]]>
|
|
||||
SCRIPT_STRING: [0x73, 0x63, 0x72, 0x69, 0x70, 0x74], //script
|
|
||||
PUBLIC_STRING: [0x50, 0x55, 0x42, 0x4C, 0x49, 0x43], //PUBLIC
|
|
||||
SYSTEM_STRING: [0x53, 0x59, 0x53, 0x54, 0x45, 0x4D] //SYSTEM
|
|
||||
}; |
|
@ -1,108 +0,0 @@ |
|||||
'use strict'; |
|
||||
|
|
||||
var Parser = require('./parser'), |
|
||||
Serializer = require('./serializer'); |
|
||||
|
|
||||
/** @namespace parse5 */ |
|
||||
|
|
||||
/** |
|
||||
* Parses an HTML string. |
|
||||
* @function parse |
|
||||
* @memberof parse5 |
|
||||
* @instance |
|
||||
* @param {string} html - Input HTML string. |
|
||||
* @param {ParserOptions} [options] - Parsing options. |
|
||||
* @returns {ASTNode<Document>} document |
|
||||
* @example |
|
||||
* var parse5 = require('parse5'); |
|
||||
* |
|
||||
* var document = parse5.parse('<!DOCTYPE html><html><head></head><body>Hi there!</body></html>'); |
|
||||
*/ |
|
||||
exports.parse = function parse(html, options) { |
|
||||
var parser = new Parser(options); |
|
||||
|
|
||||
return parser.parse(html); |
|
||||
}; |
|
||||
|
|
||||
/** |
|
||||
* Parses an HTML fragment. |
|
||||
* @function parseFragment |
|
||||
* @memberof parse5 |
|
||||
* @instance |
|
||||
* @param {ASTNode} [fragmentContext] - Parsing context element. If specified, given fragment |
|
||||
* will be parsed as if it was set to the context element's `innerHTML` property. |
|
||||
* @param {string} html - Input HTML fragment string. |
|
||||
* @param {ParserOptions} [options] - Parsing options. |
|
||||
* @returns {ASTNode<DocumentFragment>} documentFragment |
|
||||
* @example |
|
||||
* var parse5 = require('parse5'); |
|
||||
* |
|
||||
* var documentFragment = parse5.parseFragment('<table></table>'); |
|
||||
* |
|
||||
* // Parses the html fragment in the context of the parsed <table> element.
|
|
||||
* var trFragment = parser.parseFragment(documentFragment.childNodes[0], '<tr><td>Shake it, baby</td></tr>'); |
|
||||
*/ |
|
||||
exports.parseFragment = function parseFragment(fragmentContext, html, options) { |
|
||||
if (typeof fragmentContext === 'string') { |
|
||||
options = html; |
|
||||
html = fragmentContext; |
|
||||
fragmentContext = null; |
|
||||
} |
|
||||
|
|
||||
var parser = new Parser(options); |
|
||||
|
|
||||
return parser.parseFragment(html, fragmentContext); |
|
||||
}; |
|
||||
|
|
||||
/** |
|
||||
* Serializes an AST node to an HTML string. |
|
||||
* @function serialize |
|
||||
* @memberof parse5 |
|
||||
* @instance |
|
||||
* @param {ASTNode} node - Node to serialize. |
|
||||
* @param {SerializerOptions} [options] - Serialization options. |
|
||||
* @returns {String} html |
|
||||
* @example |
|
||||
* var parse5 = require('parse5'); |
|
||||
* |
|
||||
* var document = parse5.parse('<!DOCTYPE html><html><head></head><body>Hi there!</body></html>'); |
|
||||
* |
|
||||
* // Serializes a document.
|
|
||||
* var html = parse5.serialize(document); |
|
||||
* |
|
||||
* // Serializes the <body> element content.
|
|
||||
* var bodyInnerHtml = parse5.serialize(document.childNodes[0].childNodes[1]); |
|
||||
*/ |
|
||||
exports.serialize = function (node, options) { |
|
||||
var serializer = new Serializer(node, options); |
|
||||
|
|
||||
return serializer.serialize(); |
|
||||
}; |
|
||||
|
|
||||
/** |
|
||||
* Provides built-in tree adapters that can be used for parsing and serialization. |
|
||||
* @var treeAdapters |
|
||||
* @memberof parse5 |
|
||||
* @instance |
|
||||
* @property {TreeAdapter} default - Default tree format for parse5. |
|
||||
* @property {TreeAdapter} htmlparser2 - Quite popular [htmlparser2](https://github.com/fb55/htmlparser2) tree format
|
|
||||
* (e.g. used by [cheerio](https://github.com/MatthewMueller/cheerio) and [jsdom](https://github.com/tmpvar/jsdom)).
|
|
||||
* @example |
|
||||
* var parse5 = require('parse5'); |
|
||||
* |
|
||||
* // Uses the default tree adapter for parsing.
|
|
||||
* var document = parse5.parse('<div></div>', { treeAdapter: parse5.treeAdapters.default }); |
|
||||
* |
|
||||
* // Uses the htmlparser2 tree adapter with the SerializerStream.
|
|
||||
* var serializer = new parse5.SerializerStream(node, { treeAdapter: parse5.treeAdapters.htmlparser2 }); |
|
||||
*/ |
|
||||
exports.treeAdapters = { |
|
||||
default: require('./tree_adapters/default'), |
|
||||
htmlparser2: require('./tree_adapters/htmlparser2') |
|
||||
}; |
|
||||
|
|
||||
|
|
||||
// Streaming
|
|
||||
exports.ParserStream = require('./parser/stream'); |
|
||||
exports.SerializerStream = require('./serializer/stream'); |
|
||||
exports.SAXParser = require('./sax'); |
|
@ -1,217 +0,0 @@ |
|||||
'use strict'; |
|
||||
|
|
||||
var OpenElementStack = require('../parser/open_element_stack'), |
|
||||
Tokenizer = require('../tokenizer'), |
|
||||
HTML = require('../common/html'); |
|
||||
|
|
||||
|
|
||||
//Aliases
|
|
||||
var $ = HTML.TAG_NAMES; |
|
||||
|
|
||||
|
|
||||
function setEndLocation(element, closingToken, treeAdapter) { |
|
||||
var loc = element.__location; |
|
||||
|
|
||||
if (!loc) |
|
||||
return; |
|
||||
|
|
||||
/** |
|
||||
* @typedef {Object} ElementLocationInfo |
|
||||
* @extends StartTagLocationInfo |
|
||||
* |
|
||||
* @property {StartTagLocationInfo} startTag - Element's start tag location info. |
|
||||
* @property {LocationInfo} endTag - Element's end tag location info. |
|
||||
*/ |
|
||||
if (!loc.startTag) { |
|
||||
loc.startTag = { |
|
||||
line: loc.line, |
|
||||
col: loc.col, |
|
||||
startOffset: loc.startOffset, |
|
||||
endOffset: loc.endOffset |
|
||||
}; |
|
||||
if (loc.attrs) |
|
||||
loc.startTag.attrs = loc.attrs; |
|
||||
} |
|
||||
|
|
||||
if (closingToken.location) { |
|
||||
var ctLocation = closingToken.location, |
|
||||
tn = treeAdapter.getTagName(element), |
|
||||
// NOTE: For cases like <p> <p> </p> - First 'p' closes without a closing tag and
|
|
||||
// for cases like <td> <p> </td> - 'p' closes without a closing tag
|
|
||||
isClosingEndTag = closingToken.type === Tokenizer.END_TAG_TOKEN && |
|
||||
tn === closingToken.tagName; |
|
||||
|
|
||||
if (isClosingEndTag) { |
|
||||
loc.endTag = { |
|
||||
line: ctLocation.line, |
|
||||
col: ctLocation.col, |
|
||||
startOffset: ctLocation.startOffset, |
|
||||
endOffset: ctLocation.endOffset |
|
||||
}; |
|
||||
} |
|
||||
|
|
||||
if (isClosingEndTag) |
|
||||
loc.endOffset = ctLocation.endOffset; |
|
||||
else |
|
||||
loc.endOffset = ctLocation.startOffset; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
|
|
||||
exports.assign = function (parser) { |
|
||||
//NOTE: obtain Parser proto this way to avoid module circular references
|
|
||||
var parserProto = Object.getPrototypeOf(parser), |
|
||||
treeAdapter = parser.treeAdapter, |
|
||||
attachableElementLocation = null, |
|
||||
lastFosterParentingLocation = null, |
|
||||
currentToken = null; |
|
||||
|
|
||||
|
|
||||
//NOTE: patch _bootstrap method
|
|
||||
parser._bootstrap = function (document, fragmentContext) { |
|
||||
parserProto._bootstrap.call(this, document, fragmentContext); |
|
||||
|
|
||||
attachableElementLocation = null; |
|
||||
lastFosterParentingLocation = null; |
|
||||
currentToken = null; |
|
||||
|
|
||||
//OpenElementStack
|
|
||||
parser.openElements.pop = function () { |
|
||||
setEndLocation(this.current, currentToken, treeAdapter); |
|
||||
OpenElementStack.prototype.pop.call(this); |
|
||||
}; |
|
||||
|
|
||||
parser.openElements.popAllUpToHtmlElement = function () { |
|
||||
for (var i = this.stackTop; i > 0; i--) |
|
||||
setEndLocation(this.items[i], currentToken, treeAdapter); |
|
||||
|
|
||||
OpenElementStack.prototype.popAllUpToHtmlElement.call(this); |
|
||||
}; |
|
||||
|
|
||||
parser.openElements.remove = function (element) { |
|
||||
setEndLocation(element, currentToken, treeAdapter); |
|
||||
OpenElementStack.prototype.remove.call(this, element); |
|
||||
}; |
|
||||
}; |
|
||||
|
|
||||
|
|
||||
//Token processing
|
|
||||
parser._processTokenInForeignContent = function (token) { |
|
||||
currentToken = token; |
|
||||
parserProto._processTokenInForeignContent.call(this, token); |
|
||||
}; |
|
||||
|
|
||||
parser._processToken = function (token) { |
|
||||
currentToken = token; |
|
||||
parserProto._processToken.call(this, token); |
|
||||
|
|
||||
//NOTE: <body> and <html> are never popped from the stack, so we need to updated
|
|
||||
//their end location explicitly.
|
|
||||
if (token.type === Tokenizer.END_TAG_TOKEN && |
|
||||
(token.tagName === $.HTML || |
|
||||
token.tagName === $.BODY && this.openElements.hasInScope($.BODY))) { |
|
||||
for (var i = this.openElements.stackTop; i >= 0; i--) { |
|
||||
var element = this.openElements.items[i]; |
|
||||
|
|
||||
if (this.treeAdapter.getTagName(element) === token.tagName) { |
|
||||
setEndLocation(element, token, treeAdapter); |
|
||||
break; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
}; |
|
||||
|
|
||||
|
|
||||
//Doctype
|
|
||||
parser._setDocumentType = function (token) { |
|
||||
parserProto._setDocumentType.call(this, token); |
|
||||
|
|
||||
var documentChildren = this.treeAdapter.getChildNodes(this.document), |
|
||||
cnLength = documentChildren.length; |
|
||||
|
|
||||
for (var i = 0; i < cnLength; i++) { |
|
||||
var node = documentChildren[i]; |
|
||||
|
|
||||
if (this.treeAdapter.isDocumentTypeNode(node)) { |
|
||||
node.__location = token.location; |
|
||||
break; |
|
||||
} |
|
||||
} |
|
||||
}; |
|
||||
|
|
||||
|
|
||||
//Elements
|
|
||||
parser._attachElementToTree = function (element) { |
|
||||
//NOTE: _attachElementToTree is called from _appendElement, _insertElement and _insertTemplate methods.
|
|
||||
//So we will use token location stored in this methods for the element.
|
|
||||
element.__location = attachableElementLocation || null; |
|
||||
attachableElementLocation = null; |
|
||||
parserProto._attachElementToTree.call(this, element); |
|
||||
}; |
|
||||
|
|
||||
parser._appendElement = function (token, namespaceURI) { |
|
||||
attachableElementLocation = token.location; |
|
||||
parserProto._appendElement.call(this, token, namespaceURI); |
|
||||
}; |
|
||||
|
|
||||
parser._insertElement = function (token, namespaceURI) { |
|
||||
attachableElementLocation = token.location; |
|
||||
parserProto._insertElement.call(this, token, namespaceURI); |
|
||||
}; |
|
||||
|
|
||||
parser._insertTemplate = function (token) { |
|
||||
attachableElementLocation = token.location; |
|
||||
parserProto._insertTemplate.call(this, token); |
|
||||
|
|
||||
var tmplContent = this.treeAdapter.getTemplateContent(this.openElements.current); |
|
||||
|
|
||||
tmplContent.__location = null; |
|
||||
}; |
|
||||
|
|
||||
parser._insertFakeRootElement = function () { |
|
||||
parserProto._insertFakeRootElement.call(this); |
|
||||
this.openElements.current.__location = null; |
|
||||
}; |
|
||||
|
|
||||
|
|
||||
//Comments
|
|
||||
parser._appendCommentNode = function (token, parent) { |
|
||||
parserProto._appendCommentNode.call(this, token, parent); |
|
||||
|
|
||||
var children = this.treeAdapter.getChildNodes(parent), |
|
||||
commentNode = children[children.length - 1]; |
|
||||
|
|
||||
commentNode.__location = token.location; |
|
||||
}; |
|
||||
|
|
||||
|
|
||||
//Text
|
|
||||
parser._findFosterParentingLocation = function () { |
|
||||
//NOTE: store last foster parenting location, so we will be able to find inserted text
|
|
||||
//in case of foster parenting
|
|
||||
lastFosterParentingLocation = parserProto._findFosterParentingLocation.call(this); |
|
||||
return lastFosterParentingLocation; |
|
||||
}; |
|
||||
|
|
||||
parser._insertCharacters = function (token) { |
|
||||
parserProto._insertCharacters.call(this, token); |
|
||||
|
|
||||
var hasFosterParent = this._shouldFosterParentOnInsertion(), |
|
||||
parent = hasFosterParent && lastFosterParentingLocation.parent || |
|
||||
this.openElements.currentTmplContent || |
|
||||
this.openElements.current, |
|
||||
siblings = this.treeAdapter.getChildNodes(parent), |
|
||||
textNodeIdx = hasFosterParent && lastFosterParentingLocation.beforeElement ? |
|
||||
siblings.indexOf(lastFosterParentingLocation.beforeElement) - 1 : |
|
||||
siblings.length - 1, |
|
||||
textNode = siblings[textNodeIdx]; |
|
||||
|
|
||||
//NOTE: if we have location assigned by another token, then just update end position
|
|
||||
if (textNode.__location) |
|
||||
textNode.__location.endOffset = token.location.endOffset; |
|
||||
|
|
||||
else |
|
||||
textNode.__location = token.location; |
|
||||
}; |
|
||||
}; |
|
||||
|
|
@ -1,169 +0,0 @@ |
|||||
'use strict'; |
|
||||
|
|
||||
var UNICODE = require('../common/unicode'); |
|
||||
|
|
||||
//Aliases
|
|
||||
var $ = UNICODE.CODE_POINTS; |
|
||||
|
|
||||
|
|
||||
exports.assign = function (tokenizer) { |
|
||||
//NOTE: obtain Tokenizer proto this way to avoid module circular references
|
|
||||
var tokenizerProto = Object.getPrototypeOf(tokenizer), |
|
||||
tokenStartOffset = -1, |
|
||||
tokenCol = -1, |
|
||||
tokenLine = 1, |
|
||||
isEol = false, |
|
||||
lineStartPosStack = [0], |
|
||||
lineStartPos = 0, |
|
||||
col = -1, |
|
||||
line = 1; |
|
||||
|
|
||||
function attachLocationInfo(token) { |
|
||||
/** |
|
||||
* @typedef {Object} LocationInfo |
|
||||
* |
|
||||
* @property {Number} line - One-based line index |
|
||||
* @property {Number} col - One-based column index |
|
||||
* @property {Number} startOffset - Zero-based first character index |
|
||||
* @property {Number} endOffset - Zero-based last character index |
|
||||
*/ |
|
||||
token.location = { |
|
||||
line: tokenLine, |
|
||||
col: tokenCol, |
|
||||
startOffset: tokenStartOffset, |
|
||||
endOffset: -1 |
|
||||
}; |
|
||||
} |
|
||||
|
|
||||
//NOTE: patch consumption method to track line/col information
|
|
||||
tokenizer._consume = function () { |
|
||||
var cp = tokenizerProto._consume.call(this); |
|
||||
|
|
||||
//NOTE: LF should be in the last column of the line
|
|
||||
if (isEol) { |
|
||||
isEol = false; |
|
||||
line++; |
|
||||
lineStartPosStack.push(this.preprocessor.sourcePos); |
|
||||
lineStartPos = this.preprocessor.sourcePos; |
|
||||
} |
|
||||
|
|
||||
if (cp === $.LINE_FEED) |
|
||||
isEol = true; |
|
||||
|
|
||||
col = this.preprocessor.sourcePos - lineStartPos + 1; |
|
||||
|
|
||||
return cp; |
|
||||
}; |
|
||||
|
|
||||
tokenizer._unconsume = function () { |
|
||||
tokenizerProto._unconsume.call(this); |
|
||||
isEol = false; |
|
||||
|
|
||||
while (lineStartPos > this.preprocessor.sourcePos && lineStartPosStack.length > 1) { |
|
||||
lineStartPos = lineStartPosStack.pop(); |
|
||||
line--; |
|
||||
} |
|
||||
|
|
||||
col = this.preprocessor.sourcePos - lineStartPos + 1; |
|
||||
}; |
|
||||
|
|
||||
//NOTE: patch token creation methods and attach location objects
|
|
||||
tokenizer._createStartTagToken = function () { |
|
||||
tokenizerProto._createStartTagToken.call(this); |
|
||||
attachLocationInfo(this.currentToken); |
|
||||
}; |
|
||||
|
|
||||
tokenizer._createEndTagToken = function () { |
|
||||
tokenizerProto._createEndTagToken.call(this); |
|
||||
attachLocationInfo(this.currentToken); |
|
||||
}; |
|
||||
|
|
||||
tokenizer._createCommentToken = function () { |
|
||||
tokenizerProto._createCommentToken.call(this); |
|
||||
attachLocationInfo(this.currentToken); |
|
||||
}; |
|
||||
|
|
||||
tokenizer._createDoctypeToken = function (initialName) { |
|
||||
tokenizerProto._createDoctypeToken.call(this, initialName); |
|
||||
attachLocationInfo(this.currentToken); |
|
||||
}; |
|
||||
|
|
||||
tokenizer._createCharacterToken = function (type, ch) { |
|
||||
tokenizerProto._createCharacterToken.call(this, type, ch); |
|
||||
attachLocationInfo(this.currentCharacterToken); |
|
||||
}; |
|
||||
|
|
||||
tokenizer._createAttr = function (attrNameFirstCh) { |
|
||||
tokenizerProto._createAttr.call(this, attrNameFirstCh); |
|
||||
this.currentAttrLocation = { |
|
||||
line: line, |
|
||||
col: col, |
|
||||
startOffset: this.preprocessor.sourcePos, |
|
||||
endOffset: -1 |
|
||||
}; |
|
||||
}; |
|
||||
|
|
||||
tokenizer._leaveAttrName = function (toState) { |
|
||||
tokenizerProto._leaveAttrName.call(this, toState); |
|
||||
this._attachCurrentAttrLocationInfo(); |
|
||||
}; |
|
||||
|
|
||||
tokenizer._leaveAttrValue = function (toState) { |
|
||||
tokenizerProto._leaveAttrValue.call(this, toState); |
|
||||
this._attachCurrentAttrLocationInfo(); |
|
||||
}; |
|
||||
|
|
||||
tokenizer._attachCurrentAttrLocationInfo = function () { |
|
||||
this.currentAttrLocation.endOffset = this.preprocessor.sourcePos; |
|
||||
|
|
||||
if (!this.currentToken.location.attrs) |
|
||||
this.currentToken.location.attrs = {}; |
|
||||
|
|
||||
/** |
|
||||
* @typedef {Object} StartTagLocationInfo |
|
||||
* @extends LocationInfo |
|
||||
* |
|
||||
* @property {Dictionary<String, LocationInfo>} attrs - Start tag attributes' location info. |
|
||||
*/ |
|
||||
this.currentToken.location.attrs[this.currentAttr.name] = this.currentAttrLocation; |
|
||||
}; |
|
||||
|
|
||||
//NOTE: patch token emission methods to determine end location
|
|
||||
tokenizer._emitCurrentToken = function () { |
|
||||
//NOTE: if we have pending character token make it's end location equal to the
|
|
||||
//current token's start location.
|
|
||||
if (this.currentCharacterToken) |
|
||||
this.currentCharacterToken.location.endOffset = this.currentToken.location.startOffset; |
|
||||
|
|
||||
this.currentToken.location.endOffset = this.preprocessor.sourcePos + 1; |
|
||||
tokenizerProto._emitCurrentToken.call(this); |
|
||||
}; |
|
||||
|
|
||||
tokenizer._emitCurrentCharacterToken = function () { |
|
||||
//NOTE: if we have character token and it's location wasn't set in the _emitCurrentToken(),
|
|
||||
//then set it's location at the current preprocessor position.
|
|
||||
//We don't need to increment preprocessor position, since character token
|
|
||||
//emission is always forced by the start of the next character token here.
|
|
||||
//So, we already have advanced position.
|
|
||||
if (this.currentCharacterToken && this.currentCharacterToken.location.endOffset === -1) |
|
||||
this.currentCharacterToken.location.endOffset = this.preprocessor.sourcePos; |
|
||||
|
|
||||
tokenizerProto._emitCurrentCharacterToken.call(this); |
|
||||
}; |
|
||||
|
|
||||
//NOTE: patch initial states for each mode to obtain token start position
|
|
||||
Object.keys(tokenizerProto.MODE) |
|
||||
|
|
||||
.map(function (modeName) { |
|
||||
return tokenizerProto.MODE[modeName]; |
|
||||
}) |
|
||||
|
|
||||
.forEach(function (state) { |
|
||||
tokenizer[state] = function (cp) { |
|
||||
tokenStartOffset = this.preprocessor.sourcePos; |
|
||||
tokenLine = line; |
|
||||
tokenCol = col; |
|
||||
tokenizerProto[state].call(this, cp); |
|
||||
}; |
|
||||
}); |
|
||||
}; |
|
@ -1,167 +0,0 @@ |
|||||
'use strict'; |
|
||||
|
|
||||
//Const
|
|
||||
var NOAH_ARK_CAPACITY = 3; |
|
||||
|
|
||||
//List of formatting elements
|
|
||||
var FormattingElementList = module.exports = function (treeAdapter) { |
|
||||
this.length = 0; |
|
||||
this.entries = []; |
|
||||
this.treeAdapter = treeAdapter; |
|
||||
this.bookmark = null; |
|
||||
}; |
|
||||
|
|
||||
//Entry types
|
|
||||
FormattingElementList.MARKER_ENTRY = 'MARKER_ENTRY'; |
|
||||
FormattingElementList.ELEMENT_ENTRY = 'ELEMENT_ENTRY'; |
|
||||
|
|
||||
//Noah Ark's condition
|
|
||||
//OPTIMIZATION: at first we try to find possible candidates for exclusion using
|
|
||||
//lightweight heuristics without thorough attributes check.
|
|
||||
FormattingElementList.prototype._getNoahArkConditionCandidates = function (newElement) { |
|
||||
var candidates = []; |
|
||||
|
|
||||
if (this.length >= NOAH_ARK_CAPACITY) { |
|
||||
var neAttrsLength = this.treeAdapter.getAttrList(newElement).length, |
|
||||
neTagName = this.treeAdapter.getTagName(newElement), |
|
||||
neNamespaceURI = this.treeAdapter.getNamespaceURI(newElement); |
|
||||
|
|
||||
for (var i = this.length - 1; i >= 0; i--) { |
|
||||
var entry = this.entries[i]; |
|
||||
|
|
||||
if (entry.type === FormattingElementList.MARKER_ENTRY) |
|
||||
break; |
|
||||
|
|
||||
var element = entry.element, |
|
||||
elementAttrs = this.treeAdapter.getAttrList(element), |
|
||||
isCandidate = this.treeAdapter.getTagName(element) === neTagName && |
|
||||
this.treeAdapter.getNamespaceURI(element) === neNamespaceURI && |
|
||||
elementAttrs.length === neAttrsLength; |
|
||||
|
|
||||
if (isCandidate) |
|
||||
candidates.push({idx: i, attrs: elementAttrs}); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
return candidates.length < NOAH_ARK_CAPACITY ? [] : candidates; |
|
||||
}; |
|
||||
|
|
||||
FormattingElementList.prototype._ensureNoahArkCondition = function (newElement) { |
|
||||
var candidates = this._getNoahArkConditionCandidates(newElement), |
|
||||
cLength = candidates.length; |
|
||||
|
|
||||
if (cLength) { |
|
||||
var neAttrs = this.treeAdapter.getAttrList(newElement), |
|
||||
neAttrsLength = neAttrs.length, |
|
||||
neAttrsMap = {}; |
|
||||
|
|
||||
//NOTE: build attrs map for the new element so we can perform fast lookups
|
|
||||
for (var i = 0; i < neAttrsLength; i++) { |
|
||||
var neAttr = neAttrs[i]; |
|
||||
|
|
||||
neAttrsMap[neAttr.name] = neAttr.value; |
|
||||
} |
|
||||
|
|
||||
for (i = 0; i < neAttrsLength; i++) { |
|
||||
for (var j = 0; j < cLength; j++) { |
|
||||
var cAttr = candidates[j].attrs[i]; |
|
||||
|
|
||||
if (neAttrsMap[cAttr.name] !== cAttr.value) { |
|
||||
candidates.splice(j, 1); |
|
||||
cLength--; |
|
||||
} |
|
||||
|
|
||||
if (candidates.length < NOAH_ARK_CAPACITY) |
|
||||
return; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
//NOTE: remove bottommost candidates until Noah's Ark condition will not be met
|
|
||||
for (i = cLength - 1; i >= NOAH_ARK_CAPACITY - 1; i--) { |
|
||||
this.entries.splice(candidates[i].idx, 1); |
|
||||
this.length--; |
|
||||
} |
|
||||
} |
|
||||
}; |
|
||||
|
|
||||
//Mutations
|
|
||||
FormattingElementList.prototype.insertMarker = function () { |
|
||||
this.entries.push({type: FormattingElementList.MARKER_ENTRY}); |
|
||||
this.length++; |
|
||||
}; |
|
||||
|
|
||||
FormattingElementList.prototype.pushElement = function (element, token) { |
|
||||
this._ensureNoahArkCondition(element); |
|
||||
|
|
||||
this.entries.push({ |
|
||||
type: FormattingElementList.ELEMENT_ENTRY, |
|
||||
element: element, |
|
||||
token: token |
|
||||
}); |
|
||||
|
|
||||
this.length++; |
|
||||
}; |
|
||||
|
|
||||
FormattingElementList.prototype.insertElementAfterBookmark = function (element, token) { |
|
||||
var bookmarkIdx = this.length - 1; |
|
||||
|
|
||||
for (; bookmarkIdx >= 0; bookmarkIdx--) { |
|
||||
if (this.entries[bookmarkIdx] === this.bookmark) |
|
||||
break; |
|
||||
} |
|
||||
|
|
||||
this.entries.splice(bookmarkIdx + 1, 0, { |
|
||||
type: FormattingElementList.ELEMENT_ENTRY, |
|
||||
element: element, |
|
||||
token: token |
|
||||
}); |
|
||||
|
|
||||
this.length++; |
|
||||
}; |
|
||||
|
|
||||
FormattingElementList.prototype.removeEntry = function (entry) { |
|
||||
for (var i = this.length - 1; i >= 0; i--) { |
|
||||
if (this.entries[i] === entry) { |
|
||||
this.entries.splice(i, 1); |
|
||||
this.length--; |
|
||||
break; |
|
||||
} |
|
||||
} |
|
||||
}; |
|
||||
|
|
||||
FormattingElementList.prototype.clearToLastMarker = function () { |
|
||||
while (this.length) { |
|
||||
var entry = this.entries.pop(); |
|
||||
|
|
||||
this.length--; |
|
||||
|
|
||||
if (entry.type === FormattingElementList.MARKER_ENTRY) |
|
||||
break; |
|
||||
} |
|
||||
}; |
|
||||
|
|
||||
//Search
|
|
||||
FormattingElementList.prototype.getElementEntryInScopeWithTagName = function (tagName) { |
|
||||
for (var i = this.length - 1; i >= 0; i--) { |
|
||||
var entry = this.entries[i]; |
|
||||
|
|
||||
if (entry.type === FormattingElementList.MARKER_ENTRY) |
|
||||
return null; |
|
||||
|
|
||||
if (this.treeAdapter.getTagName(entry.element) === tagName) |
|
||||
return entry; |
|
||||
} |
|
||||
|
|
||||
return null; |
|
||||
}; |
|
||||
|
|
||||
FormattingElementList.prototype.getElementEntry = function (element) { |
|
||||
for (var i = this.length - 1; i >= 0; i--) { |
|
||||
var entry = this.entries[i]; |
|
||||
|
|
||||
if (entry.type === FormattingElementList.ELEMENT_ENTRY && entry.element === element) |
|
||||
return entry; |
|
||||
} |
|
||||
|
|
||||
return null; |
|
||||
}; |
|
File diff suppressed because it is too large
@ -1,395 +0,0 @@ |
|||||
'use strict'; |
|
||||
|
|
||||
var HTML = require('../common/html'); |
|
||||
|
|
||||
//Aliases
|
|
||||
var $ = HTML.TAG_NAMES, |
|
||||
NS = HTML.NAMESPACES; |
|
||||
|
|
||||
//Element utils
|
|
||||
|
|
||||
//OPTIMIZATION: Integer comparisons are low-cost, so we can use very fast tag name length filters here.
|
|
||||
//It's faster than using dictionary.
|
|
||||
function isImpliedEndTagRequired(tn) { |
|
||||
switch (tn.length) { |
|
||||
case 1: |
|
||||
return tn === $.P; |
|
||||
|
|
||||
case 2: |
|
||||
return tn === $.RB || tn === $.RP || tn === $.RT || tn === $.DD || tn === $.DT || tn === $.LI; |
|
||||
|
|
||||
case 3: |
|
||||
return tn === $.RTC; |
|
||||
|
|
||||
case 6: |
|
||||
return tn === $.OPTION; |
|
||||
|
|
||||
case 8: |
|
||||
return tn === $.OPTGROUP || tn === $.MENUITEM; |
|
||||
} |
|
||||
|
|
||||
return false; |
|
||||
} |
|
||||
|
|
||||
function isScopingElement(tn, ns) { |
|
||||
switch (tn.length) { |
|
||||
case 2: |
|
||||
if (tn === $.TD || tn === $.TH) |
|
||||
return ns === NS.HTML; |
|
||||
|
|
||||
else if (tn === $.MI || tn === $.MO || tn === $.MN || tn === $.MS) |
|
||||
return ns === NS.MATHML; |
|
||||
|
|
||||
break; |
|
||||
|
|
||||
case 4: |
|
||||
if (tn === $.HTML) |
|
||||
return ns === NS.HTML; |
|
||||
|
|
||||
else if (tn === $.DESC) |
|
||||
return ns === NS.SVG; |
|
||||
|
|
||||
break; |
|
||||
|
|
||||
case 5: |
|
||||
if (tn === $.TABLE) |
|
||||
return ns === NS.HTML; |
|
||||
|
|
||||
else if (tn === $.MTEXT) |
|
||||
return ns === NS.MATHML; |
|
||||
|
|
||||
else if (tn === $.TITLE) |
|
||||
return ns === NS.SVG; |
|
||||
|
|
||||
break; |
|
||||
|
|
||||
case 6: |
|
||||
return (tn === $.APPLET || tn === $.OBJECT) && ns === NS.HTML; |
|
||||
|
|
||||
case 7: |
|
||||
return (tn === $.CAPTION || tn === $.MARQUEE) && ns === NS.HTML; |
|
||||
|
|
||||
case 8: |
|
||||
return tn === $.TEMPLATE && ns === NS.HTML; |
|
||||
|
|
||||
case 13: |
|
||||
return tn === $.FOREIGN_OBJECT && ns === NS.SVG; |
|
||||
|
|
||||
case 14: |
|
||||
return tn === $.ANNOTATION_XML && ns === NS.MATHML; |
|
||||
} |
|
||||
|
|
||||
return false; |
|
||||
} |
|
||||
|
|
||||
//Stack of open elements
|
|
||||
var OpenElementStack = module.exports = function (document, treeAdapter) { |
|
||||
this.stackTop = -1; |
|
||||
this.items = []; |
|
||||
this.current = document; |
|
||||
this.currentTagName = null; |
|
||||
this.currentTmplContent = null; |
|
||||
this.tmplCount = 0; |
|
||||
this.treeAdapter = treeAdapter; |
|
||||
}; |
|
||||
|
|
||||
//Index of element
|
|
||||
OpenElementStack.prototype._indexOf = function (element) { |
|
||||
var idx = -1; |
|
||||
|
|
||||
for (var i = this.stackTop; i >= 0; i--) { |
|
||||
if (this.items[i] === element) { |
|
||||
idx = i; |
|
||||
break; |
|
||||
} |
|
||||
} |
|
||||
return idx; |
|
||||
}; |
|
||||
|
|
||||
//Update current element
|
|
||||
OpenElementStack.prototype._isInTemplate = function () { |
|
||||
return this.currentTagName === $.TEMPLATE && this.treeAdapter.getNamespaceURI(this.current) === NS.HTML; |
|
||||
}; |
|
||||
|
|
||||
OpenElementStack.prototype._updateCurrentElement = function () { |
|
||||
this.current = this.items[this.stackTop]; |
|
||||
this.currentTagName = this.current && this.treeAdapter.getTagName(this.current); |
|
||||
|
|
||||
this.currentTmplContent = this._isInTemplate() ? this.treeAdapter.getTemplateContent(this.current) : null; |
|
||||
}; |
|
||||
|
|
||||
//Mutations
|
|
||||
OpenElementStack.prototype.push = function (element) { |
|
||||
this.items[++this.stackTop] = element; |
|
||||
this._updateCurrentElement(); |
|
||||
|
|
||||
if (this._isInTemplate()) |
|
||||
this.tmplCount++; |
|
||||
|
|
||||
}; |
|
||||
|
|
||||
OpenElementStack.prototype.pop = function () { |
|
||||
this.stackTop--; |
|
||||
|
|
||||
if (this.tmplCount > 0 && this._isInTemplate()) |
|
||||
this.tmplCount--; |
|
||||
|
|
||||
this._updateCurrentElement(); |
|
||||
}; |
|
||||
|
|
||||
OpenElementStack.prototype.replace = function (oldElement, newElement) { |
|
||||
var idx = this._indexOf(oldElement); |
|
||||
|
|
||||
this.items[idx] = newElement; |
|
||||
|
|
||||
if (idx === this.stackTop) |
|
||||
this._updateCurrentElement(); |
|
||||
}; |
|
||||
|
|
||||
OpenElementStack.prototype.insertAfter = function (referenceElement, newElement) { |
|
||||
var insertionIdx = this._indexOf(referenceElement) + 1; |
|
||||
|
|
||||
this.items.splice(insertionIdx, 0, newElement); |
|
||||
|
|
||||
if (insertionIdx === ++this.stackTop) |
|
||||
this._updateCurrentElement(); |
|
||||
}; |
|
||||
|
|
||||
OpenElementStack.prototype.popUntilTagNamePopped = function (tagName) { |
|
||||
while (this.stackTop > -1) { |
|
||||
var tn = this.currentTagName, |
|
||||
ns = this.treeAdapter.getNamespaceURI(this.current); |
|
||||
|
|
||||
this.pop(); |
|
||||
|
|
||||
if (tn === tagName && ns === NS.HTML) |
|
||||
break; |
|
||||
} |
|
||||
}; |
|
||||
|
|
||||
OpenElementStack.prototype.popUntilElementPopped = function (element) { |
|
||||
while (this.stackTop > -1) { |
|
||||
var poppedElement = this.current; |
|
||||
|
|
||||
this.pop(); |
|
||||
|
|
||||
if (poppedElement === element) |
|
||||
break; |
|
||||
} |
|
||||
}; |
|
||||
|
|
||||
OpenElementStack.prototype.popUntilNumberedHeaderPopped = function () { |
|
||||
while (this.stackTop > -1) { |
|
||||
var tn = this.currentTagName, |
|
||||
ns = this.treeAdapter.getNamespaceURI(this.current); |
|
||||
|
|
||||
this.pop(); |
|
||||
|
|
||||
if (tn === $.H1 || tn === $.H2 || tn === $.H3 || tn === $.H4 || tn === $.H5 || tn === $.H6 && ns === NS.HTML) |
|
||||
break; |
|
||||
} |
|
||||
}; |
|
||||
|
|
||||
OpenElementStack.prototype.popUntilTableCellPopped = function () { |
|
||||
while (this.stackTop > -1) { |
|
||||
var tn = this.currentTagName, |
|
||||
ns = this.treeAdapter.getNamespaceURI(this.current); |
|
||||
|
|
||||
this.pop(); |
|
||||
|
|
||||
if (tn === $.TD || tn === $.TH && ns === NS.HTML) |
|
||||
break; |
|
||||
} |
|
||||
}; |
|
||||
|
|
||||
OpenElementStack.prototype.popAllUpToHtmlElement = function () { |
|
||||
//NOTE: here we assume that root <html> element is always first in the open element stack, so
|
|
||||
//we perform this fast stack clean up.
|
|
||||
this.stackTop = 0; |
|
||||
this._updateCurrentElement(); |
|
||||
}; |
|
||||
|
|
||||
OpenElementStack.prototype.clearBackToTableContext = function () { |
|
||||
while (this.currentTagName !== $.TABLE && |
|
||||
this.currentTagName !== $.TEMPLATE && |
|
||||
this.currentTagName !== $.HTML || |
|
||||
this.treeAdapter.getNamespaceURI(this.current) !== NS.HTML) |
|
||||
this.pop(); |
|
||||
}; |
|
||||
|
|
||||
OpenElementStack.prototype.clearBackToTableBodyContext = function () { |
|
||||
while (this.currentTagName !== $.TBODY && |
|
||||
this.currentTagName !== $.TFOOT && |
|
||||
this.currentTagName !== $.THEAD && |
|
||||
this.currentTagName !== $.TEMPLATE && |
|
||||
this.currentTagName !== $.HTML || |
|
||||
this.treeAdapter.getNamespaceURI(this.current) !== NS.HTML) |
|
||||
this.pop(); |
|
||||
}; |
|
||||
|
|
||||
OpenElementStack.prototype.clearBackToTableRowContext = function () { |
|
||||
while (this.currentTagName !== $.TR && |
|
||||
this.currentTagName !== $.TEMPLATE && |
|
||||
this.currentTagName !== $.HTML || |
|
||||
this.treeAdapter.getNamespaceURI(this.current) !== NS.HTML) |
|
||||
this.pop(); |
|
||||
}; |
|
||||
|
|
||||
OpenElementStack.prototype.remove = function (element) { |
|
||||
for (var i = this.stackTop; i >= 0; i--) { |
|
||||
if (this.items[i] === element) { |
|
||||
this.items.splice(i, 1); |
|
||||
this.stackTop--; |
|
||||
this._updateCurrentElement(); |
|
||||
break; |
|
||||
} |
|
||||
} |
|
||||
}; |
|
||||
|
|
||||
//Search
|
|
||||
OpenElementStack.prototype.tryPeekProperlyNestedBodyElement = function () { |
|
||||
//Properly nested <body> element (should be second element in stack).
|
|
||||
var element = this.items[1]; |
|
||||
|
|
||||
return element && this.treeAdapter.getTagName(element) === $.BODY ? element : null; |
|
||||
}; |
|
||||
|
|
||||
OpenElementStack.prototype.contains = function (element) { |
|
||||
return this._indexOf(element) > -1; |
|
||||
}; |
|
||||
|
|
||||
OpenElementStack.prototype.getCommonAncestor = function (element) { |
|
||||
var elementIdx = this._indexOf(element); |
|
||||
|
|
||||
return --elementIdx >= 0 ? this.items[elementIdx] : null; |
|
||||
}; |
|
||||
|
|
||||
OpenElementStack.prototype.isRootHtmlElementCurrent = function () { |
|
||||
return this.stackTop === 0 && this.currentTagName === $.HTML; |
|
||||
}; |
|
||||
|
|
||||
//Element in scope
|
|
||||
OpenElementStack.prototype.hasInScope = function (tagName) { |
|
||||
for (var i = this.stackTop; i >= 0; i--) { |
|
||||
var tn = this.treeAdapter.getTagName(this.items[i]), |
|
||||
ns = this.treeAdapter.getNamespaceURI(this.items[i]); |
|
||||
|
|
||||
if (tn === tagName && ns === NS.HTML) |
|
||||
return true; |
|
||||
|
|
||||
if (isScopingElement(tn, ns)) |
|
||||
return false; |
|
||||
} |
|
||||
|
|
||||
return true; |
|
||||
}; |
|
||||
|
|
||||
OpenElementStack.prototype.hasNumberedHeaderInScope = function () { |
|
||||
for (var i = this.stackTop; i >= 0; i--) { |
|
||||
var tn = this.treeAdapter.getTagName(this.items[i]), |
|
||||
ns = this.treeAdapter.getNamespaceURI(this.items[i]); |
|
||||
|
|
||||
if ((tn === $.H1 || tn === $.H2 || tn === $.H3 || tn === $.H4 || tn === $.H5 || tn === $.H6) && ns === NS.HTML) |
|
||||
return true; |
|
||||
|
|
||||
if (isScopingElement(tn, ns)) |
|
||||
return false; |
|
||||
} |
|
||||
|
|
||||
return true; |
|
||||
}; |
|
||||
|
|
||||
OpenElementStack.prototype.hasInListItemScope = function (tagName) { |
|
||||
for (var i = this.stackTop; i >= 0; i--) { |
|
||||
var tn = this.treeAdapter.getTagName(this.items[i]), |
|
||||
ns = this.treeAdapter.getNamespaceURI(this.items[i]); |
|
||||
|
|
||||
if (tn === tagName && ns === NS.HTML) |
|
||||
return true; |
|
||||
|
|
||||
if ((tn === $.UL || tn === $.OL) && ns === NS.HTML || isScopingElement(tn, ns)) |
|
||||
return false; |
|
||||
} |
|
||||
|
|
||||
return true; |
|
||||
}; |
|
||||
|
|
||||
OpenElementStack.prototype.hasInButtonScope = function (tagName) { |
|
||||
for (var i = this.stackTop; i >= 0; i--) { |
|
||||
var tn = this.treeAdapter.getTagName(this.items[i]), |
|
||||
ns = this.treeAdapter.getNamespaceURI(this.items[i]); |
|
||||
|
|
||||
if (tn === tagName && ns === NS.HTML) |
|
||||
return true; |
|
||||
|
|
||||
if (tn === $.BUTTON && ns === NS.HTML || isScopingElement(tn, ns)) |
|
||||
return false; |
|
||||
} |
|
||||
|
|
||||
return true; |
|
||||
}; |
|
||||
|
|
||||
OpenElementStack.prototype.hasInTableScope = function (tagName) { |
|
||||
for (var i = this.stackTop; i >= 0; i--) { |
|
||||
var tn = this.treeAdapter.getTagName(this.items[i]), |
|
||||
ns = this.treeAdapter.getNamespaceURI(this.items[i]); |
|
||||
|
|
||||
if (ns !== NS.HTML) |
|
||||
continue; |
|
||||
|
|
||||
if (tn === tagName) |
|
||||
return true; |
|
||||
|
|
||||
if (tn === $.TABLE || tn === $.TEMPLATE || tn === $.HTML) |
|
||||
return false; |
|
||||
} |
|
||||
|
|
||||
return true; |
|
||||
}; |
|
||||
|
|
||||
OpenElementStack.prototype.hasTableBodyContextInTableScope = function () { |
|
||||
for (var i = this.stackTop; i >= 0; i--) { |
|
||||
var tn = this.treeAdapter.getTagName(this.items[i]), |
|
||||
ns = this.treeAdapter.getNamespaceURI(this.items[i]); |
|
||||
|
|
||||
if (ns !== NS.HTML) |
|
||||
continue; |
|
||||
|
|
||||
if (tn === $.TBODY || tn === $.THEAD || tn === $.TFOOT) |
|
||||
return true; |
|
||||
|
|
||||
if (tn === $.TABLE || tn === $.HTML) |
|
||||
return false; |
|
||||
} |
|
||||
|
|
||||
return true; |
|
||||
}; |
|
||||
|
|
||||
OpenElementStack.prototype.hasInSelectScope = function (tagName) { |
|
||||
for (var i = this.stackTop; i >= 0; i--) { |
|
||||
var tn = this.treeAdapter.getTagName(this.items[i]), |
|
||||
ns = this.treeAdapter.getNamespaceURI(this.items[i]); |
|
||||
|
|
||||
if (ns !== NS.HTML) |
|
||||
continue; |
|
||||
|
|
||||
if (tn === tagName) |
|
||||
return true; |
|
||||
|
|
||||
if (tn !== $.OPTION && tn !== $.OPTGROUP) |
|
||||
return false; |
|
||||
} |
|
||||
|
|
||||
return true; |
|
||||
}; |
|
||||
|
|
||||
//Implied end tags
|
|
||||
OpenElementStack.prototype.generateImpliedEndTags = function () { |
|
||||
while (isImpliedEndTagRequired(this.currentTagName)) |
|
||||
this.pop(); |
|
||||
}; |
|
||||
|
|
||||
OpenElementStack.prototype.generateImpliedEndTagsWithExclusion = function (exclusionTagName) { |
|
||||
while (isImpliedEndTagRequired(this.currentTagName) && this.currentTagName !== exclusionTagName) |
|
||||
this.pop(); |
|
||||
}; |
|
@ -1,140 +0,0 @@ |
|||||
'use strict'; |
|
||||
|
|
||||
var WritableStream = require('stream').Writable, |
|
||||
inherits = require('util').inherits, |
|
||||
Parser = require('./index'); |
|
||||
|
|
||||
/** |
|
||||
* Streaming HTML parser with scripting support. |
|
||||
* A [writable stream]{@link https://nodejs.org/api/stream.html#stream_class_stream_writable}.
|
|
||||
* @class ParserStream |
|
||||
* @memberof parse5 |
|
||||
* @instance |
|
||||
* @extends stream.Writable |
|
||||
* @param {ParserOptions} options - Parsing options. |
|
||||
* @example |
|
||||
* var parse5 = require('parse5'); |
|
||||
* var http = require('http'); |
|
||||
* |
|
||||
* // Fetch the google.com content and obtain it's <body> node
|
|
||||
* http.get('http://google.com', function(res) { |
|
||||
* var parser = new parse5.ParserStream(); |
|
||||
* |
|
||||
* parser.on('finish', function() { |
|
||||
* var body = parser.document.childNodes[0].childNodes[1]; |
|
||||
* }); |
|
||||
* |
|
||||
* res.pipe(parser); |
|
||||
* }); |
|
||||
*/ |
|
||||
var ParserStream = module.exports = function (options) { |
|
||||
WritableStream.call(this); |
|
||||
|
|
||||
this.parser = new Parser(options); |
|
||||
|
|
||||
this.lastChunkWritten = false; |
|
||||
this.writeCallback = null; |
|
||||
this.pausedByScript = false; |
|
||||
|
|
||||
/** |
|
||||
* The resulting document node. |
|
||||
* @member {ASTNode<document>} document |
|
||||
* @memberof parse5#ParserStream |
|
||||
* @instance |
|
||||
*/ |
|
||||
this.document = this.parser.treeAdapter.createDocument(); |
|
||||
|
|
||||
this.pendingHtmlInsertions = []; |
|
||||
|
|
||||
this._resume = this._resume.bind(this); |
|
||||
this._documentWrite = this._documentWrite.bind(this); |
|
||||
this._scriptHandler = this._scriptHandler.bind(this); |
|
||||
|
|
||||
this.parser._bootstrap(this.document, null); |
|
||||
}; |
|
||||
|
|
||||
inherits(ParserStream, WritableStream); |
|
||||
|
|
||||
//WritableStream implementation
|
|
||||
ParserStream.prototype._write = function (chunk, encoding, callback) { |
|
||||
this.writeCallback = callback; |
|
||||
this.parser.tokenizer.write(chunk.toString('utf8'), this.lastChunkWritten); |
|
||||
this._runParsingLoop(); |
|
||||
}; |
|
||||
|
|
||||
ParserStream.prototype.end = function (chunk, encoding, callback) { |
|
||||
this.lastChunkWritten = true; |
|
||||
WritableStream.prototype.end.call(this, chunk, encoding, callback); |
|
||||
}; |
|
||||
|
|
||||
//Scriptable parser implementation
|
|
||||
ParserStream.prototype._runParsingLoop = function () { |
|
||||
this.parser._runParsingLoop(this.writeCallback, this._scriptHandler); |
|
||||
}; |
|
||||
|
|
||||
ParserStream.prototype._resume = function () { |
|
||||
if (!this.pausedByScript) |
|
||||
throw new Error('Parser was already resumed'); |
|
||||
|
|
||||
while (this.pendingHtmlInsertions.length) { |
|
||||
var html = this.pendingHtmlInsertions.pop(); |
|
||||
|
|
||||
this.parser.tokenizer.insertHtmlAtCurrentPos(html); |
|
||||
} |
|
||||
|
|
||||
this.pausedByScript = false; |
|
||||
|
|
||||
//NOTE: keep parsing if we don't wait for the next input chunk
|
|
||||
if (this.parser.tokenizer.active) |
|
||||
this._runParsingLoop(); |
|
||||
}; |
|
||||
|
|
||||
ParserStream.prototype._documentWrite = function (html) { |
|
||||
if (!this.parser.stopped) |
|
||||
this.pendingHtmlInsertions.push(html); |
|
||||
}; |
|
||||
|
|
||||
ParserStream.prototype._scriptHandler = function (scriptElement) { |
|
||||
if (this.listeners('script').length) { |
|
||||
this.pausedByScript = true; |
|
||||
|
|
||||
/** |
|
||||
* Raised then parser encounters a `<script>` element. |
|
||||
* If this event has listeners, parsing will be suspended once it is emitted. |
|
||||
* So, if `<script>` has the `src` attribute, you can fetch it, execute and then resume parsing just like browsers do. |
|
||||
* @event script |
|
||||
* @memberof parse5#ParserStream |
|
||||
* @instance |
|
||||
* @type {Function} |
|
||||
* @param {ASTNode} scriptElement - The script element that caused the event. |
|
||||
* @param {Function} documentWrite(html) - Write additional `html` at the current parsing position. |
|
||||
* Suitable for implementing the DOM `document.write` and `document.writeln` methods. |
|
||||
* @param {Function} resume - Resumes parsing. |
|
||||
* @example |
|
||||
* var parse = require('parse5'); |
|
||||
* var http = require('http'); |
|
||||
* |
|
||||
* var parser = new parse5.ParserStream(); |
|
||||
* |
|
||||
* parser.on('script', function(scriptElement, documentWrite, resume) { |
|
||||
* var src = parse5.treeAdapters.default.getAttrList(scriptElement)[0].value; |
|
||||
* |
|
||||
* http.get(src, function(res) { |
|
||||
* // Fetch the script content, execute it with DOM built around `parser.document` and
|
|
||||
* // `document.write` implemented using `documentWrite`.
|
|
||||
* ... |
|
||||
* // Then resume parsing.
|
|
||||
* resume(); |
|
||||
* }); |
|
||||
* }); |
|
||||
* |
|
||||
* parser.end('<script src="example.com/script.js"></script>'); |
|
||||
*/ |
|
||||
|
|
||||
|
|
||||
this.emit('script', scriptElement, this._documentWrite, this._resume); |
|
||||
} |
|
||||
else |
|
||||
this._runParsingLoop(); |
|
||||
}; |
|
||||
|
|
@ -1,14 +0,0 @@ |
|||||
'use strict'; |
|
||||
|
|
||||
var WritableStream = require('stream').Writable, |
|
||||
util = require('util'); |
|
||||
|
|
||||
var DevNullStream = module.exports = function () { |
|
||||
WritableStream.call(this); |
|
||||
}; |
|
||||
|
|
||||
util.inherits(DevNullStream, WritableStream); |
|
||||
|
|
||||
DevNullStream.prototype._write = function (chunk, encoding, cb) { |
|
||||
cb(); |
|
||||
}; |
|
@ -1,230 +0,0 @@ |
|||||
'use strict'; |
|
||||
|
|
||||
var TransformStream = require('stream').Transform, |
|
||||
DevNullStream = require('./dev_null_stream'), |
|
||||
inherits = require('util').inherits, |
|
||||
Tokenizer = require('../tokenizer'), |
|
||||
ParserFeedbackSimulator = require('./parser_feedback_simulator'), |
|
||||
mergeOptions = require('../common/merge_options'); |
|
||||
|
|
||||
/** |
|
||||
* @typedef {Object} SAXParserOptions |
|
||||
* |
|
||||
* @property {Boolean} [locationInfo=false] - Enables source code location information for the tokens. |
|
||||
* When enabled, each token event handler will receive {@link LocationInfo} (or {@link StartTagLocationInfo}) |
|
||||
* object as its last argument. |
|
||||
*/ |
|
||||
var DEFAULT_OPTIONS = { |
|
||||
locationInfo: false |
|
||||
}; |
|
||||
|
|
||||
/** |
|
||||
* Streaming [SAX]{@link https://en.wikipedia.org/wiki/Simple_API_for_XML}-style HTML parser.
|
|
||||
* A [transform stream](https://nodejs.org/api/stream.html#stream_class_stream_transform)
|
|
||||
* (which means you can pipe *through* it, see example). |
|
||||
* @class SAXParser |
|
||||
* @memberof parse5 |
|
||||
* @instance |
|
||||
* @extends stream.Transform |
|
||||
* @param {SAXParserOptions} options - Parsing options. |
|
||||
* @example |
|
||||
* var parse5 = require('parse5'); |
|
||||
* var http = require('http'); |
|
||||
* var fs = require('fs'); |
|
||||
* |
|
||||
* var file = fs.createWriteStream('/home/google.com.html'); |
|
||||
* var parser = new parse5.SAXParser(); |
|
||||
* |
|
||||
* parser.on('text', function(text) { |
|
||||
* // Handle page text content
|
|
||||
* ... |
|
||||
* }); |
|
||||
* |
|
||||
* http.get('http://google.com', function(res) { |
|
||||
* // SAXParser is the Transform stream, which means you can pipe
|
|
||||
* // through it. So, you can analyze page content and, e.g., save it
|
|
||||
* // to the file at the same time:
|
|
||||
* res.pipe(parser).pipe(file); |
|
||||
* }); |
|
||||
*/ |
|
||||
var SAXParser = module.exports = function (options) { |
|
||||
TransformStream.call(this); |
|
||||
|
|
||||
this.options = mergeOptions(DEFAULT_OPTIONS, options); |
|
||||
|
|
||||
this.tokenizer = new Tokenizer(options); |
|
||||
this.parserFeedbackSimulator = new ParserFeedbackSimulator(this.tokenizer); |
|
||||
|
|
||||
this.pendingText = null; |
|
||||
this.currentTokenLocation = void 0; |
|
||||
|
|
||||
this.lastChunkWritten = false; |
|
||||
this.stopped = false; |
|
||||
|
|
||||
// NOTE: always pipe stream to the /dev/null stream to avoid
|
|
||||
// `highWaterMark` hit even if we don't have consumers.
|
|
||||
// (see: https://github.com/inikulin/parse5/issues/97#issuecomment-171940774)
|
|
||||
this.pipe(new DevNullStream()); |
|
||||
}; |
|
||||
|
|
||||
inherits(SAXParser, TransformStream); |
|
||||
|
|
||||
//TransformStream implementation
|
|
||||
SAXParser.prototype._transform = function (chunk, encoding, callback) { |
|
||||
if (!this.stopped) { |
|
||||
this.tokenizer.write(chunk.toString('utf8'), this.lastChunkWritten); |
|
||||
this._runParsingLoop(); |
|
||||
} |
|
||||
|
|
||||
this.push(chunk); |
|
||||
|
|
||||
callback(); |
|
||||
}; |
|
||||
|
|
||||
SAXParser.prototype._flush = function (callback) { |
|
||||
callback(); |
|
||||
}; |
|
||||
|
|
||||
SAXParser.prototype.end = function (chunk, encoding, callback) { |
|
||||
this.lastChunkWritten = true; |
|
||||
TransformStream.prototype.end.call(this, chunk, encoding, callback); |
|
||||
}; |
|
||||
|
|
||||
/** |
|
||||
* Stops parsing. Useful if you want the parser to stop consuming CPU time once you've obtained the desired info |
|
||||
* from the input stream. Doesn't prevent piping, so that data will flow through the parser as usual. |
|
||||
* |
|
||||
* @function stop |
|
||||
* @memberof parse5#SAXParser |
|
||||
* @instance |
|
||||
* @example |
|
||||
* var parse5 = require('parse5'); |
|
||||
* var http = require('http'); |
|
||||
* var fs = require('fs'); |
|
||||
* |
|
||||
* var file = fs.createWriteStream('/home/google.com.html'); |
|
||||
* var parser = new parse5.SAXParser(); |
|
||||
* |
|
||||
* parser.on('doctype', function(name, publicId, systemId) { |
|
||||
* // Process doctype info ans stop parsing
|
|
||||
* ... |
|
||||
* parser.stop(); |
|
||||
* }); |
|
||||
* |
|
||||
* http.get('http://google.com', function(res) { |
|
||||
* // Despite the fact that parser.stop() was called whole
|
|
||||
* // content of the page will be written to the file
|
|
||||
* res.pipe(parser).pipe(file); |
|
||||
* }); |
|
||||
*/ |
|
||||
SAXParser.prototype.stop = function () { |
|
||||
this.stopped = true; |
|
||||
}; |
|
||||
|
|
||||
//Internals
|
|
||||
SAXParser.prototype._runParsingLoop = function () { |
|
||||
do { |
|
||||
var token = this.parserFeedbackSimulator.getNextToken(); |
|
||||
|
|
||||
if (token.type === Tokenizer.HIBERNATION_TOKEN) |
|
||||
break; |
|
||||
|
|
||||
if (token.type === Tokenizer.CHARACTER_TOKEN || |
|
||||
token.type === Tokenizer.WHITESPACE_CHARACTER_TOKEN || |
|
||||
token.type === Tokenizer.NULL_CHARACTER_TOKEN) { |
|
||||
|
|
||||
if (this.options.locationInfo) { |
|
||||
if (this.pendingText === null) |
|
||||
this.currentTokenLocation = token.location; |
|
||||
|
|
||||
else |
|
||||
this.currentTokenLocation.endOffset = token.location.endOffset; |
|
||||
} |
|
||||
|
|
||||
this.pendingText = (this.pendingText || '') + token.chars; |
|
||||
} |
|
||||
|
|
||||
else { |
|
||||
this._emitPendingText(); |
|
||||
this._handleToken(token); |
|
||||
} |
|
||||
} while (!this.stopped && token.type !== Tokenizer.EOF_TOKEN); |
|
||||
}; |
|
||||
|
|
||||
SAXParser.prototype._handleToken = function (token) { |
|
||||
if (this.options.locationInfo) |
|
||||
this.currentTokenLocation = token.location; |
|
||||
|
|
||||
if (token.type === Tokenizer.START_TAG_TOKEN) |
|
||||
/** |
|
||||
* Raised when the parser encounters a start tag. |
|
||||
* @event startTag |
|
||||
* @memberof parse5#SAXParser |
|
||||
* @instance |
|
||||
* @type {Function} |
|
||||
* @param {String} name - Tag name. |
|
||||
* @param {Array} attrs - List of attributes in the `{ name: String, value: String, prefix?: String }` form. |
|
||||
* @param {Boolean} selfClosing - Indicates if the tag is self-closing. |
|
||||
* @param {StartTagLocationInfo} [location] - Start tag source code location info. |
|
||||
* Available if location info is enabled in {@link SAXParserOptions}. |
|
||||
*/ |
|
||||
this.emit('startTag', token.tagName, token.attrs, token.selfClosing, this.currentTokenLocation); |
|
||||
|
|
||||
else if (token.type === Tokenizer.END_TAG_TOKEN) |
|
||||
/** |
|
||||
* Raised then parser encounters an end tag. |
|
||||
* @event endTag |
|
||||
* @memberof parse5#SAXParser |
|
||||
* @instance |
|
||||
* @type {Function} |
|
||||
* @param {String} name - Tag name. |
|
||||
* @param {LocationInfo} [location] - End tag source code location info. |
|
||||
* Available if location info is enabled in {@link SAXParserOptions}. |
|
||||
*/ |
|
||||
this.emit('endTag', token.tagName, this.currentTokenLocation); |
|
||||
|
|
||||
else if (token.type === Tokenizer.COMMENT_TOKEN) |
|
||||
/** |
|
||||
* Raised then parser encounters a comment. |
|
||||
* @event comment |
|
||||
* @memberof parse5#SAXParser |
|
||||
* @instance |
|
||||
* @type {Function} |
|
||||
* @param {String} text - Comment text. |
|
||||
* @param {LocationInfo} [location] - Comment source code location info. |
|
||||
* Available if location info is enabled in {@link SAXParserOptions}. |
|
||||
*/ |
|
||||
this.emit('comment', token.data, this.currentTokenLocation); |
|
||||
|
|
||||
else if (token.type === Tokenizer.DOCTYPE_TOKEN) |
|
||||
/** |
|
||||
* Raised then parser encounters a [document type declaration]{@link https://en.wikipedia.org/wiki/Document_type_declaration}.
|
|
||||
* @event doctype |
|
||||
* @memberof parse5#SAXParser |
|
||||
* @instance |
|
||||
* @type {Function} |
|
||||
* @param {String} name - Document type name. |
|
||||
* @param {String} publicId - Document type public identifier. |
|
||||
* @param {String} systemId - Document type system identifier. |
|
||||
* @param {LocationInfo} [location] - Document type declaration source code location info. |
|
||||
* Available if location info is enabled in {@link SAXParserOptions}. |
|
||||
*/ |
|
||||
this.emit('doctype', token.name, token.publicId, token.systemId, this.currentTokenLocation); |
|
||||
}; |
|
||||
|
|
||||
SAXParser.prototype._emitPendingText = function () { |
|
||||
if (this.pendingText !== null) { |
|
||||
/** |
|
||||
* Raised then parser encounters text content. |
|
||||
* @event text |
|
||||
* @memberof parse5#SAXParser |
|
||||
* @instance |
|
||||
* @type {Function} |
|
||||
* @param {String} text - Text content. |
|
||||
* @param {LocationInfo} [location] - Text content code location info. |
|
||||
* Available if location info is enabled in {@link SAXParserOptions}. |
|
||||
*/ |
|
||||
this.emit('text', this.pendingText, this.currentTokenLocation); |
|
||||
this.pendingText = null; |
|
||||
} |
|
||||
}; |
|
@ -1,153 +0,0 @@ |
|||||
'use strict'; |
|
||||
|
|
||||
var Tokenizer = require('../tokenizer'), |
|
||||
foreignContent = require('../common/foreign_content'), |
|
||||
UNICODE = require('../common/unicode'), |
|
||||
HTML = require('../common/html'); |
|
||||
|
|
||||
|
|
||||
//Aliases
|
|
||||
var $ = HTML.TAG_NAMES, |
|
||||
NS = HTML.NAMESPACES; |
|
||||
|
|
||||
|
|
||||
//ParserFeedbackSimulator
|
|
||||
//Simulates adjustment of the Tokenizer which performed by standard parser during tree construction.
|
|
||||
var ParserFeedbackSimulator = module.exports = function (tokenizer) { |
|
||||
this.tokenizer = tokenizer; |
|
||||
|
|
||||
this.namespaceStack = []; |
|
||||
this.namespaceStackTop = -1; |
|
||||
this._enterNamespace(NS.HTML); |
|
||||
}; |
|
||||
|
|
||||
ParserFeedbackSimulator.prototype.getNextToken = function () { |
|
||||
var token = this.tokenizer.getNextToken(); |
|
||||
|
|
||||
if (token.type === Tokenizer.START_TAG_TOKEN) |
|
||||
this._handleStartTagToken(token); |
|
||||
|
|
||||
else if (token.type === Tokenizer.END_TAG_TOKEN) |
|
||||
this._handleEndTagToken(token); |
|
||||
|
|
||||
else if (token.type === Tokenizer.NULL_CHARACTER_TOKEN && this.inForeignContent) { |
|
||||
token.type = Tokenizer.CHARACTER_TOKEN; |
|
||||
token.chars = UNICODE.REPLACEMENT_CHARACTER; |
|
||||
} |
|
||||
|
|
||||
else if (this.skipNextNewLine) { |
|
||||
if (token.type !== Tokenizer.HIBERNATION_TOKEN) |
|
||||
this.skipNextNewLine = false; |
|
||||
|
|
||||
if (token.type === Tokenizer.WHITESPACE_CHARACTER_TOKEN && token.chars[0] === '\n') { |
|
||||
if (token.chars.length === 1) |
|
||||
return this.getNextToken(); |
|
||||
|
|
||||
token.chars = token.chars.substr(1); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
return token; |
|
||||
}; |
|
||||
|
|
||||
//Namespace stack mutations
|
|
||||
ParserFeedbackSimulator.prototype._enterNamespace = function (namespace) { |
|
||||
this.namespaceStackTop++; |
|
||||
this.namespaceStack.push(namespace); |
|
||||
|
|
||||
this.inForeignContent = namespace !== NS.HTML; |
|
||||
this.currentNamespace = namespace; |
|
||||
this.tokenizer.allowCDATA = this.inForeignContent; |
|
||||
}; |
|
||||
|
|
||||
ParserFeedbackSimulator.prototype._leaveCurrentNamespace = function () { |
|
||||
this.namespaceStackTop--; |
|
||||
this.namespaceStack.pop(); |
|
||||
|
|
||||
this.currentNamespace = this.namespaceStack[this.namespaceStackTop]; |
|
||||
this.inForeignContent = this.currentNamespace !== NS.HTML; |
|
||||
this.tokenizer.allowCDATA = this.inForeignContent; |
|
||||
}; |
|
||||
|
|
||||
//Token handlers
|
|
||||
ParserFeedbackSimulator.prototype._ensureTokenizerMode = function (tn) { |
|
||||
if (tn === $.TEXTAREA || tn === $.TITLE) |
|
||||
this.tokenizer.state = Tokenizer.MODE.RCDATA; |
|
||||
|
|
||||
else if (tn === $.PLAINTEXT) |
|
||||
this.tokenizer.state = Tokenizer.MODE.PLAINTEXT; |
|
||||
|
|
||||
else if (tn === $.SCRIPT) |
|
||||
this.tokenizer.state = Tokenizer.MODE.SCRIPT_DATA; |
|
||||
|
|
||||
else if (tn === $.STYLE || tn === $.IFRAME || tn === $.XMP || |
|
||||
tn === $.NOEMBED || tn === $.NOFRAMES || tn === $.NOSCRIPT) |
|
||||
this.tokenizer.state = Tokenizer.MODE.RAWTEXT; |
|
||||
}; |
|
||||
|
|
||||
ParserFeedbackSimulator.prototype._handleStartTagToken = function (token) { |
|
||||
var tn = token.tagName; |
|
||||
|
|
||||
if (tn === $.SVG) |
|
||||
this._enterNamespace(NS.SVG); |
|
||||
|
|
||||
else if (tn === $.MATH) |
|
||||
this._enterNamespace(NS.MATHML); |
|
||||
|
|
||||
if (this.inForeignContent) { |
|
||||
if (foreignContent.causesExit(token)) { |
|
||||
this._leaveCurrentNamespace(); |
|
||||
return; |
|
||||
} |
|
||||
|
|
||||
var currentNs = this.currentNamespace; |
|
||||
|
|
||||
if (currentNs === NS.MATHML) |
|
||||
foreignContent.adjustTokenMathMLAttrs(token); |
|
||||
|
|
||||
else if (currentNs === NS.SVG) { |
|
||||
foreignContent.adjustTokenSVGTagName(token); |
|
||||
foreignContent.adjustTokenSVGAttrs(token); |
|
||||
} |
|
||||
|
|
||||
foreignContent.adjustTokenXMLAttrs(token); |
|
||||
|
|
||||
tn = token.tagName; |
|
||||
|
|
||||
if (!token.selfClosing && foreignContent.isIntegrationPoint(tn, currentNs, token.attrs)) |
|
||||
this._enterNamespace(NS.HTML); |
|
||||
} |
|
||||
|
|
||||
else { |
|
||||
if (tn === $.PRE || tn === $.TEXTAREA || tn === $.LISTING) |
|
||||
this.skipNextNewLine = true; |
|
||||
|
|
||||
else if (tn === $.IMAGE) |
|
||||
token.tagName = $.IMG; |
|
||||
|
|
||||
this._ensureTokenizerMode(tn); |
|
||||
} |
|
||||
}; |
|
||||
|
|
||||
ParserFeedbackSimulator.prototype._handleEndTagToken = function (token) { |
|
||||
var tn = token.tagName; |
|
||||
|
|
||||
if (!this.inForeignContent) { |
|
||||
var previousNs = this.namespaceStack[this.namespaceStackTop - 1]; |
|
||||
|
|
||||
if (previousNs === NS.SVG && foreignContent.SVG_TAG_NAMES_ADJUSTMENT_MAP[tn]) |
|
||||
tn = foreignContent.SVG_TAG_NAMES_ADJUSTMENT_MAP[tn]; |
|
||||
|
|
||||
//NOTE: check for exit from integration point
|
|
||||
if (foreignContent.isIntegrationPoint(tn, previousNs, token.attrs)) |
|
||||
this._leaveCurrentNamespace(); |
|
||||
} |
|
||||
|
|
||||
else if (tn === $.SVG && this.currentNamespace === NS.SVG || |
|
||||
tn === $.MATH && this.currentNamespace === NS.MATHML) |
|
||||
this._leaveCurrentNamespace(); |
|
||||
|
|
||||
// NOTE: adjust end tag name as well for consistency
|
|
||||
if (this.currentNamespace === NS.SVG) |
|
||||
foreignContent.adjustTokenSVGTagName(token); |
|
||||
}; |
|
@ -1,180 +0,0 @@ |
|||||
'use strict'; |
|
||||
|
|
||||
var defaultTreeAdapter = require('../tree_adapters/default'), |
|
||||
doctype = require('../common/doctype'), |
|
||||
mergeOptions = require('../common/merge_options'), |
|
||||
HTML = require('../common/html'); |
|
||||
|
|
||||
//Aliases
|
|
||||
var $ = HTML.TAG_NAMES, |
|
||||
NS = HTML.NAMESPACES; |
|
||||
|
|
||||
//Default serializer options
|
|
||||
/** |
|
||||
* @typedef {Object} SerializerOptions |
|
||||
* |
|
||||
* @property {TreeAdapter} [treeAdapter=parse5.treeAdapters.default] - Specifies input tree format. |
|
||||
*/ |
|
||||
var DEFAULT_OPTIONS = { |
|
||||
treeAdapter: defaultTreeAdapter |
|
||||
}; |
|
||||
|
|
||||
//Escaping regexes
|
|
||||
var AMP_REGEX = /&/g, |
|
||||
NBSP_REGEX = /\u00a0/g, |
|
||||
DOUBLE_QUOTE_REGEX = /"/g, |
|
||||
LT_REGEX = /</g, |
|
||||
GT_REGEX = />/g; |
|
||||
|
|
||||
//Serializer
|
|
||||
var Serializer = module.exports = function (node, options) { |
|
||||
this.options = mergeOptions(DEFAULT_OPTIONS, options); |
|
||||
this.treeAdapter = this.options.treeAdapter; |
|
||||
|
|
||||
this.html = ''; |
|
||||
this.startNode = node; |
|
||||
}; |
|
||||
|
|
||||
// NOTE: exported as static method for the testing purposes
|
|
||||
Serializer.escapeString = function (str, attrMode) { |
|
||||
str = str |
|
||||
.replace(AMP_REGEX, '&') |
|
||||
.replace(NBSP_REGEX, ' '); |
|
||||
|
|
||||
if (attrMode) |
|
||||
str = str.replace(DOUBLE_QUOTE_REGEX, '"'); |
|
||||
|
|
||||
else { |
|
||||
str = str |
|
||||
.replace(LT_REGEX, '<') |
|
||||
.replace(GT_REGEX, '>'); |
|
||||
} |
|
||||
|
|
||||
return str; |
|
||||
}; |
|
||||
|
|
||||
|
|
||||
//API
|
|
||||
Serializer.prototype.serialize = function () { |
|
||||
this._serializeChildNodes(this.startNode); |
|
||||
|
|
||||
return this.html; |
|
||||
}; |
|
||||
|
|
||||
|
|
||||
//Internals
|
|
||||
Serializer.prototype._serializeChildNodes = function (parentNode) { |
|
||||
var childNodes = this.treeAdapter.getChildNodes(parentNode); |
|
||||
|
|
||||
if (childNodes) { |
|
||||
for (var i = 0, cnLength = childNodes.length; i < cnLength; i++) { |
|
||||
var currentNode = childNodes[i]; |
|
||||
|
|
||||
if (this.treeAdapter.isElementNode(currentNode)) |
|
||||
this._serializeElement(currentNode); |
|
||||
|
|
||||
else if (this.treeAdapter.isTextNode(currentNode)) |
|
||||
this._serializeTextNode(currentNode); |
|
||||
|
|
||||
else if (this.treeAdapter.isCommentNode(currentNode)) |
|
||||
this._serializeCommentNode(currentNode); |
|
||||
|
|
||||
else if (this.treeAdapter.isDocumentTypeNode(currentNode)) |
|
||||
this._serializeDocumentTypeNode(currentNode); |
|
||||
} |
|
||||
} |
|
||||
}; |
|
||||
|
|
||||
Serializer.prototype._serializeElement = function (node) { |
|
||||
var tn = this.treeAdapter.getTagName(node), |
|
||||
ns = this.treeAdapter.getNamespaceURI(node); |
|
||||
|
|
||||
this.html += '<' + tn; |
|
||||
this._serializeAttributes(node); |
|
||||
this.html += '>'; |
|
||||
|
|
||||
if (tn !== $.AREA && tn !== $.BASE && tn !== $.BASEFONT && tn !== $.BGSOUND && tn !== $.BR && tn !== $.BR && |
|
||||
tn !== $.COL && tn !== $.EMBED && tn !== $.FRAME && tn !== $.HR && tn !== $.IMG && tn !== $.INPUT && |
|
||||
tn !== $.KEYGEN && tn !== $.LINK && tn !== $.MENUITEM && tn !== $.META && tn !== $.PARAM && tn !== $.SOURCE && |
|
||||
tn !== $.TRACK && tn !== $.WBR) { |
|
||||
|
|
||||
if (tn === $.PRE || tn === $.TEXTAREA || tn === $.LISTING) { |
|
||||
var firstChild = this.treeAdapter.getFirstChild(node); |
|
||||
|
|
||||
if (firstChild && this.treeAdapter.isTextNode(firstChild)) { |
|
||||
var content = this.treeAdapter.getTextNodeContent(firstChild); |
|
||||
|
|
||||
if (content[0] === '\n') |
|
||||
this.html += '\n'; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
var childNodesHolder = tn === $.TEMPLATE && ns === NS.HTML ? |
|
||||
this.treeAdapter.getTemplateContent(node) : |
|
||||
node; |
|
||||
|
|
||||
this._serializeChildNodes(childNodesHolder); |
|
||||
this.html += '</' + tn + '>'; |
|
||||
} |
|
||||
}; |
|
||||
|
|
||||
Serializer.prototype._serializeAttributes = function (node) { |
|
||||
var attrs = this.treeAdapter.getAttrList(node); |
|
||||
|
|
||||
for (var i = 0, attrsLength = attrs.length; i < attrsLength; i++) { |
|
||||
var attr = attrs[i], |
|
||||
value = Serializer.escapeString(attr.value, true); |
|
||||
|
|
||||
this.html += ' '; |
|
||||
|
|
||||
if (!attr.namespace) |
|
||||
this.html += attr.name; |
|
||||
|
|
||||
else if (attr.namespace === NS.XML) |
|
||||
this.html += 'xml:' + attr.name; |
|
||||
|
|
||||
else if (attr.namespace === NS.XMLNS) { |
|
||||
if (attr.name !== 'xmlns') |
|
||||
this.html += 'xmlns:'; |
|
||||
|
|
||||
this.html += attr.name; |
|
||||
} |
|
||||
|
|
||||
else if (attr.namespace === NS.XLINK) |
|
||||
this.html += 'xlink:' + attr.name; |
|
||||
|
|
||||
else |
|
||||
this.html += attr.namespace + ':' + attr.name; |
|
||||
|
|
||||
this.html += '="' + value + '"'; |
|
||||
} |
|
||||
}; |
|
||||
|
|
||||
Serializer.prototype._serializeTextNode = function (node) { |
|
||||
var content = this.treeAdapter.getTextNodeContent(node), |
|
||||
parent = this.treeAdapter.getParentNode(node), |
|
||||
parentTn = void 0; |
|
||||
|
|
||||
if (parent && this.treeAdapter.isElementNode(parent)) |
|
||||
parentTn = this.treeAdapter.getTagName(parent); |
|
||||
|
|
||||
if (parentTn === $.STYLE || parentTn === $.SCRIPT || parentTn === $.XMP || parentTn === $.IFRAME || |
|
||||
parentTn === $.NOEMBED || parentTn === $.NOFRAMES || parentTn === $.PLAINTEXT || parentTn === $.NOSCRIPT) |
|
||||
|
|
||||
this.html += content; |
|
||||
|
|
||||
else |
|
||||
this.html += Serializer.escapeString(content, false); |
|
||||
}; |
|
||||
|
|
||||
Serializer.prototype._serializeCommentNode = function (node) { |
|
||||
this.html += '<!--' + this.treeAdapter.getCommentNodeContent(node) + '-->'; |
|
||||
}; |
|
||||
|
|
||||
Serializer.prototype._serializeDocumentTypeNode = function (node) { |
|
||||
var name = this.treeAdapter.getDocumentTypeNodeName(node), |
|
||||
publicId = this.treeAdapter.getDocumentTypeNodePublicId(node), |
|
||||
systemId = this.treeAdapter.getDocumentTypeNodeSystemId(node); |
|
||||
|
|
||||
this.html += '<' + doctype.serializeContent(name, publicId, systemId) + '>'; |
|
||||
}; |
|
@ -1,49 +0,0 @@ |
|||||
'use strict'; |
|
||||
|
|
||||
var ReadableStream = require('stream').Readable, |
|
||||
inherits = require('util').inherits, |
|
||||
Serializer = require('./index'); |
|
||||
|
|
||||
/** |
|
||||
* Streaming AST node to an HTML serializer. |
|
||||
* A [readable stream]{@link https://nodejs.org/api/stream.html#stream_class_stream_readable}.
|
|
||||
* @class SerializerStream |
|
||||
* @memberof parse5 |
|
||||
* @instance |
|
||||
* @extends stream.Readable |
|
||||
* @param {ASTNode} node - Node to serialize. |
|
||||
* @param {SerializerOptions} [options] - Serialization options. |
|
||||
* @example |
|
||||
* var parse5 = require('parse5'); |
|
||||
* var fs = require('fs'); |
|
||||
* |
|
||||
* var file = fs.createWriteStream('/home/index.html'); |
|
||||
* |
|
||||
* // Serializes the parsed document to HTML and writes it to the file.
|
|
||||
* var document = parse5.parse('<body>Who is John Galt?</body>'); |
|
||||
* var serializer = new parse5.SerializerStream(document); |
|
||||
* |
|
||||
* serializer.pipe(file); |
|
||||
*/ |
|
||||
var SerializerStream = module.exports = function (node, options) { |
|
||||
ReadableStream.call(this); |
|
||||
|
|
||||
this.serializer = new Serializer(node, options); |
|
||||
|
|
||||
Object.defineProperty(this.serializer, 'html', { |
|
||||
//NOTE: To make `+=` concat operator work properly we define
|
|
||||
//getter which always returns empty string
|
|
||||
get: function () { |
|
||||
return ''; |
|
||||
}, |
|
||||
set: this.push.bind(this) |
|
||||
}); |
|
||||
}; |
|
||||
|
|
||||
inherits(SerializerStream, ReadableStream); |
|
||||
|
|
||||
//Readable stream implementation
|
|
||||
SerializerStream.prototype._read = function () { |
|
||||
this.serializer.serialize(); |
|
||||
this.push(null); |
|
||||
}; |
|
File diff suppressed because it is too large
File diff suppressed because one or more lines are too long
@ -1,155 +0,0 @@ |
|||||
'use strict'; |
|
||||
|
|
||||
var UNICODE = require('../common/unicode'); |
|
||||
|
|
||||
//Aliases
|
|
||||
var $ = UNICODE.CODE_POINTS; |
|
||||
|
|
||||
//Utils
|
|
||||
|
|
||||
//OPTIMIZATION: these utility functions should not be moved out of this module. V8 Crankshaft will not inline
|
|
||||
//this functions if they will be situated in another module due to context switch.
|
|
||||
//Always perform inlining check before modifying this functions ('node --trace-inlining').
|
|
||||
function isSurrogatePair(cp1, cp2) { |
|
||||
return cp1 >= 0xD800 && cp1 <= 0xDBFF && cp2 >= 0xDC00 && cp2 <= 0xDFFF; |
|
||||
} |
|
||||
|
|
||||
function getSurrogatePairCodePoint(cp1, cp2) { |
|
||||
return (cp1 - 0xD800) * 0x400 + 0x2400 + cp2; |
|
||||
} |
|
||||
|
|
||||
|
|
||||
//Const
|
|
||||
var DEFAULT_BUFFER_WATERLINE = 1 << 16; |
|
||||
|
|
||||
|
|
||||
//Preprocessor
|
|
||||
//NOTE: HTML input preprocessing
|
|
||||
//(see: http://www.whatwg.org/specs/web-apps/current-work/multipage/parsing.html#preprocessing-the-input-stream)
|
|
||||
var Preprocessor = module.exports = function () { |
|
||||
this.html = null; |
|
||||
|
|
||||
this.pos = -1; |
|
||||
this.lastGapPos = -1; |
|
||||
this.lastCharPos = -1; |
|
||||
this.droppedBufferSize = 0; |
|
||||
|
|
||||
this.gapStack = []; |
|
||||
|
|
||||
this.skipNextNewLine = false; |
|
||||
|
|
||||
this.lastChunkWritten = false; |
|
||||
this.endOfChunkHit = false; |
|
||||
this.bufferWaterline = DEFAULT_BUFFER_WATERLINE; |
|
||||
}; |
|
||||
|
|
||||
Object.defineProperty(Preprocessor.prototype, 'sourcePos', { |
|
||||
get: function () { |
|
||||
return this.droppedBufferSize + this.pos; |
|
||||
} |
|
||||
}); |
|
||||
|
|
||||
Preprocessor.prototype.dropParsedChunk = function () { |
|
||||
if (this.pos > this.bufferWaterline) { |
|
||||
this.lastCharPos -= this.pos; |
|
||||
this.droppedBufferSize += this.pos; |
|
||||
this.html = this.html.substring(this.pos); |
|
||||
this.pos = 0; |
|
||||
this.lastGapPos = -1; |
|
||||
this.gapStack = []; |
|
||||
} |
|
||||
}; |
|
||||
|
|
||||
Preprocessor.prototype._addGap = function () { |
|
||||
this.gapStack.push(this.lastGapPos); |
|
||||
this.lastGapPos = this.pos; |
|
||||
}; |
|
||||
|
|
||||
Preprocessor.prototype._processHighRangeCodePoint = function (cp) { |
|
||||
//NOTE: try to peek a surrogate pair
|
|
||||
if (this.pos !== this.lastCharPos) { |
|
||||
var nextCp = this.html.charCodeAt(this.pos + 1); |
|
||||
|
|
||||
if (isSurrogatePair(cp, nextCp)) { |
|
||||
//NOTE: we have a surrogate pair. Peek pair character and recalculate code point.
|
|
||||
this.pos++; |
|
||||
cp = getSurrogatePairCodePoint(cp, nextCp); |
|
||||
|
|
||||
//NOTE: add gap that should be avoided during retreat
|
|
||||
this._addGap(); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
// NOTE: we've hit the end of chunk, stop processing at this point
|
|
||||
else if (!this.lastChunkWritten) { |
|
||||
this.endOfChunkHit = true; |
|
||||
return $.EOF; |
|
||||
} |
|
||||
|
|
||||
return cp; |
|
||||
}; |
|
||||
|
|
||||
Preprocessor.prototype.write = function (chunk, isLastChunk) { |
|
||||
if (this.html) |
|
||||
this.html += chunk; |
|
||||
|
|
||||
else |
|
||||
this.html = chunk; |
|
||||
|
|
||||
this.lastCharPos = this.html.length - 1; |
|
||||
this.endOfChunkHit = false; |
|
||||
this.lastChunkWritten = isLastChunk; |
|
||||
}; |
|
||||
|
|
||||
Preprocessor.prototype.insertHtmlAtCurrentPos = function (chunk) { |
|
||||
this.html = this.html.substring(0, this.pos + 1) + |
|
||||
chunk + |
|
||||
this.html.substring(this.pos + 1, this.html.length); |
|
||||
|
|
||||
this.lastCharPos = this.html.length - 1; |
|
||||
this.endOfChunkHit = false; |
|
||||
}; |
|
||||
|
|
||||
|
|
||||
Preprocessor.prototype.advance = function () { |
|
||||
this.pos++; |
|
||||
|
|
||||
if (this.pos > this.lastCharPos) { |
|
||||
if (!this.lastChunkWritten) |
|
||||
this.endOfChunkHit = true; |
|
||||
|
|
||||
return $.EOF; |
|
||||
} |
|
||||
|
|
||||
var cp = this.html.charCodeAt(this.pos); |
|
||||
|
|
||||
//NOTE: any U+000A LINE FEED (LF) characters that immediately follow a U+000D CARRIAGE RETURN (CR) character
|
|
||||
//must be ignored.
|
|
||||
if (this.skipNextNewLine && cp === $.LINE_FEED) { |
|
||||
this.skipNextNewLine = false; |
|
||||
this._addGap(); |
|
||||
return this.advance(); |
|
||||
} |
|
||||
|
|
||||
//NOTE: all U+000D CARRIAGE RETURN (CR) characters must be converted to U+000A LINE FEED (LF) characters
|
|
||||
if (cp === $.CARRIAGE_RETURN) { |
|
||||
this.skipNextNewLine = true; |
|
||||
return $.LINE_FEED; |
|
||||
} |
|
||||
|
|
||||
this.skipNextNewLine = false; |
|
||||
|
|
||||
//OPTIMIZATION: first perform check if the code point in the allowed range that covers most common
|
|
||||
//HTML input (e.g. ASCII codes) to avoid performance-cost operations for high-range code points.
|
|
||||
return cp >= 0xD800 ? this._processHighRangeCodePoint(cp) : cp; |
|
||||
}; |
|
||||
|
|
||||
Preprocessor.prototype.retreat = function () { |
|
||||
if (this.pos === this.lastGapPos) { |
|
||||
this.lastGapPos = this.gapStack.pop(); |
|
||||
this.pos--; |
|
||||
} |
|
||||
|
|
||||
this.pos--; |
|
||||
}; |
|
||||
|
|
@ -1,578 +0,0 @@ |
|||||
'use strict'; |
|
||||
|
|
||||
/** |
|
||||
* @typedef {Object} TreeAdapter |
|
||||
*/ |
|
||||
|
|
||||
//Node construction
|
|
||||
|
|
||||
/** |
|
||||
* Creates a document node. |
|
||||
* |
|
||||
* @function createDocument |
|
||||
* @memberof TreeAdapter |
|
||||
* |
|
||||
* @returns {ASTNode<Document>} document |
|
||||
* |
|
||||
* @see {@link https://github.com/inikulin/parse5/blob/tree-adapter-docs-rev/lib/tree_adapters/default.js#L19|default implementation.}
|
|
||||
*/ |
|
||||
exports.createDocument = function () { |
|
||||
return { |
|
||||
nodeName: '#document', |
|
||||
quirksMode: false, |
|
||||
childNodes: [] |
|
||||
}; |
|
||||
}; |
|
||||
|
|
||||
/** |
|
||||
* Creates a document fragment node. |
|
||||
* |
|
||||
* @function createDocumentFragment |
|
||||
* @memberof TreeAdapter |
|
||||
* |
|
||||
* @returns {ASTNode<DocumentFragment>} fragment |
|
||||
* |
|
||||
* @see {@link https://github.com/inikulin/parse5/blob/tree-adapter-docs-rev/lib/tree_adapters/default.js#L37|default implementation.}
|
|
||||
*/ |
|
||||
exports.createDocumentFragment = function () { |
|
||||
return { |
|
||||
nodeName: '#document-fragment', |
|
||||
quirksMode: false, |
|
||||
childNodes: [] |
|
||||
}; |
|
||||
}; |
|
||||
|
|
||||
|
|
||||
/** |
|
||||
* Creates an element node. |
|
||||
* |
|
||||
* @function createElement |
|
||||
* @memberof TreeAdapter |
|
||||
* |
|
||||
* @param {String} tagName - Tag name of the element. |
|
||||
* @param {String} namespaceURI - Namespace of the element. |
|
||||
* @param {Array} attrs - Attribute name-value pair array. |
|
||||
* Foreign attributes may contain `namespace` and `prefix` fields as well. |
|
||||
* |
|
||||
* @returns {ASTNode<Element>} element |
|
||||
* |
|
||||
* @see {@link https://github.com/inikulin/parse5/blob/tree-adapter-docs-rev/lib/tree_adapters/default.js#L61|default implementation.}
|
|
||||
*/ |
|
||||
exports.createElement = function (tagName, namespaceURI, attrs) { |
|
||||
return { |
|
||||
nodeName: tagName, |
|
||||
tagName: tagName, |
|
||||
attrs: attrs, |
|
||||
namespaceURI: namespaceURI, |
|
||||
childNodes: [], |
|
||||
parentNode: null |
|
||||
}; |
|
||||
}; |
|
||||
|
|
||||
|
|
||||
/** |
|
||||
* Creates a comment node. |
|
||||
* |
|
||||
* @function createCommentNode |
|
||||
* @memberof TreeAdapter |
|
||||
* |
|
||||
* @param {String} data - Comment text. |
|
||||
* |
|
||||
* @returns {ASTNode<CommentNode>} comment |
|
||||
* |
|
||||
* @see {@link https://github.com/inikulin/parse5/blob/tree-adapter-docs-rev/lib/tree_adapters/default.js#L85|default implementation.}
|
|
||||
*/ |
|
||||
exports.createCommentNode = function (data) { |
|
||||
return { |
|
||||
nodeName: '#comment', |
|
||||
data: data, |
|
||||
parentNode: null |
|
||||
}; |
|
||||
}; |
|
||||
|
|
||||
var createTextNode = function (value) { |
|
||||
return { |
|
||||
nodeName: '#text', |
|
||||
value: value, |
|
||||
parentNode: null |
|
||||
}; |
|
||||
}; |
|
||||
|
|
||||
|
|
||||
//Tree mutation
|
|
||||
/** |
|
||||
* Appends a child node to the given parent node. |
|
||||
* |
|
||||
* @function appendChild |
|
||||
* @memberof TreeAdapter |
|
||||
* |
|
||||
* @param {ASTNode} parentNode - Parent node. |
|
||||
* @param {ASTNode} newNode - Child node. |
|
||||
* |
|
||||
* @see {@link https://github.com/inikulin/parse5/blob/tree-adapter-docs-rev/lib/tree_adapters/default.js#L114|default implementation.}
|
|
||||
*/ |
|
||||
var appendChild = exports.appendChild = function (parentNode, newNode) { |
|
||||
parentNode.childNodes.push(newNode); |
|
||||
newNode.parentNode = parentNode; |
|
||||
}; |
|
||||
|
|
||||
/** |
|
||||
* Inserts a child node to the given parent node before the given reference node. |
|
||||
* |
|
||||
* @function insertBefore |
|
||||
* @memberof TreeAdapter |
|
||||
* |
|
||||
* @param {ASTNode} parentNode - Parent node. |
|
||||
* @param {ASTNode} newNode - Child node. |
|
||||
* @param {ASTNode} referenceNode - Reference node. |
|
||||
* |
|
||||
* @see {@link https://github.com/inikulin/parse5/blob/tree-adapter-docs-rev/lib/tree_adapters/default.js#L131|default implementation.}
|
|
||||
*/ |
|
||||
var insertBefore = exports.insertBefore = function (parentNode, newNode, referenceNode) { |
|
||||
var insertionIdx = parentNode.childNodes.indexOf(referenceNode); |
|
||||
|
|
||||
parentNode.childNodes.splice(insertionIdx, 0, newNode); |
|
||||
newNode.parentNode = parentNode; |
|
||||
}; |
|
||||
|
|
||||
/** |
|
||||
* Sets the `<template>` element content element. |
|
||||
* |
|
||||
* @function setTemplateContent |
|
||||
* @memberof TreeAdapter |
|
||||
* |
|
||||
* @param {ASTNode<TemplateElement>} templateElement - `<template>` element. |
|
||||
* @param {ASTNode<DocumentFragment>} contentTemplate - Content element. |
|
||||
* |
|
||||
* @see {@link https://github.com/inikulin/parse5/blob/tree-adapter-docs-rev/lib/tree_adapters/default.js#L149|default implementation.}
|
|
||||
*/ |
|
||||
exports.setTemplateContent = function (templateElement, contentElement) { |
|
||||
templateElement.content = contentElement; |
|
||||
}; |
|
||||
|
|
||||
|
|
||||
/** |
|
||||
* Returns the `<template>` element content element. |
|
||||
* |
|
||||
* @function getTemplateContent |
|
||||
* @memberof TreeAdapter |
|
||||
* |
|
||||
* @param {ASTNode<TemplateElement>} templateElement - `<template>` element. |
|
||||
|
|
||||
* @returns {ASTNode<DocumentFragment>} |
|
||||
* |
|
||||
* @see {@link https://github.com/inikulin/parse5/blob/tree-adapter-docs-rev/lib/tree_adapters/default.js#L166|default implementation.}
|
|
||||
*/ |
|
||||
exports.getTemplateContent = function (templateElement) { |
|
||||
return templateElement.content; |
|
||||
}; |
|
||||
|
|
||||
/** |
|
||||
* Sets the document type. If the `document` already contains a document type node, the `name`, `publicId` and `systemId` |
|
||||
* properties of this node will be updated with the provided values. Otherwise, creates a new document type node |
|
||||
* with the given properties and inserts it into the `document`. |
|
||||
* |
|
||||
* @function setDocumentType |
|
||||
* @memberof TreeAdapter |
|
||||
* |
|
||||
* @param {ASTNode<Document>} document - Document node. |
|
||||
* @param {String} name - Document type name. |
|
||||
* @param {String} publicId - Document type public identifier. |
|
||||
* @param {String} systemId - Document type system identifier. |
|
||||
* |
|
||||
* @see {@link https://github.com/inikulin/parse5/blob/tree-adapter-docs-rev/lib/tree_adapters/default.js#L185|default implementation.}
|
|
||||
*/ |
|
||||
exports.setDocumentType = function (document, name, publicId, systemId) { |
|
||||
var doctypeNode = null; |
|
||||
|
|
||||
for (var i = 0; i < document.childNodes.length; i++) { |
|
||||
if (document.childNodes[i].nodeName === '#documentType') { |
|
||||
doctypeNode = document.childNodes[i]; |
|
||||
break; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
if (doctypeNode) { |
|
||||
doctypeNode.name = name; |
|
||||
doctypeNode.publicId = publicId; |
|
||||
doctypeNode.systemId = systemId; |
|
||||
} |
|
||||
|
|
||||
else { |
|
||||
appendChild(document, { |
|
||||
nodeName: '#documentType', |
|
||||
name: name, |
|
||||
publicId: publicId, |
|
||||
systemId: systemId |
|
||||
}); |
|
||||
} |
|
||||
}; |
|
||||
|
|
||||
/** |
|
||||
* Sets the document's quirks mode flag. |
|
||||
* |
|
||||
* @function setQuirksMode |
|
||||
* @memberof TreeAdapter |
|
||||
* |
|
||||
* @param {ASTNode<Document>} document - Document node. |
|
||||
* |
|
||||
* @see {@link https://github.com/inikulin/parse5/blob/tree-adapter-docs-rev/lib/tree_adapters/default.js#L221|default implementation.}
|
|
||||
*/ |
|
||||
exports.setQuirksMode = function (document) { |
|
||||
document.quirksMode = true; |
|
||||
}; |
|
||||
|
|
||||
/** |
|
||||
* Determines if the document's quirks mode flag is set. |
|
||||
* |
|
||||
* @function isQuirksMode |
|
||||
* @memberof TreeAdapter |
|
||||
* |
|
||||
* @param {ASTNode<Document>} document - Document node. |
|
||||
|
|
||||
* @returns {Boolean} |
|
||||
* |
|
||||
* @see {@link https://github.com/inikulin/parse5/blob/tree-adapter-docs-rev/lib/tree_adapters/default.js#L237|default implementation.}
|
|
||||
*/ |
|
||||
exports.isQuirksMode = function (document) { |
|
||||
return document.quirksMode; |
|
||||
}; |
|
||||
|
|
||||
/** |
|
||||
* Removes a node from its parent. |
|
||||
* |
|
||||
* @function detachNode |
|
||||
* @memberof TreeAdapter |
|
||||
* |
|
||||
* @param {ASTNode} node - Node. |
|
||||
|
|
||||
* @see {@link https://github.com/inikulin/parse5/blob/tree-adapter-docs-rev/lib/tree_adapters/default.js#L251|default implementation.}
|
|
||||
*/ |
|
||||
exports.detachNode = function (node) { |
|
||||
if (node.parentNode) { |
|
||||
var idx = node.parentNode.childNodes.indexOf(node); |
|
||||
|
|
||||
node.parentNode.childNodes.splice(idx, 1); |
|
||||
node.parentNode = null; |
|
||||
} |
|
||||
}; |
|
||||
|
|
||||
/** |
|
||||
* Inserts text into a node. If the last child of the node is a text node, the provided text will be appended to the |
|
||||
* text node content. Otherwise, inserts a new text node with the given text. |
|
||||
* |
|
||||
* |
|
||||
* @function insertText |
|
||||
* @memberof TreeAdapter |
|
||||
* |
|
||||
* @param {ASTNode} parentNode - Node to insert text into. |
|
||||
* @param {String} text - Text to insert. |
|
||||
|
|
||||
* @see {@link https://github.com/inikulin/parse5/blob/tree-adapter-docs-rev/lib/tree_adapters/default.js#L273|default implementation.}
|
|
||||
*/ |
|
||||
exports.insertText = function (parentNode, text) { |
|
||||
if (parentNode.childNodes.length) { |
|
||||
var prevNode = parentNode.childNodes[parentNode.childNodes.length - 1]; |
|
||||
|
|
||||
if (prevNode.nodeName === '#text') { |
|
||||
prevNode.value += text; |
|
||||
return; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
appendChild(parentNode, createTextNode(text)); |
|
||||
}; |
|
||||
|
|
||||
/** |
|
||||
* Inserts text into a sibling node that goes before the reference node. If this sibling node is the text node, |
|
||||
* the provided text will be appended to the text node content. Otherwise, inserts a new sibling text node with |
|
||||
* the given text before the reference node. |
|
||||
* |
|
||||
* |
|
||||
* @function insertTextBefore |
|
||||
* @memberof TreeAdapter |
|
||||
* |
|
||||
* @param {ASTNode} parentNode - Node to insert text into. |
|
||||
* @param {String} text - Text to insert. |
|
||||
* @param {ASTNode} referenceNode - Node to insert text before. |
|
||||
* |
|
||||
* @see {@link https://github.com/inikulin/parse5/blob/tree-adapter-docs-rev/lib/tree_adapters/default.js#L301|default implementation.}
|
|
||||
*/ |
|
||||
exports.insertTextBefore = function (parentNode, text, referenceNode) { |
|
||||
var prevNode = parentNode.childNodes[parentNode.childNodes.indexOf(referenceNode) - 1]; |
|
||||
|
|
||||
if (prevNode && prevNode.nodeName === '#text') |
|
||||
prevNode.value += text; |
|
||||
else |
|
||||
insertBefore(parentNode, createTextNode(text), referenceNode); |
|
||||
}; |
|
||||
|
|
||||
/** |
|
||||
* Copies attributes to the given node. Only attributes that are not yet present in the node are copied. |
|
||||
* |
|
||||
* @function adoptAttributes |
|
||||
* @memberof TreeAdapter |
|
||||
* |
|
||||
* @param {ASTNode} recipientNode - Node to copy attributes into. |
|
||||
* @param {Array} attrs - Attributes to copy. |
|
||||
|
|
||||
* @see {@link https://github.com/inikulin/parse5/blob/tree-adapter-docs-rev/lib/tree_adapters/default.js#L321|default implementation.}
|
|
||||
*/ |
|
||||
exports.adoptAttributes = function (recipientNode, attrs) { |
|
||||
var recipientAttrsMap = []; |
|
||||
|
|
||||
for (var i = 0; i < recipientNode.attrs.length; i++) |
|
||||
recipientAttrsMap.push(recipientNode.attrs[i].name); |
|
||||
|
|
||||
for (var j = 0; j < attrs.length; j++) { |
|
||||
if (recipientAttrsMap.indexOf(attrs[j].name) === -1) |
|
||||
recipientNode.attrs.push(attrs[j]); |
|
||||
} |
|
||||
}; |
|
||||
|
|
||||
|
|
||||
//Tree traversing
|
|
||||
|
|
||||
/** |
|
||||
* Returns the first child of the given node. |
|
||||
* |
|
||||
* @function getFirstChild |
|
||||
* @memberof TreeAdapter |
|
||||
* |
|
||||
* @param {ASTNode} node - Node. |
|
||||
* |
|
||||
* @returns {ASTNode} firstChild |
|
||||
* |
|
||||
* @see {@link https://github.com/inikulin/parse5/blob/tree-adapter-docs-rev/lib/tree_adapters/default.js#L348|default implementation.}
|
|
||||
*/ |
|
||||
exports.getFirstChild = function (node) { |
|
||||
return node.childNodes[0]; |
|
||||
}; |
|
||||
|
|
||||
/** |
|
||||
* Returns the given node's children in an array. |
|
||||
* |
|
||||
* @function getChildNodes |
|
||||
* @memberof TreeAdapter |
|
||||
* |
|
||||
* @param {ASTNode} node - Node. |
|
||||
* |
|
||||
* @returns {Array} children |
|
||||
* |
|
||||
* @see {@link https://github.com/inikulin/parse5/blob/tree-adapter-docs-rev/lib/tree_adapters/default.js#L364|default implementation.}
|
|
||||
*/ |
|
||||
exports.getChildNodes = function (node) { |
|
||||
return node.childNodes; |
|
||||
}; |
|
||||
|
|
||||
/** |
|
||||
* Returns the given node's parent. |
|
||||
* |
|
||||
* @function getParentNode |
|
||||
* @memberof TreeAdapter |
|
||||
* |
|
||||
* @param {ASTNode} node - Node. |
|
||||
* |
|
||||
* @returns {ASTNode} parent |
|
||||
* |
|
||||
* @see {@link https://github.com/inikulin/parse5/blob/tree-adapter-docs-rev/lib/tree_adapters/default.js#L380|default implementation.}
|
|
||||
*/ |
|
||||
exports.getParentNode = function (node) { |
|
||||
return node.parentNode; |
|
||||
}; |
|
||||
|
|
||||
/** |
|
||||
* Returns the given node's attributes in an array, in the form of name-value pairs. |
|
||||
* Foreign attributes may contain `namespace` and `prefix` fields as well. |
|
||||
* |
|
||||
* @function getAttrList |
|
||||
* @memberof TreeAdapter |
|
||||
* |
|
||||
* @param {ASTNode} node - Node. |
|
||||
* |
|
||||
* @returns {Array} attributes |
|
||||
* |
|
||||
* @see {@link https://github.com/inikulin/parse5/blob/tree-adapter-docs-rev/lib/tree_adapters/default.js#L397|default implementation.}
|
|
||||
*/ |
|
||||
exports.getAttrList = function (node) { |
|
||||
return node.attrs; |
|
||||
}; |
|
||||
|
|
||||
//Node data
|
|
||||
|
|
||||
/** |
|
||||
* Returns the given element's tag name. |
|
||||
* |
|
||||
* @function getTagName |
|
||||
* @memberof TreeAdapter |
|
||||
* |
|
||||
* @param {ASTNode<Element>} element - Element. |
|
||||
* |
|
||||
* @returns {String} tagName |
|
||||
* |
|
||||
* @see {@link https://github.com/inikulin/parse5/blob/tree-adapter-docs-rev/lib/tree_adapters/default.js#L415|default implementation.}
|
|
||||
*/ |
|
||||
exports.getTagName = function (element) { |
|
||||
return element.tagName; |
|
||||
}; |
|
||||
|
|
||||
/** |
|
||||
* Returns the given element's namespace. |
|
||||
* |
|
||||
* @function getNamespaceURI |
|
||||
* @memberof TreeAdapter |
|
||||
* |
|
||||
* @param {ASTNode<Element>} element - Element. |
|
||||
* |
|
||||
* @returns {String} namespaceURI |
|
||||
* |
|
||||
* @see {@link https://github.com/inikulin/parse5/blob/tree-adapter-docs-rev/lib/tree_adapters/default.js#L431|default implementation.}
|
|
||||
*/ |
|
||||
exports.getNamespaceURI = function (element) { |
|
||||
return element.namespaceURI; |
|
||||
}; |
|
||||
|
|
||||
/** |
|
||||
* Returns the given text node's content. |
|
||||
* |
|
||||
* @function getTextNodeContent |
|
||||
* @memberof TreeAdapter |
|
||||
* |
|
||||
* @param {ASTNode<Text>} textNode - Text node. |
|
||||
* |
|
||||
* @returns {String} text |
|
||||
* |
|
||||
* @see {@link https://github.com/inikulin/parse5/blob/tree-adapter-docs-rev/lib/tree_adapters/default.js#L447|default implementation.}
|
|
||||
*/ |
|
||||
exports.getTextNodeContent = function (textNode) { |
|
||||
return textNode.value; |
|
||||
}; |
|
||||
|
|
||||
/** |
|
||||
* Returns the given comment node's content. |
|
||||
* |
|
||||
* @function getCommentNodeContent |
|
||||
* @memberof TreeAdapter |
|
||||
* |
|
||||
* @param {ASTNode<Comment>} commentNode - Comment node. |
|
||||
* |
|
||||
* @returns {String} commentText |
|
||||
* |
|
||||
* @see {@link https://github.com/inikulin/parse5/blob/tree-adapter-docs-rev/lib/tree_adapters/default.js#L463|default implementation.}
|
|
||||
*/ |
|
||||
exports.getCommentNodeContent = function (commentNode) { |
|
||||
return commentNode.data; |
|
||||
}; |
|
||||
|
|
||||
/** |
|
||||
* Returns the given document type node's name. |
|
||||
* |
|
||||
* @function getDocumentTypeNodeName |
|
||||
* @memberof TreeAdapter |
|
||||
* |
|
||||
* @param {ASTNode<DocumentType>} doctypeNode - Document type node. |
|
||||
* |
|
||||
* @returns {String} name |
|
||||
* |
|
||||
* @see {@link https://github.com/inikulin/parse5/blob/tree-adapter-docs-rev/lib/tree_adapters/default.js#L479|default implementation.}
|
|
||||
*/ |
|
||||
exports.getDocumentTypeNodeName = function (doctypeNode) { |
|
||||
return doctypeNode.name; |
|
||||
}; |
|
||||
|
|
||||
/** |
|
||||
* Returns the given document type node's public identifier. |
|
||||
* |
|
||||
* @function getDocumentTypeNodePublicId |
|
||||
* @memberof TreeAdapter |
|
||||
* |
|
||||
* @param {ASTNode<DocumentType>} doctypeNode - Document type node. |
|
||||
* |
|
||||
* @returns {String} publicId |
|
||||
* |
|
||||
* @see {@link https://github.com/inikulin/parse5/blob/tree-adapter-docs-rev/lib/tree_adapters/default.js#L495|default implementation.}
|
|
||||
*/ |
|
||||
exports.getDocumentTypeNodePublicId = function (doctypeNode) { |
|
||||
return doctypeNode.publicId; |
|
||||
}; |
|
||||
|
|
||||
/** |
|
||||
* Returns the given document type node's system identifier. |
|
||||
* |
|
||||
* @function getDocumentTypeNodeSystemId |
|
||||
* @memberof TreeAdapter |
|
||||
* |
|
||||
* @param {ASTNode<DocumentType>} doctypeNode - Document type node. |
|
||||
* |
|
||||
* @returns {String} systemId |
|
||||
* |
|
||||
* @see {@link https://github.com/inikulin/parse5/blob/tree-adapter-docs-rev/lib/tree_adapters/default.js#L511|default implementation.}
|
|
||||
*/ |
|
||||
exports.getDocumentTypeNodeSystemId = function (doctypeNode) { |
|
||||
return doctypeNode.systemId; |
|
||||
}; |
|
||||
|
|
||||
//Node types
|
|
||||
/** |
|
||||
* Determines if the given node is a text node. |
|
||||
* |
|
||||
* @function isTextNode |
|
||||
* @memberof TreeAdapter |
|
||||
* |
|
||||
* @param {ASTNode} node - Node. |
|
||||
* |
|
||||
* @returns {Boolean} |
|
||||
* |
|
||||
* @see {@link https://github.com/inikulin/parse5/blob/tree-adapter-docs-rev/lib/tree_adapters/default.js#L526|default implementation.}
|
|
||||
*/ |
|
||||
exports.isTextNode = function (node) { |
|
||||
return node.nodeName === '#text'; |
|
||||
}; |
|
||||
|
|
||||
/** |
|
||||
* Determines if the given node is a comment node. |
|
||||
* |
|
||||
* @function isCommentNode |
|
||||
* @memberof TreeAdapter |
|
||||
* |
|
||||
* @param {ASTNode} node - Node. |
|
||||
* |
|
||||
* @returns {Boolean} |
|
||||
* |
|
||||
* @see {@link https://github.com/inikulin/parse5/blob/tree-adapter-docs-rev/lib/tree_adapters/default.js#L544|default implementation.}
|
|
||||
*/ |
|
||||
exports.isCommentNode = function (node) { |
|
||||
return node.nodeName === '#comment'; |
|
||||
}; |
|
||||
|
|
||||
/** |
|
||||
* Determines if the given node is a document type node. |
|
||||
* |
|
||||
* @function isDocumentTypeNode |
|
||||
* @memberof TreeAdapter |
|
||||
* |
|
||||
* @param {ASTNode} node - Node. |
|
||||
* |
|
||||
* @returns {Boolean} |
|
||||
* |
|
||||
* @see {@link https://github.com/inikulin/parse5/blob/tree-adapter-docs-rev/lib/tree_adapters/default.js#L560|default implementation.}
|
|
||||
*/ |
|
||||
exports.isDocumentTypeNode = function (node) { |
|
||||
return node.nodeName === '#documentType'; |
|
||||
}; |
|
||||
|
|
||||
/** |
|
||||
* Determines if the given node is an element. |
|
||||
* |
|
||||
* @function isElementNode |
|
||||
* @memberof TreeAdapter |
|
||||
* |
|
||||
* @param {ASTNode} node - Node. |
|
||||
* |
|
||||
* @returns {Boolean} |
|
||||
* |
|
||||
* @see {@link https://github.com/inikulin/parse5/blob/tree-adapter-docs-rev/lib/tree_adapters/default.js#L576|default implementation.}
|
|
||||
*/ |
|
||||
exports.isElementNode = function (node) { |
|
||||
return !!node.tagName; |
|
||||
}; |
|
@ -1,327 +0,0 @@ |
|||||
'use strict'; |
|
||||
|
|
||||
var doctype = require('../common/doctype'); |
|
||||
|
|
||||
//Conversion tables for DOM Level1 structure emulation
|
|
||||
var nodeTypes = { |
|
||||
element: 1, |
|
||||
text: 3, |
|
||||
cdata: 4, |
|
||||
comment: 8 |
|
||||
}; |
|
||||
|
|
||||
var nodePropertyShorthands = { |
|
||||
tagName: 'name', |
|
||||
childNodes: 'children', |
|
||||
parentNode: 'parent', |
|
||||
previousSibling: 'prev', |
|
||||
nextSibling: 'next', |
|
||||
nodeValue: 'data' |
|
||||
}; |
|
||||
|
|
||||
//Node
|
|
||||
var Node = function (props) { |
|
||||
for (var key in props) { |
|
||||
if (props.hasOwnProperty(key)) |
|
||||
this[key] = props[key]; |
|
||||
} |
|
||||
}; |
|
||||
|
|
||||
Node.prototype = { |
|
||||
get firstChild() { |
|
||||
var children = this.children; |
|
||||
|
|
||||
return children && children[0] || null; |
|
||||
}, |
|
||||
|
|
||||
get lastChild() { |
|
||||
var children = this.children; |
|
||||
|
|
||||
return children && children[children.length - 1] || null; |
|
||||
}, |
|
||||
|
|
||||
get nodeType() { |
|
||||
return nodeTypes[this.type] || nodeTypes.element; |
|
||||
} |
|
||||
}; |
|
||||
|
|
||||
Object.keys(nodePropertyShorthands).forEach(function (key) { |
|
||||
var shorthand = nodePropertyShorthands[key]; |
|
||||
|
|
||||
Object.defineProperty(Node.prototype, key, { |
|
||||
get: function () { |
|
||||
return this[shorthand] || null; |
|
||||
}, |
|
||||
set: function (val) { |
|
||||
this[shorthand] = val; |
|
||||
return val; |
|
||||
} |
|
||||
}); |
|
||||
}); |
|
||||
|
|
||||
|
|
||||
//Node construction
|
|
||||
exports.createDocument = |
|
||||
exports.createDocumentFragment = function () { |
|
||||
return new Node({ |
|
||||
type: 'root', |
|
||||
name: 'root', |
|
||||
parent: null, |
|
||||
prev: null, |
|
||||
next: null, |
|
||||
children: [] |
|
||||
}); |
|
||||
}; |
|
||||
|
|
||||
exports.createElement = function (tagName, namespaceURI, attrs) { |
|
||||
var attribs = {}, |
|
||||
attribsNamespace = {}, |
|
||||
attribsPrefix = {}; |
|
||||
|
|
||||
for (var i = 0; i < attrs.length; i++) { |
|
||||
var attrName = attrs[i].name; |
|
||||
|
|
||||
attribs[attrName] = attrs[i].value; |
|
||||
attribsNamespace[attrName] = attrs[i].namespace; |
|
||||
attribsPrefix[attrName] = attrs[i].prefix; |
|
||||
} |
|
||||
|
|
||||
return new Node({ |
|
||||
type: tagName === 'script' || tagName === 'style' ? tagName : 'tag', |
|
||||
name: tagName, |
|
||||
namespace: namespaceURI, |
|
||||
attribs: attribs, |
|
||||
'x-attribsNamespace': attribsNamespace, |
|
||||
'x-attribsPrefix': attribsPrefix, |
|
||||
children: [], |
|
||||
parent: null, |
|
||||
prev: null, |
|
||||
next: null |
|
||||
}); |
|
||||
}; |
|
||||
|
|
||||
exports.createCommentNode = function (data) { |
|
||||
return new Node({ |
|
||||
type: 'comment', |
|
||||
data: data, |
|
||||
parent: null, |
|
||||
prev: null, |
|
||||
next: null |
|
||||
}); |
|
||||
}; |
|
||||
|
|
||||
var createTextNode = function (value) { |
|
||||
return new Node({ |
|
||||
type: 'text', |
|
||||
data: value, |
|
||||
parent: null, |
|
||||
prev: null, |
|
||||
next: null |
|
||||
}); |
|
||||
}; |
|
||||
|
|
||||
|
|
||||
//Tree mutation
|
|
||||
var appendChild = exports.appendChild = function (parentNode, newNode) { |
|
||||
var prev = parentNode.children[parentNode.children.length - 1]; |
|
||||
|
|
||||
if (prev) { |
|
||||
prev.next = newNode; |
|
||||
newNode.prev = prev; |
|
||||
} |
|
||||
|
|
||||
parentNode.children.push(newNode); |
|
||||
newNode.parent = parentNode; |
|
||||
}; |
|
||||
|
|
||||
var insertBefore = exports.insertBefore = function (parentNode, newNode, referenceNode) { |
|
||||
var insertionIdx = parentNode.children.indexOf(referenceNode), |
|
||||
prev = referenceNode.prev; |
|
||||
|
|
||||
if (prev) { |
|
||||
prev.next = newNode; |
|
||||
newNode.prev = prev; |
|
||||
} |
|
||||
|
|
||||
referenceNode.prev = newNode; |
|
||||
newNode.next = referenceNode; |
|
||||
|
|
||||
parentNode.children.splice(insertionIdx, 0, newNode); |
|
||||
newNode.parent = parentNode; |
|
||||
}; |
|
||||
|
|
||||
exports.setTemplateContent = function (templateElement, contentElement) { |
|
||||
appendChild(templateElement, contentElement); |
|
||||
}; |
|
||||
|
|
||||
exports.getTemplateContent = function (templateElement) { |
|
||||
return templateElement.children[0]; |
|
||||
}; |
|
||||
|
|
||||
exports.setDocumentType = function (document, name, publicId, systemId) { |
|
||||
var data = doctype.serializeContent(name, publicId, systemId), |
|
||||
doctypeNode = null; |
|
||||
|
|
||||
for (var i = 0; i < document.children.length; i++) { |
|
||||
if (document.children[i].type === 'directive' && document.children[i].name === '!doctype') { |
|
||||
doctypeNode = document.children[i]; |
|
||||
break; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
if (doctypeNode) { |
|
||||
doctypeNode.data = data; |
|
||||
doctypeNode['x-name'] = name; |
|
||||
doctypeNode['x-publicId'] = publicId; |
|
||||
doctypeNode['x-systemId'] = systemId; |
|
||||
} |
|
||||
|
|
||||
else { |
|
||||
appendChild(document, new Node({ |
|
||||
type: 'directive', |
|
||||
name: '!doctype', |
|
||||
data: data, |
|
||||
'x-name': name, |
|
||||
'x-publicId': publicId, |
|
||||
'x-systemId': systemId |
|
||||
})); |
|
||||
} |
|
||||
|
|
||||
}; |
|
||||
|
|
||||
exports.setQuirksMode = function (document) { |
|
||||
document.quirksMode = true; |
|
||||
}; |
|
||||
|
|
||||
exports.isQuirksMode = function (document) { |
|
||||
return document.quirksMode; |
|
||||
}; |
|
||||
|
|
||||
exports.detachNode = function (node) { |
|
||||
if (node.parent) { |
|
||||
var idx = node.parent.children.indexOf(node), |
|
||||
prev = node.prev, |
|
||||
next = node.next; |
|
||||
|
|
||||
node.prev = null; |
|
||||
node.next = null; |
|
||||
|
|
||||
if (prev) |
|
||||
prev.next = next; |
|
||||
|
|
||||
if (next) |
|
||||
next.prev = prev; |
|
||||
|
|
||||
node.parent.children.splice(idx, 1); |
|
||||
node.parent = null; |
|
||||
} |
|
||||
}; |
|
||||
|
|
||||
exports.insertText = function (parentNode, text) { |
|
||||
var lastChild = parentNode.children[parentNode.children.length - 1]; |
|
||||
|
|
||||
if (lastChild && lastChild.type === 'text') |
|
||||
lastChild.data += text; |
|
||||
else |
|
||||
appendChild(parentNode, createTextNode(text)); |
|
||||
}; |
|
||||
|
|
||||
exports.insertTextBefore = function (parentNode, text, referenceNode) { |
|
||||
var prevNode = parentNode.children[parentNode.children.indexOf(referenceNode) - 1]; |
|
||||
|
|
||||
if (prevNode && prevNode.type === 'text') |
|
||||
prevNode.data += text; |
|
||||
else |
|
||||
insertBefore(parentNode, createTextNode(text), referenceNode); |
|
||||
}; |
|
||||
|
|
||||
exports.adoptAttributes = function (recipientNode, attrs) { |
|
||||
for (var i = 0; i < attrs.length; i++) { |
|
||||
var attrName = attrs[i].name; |
|
||||
|
|
||||
if (typeof recipientNode.attribs[attrName] === 'undefined') { |
|
||||
recipientNode.attribs[attrName] = attrs[i].value; |
|
||||
recipientNode['x-attribsNamespace'][attrName] = attrs[i].namespace; |
|
||||
recipientNode['x-attribsPrefix'][attrName] = attrs[i].prefix; |
|
||||
} |
|
||||
} |
|
||||
}; |
|
||||
|
|
||||
|
|
||||
//Tree traversing
|
|
||||
exports.getFirstChild = function (node) { |
|
||||
return node.children[0]; |
|
||||
}; |
|
||||
|
|
||||
exports.getChildNodes = function (node) { |
|
||||
return node.children; |
|
||||
}; |
|
||||
|
|
||||
exports.getParentNode = function (node) { |
|
||||
return node.parent; |
|
||||
}; |
|
||||
|
|
||||
exports.getAttrList = function (node) { |
|
||||
var attrList = []; |
|
||||
|
|
||||
for (var name in node.attribs) { |
|
||||
if (node.attribs.hasOwnProperty(name)) { |
|
||||
attrList.push({ |
|
||||
name: name, |
|
||||
value: node.attribs[name], |
|
||||
namespace: node['x-attribsNamespace'][name], |
|
||||
prefix: node['x-attribsPrefix'][name] |
|
||||
}); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
return attrList; |
|
||||
}; |
|
||||
|
|
||||
|
|
||||
//Node data
|
|
||||
exports.getTagName = function (element) { |
|
||||
return element.name; |
|
||||
}; |
|
||||
|
|
||||
exports.getNamespaceURI = function (element) { |
|
||||
return element.namespace; |
|
||||
}; |
|
||||
|
|
||||
exports.getTextNodeContent = function (textNode) { |
|
||||
return textNode.data; |
|
||||
}; |
|
||||
|
|
||||
exports.getCommentNodeContent = function (commentNode) { |
|
||||
return commentNode.data; |
|
||||
}; |
|
||||
|
|
||||
exports.getDocumentTypeNodeName = function (doctypeNode) { |
|
||||
return doctypeNode['x-name']; |
|
||||
}; |
|
||||
|
|
||||
exports.getDocumentTypeNodePublicId = function (doctypeNode) { |
|
||||
return doctypeNode['x-publicId']; |
|
||||
}; |
|
||||
|
|
||||
exports.getDocumentTypeNodeSystemId = function (doctypeNode) { |
|
||||
return doctypeNode['x-systemId']; |
|
||||
}; |
|
||||
|
|
||||
|
|
||||
//Node types
|
|
||||
exports.isTextNode = function (node) { |
|
||||
return node.type === 'text'; |
|
||||
}; |
|
||||
|
|
||||
exports.isCommentNode = function (node) { |
|
||||
return node.type === 'comment'; |
|
||||
}; |
|
||||
|
|
||||
exports.isDocumentTypeNode = function (node) { |
|
||||
return node.type === 'directive' && node.name === '!doctype'; |
|
||||
}; |
|
||||
|
|
||||
exports.isElementNode = function (node) { |
|
||||
return !!node.attribs; |
|
||||
}; |
|
@ -1,113 +0,0 @@ |
|||||
{ |
|
||||
"_from": "parse5@^2.2.2", |
|
||||
"_id": "parse5@2.2.3", |
|
||||
"_inBundle": false, |
|
||||
"_integrity": "sha1-DE/EHBAAxea5PUiwP4CDg3g06fY=", |
|
||||
"_location": "/parse5", |
|
||||
"_phantomChildren": {}, |
|
||||
"_requested": { |
|
||||
"type": "range", |
|
||||
"registry": true, |
|
||||
"raw": "parse5@^2.2.2", |
|
||||
"name": "parse5", |
|
||||
"escapedName": "parse5", |
|
||||
"rawSpec": "^2.2.2", |
|
||||
"saveSpec": null, |
|
||||
"fetchSpec": "^2.2.2" |
|
||||
}, |
|
||||
"_requiredBy": [ |
|
||||
"/eslint-plugin-markdown" |
|
||||
], |
|
||||
"_resolved": "https://registry.npmjs.org/parse5/-/parse5-2.2.3.tgz", |
|
||||
"_shasum": "0c4fc41c1000c5e6b93d48b03f8083837834e9f6", |
|
||||
"_spec": "parse5@^2.2.2", |
|
||||
"_where": "/Users/trott/io.js/tools/eslint-tmp/node_modules/eslint/node_modules/eslint-plugin-markdown", |
|
||||
"author": { |
|
||||
"name": "Ivan Nikulin", |
|
||||
"email": "ifaaan@gmail.com", |
|
||||
"url": "https://github.com/inikulin" |
|
||||
}, |
|
||||
"bugs": { |
|
||||
"url": "https://github.com/inikulin/parse5/issues" |
|
||||
}, |
|
||||
"bundleDependencies": false, |
|
||||
"contributors": [ |
|
||||
{ |
|
||||
"name": "Alan Clarke", |
|
||||
"url": "https://github.com/alanclarke" |
|
||||
}, |
|
||||
{ |
|
||||
"name": "Evan You", |
|
||||
"url": "http://evanyou.me" |
|
||||
}, |
|
||||
{ |
|
||||
"name": "Saksham Aggarwal", |
|
||||
"email": "s.agg2021@gmail.com" |
|
||||
}, |
|
||||
{ |
|
||||
"name": "Sebastian Mayr", |
|
||||
"email": "sebmaster16@gmail.com", |
|
||||
"url": "http://blog.smayr.name" |
|
||||
}, |
|
||||
{ |
|
||||
"name": "Sean Lang", |
|
||||
"email": "slang800@gmail.com", |
|
||||
"url": "http://slang.cx" |
|
||||
} |
|
||||
], |
|
||||
"deprecated": false, |
|
||||
"description": "WHATWG HTML5 specification-compliant, fast and ready for production HTML parsing/serialization toolset for Node.js", |
|
||||
"devDependencies": { |
|
||||
"del": "^2.0.2", |
|
||||
"gulp": "^3.9.0", |
|
||||
"gulp-benchmark": "^1.1.1", |
|
||||
"gulp-concat": "^2.6.0", |
|
||||
"gulp-download": "0.0.1", |
|
||||
"gulp-eslint": "^3.0.1", |
|
||||
"gulp-insert": "^0.5.0", |
|
||||
"gulp-install": "^0.6.0", |
|
||||
"gulp-jsdoc-to-markdown": "^1.1.1", |
|
||||
"gulp-mocha": "^2.1.3", |
|
||||
"gulp-rename": "^1.2.2", |
|
||||
"publish-please": "^2.2.0", |
|
||||
"through2": "^2.0.0" |
|
||||
}, |
|
||||
"files": [ |
|
||||
"lib" |
|
||||
], |
|
||||
"homepage": "https://github.com/inikulin/parse5", |
|
||||
"keywords": [ |
|
||||
"html", |
|
||||
"parser", |
|
||||
"html5", |
|
||||
"WHATWG", |
|
||||
"specification", |
|
||||
"fast", |
|
||||
"html parser", |
|
||||
"html5 parser", |
|
||||
"htmlparser", |
|
||||
"parse5", |
|
||||
"serializer", |
|
||||
"html serializer", |
|
||||
"htmlserializer", |
|
||||
"sax", |
|
||||
"simple api", |
|
||||
"parse", |
|
||||
"tokenize", |
|
||||
"serialize", |
|
||||
"tokenizer" |
|
||||
], |
|
||||
"license": "MIT", |
|
||||
"main": "./lib/index.js", |
|
||||
"name": "parse5", |
|
||||
"repository": { |
|
||||
"type": "git", |
|
||||
"url": "git://github.com/inikulin/parse5.git" |
|
||||
}, |
|
||||
"scripts": { |
|
||||
"prepublish": "publish-please guard", |
|
||||
"publish-please": "publish-please", |
|
||||
"test": "gulp test" |
|
||||
}, |
|
||||
"version": "2.2.3" |
|
||||
} |
|
@ -1,30 +1,14 @@ |
|||||
/** |
|
||||
* @author Titus Wormer |
|
||||
* @copyright 2015-2016 Titus Wormer |
|
||||
* @license MIT |
|
||||
* @module remark:parse |
|
||||
* @fileoverview Markdown parser. |
|
||||
*/ |
|
||||
|
|
||||
'use strict'; |
'use strict'; |
||||
|
|
||||
/* eslint-env commonjs */ |
|
||||
|
|
||||
/* Dependencies. */ |
|
||||
var unherit = require('unherit'); |
var unherit = require('unherit'); |
||||
|
var xtend = require('xtend'); |
||||
var Parser = require('./lib/parser.js'); |
var Parser = require('./lib/parser.js'); |
||||
|
|
||||
/** |
module.exports = parse; |
||||
* Attacher. |
|
||||
* |
|
||||
* @param {unified} processor - Unified processor. |
|
||||
*/ |
|
||||
function parse(processor) { |
|
||||
processor.Parser = unherit(Parser); |
|
||||
} |
|
||||
|
|
||||
/* Patch `Parser`. */ |
|
||||
parse.Parser = Parser; |
parse.Parser = Parser; |
||||
|
|
||||
/* Expose */ |
function parse(options) { |
||||
module.exports = parse; |
var Local = unherit(Parser); |
||||
|
Local.prototype.options = xtend(Local.prototype.options, this.data('settings'), options); |
||||
|
this.Parser = Local; |
||||
|
} |
||||
|
@ -1,52 +1,68 @@ |
|||||
[ |
[ |
||||
"article", |
"address", |
||||
"header", |
"article", |
||||
"aside", |
"aside", |
||||
"hgroup", |
"base", |
||||
"blockquote", |
"basefont", |
||||
"hr", |
"blockquote", |
||||
"iframe", |
"body", |
||||
"body", |
"caption", |
||||
"li", |
"center", |
||||
"map", |
"col", |
||||
"button", |
"colgroup", |
||||
"object", |
"dd", |
||||
"canvas", |
"details", |
||||
"ol", |
"dialog", |
||||
"caption", |
"dir", |
||||
"output", |
"div", |
||||
"col", |
"dl", |
||||
"p", |
"dt", |
||||
"colgroup", |
"fieldset", |
||||
"pre", |
"figcaption", |
||||
"dd", |
"figure", |
||||
"progress", |
"footer", |
||||
"div", |
"form", |
||||
"section", |
"frame", |
||||
"dl", |
"frameset", |
||||
"table", |
"h1", |
||||
"td", |
"h2", |
||||
"dt", |
"h3", |
||||
"tbody", |
"h4", |
||||
"embed", |
"h5", |
||||
"textarea", |
"h6", |
||||
"fieldset", |
"head", |
||||
"tfoot", |
"header", |
||||
"figcaption", |
"hgroup", |
||||
"th", |
"hr", |
||||
"figure", |
"html", |
||||
"thead", |
"iframe", |
||||
"footer", |
"legend", |
||||
"tr", |
"li", |
||||
"form", |
"link", |
||||
"ul", |
"main", |
||||
"h1", |
"menu", |
||||
"h2", |
"menuitem", |
||||
"h3", |
"meta", |
||||
"h4", |
"nav", |
||||
"h5", |
"noframes", |
||||
"h6", |
"ol", |
||||
"video", |
"optgroup", |
||||
"script", |
"option", |
||||
"style" |
"p", |
||||
|
"param", |
||||
|
"pre", |
||||
|
"section", |
||||
|
"source", |
||||
|
"title", |
||||
|
"summary", |
||||
|
"table", |
||||
|
"tbody", |
||||
|
"td", |
||||
|
"tfoot", |
||||
|
"th", |
||||
|
"thead", |
||||
|
"title", |
||||
|
"tr", |
||||
|
"track", |
||||
|
"ul" |
||||
] |
] |
||||
|
@ -0,0 +1,71 @@ |
|||||
|
/** |
||||
|
* @author Titus Wormer |
||||
|
* @copyright 2015 Titus Wormer |
||||
|
* @license MIT |
||||
|
* @module remark:parse:decode |
||||
|
* @fileoverview Decode entities. |
||||
|
*/ |
||||
|
|
||||
|
'use strict'; |
||||
|
|
||||
|
var entities = require('parse-entities'); |
||||
|
|
||||
|
module.exports = factory; |
||||
|
|
||||
|
/* Factory to create an entity decoder. */ |
||||
|
function factory(ctx) { |
||||
|
decoder.raw = decodeRaw; |
||||
|
|
||||
|
return decoder; |
||||
|
|
||||
|
/* Normalize `position` to add an `indent`. */ |
||||
|
function normalize(position) { |
||||
|
var offsets = ctx.offset; |
||||
|
var line = position.line; |
||||
|
var result = []; |
||||
|
|
||||
|
while (++line) { |
||||
|
if (!(line in offsets)) { |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
result.push((offsets[line] || 0) + 1); |
||||
|
} |
||||
|
|
||||
|
return { |
||||
|
start: position, |
||||
|
indent: result |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
/* Handle a warning. |
||||
|
* 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) { |
||||
|
entities(value, { |
||||
|
position: normalize(position), |
||||
|
warning: handleWarning, |
||||
|
text: handler, |
||||
|
reference: handler, |
||||
|
textContext: ctx, |
||||
|
referenceContext: ctx |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
/* Decode `value` (at `position`) into a string. */ |
||||
|
function decodeRaw(value, position) { |
||||
|
return entities(value, { |
||||
|
position: normalize(position), |
||||
|
warning: handleWarning |
||||
|
}); |
||||
|
} |
||||
|
} |
@ -1,75 +0,0 @@ |
|||||
{ |
|
||||
"default": [ |
|
||||
"\\", |
|
||||
"`", |
|
||||
"*", |
|
||||
"{", |
|
||||
"}", |
|
||||
"[", |
|
||||
"]", |
|
||||
"(", |
|
||||
")", |
|
||||
"#", |
|
||||
"+", |
|
||||
"-", |
|
||||
".", |
|
||||
"!", |
|
||||
"_", |
|
||||
">" |
|
||||
], |
|
||||
"gfm": [ |
|
||||
"\\", |
|
||||
"`", |
|
||||
"*", |
|
||||
"{", |
|
||||
"}", |
|
||||
"[", |
|
||||
"]", |
|
||||
"(", |
|
||||
")", |
|
||||
"#", |
|
||||
"+", |
|
||||
"-", |
|
||||
".", |
|
||||
"!", |
|
||||
"_", |
|
||||
">", |
|
||||
"~", |
|
||||
"|" |
|
||||
], |
|
||||
"commonmark": [ |
|
||||
"\\", |
|
||||
"`", |
|
||||
"*", |
|
||||
"{", |
|
||||
"}", |
|
||||
"[", |
|
||||
"]", |
|
||||
"(", |
|
||||
")", |
|
||||
"#", |
|
||||
"+", |
|
||||
"-", |
|
||||
".", |
|
||||
"!", |
|
||||
"_", |
|
||||
">", |
|
||||
"~", |
|
||||
"|", |
|
||||
"\n", |
|
||||
"\"", |
|
||||
"$", |
|
||||
"%", |
|
||||
"&", |
|
||||
"'", |
|
||||
",", |
|
||||
"/", |
|
||||
":", |
|
||||
";", |
|
||||
"<", |
|
||||
"=", |
|
||||
"?", |
|
||||
"@", |
|
||||
"^" |
|
||||
] |
|
||||
} |
|
@ -0,0 +1,25 @@ |
|||||
|
/** |
||||
|
* @author Titus Wormer |
||||
|
* @copyright 2015 Titus Wormer |
||||
|
* @license MIT |
||||
|
* @module remark:parse:locate:break |
||||
|
* @fileoverview Locate a break. |
||||
|
*/ |
||||
|
|
||||
|
'use strict'; |
||||
|
|
||||
|
module.exports = locate; |
||||
|
|
||||
|
function locate(value, fromIndex) { |
||||
|
var index = value.indexOf('\n', fromIndex); |
||||
|
|
||||
|
while (index > fromIndex) { |
||||
|
if (value.charAt(index - 1) !== ' ') { |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
index--; |
||||
|
} |
||||
|
|
||||
|
return index; |
||||
|
} |
@ -0,0 +1,15 @@ |
|||||
|
/** |
||||
|
* @author Titus Wormer |
||||
|
* @copyright 2015 Titus Wormer |
||||
|
* @license MIT |
||||
|
* @module remark:parse:locate:code-inline |
||||
|
* @fileoverview Locate inline code. |
||||
|
*/ |
||||
|
|
||||
|
'use strict'; |
||||
|
|
||||
|
module.exports = locate; |
||||
|
|
||||
|
function locate(value, fromIndex) { |
||||
|
return value.indexOf('`', fromIndex); |
||||
|
} |
@ -0,0 +1,15 @@ |
|||||
|
/** |
||||
|
* @author Titus Wormer |
||||
|
* @copyright 2015 Titus Wormer |
||||
|
* @license MIT |
||||
|
* @module remark:parse:locate:delete |
||||
|
* @fileoverview Locate strikethrough. |
||||
|
*/ |
||||
|
|
||||
|
'use strict'; |
||||
|
|
||||
|
module.exports = locate; |
||||
|
|
||||
|
function locate(value, fromIndex) { |
||||
|
return value.indexOf('~~', fromIndex); |
||||
|
} |
@ -0,0 +1,26 @@ |
|||||
|
/** |
||||
|
* @author Titus Wormer |
||||
|
* @copyright 2015 Titus Wormer |
||||
|
* @license MIT |
||||
|
* @module remark:parse:locate:emphasis |
||||
|
* @fileoverview Locate italics / emphasis. |
||||
|
*/ |
||||
|
|
||||
|
'use strict'; |
||||
|
|
||||
|
module.exports = locate; |
||||
|
|
||||
|
function locate(value, fromIndex) { |
||||
|
var asterisk = value.indexOf('*', fromIndex); |
||||
|
var underscore = value.indexOf('_', fromIndex); |
||||
|
|
||||
|
if (underscore === -1) { |
||||
|
return asterisk; |
||||
|
} |
||||
|
|
||||
|
if (asterisk === -1) { |
||||
|
return underscore; |
||||
|
} |
||||
|
|
||||
|
return underscore < asterisk ? underscore : asterisk; |
||||
|
} |
@ -0,0 +1,15 @@ |
|||||
|
/** |
||||
|
* @author Titus Wormer |
||||
|
* @copyright 2015 Titus Wormer |
||||
|
* @license MIT |
||||
|
* @module remark:parse:locate:escape |
||||
|
* @fileoverview Locate an escape. |
||||
|
*/ |
||||
|
|
||||
|
'use strict'; |
||||
|
|
||||
|
module.exports = locate; |
||||
|
|
||||
|
function locate(value, fromIndex) { |
||||
|
return value.indexOf('\\', fromIndex); |
||||
|
} |
@ -0,0 +1,24 @@ |
|||||
|
/** |
||||
|
* @author Titus Wormer |
||||
|
* @copyright 2015 Titus Wormer |
||||
|
* @license MIT |
||||
|
* @module remark:parse:locate:link |
||||
|
* @fileoverview Locate a link. |
||||
|
*/ |
||||
|
|
||||
|
'use strict'; |
||||
|
|
||||
|
module.exports = locate; |
||||
|
|
||||
|
function locate(value, fromIndex) { |
||||
|
var link = value.indexOf('[', fromIndex); |
||||
|
var image = value.indexOf('![', fromIndex); |
||||
|
|
||||
|
if (image === -1) { |
||||
|
return link; |
||||
|
} |
||||
|
|
||||
|
/* Link can never be `-1` if an image is found, so we don’t need |
||||
|
* to check for that :) */ |
||||
|
return link < image ? link : image; |
||||
|
} |
@ -0,0 +1,26 @@ |
|||||
|
/** |
||||
|
* @author Titus Wormer |
||||
|
* @copyright 2015 Titus Wormer |
||||
|
* @license MIT |
||||
|
* @module remark:parse:locate:strong |
||||
|
* @fileoverview Locate bold / strong / importance. |
||||
|
*/ |
||||
|
|
||||
|
'use strict'; |
||||
|
|
||||
|
module.exports = locate; |
||||
|
|
||||
|
function locate(value, fromIndex) { |
||||
|
var asterisk = value.indexOf('**', fromIndex); |
||||
|
var underscore = value.indexOf('__', fromIndex); |
||||
|
|
||||
|
if (underscore === -1) { |
||||
|
return asterisk; |
||||
|
} |
||||
|
|
||||
|
if (asterisk === -1) { |
||||
|
return underscore; |
||||
|
} |
||||
|
|
||||
|
return underscore < asterisk ? underscore : asterisk; |
||||
|
} |
@ -0,0 +1,15 @@ |
|||||
|
/** |
||||
|
* @author Titus Wormer |
||||
|
* @copyright 2015 Titus Wormer |
||||
|
* @license MIT |
||||
|
* @module remark:parse:locate:tag |
||||
|
* @fileoverview Locate a tag. |
||||
|
*/ |
||||
|
|
||||
|
'use strict'; |
||||
|
|
||||
|
module.exports = locate; |
||||
|
|
||||
|
function locate(value, fromIndex) { |
||||
|
return value.indexOf('<', fromIndex); |
||||
|
} |
@ -0,0 +1,34 @@ |
|||||
|
/** |
||||
|
* @author Titus Wormer |
||||
|
* @copyright 2015 Titus Wormer |
||||
|
* @license MIT |
||||
|
* @module remark:parse:locate:url |
||||
|
* @fileoverview Locate a URL. |
||||
|
*/ |
||||
|
|
||||
|
'use strict'; |
||||
|
|
||||
|
module.exports = locate; |
||||
|
|
||||
|
var PROTOCOLS = ['https://', 'http://', 'mailto:']; |
||||
|
|
||||
|
function locate(value, fromIndex) { |
||||
|
var length = PROTOCOLS.length; |
||||
|
var index = -1; |
||||
|
var min = -1; |
||||
|
var position; |
||||
|
|
||||
|
if (!this.options.gfm) { |
||||
|
return -1; |
||||
|
} |
||||
|
|
||||
|
while (++index < length) { |
||||
|
position = value.indexOf(PROTOCOLS[index], fromIndex); |
||||
|
|
||||
|
if (position !== -1 && (position < min || min === -1)) { |
||||
|
min = position; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return min; |
||||
|
} |
@ -0,0 +1,53 @@ |
|||||
|
/** |
||||
|
* @author Titus Wormer |
||||
|
* @copyright 2015 Titus Wormer |
||||
|
* @license MIT |
||||
|
* @module remark:parse:parse |
||||
|
* @fileoverview Parse the document |
||||
|
*/ |
||||
|
|
||||
|
'use strict'; |
||||
|
|
||||
|
var xtend = require('xtend'); |
||||
|
var removePosition = require('unist-util-remove-position'); |
||||
|
|
||||
|
module.exports = parse; |
||||
|
|
||||
|
var C_NEWLINE = '\n'; |
||||
|
var EXPRESSION_LINE_BREAKS = /\r\n|\r/g; |
||||
|
|
||||
|
/* Parse the bound file. */ |
||||
|
function parse() { |
||||
|
var self = this; |
||||
|
var value = String(self.file); |
||||
|
var start = {line: 1, column: 1, offset: 0}; |
||||
|
var content = xtend(start); |
||||
|
var node; |
||||
|
|
||||
|
/* Clean non-unix newlines: `\r\n` and `\r` are all |
||||
|
* changed to `\n`. This should not affect positional |
||||
|
* information. */ |
||||
|
value = value.replace(EXPRESSION_LINE_BREAKS, C_NEWLINE); |
||||
|
|
||||
|
if (value.charCodeAt(0) === 0xFEFF) { |
||||
|
value = value.slice(1); |
||||
|
|
||||
|
content.column++; |
||||
|
content.offset++; |
||||
|
} |
||||
|
|
||||
|
node = { |
||||
|
type: 'root', |
||||
|
children: self.tokenizeBlock(value, content), |
||||
|
position: { |
||||
|
start: start, |
||||
|
end: self.eof || xtend(start) |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
if (!self.options.position) { |
||||
|
removePosition(node, true); |
||||
|
} |
||||
|
|
||||
|
return node; |
||||
|
} |
File diff suppressed because it is too large
@ -0,0 +1,59 @@ |
|||||
|
/** |
||||
|
* @author Titus Wormer |
||||
|
* @copyright 2015 Titus Wormer |
||||
|
* @license MIT |
||||
|
* @module remark:parse |
||||
|
* @fileoverview Markdown parser. |
||||
|
*/ |
||||
|
|
||||
|
'use strict'; |
||||
|
|
||||
|
var xtend = require('xtend'); |
||||
|
var escapes = require('markdown-escapes'); |
||||
|
var defaults = require('./defaults'); |
||||
|
|
||||
|
module.exports = setOptions; |
||||
|
|
||||
|
/* Set options. */ |
||||
|
function setOptions(options) { |
||||
|
var self = this; |
||||
|
var current = self.options; |
||||
|
var key; |
||||
|
var value; |
||||
|
|
||||
|
if (options == null) { |
||||
|
options = {}; |
||||
|
} else if (typeof options === 'object') { |
||||
|
options = xtend(options); |
||||
|
} else { |
||||
|
throw new Error( |
||||
|
'Invalid value `' + options + '` ' + |
||||
|
'for setting `options`' |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
for (key in defaults) { |
||||
|
value = options[key]; |
||||
|
|
||||
|
if (value == null) { |
||||
|
value = current[key]; |
||||
|
} |
||||
|
|
||||
|
if ( |
||||
|
(key !== 'blocks' && typeof value !== 'boolean') || |
||||
|
(key === 'blocks' && typeof value !== 'object') |
||||
|
) { |
||||
|
throw new Error( |
||||
|
'Invalid value `' + value + '` ' + |
||||
|
'for setting `options.' + key + '`' |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
options[key] = value; |
||||
|
} |
||||
|
|
||||
|
self.options = options; |
||||
|
self.escape = escapes(options); |
||||
|
|
||||
|
return self; |
||||
|
} |
@ -0,0 +1,151 @@ |
|||||
|
/** |
||||
|
* @author Titus Wormer |
||||
|
* @copyright 2015 Titus Wormer |
||||
|
* @license MIT |
||||
|
* @module remark:parse:tokenize:auto-link |
||||
|
* @fileoverview Tokenise an auto-link. |
||||
|
*/ |
||||
|
|
||||
|
'use strict'; |
||||
|
|
||||
|
var decode = require('parse-entities'); |
||||
|
var locate = require('../locate/tag'); |
||||
|
|
||||
|
module.exports = autoLink; |
||||
|
autoLink.locator = locate; |
||||
|
autoLink.notInLink = true; |
||||
|
|
||||
|
var C_LT = '<'; |
||||
|
var C_GT = '>'; |
||||
|
var C_AT_SIGN = '@'; |
||||
|
var C_SLASH = '/'; |
||||
|
var MAILTO = 'mailto:'; |
||||
|
var MAILTO_LENGTH = MAILTO.length; |
||||
|
|
||||
|
/* Tokenise a link. */ |
||||
|
function autoLink(eat, value, silent) { |
||||
|
var self; |
||||
|
var subvalue; |
||||
|
var length; |
||||
|
var index; |
||||
|
var queue; |
||||
|
var character; |
||||
|
var hasAtCharacter; |
||||
|
var link; |
||||
|
var now; |
||||
|
var content; |
||||
|
var tokenize; |
||||
|
var exit; |
||||
|
|
||||
|
if (value.charAt(0) !== C_LT) { |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
self = this; |
||||
|
subvalue = ''; |
||||
|
length = value.length; |
||||
|
index = 0; |
||||
|
queue = ''; |
||||
|
hasAtCharacter = false; |
||||
|
link = ''; |
||||
|
|
||||
|
index++; |
||||
|
subvalue = C_LT; |
||||
|
|
||||
|
while (index < length) { |
||||
|
character = value.charAt(index); |
||||
|
|
||||
|
if ( |
||||
|
character === ' ' || |
||||
|
character === C_GT || |
||||
|
character === C_AT_SIGN || |
||||
|
(character === ':' && value.charAt(index + 1) === C_SLASH) |
||||
|
) { |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
queue += character; |
||||
|
index++; |
||||
|
} |
||||
|
|
||||
|
if (!queue) { |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
link += queue; |
||||
|
queue = ''; |
||||
|
|
||||
|
character = value.charAt(index); |
||||
|
link += character; |
||||
|
index++; |
||||
|
|
||||
|
if (character === C_AT_SIGN) { |
||||
|
hasAtCharacter = true; |
||||
|
} else { |
||||
|
if ( |
||||
|
character !== ':' || |
||||
|
value.charAt(index + 1) !== C_SLASH |
||||
|
) { |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
link += C_SLASH; |
||||
|
index++; |
||||
|
} |
||||
|
|
||||
|
while (index < length) { |
||||
|
character = value.charAt(index); |
||||
|
|
||||
|
if (character === ' ' || character === C_GT) { |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
queue += character; |
||||
|
index++; |
||||
|
} |
||||
|
|
||||
|
character = value.charAt(index); |
||||
|
|
||||
|
if (!queue || character !== C_GT) { |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
/* istanbul ignore if - never used (yet) */ |
||||
|
if (silent) { |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
link += queue; |
||||
|
content = link; |
||||
|
subvalue += link + character; |
||||
|
now = eat.now(); |
||||
|
now.column++; |
||||
|
now.offset++; |
||||
|
|
||||
|
if (hasAtCharacter) { |
||||
|
if (link.slice(0, MAILTO_LENGTH).toLowerCase() === MAILTO) { |
||||
|
content = content.substr(MAILTO_LENGTH); |
||||
|
now.column += MAILTO_LENGTH; |
||||
|
now.offset += MAILTO_LENGTH; |
||||
|
} else { |
||||
|
link = MAILTO + link; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/* Temporarily remove support for escapes in autolinks. */ |
||||
|
tokenize = self.inlineTokenizers.escape; |
||||
|
self.inlineTokenizers.escape = null; |
||||
|
exit = self.enterLink(); |
||||
|
|
||||
|
content = self.tokenizeInline(content, now); |
||||
|
|
||||
|
self.inlineTokenizers.escape = tokenize; |
||||
|
exit(); |
||||
|
|
||||
|
return eat(subvalue)({ |
||||
|
type: 'link', |
||||
|
title: null, |
||||
|
url: decode(link), |
||||
|
children: content |
||||
|
}); |
||||
|
} |
@ -0,0 +1,137 @@ |
|||||
|
/** |
||||
|
* @author Titus Wormer |
||||
|
* @copyright 2015 Titus Wormer |
||||
|
* @license MIT |
||||
|
* @module remark:parse:tokenize:blockquote |
||||
|
* @fileoverview Tokenise blockquote. |
||||
|
*/ |
||||
|
|
||||
|
'use strict'; |
||||
|
|
||||
|
var trim = require('trim'); |
||||
|
var interrupt = require('../util/interrupt'); |
||||
|
|
||||
|
module.exports = blockquote; |
||||
|
|
||||
|
var C_NEWLINE = '\n'; |
||||
|
var C_TAB = '\t'; |
||||
|
var C_SPACE = ' '; |
||||
|
var C_GT = '>'; |
||||
|
|
||||
|
/* Tokenise a blockquote. */ |
||||
|
function blockquote(eat, value, silent) { |
||||
|
var self = this; |
||||
|
var offsets = self.offset; |
||||
|
var tokenizers = self.blockTokenizers; |
||||
|
var interruptors = self.interruptBlockquote; |
||||
|
var now = eat.now(); |
||||
|
var currentLine = now.line; |
||||
|
var length = value.length; |
||||
|
var values = []; |
||||
|
var contents = []; |
||||
|
var indents = []; |
||||
|
var add; |
||||
|
var index = 0; |
||||
|
var character; |
||||
|
var rest; |
||||
|
var nextIndex; |
||||
|
var content; |
||||
|
var line; |
||||
|
var startIndex; |
||||
|
var prefixed; |
||||
|
var exit; |
||||
|
|
||||
|
while (index < length) { |
||||
|
character = value.charAt(index); |
||||
|
|
||||
|
if (character !== C_SPACE && character !== C_TAB) { |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
index++; |
||||
|
} |
||||
|
|
||||
|
if (value.charAt(index) !== C_GT) { |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
if (silent) { |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
index = 0; |
||||
|
|
||||
|
while (index < length) { |
||||
|
nextIndex = value.indexOf(C_NEWLINE, index); |
||||
|
startIndex = index; |
||||
|
prefixed = false; |
||||
|
|
||||
|
if (nextIndex === -1) { |
||||
|
nextIndex = length; |
||||
|
} |
||||
|
|
||||
|
while (index < length) { |
||||
|
character = value.charAt(index); |
||||
|
|
||||
|
if (character !== C_SPACE && character !== C_TAB) { |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
index++; |
||||
|
} |
||||
|
|
||||
|
if (value.charAt(index) === C_GT) { |
||||
|
index++; |
||||
|
prefixed = true; |
||||
|
|
||||
|
if (value.charAt(index) === C_SPACE) { |
||||
|
index++; |
||||
|
} |
||||
|
} else { |
||||
|
index = startIndex; |
||||
|
} |
||||
|
|
||||
|
content = value.slice(index, nextIndex); |
||||
|
|
||||
|
if (!prefixed && !trim(content)) { |
||||
|
index = startIndex; |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
if (!prefixed) { |
||||
|
rest = value.slice(index); |
||||
|
|
||||
|
/* Check if the following code contains a possible |
||||
|
* block. */ |
||||
|
if (interrupt(interruptors, tokenizers, self, [eat, rest, true])) { |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
line = startIndex === index ? content : value.slice(startIndex, nextIndex); |
||||
|
|
||||
|
indents.push(index - startIndex); |
||||
|
values.push(line); |
||||
|
contents.push(content); |
||||
|
|
||||
|
index = nextIndex + 1; |
||||
|
} |
||||
|
|
||||
|
index = -1; |
||||
|
length = indents.length; |
||||
|
add = eat(values.join(C_NEWLINE)); |
||||
|
|
||||
|
while (++index < length) { |
||||
|
offsets[currentLine] = (offsets[currentLine] || 0) + indents[index]; |
||||
|
currentLine++; |
||||
|
} |
||||
|
|
||||
|
exit = self.enterBlock(); |
||||
|
contents = self.tokenizeBlock(contents.join(C_NEWLINE), now); |
||||
|
exit(); |
||||
|
|
||||
|
return add({ |
||||
|
type: 'blockquote', |
||||
|
children: contents |
||||
|
}); |
||||
|
} |
@ -0,0 +1,51 @@ |
|||||
|
/** |
||||
|
* @author Titus Wormer |
||||
|
* @copyright 2015 Titus Wormer |
||||
|
* @license MIT |
||||
|
* @module remark:parse:tokenize:break |
||||
|
* @fileoverview Tokenise a break. |
||||
|
*/ |
||||
|
|
||||
|
'use strict'; |
||||
|
|
||||
|
var locate = require('../locate/break'); |
||||
|
|
||||
|
module.exports = hardBreak; |
||||
|
hardBreak.locator = locate; |
||||
|
|
||||
|
var MIN_BREAK_LENGTH = 2; |
||||
|
|
||||
|
/* Tokenise a break. */ |
||||
|
function hardBreak(eat, value, silent) { |
||||
|
var self = this; |
||||
|
var breaks = self.options.breaks; |
||||
|
var length = value.length; |
||||
|
var index = -1; |
||||
|
var queue = ''; |
||||
|
var character; |
||||
|
|
||||
|
while (++index < length) { |
||||
|
character = value.charAt(index); |
||||
|
|
||||
|
if (character === '\n') { |
||||
|
if (!breaks && index < MIN_BREAK_LENGTH) { |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
/* istanbul ignore if - never used (yet) */ |
||||
|
if (silent) { |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
queue += character; |
||||
|
|
||||
|
return eat(queue)({type: 'break'}); |
||||
|
} |
||||
|
|
||||
|
if (character !== ' ') { |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
queue += character; |
||||
|
} |
||||
|
} |
@ -0,0 +1,245 @@ |
|||||
|
/** |
||||
|
* @author Titus Wormer |
||||
|
* @copyright 2015 Titus Wormer |
||||
|
* @license MIT |
||||
|
* @module remark:parse:tokenize:code-fenced |
||||
|
* @fileoverview Tokenise fenced code. |
||||
|
*/ |
||||
|
|
||||
|
'use strict'; |
||||
|
|
||||
|
var trim = require('trim-trailing-lines'); |
||||
|
|
||||
|
module.exports = fencedCode; |
||||
|
|
||||
|
var C_NEWLINE = '\n'; |
||||
|
var C_TAB = '\t'; |
||||
|
var C_SPACE = ' '; |
||||
|
var C_TILDE = '~'; |
||||
|
var C_TICK = '`'; |
||||
|
|
||||
|
var MIN_FENCE_COUNT = 3; |
||||
|
var CODE_INDENT_COUNT = 4; |
||||
|
|
||||
|
/* Tokenise fenced code. */ |
||||
|
function fencedCode(eat, value, silent) { |
||||
|
var self = this; |
||||
|
var settings = self.options; |
||||
|
var length = value.length + 1; |
||||
|
var index = 0; |
||||
|
var subvalue = ''; |
||||
|
var fenceCount; |
||||
|
var marker; |
||||
|
var character; |
||||
|
var flag; |
||||
|
var queue; |
||||
|
var content; |
||||
|
var exdentedContent; |
||||
|
var closing; |
||||
|
var exdentedClosing; |
||||
|
var indent; |
||||
|
var now; |
||||
|
|
||||
|
if (!settings.gfm) { |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
/* Eat initial spacing. */ |
||||
|
while (index < length) { |
||||
|
character = value.charAt(index); |
||||
|
|
||||
|
if (character !== C_SPACE && character !== C_TAB) { |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
subvalue += character; |
||||
|
index++; |
||||
|
} |
||||
|
|
||||
|
indent = index; |
||||
|
|
||||
|
/* Eat the fence. */ |
||||
|
character = value.charAt(index); |
||||
|
|
||||
|
if (character !== C_TILDE && character !== C_TICK) { |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
index++; |
||||
|
marker = character; |
||||
|
fenceCount = 1; |
||||
|
subvalue += character; |
||||
|
|
||||
|
while (index < length) { |
||||
|
character = value.charAt(index); |
||||
|
|
||||
|
if (character !== marker) { |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
subvalue += character; |
||||
|
fenceCount++; |
||||
|
index++; |
||||
|
} |
||||
|
|
||||
|
if (fenceCount < MIN_FENCE_COUNT) { |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
/* Eat spacing before flag. */ |
||||
|
while (index < length) { |
||||
|
character = value.charAt(index); |
||||
|
|
||||
|
if (character !== C_SPACE && character !== C_TAB) { |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
subvalue += character; |
||||
|
index++; |
||||
|
} |
||||
|
|
||||
|
/* Eat flag. */ |
||||
|
flag = ''; |
||||
|
queue = ''; |
||||
|
|
||||
|
while (index < length) { |
||||
|
character = value.charAt(index); |
||||
|
|
||||
|
if ( |
||||
|
character === C_NEWLINE || |
||||
|
character === C_TILDE || |
||||
|
character === C_TICK |
||||
|
) { |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
if (character === C_SPACE || character === C_TAB) { |
||||
|
queue += character; |
||||
|
} else { |
||||
|
flag += queue + character; |
||||
|
queue = ''; |
||||
|
} |
||||
|
|
||||
|
index++; |
||||
|
} |
||||
|
|
||||
|
character = value.charAt(index); |
||||
|
|
||||
|
if (character && character !== C_NEWLINE) { |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
if (silent) { |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
now = eat.now(); |
||||
|
now.column += subvalue.length; |
||||
|
now.offset += subvalue.length; |
||||
|
|
||||
|
subvalue += flag; |
||||
|
flag = self.decode.raw(self.unescape(flag), now); |
||||
|
|
||||
|
if (queue) { |
||||
|
subvalue += queue; |
||||
|
} |
||||
|
|
||||
|
queue = ''; |
||||
|
closing = ''; |
||||
|
exdentedClosing = ''; |
||||
|
content = ''; |
||||
|
exdentedContent = ''; |
||||
|
|
||||
|
/* Eat content. */ |
||||
|
while (index < length) { |
||||
|
character = value.charAt(index); |
||||
|
content += closing; |
||||
|
exdentedContent += exdentedClosing; |
||||
|
closing = ''; |
||||
|
exdentedClosing = ''; |
||||
|
|
||||
|
if (character !== C_NEWLINE) { |
||||
|
content += character; |
||||
|
exdentedClosing += character; |
||||
|
index++; |
||||
|
continue; |
||||
|
} |
||||
|
|
||||
|
/* Add the newline to `subvalue` if its the first |
||||
|
* character. Otherwise, add it to the `closing` |
||||
|
* queue. */ |
||||
|
if (content) { |
||||
|
closing += character; |
||||
|
exdentedClosing += character; |
||||
|
} else { |
||||
|
subvalue += character; |
||||
|
} |
||||
|
|
||||
|
queue = ''; |
||||
|
index++; |
||||
|
|
||||
|
while (index < length) { |
||||
|
character = value.charAt(index); |
||||
|
|
||||
|
if (character !== C_SPACE) { |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
queue += character; |
||||
|
index++; |
||||
|
} |
||||
|
|
||||
|
closing += queue; |
||||
|
exdentedClosing += queue.slice(indent); |
||||
|
|
||||
|
if (queue.length >= CODE_INDENT_COUNT) { |
||||
|
continue; |
||||
|
} |
||||
|
|
||||
|
queue = ''; |
||||
|
|
||||
|
while (index < length) { |
||||
|
character = value.charAt(index); |
||||
|
|
||||
|
if (character !== marker) { |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
queue += character; |
||||
|
index++; |
||||
|
} |
||||
|
|
||||
|
closing += queue; |
||||
|
exdentedClosing += queue; |
||||
|
|
||||
|
if (queue.length < fenceCount) { |
||||
|
continue; |
||||
|
} |
||||
|
|
||||
|
queue = ''; |
||||
|
|
||||
|
while (index < length) { |
||||
|
character = value.charAt(index); |
||||
|
|
||||
|
if (character !== C_SPACE && character !== C_TAB) { |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
closing += character; |
||||
|
exdentedClosing += character; |
||||
|
index++; |
||||
|
} |
||||
|
|
||||
|
if (!character || character === C_NEWLINE) { |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
subvalue += content + closing; |
||||
|
|
||||
|
return eat(subvalue)({ |
||||
|
type: 'code', |
||||
|
lang: flag || null, |
||||
|
value: trim(exdentedContent) |
||||
|
}); |
||||
|
} |
@ -0,0 +1,106 @@ |
|||||
|
/** |
||||
|
* @author Titus Wormer |
||||
|
* @copyright 2015 Titus Wormer |
||||
|
* @license MIT |
||||
|
* @module remark:parse:tokenize:code-indented |
||||
|
* @fileoverview Tokenise indented code. |
||||
|
*/ |
||||
|
|
||||
|
'use strict'; |
||||
|
|
||||
|
var repeat = require('repeat-string'); |
||||
|
var trim = require('trim-trailing-lines'); |
||||
|
|
||||
|
module.exports = indentedCode; |
||||
|
|
||||
|
var C_NEWLINE = '\n'; |
||||
|
var C_TAB = '\t'; |
||||
|
var C_SPACE = ' '; |
||||
|
|
||||
|
var CODE_INDENT_COUNT = 4; |
||||
|
var CODE_INDENT = repeat(C_SPACE, CODE_INDENT_COUNT); |
||||
|
|
||||
|
/* Tokenise indented code. */ |
||||
|
function indentedCode(eat, value, silent) { |
||||
|
var index = -1; |
||||
|
var length = value.length; |
||||
|
var subvalue = ''; |
||||
|
var content = ''; |
||||
|
var subvalueQueue = ''; |
||||
|
var contentQueue = ''; |
||||
|
var character; |
||||
|
var blankQueue; |
||||
|
var indent; |
||||
|
|
||||
|
while (++index < length) { |
||||
|
character = value.charAt(index); |
||||
|
|
||||
|
if (indent) { |
||||
|
indent = false; |
||||
|
|
||||
|
subvalue += subvalueQueue; |
||||
|
content += contentQueue; |
||||
|
subvalueQueue = ''; |
||||
|
contentQueue = ''; |
||||
|
|
||||
|
if (character === C_NEWLINE) { |
||||
|
subvalueQueue = character; |
||||
|
contentQueue = character; |
||||
|
} else { |
||||
|
subvalue += character; |
||||
|
content += character; |
||||
|
|
||||
|
while (++index < length) { |
||||
|
character = value.charAt(index); |
||||
|
|
||||
|
if (!character || character === C_NEWLINE) { |
||||
|
contentQueue = character; |
||||
|
subvalueQueue = character; |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
subvalue += character; |
||||
|
content += character; |
||||
|
} |
||||
|
} |
||||
|
} else if ( |
||||
|
character === C_SPACE && |
||||
|
value.charAt(index + 1) === character && |
||||
|
value.charAt(index + 2) === character && |
||||
|
value.charAt(index + 3) === character |
||||
|
) { |
||||
|
subvalueQueue += CODE_INDENT; |
||||
|
index += 3; |
||||
|
indent = true; |
||||
|
} else if (character === C_TAB) { |
||||
|
subvalueQueue += character; |
||||
|
indent = true; |
||||
|
} else { |
||||
|
blankQueue = ''; |
||||
|
|
||||
|
while (character === C_TAB || character === C_SPACE) { |
||||
|
blankQueue += character; |
||||
|
character = value.charAt(++index); |
||||
|
} |
||||
|
|
||||
|
if (character !== C_NEWLINE) { |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
subvalueQueue += blankQueue + character; |
||||
|
contentQueue += character; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
if (content) { |
||||
|
if (silent) { |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
return eat(subvalue)({ |
||||
|
type: 'code', |
||||
|
lang: null, |
||||
|
value: trim(content) |
||||
|
}); |
||||
|
} |
||||
|
} |
@ -0,0 +1,120 @@ |
|||||
|
/** |
||||
|
* @author Titus Wormer |
||||
|
* @copyright 2015 Titus Wormer |
||||
|
* @license MIT |
||||
|
* @module remark:parse:tokenize:code-inline |
||||
|
* @fileoverview Tokenise inline code. |
||||
|
*/ |
||||
|
|
||||
|
'use strict'; |
||||
|
|
||||
|
var whitespace = require('is-whitespace-character'); |
||||
|
var locate = require('../locate/code-inline'); |
||||
|
|
||||
|
module.exports = inlineCode; |
||||
|
inlineCode.locator = locate; |
||||
|
|
||||
|
var C_TICK = '`'; |
||||
|
|
||||
|
/* Tokenise inline code. */ |
||||
|
function inlineCode(eat, value, silent) { |
||||
|
var length = value.length; |
||||
|
var index = 0; |
||||
|
var queue = ''; |
||||
|
var tickQueue = ''; |
||||
|
var contentQueue; |
||||
|
var subqueue; |
||||
|
var count; |
||||
|
var openingCount; |
||||
|
var subvalue; |
||||
|
var character; |
||||
|
var found; |
||||
|
var next; |
||||
|
|
||||
|
while (index < length) { |
||||
|
if (value.charAt(index) !== C_TICK) { |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
queue += C_TICK; |
||||
|
index++; |
||||
|
} |
||||
|
|
||||
|
if (!queue) { |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
subvalue = queue; |
||||
|
openingCount = index; |
||||
|
queue = ''; |
||||
|
next = value.charAt(index); |
||||
|
count = 0; |
||||
|
|
||||
|
while (index < length) { |
||||
|
character = next; |
||||
|
next = value.charAt(index + 1); |
||||
|
|
||||
|
if (character === C_TICK) { |
||||
|
count++; |
||||
|
tickQueue += character; |
||||
|
} else { |
||||
|
count = 0; |
||||
|
queue += character; |
||||
|
} |
||||
|
|
||||
|
if (count && next !== C_TICK) { |
||||
|
if (count === openingCount) { |
||||
|
subvalue += queue + tickQueue; |
||||
|
found = true; |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
queue += tickQueue; |
||||
|
tickQueue = ''; |
||||
|
} |
||||
|
|
||||
|
index++; |
||||
|
} |
||||
|
|
||||
|
if (!found) { |
||||
|
if (openingCount % 2 !== 0) { |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
queue = ''; |
||||
|
} |
||||
|
|
||||
|
/* istanbul ignore if - never used (yet) */ |
||||
|
if (silent) { |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
contentQueue = ''; |
||||
|
subqueue = ''; |
||||
|
length = queue.length; |
||||
|
index = -1; |
||||
|
|
||||
|
while (++index < length) { |
||||
|
character = queue.charAt(index); |
||||
|
|
||||
|
if (whitespace(character)) { |
||||
|
subqueue += character; |
||||
|
continue; |
||||
|
} |
||||
|
|
||||
|
if (subqueue) { |
||||
|
if (contentQueue) { |
||||
|
contentQueue += subqueue; |
||||
|
} |
||||
|
|
||||
|
subqueue = ''; |
||||
|
} |
||||
|
|
||||
|
contentQueue += character; |
||||
|
} |
||||
|
|
||||
|
return eat(subvalue)({ |
||||
|
type: 'inlineCode', |
||||
|
value: contentQueue |
||||
|
}); |
||||
|
} |
@ -0,0 +1,287 @@ |
|||||
|
/** |
||||
|
* @author Titus Wormer |
||||
|
* @copyright 2015 Titus Wormer |
||||
|
* @license MIT |
||||
|
* @module remark:parse:tokenize:definition |
||||
|
* @fileoverview Tokenise a definition. |
||||
|
*/ |
||||
|
|
||||
|
'use strict'; |
||||
|
|
||||
|
var whitespace = require('is-whitespace-character'); |
||||
|
var normalize = require('../util/normalize'); |
||||
|
|
||||
|
module.exports = definition; |
||||
|
definition.notInList = true; |
||||
|
definition.notInBlock = true; |
||||
|
|
||||
|
var C_DOUBLE_QUOTE = '"'; |
||||
|
var C_SINGLE_QUOTE = '\''; |
||||
|
var C_BACKSLASH = '\\'; |
||||
|
var C_NEWLINE = '\n'; |
||||
|
var C_TAB = '\t'; |
||||
|
var C_SPACE = ' '; |
||||
|
var C_BRACKET_OPEN = '['; |
||||
|
var C_BRACKET_CLOSE = ']'; |
||||
|
var C_PAREN_OPEN = '('; |
||||
|
var C_PAREN_CLOSE = ')'; |
||||
|
var C_COLON = ':'; |
||||
|
var C_LT = '<'; |
||||
|
var C_GT = '>'; |
||||
|
|
||||
|
/* Tokenise a definition. */ |
||||
|
function definition(eat, value, silent) { |
||||
|
var self = this; |
||||
|
var commonmark = self.options.commonmark; |
||||
|
var index = 0; |
||||
|
var length = value.length; |
||||
|
var subvalue = ''; |
||||
|
var beforeURL; |
||||
|
var beforeTitle; |
||||
|
var queue; |
||||
|
var character; |
||||
|
var test; |
||||
|
var identifier; |
||||
|
var url; |
||||
|
var title; |
||||
|
|
||||
|
while (index < length) { |
||||
|
character = value.charAt(index); |
||||
|
|
||||
|
if (character !== C_SPACE && character !== C_TAB) { |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
subvalue += character; |
||||
|
index++; |
||||
|
} |
||||
|
|
||||
|
character = value.charAt(index); |
||||
|
|
||||
|
if (character !== C_BRACKET_OPEN) { |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
index++; |
||||
|
subvalue += character; |
||||
|
queue = ''; |
||||
|
|
||||
|
while (index < length) { |
||||
|
character = value.charAt(index); |
||||
|
|
||||
|
if (character === C_BRACKET_CLOSE) { |
||||
|
break; |
||||
|
} else if (character === C_BACKSLASH) { |
||||
|
queue += character; |
||||
|
index++; |
||||
|
character = value.charAt(index); |
||||
|
} |
||||
|
|
||||
|
queue += character; |
||||
|
index++; |
||||
|
} |
||||
|
|
||||
|
if ( |
||||
|
!queue || |
||||
|
value.charAt(index) !== C_BRACKET_CLOSE || |
||||
|
value.charAt(index + 1) !== C_COLON |
||||
|
) { |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
identifier = queue; |
||||
|
subvalue += queue + C_BRACKET_CLOSE + C_COLON; |
||||
|
index = subvalue.length; |
||||
|
queue = ''; |
||||
|
|
||||
|
while (index < length) { |
||||
|
character = value.charAt(index); |
||||
|
|
||||
|
if ( |
||||
|
character !== C_TAB && |
||||
|
character !== C_SPACE && |
||||
|
character !== C_NEWLINE |
||||
|
) { |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
subvalue += character; |
||||
|
index++; |
||||
|
} |
||||
|
|
||||
|
character = value.charAt(index); |
||||
|
queue = ''; |
||||
|
beforeURL = subvalue; |
||||
|
|
||||
|
if (character === C_LT) { |
||||
|
index++; |
||||
|
|
||||
|
while (index < length) { |
||||
|
character = value.charAt(index); |
||||
|
|
||||
|
if (!isEnclosedURLCharacter(character)) { |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
queue += character; |
||||
|
index++; |
||||
|
} |
||||
|
|
||||
|
character = value.charAt(index); |
||||
|
|
||||
|
if (character === isEnclosedURLCharacter.delimiter) { |
||||
|
subvalue += C_LT + queue + character; |
||||
|
index++; |
||||
|
} else { |
||||
|
if (commonmark) { |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
index -= queue.length + 1; |
||||
|
queue = ''; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
if (!queue) { |
||||
|
while (index < length) { |
||||
|
character = value.charAt(index); |
||||
|
|
||||
|
if (!isUnclosedURLCharacter(character)) { |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
queue += character; |
||||
|
index++; |
||||
|
} |
||||
|
|
||||
|
subvalue += queue; |
||||
|
} |
||||
|
|
||||
|
if (!queue) { |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
url = queue; |
||||
|
queue = ''; |
||||
|
|
||||
|
while (index < length) { |
||||
|
character = value.charAt(index); |
||||
|
|
||||
|
if ( |
||||
|
character !== C_TAB && |
||||
|
character !== C_SPACE && |
||||
|
character !== C_NEWLINE |
||||
|
) { |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
queue += character; |
||||
|
index++; |
||||
|
} |
||||
|
|
||||
|
character = value.charAt(index); |
||||
|
test = null; |
||||
|
|
||||
|
if (character === C_DOUBLE_QUOTE) { |
||||
|
test = C_DOUBLE_QUOTE; |
||||
|
} else if (character === C_SINGLE_QUOTE) { |
||||
|
test = C_SINGLE_QUOTE; |
||||
|
} else if (character === C_PAREN_OPEN) { |
||||
|
test = C_PAREN_CLOSE; |
||||
|
} |
||||
|
|
||||
|
if (!test) { |
||||
|
queue = ''; |
||||
|
index = subvalue.length; |
||||
|
} else if (queue) { |
||||
|
subvalue += queue + character; |
||||
|
index = subvalue.length; |
||||
|
queue = ''; |
||||
|
|
||||
|
while (index < length) { |
||||
|
character = value.charAt(index); |
||||
|
|
||||
|
if (character === test) { |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
if (character === C_NEWLINE) { |
||||
|
index++; |
||||
|
character = value.charAt(index); |
||||
|
|
||||
|
if (character === C_NEWLINE || character === test) { |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
queue += C_NEWLINE; |
||||
|
} |
||||
|
|
||||
|
queue += character; |
||||
|
index++; |
||||
|
} |
||||
|
|
||||
|
character = value.charAt(index); |
||||
|
|
||||
|
if (character !== test) { |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
beforeTitle = subvalue; |
||||
|
subvalue += queue + character; |
||||
|
index++; |
||||
|
title = queue; |
||||
|
queue = ''; |
||||
|
} else { |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
while (index < length) { |
||||
|
character = value.charAt(index); |
||||
|
|
||||
|
if (character !== C_TAB && character !== C_SPACE) { |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
subvalue += character; |
||||
|
index++; |
||||
|
} |
||||
|
|
||||
|
character = value.charAt(index); |
||||
|
|
||||
|
if (!character || character === C_NEWLINE) { |
||||
|
if (silent) { |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
beforeURL = eat(beforeURL).test().end; |
||||
|
url = self.decode.raw(self.unescape(url), beforeURL); |
||||
|
|
||||
|
if (title) { |
||||
|
beforeTitle = eat(beforeTitle).test().end; |
||||
|
title = self.decode.raw(self.unescape(title), beforeTitle); |
||||
|
} |
||||
|
|
||||
|
return eat(subvalue)({ |
||||
|
type: 'definition', |
||||
|
identifier: normalize(identifier), |
||||
|
title: title || null, |
||||
|
url: url |
||||
|
}); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/* Check if `character` can be inside an enclosed URI. */ |
||||
|
function isEnclosedURLCharacter(character) { |
||||
|
return character !== C_GT && |
||||
|
character !== C_BRACKET_OPEN && |
||||
|
character !== C_BRACKET_CLOSE; |
||||
|
} |
||||
|
|
||||
|
isEnclosedURLCharacter.delimiter = C_GT; |
||||
|
|
||||
|
/* Check if `character` can be inside an unclosed URI. */ |
||||
|
function isUnclosedURLCharacter(character) { |
||||
|
return character !== C_BRACKET_OPEN && |
||||
|
character !== C_BRACKET_CLOSE && |
||||
|
!whitespace(character); |
||||
|
} |
@ -0,0 +1,69 @@ |
|||||
|
/** |
||||
|
* @author Titus Wormer |
||||
|
* @copyright 2015 Titus Wormer |
||||
|
* @license MIT |
||||
|
* @module remark:parse:tokenize:delete |
||||
|
* @fileoverview Tokenise strikethrough. |
||||
|
*/ |
||||
|
|
||||
|
'use strict'; |
||||
|
|
||||
|
var whitespace = require('is-whitespace-character'); |
||||
|
var locate = require('../locate/delete'); |
||||
|
|
||||
|
module.exports = strikethrough; |
||||
|
strikethrough.locator = locate; |
||||
|
|
||||
|
var C_TILDE = '~'; |
||||
|
var DOUBLE = '~~'; |
||||
|
|
||||
|
/* Tokenise strikethrough. */ |
||||
|
function strikethrough(eat, value, silent) { |
||||
|
var self = this; |
||||
|
var character = ''; |
||||
|
var previous = ''; |
||||
|
var preceding = ''; |
||||
|
var subvalue = ''; |
||||
|
var index; |
||||
|
var length; |
||||
|
var now; |
||||
|
|
||||
|
if ( |
||||
|
!self.options.gfm || |
||||
|
value.charAt(0) !== C_TILDE || |
||||
|
value.charAt(1) !== C_TILDE || |
||||
|
whitespace(value.charAt(2)) |
||||
|
) { |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
index = 1; |
||||
|
length = value.length; |
||||
|
now = eat.now(); |
||||
|
now.column += 2; |
||||
|
now.offset += 2; |
||||
|
|
||||
|
while (++index < length) { |
||||
|
character = value.charAt(index); |
||||
|
|
||||
|
if ( |
||||
|
character === C_TILDE && |
||||
|
previous === C_TILDE && |
||||
|
(!preceding || !whitespace(preceding)) |
||||
|
) { |
||||
|
/* istanbul ignore if - never used (yet) */ |
||||
|
if (silent) { |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
return eat(DOUBLE + subvalue + DOUBLE)({ |
||||
|
type: 'delete', |
||||
|
children: self.tokenizeInline(subvalue, now) |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
subvalue += previous; |
||||
|
preceding = previous; |
||||
|
previous = character; |
||||
|
} |
||||
|
} |
@ -0,0 +1,94 @@ |
|||||
|
/** |
||||
|
* @author Titus Wormer |
||||
|
* @copyright 2015 Titus Wormer |
||||
|
* @license MIT |
||||
|
* @module remark:parse:tokenize:emphasis |
||||
|
* @fileoverview Tokenise emphasis. |
||||
|
*/ |
||||
|
|
||||
|
'use strict'; |
||||
|
|
||||
|
var trim = require('trim'); |
||||
|
var word = require('is-word-character'); |
||||
|
var whitespace = require('is-whitespace-character'); |
||||
|
var locate = require('../locate/emphasis'); |
||||
|
|
||||
|
module.exports = emphasis; |
||||
|
emphasis.locator = locate; |
||||
|
|
||||
|
var C_ASTERISK = '*'; |
||||
|
var C_UNDERSCORE = '_'; |
||||
|
|
||||
|
/* Tokenise emphasis. */ |
||||
|
function emphasis(eat, value, silent) { |
||||
|
var self = this; |
||||
|
var index = 0; |
||||
|
var character = value.charAt(index); |
||||
|
var now; |
||||
|
var pedantic; |
||||
|
var marker; |
||||
|
var queue; |
||||
|
var subvalue; |
||||
|
var length; |
||||
|
var prev; |
||||
|
|
||||
|
if (character !== C_ASTERISK && character !== C_UNDERSCORE) { |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
pedantic = self.options.pedantic; |
||||
|
subvalue = character; |
||||
|
marker = character; |
||||
|
length = value.length; |
||||
|
index++; |
||||
|
queue = ''; |
||||
|
character = ''; |
||||
|
|
||||
|
if (pedantic && whitespace(value.charAt(index))) { |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
while (index < length) { |
||||
|
prev = character; |
||||
|
character = value.charAt(index); |
||||
|
|
||||
|
if (character === marker && (!pedantic || !whitespace(prev))) { |
||||
|
character = value.charAt(++index); |
||||
|
|
||||
|
if (character !== marker) { |
||||
|
if (!trim(queue) || prev === marker) { |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
if (!pedantic && marker === C_UNDERSCORE && word(character)) { |
||||
|
queue += marker; |
||||
|
continue; |
||||
|
} |
||||
|
|
||||
|
/* istanbul ignore if - never used (yet) */ |
||||
|
if (silent) { |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
now = eat.now(); |
||||
|
now.column++; |
||||
|
now.offset++; |
||||
|
|
||||
|
return eat(subvalue + queue + marker)({ |
||||
|
type: 'emphasis', |
||||
|
children: self.tokenizeInline(queue, now) |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
queue += marker; |
||||
|
} |
||||
|
|
||||
|
if (!pedantic && character === '\\') { |
||||
|
queue += character; |
||||
|
character = value.charAt(++index); |
||||
|
} |
||||
|
|
||||
|
queue += character; |
||||
|
index++; |
||||
|
} |
||||
|
} |
@ -0,0 +1,43 @@ |
|||||
|
/** |
||||
|
* @author Titus Wormer |
||||
|
* @copyright 2015 Titus Wormer |
||||
|
* @license MIT |
||||
|
* @module remark:parse:tokenize:escape |
||||
|
* @fileoverview Tokenise an escape. |
||||
|
*/ |
||||
|
|
||||
|
'use strict'; |
||||
|
|
||||
|
var locate = require('../locate/escape'); |
||||
|
|
||||
|
module.exports = escape; |
||||
|
escape.locator = locate; |
||||
|
|
||||
|
/* Tokenise an escape. */ |
||||
|
function escape(eat, value, silent) { |
||||
|
var self = this; |
||||
|
var character; |
||||
|
var node; |
||||
|
|
||||
|
if (value.charAt(0) === '\\') { |
||||
|
character = value.charAt(1); |
||||
|
|
||||
|
if (self.escape.indexOf(character) !== -1) { |
||||
|
/* istanbul ignore if - never used (yet) */ |
||||
|
if (silent) { |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
if (character === '\n') { |
||||
|
node = {type: 'break'}; |
||||
|
} else { |
||||
|
node = { |
||||
|
type: 'text', |
||||
|
value: character |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
return eat('\\' + character)(node); |
||||
|
} |
||||
|
} |
||||
|
} |
@ -0,0 +1,194 @@ |
|||||
|
/** |
||||
|
* @author Titus Wormer |
||||
|
* @copyright 2015 Titus Wormer |
||||
|
* @license MIT |
||||
|
* @module remark:parse:tokenize:footnote-definition |
||||
|
* @fileoverview Tokenise footnote definition. |
||||
|
*/ |
||||
|
|
||||
|
'use strict'; |
||||
|
|
||||
|
var whitespace = require('is-whitespace-character'); |
||||
|
var normalize = require('../util/normalize'); |
||||
|
|
||||
|
module.exports = footnoteDefinition; |
||||
|
footnoteDefinition.notInList = true; |
||||
|
footnoteDefinition.notInBlock = true; |
||||
|
|
||||
|
var C_BACKSLASH = '\\'; |
||||
|
var C_NEWLINE = '\n'; |
||||
|
var C_TAB = '\t'; |
||||
|
var C_SPACE = ' '; |
||||
|
var C_BRACKET_OPEN = '['; |
||||
|
var C_BRACKET_CLOSE = ']'; |
||||
|
var C_CARET = '^'; |
||||
|
var C_COLON = ':'; |
||||
|
|
||||
|
var EXPRESSION_INITIAL_TAB = /^( {4}|\t)?/gm; |
||||
|
|
||||
|
/* Tokenise a footnote definition. */ |
||||
|
function footnoteDefinition(eat, value, silent) { |
||||
|
var self = this; |
||||
|
var offsets = self.offset; |
||||
|
var index; |
||||
|
var length; |
||||
|
var subvalue; |
||||
|
var now; |
||||
|
var currentLine; |
||||
|
var content; |
||||
|
var queue; |
||||
|
var subqueue; |
||||
|
var character; |
||||
|
var identifier; |
||||
|
var add; |
||||
|
var exit; |
||||
|
|
||||
|
if (!self.options.footnotes) { |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
index = 0; |
||||
|
length = value.length; |
||||
|
subvalue = ''; |
||||
|
now = eat.now(); |
||||
|
currentLine = now.line; |
||||
|
|
||||
|
while (index < length) { |
||||
|
character = value.charAt(index); |
||||
|
|
||||
|
if (!whitespace(character)) { |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
subvalue += character; |
||||
|
index++; |
||||
|
} |
||||
|
|
||||
|
if ( |
||||
|
value.charAt(index) !== C_BRACKET_OPEN || |
||||
|
value.charAt(index + 1) !== C_CARET |
||||
|
) { |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
subvalue += C_BRACKET_OPEN + C_CARET; |
||||
|
index = subvalue.length; |
||||
|
queue = ''; |
||||
|
|
||||
|
while (index < length) { |
||||
|
character = value.charAt(index); |
||||
|
|
||||
|
if (character === C_BRACKET_CLOSE) { |
||||
|
break; |
||||
|
} else if (character === C_BACKSLASH) { |
||||
|
queue += character; |
||||
|
index++; |
||||
|
character = value.charAt(index); |
||||
|
} |
||||
|
|
||||
|
queue += character; |
||||
|
index++; |
||||
|
} |
||||
|
|
||||
|
if ( |
||||
|
!queue || |
||||
|
value.charAt(index) !== C_BRACKET_CLOSE || |
||||
|
value.charAt(index + 1) !== C_COLON |
||||
|
) { |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
if (silent) { |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
identifier = normalize(queue); |
||||
|
subvalue += queue + C_BRACKET_CLOSE + C_COLON; |
||||
|
index = subvalue.length; |
||||
|
|
||||
|
while (index < length) { |
||||
|
character = value.charAt(index); |
||||
|
|
||||
|
if (character !== C_TAB && character !== C_SPACE) { |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
subvalue += character; |
||||
|
index++; |
||||
|
} |
||||
|
|
||||
|
now.column += subvalue.length; |
||||
|
now.offset += subvalue.length; |
||||
|
queue = ''; |
||||
|
content = ''; |
||||
|
subqueue = ''; |
||||
|
|
||||
|
while (index < length) { |
||||
|
character = value.charAt(index); |
||||
|
|
||||
|
if (character === C_NEWLINE) { |
||||
|
subqueue = character; |
||||
|
index++; |
||||
|
|
||||
|
while (index < length) { |
||||
|
character = value.charAt(index); |
||||
|
|
||||
|
if (character !== C_NEWLINE) { |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
subqueue += character; |
||||
|
index++; |
||||
|
} |
||||
|
|
||||
|
queue += subqueue; |
||||
|
subqueue = ''; |
||||
|
|
||||
|
while (index < length) { |
||||
|
character = value.charAt(index); |
||||
|
|
||||
|
if (character !== C_SPACE) { |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
subqueue += character; |
||||
|
index++; |
||||
|
} |
||||
|
|
||||
|
if (subqueue.length === 0) { |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
queue += subqueue; |
||||
|
} |
||||
|
|
||||
|
if (queue) { |
||||
|
content += queue; |
||||
|
queue = ''; |
||||
|
} |
||||
|
|
||||
|
content += character; |
||||
|
index++; |
||||
|
} |
||||
|
|
||||
|
subvalue += content; |
||||
|
|
||||
|
content = content.replace(EXPRESSION_INITIAL_TAB, function (line) { |
||||
|
offsets[currentLine] = (offsets[currentLine] || 0) + line.length; |
||||
|
currentLine++; |
||||
|
|
||||
|
return ''; |
||||
|
}); |
||||
|
|
||||
|
add = eat(subvalue); |
||||
|
|
||||
|
exit = self.enterBlock(); |
||||
|
content = self.tokenizeBlock(content, now); |
||||
|
exit(); |
||||
|
|
||||
|
return add({ |
||||
|
type: 'footnoteDefinition', |
||||
|
identifier: identifier, |
||||
|
children: content |
||||
|
}); |
||||
|
} |
@ -0,0 +1,150 @@ |
|||||
|
/** |
||||
|
* @author Titus Wormer |
||||
|
* @copyright 2015 Titus Wormer |
||||
|
* @license MIT |
||||
|
* @module remark:parse:tokenize:heading-atx |
||||
|
* @fileoverview Tokenise an ATX-style heading. |
||||
|
*/ |
||||
|
|
||||
|
'use strict'; |
||||
|
|
||||
|
module.exports = atxHeading; |
||||
|
|
||||
|
var C_NEWLINE = '\n'; |
||||
|
var C_TAB = '\t'; |
||||
|
var C_SPACE = ' '; |
||||
|
var C_HASH = '#'; |
||||
|
|
||||
|
var MAX_ATX_COUNT = 6; |
||||
|
|
||||
|
/* Tokenise an ATX-style heading. */ |
||||
|
function atxHeading(eat, value, silent) { |
||||
|
var self = this; |
||||
|
var settings = self.options; |
||||
|
var length = value.length + 1; |
||||
|
var index = -1; |
||||
|
var now = eat.now(); |
||||
|
var subvalue = ''; |
||||
|
var content = ''; |
||||
|
var character; |
||||
|
var queue; |
||||
|
var depth; |
||||
|
|
||||
|
/* Eat initial spacing. */ |
||||
|
while (++index < length) { |
||||
|
character = value.charAt(index); |
||||
|
|
||||
|
if (character !== C_SPACE && character !== C_TAB) { |
||||
|
index--; |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
subvalue += character; |
||||
|
} |
||||
|
|
||||
|
/* Eat hashes. */ |
||||
|
depth = 0; |
||||
|
|
||||
|
while (++index <= length) { |
||||
|
character = value.charAt(index); |
||||
|
|
||||
|
if (character !== C_HASH) { |
||||
|
index--; |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
subvalue += character; |
||||
|
depth++; |
||||
|
} |
||||
|
|
||||
|
if (depth > MAX_ATX_COUNT) { |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
if ( |
||||
|
!depth || |
||||
|
(!settings.pedantic && value.charAt(index + 1) === C_HASH) |
||||
|
) { |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
length = value.length + 1; |
||||
|
|
||||
|
/* Eat intermediate white-space. */ |
||||
|
queue = ''; |
||||
|
|
||||
|
while (++index < length) { |
||||
|
character = value.charAt(index); |
||||
|
|
||||
|
if (character !== C_SPACE && character !== C_TAB) { |
||||
|
index--; |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
queue += character; |
||||
|
} |
||||
|
|
||||
|
/* Exit when not in pedantic mode without spacing. */ |
||||
|
if ( |
||||
|
!settings.pedantic && |
||||
|
queue.length === 0 && |
||||
|
character && |
||||
|
character !== C_NEWLINE |
||||
|
) { |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
if (silent) { |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
/* Eat content. */ |
||||
|
subvalue += queue; |
||||
|
queue = ''; |
||||
|
content = ''; |
||||
|
|
||||
|
while (++index < length) { |
||||
|
character = value.charAt(index); |
||||
|
|
||||
|
if (!character || character === C_NEWLINE) { |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
if ( |
||||
|
character !== C_SPACE && |
||||
|
character !== C_TAB && |
||||
|
character !== C_HASH |
||||
|
) { |
||||
|
content += queue + character; |
||||
|
queue = ''; |
||||
|
continue; |
||||
|
} |
||||
|
|
||||
|
while (character === C_SPACE || character === C_TAB) { |
||||
|
queue += character; |
||||
|
character = value.charAt(++index); |
||||
|
} |
||||
|
|
||||
|
while (character === C_HASH) { |
||||
|
queue += character; |
||||
|
character = value.charAt(++index); |
||||
|
} |
||||
|
|
||||
|
while (character === C_SPACE || character === C_TAB) { |
||||
|
queue += character; |
||||
|
character = value.charAt(++index); |
||||
|
} |
||||
|
|
||||
|
index--; |
||||
|
} |
||||
|
|
||||
|
now.column += subvalue.length; |
||||
|
now.offset += subvalue.length; |
||||
|
subvalue += content + queue; |
||||
|
|
||||
|
return eat(subvalue)({ |
||||
|
type: 'heading', |
||||
|
depth: depth, |
||||
|
children: self.tokenizeInline(content, now) |
||||
|
}); |
||||
|
} |
@ -0,0 +1,116 @@ |
|||||
|
/** |
||||
|
* @author Titus Wormer |
||||
|
* @copyright 2015 Titus Wormer |
||||
|
* @license MIT |
||||
|
* @module remark:parse:tokenize:heading-setext |
||||
|
* @fileoverview Tokenise an setext-style heading. |
||||
|
*/ |
||||
|
|
||||
|
'use strict'; |
||||
|
|
||||
|
module.exports = setextHeading; |
||||
|
|
||||
|
var C_NEWLINE = '\n'; |
||||
|
var C_TAB = '\t'; |
||||
|
var C_SPACE = ' '; |
||||
|
var C_EQUALS = '='; |
||||
|
var C_DASH = '-'; |
||||
|
|
||||
|
var MAX_HEADING_INDENT = 3; |
||||
|
|
||||
|
/* Map of characters which can be used to mark setext |
||||
|
* headers, mapping to their corresponding depth. */ |
||||
|
var SETEXT_MARKERS = {}; |
||||
|
|
||||
|
SETEXT_MARKERS[C_EQUALS] = 1; |
||||
|
SETEXT_MARKERS[C_DASH] = 2; |
||||
|
|
||||
|
/* Tokenise an setext-style heading. */ |
||||
|
function setextHeading(eat, value, silent) { |
||||
|
var self = this; |
||||
|
var now = eat.now(); |
||||
|
var length = value.length; |
||||
|
var index = -1; |
||||
|
var subvalue = ''; |
||||
|
var content; |
||||
|
var queue; |
||||
|
var character; |
||||
|
var marker; |
||||
|
var depth; |
||||
|
|
||||
|
/* Eat initial indentation. */ |
||||
|
while (++index < length) { |
||||
|
character = value.charAt(index); |
||||
|
|
||||
|
if (character !== C_SPACE || index >= MAX_HEADING_INDENT) { |
||||
|
index--; |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
subvalue += character; |
||||
|
} |
||||
|
|
||||
|
/* Eat content. */ |
||||
|
content = ''; |
||||
|
queue = ''; |
||||
|
|
||||
|
while (++index < length) { |
||||
|
character = value.charAt(index); |
||||
|
|
||||
|
if (character === C_NEWLINE) { |
||||
|
index--; |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
if (character === C_SPACE || character === C_TAB) { |
||||
|
queue += character; |
||||
|
} else { |
||||
|
content += queue + character; |
||||
|
queue = ''; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
now.column += subvalue.length; |
||||
|
now.offset += subvalue.length; |
||||
|
subvalue += content + queue; |
||||
|
|
||||
|
/* Ensure the content is followed by a newline and a |
||||
|
* valid marker. */ |
||||
|
character = value.charAt(++index); |
||||
|
marker = value.charAt(++index); |
||||
|
|
||||
|
if (character !== C_NEWLINE || !SETEXT_MARKERS[marker]) { |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
subvalue += character; |
||||
|
|
||||
|
/* Eat Setext-line. */ |
||||
|
queue = marker; |
||||
|
depth = SETEXT_MARKERS[marker]; |
||||
|
|
||||
|
while (++index < length) { |
||||
|
character = value.charAt(index); |
||||
|
|
||||
|
if (character !== marker) { |
||||
|
if (character !== C_NEWLINE) { |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
index--; |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
queue += character; |
||||
|
} |
||||
|
|
||||
|
if (silent) { |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
return eat(subvalue + queue)({ |
||||
|
type: 'heading', |
||||
|
depth: depth, |
||||
|
children: self.tokenizeInline(content, now) |
||||
|
}); |
||||
|
} |
@ -0,0 +1,103 @@ |
|||||
|
/** |
||||
|
* @author Titus Wormer |
||||
|
* @copyright 2015 Titus Wormer |
||||
|
* @license MIT |
||||
|
* @module remark:parse:tokenize:html-block |
||||
|
* @fileoverview Tokenise block HTML. |
||||
|
*/ |
||||
|
|
||||
|
'use strict'; |
||||
|
|
||||
|
var openCloseTag = require('../util/html').openCloseTag; |
||||
|
|
||||
|
module.exports = blockHTML; |
||||
|
|
||||
|
var C_TAB = '\t'; |
||||
|
var C_SPACE = ' '; |
||||
|
var C_NEWLINE = '\n'; |
||||
|
var C_LT = '<'; |
||||
|
|
||||
|
/* Tokenise block HTML. */ |
||||
|
function blockHTML(eat, value, silent) { |
||||
|
var self = this; |
||||
|
var blocks = self.options.blocks; |
||||
|
var length = value.length; |
||||
|
var index = 0; |
||||
|
var next; |
||||
|
var line; |
||||
|
var offset; |
||||
|
var character; |
||||
|
var count; |
||||
|
var sequence; |
||||
|
var subvalue; |
||||
|
|
||||
|
var sequences = [ |
||||
|
[/^<(script|pre|style)(?=(\s|>|$))/i, /<\/(script|pre|style)>/i, true], |
||||
|
[/^<!--/, /-->/, true], |
||||
|
[/^<\?/, /\?>/, true], |
||||
|
[/^<![A-Za-z]/, />/, true], |
||||
|
[/^<!\[CDATA\[/, /\]\]>/, true], |
||||
|
[new RegExp('^</?(' + blocks.join('|') + ')(?=(\\s|/?>|$))', 'i'), /^$/, true], |
||||
|
[new RegExp(openCloseTag.source + '\\s*$'), /^$/, false] |
||||
|
]; |
||||
|
|
||||
|
/* Eat initial spacing. */ |
||||
|
while (index < length) { |
||||
|
character = value.charAt(index); |
||||
|
|
||||
|
if (character !== C_TAB && character !== C_SPACE) { |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
index++; |
||||
|
} |
||||
|
|
||||
|
if (value.charAt(index) !== C_LT) { |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
next = value.indexOf(C_NEWLINE, index + 1); |
||||
|
next = next === -1 ? length : next; |
||||
|
line = value.slice(index, next); |
||||
|
offset = -1; |
||||
|
count = sequences.length; |
||||
|
|
||||
|
while (++offset < count) { |
||||
|
if (sequences[offset][0].test(line)) { |
||||
|
sequence = sequences[offset]; |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
if (!sequence) { |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
if (silent) { |
||||
|
return sequence[2]; |
||||
|
} |
||||
|
|
||||
|
index = next; |
||||
|
|
||||
|
if (!sequence[1].test(line)) { |
||||
|
while (index < length) { |
||||
|
next = value.indexOf(C_NEWLINE, index + 1); |
||||
|
next = next === -1 ? length : next; |
||||
|
line = value.slice(index + 1, next); |
||||
|
|
||||
|
if (sequence[1].test(line)) { |
||||
|
if (line) { |
||||
|
index = next; |
||||
|
} |
||||
|
|
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
index = next; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
subvalue = value.slice(0, index); |
||||
|
|
||||
|
return eat(subvalue)({type: 'html', value: subvalue}); |
||||
|
} |
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue