@deskeen/markdown
Advanced tools
Comparing version 5.0.0 to 5.1.0
# Changelog | ||
## 5.1.0 - 2021-05-20 | ||
**🌟 New** | ||
- `Element.removeChild`, `Element.remove` are added. | ||
## 5.0.0 - 2021-05-05 | ||
@@ -4,0 +9,0 @@ |
{ | ||
"name": "@deskeen/markdown", | ||
"version": "5.0.0", | ||
"version": "5.1.0", | ||
"description": "Node.js Markdown to HTML Parser", | ||
@@ -5,0 +5,0 @@ "author": "Morgan Schmiedt", |
@@ -153,2 +153,4 @@ # Parseur Markdown vers HTML pour Node.js | ||
- `append(...nodesToAppend)`: Insère une liste d'éléments après le dernier enfant. [MDN Docs](https://developer.mozilla.org/fr/docs/Web/API/ParentNode/append) | ||
- `removeChild(child)`: Enlève un élément. [MDN](https://developer.mozilla.org/fr/docs/Web/API/Node/removeChild) | ||
- `remove()`: Enlève un enfant de son parent. [MDN](https://developer.mozilla.org/fr/docs/Web/API/ChildNode/remove) | ||
- `innerHTML`: Retourne la représentation HTML des éléments contenus dans l'élément. [MDN Docs](https://developer.mozilla.org/fr/docs/Web/API/Element/innerHTML) | ||
@@ -155,0 +157,0 @@ - `outerHTML`: Retourne la représentation HTML de l'élément et de ses descendants. [MDN Docs](https://developer.mozilla.org/fr/docs/Web/API/Element/outerHTML) |
@@ -154,2 +154,4 @@ # Node.js Markdown to HTML Parser | ||
- `append(...nodesToAppend)`: Inserts a set of node or text after the last child. [MDN Docs](https://developer.mozilla.org/en-US/docs/Web/API/ParentNode/append) | ||
- `removeChild(child)`: Removes a child. [MDN](https://developer.mozilla.org/en-US/docs/Web/API/Node/removeChild) | ||
- `remove()`: Removes the child from its parent. [MDN](https://developer.mozilla.org/en-US/docs/Web/API/ChildNode/remove) | ||
- `innerHTML`: Returns the HTML markup of the elements contained in the element. [MDN Docs](https://developer.mozilla.org/en-US/docs/Web/API/Element/innerHTML) | ||
@@ -156,0 +158,0 @@ - `outerHTML`: Returns the HTML markup of the element and its descendants.( [MDN Docs](https://developer.mozilla.org/en-US/docs/Web/API/Element/outerHTML) |
'use strict' | ||
const HTML_ENTITY = require('./Entity.js') | ||
const Node = require('./Node.js') | ||
const Text = require('./Text.js') | ||
@@ -24,118 +25,51 @@ | ||
class Element { | ||
class Element extends Node { | ||
constructor(tagName) { | ||
super() | ||
this._symbol = Symbol() | ||
this._tagName = tagName.toUpperCase() | ||
this._attributes = {} | ||
this._children = [] | ||
} | ||
appendChild(node) { | ||
node.parentNode = this | ||
this._children.push(node) | ||
get attributes() { | ||
return this._attributes | ||
} | ||
append(...nodes) { | ||
this._children.push(...nodes.map(node => { | ||
if (typeof node === 'string') { | ||
return new Text(node) | ||
} | ||
return node | ||
})) | ||
get children() { | ||
return this._children | ||
.filter(node => node.constructor.name === 'Element') | ||
} | ||
prepend(...nodes) { | ||
this._children.splice(0, 0, ...nodes.map(node => { | ||
if (typeof node === 'string') { | ||
return new Text(node) | ||
} | ||
return node | ||
})) | ||
set className(value) { | ||
this.setAttribute('class', value) | ||
} | ||
hasAttribute(attributeName) { | ||
return this._attributes[attributeName] !== undefined | ||
get className() { | ||
return this.getAttribute('class') | ||
} | ||
setAttribute(attributeName, attributeValue) { | ||
if (arguments.length < 2) { | ||
throw new TypeError(`Element.setAttribute: At least 2 arguments required, but only ${arguments.length} passed`) | ||
} | ||
const hasForbiddenCharInAttrName = /[<>&"']/.exec(attributeName) != null | ||
if (hasForbiddenCharInAttrName) { | ||
throw new Error('String contains an invalid character') | ||
} | ||
let attrValueText | ||
if (attributeValue === undefined) { | ||
attrValueText = 'undefined' | ||
} else if (attributeValue === null) { | ||
attrValueText = 'null' | ||
} else { | ||
attrValueText = attributeValue.toString() | ||
} | ||
this._attributes[attributeName] = attrValueText | ||
get id() { | ||
return this.getAttribute('id') | ||
} | ||
getAttribute(attributeName) { | ||
return this._attributes[attributeName] || null | ||
set id(value) { | ||
this.setAttribute('id', value) | ||
} | ||
removeAttribute(attributeName) { | ||
delete this._attributes[attributeName] | ||
} | ||
get innerHTML() { | ||
const isVoidElement = VOID_TAGS.has(this.tagName) | ||
get attributes() { | ||
return this._attributes | ||
} | ||
if (isVoidElement) { | ||
return '' | ||
} | ||
// https://dom.spec.whatwg.org/#dom-element-tagname | ||
get tagName() { | ||
return this._tagName | ||
} | ||
let html = '' | ||
// https://dom.spec.whatwg.org/#dom-node-textcontent | ||
// https://developer.mozilla.org/en-US/docs/Web/API/Node/textContent | ||
get textContent() { | ||
let output = '' | ||
for (const child of this._children) { | ||
output += child.textContent | ||
html += child.outerHTML | ||
} | ||
return output | ||
return html | ||
} | ||
set textContent(value) { | ||
if (value == null | ||
|| value.length === 0) { | ||
this._children = [] | ||
} else { | ||
this._children = [new Text(value)] | ||
} | ||
} | ||
get children() { | ||
return this._children | ||
.filter(node => node.constructor.name === 'Element') | ||
} | ||
get childNodes() { | ||
return this._children | ||
} | ||
get firstChild() { | ||
return this._children[0] | ||
} | ||
get lastChild() { | ||
return this._children[this._children.length - 1] | ||
} | ||
get outerHTML() { | ||
@@ -175,34 +109,72 @@ const isVoidElement = VOID_TAGS.has(this.tagName) | ||
get innerHTML() { | ||
const isVoidElement = VOID_TAGS.has(this.tagName) | ||
// https://dom.spec.whatwg.org/#dom-element-tagname | ||
get tagName() { | ||
return this._tagName | ||
} | ||
if (isVoidElement) { | ||
return '' | ||
append(...nodes) { | ||
for (const node of nodes) { | ||
if (typeof node === 'string') { | ||
this.appendChild(new Text(node)) | ||
} else { | ||
this.appendChild(node) | ||
} | ||
} | ||
} | ||
let html = '' | ||
getAttribute(attributeName) { | ||
return this._attributes[attributeName] || null | ||
} | ||
for (const child of this._children) { | ||
html += child.outerHTML | ||
} | ||
return html | ||
hasAttribute(attributeName) { | ||
return this._attributes[attributeName] !== undefined | ||
} | ||
set className(value) { | ||
this.setAttribute('class', value) | ||
prepend(...nodes) { | ||
this._children.splice(0, 0, ...nodes.map(node => { | ||
if (typeof node === 'string') { | ||
return new Text(node) | ||
} | ||
return node | ||
})) | ||
} | ||
get className() { | ||
return this.getAttribute('class') | ||
remove() { | ||
if (this._parentNode == null) { | ||
return | ||
} | ||
return this._parentNode.removeChild(this) | ||
} | ||
get id() { | ||
return this.getAttribute('id') | ||
removeAttribute(attributeName) { | ||
delete this._attributes[attributeName] | ||
} | ||
set id(value) { | ||
this.setAttribute('id', value) | ||
setAttribute(attributeName, attributeValue) { | ||
if (arguments.length < 2) { | ||
throw new TypeError(`Element.setAttribute: At least 2 arguments required, but only ${arguments.length} passed`) | ||
} | ||
const hasForbiddenCharInAttrName = /[<>&"']/.exec(attributeName) != null | ||
if (hasForbiddenCharInAttrName) { | ||
throw new Error('String contains an invalid character') | ||
} | ||
let attrValueText | ||
if (attributeValue === undefined) { | ||
attrValueText = 'undefined' | ||
} else if (attributeValue === null) { | ||
attrValueText = 'null' | ||
} else { | ||
attrValueText = attributeValue.toString() | ||
} | ||
this._attributes[attributeName] = attrValueText | ||
} | ||
// Custom | ||
_attach() { | ||
@@ -209,0 +181,0 @@ for (const child of this._children) { |
@@ -7,14 +7,20 @@ 'use strict' | ||
constructor(text) { | ||
this.data = text.toString() | ||
this._symbol = Symbol() | ||
this._data = text.toString() | ||
this._parentNode = null | ||
} | ||
get textContent() { | ||
return this.data | ||
get outerHTML() { | ||
return this._data.replace(/[&<>]/g, char => HTML_ENTITY[char]) | ||
} | ||
get outerHTML() { | ||
return this.data.replace(/[&<>]/g, char => HTML_ENTITY[char]) | ||
get parentNode() { | ||
return this._parentNode | ||
} | ||
get textContent() { | ||
return this._data | ||
} | ||
} | ||
module.exports = Text |
@@ -40,3 +40,3 @@ 'use strict' | ||
const attr = attrs.substring(cursor) | ||
const match = /^([^=]+)=(?:"([^"]+)"|([^;]+))?/ | ||
const match = /^([^=]+)=(?:"(.+?)"|([^;]+))?/ | ||
.exec(attr) | ||
@@ -191,3 +191,3 @@ | ||
const restLineText = lineText.substring(lineCursor + 1) | ||
const endMatch = /^\[([^\]]*)]\((.+?)(?:\s"(.*)")?\)(?:{(.+?)})?$/ | ||
const endMatch = /^\[(.*?)]\((.+?)(?:\s"(.*)")?\)(?:{(.+?)})?$/ | ||
.exec(restLineText) | ||
@@ -592,3 +592,3 @@ | ||
const regex = remainingText[0] === '(' | ||
? /^\(([^)]+)\)/ | ||
? /^\((.+?)\)/ | ||
: /^(\w+)/ | ||
@@ -648,3 +648,3 @@ const match = regex.exec(remainingText) | ||
} else if (allowLink) { | ||
const endMatch = /([^\]]+)]\(([^)]+)\)/.exec(restLineText) | ||
const endMatch = /(.+?)]\((.+?)\)/.exec(restLineText) | ||
@@ -672,3 +672,3 @@ if (endMatch) { | ||
const restLineText = lineText.substring(lineCursor + 1) | ||
const endMatch = /^\[([^\]]+)]\(([^;)]+)\)(?:{([^}]+)})?/ | ||
const endMatch = /^\[(.+?)]\(([^;)]+)\)(?:{(.+?)})?/ | ||
.exec(restLineText) | ||
@@ -675,0 +675,0 @@ |
@@ -12,2 +12,3 @@ 'use strict' | ||
const Element = parser.Element | ||
const Text = parser.Text | ||
@@ -295,1 +296,60 @@ test('Element tagName', function (t) { | ||
}) | ||
test('Element.removeChild', function (t) { | ||
t.throws(() => { | ||
new Element('p').removeChild() | ||
}, TypeError, 'Node.removeChild: At least 1 argument required, but only 0 passed') | ||
t.throws(() => { | ||
new Element('p').removeChild(new Element('div')) | ||
}, Error, 'Node.removeChild: The node to be removed is not a child of this node') | ||
const el0 = new Element('div') | ||
el0.appendChild(new Element('p')) | ||
t.throws(() => { | ||
el0.removeChild(new Element('p')) | ||
}, Error, 'Node.removeChild: The node to be removed is not a child of this node') | ||
const elChild1 = new Element('p') | ||
elChild1.textContent = 'Child 1' | ||
const elChild2 = new Element('p') | ||
elChild2.textContent = 'Child 2' | ||
const el = new Element('div') | ||
el.appendChild(elChild1) | ||
el.appendChild(elChild2) | ||
const removedChild = el.removeChild(elChild2) | ||
t.equal(el.childNodes.length, 1, 'Child is removed') | ||
t.equal(el.lastChild.textContent, 'Child 1', 'Remaining child is valid') | ||
t.equal(elChild2.parentNode, null, 'Removed child parentNode is null') | ||
t.equal(removedChild.textContent, 'Child 2', 'return value is valid') | ||
const textChild = new Text('Text 1') | ||
el.appendChild(textChild) | ||
t.equal(el.lastChild.textContent, 'Text 1', 'Text Element added') | ||
el.removeChild(textChild) | ||
t.equal(el.lastChild.textContent, 'Child 1', 'Text Element removed') | ||
t.end() | ||
}) | ||
test('Element.remove', function (t) { | ||
t.equal(new Element('p').remove(), undefined, 'no return value if no parent') | ||
const elChild1 = new Element('p') | ||
elChild1.textContent = 'Child 1' | ||
const elChild2 = new Element('p') | ||
elChild2.textContent = 'Child 2' | ||
const el = new Element('div') | ||
el.appendChild(elChild1) | ||
el.appendChild(elChild2) | ||
const removedChild = elChild2.remove() | ||
t.equal(el.childNodes.length, 1, 'Child is removed') | ||
t.equal(el.firstChild.textContent, 'Child 1', 'Remaining child is valid') | ||
t.equal(elChild2.parentNode, null, 'Remaining child parentNode is null') | ||
t.equal(removedChild.textContent, 'Child 2', 'return value is valid') | ||
t.end() | ||
}) |
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
164670
35
3201
916