aboutsummaryrefslogtreecommitdiff
path: root/node_modules/@concordance/react/lib
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/react/lib
parent5634e77ad96bfe1818f6b6ee70b7379652e5487f (diff)
node_modules
Diffstat (limited to 'node_modules/@concordance/react/lib')
-rw-r--r--node_modules/@concordance/react/lib/diffShallow.js239
-rw-r--r--node_modules/@concordance/react/lib/elementFactory.js349
-rw-r--r--node_modules/@concordance/react/lib/escapeText.js10
-rw-r--r--node_modules/@concordance/react/lib/testJsonFactory.js59
4 files changed, 657 insertions, 0 deletions
diff --git a/node_modules/@concordance/react/lib/diffShallow.js b/node_modules/@concordance/react/lib/diffShallow.js
new file mode 100644
index 000000000..4eeb4d4d3
--- /dev/null
+++ b/node_modules/@concordance/react/lib/diffShallow.js
@@ -0,0 +1,239 @@
+'use strict'
+
+function diffShallow (api, actual, expected, theme, indent) {
+ const childBuffer = api.lineBuilder.buffer()
+ const propertyBuffer = api.lineBuilder.buffer()
+
+ return {
+ append (formatted, origin) {
+ if (origin.isItem === true) {
+ childBuffer.append(formatted)
+ } else {
+ propertyBuffer.append(formatted)
+ }
+ },
+
+ finalize: () => {
+ const namesAreEqual = actual.compareNames(expected)
+ const actualName = actual.formatName(theme)
+ const expectedName = expected.formatName(theme)
+
+ const openTag = theme.react.openTag
+ const innerIndentation = indent.increase()
+
+ const allChildren = childBuffer.withFirstPrefixed(innerIndentation)
+ const children = allChildren.decompose()
+
+ const allProperties = propertyBuffer.withFirstPrefixed(innerIndentation)
+ const properties = allProperties.decompose()
+ // If the first properties are also the last, and either side has no
+ // children, ensure the properties are treated as being last. This
+ // leads to a better balanced diff.
+ if (properties.remaining.isEmpty && (!actual.hasChildren || !expected.hasChildren)) {
+ properties.last = properties.first
+ properties.first = {actual: api.lineBuilder.buffer(), expected: api.lineBuilder.buffer()}
+ }
+
+ const result = api.lineBuilder.buffer()
+
+ // Create a custom diff that is as neat as possible. It's likely
+ // there's a generic algorithm that can be used, but for expediency's
+ // sake handles all possible diffs by brute force instead.
+ if (actual.hasProperties && expected.hasProperties) {
+ if (namesAreEqual) {
+ result
+ .append(api.lineBuilder.first(openTag.start + actualName))
+ .append(properties.first.actual.stripFlags())
+ .append(properties.first.expected.stripFlags())
+ } else {
+ result
+ .append(api.lineBuilder.actual.first(openTag.start + actualName))
+ .append(properties.first.actual.stripFlags())
+ .append(api.lineBuilder.expected.first(openTag.start + expectedName))
+ .append(properties.first.expected.stripFlags())
+ }
+ result.append(properties.remaining.stripFlags())
+
+ if (actual.hasChildren && expected.hasChildren) {
+ result
+ .append(properties.last.actual.stripFlags())
+ .append(properties.last.expected.stripFlags())
+ .append(api.lineBuilder.line(indent + openTag.end))
+
+ if (namesAreEqual) {
+ result
+ .append(allChildren.stripFlags())
+ .append(api.lineBuilder.last(indent + api.wrapFromTheme(theme.react.closeTag, actualName)))
+ } else {
+ result
+ .append(children.first.actual.stripFlags())
+ .append(children.first.expected.stripFlags())
+ .append(children.remaining.stripFlags())
+ .append(children.last.actual.stripFlags())
+ .append(api.lineBuilder.actual.last(indent + api.wrapFromTheme(theme.react.closeTag, actualName)))
+ .append(children.last.expected.stripFlags())
+ .append(api.lineBuilder.expected.last(indent + api.wrapFromTheme(theme.react.closeTag, expectedName)))
+ }
+ } else if (actual.hasChildren) {
+ result
+ .append(properties.last.actual.stripFlags())
+ .append(api.lineBuilder.actual.line(indent + openTag.end))
+ .append(allChildren.stripFlags())
+ .append(api.lineBuilder.actual.last(indent + api.wrapFromTheme(theme.react.closeTag, actualName)))
+ .append(properties.last.expected.stripFlags())
+ .append(api.lineBuilder.expected.last(indent + openTag.selfClose + openTag.end))
+ } else if (expected.hasChildren) {
+ result
+ .append(properties.last.actual.stripFlags())
+ .append(api.lineBuilder.actual.last(indent + openTag.selfClose + openTag.end))
+ .append(properties.last.expected.stripFlags())
+ .append(api.lineBuilder.expected.line(indent + openTag.end))
+ .append(allChildren.stripFlags())
+ .append(api.lineBuilder.expected.last(indent + api.wrapFromTheme(theme.react.closeTag, expectedName)))
+ } else {
+ result
+ .append(properties.last.actual.stripFlags())
+ .append(properties.last.expected.stripFlags())
+ .append(api.lineBuilder.last(indent + openTag.selfClose + openTag.end))
+ }
+ } else if (actual.hasProperties) {
+ result
+ .append(api.lineBuilder.actual.first(openTag.start + actualName))
+ .append(allProperties.stripFlags())
+
+ if (actual.hasChildren && expected.hasChildren) {
+ result
+ .append(api.lineBuilder.actual.line(indent + openTag.end))
+ .append(children.first.actual.stripFlags())
+ .append(api.lineBuilder.expected.first(openTag.start + expectedName + openTag.end))
+ .append(children.first.expected.stripFlags())
+ .append(children.remaining.stripFlags())
+
+ if (namesAreEqual) {
+ result
+ .append(children.last.actual.stripFlags())
+ .append(children.last.expected.stripFlags())
+ .append(api.lineBuilder.last(indent + api.wrapFromTheme(theme.react.closeTag, actualName)))
+ } else {
+ result
+ .append(children.last.actual.stripFlags())
+ .append(api.lineBuilder.actual.last(indent + api.wrapFromTheme(theme.react.closeTag, actualName)))
+ .append(children.last.expected.stripFlags())
+ .append(api.lineBuilder.expected.last(indent + api.wrapFromTheme(theme.react.closeTag, expectedName)))
+ }
+ } else if (actual.hasChildren) {
+ result
+ .append(api.lineBuilder.actual.last(indent + openTag.selfClose + openTag.end))
+ .append(allChildren.stripFlags())
+ .append(api.lineBuilder.actual.last(indent + api.wrapFromTheme(theme.react.closeTag, actualName)))
+ .append(api.lineBuilder.expected.single(openTag.start + expectedName + openTag.selfCloseVoid + openTag.end))
+ } else if (expected.hasChildren) {
+ result
+ .append(api.lineBuilder.actual.last(indent + openTag.selfClose + openTag.end))
+ .append(api.lineBuilder.expected.first(openTag.start + expectedName + openTag.end))
+ .append(allChildren.stripFlags())
+ .append(api.lineBuilder.expected.last(indent + api.wrapFromTheme(theme.react.closeTag, expectedName)))
+ } else {
+ result
+ .append(api.lineBuilder.actual.last(indent + openTag.selfClose + openTag.end))
+ .append(api.lineBuilder.expected.single(openTag.start + expectedName + openTag.selfCloseVoid + openTag.end))
+ }
+ } else if (expected.hasProperties) {
+ if (actual.hasChildren && expected.hasChildren) {
+ result
+ .append(api.lineBuilder.actual.first(openTag.start + actualName + openTag.end))
+ .append(children.first.actual.stripFlags())
+ .append(api.lineBuilder.expected.first(openTag.start + expectedName))
+ .append(allProperties.stripFlags())
+ .append(api.lineBuilder.expected.line(indent + openTag.end))
+ .append(children.first.expected.stripFlags())
+ .append(children.remaining.stripFlags())
+
+ if (namesAreEqual) {
+ result
+ .append(children.last.actual.stripFlags())
+ .append(children.last.expected.stripFlags())
+ .append(api.lineBuilder.last(indent + api.wrapFromTheme(theme.react.closeTag, actualName)))
+ } else {
+ result
+ .append(children.last.actual.stripFlags())
+ .append(api.lineBuilder.actual.last(indent + api.wrapFromTheme(theme.react.closeTag, actualName)))
+ .append(children.last.expected.stripFlags())
+ .append(api.lineBuilder.expected.last(indent + api.wrapFromTheme(theme.react.closeTag, expectedName)))
+ }
+ } else if (actual.hasChildren) {
+ result
+ .append(api.lineBuilder.actual.first(openTag.start + actualName + openTag.end))
+ .append(allChildren.stripFlags())
+ .append(api.lineBuilder.actual.last(indent + api.wrapFromTheme(theme.react.closeTag, actualName)))
+ .append(api.lineBuilder.expected.first(openTag.start + expectedName))
+ .append(allProperties.stripFlags())
+ .append(api.lineBuilder.expected.last(indent + openTag.selfClose + openTag.end))
+ } else if (expected.hasChildren) {
+ result
+ .append(api.lineBuilder.actual.single(openTag.start + actualName + openTag.selfCloseVoid + openTag.end))
+ .append(api.lineBuilder.expected.first(openTag.start + expectedName))
+ .append(allProperties.stripFlags())
+ .append(api.lineBuilder.expected.line(indent + openTag.end))
+ .append(allChildren.stripFlags())
+ .append(api.lineBuilder.expected.last(indent + api.wrapFromTheme(theme.react.closeTag, expectedName)))
+ } else {
+ result
+ .append(api.lineBuilder.actual.single(openTag.start + actualName + openTag.selfCloseVoid + openTag.end))
+ .append(api.lineBuilder.expected.first(openTag.start + expectedName))
+ .append(allProperties.stripFlags())
+ .append(api.lineBuilder.expected.last(indent + openTag.selfCloseVoid + openTag.end))
+ }
+ } else {
+ if (actual.hasChildren && expected.hasChildren) {
+ if (namesAreEqual) {
+ result
+ .append(api.lineBuilder.first(openTag.start + actualName + openTag.end))
+ .append(allChildren.stripFlags())
+ .append(api.lineBuilder.last(indent + api.wrapFromTheme(theme.react.closeTag, actualName)))
+ } else {
+ result
+ .append(api.lineBuilder.actual.first(openTag.start + actualName + openTag.end))
+ .append(children.first.actual.stripFlags())
+ .append(api.lineBuilder.expected.first(openTag.start + expectedName + openTag.end))
+ .append(children.first.expected.stripFlags())
+ .append(children.remaining.stripFlags())
+ .append(children.last.actual.stripFlags())
+ .append(api.lineBuilder.actual.last(indent + api.wrapFromTheme(theme.react.closeTag, actualName)))
+ .append(children.last.expected.stripFlags())
+ .append(api.lineBuilder.expected.last(indent + api.wrapFromTheme(theme.react.closeTag, expectedName)))
+ }
+ } else if (actual.hasChildren) {
+ result
+ .append(api.lineBuilder.actual.first(openTag.start + actualName + openTag.end))
+ .append(allChildren.stripFlags())
+ .append(api.lineBuilder.actual.last(indent + api.wrapFromTheme(theme.react.closeTag, actualName)))
+ .append(api.lineBuilder.expected.single(openTag.start + expectedName + openTag.selfCloseVoid + openTag.end))
+ } else if (expected.hasChildren) {
+ result
+ .append(api.lineBuilder.actual.single(openTag.start + actualName + openTag.selfCloseVoid + openTag.end))
+ .append(api.lineBuilder.expected.first(openTag.start + expectedName + openTag.end))
+ .append(allChildren.stripFlags())
+ .append(api.lineBuilder.expected.last(indent + api.wrapFromTheme(theme.react.closeTag, actualName)))
+ } else {
+ if (namesAreEqual) {
+ result.append(api.lineBuilder.single(openTag.start + actualName + openTag.selfCloseVoid + openTag.end))
+ } else {
+ result
+ .append(api.lineBuilder.actual.single(openTag.start + actualName + openTag.selfCloseVoid + openTag.end))
+ .append(api.lineBuilder.expected.single(openTag.start + expectedName + openTag.selfCloseVoid + openTag.end))
+ }
+ }
+ }
+
+ return result
+ },
+
+ shouldFormat (subject) {
+ return subject.isItem === true || subject.isProperty === true
+ },
+
+ increaseIndent: true
+ }
+}
+module.exports = diffShallow
diff --git a/node_modules/@concordance/react/lib/elementFactory.js b/node_modules/@concordance/react/lib/elementFactory.js
new file mode 100644
index 000000000..9be125cef
--- /dev/null
+++ b/node_modules/@concordance/react/lib/elementFactory.js
@@ -0,0 +1,349 @@
+'use strict'
+
+const arrify = require('arrify')
+const diffShallow = require('./diffShallow')
+const escapeText = require('./escapeText')
+
+function factory (api, reactTags) {
+ const tag = Symbol('@concordance/react.ElementValue')
+
+ function customPropertyFormatter (theme, indent, key, value) {
+ const separator = theme.react.attribute.separator + theme.react.attribute.value.openBracket
+ if (value.isSingle) {
+ return value
+ .withFirstPrefixed(key.formatAsKey(theme) + separator)
+ .withLastPostfixed(theme.react.attribute.value.closeBracket)
+ }
+
+ return api.lineBuilder.first(key.formatAsKey(theme) + separator)
+ .concat(value.withFirstPrefixed(indent.increase()).stripFlags())
+ .append(api.lineBuilder.last(indent + theme.react.attribute.value.closeBracket))
+ }
+
+ function themeProperty (theme) {
+ theme.property.increaseValueIndent = true
+ theme.property.customFormat = customPropertyFormatter
+ }
+
+ function themeStringProperty (theme) {
+ theme.property.separator = theme.react.attribute.separator
+ theme.property.after = ''
+ Object.assign(theme.string.line, theme.react.attribute.value.string.line)
+ }
+
+ function customItemFormatter (theme, indent, value) {
+ if (value.isSingle) {
+ return value
+ .withFirstPrefixed(theme.react.child.openBracket)
+ .withLastPostfixed(theme.react.child.closeBracket)
+ }
+
+ return api.lineBuilder.first(theme.react.child.openBracket)
+ .concat(value.withFirstPrefixed(indent.increase()).stripFlags())
+ .append(api.lineBuilder.last(indent + theme.react.child.closeBracket))
+ }
+
+ function themeChild (theme) {
+ theme.item.increaseValueIndent = true
+ theme.item.customFormat = customItemFormatter
+ }
+
+ function themeReactChild (theme) {
+ theme.item.after = ''
+ }
+
+ function themeStringChild (theme) {
+ theme.item.after = ''
+ Object.assign(theme.string, theme.react.child.string)
+ }
+
+ function describe (props) {
+ const element = props.value
+
+ const type = element.type
+ const hasTypeFn = typeof type === 'function'
+ const typeFn = hasTypeFn ? type : null
+ const name = hasTypeFn ? type.displayName || type.name : type
+
+ const children = arrify(element.props.children)
+
+ const properties = Object.assign({}, element.props)
+ delete properties.children
+ if (element.key !== null) {
+ properties.key = element.key
+ }
+ const hasProperties = Object.keys(properties).length > 0
+
+ return new DescribedElementValue(Object.assign({
+ children,
+ hasProperties,
+ hasTypeFn,
+ name,
+ properties,
+ typeFn,
+ isList: children.length > 0
+ }, props))
+ }
+
+ function deserialize (state, recursor) {
+ return new DeserializedElementValue(state, recursor)
+ }
+
+ class ElementValue extends api.ObjectValue {
+ constructor (props) {
+ super(props)
+ this.name = props.name
+ this.hasProperties = props.hasProperties
+ this.hasTypeFn = props.hasTypeFn
+
+ this.hasChildren = this.isList
+ }
+
+ compare (expected) {
+ return this.tag === expected.tag && this.name === expected.name
+ ? api.SHALLOW_EQUAL
+ : api.UNEQUAL
+ }
+
+ formatName (theme) {
+ const formatted = api.wrapFromTheme(theme.react.tagName, this.name)
+ return this.hasTypeFn
+ ? formatted + theme.react.functionType
+ : formatted
+ }
+
+ compareNames (expected) {
+ return this.name === expected.name && this.hasTypeFn === expected.hasTypeFn
+ }
+
+ formatShallow (theme, indent) {
+ const childBuffer = api.lineBuilder.buffer()
+ const propertyBuffer = api.lineBuilder.buffer()
+
+ return {
+ append (formatted, origin) {
+ if (origin.isItem === true) {
+ childBuffer.append(formatted)
+ } else {
+ propertyBuffer.append(formatted)
+ }
+ },
+
+ finalize: () => {
+ const name = this.formatName(theme)
+ const openTag = theme.react.openTag
+
+ if (!this.hasChildren && !this.hasProperties) {
+ return api.lineBuilder.single(openTag.start + name + openTag.selfCloseVoid + openTag.end)
+ }
+
+ const innerIndentation = indent.increase()
+ const children = childBuffer.withFirstPrefixed(innerIndentation).stripFlags()
+ const properties = propertyBuffer.withFirstPrefixed(innerIndentation).stripFlags()
+
+ const result = api.lineBuilder.buffer()
+ if (this.hasProperties) {
+ result
+ .append(api.lineBuilder.first(openTag.start + name))
+ .append(properties)
+
+ if (this.hasChildren) {
+ result.append(api.lineBuilder.line(indent + openTag.end))
+ } else {
+ result.append(api.lineBuilder.last(indent + openTag.selfClose + openTag.end))
+ }
+ } else {
+ result.append(api.lineBuilder.first(openTag.start + name + openTag.end))
+ }
+
+ if (this.hasChildren) {
+ result
+ .append(children)
+ .append(api.lineBuilder.last(indent + api.wrapFromTheme(theme.react.closeTag, name)))
+ }
+
+ return result
+ },
+
+ maxDepth: () => {
+ const name = this.formatName(theme)
+ const openTag = theme.react.openTag
+
+ if (!this.hasChildren && !this.hasProperties) {
+ return api.lineBuilder.single(openTag.start + name + openTag.selfCloseVoid + openTag.end)
+ }
+
+ let str = openTag.start + name
+ if (this.hasProperties) {
+ str += theme.maxDepth
+ if (this.hasChildren) {
+ str += openTag.end
+ } else {
+ str += ' ' + openTag.selfClose + openTag.end
+ }
+ } else {
+ str += openTag.end
+ }
+
+ if (this.hasChildren) {
+ str += theme.maxDepth + api.wrapFromTheme(theme.react.closeTag, name)
+ }
+
+ return api.lineBuilder.single(str)
+ },
+
+ shouldFormat (subject) {
+ return subject.isItem === true || subject.isProperty === true
+ },
+
+ increaseIndent: true
+ }
+ }
+
+ prepareDiff (expected) {
+ return {
+ compareResult: this.tag === expected.tag
+ ? api.SHALLOW_EQUAL
+ : api.UNEQUAL
+ }
+ }
+
+ diffShallow (expected, theme, indent) {
+ return diffShallow(api, this, expected, theme, indent)
+ }
+
+ serialize () {
+ return [this.name, this.hasProperties, this.hasTypeFn, super.serialize()]
+ }
+ }
+ Object.defineProperty(ElementValue.prototype, 'tag', {value: tag})
+
+ function modifyThemes (recursor) {
+ return api.mapRecursor(recursor, next => {
+ let modifier
+ if (next.isItem === true) {
+ if (next.tag === api.descriptorTags.primitiveItem && next.value.tag === api.descriptorTags.string) {
+ modifier = themeStringChild
+ } else if (next.tag === api.descriptorTags.complexItem && reactTags.has(next.value.tag)) {
+ modifier = themeReactChild
+ } else {
+ modifier = themeChild
+ }
+ } else if (next.isProperty === true) {
+ if (
+ next.tag === api.descriptorTags.primitiveProperty &&
+ next.value.tag === api.descriptorTags.string &&
+ !next.value.includesLinebreaks
+ ) {
+ modifier = themeStringProperty
+ } else {
+ modifier = themeProperty
+ }
+ }
+
+ return modifier
+ ? api.modifyTheme(next, modifier)
+ : next
+ })
+ }
+
+ function DescribedMixin (base) {
+ return class extends api.DescribedMixin(base) {
+ constructor (props) {
+ super(props)
+ this.children = props.children
+ this.properties = props.properties
+ this.typeFn = props.typeFn
+ }
+
+ compare (expected) {
+ const result = super.compare(expected)
+ return result === api.SHALLOW_EQUAL && this.typeFn !== expected.typeFn
+ ? api.UNEQUAL
+ : result
+ }
+
+ compareNames (expected) {
+ return super.compareNames(expected) && this.typeFn === expected.typeFn
+ }
+
+ createPropertyRecursor () {
+ // Symbols are not valid property keys for React elements. This code
+ // also assumes that the keys can be formatted as JSX-like attribute
+ // names. Keys are not pre-escaped before being passed to Concordance's
+ // property descriptor.
+ const keys = Object.keys(this.properties).sort()
+ const size = keys.length
+
+ let index = 0
+ const next = () => {
+ if (index === size) return null
+
+ const key = keys[index++]
+ // Note that string values are not specifically escaped such that the
+ // output is valid JSX.
+ return this.describeProperty(key, this.describeAny(this.properties[key]))
+ }
+
+ return {size, next}
+ }
+
+ createListRecursor () {
+ if (!this.isList) return super.createListRecursor()
+
+ const size = this.children.length
+
+ let index = 0
+ const next = () => {
+ if (index === size) return null
+
+ const current = index++
+ const child = this.children[current]
+ const type = typeof child
+ let descriptor
+ if (type === 'string') {
+ descriptor = this.describeAny(escapeText(child))
+ } else {
+ descriptor = this.describeAny(child)
+ }
+
+ return this.describeItem(current, descriptor)
+ }
+
+ return {size, next}
+ }
+
+ createRecursor () {
+ return modifyThemes(super.createRecursor())
+ }
+ }
+ }
+
+ function DeserializedMixin (base) {
+ return class extends api.DeserializedMixin(base) {
+ constructor (state, recursor) {
+ super(state[3], recursor)
+ this.name = state[0]
+ this.hasProperties = state[1]
+ this.hasTypeFn = state[2]
+ }
+
+ createRecursor () {
+ return modifyThemes(super.createRecursor())
+ }
+ }
+ }
+
+ const DescribedElementValue = DescribedMixin(ElementValue)
+ const DeserializedElementValue = DeserializedMixin(ElementValue)
+
+ return {
+ DescribedMixin,
+ DeserializedMixin,
+ ElementValue,
+ describe,
+ deserialize,
+ tag
+ }
+}
+module.exports = factory
diff --git a/node_modules/@concordance/react/lib/escapeText.js b/node_modules/@concordance/react/lib/escapeText.js
new file mode 100644
index 000000000..52447b1b6
--- /dev/null
+++ b/node_modules/@concordance/react/lib/escapeText.js
@@ -0,0 +1,10 @@
+'use strict'
+
+function escapeText (text) {
+ return text
+ .replace(/</g, '&lt;')
+ .replace(/>/g, '&gt;')
+ // TODO: Escape characters that Concordance would otherwise replace with \u
+ // sequences.
+}
+module.exports = escapeText
diff --git a/node_modules/@concordance/react/lib/testJsonFactory.js b/node_modules/@concordance/react/lib/testJsonFactory.js
new file mode 100644
index 000000000..c3e97a620
--- /dev/null
+++ b/node_modules/@concordance/react/lib/testJsonFactory.js
@@ -0,0 +1,59 @@
+'use strict'
+
+const arrify = require('arrify')
+
+function factory (api, element) {
+ const tag = Symbol('@concordance/react.TestJsonValue')
+
+ function describe (props) {
+ const obj = props.value
+
+ const name = obj.type
+ const children = arrify(obj.children)
+ const properties = Object.assign({}, obj.props)
+ const hasProperties = Object.keys(properties).length > 0
+
+ return new DescribedTestJsonValue(Object.assign({
+ children,
+ hasProperties,
+ hasTypeFn: false,
+ name,
+ properties,
+ typeFn: null,
+ isList: children.length > 0
+ }, props))
+ }
+
+ function deserialize (state, recursor) {
+ return new DeserializedTestJsonValue(state, recursor)
+ }
+
+ class TestJsonValue extends element.ElementValue {
+ compare (expected) {
+ // Allow expected value to be a React element.
+ return (this.tag === expected.tag || expected.tag === element.tag) && this.name === expected.name
+ ? api.SHALLOW_EQUAL
+ : api.UNEQUAL
+ }
+
+ prepareDiff (expected) {
+ return {
+ // Allow expected value to be a React element.
+ compareResult: this.tag === expected.tag || expected.tag === element.tag
+ ? api.SHALLOW_EQUAL
+ : api.UNEQUAL
+ }
+ }
+ }
+ Object.defineProperty(TestJsonValue.prototype, 'tag', {value: tag})
+
+ const DescribedTestJsonValue = element.DescribedMixin(TestJsonValue)
+ const DeserializedTestJsonValue = element.DeserializedMixin(TestJsonValue)
+
+ return {
+ describe,
+ deserialize,
+ tag
+ }
+}
+module.exports = factory