als-replace-between
Advanced tools
Comparing version 3.3.1 to 3.5.0
@@ -9,3 +9,2 @@ const TextNode = require('./text-node') | ||
set inner(value) {this.children = []; this.children.push(new TextNode(value,this))} | ||
walkNodes(modifiers=[],parent = this) { | ||
@@ -18,3 +17,2 @@ parent.children.forEach(child => { | ||
} | ||
walkTextNodes(modifiers=[],parent = this) { | ||
@@ -26,3 +24,2 @@ parent.children.forEach(child => { | ||
} | ||
walk(modifiers=[],parent = this) { | ||
@@ -35,3 +32,2 @@ parent.children.forEach(child => { | ||
} | ||
runModifiers(modifiers,child,isNode) { | ||
@@ -38,0 +34,0 @@ for(const modifier of modifiers) { |
@@ -17,3 +17,2 @@ function buildTree(starts, ends) { | ||
pairs.sort((a, b) => a.end.n - b.end.n); | ||
pairs.forEach((curPair, i) => { | ||
@@ -28,3 +27,2 @@ for (let k = i; k < pairs.length; k++) { | ||
}); | ||
function filterPairs(pairs, curLevel = 0) { | ||
@@ -41,2 +39,3 @@ pairs = pairs.filter(({ level }) => (!level || level <= curLevel)) | ||
} | ||
module.exports = buildTree |
@@ -1,14 +0,14 @@ | ||
function find(string, r, add, offset = 0) { | ||
function find(string, r, offset = 0) { | ||
const arr = [] | ||
let curString = string | ||
while (true) { | ||
const match = string.match(r) | ||
const match = curString.match(r) | ||
if (!match) break | ||
offset += match.index + 1 | ||
const n = add < 0 ? add : add * (match[0].length - 1) | ||
arr.push({n:offset + n,length:match[0].length}) | ||
string = string.slice(match.index + 1) | ||
const length = match[0].length | ||
arr.push({n:offset+match.index,length}) | ||
offset = offset+match.index+length | ||
curString = string.slice(offset) | ||
} | ||
return arr | ||
} | ||
module.exports = find |
@@ -18,7 +18,6 @@ const buildTree = require('./build-tree') | ||
} | ||
build() { | ||
const { content, startR, endR } = this | ||
const starts = find(content, startR, -1) | ||
const ends = find(content, endR, 1) | ||
const starts = find(content, startR) | ||
const ends = find(content, endR) | ||
if(starts.length === 0 || ends.length === 0) return | ||
@@ -28,5 +27,5 @@ const children = buildTree(starts, ends) | ||
const start = children[0].start.n | ||
const end = children[children.length - 1].end.n | ||
const {n:end,length:endLength} = children[children.length - 1].end | ||
this.before = start > 0 ? content.slice(0, start) : '' | ||
this.after = end < content.length ? content.slice(end, content.length) : '' | ||
this.after = end + endLength < content.length ? content.slice(end+endLength, content.length) : '' | ||
children.forEach((child,i) => { | ||
@@ -36,4 +35,4 @@ this.children.push(new Node(this, child, this)) | ||
const nextStart = children[i+1].start.n | ||
const curendEnd = child.end.n | ||
if(nextStart !== curendEnd) { | ||
const curendEnd = child.end.n+child.end.length | ||
if(nextStart > curendEnd) { | ||
this.children.push(new TextNode(content.slice(curendEnd,nextStart),this)) | ||
@@ -40,0 +39,0 @@ } |
@@ -12,7 +12,6 @@ const TextNode = require('./text-node') | ||
} | ||
addChildren(obj) { | ||
const { start, end, children } = obj | ||
const root = this.root | ||
let curStart = start.n + start.length, curEnd = end.n - end.length | ||
let curStart = start.n + start.length, curEnd = end.n | ||
this.open = root.content.slice(start.n, curStart) | ||
@@ -22,9 +21,8 @@ children.forEach((child,i) => { | ||
this.children.push(new Node(root, child, this)) | ||
curStart = child.end.n | ||
curStart = child.end.n+child.end.length | ||
}); | ||
if(curEnd > curStart) this.children.push(new TextNode(root.content.slice(curStart,curEnd),this)) | ||
this.close = root.content.slice(curEnd, end.n) | ||
this.close = root.content.slice(curEnd, end.n+end.length) | ||
return this | ||
} | ||
get outer() {return this.open + this.inner + this.close} | ||
@@ -31,0 +29,0 @@ set outer(value) {this.inner = value; this.open = ''; this.close = ''} |
{ | ||
"name": "als-replace-between", | ||
"version": "3.3.1", | ||
"version": "3.5.0", | ||
"main": "index.js", | ||
@@ -5,0 +5,0 @@ "scripts": { |
const ReplaceBetween = (function() { | ||
class BaseNode { constructor() {this.children = []} get outer() { return this.before + this.inner + this.after } get inner() {return this.children.map(child => child.outer).join('')} set outer(value) {this.inner = value; this.before = ''; this.after = ''} set inner(value) {this.children = []; this.children.push(new TextNode(value,this))} walkNodes(modifiers=[],parent = this) { parent.children.forEach(child => { if(child instanceof BaseNode === false) return this.walkNodes(modifiers,child) this.runModifiers(modifiers,child,true) }); } walkTextNodes(modifiers=[],parent = this) { parent.children.forEach(child => { if(child instanceof BaseNode) this.walkTextNodes(modifiers,child) else this.runModifiers(modifiers,child,false) }); } walk(modifiers=[],parent = this) { parent.children.forEach(child => { const isNode = child instanceof BaseNode if(isNode) this.walk(modifiers,child) this.runModifiers(modifiers,child,isNode) }); } runModifiers(modifiers,child,isNode) { for(const modifier of modifiers) { const result = modifier(child,isNode) if(result === false) return false } } } | ||
function buildTree(starts, ends) { if(starts[0].n > ends[0].n) ends.shift() if(starts[starts.length-1].n > ends[ends.length-1].n) starts.pop() if (starts.length !== ends.length) throw new Error(`Parsing error: unmatched tags detected. (${starts.length},${ends.length})`); let pairs = starts.map((start, i) => ({ start, end: ends[i], children: [] })); pairs.forEach((curPair, i) => { for (let k = i; k < pairs.length; k++) { if (curPair.end.n > pairs[k].start.n) { const end = pairs[k].end const curEnd = curPair.end curPair.end = end pairs[k].end = curEnd } } }) pairs.sort((a, b) => a.end.n - b.end.n); pairs.forEach((curPair, i) => { for (let k = i; k < pairs.length; k++) { if (curPair.start.n > pairs[k].start.n && curPair.end.n < pairs[k].end.n) { if (!curPair.level) curPair.level = 0 curPair.level++ pairs[k].children.push(curPair) } } }); function filterPairs(pairs, curLevel = 0) { pairs = pairs.filter(({ level }) => (!level || level <= curLevel)) pairs.forEach(pair => { if (pair.children.length === 0) return pair.children = filterPairs(pair.children, curLevel + 1) }); return pairs } pairs = filterPairs(pairs) return pairs } | ||
function find(string, r, add, offset = 0) { const arr = [] while (true) { const match = string.match(r) if (!match) break offset += match.index + 1 const n = add < 0 ? add : add * (match[0].length - 1) arr.push({n:offset + n,length:match[0].length}) string = string.slice(match.index + 1) } return arr } | ||
class ReplaceBetween extends BaseNode { constructor(content, startR, endR) { super() if (typeof content !== 'string') throw `Expected 'content' to be a string, but got '${typeof content}'` if (startR instanceof RegExp == false) throw '"startR" should be an instance of RegExp.' if (endR instanceof RegExp == false) throw '"endR" should be an instance of RegExp.' this.content = content this.startR = startR this.endR = endR this.build() } build() { const { content, startR, endR } = this const starts = find(content, startR, -1) const ends = find(content, endR, 1) if(starts.length === 0 || ends.length === 0) return const children = buildTree(starts, ends) if(children.length === 0) return const start = children[0].start.n const end = children[children.length - 1].end.n this.before = start > 0 ? content.slice(0, start) : '' this.after = end < content.length ? content.slice(end, content.length) : '' children.forEach((child,i) => { this.children.push(new Node(this, child, this)) if(i === children.length-1) return const nextStart = children[i+1].start.n const curendEnd = child.end.n if(nextStart !== curendEnd) { this.children.push(new TextNode(content.slice(curendEnd,nextStart),this)) } }); } } | ||
class Node extends BaseNode { constructor(root, obj, parent = null) { super() this.parent = parent if(parent) this.index = parent.children.length this.root = root this.addChildren(obj) } addChildren(obj) { const { start, end, children } = obj const root = this.root let curStart = start.n + start.length, curEnd = end.n - end.length this.open = root.content.slice(start.n, curStart) children.forEach((child,i) => { if(child.start.n > curStart) this.children.push(new TextNode(root.content.slice(curStart, child.start.n),this)) this.children.push(new Node(root, child, this)) curStart = child.end.n }); if(curEnd > curStart) this.children.push(new TextNode(root.content.slice(curStart,curEnd),this)) this.close = root.content.slice(curEnd, end.n) return this } get outer() {return this.open + this.inner + this.close} set outer(value) {this.inner = value; this.open = ''; this.close = ''} get prev() {return this.parent ? this.parent.children[this.index - 1] : null} get next() {return this.parent ? this.parent.children[this.index + 1] : null} } | ||
function find(string, r, offset = 0) { const arr = [] let curString = string while (true) { const match = curString.match(r) if (!match) break const length = match[0].length arr.push({n:offset+match.index,length}) offset = offset+match.index+length curString = string.slice(offset) } return arr } | ||
class ReplaceBetween extends BaseNode { constructor(content, startR, endR) { super() if (typeof content !== 'string') throw `Expected 'content' to be a string, but got '${typeof content}'` if (startR instanceof RegExp == false) throw '"startR" should be an instance of RegExp.' if (endR instanceof RegExp == false) throw '"endR" should be an instance of RegExp.' this.content = content this.startR = startR this.endR = endR this.build() } build() { const { content, startR, endR } = this const starts = find(content, startR) const ends = find(content, endR) if(starts.length === 0 || ends.length === 0) return const children = buildTree(starts, ends) if(children.length === 0) return const start = children[0].start.n const {n:end,length:endLength} = children[children.length - 1].end this.before = start > 0 ? content.slice(0, start) : '' this.after = end + endLength < content.length ? content.slice(end+endLength, content.length) : '' children.forEach((child,i) => { this.children.push(new Node(this, child, this)) if(i === children.length-1) return const nextStart = children[i+1].start.n const curendEnd = child.end.n+child.end.length if(nextStart > curendEnd) { this.children.push(new TextNode(content.slice(curendEnd,nextStart),this)) } }); } } | ||
class Node extends BaseNode { constructor(root, obj, parent = null) { super() this.parent = parent if(parent) this.index = parent.children.length this.root = root this.addChildren(obj) } addChildren(obj) { const { start, end, children } = obj const root = this.root let curStart = start.n + start.length, curEnd = end.n this.open = root.content.slice(start.n, curStart) children.forEach((child,i) => { if(child.start.n > curStart) this.children.push(new TextNode(root.content.slice(curStart, child.start.n),this)) this.children.push(new Node(root, child, this)) curStart = child.end.n+child.end.length }); if(curEnd > curStart) this.children.push(new TextNode(root.content.slice(curStart,curEnd),this)) this.close = root.content.slice(curEnd, end.n+end.length) return this } get outer() {return this.open + this.inner + this.close} set outer(value) {this.inner = value; this.open = ''; this.close = ''} get prev() {return this.parent ? this.parent.children[this.index - 1] : null} get next() {return this.parent ? this.parent.children[this.index + 1] : null} } | ||
class TextNode { constructor(content,parent) { this.outer = content this.parent = parent if(parent) this.index = parent.children.length this.open = '' this.close = '' } get prev() {return this.parent.children[this.index - 1] || null} get next() {return this.parent.children[this.index + 1] || null} } | ||
return ReplaceBetween | ||
})() |
@@ -9,6 +9,6 @@ const { describe, it, beforeEach } = require('node:test') | ||
const content = "Hello <tag>world<tag>inside</tag></tag>!"; | ||
const starts = find(content, /<tag>/, -1); | ||
const ends = find(content, /<\/tag>/, 1); | ||
const starts = find(content, /<tag>/); | ||
const ends = find(content, /<\/tag>/); | ||
assert.deepStrictEqual(starts, [{n:6,length:5}, {n:16,length:5}]); | ||
assert.deepStrictEqual(ends, [{n:33,length:6}, {n:39,length:6}]); | ||
assert.deepStrictEqual(ends, [{n:27,length:6}, {n:33,length:6}]); | ||
}); | ||
@@ -18,4 +18,4 @@ | ||
const content = "Hello <tag>world<tag>inside</tag"; | ||
const starts = find(content, /<tag>/, -1); | ||
const ends = find(content, /<\/tag>/, 1); | ||
const starts = find(content, /<tag>/); | ||
const ends = find(content, /<\/tag>/); | ||
assert.deepStrictEqual(starts, [{n:6,length:5}, {n:16,length:5}]); | ||
@@ -31,4 +31,4 @@ assert.deepStrictEqual(ends, []); | ||
largeContent += " End"; | ||
const starts = find(largeContent, /<tag>/, -1); | ||
const ends = find(largeContent, /<\/tag>/, 1); | ||
const starts = find(largeContent, /<tag>/); | ||
const ends = find(largeContent, /<\/tag>/); | ||
assert.strictEqual(starts.length, 10000); | ||
@@ -35,0 +35,0 @@ assert.strictEqual(ends.length, 10000); |
@@ -78,8 +78,10 @@ const { describe, it, beforeEach } = require('node:test') | ||
describe('Mismatched tags tests', () => { | ||
it('should throw an error when the number of start tags does not match the number of end tags', () => { | ||
it.only('should not throw an error when the number of start tags does not match the number of end tags', () => { | ||
const content = "Hello <tag>world</tag><tag>extra start without end"; | ||
assert.throws(() => { | ||
new ReplaceBetween(content, /<tag>/, /<\/tag>/, []); | ||
}, /Parsing error: unmatched tags detected/); | ||
try { | ||
const result = new ReplaceBetween(content, /<tag>/, /<\/tag>/, []); | ||
assert.ok(true) | ||
} catch (error) { | ||
assert.ok(false) | ||
} | ||
}); | ||
@@ -86,0 +88,0 @@ |
46706
637