diff --git a/packages/dataparcels/.size-limit.json b/packages/dataparcels/.size-limit.json index 566e305b..8565f28c 100644 --- a/packages/dataparcels/.size-limit.json +++ b/packages/dataparcels/.size-limit.json @@ -15,6 +15,10 @@ "limit": "7.3 KB", "path": "ChangeRequest.js" }, + { + "limit": "0.4 KB", + "path": "createUpdater.js" + }, { "limit": "0.1 KB", "path": "deleted.js" @@ -25,18 +29,10 @@ }, { "limit": "5.9 KB", - "path": "asNode.js" - }, - { - "limit": "6.2 KB", "path": "asChildNodes.js" }, { - "limit": "0.1 KB", - "path": "asRaw.js" - }, - { - "limit": "6.1 KB", + "limit": "2.2 KB", "path": "translate.js" }, { diff --git a/packages/dataparcels/__test__/Exports-test.js b/packages/dataparcels/__test__/Exports-test.js index 02f5a03b..44d021fa 100644 --- a/packages/dataparcels/__test__/Exports-test.js +++ b/packages/dataparcels/__test__/Exports-test.js @@ -4,10 +4,9 @@ import Parcel from '../src/index'; import Action from '../Action'; import ChangeRequest from '../ChangeRequest'; -import asRaw from '../asRaw'; +import createUpdater from '../createUpdater'; import deleted from '../deleted'; import ParcelNode from '../ParcelNode'; -import asNode from '../asNode'; import asChildNodes from '../asChildNodes'; import cancel from '../cancel'; import translate from '../translate'; @@ -19,10 +18,9 @@ import InternalParcel from '../src/parcel/Parcel'; // internal lib files import InternalAction from '../lib/change/Action'; import InternalChangeRequest from '../lib/change/ChangeRequest'; -import InternalUpdateRaw from '../lib/parcelData/asRaw'; +import InternalCreateUpdater from '../lib/parcelData/createUpdater'; import Internaldeleted from '../lib/parcelData/deleted'; import InternalParcelNode from '../lib/parcelNode/ParcelNode'; -import InternalAsNode from '../lib/parcelNode/asNode'; import InternalAsNodes from '../lib/parcelNode/asChildNodes'; import Internalcancel from '../lib/change/cancel'; import InternalTranslate from '../lib/modifiers/translate'; @@ -40,8 +38,8 @@ test('/ChangeRequest should export ChangeRequest', () => { expect(ChangeRequest).toBe(InternalChangeRequest); }); -test('/asRaw should export asRaw', () => { - expect(asRaw).toBe(InternalUpdateRaw); +test('/createUpdater should export createUpdater', () => { + expect(createUpdater).toBe(InternalCreateUpdater); }); test('/deleted should export deleted', () => { @@ -52,10 +50,6 @@ test('/ParcelNode should export ParcelNode', () => { expect(ParcelNode).toBe(InternalParcelNode); }); -test('/asNode should export asNode', () => { - expect(asNode).toBe(InternalAsNode); -}); - test('/asChildNodes should export asChildNodes', () => { expect(asChildNodes).toBe(InternalAsNodes); }); diff --git a/packages/dataparcels/asNode.js b/packages/dataparcels/asNode.js deleted file mode 100644 index 95e3957a..00000000 --- a/packages/dataparcels/asNode.js +++ /dev/null @@ -1,2 +0,0 @@ -/* eslint-disable */ -module.exports = require('./lib/parcelNode/asNode.js').default; diff --git a/packages/dataparcels/asRaw.js b/packages/dataparcels/asRaw.js deleted file mode 100644 index 0a7201e5..00000000 --- a/packages/dataparcels/asRaw.js +++ /dev/null @@ -1,2 +0,0 @@ -/* eslint-disable */ -module.exports = require('./lib/parcelData/asRaw.js').default; diff --git a/packages/dataparcels/createUpdater.js b/packages/dataparcels/createUpdater.js new file mode 100644 index 00000000..177736b9 --- /dev/null +++ b/packages/dataparcels/createUpdater.js @@ -0,0 +1,2 @@ +/* eslint-disable */ +module.exports = require('./lib/parcelData/createUpdater.js').default; diff --git a/packages/dataparcels/package.json b/packages/dataparcels/package.json index b241a755..821b7f92 100644 --- a/packages/dataparcels/package.json +++ b/packages/dataparcels/package.json @@ -13,10 +13,9 @@ "lib", "Action.js", "asChildNodes.js", - "asNode.js", - "asRaw.js", "cancel.js", "ChangeRequest.js", + "createUpdater.js", "deleted.js", "ParcelNode.js", "translate.js", diff --git a/packages/dataparcels/src/change/ChangeRequestReducer.js b/packages/dataparcels/src/change/ChangeRequestReducer.js index 8360121e..0adcaa1f 100644 --- a/packages/dataparcels/src/change/ChangeRequestReducer.js +++ b/packages/dataparcels/src/change/ChangeRequestReducer.js @@ -33,7 +33,8 @@ const actionMap = { swap, //: (lastKey, swapKey) => swap(lastKey, swapKey), swapNext, //: (lastKey) => swapNext(lastKey), swapPrev, //: (lastKey) => swapPrev(lastKey), - unshift: (lastKey, values) => unshift(...values) + unshift: (lastKey, values) => unshift(...values), + update: (lastKey, updater) => updater }; const parentActionMap = { diff --git a/packages/dataparcels/src/change/__test__/ChangeRequestReducer-test.js b/packages/dataparcels/src/change/__test__/ChangeRequestReducer-test.js index 3ba1a6f2..de1e395c 100644 --- a/packages/dataparcels/src/change/__test__/ChangeRequestReducer-test.js +++ b/packages/dataparcels/src/change/__test__/ChangeRequestReducer-test.js @@ -71,6 +71,12 @@ const ActionCreators = { type: "unshift", payload: values }); + }, + update: (updater): Action => { + return new Action({ + type: "update", + payload: updater + }); } }; @@ -441,3 +447,29 @@ test('ChangeRequestReducer should process deep actions that are "parent actions" expect(makeReducer(actions)(data).value).toEqual(expectedValue); }); + +test('ChangeRequestReducer should process an "update" action', () => { + let updater = jest.fn(parcelData => ({ + ...parcelData, + value: parcelData.value * 2 + })); + + var data = { + value: 123, + key: "^", + child: undefined + }; + + let actions = [ + ActionCreators.update(updater) + ]; + + let expectedData = { + ...data, + value: 246 + }; + + expect(makeReducer(actions)(data)).toEqual(expectedData); + expect(updater).toHaveBeenCalledTimes(1); + expect(updater.mock.calls[0][0]).toEqual(data); +}); diff --git a/packages/dataparcels/src/errors/Errors.js b/packages/dataparcels/src/errors/Errors.js index bc8cac77..15c85081 100644 --- a/packages/dataparcels/src/errors/Errors.js +++ b/packages/dataparcels/src/errors/Errors.js @@ -7,4 +7,3 @@ export const ParcelTypeMethodMismatch = (key: string, parcelType: string, path: export const ReducerInvalidActionError = (actionType: string) => new Error(`"${actionType}" is not a valid action`); export const ReducerInvalidStepError = (stepType: string) => new Error(`"${stepType}" is not a valid action step type`); export const ChangeRequestNoPrevDataError = () => new Error(`ChangeRequest data cannot be accessed before setting changeRequest.prevData`); -export const AsNodeReturnNonParcelNodeError = () => new Error(`The return value of an asNode() updater must be a ParcelNode`); diff --git a/packages/dataparcels/src/modifiers/translate.js b/packages/dataparcels/src/modifiers/translate.js index 74b7c369..653f7728 100644 --- a/packages/dataparcels/src/modifiers/translate.js +++ b/packages/dataparcels/src/modifiers/translate.js @@ -1,12 +1,12 @@ // @flow import type Parcel from '../parcel/Parcel'; -import type ChangeRequest from '../change/ChangeRequest'; -import asNode from '../parcelNode/asNode'; +import createUpdater from '../parcelData/createUpdater'; +import update from 'unmutable/lib/update'; type Config = { - down?: (value: any) => any, - up?: (value: any, changeRequest: ChangeRequest) => any, + down?: (parcelData: any) => any, + up?: (parcelData: any) => any, preserveInput?: boolean }; @@ -17,31 +17,40 @@ export default (config: Config) => { preserveInput } = config; + let downValue = update('value', down); + let upValue = update('value', up); + if(!preserveInput) { return (parcel: Parcel): Parcel => parcel - .modifyDown(down) - .modifyUp(up); + .modifyDown(downValue) + .modifyUp(upValue); } return (parcel: Parcel): Parcel => parcel - .modifyDown(asNode(node => { - if('translated' in node.meta) { - return node.update(() => node.meta.translated); + .modifyDown((parcelData) => { + if('translated' in parcelData.meta) { + return { + value: parcelData.meta.translated + }; } - - return node - .update(down) - .setMeta({ - untranslated: node.value - }); - })) - .modifyUp(asNode((node) => { - let updated = node.update(up); - - return updated - .setMeta({ - translated: node.value, - untranslated: updated.value - }); - })); + return createUpdater( + downValue, + () => ({ + meta: { + untranslated: parcelData.value + } + }) + )(parcelData); + }) + .modifyUp((parcelData) => { + return createUpdater( + upValue, + ({value}) => ({ + meta: { + translated: parcelData.value, + untranslated: value + } + }) + )(parcelData); + }); }; diff --git a/packages/dataparcels/src/parcel/Parcel.js b/packages/dataparcels/src/parcel/Parcel.js index fccf6dda..ec9605fb 100644 --- a/packages/dataparcels/src/parcel/Parcel.js +++ b/packages/dataparcels/src/parcel/Parcel.js @@ -15,14 +15,13 @@ import type {ParentType} from '../types/Types'; import {ParcelTypeMethodMismatch} from '../errors/Errors'; -import cancel from '../change/cancel'; import ChangeRequest from '../change/ChangeRequest'; import Action from '../change/Action'; import isIndexedValue from '../parcelData/isIndexedValue'; import isParentValue from '../parcelData/isParentValue'; import deleted from '../parcelData/deleted'; -import prepUpdater from '../parcelData/prepUpdater'; +import createUpdater from '../parcelData/createUpdater'; import setMetaDefault from '../parcelData/setMetaDefault'; import prepareChildKeys from '../parcelData/prepareChildKeys'; import keyOrIndexToKey from '../parcelData/keyOrIndexToKey'; @@ -109,10 +108,6 @@ export default class Parcel { // Parent methods has: Function; - // Side-effect methods - spy: Function; - spyChange: Function; - // Change methods set: Function; update: Function; @@ -301,35 +296,14 @@ export default class Parcel { return parcelHas(key)(this._parcelData); }); - // Side-effect methods - - // Types(`spy()`, `sideEffect`, `function`)(sideEffect); - this.spy = (sideEffect: Function): Parcel => { - sideEffect(this); - return this; - }; - - // Types(`spyChange()`, `sideEffect`, `function`)(sideEffect); - this.spyChange = (sideEffect: Function): Parcel => { - return this._create({ - rawId: this._idPushModifier('sc'), - updateChangeRequestOnDispatch: (changeRequest: ChangeRequest): ChangeRequest => { - let basedChangeRequest = changeRequest._create({ - prevData: this.data - }); - sideEffect(basedChangeRequest); - return changeRequest; - } - }); - }; - // Change methods this.set = (value: any) => fireAction('set', value); // Types(`update()`, `updater`, `function`)(updater); this.update = (updater: ParcelValueUpdater) => { - fireAction('setData', prepUpdater(updater)(this._parcelData)); + let preparedUpdater = createUpdater(updater); + fireAction('update', preparedUpdater); }; this.delete = () => fireActionOnlyType(Child, 'delete'); @@ -373,32 +347,25 @@ export default class Parcel { // Types(`modifyDown()`, `updater`, `function`)(updater); this.modifyDown = (updater: ParcelValueUpdater): Parcel => { - let parcelDataUpdater = prepUpdater(updater); + let preparedUpdater = createUpdater(updater); return this._create({ rawId: this._idPushModifierUpdater('md', updater), - parcelData: parcelDataUpdater(this._parcelData), + parcelData: preparedUpdater(this._parcelData), updateChangeRequestOnDispatch: (changeRequest) => changeRequest._addStep({ type: 'md', - updater: parcelDataUpdater + updater: parcelData => preparedUpdater(parcelData) }) }); }; // Types(`modifyUp()`, `updater`, `function`)(updater); this.modifyUp = (updater: ParcelValueUpdater): Parcel => { - let parcelDataUpdater = (parcelData: ParcelData, changeRequest: ChangeRequest): ParcelData => { - let nextData = prepUpdater(updater)(parcelData, changeRequest); - if(nextData.value === cancel) { - throw new Error('CANCEL'); - } - return nextData; - }; - + let preparedUpdater = createUpdater(updater); return this._create({ rawId: this._idPushModifierUpdater('mu', updater), updateChangeRequestOnDispatch: (changeRequest) => changeRequest._addStep({ type: 'mu', - updater: parcelDataUpdater, + updater: (parcelData, changeRequest) => preparedUpdater({...parcelData, changeRequest}), changeRequest }) }); @@ -623,12 +590,7 @@ export default class Parcel { }; _idPushModifierUpdater = (prefix: string, updater: ParcelValueUpdater): string[] => { - let hash = (fn: Function): string => `${HashString(fn.toString())}`; - let id = updater._asRaw - ? `s${hash(updater._updater || updater)}` - : hash(updater); - - return this._idPushModifier(`${prefix}-${id}`); + return this._idPushModifier(`${prefix}-${HashString((updater._updater || updater).toString())}`); }; // prepare child keys only once per parcel instance diff --git a/packages/dataparcels/src/parcel/__test__/ModifyMethods-test.js b/packages/dataparcels/src/parcel/__test__/ModifyMethods-test.js index 3bc64725..aae3f473 100644 --- a/packages/dataparcels/src/parcel/__test__/ModifyMethods-test.js +++ b/packages/dataparcels/src/parcel/__test__/ModifyMethods-test.js @@ -4,11 +4,13 @@ import ChangeRequest from '../../change/ChangeRequest'; import Parcel from '../Parcel'; import cancel from '../../change/cancel'; -import asNode from '../../parcelNode/asNode'; import asChildNodes from '../../parcelNode/asChildNodes'; test('Parcel.modifyDown() should return a new parcel with updated parcelData', () => { - let updater = jest.fn(value => value + 1); + let updater = jest.fn(({value}) => ({ + value: value + 1 + })); + var data = { value: [123] }; @@ -23,14 +25,43 @@ test('Parcel.modifyDown() should return a new parcel with updated parcelData', ( value: 124, key: "#a" }; - expect(expectedData).toEqual(updated); - expect(updater.mock.calls[0][0]).toBe(123); - expect(updater.mock.calls[0][1]).toBe(undefined); + expect(updated).toEqual(expectedData); + expect(updater.mock.calls[0][0]).toEqual(parcel.data); +}); + +test('Parcel.modifyDown() should merge meta', () => { + let handleChange = jest.fn(); + let updater = jest.fn(({value}) => ({ + value: value + 1 + })); + + var parcel = new Parcel({ + value: 123, + handleChange + }) + .setMeta({abc: 100, def: 200}); + + let newParcel = handleChange.mock.calls[0][0].modifyDown(({meta}) => { + return { + meta: { + def: 400, + ghi: 300 + } + }; + }); + + expect(newParcel.meta).toEqual({ + abc: 100, + def: 400, + ghi: 300 + }); }); test('Parcel.modifyDown() should not destroy child data', () => { let handleChange = jest.fn(); - let updater = jest.fn(value => value + 1); + let updater = jest.fn(({value}) => ({ + value: value + 1 + })); var parcel = new Parcel({ value: [123], @@ -52,24 +83,9 @@ test('Parcel.modifyDown() should not destroy child data', () => { ]); }); -test('Parcel.modifyDown() should allow non-parent types to be returned', () => { - let updatedValue = new Parcel({ - value: 123 - }) - .modifyDown(value => value + 1) - .value; - - expect(updatedValue).toEqual(124); -}); - -test('Parcel.modifyDown() should allow undefined to be returned (unlike modifyUp(parcelShapeUpdater))', () => { - let updatedValue = new Parcel({ - value: 123 - }) - .modifyDown(() => {}) - .value; - - expect(updatedValue).toEqual(undefined); +test('Parcel.modifyDown() should allow undefined to be returned', () => { + let parcel = new Parcel({value: 123}); + expect(parcel.modifyDown(() => {}).data).toEqual(parcel.data); }); test('Parcel.modifyDown() should recognise if value changes types, and set value if type changes', () => { @@ -78,7 +94,7 @@ test('Parcel.modifyDown() should recognise if value changes types, and set value value: 123, handleChange }) - .modifyDown(value => []) + .modifyDown(({value}) => ({value: []})) .push(123); expect(handleChange).toHaveBeenCalledTimes(1); @@ -86,10 +102,12 @@ test('Parcel.modifyDown() should recognise if value changes types, and set value }); test('Parcel.modifyDown() should have id which is unique to updater', () => { - let updater = value => []; + let updater = () => ({value: []}); + let updater2 = ({value}) => ({value: 123}); + let sameA1 = new Parcel().modifyDown(updater); let sameA2 = new Parcel().modifyDown(updater); - let differentA = new Parcel().modifyDown(a => 1 + 2); + let differentA = new Parcel().modifyDown(updater2); let sameB1 = new Parcel().modifyDown(asChildNodes(updater)); let sameB2 = new Parcel().modifyDown(asChildNodes(updater)); @@ -102,10 +120,12 @@ test('Parcel.modifyDown() should have id which is unique to updater', () => { }); test('Parcel.modifyUp() should have id which is unique to updater', () => { - let updater = value => []; + let updater = () => ({value: []}); + let updater2 = ({value}) => ({value: 123}); + let sameA1 = new Parcel().modifyUp(updater); let sameA2 = new Parcel().modifyUp(updater); - let differentA = new Parcel().modifyUp(a => 1 + 2); + let differentA = new Parcel().modifyUp(updater2); let sameB1 = new Parcel().modifyUp(asChildNodes(updater)); let sameB2 = new Parcel().modifyUp(asChildNodes(updater)); @@ -119,7 +139,7 @@ test('Parcel.modifyUp() should have id which is unique to updater', () => { test('Parcel.modifyUp() should allow you to change the payload of a changed parcel with an updater (and should allow non-parent types to be returned)', () => { let handleChange = jest.fn(); - let updater = jest.fn(value => value + 1); + let updater = jest.fn(({value}) => ({value: value + 1})); new Parcel({ value: 123, @@ -130,7 +150,7 @@ test('Parcel.modifyUp() should allow you to change the payload of a changed parc expect(handleChange.mock.calls[0][0].value).toBe(457); - let [value, changeRequest] = updater.mock.calls[0]; + let {value, changeRequest} = updater.mock.calls[0][0]; expect(value).toBe(456); expect(changeRequest instanceof ChangeRequest).toBe(true); expect(changeRequest.prevData.value).toBe(123); @@ -149,10 +169,26 @@ test('Parcel.modifyUp() should allow changes to meta through', () => { }; new Parcel(data) - .modifyUp(value => value + 1) - .update(asNode(node => node.setMeta({ - abc: 123 - }))); + .modifyUp(({value}) => ({value: value + 1})) + .update(() => ({ + meta: { + abc: 123 + } + })); +}); + +test('Parcel.modifyUp() should allow undefined to be returned', () => { + let handleChange = jest.fn(); + + new Parcel({ + value: 123, + handleChange + }) + .modifyUp(() => undefined) + .set(456); + + expect(handleChange).toHaveBeenCalledTimes(1); + expect(handleChange.mock.calls[0][0].value).toBe(456); }); test('Parcel.modifyUp() should cancel a change if cancel is returned', () => { @@ -171,192 +207,23 @@ test('Parcel.modifyUp() should cancel a change if cancel is returned', () => { expect(handleChange).not.toHaveBeenCalled(); }); -// test('Parcel.modifyDown(parcelShapeUpdater) should be called with parcelShape and return with no change', () => { - -// let handleChange = jest.fn(); -// let updater = jest.fn(parcelShape => parcelShape); - -// let parcel = new Parcel({ -// handleChange, -// value: [1,2,3] -// }); - -// let modifiedParcel = parcel.modifyDown(asShape(updater)); -// modifiedParcel.push(4); - -// expect(modifiedParcel.value).toEqual([1,2,3]); -// expect(updater.mock.calls[0][0] instanceof ParcelShape).toBe(true); -// expect(updater.mock.calls[0][0].data.value).toEqual([1,2,3]); -// expect(handleChange.mock.calls[0][0].data.value).toEqual([1,2,3,4]); - -// expect(updater.mock.calls[0][1]).toBe(undefined); -// }); - -// test('Parcel.modifyDown(parcelShapeUpdater) should modify value', () => { - -// let handleChange = jest.fn(); -// let updater = jest.fn(parcelShape => parcelShape.push(4)); - -// let parcel = new Parcel({ -// handleChange, -// value: [1,2,3] -// }); - -// let modifiedParcel = parcel.modifyDown(asShape(updater)); -// modifiedParcel.push(5); - -// expect(modifiedParcel.value).toEqual([1,2,3,4]); -// expect(handleChange.mock.calls[0][0].data.value).toEqual([1,2,3,4,5]); - -// }); - -// test('Parcel.modifyDown(parcelShapeUpdater) should work with a returned primitive', () => { - -// let handleChange = jest.fn(); -// let updater = jest.fn(() => "!!!"); - -// let parcel = new Parcel({ -// handleChange, -// value: [1,2,3] -// }); - -// let modifiedParcel = parcel.modifyDown(asShape(updater)); -// modifiedParcel.set(456) - -// expect(modifiedParcel.value).toEqual("!!!"); -// expect(handleChange.mock.calls[0][0].data.value).toEqual(456); -// }); - -// test('Parcel.modifyDown(parcelShapeUpdater) should work with a returned undefined (unlike modifyUp(parcelShapeUpdater))', () => { +test('Parcel.modifyUp() should cancel a change if a value of cancel is returned', () => { -// let handleChange = jest.fn(); -// let updater = jest.fn(() => {}); - -// let parcel = new Parcel({ -// handleChange, -// value: [1,2,3] -// }); - -// let modifiedParcel = parcel.modifyDown(asShape(updater)); -// modifiedParcel.set(456) - -// let expectedValue = undefined; - -// expect(modifiedParcel.value).toEqual(expectedValue); -// expect(handleChange.mock.calls[0][0].data.value).toEqual(456); -// }); - -// test('Parcel.modifyDown(parcelShapeUpdater) should work with a returned collection containing parcels for children', () => { - -// let handleChange = jest.fn(); -// let updater = jest.fn(parcelShape => parcelShape.children().reverse()); - -// let parcel = new Parcel({ -// handleChange, -// value: [1,2,3] -// }); - -// let modifiedParcel = parcel.modifyDown(asShape(updater)); -// modifiedParcel.push(4); - -// let expectedValue = [3,2,1]; - -// expect(modifiedParcel.value).toEqual(expectedValue); -// expect(handleChange.mock.calls[0][0].data.value).toEqual([3,2,1,4]); -// }); - -// test('Parcel.modifyUp(parcelShapeUpdater) should be called with parcelShape and return with no change', () => { - -// let handleChange = jest.fn(); -// let updater = jest.fn(parcelShape => parcelShape); - -// let parcel = new Parcel({ -// handleChange, -// value: 123 -// }); - -// let parcelWithModifier = parcel.modifyUp(asShape(updater)); -// let {value} = parcelWithModifier.data; - -// expect(value).toEqual(123); -// expect(updater).not.toHaveBeenCalled(); - -// parcelWithModifier.set(456); - -// let [parcelShape, changeRequest] = updater.mock.calls[0]; - -// expect(parcelShape instanceof ParcelShape).toBe(true); -// expect(parcelShape.data.value).toEqual(456); -// expect(changeRequest instanceof ChangeRequest).toBe(true); -// expect(changeRequest.prevData.value).toBe(123); -// expect(changeRequest.nextData.value).toBe(456); - -// expect(handleChange.mock.calls[0][0].data.value).toEqual(456); -// }); - -// test('Parcel.modifyUp(parcelShapeUpdater) should modify value', () => { - -// let handleChange = jest.fn(); -// let updater = jest.fn(parcelShape => parcelShape.push(5)); - -// let parcel = new Parcel({ -// handleChange, -// value: [1,2,3] -// }); - -// let parcelWithModifier = parcel.modifyUp(asShape(updater)); -// parcelWithModifier.push(4); - -// expect(handleChange.mock.calls[0][0].data.value).toEqual([1,2,3,4,5]); -// }); - -// test('Parcel.modifyUp(parcelShapeUpdater) should work with a returned primitive', () => { - -// let handleChange = jest.fn(); -// let updater = jest.fn(() => 123); - -// let parcel = new Parcel({ -// handleChange, -// value: [1,2,3] -// }); - -// let parcelWithModifier = parcel.modifyUp(asShape(updater)); -// parcelWithModifier.push(4); - -// expect(handleChange.mock.calls[0][0].data.value).toEqual(123); -// }); - -// test('Parcel.modifyUp(parcelShapeUpdater) should work with a returned collection containing parcels for children', () => { - -// let handleChange = jest.fn(); -// let updater = jest.fn(parcelShape => parcelShape.children().reverse()); - -// let parcel = new Parcel({ -// handleChange, -// value: [1,2,3] -// }); - -// let parcelWithModifier = parcel.modifyUp(asShape(updater)); -// parcelWithModifier.push(4); - -// expect(handleChange.mock.calls[0][0].data.value).toEqual([4,3,2,1]); -// }); - -// test('Parcel.modifyUp(parcelShapeUpdater) should cancel a change if cancel is returned', () => { - -// let handleChange = jest.fn(); -// let updater = jest.fn(() => cancel); + let handleChange = jest.fn(); + let updater = jest.fn(() => ({ + value: cancel + })); -// let parcel = new Parcel({ -// handleChange, -// value: [1,2,3] -// }); + let parcel = new Parcel({ + handleChange, + value: [1,2,3] + }); -// let parcelWithModifier = parcel.modifyUp(asShape(updater)); -// parcelWithModifier.push(4); + let parcelWithModifier = parcel.modifyUp(updater); + parcelWithModifier.push(4); -// expect(handleChange).not.toHaveBeenCalled(); -// }); + expect(handleChange).not.toHaveBeenCalled(); +}); test('Parcel.initialMeta() should work', () => { let handleChange = jest.fn(); @@ -435,23 +302,3 @@ test('Parcel.initialMeta() should do nothing to data if all meta keys are alread expect(parcel2.data).toEqual(parcel.data); }); - -test('Sanity check: A big strange test of a big strange chain of deep updatery stuff', () => { - - let handleChange = jest.fn(); - let updater = jest.fn(value => value + "333"); - - let parcel = new Parcel({ - handleChange, - value: [1,2,3] - }) - .modifyDown(asChildNodes(array => array.reverse())) // 1. reverse the elements in the parcel (value: [3,2,1]) - .modifyUp(asChildNodes(array => array.reverse())) // 6. reverse the elements in the parcel (value: [3333,2,1]) - .get(0) // 2. get the first element (value: 3) - .modifyDown(value => value + "") // 3. cast number to string value: "3") - .modifyUp(value => parseInt(value, 10)) // 5. cast string to number (value will be: 3333) - .update(updater); // 4. make a change to the data, append three threes (value will be: "3333") - - expect(updater.mock.calls[0][0]).toBe("3"); - expect(handleChange.mock.calls[0][0].value).toEqual([1,2,3333]); -}); diff --git a/packages/dataparcels/src/parcel/__test__/ParcelChangeMethods-test.js b/packages/dataparcels/src/parcel/__test__/ParcelChangeMethods-test.js index ae6c208b..02a3d87a 100644 --- a/packages/dataparcels/src/parcel/__test__/ParcelChangeMethods-test.js +++ b/packages/dataparcels/src/parcel/__test__/ParcelChangeMethods-test.js @@ -2,7 +2,6 @@ import Parcel from '../Parcel'; import GetAction from '../../util/__test__/GetAction-testUtil'; import ParcelNode from '../../parcelNode/ParcelNode'; -import asNode from '../../parcelNode/asNode'; import asChildNodes from '../../parcelNode/asChildNodes'; test('Parcel.dispatch() should pass handleChange to newly created parcel', () => { @@ -97,40 +96,17 @@ test('Parcel.set() should remove and replace child data when setting a deep data test('Parcel.update() should call the Parcels handleChange function with the new parcelData', () => { let handleChange = jest.fn(); - let updater = jest.fn(ii => ii + 1); + let updater = jest.fn(({value}) => ({value: value + 1})); new Parcel({ value: 123, handleChange }).update(updater); - expect(updater.mock.calls[0][0]).toBe(123); + expect(updater.mock.calls[0][0].value).toBe(123); expect(handleChange.mock.calls[0][0].data.value).toBe(124); }); -test('Parcel.update(asNode()) should call the Parcels handleChange function with the new parcelData', () => { - - let handleChange = jest.fn(); - let updater = jest.fn(node => node.setMeta({foo: true})); - - new Parcel({ - value: [1,2,3], - handleChange - }).update(asNode(updater)); - - expect(updater.mock.calls[0][0] instanceof ParcelNode).toBe(true); - expect(handleChange.mock.calls[0][0].data.meta).toEqual({foo: true}); - expect(handleChange.mock.calls[0][0].data.value).toEqual([1,2,3]); -}); - -test('Parcel.update(asNode()) should error if a parcelNode isnt returned', () => { - let parcel = new Parcel({ - value: [1,2,3] - }); - - expect(() => parcel.update(asNode(() => 'foo'))).toThrow(`The return value of an asNode() updater must be a ParcelNode`); -}); - test('Parcel.update(asChildNodes()) should call the Parcels handleChange function with the new parcelData', () => { let handleChange = jest.fn(); diff --git a/packages/dataparcels/src/parcel/__test__/ParcelGetMethods-test.js b/packages/dataparcels/src/parcel/__test__/ParcelGetMethods-test.js index 837cbd18..eb958507 100644 --- a/packages/dataparcels/src/parcel/__test__/ParcelGetMethods-test.js +++ b/packages/dataparcels/src/parcel/__test__/ParcelGetMethods-test.js @@ -107,45 +107,6 @@ test('Parcel.spreadCheckbox(notFoundValue) returns an object with cast boolean / expect(parcel.spreadCheckbox(false).checked).toBe(false); }); -test('Parcel.spy() should be called with parcel', () => { - - let spy = jest.fn(); - let spy2 = jest.fn(); - - let p = new Parcel({ - value: { - abc: 123 - } - }); - - let p2 = p.spy(spy).get('abc') - - let childValue = p2.spy(spy2).value; - - expect(spy.mock.calls[0][0]).toBe(p); - expect(spy2.mock.calls[0][0]).toBe(p2); - expect(childValue).toBe(123); -}); - -test('Parcel.spyChange() should be called with changeRequest', () => { - - let spy = jest.fn(); - let spy2 = jest.fn(); - - new Parcel({ - value: { - abc: 123 - } - }) - .spyChange(spy) - .get('abc') - .spyChange(spy2) - .set(456); - - expect(spy2.mock.calls[0][0].nextData.value).toEqual(456); - expect(spy.mock.calls[0][0].nextData.value).toEqual({abc: 456}); -}); - test('Parcel.pipe() should pass itself in and return what pipe() returns', () => { var parcel1 = new Parcel(); var parcel2 = new Parcel(); diff --git a/packages/dataparcels/src/parcelData/asRaw.js b/packages/dataparcels/src/parcelData/asRaw.js deleted file mode 100644 index e0f23cea..00000000 --- a/packages/dataparcels/src/parcelData/asRaw.js +++ /dev/null @@ -1,6 +0,0 @@ -// @flow - -export default (updater: Function): Function => { - updater._asRaw = true; - return updater; -}; diff --git a/packages/dataparcels/src/parcelData/createUpdater.js b/packages/dataparcels/src/parcelData/createUpdater.js new file mode 100644 index 00000000..f1f279a5 --- /dev/null +++ b/packages/dataparcels/src/parcelData/createUpdater.js @@ -0,0 +1,24 @@ +// @flow +import cancel from '../change/cancel'; + +export default (...updaters: Function[]) => (parcelData: any): any => { + return updaters.reduce((parcelData, updater) => { + return runUpdater(updater, parcelData); + }, parcelData); +}; + +const runUpdater = (updater: Function, parcelData: any): any => { + let nextData = updater({meta: {}, ...parcelData}) || {}; + if(nextData === cancel || nextData.value === cancel) { + throw new Error('CANCEL'); + } + + return { + ...parcelData, + ...nextData, + meta: { + ...parcelData.meta, + ...(nextData.meta || {}) + } + }; +}; diff --git a/packages/dataparcels/src/parcelData/prepUpdater.js b/packages/dataparcels/src/parcelData/prepUpdater.js deleted file mode 100644 index a82246c2..00000000 --- a/packages/dataparcels/src/parcelData/prepUpdater.js +++ /dev/null @@ -1,16 +0,0 @@ -// @flow -import type {ParcelData} from '../types/Types'; -import type {ParcelValueUpdater} from '../types/Types'; -import type ChangeRequest from '../change/ChangeRequest'; - -import setValue from './setValue'; - -export default (updater: ParcelValueUpdater): Function => { - return updater._asRaw - ? updater - : (parcelData: ParcelData, changeRequest: ?ChangeRequest): ParcelData => { - let {value} = parcelData; - let updatedValue = updater(value, changeRequest); - return setValue(updatedValue)(parcelData); - }; -}; diff --git a/packages/dataparcels/src/parcelNode/ParcelNode.js b/packages/dataparcels/src/parcelNode/ParcelNode.js index 5d737e02..d2c25946 100644 --- a/packages/dataparcels/src/parcelNode/ParcelNode.js +++ b/packages/dataparcels/src/parcelNode/ParcelNode.js @@ -2,14 +2,12 @@ import type {Index} from '../types/Types'; import type {Key} from '../types/Types'; import type {ParcelData} from '../types/Types'; -import type {ParcelMeta} from '../types/Types'; import type ChangeRequest from '../change/ChangeRequest'; import keyOrIndexToKey from '../parcelData/keyOrIndexToKey'; import prepareChildKeys from '../parcelData/prepareChildKeys'; import parcelGet from '../parcelData/get'; -import setMeta from '../parcelData/setMeta'; -import prepUpdater from '../parcelData/prepUpdater'; +import createUpdater from '../parcelData/createUpdater'; export default class ParcelNode { constructor(value: any) { @@ -89,14 +87,12 @@ export default class ParcelNode { }; update = (updater: Function): ParcelNode => { + let preparedUpdater = createUpdater(updater); let parcelNode = new ParcelNode(); - parcelNode._parcelData = prepUpdater(updater)(this._parcelData, this._changeRequest); - return parcelNode; - }; - - setMeta = (meta: ParcelMeta): ParcelNode => { - let parcelNode = new ParcelNode(); - parcelNode._parcelData = setMeta(meta)(this.data); + parcelNode._parcelData = preparedUpdater({ + ...this._parcelData, + changeRequest: this._changeRequest + }); return parcelNode; }; } diff --git a/packages/dataparcels/src/parcelNode/__test__/ParcelNode-test.js b/packages/dataparcels/src/parcelNode/__test__/ParcelNode-test.js index b3874cb5..a92f4c59 100644 --- a/packages/dataparcels/src/parcelNode/__test__/ParcelNode-test.js +++ b/packages/dataparcels/src/parcelNode/__test__/ParcelNode-test.js @@ -67,16 +67,9 @@ test('ParcelNodes should get() lazily with exisitng child data', () => { expect(result._parcelData).toEqual(expected); }); -test('ParcelNodes should setMeta()', () => { - let node = new ParcelNode([1,2,3]); - let result = node.setMeta({foo: true}).setMeta({bar: false}); - expect(result.meta).toEqual({foo: true, bar: false}); -}); - - test('ParcelNodes should update() non-parent values', () => { let node = new ParcelNode(100); - let result = node.update(value => value + 200); + let result = node.update(({value}) => ({value: value + 200})); expect(result.value).toBe(300); }); @@ -87,7 +80,7 @@ test('ParcelNodes should update() non-parent values and keep meta and key', () = meta: {foo: true}, key: 'aaa' }; - let result = node.update(value => value + 200); + let result = node.update(({value}) => ({value: value + 200})); expect(result.value).toBe(300); expect(result.meta).toEqual({foo: true}); expect(result.key).toBe('aaa'); @@ -99,10 +92,10 @@ test('ParcelNodes should update() parent values without replacing children with value: [1,2,3] }; - let updater = jest.fn(value => value); + let updater = jest.fn(data => data); let result = node.update(updater); expect(updater).toHaveBeenCalledTimes(1); - expect(updater.mock.calls[0][0]).toEqual([1,2,3]); + expect(updater.mock.calls[0][0].value).toEqual([1,2,3]); }); diff --git a/packages/dataparcels/src/parcelNode/asChildNodes.js b/packages/dataparcels/src/parcelNode/asChildNodes.js index 7f5ff8b1..917dfebe 100644 --- a/packages/dataparcels/src/parcelNode/asChildNodes.js +++ b/packages/dataparcels/src/parcelNode/asChildNodes.js @@ -11,10 +11,9 @@ import ParcelNode from './ParcelNode'; import map from 'unmutable/map'; import pipeWith from 'unmutable/pipeWith'; import shallowToJS from 'unmutable/shallowToJS'; -import asNode from './asNode'; -const updateChildNodes = (node: ParcelNode, updater: Function, changeRequest: *): ParcelNode => { - let {data, value} = node; +const updateChildNodes = (node: ParcelNode, updater: Function): ParcelNode => { + let {data, value, _changeRequest} = node; if(isParentValue(value)) { node._prepareChildKeys(); value = pipeWith( @@ -23,7 +22,7 @@ const updateChildNodes = (node: ParcelNode, updater: Function, changeRequest: *) ); } - let updated: any = updater(value, changeRequest); + let updated: any = updater(value, _changeRequest); let parcelNode = new ParcelNode(); if(!isParentValue(updated)) { @@ -80,7 +79,12 @@ const updateChildNodes = (node: ParcelNode, updater: Function, changeRequest: *) }; export default (updater: Function) => { - let fn = asNode((node, changeRequest) => updateChildNodes(node, updater, changeRequest)); + let fn = (parcelData: ParcelData, changeRequest: *): ParcelData => { + let parcelNode = new ParcelNode(); + parcelNode._parcelData = parcelData; + parcelNode._changeRequest = changeRequest; + return updateChildNodes(parcelNode, updater).data; + }; fn._updater = updater; return fn; }; diff --git a/packages/dataparcels/src/parcelNode/asNode.js b/packages/dataparcels/src/parcelNode/asNode.js deleted file mode 100644 index c3ffb1d5..00000000 --- a/packages/dataparcels/src/parcelNode/asNode.js +++ /dev/null @@ -1,21 +0,0 @@ -// @flow -import type {ParcelData} from '../types/Types'; - -import {AsNodeReturnNonParcelNodeError} from '../errors/Errors'; -import asRaw from '../parcelData/asRaw'; -import ParcelNode from './ParcelNode'; - -export default (updater: Function): Function => { - let fn = (parcelData: ParcelData, changeRequest: *): ParcelData => { - let parcelNode = new ParcelNode(); - parcelNode._parcelData = parcelData; - parcelNode._changeRequest = changeRequest; - let result = updater(parcelNode, changeRequest); - if(!(result instanceof ParcelNode)) { - throw AsNodeReturnNonParcelNodeError(); - } - return result.data; - }; - fn._updater = updater; - return asRaw(fn); -}; diff --git a/packages/dataparcels/src/validation/__test__/validation-test.js b/packages/dataparcels/src/validation/__test__/validation-test.js index aee6949c..cd909562 100644 --- a/packages/dataparcels/src/validation/__test__/validation-test.js +++ b/packages/dataparcels/src/validation/__test__/validation-test.js @@ -1,11 +1,6 @@ // @flow import validation from '../validation'; -test('validation should use a raw updater, so it will work in beforeChange', () => { - expect(validation({})._asRaw).toBe(true); -}); - - test('validation should validate specified fields', () => { let isValid = jest.fn(value => value > 200 ? undefined : "Error"); diff --git a/packages/dataparcels/src/validation/validation.js b/packages/dataparcels/src/validation/validation.js index 148744e8..ac5ca5ad 100644 --- a/packages/dataparcels/src/validation/validation.js +++ b/packages/dataparcels/src/validation/validation.js @@ -4,7 +4,6 @@ import type {ParcelData} from '../types/Types'; import type {ParcelDataEvaluator} from '../types/Types'; import type {ParcelValueUpdater} from '../types/Types'; -import asRaw from '../parcelData/asRaw'; import parcelDataSetMeta from '../parcelData/setMeta'; import parcelDataUpdate from '../parcelData/update'; @@ -37,7 +36,7 @@ type ValidationRuleMap = { }; export default (validatorMap: ValidationRuleMap): ParcelValueUpdater => { - return asRaw((parcelData) => { + return (parcelData) => { let invalidList = []; let topLevelValue = parcelData.value; let meta = parcelData.meta || {}; @@ -90,5 +89,5 @@ export default (validatorMap: ValidationRuleMap): ParcelValueUpdater => { ), updateMeta ); - }); + }; }; diff --git a/packages/react-dataparcels/.size-limit.json b/packages/react-dataparcels/.size-limit.json index 0be8d8d7..e7d22294 100644 --- a/packages/react-dataparcels/.size-limit.json +++ b/packages/react-dataparcels/.size-limit.json @@ -15,6 +15,10 @@ "limit": "7.3 KB", "path": "ChangeRequest.js" }, + { + "limit": "0.4 KB", + "path": "createUpdater.js" + }, { "limit": "0.1 KB", "path": "deleted.js" @@ -25,16 +29,8 @@ }, { "limit": "5.9 KB", - "path": "asNode.js" - }, - { - "limit": "6.2 KB", "path": "asChildNodes.js" }, - { - "limit": "0.1 KB", - "path": "asRaw.js" - }, { "limit": "6.1 KB", "path": "translate.js" @@ -55,28 +51,20 @@ "limit": "12.6 KB", "path": "ParcelBoundary.js" }, - { - "limit": "13.5 KB", - "path": "ParcelBoundaryHoc.js" - }, { "limit": "47.3 KB", "path": "ParcelDrag.js" }, { - "limit": "11.6 KB", - "path": "ParcelHoc.js" - }, - { - "limit": "12.5 KB", + "limit": "12.2 KB", "path": "useParcelBuffer.js" }, { - "limit": "13.6 KB", + "limit": "13.3 KB", "path": "useParcelForm.js" }, { - "limit": "11 KB", + "limit": "10.7 KB", "path": "useParcelState.js" } ] diff --git a/packages/react-dataparcels/ParcelBoundaryHoc.js b/packages/react-dataparcels/ParcelBoundaryHoc.js deleted file mode 100644 index 71b7c811..00000000 --- a/packages/react-dataparcels/ParcelBoundaryHoc.js +++ /dev/null @@ -1,2 +0,0 @@ -/* eslint-disable */ -module.exports = require('./lib/deprecated/ParcelBoundaryHoc.js'); diff --git a/packages/react-dataparcels/ParcelHoc.js b/packages/react-dataparcels/ParcelHoc.js deleted file mode 100644 index 933e2398..00000000 --- a/packages/react-dataparcels/ParcelHoc.js +++ /dev/null @@ -1,2 +0,0 @@ -/* eslint-disable */ -module.exports = require('./lib/deprecated/ParcelHoc.js'); diff --git a/packages/react-dataparcels/__test__/Exports-test.js b/packages/react-dataparcels/__test__/Exports-test.js index 4d487173..0f71bae2 100644 --- a/packages/react-dataparcels/__test__/Exports-test.js +++ b/packages/react-dataparcels/__test__/Exports-test.js @@ -4,19 +4,16 @@ import Parcel from '../src/index'; import Action from '../Action'; import ChangeRequest from '../ChangeRequest'; -import asRaw from '../asRaw'; +import createUpdater from '../createUpdater'; import deleted from '../deleted'; import ParcelNode from '../ParcelNode'; -import asNode from '../asNode'; import asChildNodes from '../asChildNodes'; import cancel from '../cancel'; import translate from '../translate'; import validation from '../validation'; // react-dataparcels -import ParcelHoc from '../ParcelHoc'; import ParcelBoundary from '../ParcelBoundary'; -import ParcelBoundaryHoc from '../ParcelBoundaryHoc'; import ParcelDrag from '../ParcelDrag'; import useParcelBuffer from '../useParcelBuffer'; import useParcelForm from '../useParcelForm'; @@ -28,19 +25,16 @@ import asyncValue from '../asyncValue'; import InternalParcel from 'dataparcels'; import InternalAction from 'dataparcels/Action'; import InternalChangeRequest from 'dataparcels/ChangeRequest'; -import InternalUpdateRaw from 'dataparcels/asRaw'; +import InternalCreateUpdater from 'dataparcels/createUpdater'; import Internaldeleted from 'dataparcels/deleted'; import InternalParcelNode from 'dataparcels/ParcelNode'; -import InternalAsNode from 'dataparcels/asNode'; import InternalAsNodes from 'dataparcels/asChildNodes'; import Internalcancel from 'dataparcels/cancel'; import InternalTranslate from 'dataparcels/translate'; import InternalValidation from 'dataparcels/validation'; // internal react-dataparcels -import InternalParcelHoc from '../lib/deprecated/ParcelHoc'; import InternalParcelBoundary from '../lib/ParcelBoundary'; -import InternalParcelBoundaryHoc from '../lib/deprecated/ParcelBoundaryHoc'; import InternalParcelDrag from '../lib/ParcelDrag'; import InternalUseParcelBuffer from '../lib/useParcelBuffer'; import InternalUseParcelForm from '../lib/useParcelForm'; @@ -60,8 +54,8 @@ test('/ChangeRequest should export ChangeRequest', () => { expect(ChangeRequest).toBe(InternalChangeRequest); }); -test('/asRaw should export asRaw', () => { - expect(asRaw).toBe(InternalUpdateRaw); +test('/createUpdater should export createUpdater', () => { + expect(createUpdater).toBe(InternalCreateUpdater); }); test('/deleted should export deleted', () => { @@ -72,10 +66,6 @@ test('/ParcelNode should export ParcelNode', () => { expect(ParcelNode).toBe(InternalParcelNode); }); -test('/asNode should export asNode', () => { - expect(asNode).toBe(InternalAsNode); -}); - test('/asChildNodes should export asChildNodes', () => { expect(asChildNodes).toBe(InternalAsNodes); }); @@ -92,18 +82,10 @@ test('/validation should export validation', () => { expect(validation).toBe(InternalValidation); }); -test('/ParcelHoc should export ParcelHoc', () => { - expect(ParcelHoc).toBe(InternalParcelHoc); -}); - test('/ParcelBoundary should export ParcelBoundary', () => { expect(ParcelBoundary).toBe(InternalParcelBoundary); }); -test('/ParcelBoundaryHoc should export ParcelBoundaryHoc', () => { - expect(ParcelBoundaryHoc).toBe(InternalParcelBoundaryHoc); -}); - test('/ParcelDrag should export ParcelDrag', () => { expect(ParcelDrag).toBe(InternalParcelDrag); }); diff --git a/packages/react-dataparcels/asNode.js b/packages/react-dataparcels/asNode.js deleted file mode 100644 index 453cabff..00000000 --- a/packages/react-dataparcels/asNode.js +++ /dev/null @@ -1,2 +0,0 @@ -/* eslint-disable */ -module.exports = require('dataparcels/asNode.js'); diff --git a/packages/react-dataparcels/asRaw.js b/packages/react-dataparcels/asRaw.js deleted file mode 100644 index 534a6840..00000000 --- a/packages/react-dataparcels/asRaw.js +++ /dev/null @@ -1,2 +0,0 @@ -/* eslint-disable */ -module.exports = require('dataparcels/asRaw.js'); diff --git a/packages/react-dataparcels/createUpdater.js b/packages/react-dataparcels/createUpdater.js new file mode 100644 index 00000000..7f5409b4 --- /dev/null +++ b/packages/react-dataparcels/createUpdater.js @@ -0,0 +1,2 @@ +/* eslint-disable */ +module.exports = require('dataparcels/createUpdater.js'); diff --git a/packages/react-dataparcels/package.json b/packages/react-dataparcels/package.json index f84ff29d..318306c3 100644 --- a/packages/react-dataparcels/package.json +++ b/packages/react-dataparcels/package.json @@ -14,17 +14,14 @@ "Action.js", "asyncChange.js", "asChildNodes.js", - "asNode.js", - "asRaw.js", "asyncChange.js", "asyncValue.js", "cancel.js", "ChangeRequest.js", + "createUpdater.js", "deleted.js", "ParcelBoundary.js", - "ParcelBoundaryHoc.js", "ParcelDrag.js", - "ParcelHoc.js", "ParcelNode.js", "asChildNodes.js", "useParcelBuffer.js", diff --git a/packages/react-dataparcels/src/__test__/useParcelBuffer-test.js b/packages/react-dataparcels/src/__test__/useParcelBuffer-test.js index 771e503d..316c5b69 100644 --- a/packages/react-dataparcels/src/__test__/useParcelBuffer-test.js +++ b/packages/react-dataparcels/src/__test__/useParcelBuffer-test.js @@ -493,7 +493,7 @@ describe('useParcelBuffer should use config.beforeChange', () => { let {result} = renderHook(() => useParcelBuffer({ parcel, - beforeChange: value => value * 2, + beforeChange: ({value}) => ({value: value * 2}), buffer: false })); @@ -508,8 +508,8 @@ describe('useParcelBuffer should use config.beforeChange', () => { let {result} = renderHook(() => useParcelBuffer({ parcel, beforeChange: [ - value => value * 2, - value => value + 5 + ({value}) => ({value: value * 2}), + ({value}) => ({value: value + 5}) ], buffer: false })); @@ -528,7 +528,7 @@ describe('useParcelBuffer should use config.beforeChange', () => { let {result} = renderHook(() => useParcelBuffer({ parcel, - beforeChange: value => value * 2, + beforeChange: ({value}) => ({value: value * 2}), buffer: false })); @@ -551,8 +551,8 @@ describe('useParcelBuffer should use config.beforeChange', () => { let {result} = renderHook(() => useParcelBuffer({ parcel, beforeChange: [ - value => value * 2, - value => value + 5 + ({value}) => ({value: value * 2}), + ({value}) => ({value: value + 5}) ], buffer: false })); @@ -572,7 +572,7 @@ describe('useParcelBuffer should use config.beforeChange', () => { let {result, rerender} = renderHook(() => useParcelBuffer({ parcel, - beforeChange: value => value * 2 + beforeChange: ({value}) => ({value: value * 2}) })); act(() => { diff --git a/packages/react-dataparcels/src/__test__/useParcelState-test.js b/packages/react-dataparcels/src/__test__/useParcelState-test.js index 2db3cec4..1c098346 100644 --- a/packages/react-dataparcels/src/__test__/useParcelState-test.js +++ b/packages/react-dataparcels/src/__test__/useParcelState-test.js @@ -1,7 +1,6 @@ // @flow import {act} from 'react-hooks-testing-library'; import {renderHook} from 'react-hooks-testing-library'; -import asRaw from 'dataparcels/asRaw'; import useParcelState from '../useParcelState'; import asyncChange from '../asyncChange'; import asyncValue from '../asyncValue'; @@ -39,12 +38,6 @@ describe('useParcelState should use config.value', () => { expect(result.current[0].value).toBe(123); }); - it('should create a Parcel from value updater', () => { - let {result} = renderHook(() => useParcelState({value: asRaw(() => ({value: 123, meta: {abc: 456}}))})); - expect(result.current[0].value).toBe(123); - expect(result.current[0].meta).toEqual({abc: 456}); - }); - it('should update Parcel', () => { let {result} = renderHook(() => useParcelState({value: () => 123})); @@ -114,7 +107,7 @@ describe('useParcelState should use config.value with asyncValue', () => { let {result} = renderHook(() => useParcelState({ value: asyncValue(fetcher), - beforeChange: value => value * 2 + beforeChange: ({value}) => ({value: value * 2}) })); await act(fetcher); @@ -171,45 +164,6 @@ describe('useParcelState should use config.updateValue', () => { expect(result.current[0].value).toBe(789); }); - - it('should allow updater to be passed as value', () => { - - let updater = jest.fn((prevData, foo) => { - return { - value: foo, - meta: { - foo - } - }; - }); - - let {result, rerender} = renderHookWithProps({foo: 123}, (props) => useParcelState({ - value: asRaw((prevData) => updater(prevData, props.foo)), - updateValue: true - })); - - expect(result.current[0].value).toBe(123); - expect(result.current[0].meta).toEqual({ - foo: 123 - }); - - expect(updater.mock.calls[0][0].value).toBe(undefined); - expect(updater.mock.calls[0][0].meta).toEqual({}); - - act(() => { - rerender({foo: 456}); - }); - - expect(result.current[0].value).toBe(456); - expect(result.current[0].meta).toEqual({ - foo: 456 - }); - - expect(updater.mock.calls[1][0].value).toBe(123); - expect(updater.mock.calls[1][0].meta).toEqual({ - foo: 123 - }); - }); }); describe('useParcelState should use config.onChange', () => { @@ -335,7 +289,7 @@ describe('useParcelState should use config.beforeChange', () => { it('should apply single beforeChange to parcel', () => { let {result} = renderHook(() => useParcelState({ value: 123, - beforeChange: value => value * 2 + beforeChange: ({value}) => ({value: value * 2}) })); expect(result.current[0].value).toBe(246); @@ -357,8 +311,8 @@ describe('useParcelState should use config.beforeChange', () => { let {result} = renderHook(() => useParcelState({ value: 123, beforeChange: [ - value => value * 2, - value => value + 5 + ({value}) => ({value: value * 2}), + ({value}) => ({value: value + 5}) ] })); @@ -375,7 +329,7 @@ describe('useParcelState should use config.beforeChange', () => { let {result, rerender} = renderHookWithProps({foo: 123}, (props) => useParcelState({ value: props.foo, updateValue: true, - beforeChange: value => value * 2 + beforeChange: ({value}) => ({value: value * 2}) })); expect(result.current[0].value).toBe(246); @@ -392,8 +346,8 @@ describe('useParcelState should use config.beforeChange', () => { value: props.foo, updateValue: true, beforeChange: [ - value => value * 2, - value => value + 5 + ({value}) => ({value: value * 2}), + ({value}) => ({value: value + 5}) ] })); diff --git a/packages/react-dataparcels/src/deprecated/ParcelBoundaryControlDeprecated.jsx b/packages/react-dataparcels/src/deprecated/ParcelBoundaryControlDeprecated.jsx deleted file mode 100644 index d1549384..00000000 --- a/packages/react-dataparcels/src/deprecated/ParcelBoundaryControlDeprecated.jsx +++ /dev/null @@ -1,32 +0,0 @@ -// @flow -import type Action from 'dataparcels/Action'; -import type Parcel from 'dataparcels'; - -type ParcelBoundaryControlConfig = { - release: () => void, - cancel: () => void, - buffered: boolean, - buffer: Action[], - originalParcel: Parcel -}; - -export default class ParcelBoundaryControl { - // actions - release: () => void; - cancel: () => void; - - // status - buffered: boolean; - buffer: Action[]; - - // data - originalParcel: Parcel; - - constructor(config: ParcelBoundaryControlConfig) { - this.release = config.release; - this.cancel = config.cancel; - this.buffered = config.buffered; - this.buffer = config.buffer; - this.originalParcel = config.originalParcel; - } -} diff --git a/packages/react-dataparcels/src/deprecated/ParcelBoundaryDeprecated.jsx b/packages/react-dataparcels/src/deprecated/ParcelBoundaryDeprecated.jsx deleted file mode 100644 index 5a1d6b82..00000000 --- a/packages/react-dataparcels/src/deprecated/ParcelBoundaryDeprecated.jsx +++ /dev/null @@ -1,342 +0,0 @@ -// @flow -import type {Node} from 'react'; -import type ChangeRequest from 'dataparcels/ChangeRequest'; -import type {ContinueChainFunction} from 'dataparcels'; -import type {ParcelData} from 'dataparcels'; -import type {ParcelValueUpdater} from 'dataparcels'; - -import React from 'react'; -import Parcel from 'dataparcels'; -import asRaw from 'dataparcels/asRaw'; - -import ParcelBoundaryControl from './ParcelBoundaryControlDeprecated'; -import ParcelBoundaryEquals from '../util/ParcelBoundaryEquals'; - -import identity from 'unmutable/identity'; -import isNotEmpty from 'unmutable/isNotEmpty'; -import pipe from 'unmutable/pipe'; -import set from 'unmutable/set'; -import shallowEquals from 'unmutable/shallowEquals'; -import compose from 'unmutable/compose'; - -const ApplyModifyBeforeUpdate = (modifyBeforeUpdate: Array) => compose( - ...modifyBeforeUpdate.map((fn) => parcel => parcel.modifyUp(fn)) -); - -type RenderFunction = (parcel: Parcel, control: ParcelBoundaryControl) => Node; - -type Props = { - children: RenderFunction, - debounce: number, - debugBuffer: boolean, - debugParcel: boolean, - hold: boolean, - forceUpdate: Array<*>, - modifyBeforeUpdate: Array, - onCancel: Array, - onRelease: Array, - parcel: Parcel, - pure: boolean, - keepValue: boolean -}; - -type State = { - cachedChangeRequest: ?ChangeRequest, - changeCount: number, - lastValueFromSelf: any, - makeBoundarySplit: Function, - parcel: Parcel, - parcelFromProps: Parcel -}; - -export default class ParcelBoundary extends React.Component { /* eslint-disable-line react/no-deprecated */ - - static defaultProps: * = { - debounce: 0, - debugBuffer: false, - debugParcel: false, - hold: false, - forceUpdate: [], - modifyBeforeUpdate: [], - onCancel: [], - onRelease: [], - pure: true, - keepValue: false - }; - - constructor(props: Props) { - super(props); - - let parcel = this.makeBoundarySplit(props.parcel); - - this.state = { - cachedChangeRequest: undefined, - changeCount: 0, - lastValueFromSelf: parcel.value, - makeBoundarySplit: this.makeBoundarySplit, - parcel, - parcelFromProps: parcel - }; - - if(process.env.NODE_ENV !== 'production' && props.debugParcel) { - console.log(`ParcelBoundary: Received initial value:`); // eslint-disable-line - console.log(props.parcel.data); // eslint-disable-line - } - } - - shouldComponentUpdate(nextProps: Props, nextState: State): boolean { - if(!nextProps.pure) { - return true; - } - - let parcelDataChanged: boolean = !ParcelBoundaryEquals(this.props.parcel, nextProps.parcel); - - if(!parcelDataChanged) { - parcelDataChanged = !ParcelBoundaryEquals(this.state.parcel, nextState.parcel); - } - - let forceUpdateChanged: boolean = !shallowEquals(this.props.forceUpdate)(nextProps.forceUpdate); - let cachedChangeRequestChanged: boolean = this.state.cachedChangeRequest !== nextState.cachedChangeRequest; - - return parcelDataChanged || forceUpdateChanged || cachedChangeRequestChanged; - } - - static getDerivedStateFromProps(props: Props, state: State): * { - let { - parcel, - keepValue - } = props; - - let { - lastValueFromSelf, - makeBoundarySplit, - parcelFromProps, - parcel: parcelFromState - } = state; - - let newState = {}; - - let newParcelFromProps = parcel !== parcelFromProps; - if(newParcelFromProps) { - newState.parcelFromProps = parcel; - } - - if(newParcelFromProps && !ParcelBoundaryEquals(parcelFromProps, parcel)) { - let newData = parcel.data; - - if(keepValue) { - let changedBySelf = parcel._frameMeta.lastOriginId.startsWith(parcel.id); - if(changedBySelf) { - newState.lastValueFromSelf = parcel.value; - } - - if(changedBySelf || Object.is(newData.value, lastValueFromSelf)) { - newData = { - ...parcelFromState.data, - key: newData.key, - meta: newData.meta - }; - } - } - - if(process.env.NODE_ENV !== 'production' && props.debugParcel) { - console.log(`ParcelBoundary: Parcel replaced from props:`); // eslint-disable-line - console.log(newData); // eslint-disable-line - } - - newState.cachedChangeRequest = undefined; - newState.changeCount = 0; - newState.parcel = makeBoundarySplit(parcel, newData, parcelFromState.data); - } - - return isNotEmpty()(newState) ? newState : null; - } - - addToBuffer: Function = (changeRequest: ChangeRequest) => (state: State): State => { - let {debugBuffer} = this.props; - let { - cachedChangeRequest, - changeCount - } = state; - - if(process.env.NODE_ENV !== 'production' && debugBuffer) { - console.log(`ParcelBoundary: Add to buffer:`); // eslint-disable-line - console.log(changeRequest); // eslint-disable-line - } - - let newCachedChangeRequest = cachedChangeRequest - ? cachedChangeRequest.merge(changeRequest) - : changeRequest; - - return { - ...state, - cachedChangeRequest: newCachedChangeRequest, - changeCount: changeCount + 1 - }; - }; - - cancelBuffer: Function = () => (state: State): State => { - let { - debugBuffer, - debugParcel, - parcel - } = this.props; - - let {cachedChangeRequest} = state; - - if(process.env.NODE_ENV !== 'production' && debugBuffer) { - console.log(`ParcelBoundary: Clear buffer:`); // eslint-disable-line - cachedChangeRequest && console.log(cachedChangeRequest); // eslint-disable-line - } - if(!cachedChangeRequest) { - return state; - } - - if(process.env.NODE_ENV !== 'production' && debugParcel) { - console.log(`ParcelBoundary: Buffer cancelled. Parcel reverted:`); // eslint-disable-line - console.log(parcel.data); // eslint-disable-line - } - - return { - ...state, - cachedChangeRequest: undefined, - changeCount: 0, - parcel: this.makeBoundarySplit(parcel) - }; - }; - - releaseBuffer: Function = () => (state: State): State => { - let {debugBuffer} = this.props; - let {cachedChangeRequest} = state; - - if(process.env.NODE_ENV !== 'production' && debugBuffer) { - console.log(`ParcelBoundary: Release buffer:`); // eslint-disable-line - cachedChangeRequest && console.log(cachedChangeRequest); // eslint-disable-line - } - - if(!cachedChangeRequest) { - return state; - } - - this.props.parcel.dispatch(cachedChangeRequest); - return { - ...state, - cachedChangeRequest: undefined, - changeCount: 0 - }; - }; - - makeBoundarySplit: Function = (parcel: Parcel, nextData: ?ParcelData, prevData: ?ParcelData): Parcel => { - let {modifyBeforeUpdate} = this.props; - - let handleChange = (newParcel: Parcel, changeRequest: ChangeRequest) => { - let { - debounce, - debugParcel, - hold, - keepValue - } = this.props; - - let {changeCount} = this.state; - - if(process.env.NODE_ENV !== 'production' && debugParcel) { - console.log(`ParcelBoundary: Parcel changed:`); // eslint-disable-line - console.log(newParcel.data); // eslint-disable-line - } - - let updateParcel = set('parcel', newParcel); - let addToBuffer = this.addToBuffer(changeRequest); - let releaseBuffer = this.releaseBuffer(); - - if(!debounce && !hold) { - this.setState(pipe( - keepValue ? updateParcel : ii => ii, - addToBuffer, - releaseBuffer - )); - return; - } - - if(hold) { - this.setState(pipe( - updateParcel, - addToBuffer - )); - return; - } - - // debounce && !hold - - setTimeout(() => { - if(changeCount + 1 === this.state.changeCount) { - this.setState(releaseBuffer); - } - }, debounce); - - this.setState(pipe( - updateParcel, - addToBuffer - )); - }; - - let [changedParcel] = parcel - ._boundarySplit({ - handleChange - }) - ._changeAndReturn((parcel) => parcel - .modifyDown(prevData - ? asRaw(() => prevData) - : identity() - ) - .pipe(ApplyModifyBeforeUpdate(modifyBeforeUpdate)) - ._setData(nextData || parcel.data) - ); - - return changedParcel; - }; - - render(): Node { - let { - children, - modifyBeforeUpdate, - onCancel, - onRelease - } = this.props; - - let { - cachedChangeRequest, - parcel - } = this.state; - - let actions = cachedChangeRequest - ? cachedChangeRequest.actions - : []; - - let handleCancel = () => this.setState(this.cancelBuffer()); - let handleRelease = () => this.setState(this.releaseBuffer()); - - let chain = (callbackArray, finalCallback) => callbackArray.reduceRight( - (continueChain, callback) => () => { - let {cachedChangeRequest, parcel} = this.state; - return callback( - continueChain, - cachedChangeRequest && cachedChangeRequest._create({ - prevData: parcel.data - }) - ); - }, - finalCallback - ); - - return children( - ApplyModifyBeforeUpdate(modifyBeforeUpdate)(parcel), - new ParcelBoundaryControl({ - cancel: chain(onCancel, handleCancel), - release: chain(onRelease, handleRelease), - buffered: actions.length > 0, - buffer: actions, - originalParcel: this.props.parcel - }) - ); - } -} diff --git a/packages/react-dataparcels/src/deprecated/ParcelBoundaryHoc.jsx b/packages/react-dataparcels/src/deprecated/ParcelBoundaryHoc.jsx deleted file mode 100644 index cbb0ea4d..00000000 --- a/packages/react-dataparcels/src/deprecated/ParcelBoundaryHoc.jsx +++ /dev/null @@ -1,94 +0,0 @@ -// @flow -import type {ComponentType} from 'react'; -import type {Node} from 'react'; -import type Parcel from 'dataparcels'; -import type {ContinueChainFunction} from 'dataparcels'; -import type {ParcelValueUpdater} from 'dataparcels'; -import type ParcelBoundaryControl from './ParcelBoundaryControlDeprecated'; - -import React from 'react'; -import ParcelBoundary from './ParcelBoundaryDeprecated'; - -type Props = { - // [config.name]?: Parcel -}; -type ChildProps = { - // [config.name]?: Parcel, - // [config.name + "Control"]?: ParcelBoundaryControl - // ... -}; - -type AnyProps = { - [key: string]: any -}; - -type ParcelBoundaryHocConfig = { - name: string|((props: AnyProps) => string), - debounce?: number|(props: AnyProps) => number, - hold?: boolean|(props: AnyProps) => boolean, - modifyBeforeUpdate?: Array, - onCancel?: Array, - onRelease?: Array, - debugBuffer?: boolean, - debugParcel?: boolean -}; - -export default (config: ParcelBoundaryHocConfig): Function => { - - // deprecation notice - if(process.env.NODE_ENV !== 'production') { - console.warn(`ParcelBoundaryHoc is deprecated. Please use the useParcelBuffer hook instead.`); /* eslint-disable-line no-console */ - } - - return (Component: ComponentType) => class ParcelBoundaryHoc extends React.Component { /* eslint-disable-line */ - render(): Node { - - let fromProps = (value) => (typeof value === "function") ? value(this.props) : value; - - // $FlowFixMe - flow can'tm seem to understand that name will never be a boolean or number according to its own previous types - let name: string = fromProps(config.name); - // $FlowFixMe - let debounce: ?number = fromProps(config.debounce) || undefined; - // $FlowFixMe - let hold: boolean = fromProps(config.hold) || false; - - // function array config options - let modifyBeforeUpdate: Array = config.modifyBeforeUpdate || []; - let onCancel: Array = config.onCancel || []; - let onRelease: Array = config.onRelease || []; - - // debug config options - let debugBuffer: boolean = config.debugBuffer || false; - let debugParcel: boolean = config.debugParcel || false; - - let parcel = this.props[name]; - if(!parcel) { - return ; - } - - return - {(innerParcel: Parcel, control: ParcelBoundaryControl): Node => { - let childProps = { - ...this.props, - // $FlowFixMe - I want to use a computed property, flow - [name]: innerParcel, - // $FlowFixMe - I want to use a computed property, flow - [name + "Control"]: control - }; - - return ; - }} - ; - } - }; -}; diff --git a/packages/react-dataparcels/src/deprecated/ParcelHoc.jsx b/packages/react-dataparcels/src/deprecated/ParcelHoc.jsx deleted file mode 100644 index 6fe671e7..00000000 --- a/packages/react-dataparcels/src/deprecated/ParcelHoc.jsx +++ /dev/null @@ -1,172 +0,0 @@ -// @flow -import type {ComponentType} from 'react'; -import type {Node} from 'react'; -import type ChangeRequest from 'dataparcels/ChangeRequest'; -import type {ParcelValueUpdater} from 'dataparcels'; - -import React from 'react'; -import Parcel from 'dataparcels'; -import ApplyBeforeChange from '../util/ApplyBeforeChange'; - -type Props = {}; - -type State = { - parcel: ?Parcel, - prevProps: {[key: string]: any}, - initialize: (props: Props) => Parcel -}; - -type ChildProps = { - // ${name}: Parcel -}; - -type AnyProps = { - [key: string]: any -}; - -type ValueFromProps = (props: AnyProps) => *; -type ShouldParcelUpdateFromProps = (prevProps: AnyProps, nextProps: AnyProps, valueFromProps: any) => boolean; -type OnChange = (parcel: Parcel, changeRequest: ChangeRequest) => void; - -type ParcelHocConfig = { - name: string, - valueFromProps: ValueFromProps, - shouldParcelUpdateFromProps?: ShouldParcelUpdateFromProps, - onChange?: (props: AnyProps) => OnChange, - modifyBeforeUpdate?: Array, - delayUntil?: (props: AnyProps) => boolean, - pipe?: (props: *) => (parcel: Parcel) => Parcel, - debugParcel?: boolean -}; - -export default (config: ParcelHocConfig): Function => { - - // deprecation notice - if(process.env.NODE_ENV !== 'production') { - console.warn(`ParcelHoc is deprecated. Please use the useParcelState hook instead.`); /* eslint-disable-line no-console */ - } - - let { - name, - valueFromProps, - shouldParcelUpdateFromProps, - onChange, - modifyBeforeUpdate = [], - delayUntil = (props) => true, /* eslint-disable-line no-unused-vars */ - pipe = props => ii => ii, /* eslint-disable-line no-unused-vars */ - // debug options - debugParcel = false - } = config; - - return (Component: ComponentType) => class ParcelHoc extends React.Component { - constructor(props: Props) { - super(props); - - let initialize = (props: Props) => ParcelHoc.updateParcelValueFromProps( - new Parcel({ - value: valueFromProps(props), - handleChange: this.handleChange - }), - props - ); - - this.state = { - parcel: undefined, - prevProps: {}, - initialize - }; - } - - static updateParcelValueFromProps(parcel: Parcel, props: Props): Parcel { - let [changedParcel] = parcel._changeAndReturn((parcel: Parcel) => { - let value: any = valueFromProps(props); - return ApplyBeforeChange(modifyBeforeUpdate)(parcel).set(value); - }); - - return changedParcel; - } - - static applyModifyBeforeUpdate(parcel: Parcel): Parcel { - return parcel.pipe( - ...modifyBeforeUpdate.map((fn) => parcel => parcel.modifyUp(fn)) - ); - } - - static getDerivedStateFromProps(props: Props, state: State): * { - let { - initialize, - parcel, - prevProps - } = state; - - let newState = {}; - - if(!parcel && delayUntil(props)) { - newState.parcel = initialize(props); - - if(process.env.NODE_ENV !== 'production' && debugParcel) { - console.log(`ParcelHoc: Received initial value:`); // eslint-disable-line - console.log(newState.parcel.data); // eslint-disable-line - } - } - - if(parcel && shouldParcelUpdateFromProps && shouldParcelUpdateFromProps(prevProps, props, valueFromProps) && parcel) { - newState.parcel = ParcelHoc.updateParcelValueFromProps(parcel, props); - - if(process.env.NODE_ENV !== 'production' && debugParcel) { - console.log(`ParcelHoc: Parcel updated from props:`); // eslint-disable-line - console.log(newState.parcel.data); // eslint-disable-line - } - } - - newState.prevProps = props; - return newState; - } - - handleChange = (parcel: Parcel, changeRequest: ChangeRequest) => { - parcel._frameMeta.lastOriginId = changeRequest.originId; - - this.setState({parcel}); - if(process.env.NODE_ENV !== 'production' && debugParcel) { - console.log(`ParcelHoc: Parcel changed:`); // eslint-disable-line - console.log(parcel.data); // eslint-disable-line - } - - let callOnChange = (onChange: ?Function, value: *) => { - if(!onChange) { - return; - } - let onChangeWithProps = onChange(this.props); - onChangeWithProps(value, changeRequest); - }; - - if(changeRequest.hasValueChanged()) { - callOnChange(onChange, parcel.value); - } - }; - - render(): Node { - let {parcel} = this.state; - - let renderWithProps = (extraProps = {}) => ; - - if(!parcel) { - return renderWithProps(); - } - - let pipeWithProps = pipe(this.props); - - let pipeFunctions = [ - ParcelHoc.applyModifyBeforeUpdate, - pipeWithProps - ]; - - return renderWithProps({ - [name]: parcel.pipe(...pipeFunctions) - }); - } - }; -}; diff --git a/packages/react-dataparcels/src/deprecated/__test__/ParcelBoundaryDeprecated-test.js b/packages/react-dataparcels/src/deprecated/__test__/ParcelBoundaryDeprecated-test.js deleted file mode 100644 index 1d80a22c..00000000 --- a/packages/react-dataparcels/src/deprecated/__test__/ParcelBoundaryDeprecated-test.js +++ /dev/null @@ -1,789 +0,0 @@ -// @flow -import React from 'react'; -import ParcelBoundary from '../ParcelBoundaryDeprecated'; -import ParcelBoundaryEquals from '../../util/ParcelBoundaryEquals'; -import Parcel from 'dataparcels'; -import Action from 'dataparcels/Action'; - -jest.useFakeTimers(); - -test('ParcelBoundary should pass a *value equivalent* parcel to children', () => { - let parcel = new Parcel({ - value: 123 - }); - let childRenderer = jest.fn(); - - let wrapper = shallow( - {childRenderer} - ); - - let childParcel = childRenderer.mock.calls[0][0]; - - expect(ParcelBoundaryEquals(childParcel, parcel)).toBe(true); -}); - -test('ParcelBoundary should send correct changes back up when debounce = 0', () => { - let childRenderer = jest.fn(); - let handleChange = jest.fn(); - - let parcel = new Parcel({ - value: 456, - handleChange - }); - - let wrapper = shallow( - {childRenderer} - ); - - let childParcel = childRenderer.mock.calls[0][0]; - childParcel.set(123); - expect(handleChange).toHaveBeenCalledTimes(1); - let newParcel = handleChange.mock.calls[0][0]; - expect(newParcel.value).toBe(123); -}); - -test('ParcelBoundary should pass a NEW *value equivalent* parcel to children when props change', () => { - let childRenderer = jest.fn(); - - let parcel = new Parcel(); - let parcel2 = new Parcel({value: 456}); - - let wrapper = shallow( - {childRenderer} - ); - - wrapper.setProps({ - parcel: parcel2 - }); - - wrapper.update(); - - let childParcel = childRenderer.mock.calls[0][0]; - let childParcel2 = childRenderer.mock.calls[1][0]; - - expect(ParcelBoundaryEquals(childParcel, parcel)).toBe(true); - expect(ParcelBoundaryEquals(childParcel2, parcel2)).toBe(true); -}); - -test('ParcelBoundary should lock state to props if debounce, hold and keepValue are all false', () => { - let childRenderer = jest.fn(); - - let parcel = new Parcel({value: 123}); - - let wrapper = shallow( - {childRenderer} - ); - - let childParcel = childRenderer.mock.calls[0][0]; - childParcel.set(456); - - wrapper.update(); - - expect(childRenderer).toHaveBeenCalledTimes(1); -}); - -test('ParcelBoundary should not rerender if parcel has not changed value and pure = true', () => { - let childRenderer = jest.fn(); - - let parcel = new Parcel(); - let parcel2 = new Parcel({value: 456}); - - let wrapper = shallow( - {childRenderer} - ); - - wrapper.setProps({ - parcel, - somethingElse: true - }); - - wrapper.update(); - - expect(childRenderer).toHaveBeenCalledTimes(1); -}); - -test('ParcelBoundary should rerender if parcel has not changed value and pure = false', () => { - let childRenderer = jest.fn(); - - let parcel = new Parcel(); - let parcel2 = new Parcel({value: 456}); - - let wrapper = shallow( - {childRenderer} - ); - - wrapper.setProps({ - parcel, - somethingElse: true - }); - - wrapper.update(); - - expect(childRenderer).toHaveBeenCalledTimes(2); -}); - -test('ParcelBoundary should rerender if parcel has not changed value but forceUpdate has', () => { - let childRenderer = jest.fn(); - - let parcel = new Parcel(); - let parcel2 = new Parcel({value: 456}); - let renders = 0; - - let wrapper = shallow( - {childRenderer} - ); - - wrapper.setProps({ - parcel, - forceUpdate: ["def"] - }); - - wrapper.update(); - - expect(childRenderer).toHaveBeenCalledTimes(2); -}); - -test('ParcelBoundary should release changes when called', async () => { - let childRenderer = jest.fn(); - let handleChange = jest.fn(); - - let parcel = new Parcel({ - handleChange - }); - - let wrapper = shallow( - {childRenderer} - ); - - let childParcel = childRenderer.mock.calls[0][0]; - childParcel.set(123); - // handleChange shouldn't be called yet because hold is true - expect(handleChange).toHaveBeenCalledTimes(0); - - wrapper.update(); - - let [childParcel2, control] = childRenderer.mock.calls[1]; - // inside the parcel boundary, the last change should be applied to the parcel - expect(childParcel2.value).toBe(123); - - control.release(); - - // handleChange should be called now because release() was called - expect(handleChange).toHaveBeenCalledTimes(1); - let newParcel = handleChange.mock.calls[0][0]; - - // handleChange should have been called with the correct value - expect(newParcel.value).toBe(123); -}); - -test('ParcelBoundary should use onRelease', async () => { - let childRenderer = jest.fn(); - let handleChange = jest.fn(); - let onRelease1 = jest.fn(); - let onRelease2 = jest.fn(); - - let parcel = new Parcel({ - handleChange - }); - - let wrapper = shallow( - {childRenderer} - ); - - let childParcel = childRenderer.mock.calls[0][0]; - childParcel.set(123); - wrapper.update(); - - // call release, then onRelease1 should have been called but no others - childRenderer.mock.calls[1][1].release(); - expect(onRelease1).toHaveBeenCalledTimes(1); - expect(onRelease2).not.toHaveBeenCalled(); - expect(handleChange).not.toHaveBeenCalled(); - - // call release1, then onRelease2 should have been called - let release1 = onRelease1.mock.calls[0][0]; - release1(); - expect(onRelease1).toHaveBeenCalledTimes(1); - expect(onRelease2).toHaveBeenCalledTimes(1); - expect(handleChange).not.toHaveBeenCalled(); - - // call release2 and then handleChange should have been called - let release2 = onRelease2.mock.calls[0][0]; - release2(); - expect(onRelease1).toHaveBeenCalledTimes(1); - expect(onRelease2).toHaveBeenCalledTimes(1); - expect(handleChange).toHaveBeenCalledTimes(1); -}); - -test('ParcelBoundary should cancel changes when called', async () => { - let childRenderer = jest.fn(); - let handleChange = jest.fn(); - - let parcel = new Parcel({ - handleChange, - value: 456 - }); - - let wrapper = shallow( - {childRenderer} - ); - - let childParcel = childRenderer.mock.calls[0][0]; - childParcel.set(123); - // handleChange shouldn't be called yet because hold is true - expect(handleChange).toHaveBeenCalledTimes(0); - - wrapper.update(); - - let [childParcel2, control] = childRenderer.mock.calls[1]; - // inside the parcel boundary, the last change should be applied to the parcel - expect(childParcel2.value).toBe(123); - - control.cancel(); - - // handleChange should still not have been called - expect(handleChange).toHaveBeenCalledTimes(0); - - wrapper.update(); - - - let [childParcel3] = childRenderer.mock.calls[2]; - // inside the parcel boundary, the original value should be reinstated - expect(childParcel3.value).toBe(456); -}); - -test('ParcelBoundary should onCancel', async () => { - let childRenderer = jest.fn(); - let handleChange = jest.fn(); - let onCancel1 = jest.fn(); - let onCancel2 = jest.fn(); - - let parcel = new Parcel({ - handleChange, - value: 456 - }); - - let wrapper = shallow( - {childRenderer} - ); - - let childParcel = childRenderer.mock.calls[0][0]; - childParcel.set(123); - wrapper.update(); - let childRendererCalls = childRenderer.mock.calls.length; - - // call cancel, then onCancel1 should have been called but no others - childRenderer.mock.calls[1][1].cancel(); - expect(onCancel1).toHaveBeenCalledTimes(1); - expect(onCancel2).not.toHaveBeenCalled(); - // there should have been no re-render as the cancellation shouldn't have happened yet - expect(childRenderer).toHaveBeenCalledTimes(childRendererCalls); - - // call cancel1, then onCancel2 should have been called - let cancel1 = onCancel1.mock.calls[0][0]; - cancel1(); - expect(onCancel1).toHaveBeenCalledTimes(1); - expect(onCancel2).toHaveBeenCalledTimes(1); - // there should have been no re-render as the cancellation shouldn't have happened yet - expect(childRenderer).toHaveBeenCalledTimes(childRendererCalls); - - // call cancel and then inside the parcel boundary, the original value should be reinstated - let cancel2 = onCancel2.mock.calls[0][0]; - cancel2(); - wrapper.update(); - let [childParcel2] = childRenderer.mock.calls[2]; - // inside the parcel boundary, the original value should be reinstated - expect(childParcel2.value).toBe(456); -}); - - -test('ParcelBoundary cancel should do nothing if no changes have occurred', async () => { - let childRenderer = jest.fn(); - let handleChange = jest.fn(); - - let parcel = new Parcel({ - handleChange, - value: 456 - }); - - let wrapper = shallow( - {childRenderer} - ); - - childRenderer.mock.calls[0][1].cancel(); - - wrapper.update(); - - // childRenderer should still only have been called once - // because no change of state should have occurred whatsoever - expect(childRenderer).toHaveBeenCalledTimes(1); -}); - - -test('ParcelBoundary should pass buffer info to childRenderer', async () => { - let childRenderer = jest.fn(); - - let parcel = new Parcel(); - - let wrapper = shallow( - {childRenderer} - ); - - let [childParcel, control] = childRenderer.mock.calls[0]; - childParcel.set(123); - // handleChange shouldn't be called yet because hold is true - expect(control.buffered).toBe(false); - expect(control.buffer.length).toBe(0); - - let [childParcel2, control2] = childRenderer.mock.calls[1]; - expect(control2.buffered).toBe(true); - expect(control2.buffer.length).toBe(1); - expect(control2.buffer[0] instanceof Action).toBe(true); - - control.release(); - - let [childParcel3, control3] = childRenderer.mock.calls[2]; - expect(control3.buffered).toBe(false); - expect(control3.buffer.length).toBe(0); -}); - -test('ParcelBoundary should debounce', async () => { - let childRenderer = jest.fn(); - let handleChange = jest.fn(); - - let parcel = new Parcel({ - value: {a:1, b:2}, - handleChange - }); - - let wrapper = shallow( - {childRenderer} - ); - - let childParcel = childRenderer.mock.calls[0][0]; - - // make a change with a value - childParcel.get('a').set(123); - - // handleChange shouldn't be called yet - expect(handleChange).toHaveBeenCalledTimes(0); - - // wait 20ms - jest.advanceTimersByTime(20); - - // handleChange shouldn't be called yet - expect(handleChange).toHaveBeenCalledTimes(0); - - wrapper.update(); - let childParcel2 = childRenderer.mock.calls[1][0]; - - // parcel inside parcel boundary should have updated - expect(childParcel2.value).toEqual({a:123, b:2}); - - // make another change with a value - childParcel2.get('a').set(456); - - // wait another 20ms - jest.advanceTimersByTime(20); - - // handleChange still shouldn't be called yet - expect(handleChange).toHaveBeenCalledTimes(0); - - wrapper.update(); - let childParcel3 = childRenderer.mock.calls[2][0]; - - // parcel inside parcel boundary should have updated - expect(childParcel3.value).toEqual({a:456, b:2}); - - // make another 2 changes with a value - childParcel3.get('a').set(789); - childParcel3.get('b').set(789); - - // wait another 40ms - with an interval this big, debounce should have finally had time to kick in - jest.advanceTimersByTime(40); - - // handleChange should have been called - expect(handleChange).toHaveBeenCalledTimes(1); - // handleChange should have been called with the most recent set of changes - expect(handleChange.mock.calls[0][0].value).toEqual({a:789, b:789}); -}); - -test('ParcelBoundary should cancel unreleased changes when receiving a new parcel prop', () => { - let childRenderer = jest.fn(); - let handleChange = jest.fn(); - - let parcel = new Parcel({ - value: 123, - handleChange - }); - let parcel2 = new Parcel({ - value: 456, - handleChange - }); - - let wrapper = shallow( - {childRenderer} - ); - - let childParcel = childRenderer.mock.calls[0][0]; - childParcel.set(789); - - let childParcel2 = childRenderer.mock.calls[1][0]; - - // verify that the current value of the parcel has been updated - expect(childParcel2.value).toBe(789); - - wrapper.setProps({ - parcel: parcel2 - }); - - let childParcel3 = childRenderer.mock.calls[2][0]; - // the new value received via props should be passed down WITHOUT the previous 789 change applied - expect(childParcel3.value).toBe(456); - - let control = childRenderer.mock.calls[2][1]; - control.release(); - - // after release()ing the buffer, handleChange should not be called, because there should not be anything in the buffer - expect(handleChange).toHaveBeenCalledTimes(0); -}); - -test('ParcelBoundary should not update value from props for updates caused by themselves if keepValue is true', () => { - let childRenderer = jest.fn(); - let handleChange = jest.fn(); - - let parcel = new Parcel({ - value: 123, - handleChange - }); - - let withModify = (parcel) => parcel.modifyUp(value => value + 1); - - let wrapper = shallow( - {childRenderer} - ); - - let childParcel = childRenderer.mock.calls[0][0]; - childParcel.set(456); - - let newParcel = handleChange.mock.calls[0][0]; - newParcel._frameMeta = { - lastOriginId: handleChange.mock.calls[0][1].originId - }; - - // verify that the current value of the parcel has been updated - expect(newParcel.value).toBe(457); - - wrapper.setProps({ - parcel: withModify(newParcel) - }); - - // expect that the value in the parcelboundary has not changed - // because the last change was triggered by this boundary - let childParcel2 = childRenderer.mock.calls[2][0]; - expect(childParcel2.value).toBe(456); - - // make a change externally and ensure that the value in the boundary does update - newParcel.set(789); - let newParcel2 = handleChange.mock.calls[1][0]; - newParcel2._frameMeta = { - lastOriginId: handleChange.mock.calls[1][1].originId - }; - wrapper.setProps({ - parcel: withModify(newParcel2) - }); - - let childParcel3 = childRenderer.mock.calls[3][0]; - expect(childParcel3.value).toBe(789); -}); - -test('ParcelBoundary should update meta from props for updates caused by themselves if keepValue is true', () => { - let childRenderer = jest.fn(); - let handleChange = jest.fn(); - - let parcel = new Parcel({ - value: 123, - handleChange - }); - - let withModify = (parcel) => parcel.modifyUp(value => value + 1); - - let wrapper = shallow( - {childRenderer} - ); - - let childParcel = childRenderer.mock.calls[0][0]; - childParcel.set(456); - - let newParcel = handleChange.mock.calls[0][0]; - newParcel._frameMeta = { - lastOriginId: handleChange.mock.calls[0][1].originId - }; - - // make a change that keepValue will prevent from altering its value - wrapper.setProps({ - parcel: withModify(newParcel) - }); - - // make a change to meta externally and ensure that the value in the boundary does not update - // but meta does - newParcel.setMeta({ - abc: 789 - }); - let newParcel2 = handleChange.mock.calls[1][0]; - newParcel2._frameMeta = { - lastOriginId: handleChange.mock.calls[1][1].originId - }; - wrapper.setProps({ - parcel: withModify(newParcel2) - }); - - let childParcel3 = childRenderer.mock.calls[3][0]; - expect(childParcel3.value).toBe(456); - expect(childParcel3.meta.abc).toBe(789); -}); -test('ParcelBoundary should pass initial value through modifyBeforeUpdate', () => { - let childRenderer = jest.fn(); - - let parcel = new Parcel({ - value: 123 - }); - - let modifyBeforeUpdate = [ - value => value + 1 - ]; - - let wrapper = shallow( - {childRenderer} - ); - - let childParcel = childRenderer.mock.calls[0][0]; - expect(childParcel.value).toBe(124); -}); - -test('ParcelBoundary should pass changes through modifyBeforeUpdate', () => { - let childRenderer = jest.fn(); - let handleChange = jest.fn(); - - let parcel = new Parcel({ - value: 456, - handleChange - }); - - let modifyBeforeUpdate = [ - value => value + 1, - value => value + 1 - ]; - - let wrapper = shallow( - {childRenderer} - ); - - let childParcel = childRenderer.mock.calls[0][0]; - childParcel.set(123); - expect(handleChange).toHaveBeenCalledTimes(1); - let newParcel = handleChange.mock.calls[0][0]; - expect(newParcel.value).toBe(125); -}); - -test('ParcelBoundary should pass new parcel from props change through modifyBeforeUpdate', () => { - let childRenderer = jest.fn(); - - let parcel = new Parcel({value: 123}); - let parcel2 = new Parcel({value: 456}); - - let modifyBeforeUpdate = [ - jest.fn(value => value + 1), - jest.fn(value => value + 1) - ]; - - let wrapper = shallow( - {childRenderer} - ); - - wrapper.setProps({ - parcel: parcel2 - }); - - wrapper.update(); - - let childParcel = childRenderer.mock.calls[0][0]; - let childParcel2 = childRenderer.mock.calls[1][0]; - - expect(modifyBeforeUpdate[0].mock.calls[2][0]).toBe(456); - expect(modifyBeforeUpdate[0].mock.calls[2][1].prevData.value).toBe(125); - expect(modifyBeforeUpdate[0].mock.calls[2][1].nextData.value).toBe(456); - - expect(modifyBeforeUpdate[1].mock.calls[2][0]).toBe(457); - expect(modifyBeforeUpdate[1].mock.calls[2][1].prevData.value).toBe(125); - expect(modifyBeforeUpdate[1].mock.calls[2][1].nextData.value).toBe(457); -}); - -test('ParcelBoundary should accept a debugParcel boolean and log about receiving initial value', () => { - let {log} = console; - // $FlowFixMe - console.log = jest.fn(); // eslint-disable-line - - let parcel = new Parcel({ - value: 123 - }); - - let wrapper = shallow( - {() =>
} - ); - - expect(console.log.mock.calls[0][0]).toBe("ParcelBoundary: Received initial value:"); - // $FlowFixMe - console.log = log; // eslint-disable-line -}); - -test('ParcelBoundary should accept a debugParcel boolean and log about parcel changing', () => { - let {log} = console; - // $FlowFixMe - console.log = jest.fn(); // eslint-disable-line - let childRenderer = jest.fn(); - - let parcel = new Parcel({ - value: 123 - }); - - let wrapper = shallow( - {childRenderer} - ); - - let childParcel = childRenderer.mock.calls[0][0]; - childParcel.set(123); - - expect(console.log.mock.calls[2][0]).toBe("ParcelBoundary: Parcel changed:"); - // $FlowFixMe - console.log = log; // eslint-disable-line -}); - -test('ParcelBoundary should accept a debugParcel boolean and log about replacing parcel from props', () => { - let {log} = console; - // $FlowFixMe - console.log = jest.fn(); // eslint-disable-line - - let parcel = new Parcel({ - value: 123 - }); - - let parcel2 = new Parcel({ - value: 456 - }); - - let wrapper = shallow( - {() =>
} - ); - - wrapper.setProps({ - parcel: parcel2 - }); - - wrapper.update(); - - expect(console.log.mock.calls[2][0]).toBe("ParcelBoundary: Parcel replaced from props:"); - // $FlowFixMe - console.log = log; // eslint-disable-line -}); - -test('ParcelBoundary should accept a debugParcel boolean and log about cancelling and reverting parcel', () => { - let {log} = console; - // $FlowFixMe - console.log = jest.fn(); // eslint-disable-line - let childRenderer = jest.fn(); - - let parcel = new Parcel({ - value: 123 - }); - - let wrapper = shallow( - {childRenderer} - ); - - let childParcel = childRenderer.mock.calls[0][0]; - childParcel.set(123); - - wrapper.update(); - - childRenderer.mock.calls[1][1].cancel(); - - expect(console.log.mock.calls[4][0]).toBe("ParcelBoundary: Buffer cancelled. Parcel reverted:"); - // $FlowFixMe - console.log = log; // eslint-disable-line -}); - -test('ParcelBoundary should accept a debugBuffer boolean and log about adding to buffer', () => { - let {log} = console; - // $FlowFixMe - console.log = jest.fn(); // eslint-disable-line - let childRenderer = jest.fn(); - - let parcel = new Parcel({ - value: 123 - }); - - let wrapper = shallow( - {childRenderer} - ); - - let childParcel = childRenderer.mock.calls[0][0]; - childParcel.set(123); - - expect(console.log.mock.calls[0][0]).toBe("ParcelBoundary: Add to buffer:"); - // $FlowFixMe - console.log = log; // eslint-disable-line -}); - -test('ParcelBoundary should accept a debugBuffer boolean and log about releasing buffer', () => { - let {log} = console; - // $FlowFixMe - console.log = jest.fn(); // eslint-disable-line - let childRenderer = jest.fn(); - - let parcel = new Parcel({ - value: 123 - }); - - let wrapper = shallow( - {childRenderer} - ); - - let childParcel = childRenderer.mock.calls[0][0]; - childParcel.set(123); - - wrapper.update(); - - childRenderer.mock.calls[1][1].release(); - - expect(console.log.mock.calls[2][0]).toBe("ParcelBoundary: Release buffer:"); - // $FlowFixMe - console.log = log; // eslint-disable-line -}); - - -test('ParcelBoundary should accept a debugBuffer boolean and log about cancelling buffer', () => { - let {log} = console; - // $FlowFixMe - console.log = jest.fn(); // eslint-disable-line - let childRenderer = jest.fn(); - - let parcel = new Parcel({ - value: 123 - }); - - let wrapper = shallow( - {childRenderer} - ); - - let childParcel = childRenderer.mock.calls[0][0]; - childParcel.set(123); - - wrapper.update(); - - childRenderer.mock.calls[1][1].cancel(); - - expect(console.log.mock.calls[2][0]).toBe("ParcelBoundary: Clear buffer:"); - // $FlowFixMe - console.log = log; // eslint-disable-line -}); diff --git a/packages/react-dataparcels/src/deprecated/__test__/ParcelBoundaryHoc-test.js b/packages/react-dataparcels/src/deprecated/__test__/ParcelBoundaryHoc-test.js deleted file mode 100644 index 0b9a51a5..00000000 --- a/packages/react-dataparcels/src/deprecated/__test__/ParcelBoundaryHoc-test.js +++ /dev/null @@ -1,271 +0,0 @@ -// @flow -import React from 'react'; - -import Parcel from 'dataparcels'; -import ParcelBoundaryHoc from '../ParcelBoundaryHoc'; -import ParcelBoundaryControl from '../ParcelBoundaryControlDeprecated'; - -let shallowRenderHoc = (props, hock) => { - let Component = hock((props) =>
); - return shallow(); -}; - -test('ParcelBoundaryHoc config should pass props through', () => { - let propsGivenToInnerComponent = shallowRenderHoc( - { - testParcel: new Parcel(), - abc: 123, - def: 456 - }, - ParcelBoundaryHoc({ - name: 'testParcel' - }) - ).dive().props(); - - expect(propsGivenToInnerComponent.abc).toBe(123); - expect(propsGivenToInnerComponent.def).toBe(456); -}); - - -test('ParcelBoundaryHoc config should pass props through with no parcel found', () => { - let propsGivenToInnerComponent = shallowRenderHoc( - { - abc: 123, - def: 456 - }, - ParcelBoundaryHoc({ - name: 'testParcel' - }) - ).props(); - - expect(propsGivenToInnerComponent.abc).toBe(123); - expect(propsGivenToInnerComponent.def).toBe(456); -}); - - -test('ParcelBoundaryHoc config should pass ParcelBoundary parcel down under same prop name', () => { - let propsGivenToInnerComponent = shallowRenderHoc( - { - testParcel: new Parcel({ - value: 789 - }) - }, - ParcelBoundaryHoc({ - name: 'testParcel' - }) - ).dive().props(); - - // parcel has correct contents - expect(propsGivenToInnerComponent.testParcel.value).toBe(789); - - // parcel is passed through parcel boundary as evidenced by "~bs" in its id - expect(propsGivenToInnerComponent.testParcel.id.indexOf("~bs")).not.toBe(-1); -}); - -test('ParcelBoundaryHoc config should pass control as config.name + "Control', () => { - let propsGivenToInnerComponent = shallowRenderHoc( - { - testParcel: new Parcel({ - value: 789 - }) - }, - ParcelBoundaryHoc({ - name: 'testParcel' - }) - ).dive().props(); - - // testParcelControl should contain a ParcelBoundaryControl object - expect(propsGivenToInnerComponent.testParcelControl instanceof ParcelBoundaryControl).toBe(true); -}); - -test('ParcelBoundaryHoc config.name should accept props function returning string', () => { - let propsGivenToInnerComponent = shallowRenderHoc( - { - testParcel: new Parcel({ - value: 789 - }), - parcelName: 'testParcel' - }, - ParcelBoundaryHoc({ - name: (props: Object) => props.parcelName - }) - ).dive().props(); - - // parcel has correct contents - expect(propsGivenToInnerComponent.testParcel.value).toBe(789); - - // parcel is passed through parcel boundary as evidenced by "~bs" in its id - expect(propsGivenToInnerComponent.testParcel.id.indexOf("~bs")).not.toBe(-1); -}); - -test('ParcelBoundaryHoc config.debounce should accept number', () => { - let propsGivenToParcelBoundary = shallowRenderHoc( - { - testParcel: new Parcel() - }, - ParcelBoundaryHoc({ - name: 'testParcel', - debounce: 100 - }) - ).props(); - - expect(propsGivenToParcelBoundary.debounce).toBe(100); -}); - -test('ParcelBoundaryHoc config.debounce should accept props function returning number', () => { - let propsGivenToParcelBoundary = shallowRenderHoc( - { - testParcel: new Parcel(), - debounce: 100 - }, - ParcelBoundaryHoc({ - name: 'testParcel', - debounce: (props) => props.debounce - }) - ).props(); - - expect(propsGivenToParcelBoundary.debounce).toBe(100); -}); - -test('ParcelBoundaryHoc config.hold should accept number', () => { - let propsGivenToParcelBoundary = shallowRenderHoc( - { - testParcel: new Parcel() - }, - ParcelBoundaryHoc({ - name: 'testParcel', - hold: true - }) - ).props(); - - expect(propsGivenToParcelBoundary.hold).toBe(true); -}); - -test('ParcelBoundaryHoc config.hold should accept props function returning number', () => { - let propsGivenToParcelBoundary = shallowRenderHoc( - { - testParcel: new Parcel(), - hold: true - }, - ParcelBoundaryHoc({ - name: 'testParcel', - hold: (props) => props.hold - }) - ).props(); - - expect(propsGivenToParcelBoundary.hold).toBe(true); -}); - -test('ParcelBoundaryHoc config.debugBuffer should accept number', () => { - let propsGivenToParcelBoundary = shallowRenderHoc( - { - testParcel: new Parcel() - }, - ParcelBoundaryHoc({ - name: 'testParcel', - debugBuffer: true - }) - ).props(); - - expect(propsGivenToParcelBoundary.debugBuffer).toBe(true); -}); - -test('ParcelBoundaryHoc should be not use pure rendering', () => { - let propsGivenToParcelBoundary = shallowRenderHoc( - { - testParcel: new Parcel() - }, - ParcelBoundaryHoc({ - name: 'testParcel' - }) - ).props(); - - expect(propsGivenToParcelBoundary.pure).toBe(false); -}); - -test('ParcelBoundaryHoc should pass down originalParcel in ParcelBoundaryControl', () => { - let testParcel = new Parcel({ - value: 789 - }); - - let propsGivenToInnerComponent = shallowRenderHoc( - { - testParcel - }, - ParcelBoundaryHoc({ - name: 'testParcel' - }) - ).dive().props(); - - expect(propsGivenToInnerComponent.testParcelControl.originalParcel).toBe(testParcel); -}); - -test('ParcelBoundaryHoc config.modifyBeforeUpdate should accept array', () => { - let modifyBeforeUpdate = [ - value => value + 1 - ]; - - let propsGivenToParcelBoundary = shallowRenderHoc( - { - testParcel: new Parcel() - }, - ParcelBoundaryHoc({ - name: 'testParcel', - modifyBeforeUpdate - }) - ).props(); - - expect(propsGivenToParcelBoundary.modifyBeforeUpdate).toBe(modifyBeforeUpdate); -}); - -test('ParcelBoundaryHoc config.onCancel should accept function array', () => { - let onCancel = [continueCancel => continueCancel()]; - - let propsGivenToParcelBoundary = shallowRenderHoc( - { - testParcel: new Parcel() - }, - ParcelBoundaryHoc({ - name: 'testParcel', - onCancel - }) - ).props(); - - expect(propsGivenToParcelBoundary.onCancel).toBe(onCancel); -}); - -test('ParcelBoundaryHoc config.onRelease should accept function array', () => { - let onRelease = [continueRelease => continueRelease()]; - - let propsGivenToParcelBoundary = shallowRenderHoc( - { - testParcel: new Parcel() - }, - ParcelBoundaryHoc({ - name: 'testParcel', - onRelease - }) - ).props(); - - expect(propsGivenToParcelBoundary.onRelease).toBe(onRelease); -}); - -test('ParcelBoundaryHoc should not log deprecation notice when NODE_ENV=production', () => { - let {NODE_ENV} = process.env; - process.env.NODE_ENV = 'production'; - - let {warn} = console; - // $FlowFixMe - console.warn = jest.fn(); // eslint-disable-line - - ParcelBoundaryHoc({ - name: 'testParcel' - }); - - expect(console.warn).not.toHaveBeenCalled(); - - // $FlowFixMe - console.warn = warn; // eslint-disable-line - - process.env.NODE_ENV = NODE_ENV; -}); diff --git a/packages/react-dataparcels/src/deprecated/__test__/ParcelHoc-test.js b/packages/react-dataparcels/src/deprecated/__test__/ParcelHoc-test.js deleted file mode 100644 index 3ba8896f..00000000 --- a/packages/react-dataparcels/src/deprecated/__test__/ParcelHoc-test.js +++ /dev/null @@ -1,348 +0,0 @@ -// @flow -import React from 'react'; -import {Map} from 'immutable'; -import ParcelHoc from '../ParcelHoc'; - -let shallowRenderHoc = (props, hock) => { - let Component = hock((props) =>
); - return shallow(); -}; - -test('ParcelHoc config should accept an initial valueFromProps', () => { - let valueFromProps = jest.fn((props) => 456); - - let props = { - abc: 123 - }; - - let childProps = shallowRenderHoc( - props, - ParcelHoc({ - valueFromProps, - name: "proppy" - }) - ).props(); - - // valueFromProps should be props - expect(valueFromProps.mock.calls[0][0]).toEqual(props); - - // child props should include a prop with the name from config.name and a value from the return of valueFromProps - expect(childProps.proppy.value).toBe(456); -}); - -test('ParcelHoc changes should be put back into ParcelHoc state', () => { - let Child = () =>
; - let Hocked = ParcelHoc({ - valueFromProps: () => 123, - name: "proppy" - })(Child); - - let wrapper = shallow(); - let {proppy} = wrapper.props(); - proppy.set(456); - expect(456).toBe(wrapper.update().props().proppy.value); -}); - -test('ParcelHoc config should accept an onChange function, and call it with the value when changed', () => { - let Child = () =>
; - let Hocked = ParcelHoc({ - valueFromProps: () => 123, - onChange: (props) => (value) => props.onChange(value), - name: "proppy" - })(Child); - - let onChange = jest.fn(); - let wrapper = shallow(); - let {proppy} = wrapper.props(); - proppy.set(456); - - expect(onChange).toHaveBeenCalledTimes(1); - expect(onChange.mock.calls[0][0]).toBe(456); - - // dont call onChange if the value hasnt changed - wrapper.update().props().proppy.set(456); - expect(onChange).toHaveBeenCalledTimes(1); -}); - -test('ParcelHoc config should accept an delayUntil function, and pass undefined until this evaluates to true', () => { - let Child = () =>
; - - let Hocked = ParcelHoc({ - valueFromProps: () => 123, - delayUntil: (props) => props.go, - name: "proppy" - })(Child); - - let wrapper = shallow(); - expect(wrapper.props().proppy).toBe(undefined); - - wrapper.setProps({go: true}); - expect(wrapper.props().proppy.value).toBe(123); -}); - -test('ParcelHoc config should accept a pipe function', () => { - let childProps = shallowRenderHoc( - {}, - ParcelHoc({ - valueFromProps: () => 456, - name: "proppy", - pipe: (props) => (parcel) => { - expect(456).toBe(parcel.value); - expect({}).toEqual(props); - return parcel.modifyDown(ii => ii + 1); - } - }) - ).props(); - - expect(457).toBe(childProps.proppy.value); -}); - -test('ParcelHoc shouldParcelUpdateFromProps should update value from props when it is returned true', () => { - let valueFromProps = jest.fn((props) => props.abc); - - let shouldParcelUpdateFromProps = jest.fn((prevProps: *, nextProps: *, valueFromProps: Function) => valueFromProps(prevProps) !== valueFromProps(nextProps)); - - let props = { - abc: 123, - def: 456 - }; - - let wrapper = shallowRenderHoc( - props, - ParcelHoc({ - valueFromProps, - name: "proppy", - shouldParcelUpdateFromProps - }) - ); - - let childProps = wrapper.props(); - - // valueFromProps should be props - expect(valueFromProps.mock.calls[0][0]).toEqual(props); - - // child parcel should contain result of valueFromProps - expect(childProps.proppy.value).toBe(123); - - // set prop that SHOULDN'T cause a controlled update - wrapper.setProps({ - def: 789 - }); - - let childProps2 = wrapper.props(); - - // shouldParcelUpdateFromProps should have been called with correct prevProps and nextProps - expect(shouldParcelUpdateFromProps).toHaveBeenCalledTimes(1); - expect(shouldParcelUpdateFromProps.mock.calls[0][0]).toEqual({ - abc: 123, - def: 456 - }); - - expect(shouldParcelUpdateFromProps.mock.calls[0][1]).toEqual({ - abc: 123, - def: 789 - }); - - // child parcel should still contain original result of valueFromProps - expect(childProps2.proppy.value).toBe(123); - - // set prop that SHOULD cause a controlled update - wrapper.setProps({ - abc: "!!!" - }); - - let childProps3 = wrapper.props(); - - // shouldParcelUpdateFromProps should have been called with correct prevProps and nextProps - expect(shouldParcelUpdateFromProps).toHaveBeenCalledTimes(2); - expect(shouldParcelUpdateFromProps.mock.calls[1][0]).toEqual({ - abc: 123, - def: 789 - }); - - expect(shouldParcelUpdateFromProps.mock.calls[1][1]).toEqual({ - abc: "!!!", - def: 789 - }); - - // child parcel should now contain new result of valueFromProps - expect(childProps3.proppy.value).toBe("!!!"); -}); - -test('ParcelHoc modifyBeforeUpdate should be called when value is set', () => { - let modifyBeforeUpdate = jest.fn(value => value + 1); - - let wrapper = shallowRenderHoc( - {}, - ParcelHoc({ - valueFromProps: () => 123, - name: "proppy", - modifyBeforeUpdate: [ - modifyBeforeUpdate - ] - }) - ); - - let childProps = wrapper.props(); - - // child parcel should contain value after having been passed through modifyBeforeUpdate - expect(childProps.proppy.value).toBe(124); -}); - -test('ParcelHoc modifyBeforeUpdate should be called when change occurs', () => { - - let wrapper = shallowRenderHoc( - {}, - ParcelHoc({ - valueFromProps: () => 123, - name: "proppy", - modifyBeforeUpdate: [ - value => value + 1, - value => value + 1 - ] - }) - ); - - let childProps = wrapper.props(); - childProps.proppy.set(456); - - // child parcel should contain value after having been passed through modifyBeforeUpdate - expect(wrapper.update().props().proppy.value).toBe(458); -}); - -test('ParcelHoc modifyBeforeUpdate should be called when relevant prop change occurs', () => { - let wrapper = shallowRenderHoc( - {}, - ParcelHoc({ - valueFromProps: () => 123, - name: "proppy", - modifyBeforeUpdate: [ - value => value + 1, - value => value + 1 - ] - }) - ); - - let childProps = wrapper.props(); - childProps.proppy.set(456); - - // child parcel should contain value after having been passed through modifyBeforeUpdate - expect(wrapper.update().props().proppy.value).toBe(458); -}); - -test('ParcelHoc modifyBeforeUpdate should be called when relevant prop change occurs', () => { - - let wrapper = shallowRenderHoc( - { - abc: 123 - }, - ParcelHoc({ - valueFromProps: (props) => props.abc, - name: "proppy", - shouldParcelUpdateFromProps: (prevProps, nextProps, valueFromProps) => valueFromProps(prevProps) !== valueFromProps(nextProps), - modifyBeforeUpdate: [ - value => value + 1, - value => value + 1 - ] - }) - ); - - let childProps = wrapper.props(); - - // set prop that should cause a controlled update - wrapper.setProps({ - abc: 456 - }); - - let childProps2 = wrapper.props(); - // child parcel should contain value after having been passed through modifyBeforeUpdate - expect(childProps2.proppy.value).toBe(458); -}); - - -test('ParcelHoc config should accept a debugParcel boolean and log about receiving initial value', () => { - let {log} = console; - // $FlowFixMe - console.log = jest.fn(); // eslint-disable-line - let childProps = shallowRenderHoc( - {}, - ParcelHoc({ - valueFromProps: () => 456, - name: "proppy", - debugParcel: true - }) - ).props(); - - expect(console.log).toHaveBeenCalled(); - expect(console.log.mock.calls[0][0]).toBe("ParcelHoc: Received initial value:"); - // $FlowFixMe - console.log = log; // eslint-disable-line -}); - -test('ParcelHoc config should accept a debugParcel boolean and log about changing value', () => { - let {log} = console; - // $FlowFixMe - console.log = jest.fn(); // eslint-disable-line - let childProps = shallowRenderHoc( - {}, - ParcelHoc({ - valueFromProps: () => 456, - name: "proppy", - debugParcel: true - }) - ).props(); - - childProps.proppy.set("!"); - - expect(console.log.mock.calls[2][0]).toBe("ParcelHoc: Parcel changed:"); - // $FlowFixMe - console.log = log; // eslint-disable-line -}); - - - -test('ParcelHoc config should accept a debugParcel boolean and log about updatgin from props', () => { - let {log} = console; - // $FlowFixMe - console.log = jest.fn(); // eslint-disable-line - let wrapper = shallowRenderHoc( - {}, - ParcelHoc({ - valueFromProps: () => 456, - name: "proppy", - debugParcel: true, - shouldParcelUpdateFromProps: () => true - }) - ); - - wrapper.setProps({ - def: 789 - }); - - wrapper.props(); - - expect(console.log.mock.calls[2][0]).toBe("ParcelHoc: Parcel updated from props:"); - // $FlowFixMe - console.log = log; // eslint-disable-line -}); - -test('ParcelHoc should not log deprecation notice when NODE_ENV=production', () => { - let {NODE_ENV} = process.env; - process.env.NODE_ENV = 'production'; - - let {warn} = console; - // $FlowFixMe - console.warn = jest.fn(); // eslint-disable-line - - ParcelHoc({ - name: 'testParcel', - valueFromProps: () => {} - }); - - expect(console.warn).not.toHaveBeenCalled(); - - // $FlowFixMe - console.warn = warn; // eslint-disable-line - - process.env.NODE_ENV = NODE_ENV; -}); diff --git a/packages/react-dataparcels/src/useParcelBuffer.js b/packages/react-dataparcels/src/useParcelBuffer.js index e7be6abd..0403ffb9 100644 --- a/packages/react-dataparcels/src/useParcelBuffer.js +++ b/packages/react-dataparcels/src/useParcelBuffer.js @@ -12,7 +12,6 @@ import useDebouncedCallback from 'use-debounce/lib/callback'; import pipe from 'unmutable/pipe'; import Parcel from 'dataparcels'; -import asRaw from 'dataparcels/asRaw'; import setMeta from 'dataparcels/lib/parcelData/setMeta'; import ApplyBeforeChange from './util/ApplyBeforeChange'; @@ -54,11 +53,11 @@ export default (params: Params): Return => { // 2. always add and set buffer meta to be passed to innerParcel const applyBufferMeta = (parcel) => parcel - .modifyDown(asRaw( + .modifyDown( setMeta({ _control: null }) - )); + ); const applyModifiers = pipe( applyBeforeChange, diff --git a/packages/react-dataparcels/src/useParcelState.js b/packages/react-dataparcels/src/useParcelState.js index f3115f2b..2c391e8f 100644 --- a/packages/react-dataparcels/src/useParcelState.js +++ b/packages/react-dataparcels/src/useParcelState.js @@ -8,6 +8,7 @@ import {useState} from 'react'; // $FlowFixMe - useState is a named export of react import {useRef} from 'react'; import useParcelSideEffectSync from './useParcelSideEffectSync'; + import Parcel from 'dataparcels'; import cancel from 'dataparcels/cancel'; import ApplyBeforeChange from './util/ApplyBeforeChange'; @@ -66,7 +67,7 @@ export default (params: Params): Return => { return parcel._changeAndReturn( parcel => parcel .pipe(applyBeforeChange) - .update(valueUpdater) + .set(valueUpdater()) )[0]; }); @@ -76,11 +77,11 @@ export default (params: Params): Return => { if(params.updateValue) { parcel - .modifyUp((value, changeRequest) => { + .modifyUp(({value, changeRequest}) => { return changeRequest.hasDataChanged() ? value : cancel; }) .pipe(applyBeforeChange) - .update(valueUpdater); + .set(valueUpdater()); } // use the rebase param diff --git a/packages/react-dataparcels/src/util/__test__/pipeWithFakePrevParcel-test.js b/packages/react-dataparcels/src/util/__test__/pipeWithFakePrevParcel-test.js index 237936b7..32f4fa45 100644 --- a/packages/react-dataparcels/src/util/__test__/pipeWithFakePrevParcel-test.js +++ b/packages/react-dataparcels/src/util/__test__/pipeWithFakePrevParcel-test.js @@ -12,17 +12,17 @@ test('pipeWithFakePrevParcel should fakely set a previous', () => { value: 100 }); - let modifyUp = jest.fn(value => value * 2); + let modifyUp = jest.fn(({value}) => ({value: value * 2})); let newParcel = parcel.pipe(pipeWithFakePrevParcel( fakePrevParcel, parcel => parcel.modifyUp(modifyUp) )); - let [modifyUpValue, changeRequest] = modifyUp.mock.calls[0]; + let {value, changeRequest} = modifyUp.mock.calls[0][0]; expect(newParcel.value).toBe(246); - expect(modifyUpValue).toBe(123); + expect(value).toBe(123); expect(changeRequest.prevData.value).toBe(100); expect(changeRequest.nextData.value).toBe(123); }); diff --git a/packages/react-dataparcels/src/util/pipeWithFakePrevParcel.js b/packages/react-dataparcels/src/util/pipeWithFakePrevParcel.js index 24bfb9ee..d67edfb2 100644 --- a/packages/react-dataparcels/src/util/pipeWithFakePrevParcel.js +++ b/packages/react-dataparcels/src/util/pipeWithFakePrevParcel.js @@ -3,7 +3,6 @@ import type {ParcelUpdater} from 'dataparcels'; import Parcel from 'dataparcels'; -import asRaw from 'dataparcels/asRaw'; export default (prevParcel: ?Parcel, ...pipe: ParcelUpdater[]) => (parcel: Parcel): Parcel => { let [changedParcel] = parcel._changeAndReturn((parcel) => { @@ -11,7 +10,7 @@ export default (prevParcel: ?Parcel, ...pipe: ParcelUpdater[]) => (parcel: Parce let setPrevParcel; if(prevParcel) { let prevParcelData = prevParcel.data; - setPrevParcel = asRaw(() => prevParcelData); + setPrevParcel = () => prevParcelData; } return parcel