diff --git a/src/index.js b/src/index.js index 90a88331..6edfdbd3 100644 --- a/src/index.js +++ b/src/index.js @@ -4,6 +4,10 @@ function objectEntries(obj) { return Object.keys(obj).map(key => [key, obj[key]]); } +function typeOf(obj) { + return ({}).toString.call(obj).match(/\s([a-zA-Z]+)/)[1].toLowerCase(); +} + function normalizeNamespace(fn) { return (...params) => { // eslint-disable-next-line prefer-const @@ -23,11 +27,11 @@ function normalizeNamespace(fn) { } export function getField(state) { - return path => path.split(/[.[\]]+/).reduce((prev, key) => prev[key], state); + return path => path.split(/[.[\]]+/).filter(x => x).reduce((prev, key) => prev[key], state); } export function updateField(state, { path, value }) { - path.split(/[.[\]]+/).reduce((prev, key, index, array) => { + path.split(/[.[\]]+/).filter(x => x).reduce((prev, key, index, array) => { if (array.length === index + 1) { // eslint-disable-next-line no-param-reassign prev[key] = value; @@ -37,24 +41,44 @@ export function updateField(state, { path, value }) { }, state); } -export const mapFields = normalizeNamespace((namespace, fields, getterType, mutationType) => { - const fieldsObject = Array.isArray(fields) ? arrayToObject(fields) : fields; +export const mapFields = normalizeNamespace(( + namespace, + paths, + getterType, + mutationType, +) => { + const pathsObject = Array.isArray(paths) ? arrayToObject(paths) : paths; + return Object.keys(pathsObject).reduce((entries, key) => { + const path = pathsObject[key]; - return Object.keys(fieldsObject).reduce((prev, key) => { - const path = fieldsObject[key]; - const field = { + // eslint-disable-next-line no-param-reassign + entries[key] = { get() { - return this.$store.getters[getterType](path); + const tpath = typeof path === `function` ? path.call(null, this) : path; + const store = this.$store; + const row = store.getters[getterType](tpath); + + if (!row || typeOf(row) !== `object`) return row; + + return Object.keys(row).reduce((prev, fieldKey) => { + const fieldPath = `${tpath}.${fieldKey}`; + return Object.defineProperty(prev, fieldKey, { + get() { + return store.getters[getterType](fieldPath); + }, + set(value) { + store.commit(mutationType, { path: fieldPath, value }); + }, + }); + }, {}); }, set(value) { - this.$store.commit(mutationType, { path, value }); + const tpath = typeof path === `function` ? path.call(null, this) : path; + this.$store.commit(mutationType, { path: tpath, value }); }, }; - // eslint-disable-next-line no-param-reassign - prev[key] = field; - - return prev; + return entries; }, {}); }); @@ -72,12 +96,13 @@ export const mapMultiRowFields = normalizeNamespace(( // eslint-disable-next-line no-param-reassign entries[key] = { get() { + const tpath = typeof path === `function` ? path.call(null, this) : path; const store = this.$store; - const rows = objectEntries(store.getters[getterType](path)); + const rows = objectEntries(store.getters[getterType](tpath)); return rows .map(fieldsObject => Object.keys(fieldsObject[1]).reduce((prev, fieldKey) => { - const fieldPath = `${path}[${fieldsObject[0]}].${fieldKey}`; + const fieldPath = `${tpath}[${fieldsObject[0]}].${fieldKey}`; return Object.defineProperty(prev, fieldKey, { get() { diff --git a/src/lib/array-to-object.js b/src/lib/array-to-object.js index 7528582e..452098cb 100644 --- a/src/lib/array-to-object.js +++ b/src/lib/array-to-object.js @@ -1,5 +1,7 @@ export default function arrayToObject(fields = []) { return fields.reduce((prev, path) => { + if (typeof path === `object`) return { ...prev, ...path }; + const key = path.split(`.`).slice(-1)[0]; if (prev[key]) { diff --git a/test/function-param.test.js b/test/function-param.test.js new file mode 100644 index 00000000..b93af628 --- /dev/null +++ b/test/function-param.test.js @@ -0,0 +1,81 @@ +import Vuex from 'vuex'; +import { createLocalVue, shallowMount } from '@vue/test-utils'; + +import { createHelpers, getField, updateField } from '../src'; + +const localVue = createLocalVue(); + +localVue.use(Vuex); + +const { mapFields } = createHelpers({ + getterType: `getField`, + mutationType: `updateField`, +}); + +describe(`Component initialized with row setup.`, () => { + let Component; + let store; + let wrapper; + + beforeEach(() => { + + Component = { + template: ` +