generated from polymech/site-template
latest
This commit is contained in:
@@ -1,119 +0,0 @@
|
||||
import { JSONPath } from 'jsonpath-plus'
|
||||
import pThrottle from 'p-throttle'
|
||||
import pMap from 'p-map'
|
||||
|
||||
export type AsyncTransformer = (input: string, path: string) => Promise<string>
|
||||
export type ErrorCallback = (path: string, value: string, error: any) => void
|
||||
export type FilterCallback = (input: string, path: string) => Promise<boolean>
|
||||
export type Filter = (input: string) => Promise<boolean>
|
||||
|
||||
export interface TransformOptions {
|
||||
transform: AsyncTransformer
|
||||
path: string
|
||||
throttleDelay: number
|
||||
concurrentTasks: number
|
||||
errorCallback: ErrorCallback
|
||||
filterCallback: FilterCallback
|
||||
}
|
||||
|
||||
export const isNumber: Filter = async (input: string) => (/^-?\d+(\.\d+)?$/.test(input))
|
||||
export const isBoolean: Filter = async (input: string) => /^(true|false)$/i.test(input)
|
||||
export const isValidString: Filter = async (input: string) => !(input.trim() !== '')
|
||||
|
||||
export const testFilters = (filters: Filter[]): FilterCallback => {
|
||||
return async (input: string) => {
|
||||
for (const filter of filters) {
|
||||
if (await filter(input)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
};
|
||||
|
||||
export const defaultFilters = (filters: Filter[] = []) =>
|
||||
[
|
||||
isNumber, isBoolean, isValidString, ...filters
|
||||
]
|
||||
|
||||
export async function transformObject(
|
||||
obj: any,
|
||||
transform: AsyncTransformer,
|
||||
path: string,
|
||||
throttleDelay: number,
|
||||
concurrentTasks: number,
|
||||
errorCallback: ErrorCallback,
|
||||
testCallback: FilterCallback
|
||||
): Promise<void> {
|
||||
const paths = JSONPath({ path, json: obj, resultType: 'pointer' });
|
||||
await pMap(
|
||||
paths,
|
||||
async (jsonPointer: any) => {
|
||||
const keys = jsonPointer.slice(1).split('/')
|
||||
await transformPath(obj, keys, transform, throttleDelay, concurrentTasks, jsonPointer, errorCallback, testCallback)
|
||||
},
|
||||
{ concurrency: concurrentTasks }
|
||||
)
|
||||
}
|
||||
export async function transformPath(
|
||||
obj: any,
|
||||
keys: string[],
|
||||
transform: AsyncTransformer,
|
||||
throttleDelay: number,
|
||||
concurrentTasks: number,
|
||||
currentPath: string,
|
||||
errorCallback: ErrorCallback,
|
||||
testCallback: FilterCallback
|
||||
): Promise<void> {
|
||||
|
||||
let current = obj
|
||||
|
||||
for (let i = 0; i < keys.length - 1; i++) {
|
||||
current = current[keys[i]]
|
||||
}
|
||||
const lastKey = keys[keys.length - 1]
|
||||
const throttle = pThrottle({
|
||||
limit: 1,
|
||||
interval: throttleDelay,
|
||||
})
|
||||
|
||||
if (typeof lastKey === 'string' && lastKey !== '') {
|
||||
try {
|
||||
const newKey = isValidString(lastKey) && !isNumber(lastKey) ? await throttle(transform)(lastKey, currentPath) : lastKey
|
||||
if (newKey !== lastKey) {
|
||||
current[newKey] = current[lastKey]
|
||||
delete current[lastKey]
|
||||
}
|
||||
if (typeof current[newKey] === 'string' && current[newKey] !== '') {
|
||||
if (await testCallback(current[newKey], `${currentPath}/${lastKey}`)) {
|
||||
current[newKey] = await throttle(transform)(current[newKey], `${currentPath}/${lastKey}`)
|
||||
}
|
||||
} else if (typeof current[newKey] === 'object' && current[newKey] !== null) {
|
||||
await transformObject(current[newKey], transform, '$.*', throttleDelay, concurrentTasks, errorCallback, testCallback)
|
||||
}
|
||||
} catch (error) {
|
||||
errorCallback(currentPath, lastKey, error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const exampleTransformFunction: AsyncTransformer = async (input: string, path: string): Promise<string> => {
|
||||
if (input === 'random') throw new Error('API error')
|
||||
return input.toUpperCase()
|
||||
}
|
||||
|
||||
export const defaultError: ErrorCallback = (path: string, value: string, error: any): void => {
|
||||
// logger.error(`Error at path: ${path}, value: ${value}, error: ${error}`)
|
||||
}
|
||||
|
||||
export const defaultOptions = (options: TransformOptions = {} as TransformOptions): TransformOptions => {
|
||||
return {
|
||||
transform: exampleTransformFunction,
|
||||
path: options.path || '$[*][0,1,2]',
|
||||
throttleDelay: 10,
|
||||
concurrentTasks: 1,
|
||||
errorCallback: defaultError,
|
||||
filterCallback: testFilters(defaultFilters()),
|
||||
...options
|
||||
}
|
||||
}
|
||||
@@ -184,7 +184,7 @@ async function example() {
|
||||
alt: "IMG_20200605_142311.jpg"
|
||||
},
|
||||
files: [],
|
||||
category: {\n label: "uncategorized"\n }
|
||||
category: { label: "uncategorized" }
|
||||
//...truncated for brevity
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user