mirror of
https://github.com/tenrok/vue-meta.git
synced 2026-06-25 01:20:34 +03:00
refactor: optimize getComponentOption by making it less generic
This commit is contained in:
committed by
Alexander Lichter
parent
7b888c9437
commit
23c3380c90
@@ -1,7 +1,7 @@
|
|||||||
import deepmerge from 'deepmerge'
|
import { merge } from './merge'
|
||||||
import uniqueId from 'lodash.uniqueid'
|
import applyTemplate from './applyTemplate'
|
||||||
import { isUndefined, isFunction, isObject } from './typeof'
|
import inMetaInfoBranch from './inMetaInfoBranch'
|
||||||
import uniqBy from './uniqBy'
|
import { isFunction, isObject } from './typeof'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the `opts.option` $option value of the given `opts.component`.
|
* 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
|
* @param {Object} [result={}] - result so far
|
||||||
* @return {Object} result - final aggregated result
|
* @return {Object} result - final aggregated result
|
||||||
*/
|
*/
|
||||||
export default function getComponentOption({ component, deep, arrayMerge, keyName, metaTemplateKeyName, tagIDKeyName, contentKeyName } = {}, result = {}) {
|
export default function getComponentOption(options = {}, result = {}) {
|
||||||
const { $options } = component
|
const { component, keyName, metaTemplateKeyName, tagIDKeyName } = options
|
||||||
|
const { $options, $children } = component
|
||||||
|
|
||||||
if (component._inactive) {
|
if (component._inactive) {
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
// only collect option data if it exists
|
// only collect option data if it exists
|
||||||
if (!isUndefined($options[keyName]) && $options[keyName] !== null) {
|
if ($options[keyName]) {
|
||||||
let data = $options[keyName]
|
let data = $options[keyName]
|
||||||
|
|
||||||
// if option is a function, replace it with it's result
|
// 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)
|
data = data.call(component)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isObject(data)) {
|
// ignore data if its not an object, then we keep our previous result
|
||||||
// merge with existing options
|
if (!isObject(data)) {
|
||||||
result = deepmerge(result, data, { arrayMerge })
|
console.log(data)
|
||||||
} else {
|
return result
|
||||||
result = data
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// merge with existing options
|
||||||
|
result = merge(result, data, options)
|
||||||
}
|
}
|
||||||
|
|
||||||
// collect & aggregate child options if deep = true
|
// collect & aggregate child options if deep = true
|
||||||
if (deep && component.$children.length) {
|
if ($children.length) {
|
||||||
component.$children.forEach((childComponent) => {
|
$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({
|
result = getComponentOption({
|
||||||
component: childComponent,
|
...options,
|
||||||
keyName,
|
component: childComponent
|
||||||
deep,
|
|
||||||
arrayMerge
|
|
||||||
}, result)
|
}, result)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
if (metaTemplateKeyName && result.hasOwnProperty('meta')) {
|
if (metaTemplateKeyName && result.meta) {
|
||||||
result.meta = Object.keys(result.meta).map((metaKey) => {
|
// apply templates if needed
|
||||||
const metaObject = result.meta[metaKey]
|
result.meta.forEach(metaObject => applyTemplate(options, metaObject))
|
||||||
if (!metaObject.hasOwnProperty(metaTemplateKeyName) || !metaObject.hasOwnProperty(contentKeyName) || isUndefined(metaObject[metaTemplateKeyName])) {
|
|
||||||
return result.meta[metaKey]
|
|
||||||
}
|
|
||||||
|
|
||||||
const template = metaObject[metaTemplateKeyName]
|
// remove meta items with duplicate vmid's
|
||||||
delete metaObject[metaTemplateKeyName]
|
result.meta = result.meta.filter((metaItem, index, arr) => {
|
||||||
|
return (
|
||||||
if (template) {
|
// keep meta item if it doesnt has a vmid
|
||||||
metaObject.content = isFunction(template) ? template(metaObject.content) : template.replace(/%s/g, metaObject.content)
|
!metaItem.hasOwnProperty(tagIDKeyName) ||
|
||||||
}
|
// or if it's the first item in the array with this vmid
|
||||||
|
index === arr.findIndex(item => item[tagIDKeyName] === metaItem[tagIDKeyName])
|
||||||
return metaObject
|
)
|
||||||
})
|
})
|
||||||
result.meta = uniqBy(
|
|
||||||
result.meta,
|
|
||||||
metaObject => metaObject.hasOwnProperty(tagIDKeyName) ? metaObject[tagIDKeyName] : uniqueId()
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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])
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import getComponentOption from '../src/shared/getComponentOption'
|
import getComponentOption from '../src/shared/getComponentOption'
|
||||||
import { getVue } from './utils'
|
import { mount, getVue, loadVueMetaPlugin } from './utils'
|
||||||
|
|
||||||
describe('getComponentOption', () => {
|
describe('getComponentOption', () => {
|
||||||
let Vue
|
let Vue
|
||||||
@@ -31,46 +31,53 @@ describe('getComponentOption', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('fetches deeply nested component options and merges them', () => {
|
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' },
|
foo: { fizz: 'buzz' },
|
||||||
el: document.createElement('div'),
|
|
||||||
render: h => h('div', null, [h('merge-child')])
|
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' })
|
expect(mergedOption).toEqual({ bar: 'baz', fizz: 'buzz' })
|
||||||
})
|
})
|
||||||
|
|
||||||
it('allows for a custom array merge strategy', () => {
|
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'),
|
render: h => h('div'),
|
||||||
foo: [
|
foo: {
|
||||||
{ name: 'flower', content: 'rose' }
|
meta: [
|
||||||
]
|
{ name: 'flower', content: 'rose' }
|
||||||
|
]
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const component = new Vue({
|
const component = localVue.component('parent', {
|
||||||
foo: [
|
foo: {
|
||||||
{ name: 'flower', content: 'tulip' }
|
meta: [
|
||||||
],
|
{ name: 'flower', content: 'tulip' }
|
||||||
el: document.createElement('div'),
|
]
|
||||||
|
},
|
||||||
render: h => h('div', null, [h('array-child')])
|
render: h => h('div', null, [h('array-child')])
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const wrapper = mount(component, { localVue })
|
||||||
|
|
||||||
const mergedOption = getComponentOption({
|
const mergedOption = getComponentOption({
|
||||||
component,
|
component: wrapper.vm,
|
||||||
keyName: 'foo',
|
keyName: 'foo',
|
||||||
deep: true,
|
|
||||||
arrayMerge(target, source) {
|
arrayMerge(target, source) {
|
||||||
return target.concat(source)
|
return target.concat(source)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(mergedOption).toEqual([
|
expect(mergedOption).toEqual({ meta: [
|
||||||
{ name: 'flower', content: 'tulip' },
|
{ name: 'flower', content: 'tulip' },
|
||||||
{ name: 'flower', content: 'rose' }
|
{ name: 'flower', content: 'rose' }
|
||||||
])
|
] })
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user