# All files / util misc.ts

91.89% Statements 34/37
72.22% Branches 13/18
100% Functions 7/7
91.18% Lines 31/34

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124

    2x

    2x
    2x

    670x
    670x
    670x
    13400x

    670x
    670x

    2x

    2x
    140324x
    126714x
    109885x

    2x

    248x

    248x

    2x
    248x

    248x
    256x

    248x

    2x

    20x
    20x

    1x
    19x
    3x

    16x

    2x

    95x

     /**
     * Copyright 2017 Google Inc.
     *
     * Licensed under the Apache License, Version 2.0 (the "License");
     * you may not use this file except in compliance with the License.
     * You may obtain a copy of the License at
     *
     *   http://www.apache.org/licenses/LICENSE-2.0
     *
     * Unless required by applicable law or agreed to in writing, software
     * distributed under the License is distributed on an "AS IS" BASIS,
     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     * See the License for the specific language governing permissions and
     * limitations under the License.
     */

    import { assert } from './assert';

    export type EventHandler<E> = (value: E) => void;

    /**
     * A union of all of the standard JS types, useful for cases where the type is
     * unknown. Unlike "any" this doesn't lose all type-safety, since the consuming
     * code must still cast to a particular type before using it.
     */
    export type AnyJs = null | undefined | boolean | number | string | object;

    // TODO(b/66916745): AnyDuringMigration was used to suppress type check failures
    // that were found during the upgrade to TypeScript 2.4. They need to be audited
    // and fixed.
    // tslint:disable-next-line:no-any
    export type AnyDuringMigration = any;

    // tslint:disable-next-line:class-as-namespace
    export class AutoId {
      static newId(): string {
        // Alphanumeric characters
        const chars =
          'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
        let autoId = '';
        for (let i = 0; i < 20; i++) {
          autoId += chars.charAt(Math.floor(Math.random() * chars.length));
        }
        assert(autoId.length === 20, 'Invalid auto ID: ' + autoId);
        return autoId;
      }
    }

    export function primitiveComparator<T>(left: T, right: T): number {
      if (left < right) return -1;
      if (left > right) return 1;
      return 0;
    }

    /** Duck-typed interface for objects that have an isEqual() method. */
    export interface Equatable<T> {
      isEqual(other: T): boolean;
    }

    /** Helper to compare nullable (or undefined-able) objects using isEqual(). */
    export function equals<T>(
      left: Equatable<T> | null | undefined,
      right: T | null | undefined
    ): boolean {
      Iif (left !== null && left !== undefined) {
        return !!(right && left.isEqual(right));
      } else {
        // HACK: Explicitly cast since TypeScript's type narrowing apparently isn't
        // smart enough.
        return (left as null | undefined) === right;
      }
    }

    /** Helper to compare arrays using isEqual(). */
    export function arrayEquals<T>(left: Array<Equatable<T>>, right: T[]): boolean {
      Iif (left.length !== right.length) {
        return false;
      }

      for (let i = 0; i < left.length; i++) {
        Iif (!left[i].isEqual(right[i])) {
          return false;
        }
      }

      return true;
    }

    /**
     * Returns the largest lexicographically smaller string of equal or smaller
     * length. Returns an empty string if there is no such predecessor (if the input
     * is empty).
     *
     * Strings returned from this method can be invalid UTF-16 but this is sufficent
     * in use for indexeddb because that depends on lexicographical ordering but
     * shouldn't be used elsewhere.
     */
    export function immediatePredecessor(s: string): string {
      // We can decrement the last character in the string and be done
      // unless that character is 0 (0x0000), in which case we have to erase the
      // last character.
      const lastIndex = s.length - 1;
      if (s.length === 0) {
        // Special case the empty string.
        return '';
      } else if (s.charAt(lastIndex) === '\0') {
        return s.substring(0, lastIndex);
      } else {
        return (
          s.substring(0, lastIndex) +
          String.fromCharCode(s.charCodeAt(lastIndex) - 1)
        );
      }
    }

    /**
     * Returns the immediate lexicographically-following string. This is useful to
     * construct an inclusive range for indexeddb iterators.
     */
    export function immediateSuccessor(s: string): string {
      // Return the input string, with an additional NUL byte appended.
      return s + '\0';
    }