@@ -3,15 +3,15 @@ import _ from "lodash"
3
3
import type { IGatsbyNode } from "../redux/types"
4
4
import type { GatsbyIterable } from "../datastore/common/iterable"
5
5
6
- type data = IGatsbyNode | GatsbyIterable < IGatsbyNode >
6
+ type Data = IGatsbyNode | GatsbyIterable < IGatsbyNode >
7
+
8
+ type OmitUndefined = ( data : Data ) => Partial < Data >
7
9
8
10
/**
9
11
* @param {Object|Array } data
10
12
* @returns {Object|Array } data without undefined values
11
13
*/
12
- type omitUndefined = ( data : data ) => Partial < data >
13
-
14
- const omitUndefined : omitUndefined = data => {
14
+ const omitUndefined : OmitUndefined = data => {
15
15
const isPlainObject = _ . isPlainObject ( data )
16
16
if ( isPlainObject ) {
17
17
return _ . pickBy ( data , p => p !== undefined )
@@ -20,12 +20,12 @@ const omitUndefined: omitUndefined = data => {
20
20
return ( data as GatsbyIterable < IGatsbyNode > ) . filter ( p => p !== undefined )
21
21
}
22
22
23
+ type isTypeSupported = ( data : Data ) => boolean
24
+
23
25
/**
24
26
* @param {* } data
25
- * @return {boolean }
27
+ * @return {boolean } Boolean if type is supported
26
28
*/
27
- type isTypeSupported = ( data : data ) => boolean
28
-
29
29
const isTypeSupported : isTypeSupported = data => {
30
30
if ( data === null ) {
31
31
return true
@@ -41,42 +41,67 @@ const isTypeSupported: isTypeSupported = data => {
41
41
return isSupported
42
42
}
43
43
44
+ type sanitizeNode = (
45
+ data : Data ,
46
+ isNode ?: boolean ,
47
+ path ?: Set < unknown >
48
+ ) => Data | undefined
49
+
44
50
/**
45
51
* Make data serializable
46
52
* @param {(Object|Array) } data to sanitize
47
53
* @param {boolean } isNode = true
48
54
* @param {Set<string> } path = new Set
49
55
*/
50
-
51
- type sanitizeNode = (
52
- data : data ,
53
- isNode ?: boolean ,
54
- path ?: Set < unknown >
55
- ) => data | undefined
56
-
57
- const sanitizeNode : sanitizeNode = ( data , isNode = true , path = new Set ( ) ) => {
56
+ export const sanitizeNode : sanitizeNode = (
57
+ data ,
58
+ isNode = true ,
59
+ path = new Set ( )
60
+ ) => {
58
61
const isPlainObject = _ . isPlainObject ( data )
62
+ const isArray = _ . isArray ( data )
59
63
60
- if ( isPlainObject || _ . isArray ( data ) ) {
64
+ if ( isPlainObject || isArray ) {
61
65
if ( path . has ( data ) ) return data
62
66
path . add ( data )
63
67
64
- const returnData = isPlainObject ? { } : [ ]
68
+ const returnData = isPlainObject
69
+ ? ( { } as IGatsbyNode )
70
+ : ( [ ] as Array < IGatsbyNode > )
65
71
let anyFieldChanged = false
66
- _ . each ( data , ( o , key ) => {
72
+
73
+ // _.each is a "Collection" method and thus objects with "length" property are iterated as arrays
74
+ const hasLengthProperty = isPlainObject
75
+ ? Object . prototype . hasOwnProperty . call ( data , `length` )
76
+ : false
77
+ let lengthProperty
78
+ if ( hasLengthProperty ) {
79
+ lengthProperty = ( data as IGatsbyNode ) . length
80
+ delete ( data as IGatsbyNode ) . length
81
+ }
82
+
83
+ _ . each ( data , ( value , key ) => {
67
84
if ( isNode && key === `internal` ) {
68
- returnData [ key ] = o
85
+ returnData [ key ] = value
69
86
return
70
87
}
71
- returnData [ key ] = sanitizeNode ( o as data , false , path )
88
+ returnData [ key ] = sanitizeNode ( value as Data , false , path )
72
89
73
- if ( returnData [ key ] !== o ) {
90
+ if ( returnData [ key ] !== value ) {
74
91
anyFieldChanged = true
75
92
}
76
93
} )
77
94
95
+ if ( hasLengthProperty ) {
96
+ ; ( data as IGatsbyNode ) . length = lengthProperty
97
+ returnData . length = sanitizeNode ( lengthProperty as Data , false , path )
98
+ if ( returnData . length !== lengthProperty ) {
99
+ anyFieldChanged = true
100
+ }
101
+ }
102
+
78
103
if ( anyFieldChanged ) {
79
- data = omitUndefined ( returnData as data ) as data
104
+ data = omitUndefined ( returnData as Data ) as Data
80
105
}
81
106
82
107
// arrays and plain objects are supported - no need to to sanitize
@@ -89,5 +114,3 @@ const sanitizeNode: sanitizeNode = (data, isNode = true, path = new Set()) => {
89
114
return data
90
115
}
91
116
}
92
-
93
- export default sanitizeNode
0 commit comments