<commit_before>module.exports = function (fork) {
  // Since TypeScript is parsed by Babylon, include the core Babylon types
  // but omit the Flow-related types.
  fork.use(require("./babel-core"));

  var types = fork.use(require("../lib/types"));
  var n = types.namedTypes;
  var def = types.Type.def;
  var or = types.Type.or;
  var defaults = fork.use(require("../lib/shared")).defaults;
  var StringLiteral = new types.Type(function (value, deep) {
    if (n.StringLiteral &&
        n.StringLiteral.check(value, deep)) {
      return true
    }
    if (n.Literal &&
        n.Literal.check(value, deep) &&
        typeof value.value === "string") {
      return true;
    }
    return false;
  }, "StringLiteral");

  def("TSType")
    .bases("Node");

  var IdOrQualifiedName = or(
    def("Identifier"),
    def("TSQualifiedName")
  );

  def("TSTypeReference")
    .bases("TSType")
    .field("typeName", IdOrQualifiedName)
    .field("typeParameters",
           or(def("TSTypeParameterInstantiation"), null),
           defaults["null"]);

  // An abstract (non-buildable) base type that provide a commonly-needed
  // optional .typeParameters field.
  def("TSHasOptionalTypeParameters")
    .field("typeParameters",
           or(def("TSTypeParameterDeclaration"), null),
           defaults["null"]);

  // An abstract (non-buildable) base type that provide a commonly-needed
  // optional .typeAnnotation field.
  def("TSHasOptionalTypeAnnotation")
    .field("typeAnnotation",
           or(def("TSTypeAnnotation"), null),
           defaults["null"]);

  def("TSQualifiedName")
    .bases("Node")
    .build("left", "right")
    .field("left", IdOrQualifiedName)
    .field("right", IdOrQualifiedName);

  def("TSAsExpression")
    .bases("Expression")
    .build("expression")
    .field("expression", def("Expression"))
    .field("typeAnnotation", def("TSType"))
    .field("extra",
           or({ parenthesized: Boolean }, null),
           defaults["null"]);

  def("TSNonNullExpression")
    .bases("Expression")
    .build("expression")
    .field("expression", def("Expression"));

  [ // Define all the simple keyword types.
    "TSAnyKeyword",
    "TSBooleanKeyword",
    "TSNeverKeyword",
    "TSNullKeyword",
    "TSNumberKeyword",
    "TSObjectKeyword",
    "TSStringKeyword",
    "TSSymbolKeyword",
    "TSUndefinedKeyword",
    "TSVoidKeyword",
    "TSThisType",
  ].forEach(keywordType => {
    def(keywordType)
      .bases("TSType")
      .build();
  });

  def("TSArrayType")
    .bases("TSType")
    .build("elementType")
    .field("elementType", def("TSType"))

  def("TSLiteralType")
    .bases("TSType")
    .build("literal")
    .field("literal",
           or(def("NumericLiteral"),
              def("StringLiteral"),
              def("BooleanLiteral")));

  ["TSUnionType",
   "TSIntersectionType",
  ].forEach(typeName => {
    def(typeName)
      .bases("TSType")
      .build("types")
      .field("types", [def("TSType")]);
  });

  def("TSParenthesizedType")
    .bases("TSType")
    .build("typeAnnotation")
    .field("typeAnnotation", def("TSType"));

  var ParametersType = [or(
    def("Identifier"),
    def("RestElement")
  )];

  ["TSFunctionType",
   "TSConstructorType",
  ].forEach(typeName => {
    def(typeName)
      .bases("TSType",
             "TSHasOptionalTypeParameters",
             "TSHasOptionalTypeAnnotation")
      .build("parameters")
      .field("parameters", ParametersType);
  });

  def("TSDeclareFunction")
    .bases("Declaration", "TSHasOptionalTypeParameters")
    .build("id", "params", "returnType")
    .field("declare", Boolean, defaults["false"])
    .field("async", Boolean, defaults["false"])
    .field("generator", Boolean, defaults["false"])
    .field("id", or(def("Identifier"), null), defaults["null"])
    .field("params", [def("Pattern")])
    // tSFunctionTypeAnnotationCommon
    .field("returnType",
           or(def("TSTypeAnnotation"),
              def("Noop"), // Still used?
              null),
           defaults["null"]);

  def("TSDeclareMethod")
    .bases("Declaration", "TSHasOptionalTypeParameters")
    .build("key", "params", "returnType")
    .field("async", Boolean, defaults["false"])
    .field("generator", Boolean, defaults["false"])
    .field("params", [def("Pattern")])
    // classMethodOrPropertyCommon
    .field("abstract", Boolean, defaults["false"])
    .field("accessibility",
           or("public", "private", "protected", void 0),
           defaults["undefined"])
    .field("static", Boolean, defaults["false"])
    .field("computed", Boolean, defaults["false"])
    .field("optional", Boolean, defaults["false"])
    .field("key", or(
      def("Identifier"),
      def("StringLiteral"),
      def("NumericLiteral"),
      // Only allowed if .computed is true.
      def("Expression")
    ))
    // classMethodOrDeclareMethodCommon
    .field("kind",
           or("get", "set", "method", "constructor"),
           function getDefault() { return "method"; })
    .field("access", // Not "accessibility"?
           or("public", "private", "protected", void 0),
           defaults["undefined"])
    .field("decorators",
           or([def("Decorator")], null),
           defaults["null"])
    // tSFunctionTypeAnnotationCommon
    .field("returnType",
           or(def("TSTypeAnnotation"),
              def("Noop"), // Still used?
              null),
           defaults["null"]);

  def("TSMappedType")
    .bases("TSType")
    .build("typeParameter", "typeAnnotation")
    .field("readonly", Boolean, defaults["false"])
    .field("typeParameter", def("TSTypeParameter"))
    .field("optional", Boolean, defaults["false"])
    .field("typeAnnotation",
           or(def("TSType"), null),
           defaults["null"]);

  def("TSTupleType")
    .bases("TSType")
    .build("elementTypes")
    .field("elementTypes", [def("TSType")]);

  def("TSIndexedAccessType")
    .bases("TSType")
    .build("objectType", "indexType")
    .field("objectType", def("TSType"))
    .field("indexType", def("TSType"))

  def("TSTypeOperator")
    .bases("TSType")
    .build("operator")
    .field("operator", String)
    .field("typeAnnotation", def("TSType"));

  def("TSTypeAnnotation")
    .bases("Node")
    .build("typeAnnotation")
    .field("typeAnnotation",
           or(def("TSType"),
              def("TSTypeAnnotation")));

  def("TSIndexSignature")
    .bases("Node", "TSHasOptionalTypeAnnotation")
    .build("parameters")
    .field("parameters", [def("Identifier")]) // Length === 1
    .field("readonly", Boolean, defaults["false"]);

  def("TSPropertySignature")
    .bases("Node", "TSHasOptionalTypeAnnotation")
    .build("key")
    .field("key", def("Expression"))
    .field("computed", Boolean, defaults["false"])
    .field("readonly", Boolean, defaults["false"])
    .field("optional", Boolean, defaults["false"])
    .field("initializer",
           or(def("Expression"), null),
           defaults["null"]);

  def("TSMethodSignature")
    .bases("Node",
           "TSHasOptionalTypeParameters",
           "TSHasOptionalTypeAnnotation")
    .build("key")
    .field("key", def("Expression"))
    .field("computed", Boolean, defaults["false"])
    .field("optional", Boolean, defaults["false"])
    .field("parameters", ParametersType);

  def("TSTypePredicate")
    .bases("TSTypeAnnotation")
    .build("parameterName", "typeAnnotation")
    .field("parameterName",
           or(def("Identifier"),
              def("TSThisType")))
    .field("typeAnnotation", def("TSTypeAnnotation"));

  ["TSCallSignatureDeclaration",
   "TSConstructSignatureDeclaration",
  ].forEach(typeName => {
    def(typeName)
      .bases("Declaration",
             "TSHasOptionalTypeParameters",
             "TSHasOptionalTypeAnnotation")
      .build("parameters")
      .field("parameters", ParametersType);
  });

  def("TSEnumMember")
    .bases("Node")
    .build("id", "initializer")
    .field("id", or(def("Identifier"), StringLiteral))
    .field("initializer",
           or(def("Expression"), null),
           defaults["null"]);

  def("TSTypeQuery")
    .bases("TSType")
    .build("exprName")
    .field("exprName", def("Identifier"));

  // Inferred from Babylon's tsParseTypeMember method.
  var TSTypeMember = or(
    def("TSCallSignatureDeclaration"),
    def("TSConstructSignatureDeclaration"),
    def("TSIndexSignature"),
    def("TSMethodSignature"),
    def("TSPropertySignature")
  );

  def("TSTypeLiteral")
    .bases("TSType")
    .build("members")
    .field("members", [TSTypeMember]);

  def("TSTypeParameter")
    .bases("Identifier")
    .field("name", String)
    .field("constraint", or(def("TSType"), null), defaults["null"])
    .field("default", or(def("TSType"), null), defaults["null"]);

  def("TSTypeAssertion")
    .bases("Expression")
    .build("typeAnnotation", "expression")
    .field("typeAnnotation", def("TSType"))
    .field("expression", def("Expression"))
    .field("extra",
           or({ parenthesized: Boolean }, null),
           defaults["null"]);

  def("TSTypeParameterDeclaration")
    .bases("Declaration")
    .build("params")
    .field("params", [def("TSTypeParameter")]);

  def("TSTypeParameterInstantiation")
    .bases("Node")
    .build("params")
    .field("params", [def("TSType")]);

  def("TSEnumDeclaration")
    .bases("Declaration")
    .build("id", "members")
    .field("id", def("Identifier"))
    .field("const", Boolean, defaults["false"])
    .field("declare", Boolean, defaults["false"])
    .field("members", [def("TSEnumMember")])
    .field("initializer",
           or(def("Expression"), null),
           defaults["null"]);

  def("TSTypeAliasDeclaration")
    .bases("Declaration", "TSHasOptionalTypeParameters")
    .build("id")
    .field("id", def("Identifier"))
    .field("declare", Boolean, defaults["false"])
    .field("typeAnnotation", def("TSType"));

  def("TSModuleBlock")
    .bases("Node")
    .build("body")
    .field("body", [def("Statement")]);

  def("TSModuleDeclaration")
    .bases("Declaration")
    .build("id", "body")
    .field("id", or(StringLiteral, IdOrQualifiedName))
    .field("declare", Boolean, defaults["false"])
    .field("global", Boolean, defaults["false"])
    .field("body",
           or(def("TSModuleBlock"),
              def("TSModuleDeclaration"),
              null),
           defaults["null"]);

  def("TSImportEqualsDeclaration")
    .bases("Statement")
    .build("id", "moduleReference")
    .field("id", def("Identifier"))
    .field("isExport", Boolean, defaults["false"])
    .field("moduleReference",
           or(IdOrQualifiedName,
              def("TSExternalModuleReference")));

  def("TSExternalModuleReference")
    .bases("Node")
    .build("expression")
    .field("expression", StringLiteral);

  def("TSExportAssignment")
    .bases("Statement")
    .build("expression")
    .field("expression", def("Expression"));

  def("TSNamespaceExportDeclaration")
    .bases("Statement")
    .build("id")
    .field("id", def("Identifier"));

  def("TSInterfaceBody")
    .bases("Node")
    .build("body")
    .field("body", [TSTypeMember]);

  def("TSExpressionWithTypeArguments")
    .bases("TSType")
    .build("expression", "typeParameters")
    .field("expression", IdOrQualifiedName)
    .field("typeParameters",
           or(def("TSTypeParameterInstantiation"), null),
           defaults["null"]);

  def("TSInterfaceDeclaration")
    .bases("Declaration", "TSHasOptionalTypeParameters")
    .build("id", "body")
    .field("id", IdOrQualifiedName)
    .field("declare", Boolean, defaults["false"])
    .field("extends",
           or([def("TSExpressionWithTypeArguments")], null),
           defaults["null"])
    .field("body", def("TSInterfaceBody"));

  ["ClassDeclaration",
   "ClassExpression",
  ].forEach(typeName => {
    def(typeName)
      .field("implements",
             [def("TSExpressionWithTypeArguments")],
             defaults.emptyArray);
  });

  def("TSParameterProperty")
    .bases("Pattern")
    .build("parameter")
    .field("accessibility",
           or("public", "private", "protected", void 0),
           defaults["undefined"])
    .field("readonly", Boolean, defaults["false"])
    .field("parameter", or(def("Identifier"),
                           def("AssignmentPattern")));

  // Defined already in es6 and babel-core.
  def("ClassBody")
    .field("body", [or(
      def("MethodDefinition"),
      def("VariableDeclarator"),
      def("ClassPropertyDefinition"),
      def("ClassProperty"),
      def("ClassMethod"),
      // Just need to add these types:
      def("TSDeclareMethod"),
      TSTypeMember
    )]);
};
<commit_msg>Make more TypeScript Node and Statement subtypes Declarations instead.<commit_after>module.exports = function (fork) {
  // Since TypeScript is parsed by Babylon, include the core Babylon types
  // but omit the Flow-related types.
  fork.use(require("./babel-core"));

  var types = fork.use(require("../lib/types"));
  var n = types.namedTypes;
  var def = types.Type.def;
  var or = types.Type.or;
  var defaults = fork.use(require("../lib/shared")).defaults;
  var StringLiteral = new types.Type(function (value, deep) {
    if (n.StringLiteral &&
        n.StringLiteral.check(value, deep)) {
      return true
    }
    if (n.Literal &&
        n.Literal.check(value, deep) &&
        typeof value.value === "string") {
      return true;
    }
    return false;
  }, "StringLiteral");

  def("TSType")
    .bases("Node");

  var IdOrQualifiedName = or(
    def("Identifier"),
    def("TSQualifiedName")
  );

  def("TSTypeReference")
    .bases("TSType")
    .field("typeName", IdOrQualifiedName)
    .field("typeParameters",
           or(def("TSTypeParameterInstantiation"), null),
           defaults["null"]);

  // An abstract (non-buildable) base type that provide a commonly-needed
  // optional .typeParameters field.
  def("TSHasOptionalTypeParameters")
    .field("typeParameters",
           or(def("TSTypeParameterDeclaration"), null),
           defaults["null"]);

  // An abstract (non-buildable) base type that provide a commonly-needed
  // optional .typeAnnotation field.
  def("TSHasOptionalTypeAnnotation")
    .field("typeAnnotation",
           or(def("TSTypeAnnotation"), null),
           defaults["null"]);

  def("TSQualifiedName")
    .bases("Node")
    .build("left", "right")
    .field("left", IdOrQualifiedName)
    .field("right", IdOrQualifiedName);

  def("TSAsExpression")
    .bases("Expression")
    .build("expression")
    .field("expression", def("Expression"))
    .field("typeAnnotation", def("TSType"))
    .field("extra",
           or({ parenthesized: Boolean }, null),
           defaults["null"]);

  def("TSNonNullExpression")
    .bases("Expression")
    .build("expression")
    .field("expression", def("Expression"));

  [ // Define all the simple keyword types.
    "TSAnyKeyword",
    "TSBooleanKeyword",
    "TSNeverKeyword",
    "TSNullKeyword",
    "TSNumberKeyword",
    "TSObjectKeyword",
    "TSStringKeyword",
    "TSSymbolKeyword",
    "TSUndefinedKeyword",
    "TSVoidKeyword",
    "TSThisType",
  ].forEach(keywordType => {
    def(keywordType)
      .bases("TSType")
      .build();
  });

  def("TSArrayType")
    .bases("TSType")
    .build("elementType")
    .field("elementType", def("TSType"))

  def("TSLiteralType")
    .bases("TSType")
    .build("literal")
    .field("literal",
           or(def("NumericLiteral"),
              def("StringLiteral"),
              def("BooleanLiteral")));

  ["TSUnionType",
   "TSIntersectionType",
  ].forEach(typeName => {
    def(typeName)
      .bases("TSType")
      .build("types")
      .field("types", [def("TSType")]);
  });

  def("TSParenthesizedType")
    .bases("TSType")
    .build("typeAnnotation")
    .field("typeAnnotation", def("TSType"));

  var ParametersType = [or(
    def("Identifier"),
    def("RestElement")
  )];

  ["TSFunctionType",
   "TSConstructorType",
  ].forEach(typeName => {
    def(typeName)
      .bases("TSType",
             "TSHasOptionalTypeParameters",
             "TSHasOptionalTypeAnnotation")
      .build("parameters")
      .field("parameters", ParametersType);
  });

  def("TSDeclareFunction")
    .bases("Declaration", "TSHasOptionalTypeParameters")
    .build("id", "params", "returnType")
    .field("declare", Boolean, defaults["false"])
    .field("async", Boolean, defaults["false"])
    .field("generator", Boolean, defaults["false"])
    .field("id", or(def("Identifier"), null), defaults["null"])
    .field("params", [def("Pattern")])
    // tSFunctionTypeAnnotationCommon
    .field("returnType",
           or(def("TSTypeAnnotation"),
              def("Noop"), // Still used?
              null),
           defaults["null"]);

  def("TSDeclareMethod")
    .bases("Declaration", "TSHasOptionalTypeParameters")
    .build("key", "params", "returnType")
    .field("async", Boolean, defaults["false"])
    .field("generator", Boolean, defaults["false"])
    .field("params", [def("Pattern")])
    // classMethodOrPropertyCommon
    .field("abstract", Boolean, defaults["false"])
    .field("accessibility",
           or("public", "private", "protected", void 0),
           defaults["undefined"])
    .field("static", Boolean, defaults["false"])
    .field("computed", Boolean, defaults["false"])
    .field("optional", Boolean, defaults["false"])
    .field("key", or(
      def("Identifier"),
      def("StringLiteral"),
      def("NumericLiteral"),
      // Only allowed if .computed is true.
      def("Expression")
    ))
    // classMethodOrDeclareMethodCommon
    .field("kind",
           or("get", "set", "method", "constructor"),
           function getDefault() { return "method"; })
    .field("access", // Not "accessibility"?
           or("public", "private", "protected", void 0),
           defaults["undefined"])
    .field("decorators",
           or([def("Decorator")], null),
           defaults["null"])
    // tSFunctionTypeAnnotationCommon
    .field("returnType",
           or(def("TSTypeAnnotation"),
              def("Noop"), // Still used?
              null),
           defaults["null"]);

  def("TSMappedType")
    .bases("TSType")
    .build("typeParameter", "typeAnnotation")
    .field("readonly", Boolean, defaults["false"])
    .field("typeParameter", def("TSTypeParameter"))
    .field("optional", Boolean, defaults["false"])
    .field("typeAnnotation",
           or(def("TSType"), null),
           defaults["null"]);

  def("TSTupleType")
    .bases("TSType")
    .build("elementTypes")
    .field("elementTypes", [def("TSType")]);

  def("TSIndexedAccessType")
    .bases("TSType")
    .build("objectType", "indexType")
    .field("objectType", def("TSType"))
    .field("indexType", def("TSType"))

  def("TSTypeOperator")
    .bases("TSType")
    .build("operator")
    .field("operator", String)
    .field("typeAnnotation", def("TSType"));

  def("TSTypeAnnotation")
    .bases("Node")
    .build("typeAnnotation")
    .field("typeAnnotation",
           or(def("TSType"),
              def("TSTypeAnnotation")));

  def("TSIndexSignature")
    .bases("Declaration", "TSHasOptionalTypeAnnotation")
    .build("parameters")
    .field("parameters", [def("Identifier")]) // Length === 1
    .field("readonly", Boolean, defaults["false"]);

  def("TSPropertySignature")
    .bases("Declaration", "TSHasOptionalTypeAnnotation")
    .build("key")
    .field("key", def("Expression"))
    .field("computed", Boolean, defaults["false"])
    .field("readonly", Boolean, defaults["false"])
    .field("optional", Boolean, defaults["false"])
    .field("initializer",
           or(def("Expression"), null),
           defaults["null"]);

  def("TSMethodSignature")
    .bases("Declaration",
           "TSHasOptionalTypeParameters",
           "TSHasOptionalTypeAnnotation")
    .build("key")
    .field("key", def("Expression"))
    .field("computed", Boolean, defaults["false"])
    .field("optional", Boolean, defaults["false"])
    .field("parameters", ParametersType);

  def("TSTypePredicate")
    .bases("TSTypeAnnotation")
    .build("parameterName", "typeAnnotation")
    .field("parameterName",
           or(def("Identifier"),
              def("TSThisType")))
    .field("typeAnnotation", def("TSTypeAnnotation"));

  ["TSCallSignatureDeclaration",
   "TSConstructSignatureDeclaration",
  ].forEach(typeName => {
    def(typeName)
      .bases("Declaration",
             "TSHasOptionalTypeParameters",
             "TSHasOptionalTypeAnnotation")
      .build("parameters")
      .field("parameters", ParametersType);
  });

  def("TSEnumMember")
    .bases("Node")
    .build("id", "initializer")
    .field("id", or(def("Identifier"), StringLiteral))
    .field("initializer",
           or(def("Expression"), null),
           defaults["null"]);

  def("TSTypeQuery")
    .bases("TSType")
    .build("exprName")
    .field("exprName", def("Identifier"));

  // Inferred from Babylon's tsParseTypeMember method.
  var TSTypeMember = or(
    def("TSCallSignatureDeclaration"),
    def("TSConstructSignatureDeclaration"),
    def("TSIndexSignature"),
    def("TSMethodSignature"),
    def("TSPropertySignature")
  );

  def("TSTypeLiteral")
    .bases("TSType")
    .build("members")
    .field("members", [TSTypeMember]);

  def("TSTypeParameter")
    .bases("Identifier")
    .field("name", String)
    .field("constraint", or(def("TSType"), null), defaults["null"])
    .field("default", or(def("TSType"), null), defaults["null"]);

  def("TSTypeAssertion")
    .bases("Expression")
    .build("typeAnnotation", "expression")
    .field("typeAnnotation", def("TSType"))
    .field("expression", def("Expression"))
    .field("extra",
           or({ parenthesized: Boolean }, null),
           defaults["null"]);

  def("TSTypeParameterDeclaration")
    .bases("Declaration")
    .build("params")
    .field("params", [def("TSTypeParameter")]);

  def("TSTypeParameterInstantiation")
    .bases("Node")
    .build("params")
    .field("params", [def("TSType")]);

  def("TSEnumDeclaration")
    .bases("Declaration")
    .build("id", "members")
    .field("id", def("Identifier"))
    .field("const", Boolean, defaults["false"])
    .field("declare", Boolean, defaults["false"])
    .field("members", [def("TSEnumMember")])
    .field("initializer",
           or(def("Expression"), null),
           defaults["null"]);

  def("TSTypeAliasDeclaration")
    .bases("Declaration", "TSHasOptionalTypeParameters")
    .build("id")
    .field("id", def("Identifier"))
    .field("declare", Boolean, defaults["false"])
    .field("typeAnnotation", def("TSType"));

  def("TSModuleBlock")
    .bases("Node")
    .build("body")
    .field("body", [def("Statement")]);

  def("TSModuleDeclaration")
    .bases("Declaration")
    .build("id", "body")
    .field("id", or(StringLiteral, IdOrQualifiedName))
    .field("declare", Boolean, defaults["false"])
    .field("global", Boolean, defaults["false"])
    .field("body",
           or(def("TSModuleBlock"),
              def("TSModuleDeclaration"),
              null),
           defaults["null"]);

  def("TSImportEqualsDeclaration")
    .bases("Declaration")
    .build("id", "moduleReference")
    .field("id", def("Identifier"))
    .field("isExport", Boolean, defaults["false"])
    .field("moduleReference",
           or(IdOrQualifiedName,
              def("TSExternalModuleReference")));

  def("TSExternalModuleReference")
    .bases("Declaration")
    .build("expression")
    .field("expression", StringLiteral);

  def("TSExportAssignment")
    .bases("Statement")
    .build("expression")
    .field("expression", def("Expression"));

  def("TSNamespaceExportDeclaration")
    .bases("Declaration")
    .build("id")
    .field("id", def("Identifier"));

  def("TSInterfaceBody")
    .bases("Node")
    .build("body")
    .field("body", [TSTypeMember]);

  def("TSExpressionWithTypeArguments")
    .bases("TSType")
    .build("expression", "typeParameters")
    .field("expression", IdOrQualifiedName)
    .field("typeParameters",
           or(def("TSTypeParameterInstantiation"), null),
           defaults["null"]);

  def("TSInterfaceDeclaration")
    .bases("Declaration", "TSHasOptionalTypeParameters")
    .build("id", "body")
    .field("id", IdOrQualifiedName)
    .field("declare", Boolean, defaults["false"])
    .field("extends",
           or([def("TSExpressionWithTypeArguments")], null),
           defaults["null"])
    .field("body", def("TSInterfaceBody"));

  ["ClassDeclaration",
   "ClassExpression",
  ].forEach(typeName => {
    def(typeName)
      .field("implements",
             [def("TSExpressionWithTypeArguments")],
             defaults.emptyArray);
  });

  def("TSParameterProperty")
    .bases("Pattern")
    .build("parameter")
    .field("accessibility",
           or("public", "private", "protected", void 0),
           defaults["undefined"])
    .field("readonly", Boolean, defaults["false"])
    .field("parameter", or(def("Identifier"),
                           def("AssignmentPattern")));

  // Defined already in es6 and babel-core.
  def("ClassBody")
    .field("body", [or(
      def("MethodDefinition"),
      def("VariableDeclarator"),
      def("ClassPropertyDefinition"),
      def("ClassProperty"),
      def("ClassMethod"),
      // Just need to add these types:
      def("TSDeclareMethod"),
      TSTypeMember
    )]);
};
<|endoftext|>


<commit_before>$(window).load(function() {
    mainApp.init();
});

//Moy huy
//Основной объект - приложение
var mainApp = {
    listGetFullDate: new Array,
    numOfListDays: 5,
    animateDuration: 400,
    previousName: "Сегодня",
    weekDays: ['Воскресенье', 'Понедельник', 'Вторник', 'Среда', 'Четверг', 'Пятница', 'Суббота'],
    init: function() {
        openPreloader();
        $("div.nav-popup-menu").fadeOut("fast");
        $("div.film-popup").fadeOut("fast");
        $("div.popup-back").fadeOut("fast");
        makeWeekDates();
        makeNavPopupMenu();
        getFilmsList(mainApp.numOfListDays + 1, $('#now-icon'));
        $(".sidebar-nav-button:first").addClass("side-bar-button-active");
    }
};
//--------------------------------------------------------------------------------------------

//Получить список фильмов
var getFilmsList = function(day, that) {
    if (!that){
        that = $(".nav-popup-menu-button");
    }
    closeSidebar();
    closeNavPopupMenu();
    closeFilmPopup();
    $(".side-bar-button-active").removeClass("side-bar-button-active");
    that.find(".sidebar-nav-button").addClass("side-bar-button-active");
    openPreloader(function() {
        var getFilmsListLink = "http://afisha51.northshining.xyz/getSiteHtml.php?whatNeed=now&siteUrl=http://vmurmanske.ru/%D0%9A%D0%B8%D0%BD%D0%BE/%D0%A1%D0%B5%D0%B9%D1%87%D0%B0%D1%81  table.filmIndexTable";
        if (day != mainApp.numOfListDays + 1) {
            getFilmsListLink = "http://afisha51.northshining.xyz/getSiteHtml.php?whatNeed=" + mainApp.listGetFullDate[day].dateForGet + "&siteUrl=http://vmurmanske.ru/%D0%9A%D0%B8%D0%BD%D0%BE/" + mainApp.listGetFullDate[day].dateForGet +
                " table.filmDateTable";
        };
        filmsListMake(day, getFilmsListLink);
    });

};

var filmsListMake = function(day, link) {
    $("#content").load(link,
        function() {
            $("div.filmIndex-filmImageWrapperRounding").detach();
            $("td.filmDateTableVS").detach();
            $(".filmDateTableFilmImage").each(function() {
                var filmRowImage = jQuery(this).find('img').attr("src");
                jQuery(this).html('');
            });
            $(".filmIndex-filmImageWrapper1").each(function() {
                var filmRowImage = jQuery(this).find('img').attr("src");
                jQuery(this).html('');
            });
            $(".filmIndexTable-film").each(function() {
                var filmRowImage = jQuery(this).parent().addClass("film-container");
            });
            $(".filmDateTableFilmName").each(function() {
                var filmRowImage = jQuery(this).parent().addClass("film-container");
            });
            $("div.header-nav-name").html(mainApp.listGetFullDate[day].dateForPeople);
            filmsLinkToPopup();
            pageClear();
            window.scrollTo(0, 0);
            closePreloader();
            filmsCostParse();
        });
};
//--------------------------------------------------------------------------------------------

//Прелоадер
var openPreloader = function(callback) {
    $(".loader-inner").fadeIn();
    $(".loader").fadeIn(mainApp.animateDuration, callback);
};

var closePreloader = function() {
    $(".loader-inner").fadeOut();
    $(".loader").fadeOut(mainApp.animateDuration);
};
//--------------------------------------------------------------------------------------------

//Сайдбар
var openSidebar = function() {
    if ($(".sidebar").hasClass("openedSidebar")) {
        closeSidebar();
    } else {
        $(".sidebar").animate({
            left: "+=230"
        }, mainApp.animateDuration, 'easeInOutSine');
        $(".main-page-wrapper").animate({
            "margin-left": "+=225"
        }, mainApp.animateDuration, 'easeInOutSine');
        $(".sidebar").addClass("openedSidebar");
    }

};

var closeSidebar = function() {
    if ($(".sidebar").hasClass("openedSidebar")) {
        $(".sidebar").animate({
            left: "-=230"
        }, mainApp.animateDuration, 'easeInOutSine');
        $(".main-page-wrapper").animate({
            "margin-left": "-=225"
        }, mainApp.animateDuration, 'easeInOutSine');
        $(".sidebar").removeClass("openedSidebar");
    }
};
//--------------------------------------------------------------------------------------------

//Очистка страницы от ненужного мусора
var pageClear = function() {
    $("a.filmCinema").each(function() {
        var cinemaLink = "http://vmurmanske.ru" + jQuery(this).attr("href");
        jQuery(this).attr("href", cinemaLink);
    });
    $("a.filmShowStatus").each(function() {
        var cinemaTimeLink = "http://vmurmanske.ru" + jQuery(this).attr("href");
        jQuery(this).attr("href", cinemaTimeLink);
    });
    $(".filmDateTableFilmImage").detach();
	$(".filmIndex-filmImageWrapper1").detach();
    $(".filmCinema").removeAttr("href");
};
//--------------------------------------------------------------------------------------------

//Парсинг цен фильма
var filmsCostParse = function() {
    var prices = [];
    $("span.film-price").each(function() {
        var price = jQuery(this).text().split(' ');
        prices.push(price[0]);
    });

    var maxPrice = prices[0];
    var minPrice = prices[0];

    prices.forEach(function(item) {
        if (item > maxPrice) {
            maxPrice = item;
        }
        if (item < minPrice) {
            minPrice = item;
        }
    });
    console.log(maxPrice + " " + minPrice);
};

//--------------------------------------------------------------------------------------------

//Описание фильма
var filmsLinkToPopup = function() {
    $("a.filmName").each(function() {
        var linkToFilm = jQuery(this).attr('href');
        var nameOfFilm = jQuery(this).text();
        nameOfFilm = translite(nameOfFilm.replace(/ /g, ""));
        jQuery(this).removeAttr('href');
        if ($("div.list-date").text() === "Сейчас") {
            jQuery(this).closest("div.filmIndexTable-film").attr('onClick', 'openFilmPopup("http://afisha51.northshining.xyz/getSiteHtml.php?whatNeed=' + nameOfFilm + '&siteUrl=http://vmurmanske.ru' + linkToFilm + '");');
        } else {
            jQuery(this).closest("tr").attr('onClick', 'openFilmPopup("http://afisha51.northshining.xyz/getSiteHtml.php?whatNeed=' + nameOfFilm + '&siteUrl=http://vmurmanske.ru' + linkToFilm + '");');
        }

    });

    $("div.filmIndex-filmImageWrapper3 a").each(function() {
        jQuery(this).removeAttr('href');
    });
};

var openFilmPopup = function(link) {
    openPreloader(function() {
        $(".film-popup").load(link + " #filmline-center",
            function() {
                $("body").attr("style", "overflow:hidden;");
                $("#info_pics").detach();
                mainApp.previousName = $(".header-nav-name").html();
                $(".header-nav-name").html("О фильме");
                $(".film-popup p:first").detach();
                $(".filmOptions").detach();
                $(".film-popup").fadeIn(100);
                $(".popup-back").fadeIn(100);
                $(".film-popup").scrollTop(0);
                closePreloader();
            });
    });

};

var closeFilmPopup = function() {
    $("body").removeAttr("style");
    $(".film-popup").fadeOut(mainApp.animateDuration);
    $(".popup-back").fadeOut(mainApp.animateDuration);
};
//--------------------------------------------------------------------------------------------

//Создание дат на ближайшую неделю
var makeWeekDates = function() {
    var dateNow = new Date();
    var dateNowYear = dateNow.getFullYear();
    var dateNowMonth = dateNow.getMonth();
    for (var i = 0; i <= mainApp.numOfListDays; i++) {
        var listDateDay = dateNow.getDate() + i;
        var dayName = new Date(dateNowYear, dateNowMonth, listDateDay);
        var listDateYear = dayName.getFullYear();
        var listDateMonth = dayName.getMonth() + 1;
        var listDateDay = dayName.getDate();
        var listDateDayName = dayName.getDay();
        mainApp.listGetFullDate[i] = {}
        mainApp.listGetFullDate[i].dateForGet = listDateYear + "-" + listDateMonth + "-" + listDateDay;
        mainApp.listGetFullDate[i].dateForPeople = listDateDay + "." + listDateMonth + "." + listDateYear + " " + mainApp.weekDays[listDateDayName];
    };
    mainApp.listGetFullDate[mainApp.numOfListDays + 1] = {}
    mainApp.listGetFullDate[mainApp.numOfListDays + 1].dateForPeople = "Сейчас";
};
//--------------------------------------------------------------------------------------------

//Меню выбора даты сеанса
var openNavPopupMenu = function(that) {
    if ($(".nav-popup-menu").attr("style") === "display: block;") {
        closeNavPopupMenu();
        $(".side-bar-button-active").removeClass("side-bar-button-active");
    } else {
        openPreloader(function() {
            $(".popup-back").fadeIn(100);
            mainApp.previousName = $(".header-nav-name").html();
            $(".header-nav-name").html("Выбор даты");
            $("div.nav-popup-menu").fadeIn(mainApp.animateDuration);
            $(".side-bar-button-active").removeClass("side-bar-button-active");
            that.find(".sidebar-nav-button").addClass("side-bar-button-active");
            closeSidebar();
            closePreloader();
        });

    }

};

var closeNavPopupMenu = function() {
    $("div.nav-popup-menu").fadeOut(mainApp.animateDuration);
    $(".popup-back").fadeOut(mainApp.animateDuration);
    $(".side-bar-button-active").removeClass("side-bar-button-active");
};

var makeNavPopupMenu = function() {
    for (var i = 0; i <= mainApp.numOfListDays; i++) {
        $("div.nav-popup-menu").append('
' + mainApp.listGetFullDate[i].dateForPeople + '
');
    }
};
//--------------------------------------------------------------------------------------------

//Меню выбора даты сеанса
var closePopup = function() {
    $(".header-nav-name").html(mainApp.previousName);
    closeFilmPopup();
    closeNavPopupMenu();
};
//--------------------------------------------------------------------------------------------

function translite(str) {
    var arr = {
        'а': 'a',
        'б': 'b',
        'в': 'v',
        'г': 'g',
        'д': 'd',
        'е': 'e',
        'ж': 'g',
        'з': 'z',
        'и': 'i',
        'й': 'y',
        'к': 'k',
        'л': 'l',
        'м': 'm',
        'н': 'n',
        'о': 'o',
        'п': 'p',
        'р': 'r',
        'с': 's',
        'т': 't',
        'у': 'u',
        'ф': 'f',
        'ы': 'i',
        'э': 'e',
        'А': 'A',
        'Б': 'B',
        'В': 'V',
        'Г': 'G',
        'Д': 'D',
        'Е': 'E',
        'Ж': 'G',
        'З': 'Z',
        'И': 'I',
        'Й': 'Y',
        'К': 'K',
        'Л': 'L',
        'М': 'M',
        'Н': 'N',
        'О': 'O',
        'П': 'P',
        'Р': 'R',
        'С': 'S',
        'Т': 'T',
        'У': 'U',
        'Ф': 'F',
        'Ы': 'I',
        'Э': 'E',
        'ё': 'yo',
        'х': 'h',
        'ц': 'ts',
        'ч': 'ch',
        'ш': 'sh',
        'щ': 'shch',
        'ъ': '',
        'ь': '',
        'ю': 'yu',
        'я': 'ya',
        'Ё': 'YO',
        'Х': 'H',
        'Ц': 'TS',
        'Ч': 'CH',
        'Ш': 'SH',
        'Щ': 'SHCH',
        'Ъ': '',
        'Ь': '',
        'Ю': 'YU',
        'Я': 'YA'
    };
    var replacer = function(a) {
        return arr[a] || a
    };
    return str.replace(/[А-яёЁ]/g, replacer)
};
<commit_msg>fixed crossdomain sharing<commit_after>$(window).load(function() {
    mainApp.init();
});

//Moy huy
//Основной объект - приложение
var mainApp = {
    listGetFullDate: new Array,
    numOfListDays: 5,
    animateDuration: 400,
    previousName: "Сегодня",
    weekDays: ['Воскресенье', 'Понедельник', 'Вторник', 'Среда', 'Четверг', 'Пятница', 'Суббота'],
    init: function() {
        openPreloader();
        $("div.nav-popup-menu").fadeOut("fast");
        $("div.film-popup").fadeOut("fast");
        $("div.popup-back").fadeOut("fast");
        makeWeekDates();
        makeNavPopupMenu();
        getFilmsList(mainApp.numOfListDays + 1, $('#now-icon'));
        $(".sidebar-nav-button:first").addClass("side-bar-button-active");
    }
};
//--------------------------------------------------------------------------------------------

//Получить список фильмов
var getFilmsList = function(day, that) {
    if (!that){
        that = $(".nav-popup-menu-button");
    }
    closeSidebar();
    closeNavPopupMenu();
    $(".side-bar-button-active").removeClass("side-bar-button-active");
    that.find(".sidebar-nav-button").addClass("side-bar-button-active");
    openPreloader(function() {
        var getFilmsListLink = "http://52.33.178.54/getSiteHtml.php?allow=1&whatNeed=now&siteUrl=http://vmurmanske.ru/%D0%9A%D0%B8%D0%BD%D0%BE/%D0%A1%D0%B5%D0%B9%D1%87%D0%B0%D1%81  table.filmIndexTable";
        if (day != mainApp.numOfListDays + 1) {
            getFilmsListLink = "http://52.33.178.54/getSiteHtml.php?allow=1&whatNeed=" + mainApp.listGetFullDate[day].dateForGet + "&siteUrl=http://vmurmanske.ru/%D0%9A%D0%B8%D0%BD%D0%BE/" + mainApp.listGetFullDate[day].dateForGet +
                " table.filmDateTable";
        };
        filmsListMake(day, getFilmsListLink);
    });

};

var filmsListMake = function(day, link) {
    $("#content").load(link,
        function() {
            $("div.filmIndex-filmImageWrapperRounding").detach();
            $("td.filmDateTableVS").detach();
            $(".filmDateTableFilmImage").each(function() {
                var filmRowImage = jQuery(this).find('img').attr("src");
                jQuery(this).html('');
            });
            $(".filmIndex-filmImageWrapper1").each(function() {
                var filmRowImage = jQuery(this).find('img').attr("src");
                jQuery(this).html('');
            });
            $(".filmIndexTable-film").each(function() {
                var filmRowImage = jQuery(this).parent().addClass("film-container");
            });
            $(".filmDateTableFilmName").each(function() {
                var filmRowImage = jQuery(this).parent().addClass("film-container");
            });
            $("div.header-nav-name").html(mainApp.listGetFullDate[day].dateForPeople);
            filmsLinkToPopup();
            pageClear();
            window.scrollTo(0, 0);
            closePreloader();
            filmsCostParse();
        });
};
//--------------------------------------------------------------------------------------------

//Прелоадер
var openPreloader = function(callback) {
    $(".loader-inner").fadeIn();
    $(".loader").fadeIn(mainApp.animateDuration, callback);
};

var closePreloader = function() {
    $(".loader-inner").fadeOut();
    $(".loader").fadeOut(mainApp.animateDuration);
};
//--------------------------------------------------------------------------------------------

//Сайдбар
var openSidebar = function() {
    if ($(".sidebar").hasClass("openedSidebar")) {
        closeSidebar();
    } else {
        $(".sidebar").animate({
            left: "+=230"
        }, mainApp.animateDuration, 'easeInOutSine');
        $(".main-page-wrapper").animate({
            "margin-left": "+=225"
        }, mainApp.animateDuration, 'easeInOutSine');
        $(".sidebar").addClass("openedSidebar");
    }

};

var closeSidebar = function() {
    if ($(".sidebar").hasClass("openedSidebar")) {
        $(".sidebar").animate({
            left: "-=230"
        }, mainApp.animateDuration, 'easeInOutSine');
        $(".main-page-wrapper").animate({
            "margin-left": "-=225"
        }, mainApp.animateDuration, 'easeInOutSine');
        $(".sidebar").removeClass("openedSidebar");
    }
};
//--------------------------------------------------------------------------------------------

//Очистка страницы от ненужного мусора
var pageClear = function() {
    $("a.filmCinema").each(function() {
        var cinemaLink = "http://vmurmanske.ru" + jQuery(this).attr("href");
        jQuery(this).attr("href", cinemaLink);
    });
    $("a.filmShowStatus").each(function() {
        var cinemaTimeLink = "http://vmurmanske.ru" + jQuery(this).attr("href");
        jQuery(this).attr("href", cinemaTimeLink);
    });
};
//--------------------------------------------------------------------------------------------

//Парсинг цен фильма
var filmsCostParse = function() {
    var prices = [];
    $("span.film-price").each(function() {
        var price = jQuery(this).text().split(' ');
        prices.push(price[0]);
    });

    var maxPrice = prices[0];
    var minPrice = prices[0];

    prices.forEach(function(item) {
        if (item > maxPrice) {
            maxPrice = item;
        }
        if (item < minPrice) {
            minPrice = item;
        }
    });
    console.log(maxPrice + " " + minPrice);
};

//--------------------------------------------------------------------------------------------

//Описание фильма
var filmsLinkToPopup = function() {
    $("a.filmName").each(function() {
        var linkToFilm = jQuery(this).attr('href');
        var nameOfFilm = jQuery(this).text();
        nameOfFilm = translite(nameOfFilm.replace(/ /g, ""));
        jQuery(this).removeAttr('href');
        if ($("div.list-date").text() === "Сейчас") {
            jQuery(this).closest("div.filmIndexTable-film").attr('onClick', 'openFilmPopup("http://52.33.178.54/getSiteHtml.php?allow=1&whatNeed=' + nameOfFilm + '&siteUrl=http://vmurmanske.ru' + linkToFilm + '");');
        } else {
            jQuery(this).closest("tr").attr('onClick', 'openFilmPopup("http://52.33.178.54/getSiteHtml.php?allow=1&whatNeed=' + nameOfFilm + '&siteUrl=http://vmurmanske.ru' + linkToFilm + '");');
        }

    });

    $("div.filmIndex-filmImageWrapper3 a").each(function() {
        jQuery(this).removeAttr('href');
    });
};

var openFilmPopup = function(link) {
    openPreloader(function() {
        $(".film-popup").load(link + " #filmline-center",
            function() {
                $("body").attr("style", "overflow:hidden;");
                $("#info_pics").detach();
                mainApp.previousName = $(".header-nav-name").html();
                $(".header-nav-name").html($(".filmSingle").html());
                $(".film-popup p:first").detach();
                $(".filmSingle").detach();
                $(".filmOptions").detach();
                $(".film-popup").fadeIn(100);
                $(".popup-back").fadeIn(100);
                $(".film-popup").scrollTop(0);
                closePreloader();
            });
    });

};

var closeFilmPopup = function() {
    $("body").removeAttr("style");
    $(".film-popup").fadeOut(mainApp.animateDuration);
    $(".popup-back").fadeOut(mainApp.animateDuration);
};
//--------------------------------------------------------------------------------------------

//Создание дат на ближайшую неделю
var makeWeekDates = function() {
    var dateNow = new Date();
    var dateNowYear = dateNow.getFullYear();
    var dateNowMonth = dateNow.getMonth();
    for (var i = 0; i <= mainApp.numOfListDays; i++) {
        var listDateDay = dateNow.getDate() + i;
        var dayName = new Date(dateNowYear, dateNowMonth, listDateDay);
        var listDateYear = dayName.getFullYear();
        var listDateMonth = dayName.getMonth() + 1;
        var listDateDay = dayName.getDate();
        var listDateDayName = dayName.getDay();
        mainApp.listGetFullDate[i] = {}
        mainApp.listGetFullDate[i].dateForGet = listDateYear + "-" + listDateMonth + "-" + listDateDay;
        mainApp.listGetFullDate[i].dateForPeople = listDateDay + "." + listDateMonth + "." + listDateYear + " " + mainApp.weekDays[listDateDayName];
    };
    mainApp.listGetFullDate[mainApp.numOfListDays + 1] = {}
    mainApp.listGetFullDate[mainApp.numOfListDays + 1].dateForPeople = "Сейчас";
};
//--------------------------------------------------------------------------------------------

//Меню выбора даты сеанса
var openNavPopupMenu = function(that) {
    if ($(".nav-popup-menu").attr("style") === "display: block;") {
        closeNavPopupMenu();
        $(".side-bar-button-active").removeClass("side-bar-button-active");
    } else {
        openPreloader(function() {
            $(".popup-back").fadeIn(100);
            mainApp.previousName = $(".header-nav-name").html();
            $(".header-nav-name").html("Выбор даты");
            $("div.nav-popup-menu").fadeIn(mainApp.animateDuration);
            $(".side-bar-button-active").removeClass("side-bar-button-active");
            that.find(".sidebar-nav-button").addClass("side-bar-button-active");
            closeSidebar();
            closePreloader();
        });

    }

};

var closeNavPopupMenu = function() {
    $("div.nav-popup-menu").fadeOut(mainApp.animateDuration);
    $(".popup-back").fadeOut(mainApp.animateDuration);
    $(".side-bar-button-active").removeClass("side-bar-button-active");
};

var makeNavPopupMenu = function() {
    for (var i = 0; i <= mainApp.numOfListDays; i++) {
        $("div.nav-popup-menu").append('
' + mainApp.listGetFullDate[i].dateForPeople + '
');
    }
};
//--------------------------------------------------------------------------------------------

//Меню выбора даты сеанса
var closePopup = function() {
    $(".header-nav-name").html(mainApp.previousName);
    closeFilmPopup();
    closeNavPopupMenu();
};
//--------------------------------------------------------------------------------------------

function translite(str) {
    var arr = {
        'а': 'a',
        'б': 'b',
        'в': 'v',
        'г': 'g',
        'д': 'd',
        'е': 'e',
        'ж': 'g',
        'з': 'z',
        'и': 'i',
        'й': 'y',
        'к': 'k',
        'л': 'l',
        'м': 'm',
        'н': 'n',
        'о': 'o',
        'п': 'p',
        'р': 'r',
        'с': 's',
        'т': 't',
        'у': 'u',
        'ф': 'f',
        'ы': 'i',
        'э': 'e',
        'А': 'A',
        'Б': 'B',
        'В': 'V',
        'Г': 'G',
        'Д': 'D',
        'Е': 'E',
        'Ж': 'G',
        'З': 'Z',
        'И': 'I',
        'Й': 'Y',
        'К': 'K',
        'Л': 'L',
        'М': 'M',
        'Н': 'N',
        'О': 'O',
        'П': 'P',
        'Р': 'R',
        'С': 'S',
        'Т': 'T',
        'У': 'U',
        'Ф': 'F',
        'Ы': 'I',
        'Э': 'E',
        'ё': 'yo',
        'х': 'h',
        'ц': 'ts',
        'ч': 'ch',
        'ш': 'sh',
        'щ': 'shch',
        'ъ': '',
        'ь': '',
        'ю': 'yu',
        'я': 'ya',
        'Ё': 'YO',
        'Х': 'H',
        'Ц': 'TS',
        'Ч': 'CH',
        'Ш': 'SH',
        'Щ': 'SHCH',
        'Ъ': '',
        'Ь': '',
        'Ю': 'YU',
        'Я': 'YA'
    };
    var replacer = function(a) {
        return arr[a] || a
    };
    return str.replace(/[А-яёЁ]/g, replacer)
};
<|endoftext|>


<commit_before>import { Template } from 'meteor/templating';
import {FlowRouter} from 'meteor/ostrio:flow-router-extra';
import { Wallet, UserData } from '/imports/api/indexDB.js';

import '/imports/ui/components/notLoggedIn.html'
import './walletTransactions.html'
import './wallet.scss'

Template.walletTransactions.onCreated(function bodyOnCreated() {
	var currency = FlowRouter.getParam('currency');

    this.rewardType = new ReactiveVar()
    this.currencyType = FlowRouter.current().params.currency

    var self = this
    self.autorun(function() {
      SubsCache.subscribe('wallet');
      SubsCache.subscribe('users');
    })

	// mark notifications for selected currency as read
	Meteor.call('markAsRead', currency, (error, result) => {
		if (error) {
			console.error(error)
		}
	});
});

Template.walletTransactions.helpers({
  canDeposit: () => ~['xmr'].indexOf(FlowRouter.getParam('currency')),
  hasPaymentId: () => ~['xmr'].indexOf(FlowRouter.getParam('currency')),
  depositAddress: () => global[`_${FlowRouter.getParam('currency').toUpperCase()}Address`],
  paymentId: () => {
    let user = UserData.findOne({
      _id: Meteor.userId()
    })

    return user.paymentId
  },
  entry (){
    var filter = Template.instance().rewardType.get();
    var currencyType = Template.instance().currencyType;
    var query = filter ? {type: "transaction", rewardType:filter} : {type: "transaction"}

    if (currencyType) {
      switch(currencyType.toUpperCase()) {
        case 'KZR' :
          query = filter ? {type: "transaction", rewardType:filter,  $or: [ {message:/KZR/i}, {message:/ZRQ/i}, {message:/ZZR/i} ]} : {type: "transaction",  $or: [ {message:/KZR/i}, {message:/ZRQ/i} ]}
          break
        case 'USD' :
          query = filter ? {type: "transaction", rewardType:filter, message:/USD/i} : {type: "transaction", message:/USD/i}
          break
        case 'ETH' :
          query = filter ? {type: "transaction", rewardType:filter, message:/ETH/i} : {type: "transaction", message:/ETH/i}
          break
        case 'XMR' :
          query = filter ? {type: "transaction", rewardType:filter, message:/XMR/i} : {type: "transaction", message:/XMR/i}
          break
      }
    }
    return Wallet.find(query, {sort: {time: -1 }});
  },
  walletTable: function () {
    return {
      noDataTmpl: 'noDataTmpl',
      rowsPerPage: 100,
      showFilter: false,
      fields: [
        {
          key: 'message',
          label: TAPi18n.__('kzrWallet.message'),
          fn: function(value, object, key) {
            // convert old 'ZZR' and 'ZRQ' labels to 'KZR' and return
            return value.replace("ZZR", "KZR").replace("ZRQ", "KZR");
          }
        },
                        {
          key: 'amount',
          label: TAPi18n.__('kzrWallet.amount')
        },
        {
          key: 'time',
          label: TAPi18n.__('kzrWallet.date'),
          sortByValue:true,
          sortOrder: 0,
          sortDirection: -1,
          fn: function(value, object, key) { return new Date(value).toLocaleString([], {day:'numeric',month:'short',year:'numeric',hour: '2-digit', minute:'2-digit'}) }
        },
        {
          key: 'from',
          label: TAPi18n.__('kzrWallet.from'),
          fn: function(value, object, key) { return (Meteor.users.findOne(value) || {}).username || value; }
        },
        {
          key: 'rewardType',
          label: TAPi18n.__('kzrWallet.type'),
          fn: function(value, object, key) { return transactionTypes(value); }
        },
      ]
    };
  },
  currencyType : () => {
    return Template.instance().currencyType.toUpperCase()
  }
})

Template.walletTransactions.events({
	'click .form-check-input': function(event, templateInstance) {
		if (templateInstance.$('input:checked').length > 0) {
			templateInstance.$('input:checked').each(function() {
				if ($(this).val() !== $(event.currentTarget).val()) {
					$(this).prop('checked', false)
				}
			});
			if (event.target.value === 'all') {
				Template.instance().rewardType.set(false);
			} else {
				Template.instance().rewardType.set(event.target.value);
			}
		} else {
			Template.instance().rewardType.set(' ')
		}
  }
})
<commit_msg>Problem : Currency amount is not formatted #1848<commit_after>import { Template } from 'meteor/templating';
import { FlowRouter } from 'meteor/ostrio:flow-router-extra';
import { Wallet, UserData } from '/imports/api/indexDB.js';

import '/imports/ui/components/notLoggedIn.html'
import './walletTransactions.html'
import './wallet.scss'

Template.walletTransactions.onCreated(function bodyOnCreated() {
  var currency = FlowRouter.getParam('currency');

  this.rewardType = new ReactiveVar()
  this.currencyType = FlowRouter.current().params.currency

  var self = this
  self.autorun(function () {
    SubsCache.subscribe('wallet')
    SubsCache.subscribe('users')
  })

  // mark notifications for selected currency as read
  Meteor.call('markAsRead', currency, (error, result) => {
    if (error) {
      console.error(error)
    }
  });
});

function currencyValue (currency) {
  let bal = currency.amount
  let name = currency.currency
  switch(name.toUpperCase()){
    case 'USD' :
      bal = bal ? (bal).toFixed(2).replace(/\d(?=(\d{3})+\.)/g, '$&,') : 0
      break
    case 'ETH' :
      bal = bal ? (bal).toFixed(18).replace(/\d(?=(\d{3})+\.)/g, '$&,') : 0
      break
    case 'XMR' :
      bal = bal ? (bal).toFixed(12).replace(/\d(?=(\d{3})+\.)/g, '$&,') : 0
      break
  }
  return bal
}

Template.walletTransactions.helpers({
  canDeposit: () => ~['xmr'].indexOf(FlowRouter.getParam('currency')),
  hasPaymentId: () => ~['xmr'].indexOf(FlowRouter.getParam('currency')),
  depositAddress: () => global[`_${FlowRouter.getParam('currency').toUpperCase()}Address`],
  paymentId: () => {
    let user = UserData.findOne({
      _id: Meteor.userId()
    })

    return user.paymentId
  },
  entry() {
    var filter = Template.instance().rewardType.get();
    var currencyType = Template.instance().currencyType;
    var query = filter ? { type: "transaction", rewardType: filter } : { type: "transaction" }

    if (currencyType) {
      switch (currencyType.toUpperCase()) {
        case 'KZR':
          query = filter ? { type: "transaction", rewardType: filter, $or: [{ message: /KZR/i }, { message: /ZRQ/i }, { message: /ZZR/i }] } : { type: "transaction", $or: [{ message: /KZR/i }, { message: /ZRQ/i }] }
          break
        case 'USD':
          query = filter ? { type: "transaction", rewardType: filter, message: /USD/i } : { type: "transaction", message: /USD/i }
          break
        case 'ETH':
          query = filter ? { type: "transaction", rewardType: filter, message: /ETH/i } : { type: "transaction", message: /ETH/i }
          break
        case 'XMR':
          query = filter ? { type: "transaction", rewardType: filter, message: /XMR/i } : { type: "transaction", message: /XMR/i }
          break
      }
    }
    return Wallet.find(query, { sort: { time: -1 } });
  },
  walletTable: function () {
    return {
      noDataTmpl: 'noDataTmpl',
      rowsPerPage: 100,
      showFilter: false,
      fields: [
        {
          key: 'message',
          label: TAPi18n.__('kzrWallet.message'),
          fn: function (value, object, key) {
            // convert old 'ZZR' and 'ZRQ' labels to 'KZR' and return
            return value.replace("ZZR", "KZR").replace("ZRQ", "KZR");
          }
        },
        {
          key: 'amount',
          label: TAPi18n.__('kzrWallet.amount')
        },
        {
          key: 'time',
          label: TAPi18n.__('kzrWallet.date'),
          sortByValue: true,
          sortOrder: 0,
          sortDirection: -1,
          fn: function (value, object, key) {
            return currencyValue(object) }
            // return new Date(value).toLocaleString([], { day: 'numeric', month: 'short', year: 'numeric', hour: '2-digit', minute: '2-digit' }) }
        },
        {
          key: 'from',
          label: TAPi18n.__('kzrWallet.from'),
          fn: function (value, object, key) { return (Meteor.users.findOne(value) || {}).username || value; }
        },
        {
          key: 'rewardType',
          label: TAPi18n.__('kzrWallet.type'),
          fn: function (value, object, key) { return transactionTypes(value); }
        },
      ]
    };
  },
  currencyType: () => {
    return Template.instance().currencyType.toUpperCase()
  }
})

Template.walletTransactions.events({
  'click .form-check-input': function (event, templateInstance) {
    if (templateInstance.$('input:checked').length > 0) {
      templateInstance.$('input:checked').each(function () {
        if ($(this).val() !== $(event.currentTarget).val()) {
          $(this).prop('checked', false)
        }
      });
      if (event.target.value === 'all') {
        Template.instance().rewardType.set(false);
      } else {
        Template.instance().rewardType.set(event.target.value);
      }
    } else {
      Template.instance().rewardType.set(' ')
    }
  }
})
<|endoftext|>


<commit_before>import { countDecimalPlaces } from './utils'

describe('countDecimalPlaces', () => {
  it('Should count decimals with dot notation', () => {
    expect(countDecimalPlaces('1.123')).toBe(3)
    expect(countDecimalPlaces('1.12')).toBe(2)
    expect(countDecimalPlaces('1.')).toBe(0)
    expect(countDecimalPlaces('1')).toBe(0)
    expect(countDecimalPlaces('.123')).toBe(3)
  })

  it('Should count decimals with scientific notation', () => {
    expect(countDecimalPlaces('1e-3')).toBe(3)
    expect(countDecimalPlaces('1e-2')).toBe(2)
    expect(countDecimalPlaces('1.2e-2')).toBe(3)
    expect(countDecimalPlaces('1.e-2')).toBe(2)
    expect(countDecimalPlaces('1.23123e2')).toBe(3)
    expect(countDecimalPlaces('123.123e+2')).toBe(1)
    expect(countDecimalPlaces('.2e-2')).toBe(3)
  })

  it('Should return zero when parameter is an integer', () => {
    expect(countDecimalPlaces('1')).toBe(0)
    expect(countDecimalPlaces('123')).toBe(0)
    expect(countDecimalPlaces('0')).toBe(0)
    expect(countDecimalPlaces('-123')).toBe(0)
  })

  it('Should return zero when parameter is not a valid number', () => {
    expect(countDecimalPlaces('abc')).toBe(0)
    expect(countDecimalPlaces('e')).toBe(0)
    expect(countDecimalPlaces('')).toBe(0)
    expect(countDecimalPlaces(null)).toBe(0)
    expect(countDecimalPlaces(false)).toBe(0)
    expect(countDecimalPlaces(undefined)).toBe(0)
  })
})
<commit_msg>Update countDecimalPlaces tests<commit_after>import { countDecimalPlaces } from './utils'

describe('countDecimalPlaces', () => {
  [
    { value: '1.123', expected: 3 },
    { value: '1.12', expected: 2 },
    { value: '1.', expected: 0 },
    { value: '1', expected: 0 },
    { value: '.123', expected: 3 },
    { value: .123, expected: 3 },
    { value: '1e-3', expected: 3 },
    { value: '1e-2', expected: 2 },
    { value: '1.2e-2', expected: 3 },
    { value: '1.e-2', expected: 2 },
    { value: '1.23123e2', expected: 3 },
    { value: '123.123e+2', expected: 1 },
    { value: 123.123e+2, expected: 1 },
    { value: '.2e-2', expected: 3 },
    { value: '1', expected: 0 },
    { value: '123', expected: 0 },
    { value: '0', expected: 0 },
    { value: '-123', expected: 0 },
    { value: 'abc', expected: 0 },
    { value: 'e', expected: 0 },
    { value: '', expected: 0 },
    { value: null, expected: 0 },
    { value: false, expected: 0 },
    { value: undefined, expected: 0 }
  ].forEach(testCase => {
    it(`Should count decimals for ${testCase.value}`, () => {
      expect(countDecimalPlaces(testCase.value)).toBe(testCase.expected)
    })
  })
})
<|endoftext|>


<commit_before>import Ember from 'ember';

var ESC       = 27;
var $document = Ember.$(document);

export default Ember.Component.extend({
  classNames: 'ui-overlay',
  role: 'dialog',

  actions: {
    close: function() {
      var component = this;

      this.$().addClass('fade-out');

      this.$().on('transitionend', function() {
        Ember.run(function() {
          component.sendAction('close');
        });
      });
    }
  },

  closeIfClickedOutsideOfContentArea: function(event) {
    if (event.target !== this.get('element')) {
      return;
    }

    this.send('close');
  }.on('click'),

  addFadeInClass: function() {
    this.$().addClass('fade-in');
  }.on('didInsertElement'),

  registerEscapeListener: function() {
    var component = this;

    $document.on('keyup.ui-overlay', function(event) {
      Ember.run(function() {
        if (event.which !== ESC) {
          return;
        }

        component.send('close');
      });
    });

  }.on('didInsertElement'),

  deregisterEscapeListener: function() {
    $document.off('keyup.ui-overlay');
  }.on('willDestroyElement')
});
<commit_msg>Add nonspec handlers for animationend.<commit_after>import Ember from 'ember';

var ESC          = 27;
var ANIMATIONEND = 'animationend webkitAnimationEnd oanimationend MSAnimationEnd';
var $document    = Ember.$(document);

export default Ember.Component.extend({
  classNames: 'ui-overlay',
  role: 'dialog',

  actions: {
    close: function() {
      var component = this;

      this.$().addClass('fade-out');

      this.$().on(ANIMATIONEND, function() {
        Ember.run(function() {
          component.sendAction('close');
        });
      });
    }
  },

  closeIfClickedOutsideOfContentArea: function(event) {
    if (event.target !== this.get('element')) {
      return;
    }

    this.send('close');
  }.on('click'),

  addFadeInClass: function() {
    this.$().addClass('fade-in');
  }.on('didInsertElement'),

  registerEscapeListener: function() {
    var component = this;

    $document.on('keyup.ui-overlay', function(event) {
      Ember.run(function() {
        if (event.which !== ESC) {
          return;
        }

        component.send('close');
      });
    });

  }.on('didInsertElement'),

  deregisterEscapeListener: function() {
    $document.off('keyup.ui-overlay');
  }.on('willDestroyElement')
});
<|endoftext|>


<commit_before>var $p = (function () {

    var $ = {}, // Public namespace
        _ = {}; // Private namespace

    // Polyfills
    // From https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys
    if (!Object.keys) {
        Object.keys = (function() {
            'use strict';
            var hasOwnProperty = Object.prototype.hasOwnProperty,
                hasDontEnumBug = !({ toString: null }).propertyIsEnumerable('toString'),
                dontEnums = [
                    'toString',
                    'toLocaleString',
                    'valueOf',
                    'hasOwnProperty',
                    'isPrototypeOf',
                    'propertyIsEnumerable',
                    'constructor'
                ],
                dontEnumsLength = dontEnums.length;

            return function(obj) {
                if (typeof obj !== 'object' && (typeof obj !== 'function' || obj === null)) {
                    throw new TypeError('Object.keys called on non-object');
                }

                var result = [], prop, i;

                for (prop in obj) {
                    if (hasOwnProperty.call(obj, prop)) {
                        result.push(prop);
                    }
                }

                if (hasDontEnumBug) {
                    for (i = 0; i < dontEnumsLength; i++) {
                        if (hasOwnProperty.call(obj, dontEnums[i])) {
                            result.push(dontEnums[i]);
                        }
                    }
                }
                return result;
            };
        }());
    }

    // Production steps of ECMA-262, Edition 5, 15.4.4.18
    // Reference: http://es5.github.io/#x15.4.4.18
    if (!Array.prototype.forEach) {

        Array.prototype.forEach = function(callback, thisArg) {

            var T, k;

            if (this == null) {
                throw new TypeError(' this is null or not defined');
            }

            // 1. Let O be the result of calling ToObject passing the |this| value as the argument.
            var O = Object(this);

            // 2. Let lenValue be the result of calling the Get internal method of O with the argument "length".
            // 3. Let len be ToUint32(lenValue).
            var len = O.length >>> 0;

            // 4. If IsCallable(callback) is false, throw a TypeError exception.
            // See: http://es5.github.com/#x9.11
            if (typeof callback !== "function") {
                throw new TypeError(callback + ' is not a function');
            }

            // 5. If thisArg was supplied, let T be thisArg; else let T be undefined.
            if (arguments.length > 1) {
                T = thisArg;
            }

            // 6. Let k be 0
            k = 0;

            // 7. Repeat, while k < len
            while (k < len) {

                var kValue;

                // a. Let Pk be ToString(k).
                //   This is implicit for LHS operands of the in operator
                // b. Let kPresent be the result of calling the HasProperty internal method of O with argument Pk.
                //   This step can be combined with c
                // c. If kPresent is true, then
                if (k in O) {

                    // i. Let kValue be the result of calling the Get internal method of O with argument Pk.
                    kValue = O[k];

                    // ii. Call the Call internal method of callback with T as the this value and
                    // argument list containing kValue, k, and O.
                    callback.call(T, kValue, k, O);
                }
                // d. Increase k by 1.
                k++;
            }
            // 8. return undefined
        };
    }

    if (!Array.isArray) {
        Array.isArray = function(arg) {
            return Object.prototype.toString.call(arg) === '[object Array]';
        };
    }

    // Exceptions
    function PatternMatchingException(message) {
        this.message = message;
    }

    // Private members
    $.ARRAY_REGEX = {
        'CONS1': /^\[.*\]$/g,
        'CONS2': /^(\w+::\w+)+$/g,
        'CONS3': /^\w+\.\.\w+$/g
    };

    $.PAR_REGEX = /^__\w+__$/g;
    $.ADT_REGEX = /^\w+\(.*\)$/g;

    $.assertType = function (obj, type) {
        return obj === null && type === null || obj.constructor.name === type;
    };

    $.isZero = function (v) {
        return v === 0;
    };

    $.all = function (p, arr) {
        arr.forEach(function (v) {
            if (!p(v)) return false;
        });

        return true;
    };

    $.map = function (arr, fn) {
        var out = [];

        arr.forEach(function (val) {
            out.push(fn(val));
        });

        return out;
    };

    $.range = function (low, high) {
        var arr = [];

        for (var i = low; i <= high; i++)
            arr.push(i);

        return arr;
    };

    $.cmp = function (a, b) {
        return a - b;
    };

    $.hasPattern = function (arr, reg) {
        for (var i = 0, len = arr.length; i < len; i++) {
            if (arr[i].match(reg))
                return arr[i];
        }

        return null;
    };

    $.checkCons = function (arg, type) {
        var bexpr = !(arg === null && type === null) &&
                    (arg.__variant__ === undefined ?
                    (arg.constructor !== type)    :
                    (arg.__variant__ !== type.__name__));

        if (bexpr)
            throw new PatternMatchingException('Provided wrong type of argument: ' + arg.constructor.name);
    };

    $.equalArr = function (a1, a2, cmp) {
        cmp = cmp || $.cmp;

        if (a1.length !== a2.length) return false;

        for (var i = 0, len = a1.length; i < len; i++) {
            if (cmp(a1[i], a2[i]) !== 0)
                return false;
        }

        return true;
    };

    $.isNum = function (str) {
        return !isNaN(str);
    };

    // compare: x::xs and x1::x2::xs (latter to be checked first)
    $.compareArrayPtrFn = function (a, b) {
        if (a === '_' || a.match($.PAR_REGEX)) return 1;
        if ((a.match($.ARRAY_REGEX.CONS1) && b.match($.ARRAY_REGEX.CONS1)) ||
            (a.match($.ARRAY_REGEX.CONS2) && b.match($.ARRAY_REGEX.CONS2)) ||
            (a.match($.ARRAY_REGEX.CONS3) && b.match($.ARRAY_REGEX.CONS3))) return 0;
        if (a.match($.ARRAY_REGEX.CONS2)) return 1;

        return -1;
    };

    $.isArr = function (str) {
        return $.ARRAY_REGEX.CONS1.test(str) ||
            $.ARRAY_REGEX.CONS2.test(str) ||
            $.ARRAY_REGEX.CONS3.test(str);
    };

    $.checkOtherZero = function (type, keys, obj) {
        keys.forEach(function (t) {
            if (t !== type && (t !== 'WC' && obj[t] > 0))
                return false;
        });

        return true;
    };

    /**
     * Type inference, exhaustiveness and redundancies check
     * @param ks Pattern keys
     * @returns {string} Type name
     */
    $.inferType = function (ks) {
        var tmap = {
            'Number': 0,
            'Boolean': 0,
            'Array': 0,
            'Function': 0, // TODO
            'ADT': 0, // TODO
            'PAR': 0,
            'WC': 0,
            'FVC': 0
        };

        ks.forEach(function (v) {
            if (v === 'true' || v === 'false')                        // Boolean
                tmap.Boolean++;
            else if ($.isNum(v))                                      // Number
                tmap.Number++;
            else if (v === '_')                                       // Wildcard
                tmap.WC++;
            else if (v === null || v === undefined)                   // Falsy values
                tmap.FVC++;
            else if ($.isArr(v))    // Array
                tmap.Array++;
            else if ($.ADT_REGEX.test(v))
                tmap.ADT++;
            else if ($.PAR_REGEX.test(v))                             // Parameter
                tmap.PAR++;
        });

        console.log(tmap);

        if ((tmap.PAR === 0 && tmap.WC === 0) || Math.abs(tmap.PAR - tmap.WC) !== 1)
            throw new PatternMatchingException('Pattern matching is not consistent');

        // Get max of counts
        // for all types except string:
        //  if the number of values is bigger than 0 and wc or par is 1 then type is valid
        // string:
        //
        var maxc = -1,
            maxr = '',
            tmKeys = Object.keys(tmap);

        tmKeys.forEach(function (t) {
            if (tmap[t] > maxc) {
                maxr = t;
                maxc = tmap[t];
            }
        });

        if (!$.checkOtherZero(maxr, tmKeys, tmap))
            throw new PatternMatchingException('Patterns are not consistent (not the same type)');

        // Check for redundancies and exhaustiveness

        return maxr;
    };

    /**
     *
     * @param o Object map
     * @param val Value to match against
     * @param bindings Bindings to attach
     * @param type Type of the patterns
     * @returns {Function}
     */
    $.match = function (o, val, bindings, type) {
        var fn, parts;

        // Apply bindings
        if (bindings) {
            var oTmp = {}; // Temporary object

            Object.keys(o).forEach(function (v) {
                oTmp[v] = o[v].bind(bindings);
            });

            o = oTmp;
        }

        var keys = Object.keys(o);

        // NUMBER AND BOOLEAN
        if (type === 'Number' || type === 'Boolean') {
            fn = o[val + ''];

            if (fn !== undefined) return fn();
            else {
                if ((res = $.hasPattern(keys, $.PAR_REGEX)) !== null) {
                    fn = o[res];
                    return fn(val);
                }
                else {
                    fn = o['_'];
                    return fn();
                }
            }
        }
        // ARRAY
        else if (type === 'Array') {
            var res;

            // Order keys
            keys.sort($.compareArrayPtrFn);

            // Loop through patterns
            for (var i = 0, len = keys.length; i < len; i++) {
                var ptr = keys[i].replace(/\s+/g, '');

                // CONS 1
                if ((res = ptr.match($.ARRAY_REGEX.CONS1))) {
                    var carr = ptr.slice(1, -1);
                    fn = o[ptr];

                    if (carr === '' && val.length === 0)
                        return fn();
                    else {
                        var arr = carr.split(',');

                        // Check equality between arr and val
                    }
                }
                // CONS 2
                else if ((res = ptr.match($.ARRAY_REGEX.CONS2))) { // Check x::[] !!!
                    var hds = [],  // heads (individual elements)
                        tail;      // tail
                    parts = res[0].split('::');

                    parts.forEach(function (v, i) {
                        if (i !== parts.length - 1) {
                            hds.push(val[i]);
                        }
                        else {
                            tail = val.slice(i);
                        }
                    });

                    fn = o[ptr];
                    hds.push(tail);
                    return fn.apply(null, hds);
                }
                // CONS 3
                else if ((res = ptr.match($.ARRAY_REGEX.CONS3))) {
                    parts = res[0].split('..');
                    var low   = parseFloat(parts[0]),
                        high  = parseFloat(parts[1]),
                        arr = $.range(low, high);

                    if ($.equalArr(val, arr)) {
                        fn = o[res];
                        return fn(val); // check this
                    }
                }
                // WILD CARD / PARAMETER
                else {
                    if ((res = $.hasPattern(keys, $.PAR_REGEX)) !== null) {
                        fn = o[res];
                        return fn(val);
                    }

                    fn = o['_'];
                    return fn();
                }
            }
        }
        else if (type === 'ADT') {
            fn = o[val + ''];

            if (fn !== undefined) return fn();
            else {
                if ((res = $.hasPattern(keys, $.PAR_REGEX)) !== null) {
                    fn = o[res];
                    return fn(val);
                }
                else {
                    fn = o['_'];
                    return fn();
                }
            }
        }
        // FALSY VALUES
        else {

        }
    };

    /**
     * Pattern matching higher-order function
     * @param o The object with the patterns and their mappings
     * @returns {Function}
     */
    _.fun = function (o) {
        var ks = Object.keys(o), // Get keys
            t = $.inferType(ks); // Infer type, redundancy and exhaustiveness check

        return function (val, bindings) {
            // Check input consistency (e.g. expected input of type...)
            if (!$.assertType(val, t)) throw new PatternMatchingException('Expected input of type ' + t);
            return $.match(o, val, bindings, t);
        };
    };

    _.variant = function (name, o, global) {
        global = (global === undefined ? false : global);
        var cons = global ? window : _;

        cons[name] = function (o) {
            if (!(this instanceof cons[name]))
                return new cons[name](o);

            this.constructors = o;
        };
        cons[name].__name__ = name;

        var variant = cons[name](o);

        (function (variant) {
            var o = variant.constructors,
                keys = Object.keys(o);

            keys.forEach(function (k) {
                var type = o[k];

                /*cons[k].__variant__ = name;
                cons[k].__name__ = k;*/
                cons[k] = function (v) {
                    if (!(this instanceof cons[k]))
                        return new cons[k](v);

                    if (Array.isArray(v) && Array.isArray(type)) { // More args
                        for (var i = 0, len = v.length; i < len; i++)
                            $.checkCons(v[i], type[i]);

                        return cons[k];
                    }
                    else if (!Array.isArray(v) && !Array.isArray(type)) { // One arg
                        $.checkCons(v, type);
                        return cons[k];
                    }
                    else {
                        throw new PatternMatchingException('Types not compatible');
                    }
                };
                cons[k].__variant__ = name;
            });
        })(variant);

        return variant; // Chaining capabilities
    };

    /**
     * $p.fun({
     *      'name|par1:type,par2:type|ret:type': function () { return 0; }
     * });
     *
     * $p.fun({
     *      'False(3)': function (n) { return n; }
     * });
     *
     * $p.variant('Suit').make({
     *      'King': suit, // Variant
     *      'Queen': suit, // Variant
     *      'Trump': Number,
     *      'Joker': null
     * });
     *
     * Trump(3);
     */

    return _;
})();
<commit_msg>Modified ADT<commit_after>var $p = (function () {

    var $ = {}, // Public namespace
        _ = {}; // Private namespace

    // Polyfills
    // From https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys
    if (!Object.keys) {
        Object.keys = (function() {
            'use strict';
            var hasOwnProperty = Object.prototype.hasOwnProperty,
                hasDontEnumBug = !({ toString: null }).propertyIsEnumerable('toString'),
                dontEnums = [
                    'toString',
                    'toLocaleString',
                    'valueOf',
                    'hasOwnProperty',
                    'isPrototypeOf',
                    'propertyIsEnumerable',
                    'constructor'
                ],
                dontEnumsLength = dontEnums.length;

            return function(obj) {
                if (typeof obj !== 'object' && (typeof obj !== 'function' || obj === null)) {
                    throw new TypeError('Object.keys called on non-object');
                }

                var result = [], prop, i;

                for (prop in obj) {
                    if (hasOwnProperty.call(obj, prop)) {
                        result.push(prop);
                    }
                }

                if (hasDontEnumBug) {
                    for (i = 0; i < dontEnumsLength; i++) {
                        if (hasOwnProperty.call(obj, dontEnums[i])) {
                            result.push(dontEnums[i]);
                        }
                    }
                }
                return result;
            };
        }());
    }

    // Production steps of ECMA-262, Edition 5, 15.4.4.18
    // Reference: http://es5.github.io/#x15.4.4.18
    if (!Array.prototype.forEach) {

        Array.prototype.forEach = function(callback, thisArg) {

            var T, k;

            if (this == null) {
                throw new TypeError(' this is null or not defined');
            }

            // 1. Let O be the result of calling ToObject passing the |this| value as the argument.
            var O = Object(this);

            // 2. Let lenValue be the result of calling the Get internal method of O with the argument "length".
            // 3. Let len be ToUint32(lenValue).
            var len = O.length >>> 0;

            // 4. If IsCallable(callback) is false, throw a TypeError exception.
            // See: http://es5.github.com/#x9.11
            if (typeof callback !== "function") {
                throw new TypeError(callback + ' is not a function');
            }

            // 5. If thisArg was supplied, let T be thisArg; else let T be undefined.
            if (arguments.length > 1) {
                T = thisArg;
            }

            // 6. Let k be 0
            k = 0;

            // 7. Repeat, while k < len
            while (k < len) {

                var kValue;

                // a. Let Pk be ToString(k).
                //   This is implicit for LHS operands of the in operator
                // b. Let kPresent be the result of calling the HasProperty internal method of O with argument Pk.
                //   This step can be combined with c
                // c. If kPresent is true, then
                if (k in O) {

                    // i. Let kValue be the result of calling the Get internal method of O with argument Pk.
                    kValue = O[k];

                    // ii. Call the Call internal method of callback with T as the this value and
                    // argument list containing kValue, k, and O.
                    callback.call(T, kValue, k, O);
                }
                // d. Increase k by 1.
                k++;
            }
            // 8. return undefined
        };
    }

    if (!Array.isArray) {
        Array.isArray = function(arg) {
            return Object.prototype.toString.call(arg) === '[object Array]';
        };
    }

    // Exceptions
    function PatternMatchingException(message) {
        this.message = message;
    }

    // Private members
    $.ARRAY_REGEX = {
        'CONS1': /^\[.*\]$/g,
        'CONS2': /^(\w+::\w+)+$/g,
        'CONS3': /^\w+\.\.\w+$/g
    };

    $.PAR_REGEX = /^__\w+__$/g;
    $.ADT_REGEX = /^\w+\(.*\)$/g;

    $.assertType = function (obj, type) {
        return obj === null && type === null || obj.constructor.name === type;
    };

    $.isZero = function (v) {
        return v === 0;
    };

    $.all = function (p, arr) {
        arr.forEach(function (v) {
            if (!p(v)) return false;
        });

        return true;
    };

    $.map = function (arr, fn) {
        var out = [];

        arr.forEach(function (val) {
            out.push(fn(val));
        });

        return out;
    };

    $.range = function (low, high) {
        var arr = [];

        for (var i = low; i <= high; i++)
            arr.push(i);

        return arr;
    };

    $.cmp = function (a, b) {
        return a - b;
    };

    $.hasPattern = function (arr, reg) {
        for (var i = 0, len = arr.length; i < len; i++) {
            if (arr[i].match(reg))
                return arr[i];
        }

        return null;
    };

    $.checkCons = function (arg, type) {
        var bexpr = !(arg === null && type === null) &&
                    (arg.__variant__ === undefined ?
                    (arg.constructor !== type)    :
                    (arg.__variant__ !== type.__name__));

        if (bexpr)
            throw new PatternMatchingException('Provided wrong type of argument: ' + arg.constructor.name);
    };

    $.equalArr = function (a1, a2, cmp) {
        cmp = cmp || $.cmp;

        if (a1.length !== a2.length) return false;

        for (var i = 0, len = a1.length; i < len; i++) {
            if (cmp(a1[i], a2[i]) !== 0)
                return false;
        }

        return true;
    };

    $.isNum = function (str) {
        return !isNaN(str);
    };

    // compare: x::xs and x1::x2::xs (latter to be checked first)
    $.compareArrayPtrFn = function (a, b) {
        if (a === '_' || a.match($.PAR_REGEX)) return 1;
        if ((a.match($.ARRAY_REGEX.CONS1) && b.match($.ARRAY_REGEX.CONS1)) ||
            (a.match($.ARRAY_REGEX.CONS2) && b.match($.ARRAY_REGEX.CONS2)) ||
            (a.match($.ARRAY_REGEX.CONS3) && b.match($.ARRAY_REGEX.CONS3))) return 0;
        if (a.match($.ARRAY_REGEX.CONS2)) return 1;

        return -1;
    };

    $.isArr = function (str) {
        return $.ARRAY_REGEX.CONS1.test(str) ||
            $.ARRAY_REGEX.CONS2.test(str) ||
            $.ARRAY_REGEX.CONS3.test(str);
    };

    $.checkOtherZero = function (type, keys, obj) {
        keys.forEach(function (t) {
            if (t !== type && (t !== 'WC' && obj[t] > 0))
                return false;
        });

        return true;
    };

    /**
     * Type inference, exhaustiveness and redundancies check
     * @param ks Pattern keys
     * @returns {string} Type name
     */
    $.inferType = function (ks) {
        var tmap = {
            'Number': 0,
            'Boolean': 0,
            'Array': 0,
            'Function': 0, // TODO
            'ADT': 0, // TODO
            'PAR': 0,
            'WC': 0,
            'FVC': 0
        };

        ks.forEach(function (v) {
            if (v === 'true' || v === 'false')                        // Boolean
                tmap.Boolean++;
            else if ($.isNum(v))                                      // Number
                tmap.Number++;
            else if (v === '_')                                       // Wildcard
                tmap.WC++;
            else if (v === null || v === undefined)                   // Falsy values
                tmap.FVC++;
            else if ($.isArr(v))    // Array
                tmap.Array++;
            else if ($.ADT_REGEX.test(v))
                tmap.ADT++;
            else if ($.PAR_REGEX.test(v))                             // Parameter
                tmap.PAR++;
        });

        console.log(tmap);

        if ((tmap.PAR === 0 && tmap.WC === 0) || Math.abs(tmap.PAR - tmap.WC) !== 1)
            throw new PatternMatchingException('Pattern matching is not consistent');

        // Get max of counts
        // for all types except string:
        //  if the number of values is bigger than 0 and wc or par is 1 then type is valid
        // string:
        //
        var maxc = -1,
            maxr = '',
            tmKeys = Object.keys(tmap);

        tmKeys.forEach(function (t) {
            if (tmap[t] > maxc) {
                maxr = t;
                maxc = tmap[t];
            }
        });

        if (!$.checkOtherZero(maxr, tmKeys, tmap))
            throw new PatternMatchingException('Patterns are not consistent (not the same type)');

        // Check for redundancies and exhaustiveness

        return maxr;
    };

    /**
     *
     * @param o Object map
     * @param val Value to match against
     * @param bindings Bindings to attach
     * @param type Type of the patterns
     * @returns {Function}
     */
    $.match = function (o, val, bindings, type) {
        var fn, parts;

        // Apply bindings
        if (bindings) {
            var oTmp = {}; // Temporary object

            Object.keys(o).forEach(function (v) {
                oTmp[v] = o[v].bind(bindings);
            });

            o = oTmp;
        }

        var keys = Object.keys(o);

        // NUMBER AND BOOLEAN
        if (type === 'Number' || type === 'Boolean') {
            fn = o[val + ''];

            if (fn !== undefined) return fn();
            else {
                if ((res = $.hasPattern(keys, $.PAR_REGEX)) !== null) {
                    fn = o[res];
                    return fn(val);
                }
                else {
                    fn = o['_'];
                    return fn();
                }
            }
        }
        // ARRAY
        else if (type === 'Array') {
            var res;

            // Order keys
            keys.sort($.compareArrayPtrFn);

            // Loop through patterns
            for (var i = 0, len = keys.length; i < len; i++) {
                var ptr = keys[i].replace(/\s+/g, '');

                // CONS 1
                if ((res = ptr.match($.ARRAY_REGEX.CONS1))) {
                    var carr = ptr.slice(1, -1);
                    fn = o[ptr];

                    if (carr === '' && val.length === 0)
                        return fn();
                    else {
                        var arr = carr.split(',');

                        // Check equality between arr and val
                    }
                }
                // CONS 2
                else if ((res = ptr.match($.ARRAY_REGEX.CONS2))) { // Check x::[] !!!
                    var hds = [],  // heads (individual elements)
                        tail;      // tail
                    parts = res[0].split('::');

                    parts.forEach(function (v, i) {
                        if (i !== parts.length - 1) {
                            hds.push(val[i]);
                        }
                        else {
                            tail = val.slice(i);
                        }
                    });

                    fn = o[ptr];
                    hds.push(tail);
                    return fn.apply(null, hds);
                }
                // CONS 3
                else if ((res = ptr.match($.ARRAY_REGEX.CONS3))) {
                    parts = res[0].split('..');
                    var low   = parseFloat(parts[0]),
                        high  = parseFloat(parts[1]),
                        arr = $.range(low, high);

                    if ($.equalArr(val, arr)) {
                        fn = o[res];
                        return fn(val); // check this
                    }
                }
                // WILD CARD / PARAMETER
                else {
                    if ((res = $.hasPattern(keys, $.PAR_REGEX)) !== null) {
                        fn = o[res];
                        return fn(val);
                    }

                    fn = o['_'];
                    return fn();
                }
            }
        }
        else if (type === 'ADT') {
            fn = o[val + ''];

            if (fn !== undefined) return fn();
            else {
                if ((res = $.hasPattern(keys, $.PAR_REGEX)) !== null) {
                    fn = o[res];
                    return fn(val);
                }
                else {
                    fn = o['_'];
                    return fn();
                }
            }
        }
        // FALSY VALUES
        else {

        }
    };

    /**
     * Pattern matching higher-order function
     * @param o The object with the patterns and their mappings
     * @returns {Function}
     */
    _.fun = function (o) {
        var ks = Object.keys(o), // Get keys
            t = $.inferType(ks); // Infer type, redundancy and exhaustiveness check

        return function (val, bindings) {
            // Check input consistency (e.g. expected input of type...)
            if (!$.assertType(val, t)) throw new PatternMatchingException('Expected input of type ' + t);
            return $.match(o, val, bindings, t);
        };
    };

    _.variant = function (name, global) {
        global = (global === undefined ? false : global);
        var cons = global ? window : _;

        cons[name] = {
            '__name__': name,
            'make': function (o) {
                var keys = Object.keys(o);

                keys.forEach(function (k) {
                    var type = o[k];

                    /*cons[k].__variant__ = name;
                     cons[k].__name__ = k;*/
                    cons[k] = function (v) {
                        if (!(this instanceof cons[k]))
                            return new cons[k](v);

                        var tstring = function _tstring (o) {
                            if (o.value !== null && o.value.constructor !== o) {
                                return o.__name__ + '(' + _tstring(o.value) + ')';
                            }
                            else {
                                return o.__name__ + '(' + o.value + ')';
                            }
                        };

                        this.__variant__ = name;
                        this.__name__ = k;
                        this.value = v;
                        this.toString = function () {
                            // TODO
                            return tstring(this);
                        };

                        if (Array.isArray(v) && Array.isArray(type)) {          // More args
                            for (var i = 0, len = v.length; i < len; i++)
                                $.checkCons(v[i], type[i]);
                        }
                        else if (!Array.isArray(v) && !Array.isArray(type)) {   // One arg
                            $.checkCons(v, type);
                        }
                        else {
                            throw new PatternMatchingException('Types not compatible');
                        }
                    };
                    //cons[k].__variant__ = name;
                });
            }
        };

        return cons[name];
    };

    /**
     * $p.fun({
     *      'name|par1:type,par2:type|ret:type': function () { return 0; }
     * });
     *
     * $p.fun({
     *      'False(3)': function (n) { return n; }
     * });
     *
     * $p.variant('Suit').make({
     *      'King': suit, // Variant
     *      'Queen': suit, // Variant
     *      'Trump': Number,
     *      'Joker': null
     * });
     *
     * Trump(3);
     */

    return _;
})();
<|endoftext|>