@v4fire/client
Version:
V4Fire client core library
114 lines (96 loc) • 2.93 kB
text/typescript
/*!
* V4Fire Client Core
* https://github.com/V4Fire/Client
*
* Released under the MIT license
* https://github.com/V4Fire/Client/blob/master/LICENSE
*/
const fnEvalSymbol = Symbol('Function for eval');
export const
fnAlias = 'FN__',
fnEvalAlias = 'FNEVAL__',
fnMockAlias = 'FNMOCK__',
regExpAlias = 'REGEX__';
export function evalFn<T extends Function>(func: T): T {
func[fnEvalSymbol] = true;
return func;
}
/**
* Overrides the `toJSON` method of the provided object to return the identifier of a mock function
* within the page context.
*
* @example
* ```
* const val1 = JSON.stringify({val: 1}); // '{"val": 1}';
* const val2 = JSON.stringify(setSerializerAsMockFn({val: 1}, 'id')); // '"id"'
* ```
*
* This function is needed in order to extract a previously inserted mock function
* into the context of a browser page by its ID.
*
* @param obj - the object to override the `toJSON` method for.
* @param id - the identifier of the mock function.
* @returns The modified object with the overridden `toJSON` method.
*/
export function setSerializerAsMockFn<T extends object>(obj: T, id: string): T {
Object.assign(obj, {
toJSON: () => `${fnMockAlias}${id}`
});
return obj;
}
export function stringifyFunction(val: Function): string {
if (val[fnEvalSymbol] != null) {
return `${fnEvalAlias}${val.toString()}`;
}
return `${fnAlias}${val.toString()}`;
}
export function stringifyRegExp(regExp: RegExp): string {
return `${regExpAlias}${JSON.stringify({source: regExp.source, flags: regExp.flags})}`;
}
/**
* Stringifies the passed object to a JSON string and returns it.
* The function also supports serialization of functions and regular expressions.
*
* @param obj
*/
export function expandedStringify(obj: object): string {
return JSON.stringify(obj, (_, val) => {
if (Object.isFunction(val)) {
return stringifyFunction(val);
}
if (Object.isRegExp(val)) {
return stringifyRegExp(val);
}
return val;
});
}
/**
* Parses the specified JSON string into a JS value and returns it.
* The function also supports parsing of functions and regular expressions.
*
* @param str
*/
export function expandedParse<T = JSONLikeValue>(str: string): T {
return JSON.parse(str, (_, val) => {
if (Object.isString(val)) {
if (val.startsWith(fnAlias)) {
// eslint-disable-next-line no-new-func
return Function(`return ${val.replace(fnAlias, '')}`)();
}
if (val.startsWith(fnEvalAlias)) {
// eslint-disable-next-line no-new-func
return Function(`return ${val.replace(fnEvalAlias, '')}`)()();
}
if (val.startsWith(fnMockAlias)) {
const mockId = val.replace(fnMockAlias, '');
return globalThis[mockId];
}
if (val.startsWith(regExpAlias)) {
const obj = JSON.parse(val.replace(regExpAlias, ''));
return new RegExp(obj.source, obj.flags);
}
}
return val;
});
}
globalThis.expandedParse = expandedParse;