Skip to content

Commit

Permalink
fix(revert-stringify): Replace json-stringify-safe package (#359)
Browse files Browse the repository at this point in the history
This reverts commit 6eddb98.
  • Loading branch information
matthew-contentful committed Dec 20, 2019
1 parent 6eddb98 commit 63645c4
Show file tree
Hide file tree
Showing 4 changed files with 3 additions and 213 deletions.
65 changes: 2 additions & 63 deletions lib/mixins/stringify-safe.js
Original file line number Diff line number Diff line change
@@ -1,72 +1,12 @@
// This is a modified version of the algorithm by Douglas Crockford: https://github.com/douglascrockford/JSON-js/blob/master/cycle.js

const decycleObject = (object, replacer = (oldPath, value) => ({ $ref: oldPath })) => {
// Make a deep copy of an object or array, assuring that there is at most
// one instance of each object or array in the resulting structure. The
// duplicate references (which might be forming cycles) are replaced with
// an object of the form

// {
// sys: {
// type: 'Link',
// linkType: 'Entry',
// id: value.sys.id,
// circular: true
// }
// }

const objects = new WeakMap() // object to path mappings

return (function createDeepCopy (value, path) {
// The createDeepCopy function recurses through the object, producing the deep copy.

// typeof null === "object", so go on if this value is really an object but not
// one of the weird builtin objects.
if (
typeof value === 'object' &&
value !== null &&
!(value instanceof Boolean) &&
!(value instanceof Date) &&
!(value instanceof Number) &&
!(value instanceof RegExp) &&
!(value instanceof String)
) {
// If the value is an object or array, look to see if we have already
// encountered it. If so, return a {"$ref":PATH} object. This uses an
// ES6 WeakMap.

const oldPath = objects.get(value) // The path of an earlier occurance of value
if (oldPath !== undefined) {
return replacer(oldPath, value)
}

// Otherwise, accumulate the unique value and its path.
objects.set(value, path)

// If it is an array, replicate the array.
if (Array.isArray(value)) {
return value.map((element, i) => createDeepCopy(element, `${path}[${i}]`))
}
// If it is an object, replicate the object.
return Object.entries(value).reduce(
(red, [key, val]) =>
Object.assign({}, red, {
[key]: createDeepCopy(val, `${path}[${JSON.stringify(key)}]`)
}),
{}
)
}
return value
})(object, '$')
}
import jsonStringifySafe from 'json-stringify-safe'

export default function mixinStringifySafe (data) {
return Object.defineProperty(data, 'stringifySafe', {
enumerable: false,
configurable: false,
writable: false,
value: function (serializer = null, indent = '') {
const decycledObject = decycleObject(this, (oldPath, value) => {
return jsonStringifySafe(this, serializer, indent, (key, value) => {
return {
sys: {
type: 'Link',
Expand All @@ -76,7 +16,6 @@ export default function mixinStringifySafe (data) {
}
}
})
return JSON.stringify(decycledObject, serializer, indent)
}
})
}
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@
"axios": "^0.19.0",
"contentful-resolve-response": "^1.1.4",
"contentful-sdk-core": "^6.4.0",
"json-stringify-safe": "^5.0.1",
"lodash": "^4.17.11"
},
"devDependencies": {
Expand Down
75 changes: 0 additions & 75 deletions test/unit/entities/entry-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -101,78 +101,3 @@ test('Entry collection links are resolved', (t) => {
t.ok(wrappedCollection.stringifySafe(), 'stringifies safely')
t.end()
})

test('Entry collection with circular references are decycled and stringified safely', (t) => {
const entry1 = cloneDeep(entryMock)
const entry2 = cloneDeep(entryMock)
const entry3 = cloneDeep(entryMock)

entry1.sys.id = 'entry1'
entry2.sys.id = 'entry2'
entry3.sys.id = 'entry3'

// set up circular structure:
// entry1 -> entry2, entry 3
// entry2 -> entry1
// entry3 -> entry1

entry1.fields.entry2link = {
sys: {
id: 'entry2',
type: 'Link',
linkType: 'Entry'
}
}
entry1.fields.entry3link = {
sys: {
id: 'entry3',
type: 'Link',
linkType: 'Entry'
}
}
entry2.fields.linked = {
sys: {
id: 'entry1',
type: 'Link',
linkType: 'Entry'
}
}
entry3.fields.linked = {
sys: {
id: 'entry1',
type: 'Link',
linkType: 'Entry'
}
}

// define entry collection
const entryCollection = {
total: 1,
skip: 0,
limit: 100,
items: [
entry1,
entry2
],
includes: {
Entry: [ entry3 ]
}
}

// circular entries will be replaced in decycle procedure
const replacedEntry1 = { sys: { type: 'Link', linkType: 'Entry', id: 'entry1', circular: true } }
const replacedEntry2 = { sys: { type: 'Link', linkType: 'Entry', id: 'entry2', circular: true } }
const replacedEntry3 = { sys: { type: 'Link', linkType: 'Entry', id: 'entry3', circular: true } }

const wrappedCollection = wrapEntryCollection(entryCollection, {resolveLinks: true})
const safelystringed = wrappedCollection.stringifySafe()

t.ok(safelystringed, 'safely stringify completes')
const parsed = JSON.parse(safelystringed)

t.deepEquals(parsed.items[0].fields.entry2link.fields.linked, replacedEntry1, 'first circular link replaced correctly in nested fields')
t.deepEquals(parsed.items[0].fields.entry3link.fields.linked, replacedEntry1, 'second circular link replaced correctly in nested fields')
t.deepEquals(parsed.items[1], replacedEntry2, 'circular link replaced correctly in items list')
t.deepEquals(parsed.includes.Entry[0], replacedEntry3, 'circular link replaced correctly in includes')
t.end()
})
75 changes: 0 additions & 75 deletions test/unit/mixins/stringify-safe-test.js

This file was deleted.

0 comments on commit 63645c4

Please sign in to comment.