Source: client/parser/well-known-parsers.js

/*
 * Copyright 2023, TeamDev. All rights reserved.
 *
 * 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
 *
 * Redistribution and use in source and/or binary forms, with or without
 * modification, must retain the above copyright notice and the following
 * disclaimer.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

"use strict";

import TypeParsers from './type-parsers';
import ObjectParser from './object-parser';

import wrappers from 'google-protobuf/google/protobuf/wrappers_pb';
import struct from 'google-protobuf/google/protobuf/struct_pb';
import {Empty} from 'google-protobuf/google/protobuf/empty_pb';
import {Timestamp} from 'google-protobuf/google/protobuf/timestamp_pb';
import {Duration} from 'google-protobuf/google/protobuf/duration_pb';
import {FieldMask} from 'google-protobuf/google/protobuf/field_mask_pb';
import {Any} from 'google-protobuf/google/protobuf/any_pb';

/**
 * The parsers for standard Protobuf types.
 *
 * <p>For the details about how the parsers should work,
 * see {@link https://developers.google.com/protocol-buffers/docs/proto3#json Protobuf documentation}.
 */

class BoolValueParser extends ObjectParser {

  fromObject(object) {
    let boolValue = new wrappers.BoolValue();
    boolValue.setValue(object);
    return boolValue;
  }
}

class BytesValueParser extends ObjectParser {

  fromObject(object) {
    let bytesValue = new wrappers.BytesValue();
    bytesValue.setValue(object);
    return bytesValue;
  }
}

class DoubleValueParser extends ObjectParser {

  fromObject(object) {
    let doubleValue = new wrappers.DoubleValue();
    doubleValue.setValue(object);
    return doubleValue;
  }
}

class FloatValueParser extends ObjectParser {

  fromObject(object) {
    let floatValue = new wrappers.FloatValue();
    floatValue.setValue(object);
    return floatValue;
  }
}

class Int32ValueParser extends ObjectParser {

  fromObject(object) {
    let int32Value = new wrappers.Int32Value();
    int32Value.setValue(object);
    return int32Value;
  }
}

class Int64ValueParser extends ObjectParser {

  fromObject(object) {
    let int64Value = new wrappers.Int64Value();
    int64Value.setValue(object);
    return int64Value;
  }
}

class StringValueParser extends ObjectParser {

  fromObject(object) {
    let stringValue = new wrappers.StringValue();
    stringValue.setValue(object);
    return stringValue;
  }
}

class UInt32ValueParser extends ObjectParser {

  fromObject(object) {
    let uInt32Value = new wrappers.UInt32Value();
    uInt32Value.setValue(object);
    return uInt32Value;
  }
}

class UInt64ValueParser extends ObjectParser {

  fromObject(object) {
    let uInt64Value = new wrappers.UInt64Value();
    uInt64Value.setValue(object);
    return uInt64Value;
  }
}

class ListValueParser extends ObjectParser {

  fromObject(object) {
    let listValue = new struct.ListValue;
    object.forEach(
      function callback(currentValue, index, array) {
        let valueParser = new ValueParser();
        array[index] = valueParser.fromObject(currentValue);
      }
    );
    listValue.setValuesList(object);
    return listValue;
  }
}

class StructParser extends ObjectParser {

  fromObject(object) {
    let result = new struct.Struct();
    let values = new ValueParser();
    for (let fieldName in object) {
      result.getFieldsMap().set(fieldName, values.fromObject(object[fieldName]));
    }
    return result;
  }
}

class ValueParser extends ObjectParser {

  fromObject(object) {
    let result = new struct.Value();
    if (object === null) {
      result.setNullValue(struct.NullValue.NULL_VALUE);
    } else if (typeof object === "number") {
      result.setNumberValue(object);
    } else if (typeof object === "string") {
      result.setStringValue(object);
    } else if (typeof object === "boolean") {
      result.setBoolValue(object);
    } else if (Array.isArray(object)) {
      let parser = new ListValueParser(object);
      let listValue = parser.fromObject(object);
      result.setListValue(listValue);
    } else {
      let parser = new StructParser(object);
      let structValue = parser.fromObject(object);
      result.setStructValue(structValue);
    }
    return result;
  }
}

class EmptyParser extends ObjectParser {

  fromObject(object) {
    let emptyValue = new Empty();
    return emptyValue;
  }
}

class TimestampParser extends ObjectParser {

  fromObject(object) {
    let date = new Date(object);
    let result = new Timestamp();
    result.fromDate(date);
    return result;
  }
}

class DurationParser extends ObjectParser {

  fromObject(object) {
    object = object.substring(0, object.length - 1);
    let values = object.split(".");
    let result = new Duration();
    if (values.length === 1) {
      result.setSeconds(values[0]);
    } else if (values.length === 2) {
      result.setSeconds(values[0]);
      let nanos = values[1];
      for (let i = 0; i < 9 - nanos.length; i++) {
        nanos += "0";
      }
      let nanosNumber = parseInt(nanos, 10);
      result.setNanos(nanosNumber);
    }
    return result;
  }
}

class FieldMaskParser extends ObjectParser {

  fromObject(object) {
    let fieldMask = new FieldMask();
    fieldMask.setPathsList(object.split(","));
    return fieldMask;
  }
}

class AnyParser extends ObjectParser {

  fromObject(object) {
    const typeUrl = object["@type"];
    const isWellKnown = wellKnownParsers.has(typeUrl);
    const packedValue = isWellKnown
      ? object["value"]
      : object;
    const parser = TypeParsers.parserFor(typeUrl);
    const messageValue = parser.fromObject(packedValue);
    const bytes = messageValue.serializeBinary();
    const anyMsg = new Any();
    anyMsg.setTypeUrl(typeUrl);
    anyMsg.setValue(bytes);
    return anyMsg;
  }
}

/**
 * The map of parsers for standard Protobuf types.
 *
 * @type {Map<string, ObjectParser>}
 */
export const wellKnownParsers = new Map([
  ['type.googleapis.com/google.protobuf.BoolValue', new BoolValueParser()],
  ['type.googleapis.com/google.protobuf.BytesValue', new BytesValueParser()],
  ['type.googleapis.com/google.protobuf.DoubleValue', new DoubleValueParser()],
  ['type.googleapis.com/google.protobuf.FloatValue', new FloatValueParser()],
  ['type.googleapis.com/google.protobuf.StringValue', new StringValueParser()],
  ['type.googleapis.com/google.protobuf.Int32Value', new Int32ValueParser()],
  ['type.googleapis.com/google.protobuf.Int64Value', new Int64ValueParser()],
  ['type.googleapis.com/google.protobuf.UInt32Value', new UInt32ValueParser()],
  ['type.googleapis.com/google.protobuf.UInt64Value', new UInt64ValueParser()],
  ['type.googleapis.com/google.protobuf.Struct', new StructParser()],
  ['type.googleapis.com/google.protobuf.Value', new ValueParser()],
  ['type.googleapis.com/google.protobuf.ListValue', new ListValueParser()],
  ['type.googleapis.com/google.protobuf.Empty', new EmptyParser()],
  ['type.googleapis.com/google.protobuf.Timestamp', new TimestampParser()],
  ['type.googleapis.com/google.protobuf.Duration', new DurationParser()],
  ['type.googleapis.com/google.protobuf.FieldMask', new FieldMaskParser()],
  ['type.googleapis.com/google.protobuf.Any', new AnyParser()]
]);