-
Notifications
You must be signed in to change notification settings - Fork 10.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
chore(gatsby): convert sanitize-node to typescript #36327
Changes from all commits
a0c5640
d5082a9
09e5fa0
5c5de8a
389f59b
fd502fe
90d38b0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,12 +1,60 @@ | ||
import _ from "lodash" | ||
|
||
import type { IGatsbyNode } from "../redux/types" | ||
import type { GatsbyIterable } from "../datastore/common/iterable" | ||
|
||
type data = IGatsbyNode | GatsbyIterable<IGatsbyNode> | ||
|
||
/** | ||
* @param {Object|Array} data | ||
* @returns {Object|Array} data without undefined values | ||
*/ | ||
type omitUndefined = (data: data) => Partial<data> | ||
|
||
const omitUndefined: omitUndefined = data => { | ||
const isPlainObject = _.isPlainObject(data) | ||
if (isPlainObject) { | ||
return _.pickBy(data, p => p !== undefined) | ||
} | ||
|
||
return (data as GatsbyIterable<IGatsbyNode>).filter(p => p !== undefined) | ||
} | ||
|
||
/** | ||
* @param {*} data | ||
* @return {boolean} | ||
*/ | ||
type isTypeSupported = (data: data) => boolean | ||
|
||
const isTypeSupported: isTypeSupported = data => { | ||
if (data === null) { | ||
return true | ||
} | ||
|
||
const type = typeof data | ||
const isSupported = | ||
type === `number` || | ||
type === `string` || | ||
type === `boolean` || | ||
data instanceof Date | ||
|
||
return isSupported | ||
} | ||
|
||
/** | ||
* Make data serializable | ||
* @param {(Object|Array)} data to sanitize | ||
* @param {boolean} isNode = true | ||
* @param {Set<string>} path = new Set | ||
*/ | ||
const sanitizeNode = (data, isNode = true, path = new Set()) => { | ||
|
||
type sanitizeNode = ( | ||
data: data, | ||
isNode?: boolean, | ||
path?: Set<unknown> | ||
) => data | undefined | ||
|
||
const sanitizeNode: sanitizeNode = (data, isNode = true, path = new Set()) => { | ||
const isPlainObject = _.isPlainObject(data) | ||
|
||
if (isPlainObject || _.isArray(data)) { | ||
|
@@ -20,15 +68,15 @@ const sanitizeNode = (data, isNode = true, path = new Set()) => { | |
returnData[key] = o | ||
return | ||
} | ||
returnData[key] = sanitizeNode(o, false, path) | ||
returnData[key] = sanitizeNode(o as data, false, path) | ||
|
||
if (returnData[key] !== o) { | ||
anyFieldChanged = true | ||
} | ||
}) | ||
|
||
if (anyFieldChanged) { | ||
data = omitUndefined(returnData) | ||
data = omitUndefined(returnData as data) as data | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If we can type There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I could cast when we define I think it's down to personal preference here, I feel the double cast here is more significant than having it when we define There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sounds reasonable enough. Thank you for the detailed response. 😄 |
||
} | ||
|
||
// arrays and plain objects are supported - no need to to sanitize | ||
|
@@ -42,36 +90,4 @@ const sanitizeNode = (data, isNode = true, path = new Set()) => { | |
} | ||
} | ||
|
||
/** | ||
* @param {Object|Array} data | ||
* @returns {Object|Array} data without undefined values | ||
*/ | ||
const omitUndefined = data => { | ||
const isPlainObject = _.isPlainObject(data) | ||
if (isPlainObject) { | ||
return _.pickBy(data, p => p !== undefined) | ||
} | ||
|
||
return data.filter(p => p !== undefined) | ||
} | ||
|
||
/** | ||
* @param {*} data | ||
* @return {boolean} | ||
*/ | ||
const isTypeSupported = data => { | ||
if (data === null) { | ||
return true | ||
} | ||
|
||
const type = typeof data | ||
const isSupported = | ||
type === `number` || | ||
type === `string` || | ||
type === `boolean` || | ||
data instanceof Date | ||
|
||
return isSupported | ||
} | ||
|
||
module.exports = sanitizeNode | ||
export default sanitizeNode |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we change this loop to a
Object.entries(data).forEach
? That should allow TS to pick up the right types and we shouldn't need to cast.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Object.entries
hardcodes the first valueo
as string, making tests fail (Symbol/string issue,.each
avoids this issue).