Skip to content

Commit

Permalink
fix(core): add merge strategy for provide option (#6025)
Browse files Browse the repository at this point in the history
Fix #6008
  • Loading branch information
znck authored and yyx990803 committed Jul 7, 2017
1 parent 254d85c commit 306997e
Show file tree
Hide file tree
Showing 2 changed files with 126 additions and 11 deletions.
36 changes: 25 additions & 11 deletions src/core/util/options.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ function mergeData (to: Object, from: ?Object): Object {
/**
* Data
*/
strats.data = function (
export function mergeDataOrFn (
parentVal: any,
childVal: any,
vm?: Component
Expand All @@ -73,15 +73,6 @@ strats.data = function (
if (!childVal) {
return parentVal
}
if (typeof childVal !== 'function') {
process.env.NODE_ENV !== 'production' && warn(
'The "data" option should be a function ' +
'that returns a per-instance value in component ' +
'definitions.',
vm
)
return parentVal
}
if (!parentVal) {
return childVal
}
Expand All @@ -92,7 +83,7 @@ strats.data = function (
// it has to be a function to pass previous merges.
return function mergedDataFn () {
return mergeData(
childVal.call(this),
typeof childVal === 'function' ? childVal.call(this) : childVal,
parentVal.call(this)
)
}
Expand All @@ -114,6 +105,28 @@ strats.data = function (
}
}

strats.data = function (
parentVal: any,
childVal: any,
vm?: Component
): ?Function {
if (!vm) {
if (childVal && typeof childVal !== 'function') {
process.env.NODE_ENV !== 'production' && warn(
'The "data" option should be a function ' +
'that returns a per-instance value in component ' +
'definitions.',
vm
)

return parentVal
}
return mergeDataOrFn.call(this, parentVal, childVal)
}

return mergeDataOrFn(parentVal, childVal, vm)
}

/**
* Hooks and props are merged as arrays.
*/
Expand Down Expand Up @@ -191,6 +204,7 @@ strats.computed = function (parentVal: ?Object, childVal: ?Object): ?Object {
extend(ret, childVal)
return ret
}
strats.provide = mergeDataOrFn

/**
* Default strategy.
Expand Down
101 changes: 101 additions & 0 deletions test/unit/features/options/inject.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -298,4 +298,105 @@ describe('Options provide/inject', () => {
expect(`Injection "bar" not found`).not.toHaveBeenWarned()
expect(`Injection "baz" not found`).not.toHaveBeenWarned()
})

// Github issue #6008
it('should merge provide from mixins (objects)', () => {
const mixinA = { provide: { foo: 'foo' }}
const mixinB = { provide: { bar: 'bar' }}
const child = {
inject: ['foo', 'bar'],
template: `<span/>`,
created () {
injected = [this.foo, this.bar]
}
}
new Vue({
mixins: [mixinA, mixinB],
render (h) {
return h(child)
}
}).$mount()

expect(injected).toEqual(['foo', 'bar'])
})
it('should merge provide from mixins (functions)', () => {
const mixinA = { provide: () => ({ foo: 'foo' }) }
const mixinB = { provide: () => ({ bar: 'bar' }) }
const child = {
inject: ['foo', 'bar'],
template: `<span/>`,
created () {
injected = [this.foo, this.bar]
}
}
new Vue({
mixins: [mixinA, mixinB],
render (h) {
return h(child)
}
}).$mount()

expect(injected).toEqual(['foo', 'bar'])
})
it('should merge provide from mixins (mix of objects and functions)', () => {
const mixinA = { provide: { foo: 'foo' }}
const mixinB = { provide: () => ({ bar: 'bar' }) }
const mixinC = { provide: { baz: 'baz' }}
const mixinD = { provide: () => ({ bam: 'bam' }) }
const child = {
inject: ['foo', 'bar', 'baz', 'bam'],
template: `<span/>`,
created () {
injected = [this.foo, this.bar, this.baz, this.bam]
}
}
new Vue({
mixins: [mixinA, mixinB, mixinC, mixinD],
render (h) {
return h(child)
}
}).$mount()

expect(injected).toEqual(['foo', 'bar', 'baz', 'bam'])
})
it('should merge provide from mixins and override existing keys', () => {
const mixinA = { provide: { foo: 'foo' }}
const mixinB = { provide: { foo: 'bar' }}
const child = {
inject: ['foo'],
template: `<span/>`,
created () {
injected = [this.foo]
}
}
new Vue({
mixins: [mixinA, mixinB],
render (h) {
return h(child)
}
}).$mount()

expect(injected).toEqual(['bar'])
})
it('should merge provide when Vue.extend', () => {
const mixinA = { provide: () => ({ foo: 'foo' }) }
const child = {
inject: ['foo', 'bar'],
template: `<span/>`,
created () {
injected = [this.foo, this.bar]
}
}
const Ctor = Vue.extend({
mixins: [mixinA],
provide: { bar: 'bar' },
render (h) {
return h(child)
}
})

new Ctor().$mount()

expect(injected).toEqual(['foo', 'bar'])
})
})

0 comments on commit 306997e

Please sign in to comment.