tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

Serializer.ts (2908B)


      1 /**
      2 * @license
      3 * Copyright 2023 Google Inc.
      4 * SPDX-License-Identifier: Apache-2.0
      5 */
      6 
      7 import type * as Bidi from 'chromium-bidi/lib/cjs/protocol/protocol.js';
      8 
      9 import {isDate, isPlainObject, isRegExp} from '../common/util.js';
     10 
     11 /**
     12 * @internal
     13 */
     14 class UnserializableError extends Error {}
     15 
     16 /**
     17 * @internal
     18 */
     19 export class BidiSerializer {
     20  static serialize(arg: unknown): Bidi.Script.LocalValue {
     21    switch (typeof arg) {
     22      case 'symbol':
     23      case 'function':
     24        throw new UnserializableError(`Unable to serializable ${typeof arg}`);
     25      case 'object':
     26        return this.#serializeObject(arg);
     27 
     28      case 'undefined':
     29        return {
     30          type: 'undefined',
     31        };
     32      case 'number':
     33        return this.#serializeNumber(arg);
     34      case 'bigint':
     35        return {
     36          type: 'bigint',
     37          value: arg.toString(),
     38        };
     39      case 'string':
     40        return {
     41          type: 'string',
     42          value: arg,
     43        };
     44      case 'boolean':
     45        return {
     46          type: 'boolean',
     47          value: arg,
     48        };
     49    }
     50  }
     51 
     52  static #serializeNumber(arg: number): Bidi.Script.LocalValue {
     53    let value: Bidi.Script.SpecialNumber | number;
     54    if (Object.is(arg, -0)) {
     55      value = '-0';
     56    } else if (Object.is(arg, Infinity)) {
     57      value = 'Infinity';
     58    } else if (Object.is(arg, -Infinity)) {
     59      value = '-Infinity';
     60    } else if (Object.is(arg, NaN)) {
     61      value = 'NaN';
     62    } else {
     63      value = arg;
     64    }
     65    return {
     66      type: 'number',
     67      value,
     68    };
     69  }
     70 
     71  static #serializeObject(arg: object | null): Bidi.Script.LocalValue {
     72    if (arg === null) {
     73      return {
     74        type: 'null',
     75      };
     76    } else if (Array.isArray(arg)) {
     77      const parsedArray = arg.map(subArg => {
     78        return this.serialize(subArg);
     79      });
     80 
     81      return {
     82        type: 'array',
     83        value: parsedArray,
     84      };
     85    } else if (isPlainObject(arg)) {
     86      try {
     87        JSON.stringify(arg);
     88      } catch (error) {
     89        if (
     90          error instanceof TypeError &&
     91          error.message.startsWith('Converting circular structure to JSON')
     92        ) {
     93          error.message += ' Recursive objects are not allowed.';
     94        }
     95        throw error;
     96      }
     97 
     98      const parsedObject: Bidi.Script.MappingLocalValue = [];
     99      for (const key in arg) {
    100        parsedObject.push([this.serialize(key), this.serialize(arg[key])]);
    101      }
    102 
    103      return {
    104        type: 'object',
    105        value: parsedObject,
    106      };
    107    } else if (isRegExp(arg)) {
    108      return {
    109        type: 'regexp',
    110        value: {
    111          pattern: arg.source,
    112          flags: arg.flags,
    113        },
    114      };
    115    } else if (isDate(arg)) {
    116      return {
    117        type: 'date',
    118        value: arg.toISOString(),
    119      };
    120    }
    121 
    122    throw new UnserializableError(
    123      'Custom object serialization not possible. Use plain objects instead.',
    124    );
    125  }
    126 }