[ci] format

This commit is contained in:
okikio 2022-04-26 21:53:43 +00:00 committed by github-actions[bot]
parent f0d22b9332
commit cbd9e6222e
2 changed files with 269 additions and 225 deletions

View file

@ -12,36 +12,40 @@ const MAX_UINT32 = 4294967295;
const GlobalCrypto = globalThis.crypto as Crypto; const GlobalCrypto = globalThis.crypto as Crypto;
export function randomBytes(size: number, cb?: (...args: any) => any) { export function randomBytes(size: number, cb?: (...args: any) => any) {
if (!(GlobalCrypto && GlobalCrypto.getRandomValues)) { if (!(GlobalCrypto && GlobalCrypto.getRandomValues)) {
throw new Error('Secure random number generation is not supported by this browser.\nUse Chrome, Firefox or Internet Explorer 11') throw new Error(
} 'Secure random number generation is not supported by this browser.\nUse Chrome, Firefox or Internet Explorer 11'
);
}
// phantomjs needs to throw // phantomjs needs to throw
if (size > MAX_UINT32) throw new RangeError('requested too many random bytes'); if (size > MAX_UINT32) throw new RangeError('requested too many random bytes');
let bytes = new Uint32Array(size) let bytes = new Uint32Array(size);
if (size > 0) { // getRandomValues fails on IE if size == 0 if (size > 0) {
if (size > MAX_BYTES) { // this is the max bytes crypto.getRandomValues // getRandomValues fails on IE if size == 0
// can do at once see https://developer.mozilla.org/en-US/docs/Web/API/window.crypto.getRandomValues if (size > MAX_BYTES) {
for (let generated = 0; generated < size; generated += MAX_BYTES) { // this is the max bytes crypto.getRandomValues
// buffer.slice automatically checks if the end is past the end of // can do at once see https://developer.mozilla.org/en-US/docs/Web/API/window.crypto.getRandomValues
// the buffer so we don't have to here for (let generated = 0; generated < size; generated += MAX_BYTES) {
GlobalCrypto.getRandomValues(bytes.slice(generated, generated + MAX_BYTES)); // buffer.slice automatically checks if the end is past the end of
} // the buffer so we don't have to here
} else { GlobalCrypto.getRandomValues(bytes.slice(generated, generated + MAX_BYTES));
GlobalCrypto.getRandomValues(bytes); }
} } else {
} GlobalCrypto.getRandomValues(bytes);
}
}
if (typeof cb === 'function') { if (typeof cb === 'function') {
Promise.resolve().then(() => { Promise.resolve().then(() => {
return cb(null, bytes); return cb(null, bytes);
}); });
return; return;
} }
return bytes; return bytes;
} }
export default randomBytes; export default randomBytes;

View file

@ -7,12 +7,15 @@ Copyrights licensed under the New BSD License.
See the accompanying LICENSE file for terms. See the accompanying LICENSE file for terms.
*/ */
import { randomBytes } from "./random-bytes"; import { randomBytes } from './random-bytes';
// Generate an internal UID to make the regexp pattern harder to guess. // Generate an internal UID to make the regexp pattern harder to guess.
const UID_LENGTH = 16; const UID_LENGTH = 16;
const UID = generateUID(); const UID = generateUID();
const PLACE_HOLDER_REGEXP = new RegExp('(\\\\)?"@__(F|R|D|M|S|A|U|I|B|L)-' + UID + '-(\\d+)__@"', 'g'); const PLACE_HOLDER_REGEXP = new RegExp(
'(\\\\)?"@__(F|R|D|M|S|A|U|I|B|L)-' + UID + '-(\\d+)__@"',
'g'
);
const IS_NATIVE_CODE_REGEXP = /\{\s*\[native code\]\s*\}/g; const IS_NATIVE_CODE_REGEXP = /\{\s*\[native code\]\s*\}/g;
const IS_PURE_FUNCTION = /function.*?\(/; const IS_PURE_FUNCTION = /function.*?\(/;
@ -24,254 +27,291 @@ const RESERVED_SYMBOLS = ['*', 'async'];
// Mapping of unsafe HTML and invalid JavaScript line terminator chars to their // Mapping of unsafe HTML and invalid JavaScript line terminator chars to their
// Unicode char counterparts which are safe to use in JavaScript strings. // Unicode char counterparts which are safe to use in JavaScript strings.
const ESCAPED_CHARS = { const ESCAPED_CHARS = {
'<': '\\u003C', '<': '\\u003C',
'>': '\\u003E', '>': '\\u003E',
'/': '\\u002F', '/': '\\u002F',
'\u2028': '\\u2028', '\u2028': '\\u2028',
'\u2029': '\\u2029' '\u2029': '\\u2029',
}; };
function escapeUnsafeChars(unsafeChar: keyof typeof ESCAPED_CHARS): typeof ESCAPED_CHARS[keyof typeof ESCAPED_CHARS] { function escapeUnsafeChars(
return ESCAPED_CHARS[unsafeChar]; unsafeChar: keyof typeof ESCAPED_CHARS
): typeof ESCAPED_CHARS[keyof typeof ESCAPED_CHARS] {
return ESCAPED_CHARS[unsafeChar];
} }
function generateUID() { function generateUID() {
let bytes = randomBytes(UID_LENGTH) as Uint32Array; let bytes = randomBytes(UID_LENGTH) as Uint32Array;
let result = ''; let result = '';
for (let i = 0; i < UID_LENGTH; ++i) { for (let i = 0; i < UID_LENGTH; ++i) {
result += bytes[i].toString(16); result += bytes[i].toString(16);
} }
return result; return result;
} }
function deleteFunctions(obj: Record<any, any>) { function deleteFunctions(obj: Record<any, any>) {
let functionKeys = []; let functionKeys = [];
for (let key in obj) { for (let key in obj) {
if (typeof obj[key] === "function") { if (typeof obj[key] === 'function') {
functionKeys.push(key); functionKeys.push(key);
} }
} }
for (let i = 0; i < functionKeys.length; i++) { for (let i = 0; i < functionKeys.length; i++) {
delete obj[functionKeys[i]]; delete obj[functionKeys[i]];
} }
} }
export type TypeGenericFunction = (...args: any[]) => any; export type TypeGenericFunction = (...args: any[]) => any;
export function serialize(obj: Record<any, any> | any, options?: number | string | Record<any, any>): string | any { export function serialize(
options || (options = {}); obj: Record<any, any> | any,
options?: number | string | Record<any, any>
): string | any {
options || (options = {});
// Backwards-compatibility for `space` as the second argument. // Backwards-compatibility for `space` as the second argument.
if (typeof options === 'number' || typeof options === 'string') { if (typeof options === 'number' || typeof options === 'string') {
options = { space: options }; options = { space: options };
} }
let functions: TypeGenericFunction[] = []; let functions: TypeGenericFunction[] = [];
let regexps: RegExp[] = []; let regexps: RegExp[] = [];
let dates: Date[] = []; let dates: Date[] = [];
let maps: Map<any, any>[] = []; let maps: Map<any, any>[] = [];
let sets: Set<any>[] = []; let sets: Set<any>[] = [];
let arrays: any[] = []; let arrays: any[] = [];
let undefs: undefined[] = []; let undefs: undefined[] = [];
let infinities: (typeof Infinity)[] = []; let infinities: typeof Infinity[] = [];
let bigInts: BigInt[] = []; let bigInts: BigInt[] = [];
let urls: URL[] = []; let urls: URL[] = [];
// Returns placeholders for functions and regexps (identified by index) // Returns placeholders for functions and regexps (identified by index)
// which are later replaced by their string representation. // which are later replaced by their string representation.
function replacer(key: any, value: any) { function replacer(key: any, value: any) {
// For nested function
// @ts-ignore
if (options.ignoreFunction) {
deleteFunctions(value);
}
// For nested function if (!value && value !== undefined) {
// @ts-ignore return value;
if (options.ignoreFunction) { }
deleteFunctions(value);
}
if (!value && value !== undefined) { // If the value is an object w/ a toJSON method, toJSON is called before
return value; // the replacer runs, so we use this[key] to get the non-toJSONed value.
} // @ts-ignore
let origValue = (this as any)[key];
let type = typeof origValue;
// If the value is an object w/ a toJSON method, toJSON is called before if (type === 'object') {
// the replacer runs, so we use this[key] to get the non-toJSONed value. if (origValue instanceof RegExp) {
// @ts-ignore return '@__R-' + UID + '-' + (regexps.push(origValue) - 1) + '__@';
let origValue = (this as any)[key]; }
let type = typeof origValue;
if (type === 'object') { if (origValue instanceof Date) {
if (origValue instanceof RegExp) { return '@__D-' + UID + '-' + (dates.push(origValue) - 1) + '__@';
return '@__R-' + UID + '-' + (regexps.push(origValue) - 1) + '__@'; }
}
if (origValue instanceof Date) { if (origValue instanceof Map) {
return '@__D-' + UID + '-' + (dates.push(origValue) - 1) + '__@'; return '@__M-' + UID + '-' + (maps.push(origValue) - 1) + '__@';
} }
if (origValue instanceof Map) { if (origValue instanceof Set) {
return '@__M-' + UID + '-' + (maps.push(origValue) - 1) + '__@'; return '@__S-' + UID + '-' + (sets.push(origValue) - 1) + '__@';
} }
if (origValue instanceof Set) { if (origValue instanceof Array) {
return '@__S-' + UID + '-' + (sets.push(origValue) - 1) + '__@'; let isSparse =
} origValue.filter(function () {
return true;
}).length !== origValue.length;
if (isSparse) {
return '@__A-' + UID + '-' + (arrays.push(origValue) - 1) + '__@';
}
}
if (origValue instanceof Array) { if (origValue instanceof URL) {
let isSparse = origValue.filter(function () { return true }).length !== origValue.length; return '@__L-' + UID + '-' + (urls.push(origValue) - 1) + '__@';
if (isSparse) { }
return '@__A-' + UID + '-' + (arrays.push(origValue) - 1) + '__@'; }
}
}
if (origValue instanceof URL) { if (type === 'function') {
return '@__L-' + UID + '-' + (urls.push(origValue) - 1) + '__@'; return '@__F-' + UID + '-' + (functions.push(origValue) - 1) + '__@';
} }
}
if (type === 'function') { if (type === 'undefined') {
return '@__F-' + UID + '-' + (functions.push(origValue) - 1) + '__@'; return '@__U-' + UID + '-' + (undefs.push(origValue) - 1) + '__@';
} }
if (type === 'undefined') { if (type === 'number' && !isNaN(origValue) && !isFinite(origValue)) {
return '@__U-' + UID + '-' + (undefs.push(origValue) - 1) + '__@'; return '@__I-' + UID + '-' + (infinities.push(origValue) - 1) + '__@';
} }
if (type === 'number' && !isNaN(origValue) && !isFinite(origValue)) { if (type === 'bigint') {
return '@__I-' + UID + '-' + (infinities.push(origValue) - 1) + '__@'; return '@__B-' + UID + '-' + (bigInts.push(origValue) - 1) + '__@';
} }
if (type === 'bigint') { return value;
return '@__B-' + UID + '-' + (bigInts.push(origValue) - 1) + '__@'; }
}
return value; function serializeFunc(fn: TypeGenericFunction) {
} let serializedFn = fn.toString();
if (IS_NATIVE_CODE_REGEXP.test(serializedFn)) {
throw new TypeError('Serializing native function: ' + fn.name);
}
function serializeFunc(fn: TypeGenericFunction) { // pure functions, example: {key: function() {}}
let serializedFn = fn.toString(); if (IS_PURE_FUNCTION.test(serializedFn)) {
if (IS_NATIVE_CODE_REGEXP.test(serializedFn)) { return serializedFn;
throw new TypeError('Serializing native function: ' + fn.name); }
}
// pure functions, example: {key: function() {}} // arrow functions, example: arg1 => arg1+5
if (IS_PURE_FUNCTION.test(serializedFn)) { if (IS_ARROW_FUNCTION.test(serializedFn)) {
return serializedFn; return serializedFn;
} }
// arrow functions, example: arg1 => arg1+5 let argsStartsAt = serializedFn.indexOf('(');
if (IS_ARROW_FUNCTION.test(serializedFn)) { let def = serializedFn
return serializedFn; .substr(0, argsStartsAt)
} .trim()
.split(' ')
.filter(function (val: string) {
return val.length > 0;
});
let argsStartsAt = serializedFn.indexOf('('); let nonReservedSymbols = def.filter(function (val: string) {
let def = serializedFn.substr(0, argsStartsAt) return RESERVED_SYMBOLS.indexOf(val) === -1;
.trim() });
.split(' ')
.filter(function (val: string) { return val.length > 0 });
let nonReservedSymbols = def.filter(function (val: string) { // enhanced literal objects, example: {key() {}}
return RESERVED_SYMBOLS.indexOf(val) === -1 if (nonReservedSymbols.length > 0) {
}); return (
(def.indexOf('async') > -1 ? 'async ' : '') +
'function' +
(def.join('').indexOf('*') > -1 ? '*' : '') +
serializedFn.substr(argsStartsAt)
);
}
// enhanced literal objects, example: {key() {}} // arrow functions
if (nonReservedSymbols.length > 0) { return serializedFn;
return (def.indexOf('async') > -1 ? 'async ' : '') + 'function' }
+ (def.join('').indexOf('*') > -1 ? '*' : '')
+ serializedFn.substr(argsStartsAt);
}
// arrow functions // Check if the parameter is function
return serializedFn; if (options.ignoreFunction && typeof obj === 'function') {
} obj = undefined;
}
// Protects against `JSON.stringify()` returning `undefined`, by serializing
// to the literal string: "undefined".
if (obj === undefined) {
return String(obj);
}
// Check if the parameter is function let str;
if (options.ignoreFunction && typeof obj === "function") {
obj = undefined;
}
// Protects against `JSON.stringify()` returning `undefined`, by serializing
// to the literal string: "undefined".
if (obj === undefined) {
return String(obj);
}
let str; // Creates a JSON string representation of the value.
// NOTE: Node 0.12 goes into slow mode with extra JSON.stringify() args.
if (options.isJSON && !options.space) {
str = JSON.stringify(obj);
} else {
// @ts-ignore
str = JSON.stringify(obj, options.isJSON ? null : replacer, options.space);
}
// Creates a JSON string representation of the value. // Protects against `JSON.stringify()` returning `undefined`, by serializing
// NOTE: Node 0.12 goes into slow mode with extra JSON.stringify() args. // to the literal string: "undefined".
if (options.isJSON && !options.space) { if (typeof str !== 'string') {
str = JSON.stringify(obj); return String(str);
} else { }
// @ts-ignore
str = JSON.stringify(obj, options.isJSON ? null : replacer, options.space);
}
// Protects against `JSON.stringify()` returning `undefined`, by serializing // Replace unsafe HTML and invalid JavaScript line terminator chars with
// to the literal string: "undefined". // their safe Unicode char counterpart. This _must_ happen before the
if (typeof str !== 'string') { // regexps and functions are serialized and added back to the string.
return String(str); if (options.unsafe !== true) {
} // @ts-ignore
str = str.replace(UNSAFE_CHARS_REGEXP, escapeUnsafeChars);
}
// Replace unsafe HTML and invalid JavaScript line terminator chars with if (
// their safe Unicode char counterpart. This _must_ happen before the functions.length === 0 &&
// regexps and functions are serialized and added back to the string. regexps.length === 0 &&
if (options.unsafe !== true) { dates.length === 0 &&
// @ts-ignore maps.length === 0 &&
str = str.replace(UNSAFE_CHARS_REGEXP, escapeUnsafeChars); sets.length === 0 &&
} arrays.length === 0 &&
undefs.length === 0 &&
infinities.length === 0 &&
bigInts.length === 0 &&
urls.length === 0
) {
return str;
}
if (functions.length === 0 && regexps.length === 0 && dates.length === 0 && maps.length === 0 && sets.length === 0 && arrays.length === 0 && undefs.length === 0 && infinities.length === 0 && bigInts.length === 0 && urls.length === 0) { // Replaces all occurrences of function, regexp, date, map and set placeholders in the
return str; // JSON string with their string representations. If the original value can
} // not be found, then `undefined` is used.
// @ts-ignore
return str.replace(PLACE_HOLDER_REGEXP, function (match, backSlash, type, valueIndex) {
// The placeholder may not be preceded by a backslash. This is to prevent
// replacing things like `"a\"@__R-<UID>-0__@"` and thus outputting
// invalid JS.
if (backSlash) {
return match;
}
// Replaces all occurrences of function, regexp, date, map and set placeholders in the if (type === 'D') {
// JSON string with their string representations. If the original value can return 'new Date("' + dates[valueIndex].toISOString() + '")';
// not be found, then `undefined` is used. }
// @ts-ignore
return str.replace(PLACE_HOLDER_REGEXP, function (match, backSlash, type, valueIndex) {
// The placeholder may not be preceded by a backslash. This is to prevent
// replacing things like `"a\"@__R-<UID>-0__@"` and thus outputting
// invalid JS.
if (backSlash) {
return match;
}
if (type === 'D') { if (type === 'R') {
return "new Date(\"" + dates[valueIndex].toISOString() + "\")"; return (
} 'new RegExp(' +
serialize(regexps[valueIndex].source) +
', "' +
regexps[valueIndex].flags +
'")'
);
}
if (type === 'R') { if (type === 'M') {
return "new RegExp(" + serialize(regexps[valueIndex].source) + ", \"" + regexps[valueIndex].flags + "\")"; return 'new Map(' + serialize(Array.from(maps[valueIndex].entries()), options) + ')';
} }
if (type === 'M') { if (type === 'S') {
return "new Map(" + serialize(Array.from(maps[valueIndex].entries()), options) + ")"; return 'new Set(' + serialize(Array.from(sets[valueIndex].values()), options) + ')';
} }
if (type === 'S') { if (type === 'A') {
return "new Set(" + serialize(Array.from(sets[valueIndex].values()), options) + ")"; return (
} 'Array.prototype.slice.call(' +
serialize(
Object.assign({ length: arrays[valueIndex].length }, arrays[valueIndex]),
options
) +
')'
);
}
if (type === 'A') { if (type === 'U') {
return "Array.prototype.slice.call(" + serialize(Object.assign({ length: arrays[valueIndex].length }, arrays[valueIndex]), options) + ")"; return 'undefined';
} }
if (type === 'U') { if (type === 'I') {
return 'undefined' return infinities[valueIndex];
} }
if (type === 'I') { if (type === 'B') {
return infinities[valueIndex]; return 'BigInt("' + bigInts[valueIndex] + '")';
} }
if (type === 'B') { if (type === 'L') {
return "BigInt(\"" + bigInts[valueIndex] + "\")"; return 'new URL("' + urls[valueIndex].toString() + '")';
} }
if (type === 'L') { let fn = functions[valueIndex];
return "new URL(\"" + urls[valueIndex].toString() + "\")";
}
let fn = functions[valueIndex]; return serializeFunc(fn);
});
return serializeFunc(fn);
});
} }
export default serialize; export default serialize;