Skip to content

Commit 28bb545

Browse files
fix(#2): don't copy level 1 obj refs
1 parent 72cfbae commit 28bb545

File tree

1 file changed

+91
-81
lines changed

1 file changed

+91
-81
lines changed

Diff for: src/index.ts

+91-81
Original file line numberDiff line numberDiff line change
@@ -1,103 +1,113 @@
11
import { VNodeData } from "vue"
22

3-
const keys = Object.keys
4-
53
function concat(...items: any[]): any[]
64
function concat(...items: any[][]): any[]
75
function concat() {
8-
return Array.prototype.concat.apply([], arguments)
6+
return Array.prototype.concat.apply([], arguments)
7+
}
8+
9+
function cp(value: any): any {
10+
if (typeof value != "object" || value == null) {
11+
return value
12+
}
13+
if (Array.isArray(value)) {
14+
return [...value]
15+
}
16+
return Object.assign({}, value)
917
}
1018

1119
/**
1220
* Intelligently merges data for createElement.
1321
* Merges arguments left to right, preferring the right argument.
1422
* Returns new VNodeData object.
1523
*/
16-
function mergeData(...vNodeData: VNodeData[]): VNodeData
17-
function mergeData() {
18-
// Start by copying the first arg into a fresh object
19-
let mergeTarget = { ...arguments[0] }
24+
function mergeData(...vNodeData: VNodeData[]): VNodeData {
25+
let mergeTarget: VNodeData & { [key: string]: any } = {}
26+
let i: number = 0
27+
let argLen: number = arguments.length
28+
let prop: string
2029

21-
// Allow for variadic argument length.
22-
// Skip first argument that was assigned to mergeTarget.
23-
for (let i = 1; i < arguments.length; i++) {
24-
// Iterate through the data properties and execute merge strategies
25-
// Object.keys eliminates need for hasOwnProperty call
26-
for (const prop of keys(arguments[i])) {
27-
// If strictly undefined, simply assign value and continue
28-
if (mergeTarget[prop] === undefined) {
29-
mergeTarget[prop] = arguments[i][prop]
30-
continue
31-
}
30+
// Allow for variadic argument length.
31+
for (; i < argLen; i++) {
32+
// Iterate through the data properties and execute merge strategies
33+
// Object.keys eliminates need for hasOwnProperty call
34+
for (prop of Object.keys(arguments[i])) {
35+
// If strictly undefined, copy value and continue
36+
if (mergeTarget[prop] === undefined) {
37+
mergeTarget[prop] = cp(arguments[i][prop])
38+
continue
39+
}
3240

33-
switch (prop) {
34-
// Array merge strategy (array concatenation)
35-
case "class":
36-
case "style":
37-
case "directives":
38-
// Repackaging in an array allows Vue runtime
39-
// to merge class/style bindings regardless of type.
40-
mergeTarget[prop] = concat(mergeTarget[prop], arguments[i][prop])
41-
break
41+
switch (prop) {
42+
// Array merge strategy (array concatenation)
43+
case "class":
44+
case "style":
45+
case "directives":
46+
if (!Array.isArray(mergeTarget[prop])) {
47+
mergeTarget[prop] = []
48+
}
49+
// Repackaging in an array allows Vue runtime
50+
// to merge class/style bindings regardless of type.
51+
mergeTarget[prop] = concat(mergeTarget[prop], arguments[i][prop])
52+
break
4253

43-
// Space delimited string concatenation strategy
44-
case "staticClass":
45-
// If we get here,
46-
// value !== undefined,
47-
// but it could still be an empty string.
48-
if (mergeTarget[prop]) {
49-
// Not an empty string, so concatenate
50-
mergeTarget[prop] = mergeTarget[prop].trim() + " "
51-
}
52-
mergeTarget[prop] += arguments[i][prop].trim()
53-
break
54+
// Space delimited string concatenation strategy
55+
case "staticClass":
56+
// undefined values are handled above.
57+
if (mergeTarget[prop]) {
58+
// Not an empty string, so concatenate
59+
mergeTarget[prop] += " "
60+
}
61+
mergeTarget[prop] += arguments[i][prop].trim()
62+
break
5463

55-
// Object, the properties of which to merge via array merge strategy (array concatenation).
56-
// Callback merge strategy merges callbacks to the beginning of the array,
57-
// so that the last defined callback will be invoked first.
58-
// This is done since to mimic how Object.assign merging
59-
// uses the last given value to assign.
60-
case "on":
61-
case "nativeOn":
62-
// If we get here,
63-
// value must be of type Object.
64-
for (const event of keys(arguments[i][prop])) {
65-
// Concat function to array of functions if callback present.
66-
if (mergeTarget[prop][event]) {
67-
// Insert current iteration data in beginning of merged array.
68-
mergeTarget[prop][event] = concat(arguments[i][prop][event], mergeTarget[prop][event])
69-
} else {
70-
// Straight assign.
71-
mergeTarget[prop][event] = arguments[i][prop][event]
72-
}
73-
}
74-
break
64+
// Object, the properties of which to merge via array merge strategy (array concatenation).
65+
// Callback merge strategy merges callbacks to the beginning of the array,
66+
// so that the last defined callback will be invoked first.
67+
// This is done since to mimic how Object.assign merging
68+
// uses the last given value to assign.
69+
case "on":
70+
case "nativeOn":
71+
// If we get here,
72+
// value must be of type Object.
73+
for (const event of Object.keys(arguments[i][prop])) {
74+
// Concat function to array of functions if callback present.
75+
if (mergeTarget[prop][event]) {
76+
// Insert current iteration data in beginning of merged array.
77+
mergeTarget[prop][event] = concat(arguments[i][prop][event], mergeTarget[prop][event])
78+
} else {
79+
// Straight assign.
80+
mergeTarget[prop][event] = arguments[i][prop][event]
81+
}
82+
}
83+
break
7584

76-
// Object merge strategy
77-
case "attrs":
78-
case "props":
79-
case "domProps":
80-
case "scopedSlots":
81-
case "staticStyle":
82-
case "hook":
83-
case "transition":
84-
mergeTarget[prop] = { ...mergeTarget[prop], ...arguments[i][prop] }
85-
break
85+
// Object merge strategy
86+
case "attrs":
87+
case "props":
88+
case "domProps":
89+
case "scopedSlots":
90+
case "staticStyle":
91+
case "hook":
92+
case "transition":
93+
mergeTarget[prop] = { ...mergeTarget[prop], ...arguments[i][prop] }
94+
break
8695

87-
// Reassignment strategy (no merge)
88-
case "slot":
89-
case "key":
90-
case "ref":
91-
case "tag":
92-
case "show":
93-
case "keepAlive":
94-
default:
95-
mergeTarget[prop] = arguments[i][prop]
96-
}
97-
}
98-
}
96+
// Reassignment strategy (no merge)
97+
case "slot":
98+
case "key":
99+
case "ref":
100+
case "tag":
101+
case "show":
102+
case "keepAlive":
103+
default:
104+
mergeTarget[prop] = arguments[i][prop]
105+
}
106+
}
107+
}
99108

100-
return mergeTarget
109+
return mergeTarget
101110
}
102111

103112
export default mergeData
113+
export { mergeData }

0 commit comments

Comments
 (0)