From 23c3380c90d4a0c9ecce9b6d1651f56338a94ef8 Mon Sep 17 00:00:00 2001 From: pimlie Date: Fri, 8 Mar 2019 13:40:30 +0100 Subject: [PATCH] refactor: optimize getComponentOption by making it less generic --- src/shared/getComponentOption.js | 73 ++++++++++++++++---------------- src/shared/uniqBy.js | 7 --- test/getComponentOptions.test.js | 43 +++++++++++-------- 3 files changed, 62 insertions(+), 61 deletions(-) delete mode 100644 src/shared/uniqBy.js diff --git a/src/shared/getComponentOption.js b/src/shared/getComponentOption.js index f468520..dfcca9c 100644 --- a/src/shared/getComponentOption.js +++ b/src/shared/getComponentOption.js @@ -1,7 +1,7 @@ -import deepmerge from 'deepmerge' -import uniqueId from 'lodash.uniqueid' -import { isUndefined, isFunction, isObject } from './typeof' -import uniqBy from './uniqBy' +import { merge } from './merge' +import applyTemplate from './applyTemplate' +import inMetaInfoBranch from './inMetaInfoBranch' +import { isFunction, isObject } from './typeof' /** * Returns the `opts.option` $option value of the given `opts.component`. @@ -17,15 +17,16 @@ import uniqBy from './uniqBy' * @param {Object} [result={}] - result so far * @return {Object} result - final aggregated result */ -export default function getComponentOption({ component, deep, arrayMerge, keyName, metaTemplateKeyName, tagIDKeyName, contentKeyName } = {}, result = {}) { - const { $options } = component +export default function getComponentOption(options = {}, result = {}) { + const { component, keyName, metaTemplateKeyName, tagIDKeyName } = options + const { $options, $children } = component if (component._inactive) { return result } // only collect option data if it exists - if (!isUndefined($options[keyName]) && $options[keyName] !== null) { + if ($options[keyName]) { let data = $options[keyName] // if option is a function, replace it with it's result @@ -33,46 +34,46 @@ export default function getComponentOption({ component, deep, arrayMerge, keyNam data = data.call(component) } - if (isObject(data)) { - // merge with existing options - result = deepmerge(result, data, { arrayMerge }) - } else { - result = data + // ignore data if its not an object, then we keep our previous result + if (!isObject(data)) { + console.log(data) + return result } + + // merge with existing options + result = merge(result, data, options) } // collect & aggregate child options if deep = true - if (deep && component.$children.length) { - component.$children.forEach((childComponent) => { + if ($children.length) { + $children.forEach((childComponent) => { + // check if the childComponent is in a branch + // return otherwise so we dont walk all component branches unnecessarily + if (!inMetaInfoBranch(childComponent)) { + return + } + result = getComponentOption({ - component: childComponent, - keyName, - deep, - arrayMerge + ...options, + component: childComponent }, result) }) } - if (metaTemplateKeyName && result.hasOwnProperty('meta')) { - result.meta = Object.keys(result.meta).map((metaKey) => { - const metaObject = result.meta[metaKey] - if (!metaObject.hasOwnProperty(metaTemplateKeyName) || !metaObject.hasOwnProperty(contentKeyName) || isUndefined(metaObject[metaTemplateKeyName])) { - return result.meta[metaKey] - } + if (metaTemplateKeyName && result.meta) { + // apply templates if needed + result.meta.forEach(metaObject => applyTemplate(options, metaObject)) - const template = metaObject[metaTemplateKeyName] - delete metaObject[metaTemplateKeyName] - - if (template) { - metaObject.content = isFunction(template) ? template(metaObject.content) : template.replace(/%s/g, metaObject.content) - } - - return metaObject + // remove meta items with duplicate vmid's + result.meta = result.meta.filter((metaItem, index, arr) => { + return ( + // keep meta item if it doesnt has a vmid + !metaItem.hasOwnProperty(tagIDKeyName) || + // or if it's the first item in the array with this vmid + index === arr.findIndex(item => item[tagIDKeyName] === metaItem[tagIDKeyName]) + ) }) - result.meta = uniqBy( - result.meta, - metaObject => metaObject.hasOwnProperty(tagIDKeyName) ? metaObject[tagIDKeyName] : uniqueId() - ) } + return result } diff --git a/src/shared/uniqBy.js b/src/shared/uniqBy.js deleted file mode 100644 index c3257d9..0000000 --- a/src/shared/uniqBy.js +++ /dev/null @@ -1,7 +0,0 @@ -export default function uniqBy(inputArray, predicate) { - return inputArray - .filter((x, i, arr) => i === arr.length - 1 - ? true - : predicate(x) !== predicate(arr[i + 1]) - ) -} diff --git a/test/getComponentOptions.test.js b/test/getComponentOptions.test.js index ba04fb2..2517745 100644 --- a/test/getComponentOptions.test.js +++ b/test/getComponentOptions.test.js @@ -1,5 +1,5 @@ import getComponentOption from '../src/shared/getComponentOption' -import { getVue } from './utils' +import { mount, getVue, loadVueMetaPlugin } from './utils' describe('getComponentOption', () => { let Vue @@ -31,46 +31,53 @@ describe('getComponentOption', () => { }) it('fetches deeply nested component options and merges them', () => { - Vue.component('merge-child', { render: h => h('div'), foo: { bar: 'baz' } }) + const localVue = loadVueMetaPlugin(true, { keyName: 'foo' }) + localVue.component('merge-child', { render: h => h('div'), foo: { bar: 'baz' } }) - const component = new Vue({ + const component = localVue.component('parent', { foo: { fizz: 'buzz' }, - el: document.createElement('div'), render: h => h('div', null, [h('merge-child')]) }) - const mergedOption = getComponentOption({ component, keyName: 'foo', deep: true }) + const wrapper = mount(component, { localVue }) + + const mergedOption = getComponentOption({ component: wrapper.vm, keyName: 'foo' }) expect(mergedOption).toEqual({ bar: 'baz', fizz: 'buzz' }) }) it('allows for a custom array merge strategy', () => { - Vue.component('array-child', { + const localVue = loadVueMetaPlugin(false, { keyName: 'foo' }) + localVue.component('array-child', { render: h => h('div'), - foo: [ - { name: 'flower', content: 'rose' } - ] + foo: { + meta: [ + { name: 'flower', content: 'rose' } + ] + } }) - const component = new Vue({ - foo: [ - { name: 'flower', content: 'tulip' } - ], - el: document.createElement('div'), + const component = localVue.component('parent', { + foo: { + meta: [ + { name: 'flower', content: 'tulip' } + ] + }, render: h => h('div', null, [h('array-child')]) }) + const wrapper = mount(component, { localVue }) + const mergedOption = getComponentOption({ - component, + component: wrapper.vm, keyName: 'foo', - deep: true, arrayMerge(target, source) { return target.concat(source) } }) - expect(mergedOption).toEqual([ + expect(mergedOption).toEqual({ meta: [ { name: 'flower', content: 'tulip' }, { name: 'flower', content: 'rose' } - ]) + ] }) }) })