Skip to content
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) Migrate db methods to Typescript #22725

Closed
wants to merge 8 commits into from
2 changes: 1 addition & 1 deletion packages/gatsby/src/db/__tests__/sanitize-node.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const sanitizeNode = require(`../sanitize-node`)
import { sanitizeNode } from "../sanitize-node"

describe(`node sanitization`, () => {
let testNode
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
const _ = require(`lodash`)
const report = require(`gatsby-cli/lib/reporter`)
const redux = require(`../redux`)
import _ from "lodash"
import reporter from "gatsby-cli/lib/reporter"
import * as redux from "../redux"
// import { backend } from "./nodes"
const { emitter } = redux

let saveInProgress = false
async function saveState() {
export async function saveState(): Promise<void> {
if (saveInProgress) return
saveInProgress = true

try {
await redux.saveState()
} catch (err) {
report.warn(`Error persisting state: ${(err && err.message) || err}`)
reporter.warn(`Error persisting state: ${(err && err.message) || err}`)
}

saveInProgress = false
Expand All @@ -22,12 +23,7 @@ const saveStateDebounced = _.debounce(saveState, 1000)
* Starts listening to redux actions and triggers a database save to
* disk upon any action (debounced to every 1 second)
*/
function startAutosave() {
export function startAutosave(): void {
saveStateDebounced()
emitter.on(`*`, () => saveStateDebounced())
}

module.exports = {
startAutosave,
saveState,
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,47 @@
const _ = require(`lodash`)
import _ from "lodash"
import { IGatsbyNode } from "gatsby/src/redux/types"

// eslint-disable-next-line @typescript-eslint/no-explicit-any
type ObjectOrArray = Record<string, any> | Array<any> | IGatsbyNode

/**
* Removes undefined keys from and Object or Array
*/
const omitUndefined = <T extends ObjectOrArray>(data: T): T => {
const isPlainObject = _.isPlainObject(data)
if (isPlainObject) {
return _.pickBy(data, p => p !== undefined) as T
}

if (Array.isArray(data)) {
return data.filter(p => p !== undefined)
}

return;
}

const isTypeSupported = (data: unknown): boolean => {
if (data === null) {
return true
}

const type = typeof data
return (
type === `number` ||
type === `string` ||
type === `boolean` ||
data instanceof Date
)
}

/**
* 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()) => {
export function sanitizeNode(
data: unknown,
isNode: boolean = true,
path: Set<T> = new Set()
): T | undefined {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe the initial call to this recursive function should be separated (fine from a perf pov) because that call must return an IGatsbyNode whereas recursive calls can, but can also return a plain object. Not sure how to go about typing those tbh since it's, from TS's pov, untyped arbitrary content.

const isPlainObject = _.isPlainObject(data)

if (isPlainObject || _.isArray(data)) {
Expand All @@ -28,7 +63,7 @@ const sanitizeNode = (data, isNode = true, path = new Set()) => {
})

if (anyFieldChanged) {
data = omitUndefined(returnData)
data = omitUndefined(returnData) as T
}

// arrays and plain objects are supported - no need to to sanitize
Expand All @@ -41,37 +76,3 @@ const sanitizeNode = (data, isNode = true, path = new Set()) => {
return data
}
}

/**
* @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