void t_js_generator::generate_js_struct_definition()

in compiler/cpp/src/thrift/generate/t_js_generator.cc [854:1054]


void t_js_generator::generate_js_struct_definition(ostream& out,
                                                   t_struct* tstruct,
                                                   bool is_exception,
                                                   bool is_exported) {
  const vector<t_field*>& members = tstruct->get_members();
  vector<t_field*>::const_iterator m_iter;

  if (gen_node_) {
    string prefix = has_js_namespace(tstruct->get_program()) ? js_namespace(tstruct->get_program()) : js_const_type_;
    out << prefix << tstruct->get_name() <<
      (is_exported ? " = module.exports." + tstruct->get_name() : "");
    if (gen_ts_) {
      f_types_ts_ << ts_print_doc(tstruct) << ts_indent() << ts_declare() << "class "
                  << tstruct->get_name() << (is_exception ? " extends Thrift.TException" : "")
                  << " {" << '\n';
    }
  } else {
    out << js_namespace(tstruct->get_program()) << tstruct->get_name();
    if (gen_ts_) {
      f_types_ts_ << ts_print_doc(tstruct) << ts_indent() << ts_declare() << "class "
                  << tstruct->get_name() << (is_exception ? " extends Thrift.TException" : "")
                  << " {" << '\n';
    }
  }

  if (gen_es6_) {
    if (gen_node_ && is_exception) {
      out << " = class extends Thrift.TException {" << '\n';
    } else {
      out << " = class {" << '\n';
    }
    indent_up();
    indent(out) << "constructor(args) {" << '\n';
  } else {
    out << " = function(args) {" << '\n';
  }

  indent_up();

  // Call super() method on inherited Error class
  if (gen_node_ && is_exception) {
    if (gen_es6_) {
      indent(out) << "super(args);" << '\n';
    } else {
      indent(out) << "Thrift.TException.call(this, \"" << js_namespace(tstruct->get_program())
        << tstruct->get_name() << "\");" << '\n';
    }
    out << indent() << "this.name = \"" << js_namespace(tstruct->get_program())
        << tstruct->get_name() << "\";" << '\n';
  }

  // members with arguments
  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
    string dval = declare_field(*m_iter, false, true);
    t_type* t = get_true_type((*m_iter)->get_type());
    if ((*m_iter)->get_value() != nullptr && !(t->is_struct() || t->is_xception())) {
      dval = render_const_value((*m_iter)->get_type(), (*m_iter)->get_value());
      out << indent() << "this." << (*m_iter)->get_name() << " = " << dval << ";" << '\n';
    } else {
      out << indent() << dval << ";" << '\n';
    }
    if (gen_ts_) {
      string ts_access = gen_node_ ? "public " : "";
      string member_name = (*m_iter)->get_name();

      // Special case. Exceptions derive from Error, and error has a non optional message field.
      // Ignore the optional flag in this case, otherwise we will generate a incompatible field
      // in the eyes of typescript.
      string optional_flag = is_exception && member_name == "message" ? "" : ts_get_req(*m_iter);

      f_types_ts_ << ts_indent() << ts_access << member_name << optional_flag << ": "
                  << ts_get_type((*m_iter)->get_type()) << ";" << '\n';
    }
  }

  // Generate constructor from array
  if (members.size() > 0) {

    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
      t_type* t = get_true_type((*m_iter)->get_type());
      if ((*m_iter)->get_value() != nullptr && (t->is_struct() || t->is_xception())) {
        indent(out) << "this." << (*m_iter)->get_name() << " = "
                    << render_const_value(t, (*m_iter)->get_value()) << ";" << '\n';
      }
    }

    // Early returns for exceptions
    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
      t_type* t = get_true_type((*m_iter)->get_type());
      if (t->is_xception()) {
        out << indent() << "if (args instanceof " << js_type_namespace(t->get_program())
            << t->get_name() << ") {" << '\n' << indent() << indent() << "this."
            << (*m_iter)->get_name() << " = args;" << '\n' << indent() << indent() << "return;"
            << '\n' << indent() << "}" << '\n';
      }
    }

    indent(out) << "if (args) {" << '\n';
    indent_up();
    if (gen_ts_) {
      f_types_ts_ << '\n' << ts_indent() << "constructor(args?: { ";
    }

    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
      t_type* t = get_true_type((*m_iter)->get_type());
      indent(out) << "if (args." << (*m_iter)->get_name() << " !== undefined && args." << (*m_iter)->get_name() << " !== null) {" << '\n';
      indent_up();
      indent(out) << "this." << (*m_iter)->get_name();

      if (t->is_struct()) {
        out << (" = new " + js_type_namespace(t->get_program()) + t->get_name() +
                "(args."+(*m_iter)->get_name() +");");
        out << '\n';
      } else if (t->is_container()) {
        t_type* etype = get_contained_type(t);
        string copyFunc = t->is_map() ? "Thrift.copyMap" : "Thrift.copyList";
        string type_list = "";

        while (etype->is_container()) {
          if (type_list.length() > 0) {
            type_list += ", ";
          }
          type_list += etype->is_map() ? "Thrift.copyMap" : "Thrift.copyList";
          etype = get_contained_type(etype);
        }

        if (etype->is_struct()) {
          if (type_list.length() > 0) {
            type_list += ", ";
          }
          type_list += js_type_namespace(etype->get_program()) + etype->get_name();
        }
        else {
          if (type_list.length() > 0) {
            type_list += ", ";
          }
          type_list += "null";
        }

        out << (" = " + copyFunc + "(args." + (*m_iter)->get_name() +
                ", [" + type_list + "]);");
        out << '\n';
      } else {
        out << " = args." << (*m_iter)->get_name() << ";" << '\n';
      }

      indent_down();
      if (!(*m_iter)->get_req()) {
        indent(out) << "} else {" << '\n';
         indent(out)
            << "  throw new Thrift.TProtocolException(Thrift.TProtocolExceptionType.UNKNOWN, "
               "'Required field " << (*m_iter)->get_name() << " is unset!');" << '\n';
      }
      indent(out) << "}" << '\n';
      if (gen_ts_) {
        f_types_ts_ << (*m_iter)->get_name() << ts_get_req(*m_iter) << ": "
                    << ts_get_type((*m_iter)->get_type()) << "; ";
      }
    }
    indent_down();
    out << indent() << "}" << '\n';
    if (gen_ts_) {
      f_types_ts_ << "});" << '\n';
    }
  }

  // Done with constructor
  indent_down();
  if (gen_es6_) {
    indent(out) << "}" << '\n' << '\n';
  } else {
    indent(out) << "};" << '\n';
  }

  if (gen_ts_) {
    f_types_ts_ << ts_indent() << "}" << '\n';
  }

  if (!gen_es6_) {
    if (is_exception) {
      out << "Thrift.inherits(" << js_namespace(tstruct->get_program()) << tstruct->get_name()
          << ", Thrift.TException);" << '\n';
      out << js_namespace(tstruct->get_program()) << tstruct->get_name() << ".prototype.name = '"
          << tstruct->get_name() << "';" << '\n';
    } else {
      // init prototype manually if we aren't using es6
      out << js_namespace(tstruct->get_program()) << tstruct->get_name() << ".prototype = {};"
          << '\n';
    }

  }

  generate_js_struct_reader(out, tstruct);
  generate_js_struct_writer(out, tstruct);

  // Close out the class definition
  if (gen_es6_) {
    indent_down();
    indent(out) << "};" << '\n';
  }
}