markdown-it-attrs
Advanced tools
Comparing version 4.1.3 to 4.1.4
@@ -9,3 +9,3 @@ { | ||
}, | ||
"extends": "eslint:recommended", | ||
"extends": [ "eslint:recommended" ], | ||
"rules": { | ||
@@ -33,4 +33,15 @@ "indent": [ | ||
], | ||
"no-var": "error" | ||
"no-var": "error", | ||
"prefer-const": "error", | ||
"no-else-return": "error", | ||
"default-case": "error", | ||
"consistent-return": "error", | ||
"no-restricted-syntax": [ | ||
"error", | ||
{ | ||
"selector": "ForInStatement", | ||
"message": "for..in loops iterate over the entire prototype chain. Use Object.{keys,values,entries}." | ||
} | ||
] | ||
} | ||
} |
@@ -7,3 +7,3 @@ /* eslint-env es6 */ | ||
let src = `header1 | header2 | ||
const src = `header1 | header2 | ||
------- | ------- | ||
@@ -15,4 +15,4 @@ column1 | column2 | ||
let res = md.render(src); | ||
const res = md.render(src); | ||
console.log(res); // eslint-disable-line |
@@ -1,3 +0,3 @@ | ||
let md = require('markdown-it')(); | ||
let markdownItAttrs = require('markdown-it-attrs'); | ||
const md = require('markdown-it')(); | ||
const markdownItAttrs = require('markdown-it-attrs'); | ||
@@ -4,0 +4,0 @@ md.use(markdownItAttrs); |
24
index.js
@@ -18,10 +18,10 @@ 'use strict'; | ||
function curlyAttrs(state) { | ||
let tokens = state.tokens; | ||
const tokens = state.tokens; | ||
for (let i = 0; i < tokens.length; i++) { | ||
for (let p = 0; p < patterns.length; p++) { | ||
let pattern = patterns[p]; | ||
const pattern = patterns[p]; | ||
let j = null; // position of child with offset 0 | ||
let match = pattern.tests.every(t => { | ||
let res = test(tokens, i, t); | ||
const match = pattern.tests.every(t => { | ||
const res = test(tokens, i, t); | ||
if (res.j !== null) { j = res.j; } | ||
@@ -53,3 +53,3 @@ return res.match; | ||
function test(tokens, i, t) { | ||
let res = { | ||
const res = { | ||
match: false, | ||
@@ -59,3 +59,3 @@ j: null // position of child | ||
let ii = t.shift !== undefined | ||
const ii = t.shift !== undefined | ||
? i + t.shift | ||
@@ -69,3 +69,3 @@ : t.position; | ||
let token = get(tokens, ii); // supports negative ii | ||
const token = get(tokens, ii); // supports negative ii | ||
@@ -75,3 +75,3 @@ | ||
for (let key in t) { | ||
for (const key of Object.keys(t)) { | ||
if (key === 'shift' || key === 'position') { continue; } | ||
@@ -86,4 +86,4 @@ | ||
let match; | ||
let childTests = t.children; | ||
let children = token.children; | ||
const childTests = t.children; | ||
const children = token.children; | ||
if (childTests.every(tt => tt.position !== undefined)) { | ||
@@ -94,3 +94,3 @@ // positions instead of shifts, do not loop all children | ||
// we may need position of child in transform | ||
let j = last(childTests).position; | ||
const j = last(childTests).position; | ||
res.j = j >= 0 ? j : children.length + j; | ||
@@ -125,3 +125,3 @@ } | ||
if (isArrayOfFunctions(t[key])) { | ||
let r = t[key].every(tt => tt(token[key])); | ||
const r = t[key].every(tt => tt(token[key])); | ||
if (r === false) { return res; } | ||
@@ -128,0 +128,0 @@ break; |
@@ -84,3 +84,5 @@ (function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.markdownItAttrs = f()}})(function(){var define,module,exports;return (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){ | ||
var _loop2 = function _loop2(key) { | ||
var _loop2 = function _loop2() { | ||
var key = _Object$keys[_i]; | ||
if (key === 'shift' || key === 'position') { | ||
@@ -202,4 +204,4 @@ return "continue"; | ||
for (var key in t) { | ||
var _ret = _loop2(key); | ||
for (var _i = 0, _Object$keys = Object.keys(t); _i < _Object$keys.length; _i++) { | ||
var _ret = _loop2(); | ||
@@ -569,3 +571,4 @@ if (_ret === "continue") continue; | ||
},{"./utils.js":3}],3:[function(require,module,exports){ | ||
'use strict'; | ||
"use strict"; | ||
/** | ||
@@ -577,3 +580,2 @@ * parse {.class #id key=val} strings | ||
*/ | ||
exports.getAttrs = function (str, start, options) { | ||
@@ -680,5 +682,5 @@ // not tab, line feed, form feed, space, solidus, greater than sign, quotation mark, apostrophe and equals sign | ||
}); | ||
} else { | ||
return attrs; | ||
} | ||
return attrs; | ||
}; | ||
@@ -712,7 +714,6 @@ /** | ||
* start: '{.a} asdf' | ||
* middle: 'a{.b}c' | ||
* end: 'asdf {.a}' | ||
* only: '{.a}' | ||
* | ||
* @param {string} where to expect {} curly. start, middle, end or only. | ||
* @param {string} where to expect {} curly. start, end or only. | ||
* @return {function(string)} Function which testes if string has curly. | ||
@@ -724,3 +725,3 @@ */ | ||
if (!where) { | ||
throw new Error('Parameter `where` not passed. Should be "start", "middle", "end" or "only".'); | ||
throw new Error('Parameter `where` not passed. Should be "start", "end" or "only".'); | ||
} | ||
@@ -779,2 +780,5 @@ /** | ||
break; | ||
default: | ||
throw new Error("Unexpected case ".concat(where, ", expected 'start', 'end' or 'only'")); | ||
} | ||
@@ -833,2 +837,4 @@ | ||
} | ||
return false; | ||
}; | ||
@@ -835,0 +841,0 @@ /** |
{ | ||
"name": "markdown-it-attrs", | ||
"version": "4.1.3", | ||
"version": "4.1.4", | ||
"description": "Add classes, identifiers and attributes to your markdown with {} curly brackets, similar to pandoc's header attributes", | ||
@@ -45,3 +45,3 @@ "main": "index.js", | ||
"eslint": "^8.4.1", | ||
"markdown-it": "^12.2.0", | ||
"markdown-it": "^13.0.1", | ||
"markdown-it-implicit-figures": "^0.9.0", | ||
@@ -53,5 +53,5 @@ "markdown-it-katex": "^2.0.3", | ||
"peerDependencies": { | ||
"markdown-it": ">= 9.0.0 < 13.0.0" | ||
"markdown-it": ">= 9.0.0" | ||
}, | ||
"tonicExampleFilename": "demo.js" | ||
} |
@@ -31,5 +31,5 @@ 'use strict'; | ||
transform: (tokens, i) => { | ||
let token = tokens[i]; | ||
let start = token.info.lastIndexOf(options.leftDelimiter); | ||
let attrs = utils.getAttrs(token.info, start, options); | ||
const token = tokens[i]; | ||
const start = token.info.lastIndexOf(options.leftDelimiter); | ||
const attrs = utils.getAttrs(token.info, start, options); | ||
utils.addAttrs(attrs, token); | ||
@@ -63,6 +63,6 @@ token.info = utils.removeDelimiter(token.info, options); | ||
transform: (tokens, i, j) => { | ||
let token = tokens[i].children[j]; | ||
let endChar = token.content.indexOf(options.rightDelimiter); | ||
let attrToken = tokens[i].children[j - 1]; | ||
let attrs = utils.getAttrs(token.content, 0, options); | ||
const token = tokens[i].children[j]; | ||
const endChar = token.content.indexOf(options.rightDelimiter); | ||
const attrToken = tokens[i].children[j - 1]; | ||
const attrs = utils.getAttrs(token.content, 0, options); | ||
utils.addAttrs(attrs, attrToken); | ||
@@ -100,5 +100,5 @@ if (token.content.length === (endChar + options.rightDelimiter.length)) { | ||
transform: (tokens, i) => { | ||
let token = tokens[i + 2]; | ||
let tableOpen = utils.getMatchingOpeningToken(tokens, i); | ||
let attrs = utils.getAttrs(token.content, 0, options); | ||
const token = tokens[i + 2]; | ||
const tableOpen = utils.getMatchingOpeningToken(tokens, i); | ||
const attrs = utils.getAttrs(token.content, 0, options); | ||
// add attributes | ||
@@ -131,6 +131,6 @@ utils.addAttrs(attrs, tableOpen); | ||
transform: (tokens, i, j) => { | ||
let token = tokens[i].children[j]; | ||
let content = token.content; | ||
let attrs = utils.getAttrs(content, 0, options); | ||
let openingToken = utils.getMatchingOpeningToken(tokens[i].children, j - 1); | ||
const token = tokens[i].children[j]; | ||
const content = token.content; | ||
const attrs = utils.getAttrs(content, 0, options); | ||
const openingToken = utils.getMatchingOpeningToken(tokens[i].children, j - 1); | ||
utils.addAttrs(attrs, openingToken); | ||
@@ -165,5 +165,5 @@ token.content = content.slice(content.indexOf(options.rightDelimiter) + options.rightDelimiter.length); | ||
transform: (tokens, i, j) => { | ||
let token = tokens[i].children[j]; | ||
let content = token.content; | ||
let attrs = utils.getAttrs(content, 0, options); | ||
const token = tokens[i].children[j]; | ||
const content = token.content; | ||
const attrs = utils.getAttrs(content, 0, options); | ||
let ii = i - 2; | ||
@@ -207,6 +207,6 @@ while (tokens[ii - 1] && | ||
transform: (tokens, i) => { | ||
let token = tokens[i + 2]; | ||
let content = token.content; | ||
let attrs = utils.getAttrs(content, 0, options); | ||
let openingToken = utils.getMatchingOpeningToken(tokens, i); | ||
const token = tokens[i + 2]; | ||
const content = token.content; | ||
const attrs = utils.getAttrs(content, 0, options); | ||
const openingToken = utils.getMatchingOpeningToken(tokens, i); | ||
utils.addAttrs(attrs, openingToken); | ||
@@ -237,7 +237,7 @@ tokens.splice(i + 1, 3); | ||
transform: (tokens, i, j) => { | ||
let token = tokens[i].children[j]; | ||
let content = token.content; | ||
let attrs = utils.getAttrs(content, content.lastIndexOf(options.leftDelimiter), options); | ||
const token = tokens[i].children[j]; | ||
const content = token.content; | ||
const attrs = utils.getAttrs(content, content.lastIndexOf(options.leftDelimiter), options); | ||
utils.addAttrs(attrs, tokens[i - 2]); | ||
let trimmed = content.slice(0, content.lastIndexOf(options.leftDelimiter)); | ||
const trimmed = content.slice(0, content.lastIndexOf(options.leftDelimiter)); | ||
token.content = last(trimmed) !== ' ' ? | ||
@@ -269,8 +269,8 @@ trimmed : trimmed.slice(0, -1); | ||
transform: (tokens, i, j) => { | ||
let token = tokens[i].children[j]; | ||
let attrs = utils.getAttrs(token.content, 0, options); | ||
const token = tokens[i].children[j]; | ||
const attrs = utils.getAttrs(token.content, 0, options); | ||
// find last closing tag | ||
let ii = i + 1; | ||
while (tokens[ii + 1] && tokens[ii + 1].nesting === -1) { ii++; } | ||
let openingToken = utils.getMatchingOpeningToken(tokens, ii); | ||
const openingToken = utils.getMatchingOpeningToken(tokens, ii); | ||
utils.addAttrs(attrs, openingToken); | ||
@@ -301,9 +301,9 @@ tokens[i].children = tokens[i].children.slice(0, -2); | ||
transform: (tokens, i) => { | ||
let token = tokens[i]; | ||
const token = tokens[i]; | ||
token.type = 'hr'; | ||
token.tag = 'hr'; | ||
token.nesting = 0; | ||
let content = tokens[i + 1].content; | ||
let start = content.lastIndexOf(options.leftDelimiter); | ||
let attrs = utils.getAttrs(content, start, options); | ||
const content = tokens[i + 1].content; | ||
const start = content.lastIndexOf(options.leftDelimiter); | ||
const attrs = utils.getAttrs(content, start, options); | ||
utils.addAttrs(attrs, token); | ||
@@ -332,10 +332,10 @@ token.markup = content; | ||
transform: (tokens, i, j) => { | ||
let token = tokens[i].children[j]; | ||
let content = token.content; | ||
let attrs = utils.getAttrs(content, content.lastIndexOf(options.leftDelimiter), options); | ||
const token = tokens[i].children[j]; | ||
const content = token.content; | ||
const attrs = utils.getAttrs(content, content.lastIndexOf(options.leftDelimiter), options); | ||
let ii = i + 1; | ||
while (tokens[ii + 1] && tokens[ii + 1].nesting === -1) { ii++; } | ||
let openingToken = utils.getMatchingOpeningToken(tokens, ii); | ||
const openingToken = utils.getMatchingOpeningToken(tokens, ii); | ||
utils.addAttrs(attrs, openingToken); | ||
let trimmed = content.slice(0, content.lastIndexOf(options.leftDelimiter)); | ||
const trimmed = content.slice(0, content.lastIndexOf(options.leftDelimiter)); | ||
token.content = last(trimmed) !== ' ' ? | ||
@@ -342,0 +342,0 @@ trimmed : trimmed.slice(0, -1); |
@@ -1,5 +0,19 @@ | ||
# markdown-it-attrs [![Build Status](https://travis-ci.org/arve0/markdown-it-attrs.svg?branch=master)](https://travis-ci.org/arve0/markdown-it-attrs) [![npm version](https://badge.fury.io/js/markdown-it-attrs.svg)](http://badge.fury.io/js/markdown-it-attrs) [![Coverage Status](https://coveralls.io/repos/github/arve0/markdown-it-attrs/badge.svg?branch=master)](https://coveralls.io/github/arve0/markdown-it-attrs?branch=master) | ||
# markdown-it-attrs [![Build Status](https://travis-ci.org/arve0/markdown-it-attrs.svg?branch=master)](https://travis-ci.org/arve0/markdown-it-attrs) [![npm version](https://badge.fury.io/js/markdown-it-attrs.svg)](http://badge.fury.io/js/markdown-it-attrs) [![Coverage Status](https://coveralls.io/repos/github/arve0/markdown-it-attrs/badge.svg?branch=master)](https://coveralls.io/github/arve0/markdown-it-attrs?branch=master) <!-- omit in toc --> | ||
Add classes, identifiers and attributes to your markdown with `{.class #identifier attr=value attr2="spaced value"}` curly brackets, similar to [pandoc's header attributes](http://pandoc.org/README.html#extension-header_attributes). | ||
# Table of contents <!-- omit in toc --> | ||
- [Examples](#examples) | ||
- [Install](#install) | ||
- [Support](#support) | ||
- [Usage](#usage) | ||
- [Security](#security) | ||
- [Limitations](#limitations) | ||
- [Ambiguity](#ambiguity) | ||
- [Custom rendering](#custom-rendering) | ||
- [Custom blocks](#custom-blocks) | ||
- [Custom delimiters](#custom-delimiters) | ||
- [Development](#development) | ||
- [License](#license) | ||
## Examples | ||
Example input: | ||
@@ -69,3 +83,12 @@ ```md | ||
## Support | ||
Library is considered done from my part. I'm maintaining it with bug fixes and | ||
security updates. | ||
I'll approve pull requests that are easy to understand. Generally not willing | ||
merge pull requests that increase maintainance complexity. Feel free to open | ||
anyhow and I'll give my feedback. | ||
If you need some extra features, I'm available for hire. | ||
## Usage | ||
@@ -118,2 +141,28 @@ | ||
## Limitations | ||
markdown-it-attrs relies on markdown parsing in markdown-it, which means some | ||
special cases are not possible to fix. Like using `_` outside and inside | ||
attributes: | ||
```md | ||
_i want [all of this](/link){target="_blank"} to be italics_ | ||
``` | ||
Above example will render to: | ||
```html | ||
<p>_i want <a href="/link">all of this</a>{target="<em>blank"} to be italics</em></p> | ||
``` | ||
...which is probably not what you wanted. Of course, you could use `*` for | ||
italics to solve this parsing issue: | ||
```md | ||
*i want [all of this](/link){target="_blank"} to be italics* | ||
``` | ||
Output: | ||
```html | ||
<p><em>i want <a href="/link" target="_blank">all of this</a> to be italics</em></p> | ||
``` | ||
## Ambiguity | ||
@@ -272,4 +321,29 @@ When class can be applied to both inline or block element, inline element will take precedence: | ||
## Development | ||
Tests are in [test.js](./test.js). | ||
Run all tests: | ||
```sh | ||
npm test | ||
``` | ||
Run particular test: | ||
```sh | ||
npm test -- -g "not crash" | ||
``` | ||
In tests, use helper function `replaceDelimiters` to make test run with | ||
different delimiters (`{}`, `[]` and `[[]]`). | ||
For easy access to HTML output you can use [debug.js](./debug.js): | ||
```sh | ||
node debug.js # will print HTML output | ||
``` | ||
Please do **not** submit pull requests with changes in package version or built | ||
files like browser.js. | ||
## License | ||
MIT © [Arve Seljebu](http://arve0.github.io/) |
45
utils.js
@@ -1,2 +0,1 @@ | ||
'use strict'; | ||
/** | ||
@@ -30,3 +29,3 @@ * parse {.class #id key=val} strings | ||
} | ||
let char_ = str.charAt(i); | ||
const char_ = str.charAt(i); | ||
@@ -95,6 +94,6 @@ // switch to reading value if equal sign | ||
if (options.allowedAttributes && options.allowedAttributes.length) { | ||
let allowedAttributes = options.allowedAttributes; | ||
const allowedAttributes = options.allowedAttributes; | ||
return attrs.filter(function (attrPair) { | ||
let attr = attrPair[0]; | ||
const attr = attrPair[0]; | ||
@@ -110,5 +109,5 @@ function isAllowedAttribute (allowedAttribute) { | ||
} else { | ||
return attrs; | ||
} | ||
return attrs; | ||
}; | ||
@@ -124,3 +123,3 @@ | ||
for (let j = 0, l = attrs.length; j < l; ++j) { | ||
let key = attrs[j][0]; | ||
const key = attrs[j][0]; | ||
if (key === 'class') { | ||
@@ -141,7 +140,6 @@ token.attrJoin('class', attrs[j][1]); | ||
* start: '{.a} asdf' | ||
* middle: 'a{.b}c' | ||
* end: 'asdf {.a}' | ||
* only: '{.a}' | ||
* | ||
* @param {string} where to expect {} curly. start, middle, end or only. | ||
* @param {string} where to expect {} curly. start, end or only. | ||
* @return {function(string)} Function which testes if string has curly. | ||
@@ -152,3 +150,3 @@ */ | ||
if (!where) { | ||
throw new Error('Parameter `where` not passed. Should be "start", "middle", "end" or "only".'); | ||
throw new Error('Parameter `where` not passed. Should be "start", "end" or "only".'); | ||
} | ||
@@ -162,3 +160,3 @@ | ||
// we need minimum three chars, for example {b} | ||
let minCurlyLength = options.leftDelimiter.length + 1 + options.rightDelimiter.length; | ||
const minCurlyLength = options.leftDelimiter.length + 1 + options.rightDelimiter.length; | ||
if (!str || typeof str !== 'string' || str.length < minCurlyLength) { | ||
@@ -169,4 +167,4 @@ return false; | ||
function validCurlyLength (curly) { | ||
let isClass = curly.charAt(options.leftDelimiter.length) === '.'; | ||
let isId = curly.charAt(options.leftDelimiter.length) === '#'; | ||
const isClass = curly.charAt(options.leftDelimiter.length) === '.'; | ||
const isId = curly.charAt(options.leftDelimiter.length) === '#'; | ||
return (isClass || isId) | ||
@@ -178,3 +176,3 @@ ? curly.length >= (minCurlyLength + 1) | ||
let start, end, slice, nextChar; | ||
let rightDelimiterMinimumShift = minCurlyLength - options.rightDelimiter.length; | ||
const rightDelimiterMinimumShift = minCurlyLength - options.rightDelimiter.length; | ||
switch (where) { | ||
@@ -207,2 +205,5 @@ case 'start': | ||
break; | ||
default: | ||
throw new Error(`Unexpected case ${where}, expected 'start', 'end' or 'only'`); | ||
} | ||
@@ -221,6 +222,6 @@ | ||
let curly = new RegExp( | ||
const curly = new RegExp( | ||
'[ \\n]?' + start + '[^' + start + end + ']+' + end + '$' | ||
); | ||
let pos = str.search(curly); | ||
const pos = str.search(curly); | ||
@@ -254,4 +255,4 @@ return pos !== -1 ? str.slice(0, pos) : str; | ||
let level = tokens[i].level; | ||
let type = tokens[i].type.replace('_close', '_open'); | ||
const level = tokens[i].level; | ||
const type = tokens[i].type.replace('_close', '_open'); | ||
@@ -263,2 +264,4 @@ for (; i >= 0; --i) { | ||
} | ||
return false; | ||
}; | ||
@@ -270,5 +273,5 @@ | ||
*/ | ||
let HTML_ESCAPE_TEST_RE = /[&<>"]/; | ||
let HTML_ESCAPE_REPLACE_RE = /[&<>"]/g; | ||
let HTML_REPLACEMENTS = { | ||
const HTML_ESCAPE_TEST_RE = /[&<>"]/; | ||
const HTML_ESCAPE_REPLACE_RE = /[&<>"]/g; | ||
const HTML_REPLACEMENTS = { | ||
'&': '&', | ||
@@ -275,0 +278,0 @@ '<': '<', |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
57525
1502
347