|
1 | 1 | import { VNodeData } from "vue"
|
2 | 2 |
|
3 |
| -const keys = Object.keys |
4 |
| - |
5 | 3 | function concat(...items: any[]): any[]
|
6 | 4 | function concat(...items: any[][]): any[]
|
7 | 5 | 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) |
9 | 17 | }
|
10 | 18 |
|
11 | 19 | /**
|
12 | 20 | * Intelligently merges data for createElement.
|
13 | 21 | * Merges arguments left to right, preferring the right argument.
|
14 | 22 | * Returns new VNodeData object.
|
15 | 23 | */
|
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 |
20 | 29 |
|
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 | + } |
32 | 40 |
|
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 |
42 | 53 |
|
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 |
54 | 63 |
|
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 |
75 | 84 |
|
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 |
86 | 95 |
|
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 | + } |
99 | 108 |
|
100 |
| - return mergeTarget |
| 109 | + return mergeTarget |
101 | 110 | }
|
102 | 111 |
|
103 | 112 | export default mergeData
|
| 113 | +export { mergeData } |
0 commit comments