aboutsummaryrefslogtreecommitdiff
path: root/node_modules/concordance/lib/lineBuilder.js
diff options
context:
space:
mode:
authorFlorian Dold <florian.dold@gmail.com>2017-08-14 05:01:11 +0200
committerFlorian Dold <florian.dold@gmail.com>2017-08-14 05:02:09 +0200
commit363723fc84f7b8477592e0105aeb331ec9a017af (patch)
tree29f92724f34131bac64d6a318dd7e30612e631c7 /node_modules/concordance/lib/lineBuilder.js
parent5634e77ad96bfe1818f6b6ee70b7379652e5487f (diff)
node_modules
Diffstat (limited to 'node_modules/concordance/lib/lineBuilder.js')
-rw-r--r--node_modules/concordance/lib/lineBuilder.js309
1 files changed, 309 insertions, 0 deletions
diff --git a/node_modules/concordance/lib/lineBuilder.js b/node_modules/concordance/lib/lineBuilder.js
new file mode 100644
index 000000000..934ac0095
--- /dev/null
+++ b/node_modules/concordance/lib/lineBuilder.js
@@ -0,0 +1,309 @@
+'use strict'
+
+const ACTUAL = Symbol('lineBuilder.gutters.ACTUAL')
+const EXPECTED = Symbol('lineBuilder.gutters.EXPECTED')
+
+function translateGutter (theme, invert, gutter) {
+ if (invert) {
+ if (gutter === ACTUAL) return theme.diffGutters.expected
+ if (gutter === EXPECTED) return theme.diffGutters.actual
+ } else {
+ if (gutter === ACTUAL) return theme.diffGutters.actual
+ if (gutter === EXPECTED) return theme.diffGutters.expected
+ }
+ return theme.diffGutters.padding
+}
+
+class Line {
+ constructor (isFirst, isLast, gutter, stringValue) {
+ this.isFirst = isFirst
+ this.isLast = isLast
+ this.gutter = gutter
+ this.stringValue = stringValue
+ }
+
+ * [Symbol.iterator] () {
+ yield this
+ }
+
+ get isEmpty () {
+ return false
+ }
+
+ get hasGutter () {
+ return this.gutter !== null
+ }
+
+ get isSingle () {
+ return this.isFirst && this.isLast
+ }
+
+ append (other) {
+ return this.concat(other)
+ }
+
+ concat (other) {
+ return new Collection()
+ .append(this)
+ .append(other)
+ }
+
+ toString (options) {
+ if (options.diff === false) return this.stringValue
+
+ return translateGutter(options.theme, options.invert, this.gutter) + this.stringValue
+ }
+
+ mergeWithInfix (infix, other) {
+ if (other.isLine !== true) {
+ return new Collection()
+ .append(this)
+ .mergeWithInfix(infix, other)
+ }
+
+ return new Line(this.isFirst, other.isLast, other.gutter, this.stringValue + infix + other.stringValue)
+ }
+
+ withFirstPrefixed (prefix) {
+ if (!this.isFirst) return this
+
+ return new Line(true, this.isLast, this.gutter, prefix + this.stringValue)
+ }
+
+ withLastPostfixed (postfix) {
+ if (!this.isLast) return this
+
+ return new Line(this.isFirst, true, this.gutter, this.stringValue + postfix)
+ }
+
+ stripFlags () {
+ return new Line(false, false, this.gutter, this.stringValue)
+ }
+
+ decompose () {
+ return new Collection()
+ .append(this)
+ .decompose()
+ }
+}
+Object.defineProperty(Line.prototype, 'isLine', {value: true})
+
+class Collection {
+ constructor () {
+ this.buffer = []
+ }
+
+ * [Symbol.iterator] () {
+ for (const appended of this.buffer) {
+ for (const line of appended) yield line
+ }
+ }
+
+ get isEmpty () {
+ return this.buffer.length === 0
+ }
+
+ get hasGutter () {
+ for (const line of this) {
+ if (line.hasGutter) return true
+ }
+ return false
+ }
+
+ get isSingle () {
+ const iterator = this[Symbol.iterator]()
+ iterator.next()
+ return iterator.next().done === true
+ }
+
+ append (lineOrLines) {
+ if (!lineOrLines.isEmpty) this.buffer.push(lineOrLines)
+ return this
+ }
+
+ concat (other) {
+ return new Collection()
+ .append(this)
+ .append(other)
+ }
+
+ toString (options) {
+ let lines = this
+
+ if (options.invert) {
+ lines = new Collection()
+ let buffer = new Collection()
+
+ let prev = null
+ for (const line of this) {
+ if (line.gutter === ACTUAL) {
+ if (prev !== null && prev.gutter !== ACTUAL && !buffer.isEmpty) {
+ lines.append(buffer)
+ buffer = new Collection()
+ }
+
+ buffer.append(line)
+ } else if (line.gutter === EXPECTED) {
+ lines.append(line)
+ } else {
+ if (!buffer.isEmpty) {
+ lines.append(buffer)
+ buffer = new Collection()
+ }
+
+ lines.append(line)
+ }
+
+ prev = line
+ }
+ lines.append(buffer)
+ }
+
+ return Array.from(lines, line => line.toString(options)).join('\n')
+ }
+
+ mergeWithInfix (infix, from) {
+ if (from.isEmpty) throw new Error('Cannot merge, `from` is empty.')
+
+ const otherLines = Array.from(from)
+ if (!otherLines[0].isFirst) throw new Error('Cannot merge, `from` has no first line.')
+
+ const merged = new Collection()
+ let seenLast = false
+ for (const line of this) {
+ if (seenLast) throw new Error('Cannot merge line, the last line has already been seen.')
+
+ if (!line.isLast) {
+ merged.append(line)
+ continue
+ }
+
+ seenLast = true
+ for (const other of otherLines) {
+ if (other.isFirst) {
+ merged.append(line.mergeWithInfix(infix, other))
+ } else {
+ merged.append(other)
+ }
+ }
+ }
+ return merged
+ }
+
+ withFirstPrefixed (prefix) {
+ return new Collection()
+ .append(Array.from(this, line => line.withFirstPrefixed(prefix)))
+ }
+
+ withLastPostfixed (postfix) {
+ return new Collection()
+ .append(Array.from(this, line => line.withLastPostfixed(postfix)))
+ }
+
+ stripFlags () {
+ return new Collection()
+ .append(Array.from(this, line => line.stripFlags()))
+ }
+
+ decompose () {
+ const first = {actual: new Collection(), expected: new Collection()}
+ const last = {actual: new Collection(), expected: new Collection()}
+ const remaining = new Collection()
+
+ for (const line of this) {
+ if (line.isFirst && line.gutter === ACTUAL) {
+ first.actual.append(line)
+ } else if (line.isFirst && line.gutter === EXPECTED) {
+ first.expected.append(line)
+ } else if (line.isLast && line.gutter === ACTUAL) {
+ last.actual.append(line)
+ } else if (line.isLast && line.gutter === EXPECTED) {
+ last.expected.append(line)
+ } else {
+ remaining.append(line)
+ }
+ }
+
+ return {first, last, remaining}
+ }
+}
+Object.defineProperty(Collection.prototype, 'isCollection', {value: true})
+
+function setDefaultGutter (iterable, gutter) {
+ return new Collection()
+ .append(Array.from(iterable, line => {
+ return line.gutter === null
+ ? new Line(line.isFirst, line.isLast, gutter, line.stringValue)
+ : line
+ }))
+}
+
+module.exports = {
+ buffer () {
+ return new Collection()
+ },
+
+ first (stringValue) {
+ return new Line(true, false, null, stringValue)
+ },
+
+ last (stringValue) {
+ return new Line(false, true, null, stringValue)
+ },
+
+ line (stringValue) {
+ return new Line(false, false, null, stringValue)
+ },
+
+ single (stringValue) {
+ return new Line(true, true, null, stringValue)
+ },
+
+ setDefaultGutter (lineOrCollection) {
+ return lineOrCollection
+ },
+
+ actual: {
+ first (stringValue) {
+ return new Line(true, false, ACTUAL, stringValue)
+ },
+
+ last (stringValue) {
+ return new Line(false, true, ACTUAL, stringValue)
+ },
+
+ line (stringValue) {
+ return new Line(false, false, ACTUAL, stringValue)
+ },
+
+ single (stringValue) {
+ return new Line(true, true, ACTUAL, stringValue)
+ },
+
+ setDefaultGutter (lineOrCollection) {
+ return setDefaultGutter(lineOrCollection, ACTUAL)
+ }
+ },
+
+ expected: {
+ first (stringValue) {
+ return new Line(true, false, EXPECTED, stringValue)
+ },
+
+ last (stringValue) {
+ return new Line(false, true, EXPECTED, stringValue)
+ },
+
+ line (stringValue) {
+ return new Line(false, false, EXPECTED, stringValue)
+ },
+
+ single (stringValue) {
+ return new Line(true, true, EXPECTED, stringValue)
+ },
+
+ setDefaultGutter (lineOrCollection) {
+ return setDefaultGutter(lineOrCollection, EXPECTED)
+ }
+ }
+}