<commit_before>/*
 * @flow
 * @lint-ignore-every LINE_WRAP1
 */

import {suite, test} from '../../tsrc/test/Tester';

export default suite(({ideStart, ideNotification, ideRequest, addCode, addFile}) => [
  test('The initial subscribe does not send existing errors', [
    addCode('var x: string = 123;')
      .newErrors(
        `
          test.js:3
            3: var x: string = 123;
                               ^^^ number. This type is incompatible with
            3: var x: string = 123;
                      ^^^^^^ string
        `,
      ),
    ideStart()
      .ideNoNewMessagesAfterSleep(500)
      .because('We are connected, but not subscribed'),
    ideNotification('subscribeToDiagnostics')
      .ideNewMessagesWithTimeout(
        5000,
        [
          {
            "method": "diagnosticsNotification",
            "params": [
              {
                "flowVersion": "<VERSION STUBBED FOR TEST>",
                "errors": [
                  {
                    "kind": "infer",
                    "level": "error",
                    "suppressions": [],
                    "message": [
                      {
                        "context": "var x: string = 123;",
                        "descr": "number",
                        "type": "Blame",
                        "loc": {
                          "source": "test.js",
                          "type": "SourceFile",
                          "start": {
                            "line": 3,
                            "column": 17,
                            "offset": 29
                          },
                          "end": {
                            "line": 3,
                            "column": 19,
                            "offset": 32
                          }
                        },
                        "path": "test.js",
                        "line": 3,
                        "endline": 3,
                        "start": 17,
                        "end": 19
                      },
                      {
                        "context": null,
                        "descr": "This type is incompatible with",
                        "type": "Comment",
                        "path": "",
                        "line": 0,
                        "endline": 0,
                        "start": 1,
                        "end": 0
                      },
                      {
                        "context": "var x: string = 123;",
                        "descr": "string",
                        "type": "Blame",
                        "loc": {
                          "source": "test.js",
                          "type": "SourceFile",
                          "start": {
                            "line": 3,
                            "column": 8,
                            "offset": 20
                          },
                          "end": {
                            "line": 3,
                            "column": 13,
                            "offset": 26
                          }
                        },
                        "path": "test.js",
                        "line": 3,
                        "endline": 3,
                        "start": 8,
                        "end": 13
                      }
                    ]
                  }
                ],
                "passed": false
              }
            ]
          }
        ],
      )
      .because('Subscribing sends all the existing errors'),
  ]),

  test('Recheck behavior', [
    addFile('existingError.js')
      .ideStart()
      .ideNotification('subscribeToDiagnostics')
      .newErrors(
        `
          existingError.js:1
            1: var existingError: number = true;
                                           ^^^^ boolean. This type is incompatible with
            1: var existingError: number = true;
                                  ^^^^^^ number
        `,
      ),
    addCode('var newError: string = 123;')
      .ideNewMessagesWithTimeout(
        5000,
        [
          {
            "method": "startRecheck",
            "params": []
          },
          {
            "method": "diagnosticsNotification",
            "params": [
              {
                "flowVersion": "<VERSION STUBBED FOR TEST>",
                "errors": [],
                "passed": true
              }
            ]
          },
          {
            "method": "diagnosticsNotification",
            "params": [
              {
                "flowVersion": "<VERSION STUBBED FOR TEST>",
                "errors": [
                  {
                    "kind": "infer",
                    "level": "error",
                    "suppressions": [],
                    "message": [
                      {
                        "context": "var newError: string = 123;",
                        "descr": "number",
                        "type": "Blame",
                        "loc": {
                          "source": "test.js",
                          "type": "SourceFile",
                          "start": {
                            "line": 3,
                            "column": 24,
                            "offset": 36
                          },
                          "end": {
                            "line": 3,
                            "column": 26,
                            "offset": 39
                          }
                        },
                        "path": "test.js",
                        "line": 3,
                        "endline": 3,
                        "start": 24,
                        "end": 26
                      },
                      {
                        "context": null,
                        "descr": "This type is incompatible with",
                        "type": "Comment",
                        "path": "",
                        "line": 0,
                        "endline": 0,
                        "start": 1,
                        "end": 0
                      },
                      {
                        "context": "var newError: string = 123;",
                        "descr": "string",
                        "type": "Blame",
                        "loc": {
                          "source": "test.js",
                          "type": "SourceFile",
                          "start": {
                            "line": 3,
                            "column": 15,
                            "offset": 27
                          },
                          "end": {
                            "line": 3,
                            "column": 20,
                            "offset": 33
                          }
                        },
                        "path": "test.js",
                        "line": 3,
                        "endline": 3,
                        "start": 15,
                        "end": 20
                      }
                    ]
                  }
                ],
                "passed": false
              }
            ]
          },
          {
            "method": "endRecheck",
            "params": []
          },
          {
            "method": "diagnosticsNotification",
            "params": [
              {
                "flowVersion": "<VERSION STUBBED FOR TEST>",
                "errors": [
                  {
                    "kind": "infer",
                    "level": "error",
                    "suppressions": [],
                    "message": [
                      {
                        "context": "var existingError: number = true;",
                        "descr": "boolean",
                        "type": "Blame",
                        "loc": {
                          "source": "existingError.js",
                          "type": "SourceFile",
                          "start": {
                            "line": 1,
                            "column": 29,
                            "offset": 28
                          },
                          "end": {
                            "line": 1,
                            "column": 32,
                            "offset": 32
                          }
                        },
                        "path": "existingError.js",
                        "line": 1,
                        "endline": 1,
                        "start": 29,
                        "end": 32
                      },
                      {
                        "context": null,
                        "descr": "This type is incompatible with",
                        "type": "Comment",
                        "path": "",
                        "line": 0,
                        "endline": 0,
                        "start": 1,
                        "end": 0
                      },
                      {
                        "context": "var existingError: number = true;",
                        "descr": "number",
                        "type": "Blame",
                        "loc": {
                          "source": "existingError.js",
                          "type": "SourceFile",
                          "start": {
                            "line": 1,
                            "column": 20,
                            "offset": 19
                          },
                          "end": {
                            "line": 1,
                            "column": 25,
                            "offset": 25
                          }
                        },
                        "path": "existingError.js",
                        "line": 1,
                        "endline": 1,
                        "start": 20,
                        "end": 25
                      }
                    ]
                  },
                  {
                    "kind": "infer",
                    "level": "error",
                    "suppressions": [],
                    "message": [
                      {
                        "context": "var newError: string = 123;",
                        "descr": "number",
                        "type": "Blame",
                        "loc": {
                          "source": "test.js",
                          "type": "SourceFile",
                          "start": {
                            "line": 3,
                            "column": 24,
                            "offset": 36
                          },
                          "end": {
                            "line": 3,
                            "column": 26,
                            "offset": 39
                          }
                        },
                        "path": "test.js",
                        "line": 3,
                        "endline": 3,
                        "start": 24,
                        "end": 26
                      },
                      {
                        "context": null,
                        "descr": "This type is incompatible with",
                        "type": "Comment",
                        "path": "",
                        "line": 0,
                        "endline": 0,
                        "start": 1,
                        "end": 0
                      },
                      {
                        "context": "var newError: string = 123;",
                        "descr": "string",
                        "type": "Blame",
                        "loc": {
                          "source": "test.js",
                          "type": "SourceFile",
                          "start": {
                            "line": 3,
                            "column": 15,
                            "offset": 27
                          },
                          "end": {
                            "line": 3,
                            "column": 20,
                            "offset": 33
                          }
                        },
                        "path": "test.js",
                        "line": 3,
                        "endline": 3,
                        "start": 15,
                        "end": 20
                      }
                    ]
                  }
                ],
                "passed": false
              }
            ]
          },
          {
            "method": "startRecheck",
            "params": []
          },
          {
            "method": "diagnosticsNotification",
            "params": [
              {
                "flowVersion": "<VERSION STUBBED FOR TEST>",
                "errors": [],
                "passed": true
              }
            ]
          },
          {
            "method": "endRecheck",
            "params": []
          },
          {
            "method": "diagnosticsNotification",
            "params": [
              {
                "flowVersion": "<VERSION STUBBED FOR TEST>",
                "errors": [
                  {
                    "kind": "infer",
                    "level": "error",
                    "suppressions": [],
                    "message": [
                      {
                        "context": "var existingError: number = true;",
                        "descr": "boolean",
                        "type": "Blame",
                        "loc": {
                          "source": "existingError.js",
                          "type": "SourceFile",
                          "start": {
                            "line": 1,
                            "column": 29,
                            "offset": 28
                          },
                          "end": {
                            "line": 1,
                            "column": 32,
                            "offset": 32
                          }
                        },
                        "path": "existingError.js",
                        "line": 1,
                        "endline": 1,
                        "start": 29,
                        "end": 32
                      },
                      {
                        "context": null,
                        "descr": "This type is incompatible with",
                        "type": "Comment",
                        "path": "",
                        "line": 0,
                        "endline": 0,
                        "start": 1,
                        "end": 0
                      },
                      {
                        "context": "var existingError: number = true;",
                        "descr": "number",
                        "type": "Blame",
                        "loc": {
                          "source": "existingError.js",
                          "type": "SourceFile",
                          "start": {
                            "line": 1,
                            "column": 20,
                            "offset": 19
                          },
                          "end": {
                            "line": 1,
                            "column": 25,
                            "offset": 25
                          }
                        },
                        "path": "existingError.js",
                        "line": 1,
                        "endline": 1,
                        "start": 20,
                        "end": 25
                      }
                    ]
                  },
                  {
                    "kind": "infer",
                    "level": "error",
                    "suppressions": [],
                    "message": [
                      {
                        "context": "var newError: string = 123;",
                        "descr": "number",
                        "type": "Blame",
                        "loc": {
                          "source": "test.js",
                          "type": "SourceFile",
                          "start": {
                            "line": 3,
                            "column": 24,
                            "offset": 36
                          },
                          "end": {
                            "line": 3,
                            "column": 26,
                            "offset": 39
                          }
                        },
                        "path": "test.js",
                        "line": 3,
                        "endline": 3,
                        "start": 24,
                        "end": 26
                      },
                      {
                        "context": null,
                        "descr": "This type is incompatible with",
                        "type": "Comment",
                        "path": "",
                        "line": 0,
                        "endline": 0,
                        "start": 1,
                        "end": 0
                      },
                      {
                        "context": "var newError: string = 123;",
                        "descr": "string",
                        "type": "Blame",
                        "loc": {
                          "source": "test.js",
                          "type": "SourceFile",
                          "start": {
                            "line": 3,
                            "column": 15,
                            "offset": 27
                          },
                          "end": {
                            "line": 3,
                            "column": 20,
                            "offset": 33
                          }
                        },
                        "path": "test.js",
                        "line": 3,
                        "endline": 3,
                        "start": 15,
                        "end": 20
                      }
                    ]
                  }
                ],
                "passed": false
              }
            ]
          }
        ],
      )
      .because(
        'We get startRecheck when recheck starts and endRecheck when it ends.'
        + ' During recheck, we get incremental results.'
        + ' After recheck, we get total results.'
      ),
  ]),

  test('autocomplete', [
    ideStart(),
    ideRequest('autocomplete', 'test.js', 1, 12, "({x: 123}).;")
      .ideNewMessagesWithTimeout(
        5000,
        [
          {
            "result": [
              {
                "name": "x",
                "type": "number",
                "func_details": null,
                "path": "test.js",
                "line": 1,
                "endline": 1,
                "start": 6,
                "end": 8
              }
            ]
          }
        ],
      ),
  ]),
]);
<commit_msg>Add a no-error recheck to the ide test<commit_after>/*
 * @flow
 * @lint-ignore-every LINE_WRAP1
 */

import {suite, test} from '../../tsrc/test/Tester';

export default suite(({ideStart, ideNotification, ideRequest, addCode, addFile}) => [
  test('The initial subscribe does not send existing errors', [
    addCode('var x: string = 123;')
      .newErrors(
        `
          test.js:3
            3: var x: string = 123;
                               ^^^ number. This type is incompatible with
            3: var x: string = 123;
                      ^^^^^^ string
        `,
      ),
    ideStart()
      .ideNoNewMessagesAfterSleep(500)
      .because('We are connected, but not subscribed'),
    ideNotification('subscribeToDiagnostics')
      .ideNewMessagesWithTimeout(
        5000,
        [
          {
            "method": "diagnosticsNotification",
            "params": [
              {
                "flowVersion": "<VERSION STUBBED FOR TEST>",
                "errors": [
                  {
                    "kind": "infer",
                    "level": "error",
                    "suppressions": [],
                    "message": [
                      {
                        "context": "var x: string = 123;",
                        "descr": "number",
                        "type": "Blame",
                        "loc": {
                          "source": "test.js",
                          "type": "SourceFile",
                          "start": {
                            "line": 3,
                            "column": 17,
                            "offset": 29
                          },
                          "end": {
                            "line": 3,
                            "column": 19,
                            "offset": 32
                          }
                        },
                        "path": "test.js",
                        "line": 3,
                        "endline": 3,
                        "start": 17,
                        "end": 19
                      },
                      {
                        "context": null,
                        "descr": "This type is incompatible with",
                        "type": "Comment",
                        "path": "",
                        "line": 0,
                        "endline": 0,
                        "start": 1,
                        "end": 0
                      },
                      {
                        "context": "var x: string = 123;",
                        "descr": "string",
                        "type": "Blame",
                        "loc": {
                          "source": "test.js",
                          "type": "SourceFile",
                          "start": {
                            "line": 3,
                            "column": 8,
                            "offset": 20
                          },
                          "end": {
                            "line": 3,
                            "column": 13,
                            "offset": 26
                          }
                        },
                        "path": "test.js",
                        "line": 3,
                        "endline": 3,
                        "start": 8,
                        "end": 13
                      }
                    ]
                  }
                ],
                "passed": false
              }
            ]
          }
        ],
      )
      .because('Subscribing sends all the existing errors'),
  ]),

  test('Recheck behavior', [
    addFile('existingError.js')
      .ideStart()
      .ideNotification('subscribeToDiagnostics')
      .newErrors(
        `
          existingError.js:1
            1: var existingError: number = true;
                                           ^^^^ boolean. This type is incompatible with
            1: var existingError: number = true;
                                  ^^^^^^ number
        `,
      ),
    addCode('var notAnError: number = 123;')
      .ideNewMessagesWithTimeout(
        5000,
        [
          {
            "method": "startRecheck",
            "params": []
          },
          {
            "method": "diagnosticsNotification",
            "params": [
              {
                "flowVersion": "<VERSION STUBBED FOR TEST>",
                "errors": [],
                "passed": true
              }
            ]
          },
          {
            "method": "endRecheck",
            "params": []
          },
          {
            "method": "diagnosticsNotification",
            "params": [
              {
                "flowVersion": "<VERSION STUBBED FOR TEST>",
                "errors": [
                  {
                    "kind": "infer",
                    "level": "error",
                    "suppressions": [],
                    "message": [
                      {
                        "context": "var existingError: number = true;",
                        "descr": "boolean",
                        "type": "Blame",
                        "loc": {
                          "source": "existingError.js",
                          "type": "SourceFile",
                          "start": {
                            "line": 1,
                            "column": 29,
                            "offset": 28
                          },
                          "end": {
                            "line": 1,
                            "column": 32,
                            "offset": 32
                          }
                        },
                        "path": "existingError.js",
                        "line": 1,
                        "endline": 1,
                        "start": 29,
                        "end": 32
                      },
                      {
                        "context": null,
                        "descr": "This type is incompatible with",
                        "type": "Comment",
                        "path": "",
                        "line": 0,
                        "endline": 0,
                        "start": 1,
                        "end": 0
                      },
                      {
                        "context": "var existingError: number = true;",
                        "descr": "number",
                        "type": "Blame",
                        "loc": {
                          "source": "existingError.js",
                          "type": "SourceFile",
                          "start": {
                            "line": 1,
                            "column": 20,
                            "offset": 19
                          },
                          "end": {
                            "line": 1,
                            "column": 25,
                            "offset": 25
                          }
                        },
                        "path": "existingError.js",
                        "line": 1,
                        "endline": 1,
                        "start": 20,
                        "end": 25
                      }
                    ]
                  }
                ],
                "passed": false
              }
            ]
          },
          {
            "method": "startRecheck",
            "params": []
          },
          {
            "method": "diagnosticsNotification",
            "params": [
              {
                "flowVersion": "<VERSION STUBBED FOR TEST>",
                "errors": [],
                "passed": true
              }
            ]
          },
          {
            "method": "endRecheck",
            "params": []
          },
          {
            "method": "diagnosticsNotification",
            "params": [
              {
                "flowVersion": "<VERSION STUBBED FOR TEST>",
                "errors": [
                  {
                    "kind": "infer",
                    "level": "error",
                    "suppressions": [],
                    "message": [
                      {
                        "context": "var existingError: number = true;",
                        "descr": "boolean",
                        "type": "Blame",
                        "loc": {
                          "source": "existingError.js",
                          "type": "SourceFile",
                          "start": {
                            "line": 1,
                            "column": 29,
                            "offset": 28
                          },
                          "end": {
                            "line": 1,
                            "column": 32,
                            "offset": 32
                          }
                        },
                        "path": "existingError.js",
                        "line": 1,
                        "endline": 1,
                        "start": 29,
                        "end": 32
                      },
                      {
                        "context": null,
                        "descr": "This type is incompatible with",
                        "type": "Comment",
                        "path": "",
                        "line": 0,
                        "endline": 0,
                        "start": 1,
                        "end": 0
                      },
                      {
                        "context": "var existingError: number = true;",
                        "descr": "number",
                        "type": "Blame",
                        "loc": {
                          "source": "existingError.js",
                          "type": "SourceFile",
                          "start": {
                            "line": 1,
                            "column": 20,
                            "offset": 19
                          },
                          "end": {
                            "line": 1,
                            "column": 25,
                            "offset": 25
                          }
                        },
                        "path": "existingError.js",
                        "line": 1,
                        "endline": 1,
                        "start": 20,
                        "end": 25
                      }
                    ]
                  }
                ],
                "passed": false
              }
            ]
          }
        ],
      ).because('No errors should be streamed during the recheck'),
    addCode('var newError: string = 123;')
      .ideNewMessagesWithTimeout(
        5000,
        [
          {
            "method": "startRecheck",
            "params": []
          },
          {
            "method": "diagnosticsNotification",
            "params": [
              {
                "flowVersion": "<VERSION STUBBED FOR TEST>",
                "errors": [],
                "passed": true
              }
            ]
          },
          {
            "method": "diagnosticsNotification",
            "params": [
              {
                "flowVersion": "<VERSION STUBBED FOR TEST>",
                "errors": [
                  {
                    "kind": "infer",
                    "level": "error",
                    "suppressions": [],
                    "message": [
                      {
                        "context": "var newError: string = 123;",
                        "descr": "number",
                        "type": "Blame",
                        "loc": {
                          "source": "test.js",
                          "type": "SourceFile",
                          "start": {
                            "line": 5,
                            "column": 24,
                            "offset": 67
                          },
                          "end": {
                            "line": 5,
                            "column": 26,
                            "offset": 70
                          }
                        },
                        "path": "test.js",
                        "line": 5,
                        "endline": 5,
                        "start": 24,
                        "end": 26
                      },
                      {
                        "context": null,
                        "descr": "This type is incompatible with",
                        "type": "Comment",
                        "path": "",
                        "line": 0,
                        "endline": 0,
                        "start": 1,
                        "end": 0
                      },
                      {
                        "context": "var newError: string = 123;",
                        "descr": "string",
                        "type": "Blame",
                        "loc": {
                          "source": "test.js",
                          "type": "SourceFile",
                          "start": {
                            "line": 5,
                            "column": 15,
                            "offset": 58
                          },
                          "end": {
                            "line": 5,
                            "column": 20,
                            "offset": 64
                          }
                        },
                        "path": "test.js",
                        "line": 5,
                        "endline": 5,
                        "start": 15,
                        "end": 20
                      }
                    ]
                  }
                ],
                "passed": false
              }
            ]
          },
          {
            "method": "endRecheck",
            "params": []
          },
          {
            "method": "diagnosticsNotification",
            "params": [
              {
                "flowVersion": "<VERSION STUBBED FOR TEST>",
                "errors": [
                  {
                    "kind": "infer",
                    "level": "error",
                    "suppressions": [],
                    "message": [
                      {
                        "context": "var existingError: number = true;",
                        "descr": "boolean",
                        "type": "Blame",
                        "loc": {
                          "source": "existingError.js",
                          "type": "SourceFile",
                          "start": {
                            "line": 1,
                            "column": 29,
                            "offset": 28
                          },
                          "end": {
                            "line": 1,
                            "column": 32,
                            "offset": 32
                          }
                        },
                        "path": "existingError.js",
                        "line": 1,
                        "endline": 1,
                        "start": 29,
                        "end": 32
                      },
                      {
                        "context": null,
                        "descr": "This type is incompatible with",
                        "type": "Comment",
                        "path": "",
                        "line": 0,
                        "endline": 0,
                        "start": 1,
                        "end": 0
                      },
                      {
                        "context": "var existingError: number = true;",
                        "descr": "number",
                        "type": "Blame",
                        "loc": {
                          "source": "existingError.js",
                          "type": "SourceFile",
                          "start": {
                            "line": 1,
                            "column": 20,
                            "offset": 19
                          },
                          "end": {
                            "line": 1,
                            "column": 25,
                            "offset": 25
                          }
                        },
                        "path": "existingError.js",
                        "line": 1,
                        "endline": 1,
                        "start": 20,
                        "end": 25
                      }
                    ]
                  },
                  {
                    "kind": "infer",
                    "level": "error",
                    "suppressions": [],
                    "message": [
                      {
                        "context": "var newError: string = 123;",
                        "descr": "number",
                        "type": "Blame",
                        "loc": {
                          "source": "test.js",
                          "type": "SourceFile",
                          "start": {
                            "line": 5,
                            "column": 24,
                            "offset": 67
                          },
                          "end": {
                            "line": 5,
                            "column": 26,
                            "offset": 70
                          }
                        },
                        "path": "test.js",
                        "line": 5,
                        "endline": 5,
                        "start": 24,
                        "end": 26
                      },
                      {
                        "context": null,
                        "descr": "This type is incompatible with",
                        "type": "Comment",
                        "path": "",
                        "line": 0,
                        "endline": 0,
                        "start": 1,
                        "end": 0
                      },
                      {
                        "context": "var newError: string = 123;",
                        "descr": "string",
                        "type": "Blame",
                        "loc": {
                          "source": "test.js",
                          "type": "SourceFile",
                          "start": {
                            "line": 5,
                            "column": 15,
                            "offset": 58
                          },
                          "end": {
                            "line": 5,
                            "column": 20,
                            "offset": 64
                          }
                        },
                        "path": "test.js",
                        "line": 5,
                        "endline": 5,
                        "start": 15,
                        "end": 20
                      }
                    ]
                  }
                ],
                "passed": false
              }
            ]
          },
          {
            "method": "startRecheck",
            "params": []
          },
          {
            "method": "diagnosticsNotification",
            "params": [
              {
                "flowVersion": "<VERSION STUBBED FOR TEST>",
                "errors": [],
                "passed": true
              }
            ]
          },
          {
            "method": "endRecheck",
            "params": []
          },
          {
            "method": "diagnosticsNotification",
            "params": [
              {
                "flowVersion": "<VERSION STUBBED FOR TEST>",
                "errors": [
                  {
                    "kind": "infer",
                    "level": "error",
                    "suppressions": [],
                    "message": [
                      {
                        "context": "var existingError: number = true;",
                        "descr": "boolean",
                        "type": "Blame",
                        "loc": {
                          "source": "existingError.js",
                          "type": "SourceFile",
                          "start": {
                            "line": 1,
                            "column": 29,
                            "offset": 28
                          },
                          "end": {
                            "line": 1,
                            "column": 32,
                            "offset": 32
                          }
                        },
                        "path": "existingError.js",
                        "line": 1,
                        "endline": 1,
                        "start": 29,
                        "end": 32
                      },
                      {
                        "context": null,
                        "descr": "This type is incompatible with",
                        "type": "Comment",
                        "path": "",
                        "line": 0,
                        "endline": 0,
                        "start": 1,
                        "end": 0
                      },
                      {
                        "context": "var existingError: number = true;",
                        "descr": "number",
                        "type": "Blame",
                        "loc": {
                          "source": "existingError.js",
                          "type": "SourceFile",
                          "start": {
                            "line": 1,
                            "column": 20,
                            "offset": 19
                          },
                          "end": {
                            "line": 1,
                            "column": 25,
                            "offset": 25
                          }
                        },
                        "path": "existingError.js",
                        "line": 1,
                        "endline": 1,
                        "start": 20,
                        "end": 25
                      }
                    ]
                  },
                  {
                    "kind": "infer",
                    "level": "error",
                    "suppressions": [],
                    "message": [
                      {
                        "context": "var newError: string = 123;",
                        "descr": "number",
                        "type": "Blame",
                        "loc": {
                          "source": "test.js",
                          "type": "SourceFile",
                          "start": {
                            "line": 5,
                            "column": 24,
                            "offset": 67
                          },
                          "end": {
                            "line": 5,
                            "column": 26,
                            "offset": 70
                          }
                        },
                        "path": "test.js",
                        "line": 5,
                        "endline": 5,
                        "start": 24,
                        "end": 26
                      },
                      {
                        "context": null,
                        "descr": "This type is incompatible with",
                        "type": "Comment",
                        "path": "",
                        "line": 0,
                        "endline": 0,
                        "start": 1,
                        "end": 0
                      },
                      {
                        "context": "var newError: string = 123;",
                        "descr": "string",
                        "type": "Blame",
                        "loc": {
                          "source": "test.js",
                          "type": "SourceFile",
                          "start": {
                            "line": 5,
                            "column": 15,
                            "offset": 58
                          },
                          "end": {
                            "line": 5,
                            "column": 20,
                            "offset": 64
                          }
                        },
                        "path": "test.js",
                        "line": 5,
                        "endline": 5,
                        "start": 15,
                        "end": 20
                      }
                    ]
                  }
                ],
                "passed": false
              }
            ]
          }
        ],
      )
      .because(
        'We get startRecheck when recheck starts and endRecheck when it ends.'
        + ' During recheck, we get incremental results.'
        + ' After recheck, we get total results.'
      ),
  ]),

  test('autocomplete', [
    ideStart(),
    ideRequest('autocomplete', 'test.js', 1, 12, "({x: 123}).;")
      .ideNewMessagesWithTimeout(
        5000,
        [
          {
            "result": [
              {
                "name": "x",
                "type": "number",
                "func_details": null,
                "path": "test.js",
                "line": 1,
                "endline": 1,
                "start": 6,
                "end": 8
              }
            ]
          }
        ],
      ),
  ]),
]);
<|endoftext|>


<commit_before>var util = require('../util');
var _ = require('lodash');

exports.get = (userData, apiService, definitionService, cityResourcesService, cityMapService, otherPlayerService) => {
	const serviceName = 'GreatBuildingsService';
	const wls = util.writeLogService(userData);

	wls.writeLog(`Tworzę usługę ${serviceName}`);

	var spendSpForGb = function(bldList) {
		var amountToSpend = 1;
		if (cityResourcesService.isPossibleToSpendSp()) {
			var gb = _(bldList).filter(o => {
				return o.type === 'greatbuilding' && o.state && (o.state.invested_forge_points || 0) < o.state.forge_points_for_level_up;
			}).orderBy(o => o.level || 0).first();
			if (gb) {
				const bd = definitionService.findBuildingDefinition(gb.cityentity_id);
				const player = otherPlayerService.findPlayer(gb.player_id);
				wls.writeLog(`Wydawanie ${amountToSpend} punktu(ów) na perłę architektury ${bd.name} gracza ${player.name}`);
				return apiService.doServerRequest(serviceName, [gb.id, gb.player_id, gb.level, amountToSpend], 'spendForgePoints');
			}
		}
		return util.getEmptyPromise(null);
	};

	var lastSpendSpForFriends = {};
	var processSpendSpForFriends = function() {
		util.intervalPromiseGuard(lastSpendSpForFriends, 180, () => {
			if (!cityResourcesService.isPossibleToSpendSp()) {
				return util.getEmptyPromise({});
			}

			var guildMemberList = _.filter(otherPlayerService.getNeighborList(), n => n.is_guild_member && n.player_id !== userData.playerId);
			if (guildMemberList.length) {
				var randomIndex = _.random(0, guildMemberList.length - 1);
				var gm = guildMemberList[randomIndex];
				wls.writeLog(`Znaleziono członka gildii ${gm.name}`);
				return otherPlayerService.visitPlayer(gm.player_id).then(rd => spendSpForGb(rd.city_map.entities));
			}
			return util.getEmptyPromise({});
		});
	};

	return {
		handleResponse: () => {

		},
		getServiceName: () => serviceName,
		process: () => {
			return spendSpForGb(cityMapService.getBuildingList()).then(processSpendSpForFriends);
		},
		spendSpForGb
	};
};
<commit_msg>Fixed spending SP for 0-level great buildings<commit_after>var util = require('../util');
var _ = require('lodash');

exports.get = (userData, apiService, definitionService, cityResourcesService, cityMapService, otherPlayerService) => {
	const serviceName = 'GreatBuildingsService';
	const wls = util.writeLogService(userData);

	wls.writeLog(`Tworzę usługę ${serviceName}`);

	var spendSpForGb = function(bldList) {
		var amountToSpend = 1;
		if (cityResourcesService.isPossibleToSpendSp()) {
			var gb = _(bldList).filter(o => {
				return o.type === 'greatbuilding' && o.state && (o.state.invested_forge_points || 0) < o.state.forge_points_for_level_up;
			}).orderBy(o => o.level || 0).first();
			if (gb) {
				const bd = definitionService.findBuildingDefinition(gb.cityentity_id);
				const player = otherPlayerService.findPlayer(gb.player_id);
				wls.writeLog(`Wydawanie ${amountToSpend} punktu(ów) na perłę architektury ${bd.name} gracza ${player.name}`);
				return apiService.doServerRequest(serviceName, [gb.id, gb.player_id, gb.level || 0, amountToSpend], 'spendForgePoints');
			}
		}
		return util.getEmptyPromise(null);
	};

	var lastSpendSpForFriends = {};
	var processSpendSpForFriends = function() {
		util.intervalPromiseGuard(lastSpendSpForFriends, 180, () => {
			if (!cityResourcesService.isPossibleToSpendSp()) {
				return util.getEmptyPromise({});
			}

			var guildMemberList = _.filter(otherPlayerService.getNeighborList(), n => n.is_guild_member && n.player_id !== userData.playerId);
			if (guildMemberList.length) {
				var randomIndex = _.random(0, guildMemberList.length - 1);
				var gm = guildMemberList[randomIndex];
				wls.writeLog(`Znaleziono członka gildii ${gm.name}`);
				return otherPlayerService.visitPlayer(gm.player_id).then(rd => spendSpForGb(rd.city_map.entities));
			}
			return util.getEmptyPromise({});
		});
	};

	return {
		handleResponse: () => {

		},
		getServiceName: () => serviceName,
		process: () => {
			return spendSpForGb(cityMapService.getBuildingList()).then(processSpendSpForFriends);
		},
		spendSpForGb
	};
};
<|endoftext|>


<commit_before>'use strict';

angular.module('confRegistrationWebApp')
  .controller('eventDetailsCtrl', function ($rootScope, $scope, $http, $sce, $timeout, $window, modalMessage, $filter, $location, conference, ConfCache, permissions, permissionConstants, uuid) {
    $rootScope.globalPage = {
      type: 'admin',
      mainClass: 'container event-details',
      bodyClass: '',
      title: conference.name,
      confId: conference.id,
      footer: true
    };
    if (permissions.permissionInt >= permissionConstants.UPDATE) {
      $scope.templateUrl = 'views/eventDetails.html';
    } else {
      $scope.templateUrl = 'views/permissionError.html';
    }

    $scope.tabs = [
      {id: 'eventInfo', name: 'Event Information', view: 'views/eventDetails/eventInformation.html'},
      {id: 'regOptions', name: 'Registration Options', view: 'views/eventDetails/regOptions.html'},
      {id: 'regTypes', name: 'Registration Types', view: 'views/eventDetails/regTypes.html'},
      {id: 'paymentOptions', name: 'Payment Options', view: 'views/eventDetails/paymentOptions.html'},
      {id: 'contactInfo', name: 'Contact Information', view: 'views/eventDetails/contactInfo.html'}
    ];

    $scope.changeTab = function(tab){
      $scope.activeTab = tab;
    };
    $scope.changeTab($scope.tabs[0]);

    $scope.paymentGateways = [
      {id: 'AUTHORIZE_NET', name: 'Authorize.Net'}
    ];

    $scope.conference = angular.copy(conference);

    $scope.$on('$locationChangeStart', function(event, newLocation) {
      if(!angular.equals(conference, $scope.conference)){
        event.preventDefault();
        modalMessage.confirm({
          title: 'Warning',
          question: 'You have some unsaved changes on this page, are you sure you want to leave? Your changes will be lost.',
          normalSize: true
        }).then(function(){
          conference = angular.copy($scope.conference);
          $location.url($location.url(newLocation).hash());
        });
      }
    });

    $scope.addRegType = function(){
      $scope.conference.registrantTypes.push({
        id: uuid(),
        cost: 0,
        earlyRegistrationCutoff: moment().add(7, 'days').format('YYYY-MM-DD HH:mm:ss')
      });
    };

    $scope.deleteRegType = function(id){
      if ($scope.conference.registrantTypes.length > 1) {
        _.remove($scope.conference.registrantTypes, function(type) { return type.id === id; });
      } else {
        $scope.notify = {
          class: 'alert-danger',
          message: $sce.trustAsHtml('You must have at least one registration type per event.')
        };
        $timeout(function() { $scope.notify = {}; }, 3500);
      }
    };

    $scope.saveEvent = function () {
      //validation check
      var validationErrors = [];

      //Event Name
      if (_.isEmpty($scope.conference.name)) {
        validationErrors.push('Please enter an event name.');
      }

      //Event Dates
      if ($scope.conference.eventStartTime > $scope.conference.eventEndTime) {
        validationErrors.push('Event end date/time must be after event start date/time.');
      }

      //Registration Window
      if ($scope.conference.registrationStartTime > $scope.conference.registrationEndTime) {
        validationErrors.push('Registration end date/time must be after registration start date/time.');
      }

      //Registrant Name
      angular.forEach($scope.conference.registrantTypes, function(t) {
        if (_.isEmpty(t.name)) {
          validationErrors.push('Please enter a name for all registration types.');
        }
      });

      //Event Cost
      angular.forEach($scope.conference.registrantTypes, function(t) {
        t.cost = Number(t.cost);
        if ( _.isNaN(t.cost) || t.cost < 0) {
          validationErrors.push('Event cost for \'' + t.name + '\' must be a positive number.');
        }
      });

      //Credit cards
      if (_.isEmpty($scope.conference.paymentGatewayId) && _.some($scope.conference.registrantTypes, 'acceptCreditCards')) {
        validationErrors.push('Please enter a credit card Account ID.');
      }

      //Minimum Deposit
      angular.forEach($scope.conference.registrantTypes, function(t) {
        if ($scope.conference.requireLogin && $scope.anyPaymentMethodAccepted(t) && String(t.minimumDeposit).length > 0 && !_.isNull(t.minimumDeposit)) {
          t.minimumDeposit = Number(t.minimumDeposit);
          if (t.minimumDeposit > t.cost) {
            validationErrors.push('The minimum deposit for \'' + t.name + '\' must be less than the cost.');
          }
        } else {
          t.minimumDeposit = null;
        }
      });

      //Early bird discount
      angular.forEach($scope.conference.registrantTypes, function(t) {
        angular.forEach(t.earlyRegistrationDiscounts, function(d, index){
          if (d.enabled) {
            d.amountOfDiscount = Number(d.amountOfDiscount);
            if (d.amountOfDiscount < 0) {
              validationErrors.push('Early registration discount ' + (index + 1) + ' for \'' + t.name + '\' must be a positive number.');
            }
            if (!d.deadline) {
              validationErrors.push('Early registration discount ' + (index + 1) + ' for \'' + t.name + '\' must include a valid date and time.');
            }
          }
        });
      });

      $window.scrollTo(0, 0);
      if (validationErrors.length > 0) {
        var errorMsg = 'Error! Please fix the following issues:
';
        angular.forEach(validationErrors, function (e) {
          errorMsg = errorMsg + '
' + e + '
';
        });
        errorMsg = errorMsg + '
';
        $scope.notify = {
          class: 'alert-danger',
          message: $sce.trustAsHtml(errorMsg)
        };
      } else {
        $scope.notify = {
          class: 'alert-warning',
          message: $sce.trustAsHtml('Saving...')
        };

        $http(
          {method: 'PUT',
            url: 'conferences/' + conference.id,
            data: $scope.conference
        }).success(function () {
            $scope.notify = {
              class: 'alert-success',
              message: $sce.trustAsHtml('Saved! Your event details have been updated.')
            };

            conference = angular.copy($scope.conference);
            //Clear cache
            ConfCache.empty();
          }).error(function (data) {
            $scope.notify = {
              class: 'alert-danger',
              message: $sce.trustAsHtml('Error ' + data.errorMessage)
            };
          });
      }
    };

    $scope.anyPaymentMethodAccepted = function(type){
      return type.acceptCreditCards || type.acceptChecks || type.acceptTransfers || type.acceptScholarships;
    };

    $scope.acceptedPaymentMethods = function(){
      var regTypes = $scope.conference.registrantTypes;

      var paymentMethods = {
        acceptCreditCards: _.some(regTypes, 'acceptCreditCards'),
        acceptChecks:_.some(regTypes, 'acceptChecks'),
        acceptTransfers: _.some(regTypes, 'acceptTransfers'),
        acceptScholarships: _.some(regTypes, 'acceptScholarships')
      };
      return paymentMethods;
    };

    $scope.previewEmail = function(reg){
      var cost = $filter('currency')(reg.cost, '$');
      var eventStartTime = moment(conference.eventStartTime).format('dddd, MMMM D YYYY, h:mm a');
      var eventEndTime = moment(conference.eventEndTime).format('dddd, MMMM D YYYY, h:mm a');
      modalMessage.info({
        'title': 'Email Preview',
        'message': '
Hello ' + $rootScope.globalGreetingName + '!

You are registered for ' + $scope.conference.name + '.
' +
        '
Start Time: ' + eventStartTime + '
End Time: ' + eventEndTime + '
' +
        '
Total Cost: ' + cost + '
Total Amount Paid: ' + cost + '
Remaining Balance: $0.00
' +
        reg.customConfirmationEmailText,
        'okString': 'Close'
      });
    };
  });
<commit_msg>button caption<commit_after>'use strict';

angular.module('confRegistrationWebApp')
  .controller('eventDetailsCtrl', function ($rootScope, $scope, $http, $sce, $timeout, $window, modalMessage, $filter, $location, conference, ConfCache, permissions, permissionConstants, uuid) {
    $rootScope.globalPage = {
      type: 'admin',
      mainClass: 'container event-details',
      bodyClass: '',
      title: conference.name,
      confId: conference.id,
      footer: true
    };
    if (permissions.permissionInt >= permissionConstants.UPDATE) {
      $scope.templateUrl = 'views/eventDetails.html';
    } else {
      $scope.templateUrl = 'views/permissionError.html';
    }

    $scope.tabs = [
      {id: 'eventInfo', name: 'Event Information', view: 'views/eventDetails/eventInformation.html'},
      {id: 'regOptions', name: 'Registration Options', view: 'views/eventDetails/regOptions.html'},
      {id: 'regTypes', name: 'Registration Types', view: 'views/eventDetails/regTypes.html'},
      {id: 'paymentOptions', name: 'Payment Options', view: 'views/eventDetails/paymentOptions.html'},
      {id: 'contactInfo', name: 'Contact Information', view: 'views/eventDetails/contactInfo.html'}
    ];

    $scope.changeTab = function(tab){
      $scope.activeTab = tab;
    };
    $scope.changeTab($scope.tabs[0]);

    $scope.paymentGateways = [
      {id: 'AUTHORIZE_NET', name: 'Authorize.Net'}
    ];

    $scope.conference = angular.copy(conference);

    $scope.$on('$locationChangeStart', function(event, newLocation) {
      if(!angular.equals(conference, $scope.conference)){
        event.preventDefault();
        modalMessage.confirm({
          title: 'Warning: Unsaved Changes',
          question: 'You have some unsaved changes on this page, are you sure you want to leave? Your changes will be lost.',
          yesString: 'Discard changes',
          noString: 'Stay on this page',
          normalSize: true
        }).then(function(){
          conference = angular.copy($scope.conference);
          $location.url($location.url(newLocation).hash());
        });
      }
    });

    $scope.addRegType = function(){
      $scope.conference.registrantTypes.push({
        id: uuid(),
        cost: 0,
        earlyRegistrationCutoff: moment().add(7, 'days').format('YYYY-MM-DD HH:mm:ss')
      });
    };

    $scope.deleteRegType = function(id){
      if ($scope.conference.registrantTypes.length > 1) {
        _.remove($scope.conference.registrantTypes, function(type) { return type.id === id; });
      } else {
        $scope.notify = {
          class: 'alert-danger',
          message: $sce.trustAsHtml('You must have at least one registration type per event.')
        };
        $timeout(function() { $scope.notify = {}; }, 3500);
      }
    };

    $scope.saveEvent = function () {
      //validation check
      var validationErrors = [];

      //Event Name
      if (_.isEmpty($scope.conference.name)) {
        validationErrors.push('Please enter an event name.');
      }

      //Event Dates
      if ($scope.conference.eventStartTime > $scope.conference.eventEndTime) {
        validationErrors.push('Event end date/time must be after event start date/time.');
      }

      //Registration Window
      if ($scope.conference.registrationStartTime > $scope.conference.registrationEndTime) {
        validationErrors.push('Registration end date/time must be after registration start date/time.');
      }

      //Registrant Name
      angular.forEach($scope.conference.registrantTypes, function(t) {
        if (_.isEmpty(t.name)) {
          validationErrors.push('Please enter a name for all registration types.');
        }
      });

      //Event Cost
      angular.forEach($scope.conference.registrantTypes, function(t) {
        t.cost = Number(t.cost);
        if ( _.isNaN(t.cost) || t.cost < 0) {
          validationErrors.push('Event cost for \'' + t.name + '\' must be a positive number.');
        }
      });

      //Credit cards
      if (_.isEmpty($scope.conference.paymentGatewayId) && _.some($scope.conference.registrantTypes, 'acceptCreditCards')) {
        validationErrors.push('Please enter a credit card Account ID.');
      }

      //Minimum Deposit
      angular.forEach($scope.conference.registrantTypes, function(t) {
        if ($scope.conference.requireLogin && $scope.anyPaymentMethodAccepted(t) && String(t.minimumDeposit).length > 0 && !_.isNull(t.minimumDeposit)) {
          t.minimumDeposit = Number(t.minimumDeposit);
          if (t.minimumDeposit > t.cost) {
            validationErrors.push('The minimum deposit for \'' + t.name + '\' must be less than the cost.');
          }
        } else {
          t.minimumDeposit = null;
        }
      });

      //Early bird discount
      angular.forEach($scope.conference.registrantTypes, function(t) {
        angular.forEach(t.earlyRegistrationDiscounts, function(d, index){
          if (d.enabled) {
            d.amountOfDiscount = Number(d.amountOfDiscount);
            if (d.amountOfDiscount < 0) {
              validationErrors.push('Early registration discount ' + (index + 1) + ' for \'' + t.name + '\' must be a positive number.');
            }
            if (!d.deadline) {
              validationErrors.push('Early registration discount ' + (index + 1) + ' for \'' + t.name + '\' must include a valid date and time.');
            }
          }
        });
      });

      $window.scrollTo(0, 0);
      if (validationErrors.length > 0) {
        var errorMsg = 'Error! Please fix the following issues:
';
        angular.forEach(validationErrors, function (e) {
          errorMsg = errorMsg + '
' + e + '
';
        });
        errorMsg = errorMsg + '
';
        $scope.notify = {
          class: 'alert-danger',
          message: $sce.trustAsHtml(errorMsg)
        };
      } else {
        $scope.notify = {
          class: 'alert-warning',
          message: $sce.trustAsHtml('Saving...')
        };

        $http(
          {method: 'PUT',
            url: 'conferences/' + conference.id,
            data: $scope.conference
        }).success(function () {
            $scope.notify = {
              class: 'alert-success',
              message: $sce.trustAsHtml('Saved! Your event details have been updated.')
            };

            conference = angular.copy($scope.conference);
            //Clear cache
            ConfCache.empty();
          }).error(function (data) {
            $scope.notify = {
              class: 'alert-danger',
              message: $sce.trustAsHtml('Error ' + data.errorMessage)
            };
          });
      }
    };

    $scope.anyPaymentMethodAccepted = function(type){
      return type.acceptCreditCards || type.acceptChecks || type.acceptTransfers || type.acceptScholarships;
    };

    $scope.acceptedPaymentMethods = function(){
      var regTypes = $scope.conference.registrantTypes;

      var paymentMethods = {
        acceptCreditCards: _.some(regTypes, 'acceptCreditCards'),
        acceptChecks:_.some(regTypes, 'acceptChecks'),
        acceptTransfers: _.some(regTypes, 'acceptTransfers'),
        acceptScholarships: _.some(regTypes, 'acceptScholarships')
      };
      return paymentMethods;
    };

    $scope.previewEmail = function(reg){
      var cost = $filter('currency')(reg.cost, '$');
      var eventStartTime = moment(conference.eventStartTime).format('dddd, MMMM D YYYY, h:mm a');
      var eventEndTime = moment(conference.eventEndTime).format('dddd, MMMM D YYYY, h:mm a');
      modalMessage.info({
        'title': 'Email Preview',
        'message': '
Hello ' + $rootScope.globalGreetingName + '!

You are registered for ' + $scope.conference.name + '.
' +
        '
Start Time: ' + eventStartTime + '
End Time: ' + eventEndTime + '
' +
        '
Total Cost: ' + cost + '
Total Amount Paid: ' + cost + '
Remaining Balance: $0.00
' +
        reg.customConfirmationEmailText,
        'okString': 'Close'
      });
    };
  });
<|endoftext|>


<commit_before>var express = require('express');
var router = express.Router();
var jwt = require('jwt-simple');
var db = require('./../database/db.js');
var moment = require('moment');

var tokenVerification = require('./../middlewares/tokenVerification');

/* GET home page. */
router.post('/login', function(req, res, next) {

    var user =  db.findByUserName(req.body.username);

    if (!user) {
        // incorrect username
        return res.status(401).send('invalid credentials');
    }

    if (!user.password === req.body.password) {
        // incorrect password
        return res.status(401).send('invalid credentials');
    }

    var expires = moment().add(15, 'minutes').valueOf();
    var token = jwt.encode({
        iss: user.id,
        exp: expires
    }, 'F7CA77BE-622C-4CA5-8540-361A3E3CE1A7');

    res.json({
        token : token,
        expires: expires,
        username: user.username
    });
});

module.exports = router;
<commit_msg>added action<commit_after>var express = require('express');
var router = express.Router();
var jwt = require('jwt-simple');
var db = require('./../database/db.js');
var moment = require('moment');

var tokenVerification = require('./../middlewares/tokenVerification');

/* GET home page. */
router.post('/login', function(req, res, next) {

    var user =  db.findByUserName(req.body.username);

    if (!user) {
        // incorrect username
        return res.status(401).send('invalid credentials');
    }

    if (!user.password === req.body.password) {
        // incorrect password
        return res.status(401).send('invalid credentials');
    }

    var expires = moment().add(15, 'minutes').valueOf();
    var token = jwt.encode({
        iss: user.id,
        exp: expires
    }, 'F7CA77BE-622C-4CA5-8540-361A3E3CE1A7');

    res.json({
        token : token,
        expires: expires,
        username: user.username
    });
});

router.post('/logout', function(req, res, next) {
    //get token
    //change expiration date
    //return expired token

    res.json({
        token : undefined,
        expires: undefined,
        username: undefined
    });
});

module.exports = router;
<|endoftext|>


<commit_before>/* jshint esversion: 6 */
/* jshint node: true */
'use strict';

var q = require('q');
var HubsConfig = require("./hubsConfig");
var OpenT2TError = require('opent2t').OpenT2TError;
var OpenT2TConstants = require('opent2t').OpenT2TConstants;
var OpenT2T = require('opent2t').OpenT2T;

class HubController {

    constructor() {
        this.supportedHubsCache = undefined;
    }

    /**
     * returns the list of supported hubs
     * format is as follows:
     * [
     *   {
     *     id: "hubId",
     *     name: hubName",
     *     translator: "name of hub translator",
     *     onboarding: "name of hub onboarding",
     *     // this is the onboardingFlow object as defined by the hub's manifest.xml'
     *     onboardingFlow: {}
     *   }
     * ]
     */
    supportedHubs(logger, hubs, i) {
        // use cache if we have it
        if (this.supportedHubsCache !== undefined) {
            return q(this.supportedHubsCache);
        }

        // this is a recursive function, setup the initial call with initial values
        if (hubs === undefined) {
            hubs = HubsConfig.hubs;
        }

        if (i === undefined) {
            logger.verbose("supportedHubs()");
            i = 0;
        }

        // load info for the current hub
        var hubInfo = hubs[i];
        logger.verbose("i: " + i);

        var LocalPackageSourceClass = require('opent2t/package/LocalPackageSource').LocalPackageSource;
        var localPackageSource = new LocalPackageSourceClass("./node_modules/" + hubInfo.translator);

        return localPackageSource.getAllPackageInfoAsync().then((packages) => {

            // default use the first package
            var p = packages[0];
            if (p.translators.length > 0) {

                var tinfo = p.translators[0];
                logger.verbose("Package info: ", tinfo);
                hubInfo.onboarding = tinfo.onboarding;
                hubInfo.onboardingFlow = tinfo.onboardingFlow;
            }

            // we are done, save as the cache and return
            if (i == hubs.length - 1) {
                this.supportedHubsCache = hubs;
                return this.supportedHubsCache;
            }
            // we are not done, recurse to the next hub
            else {
                return this.supportedHubs(logger, hubs, i + 1);
            }
        }).catch((err) => {
            return this._handleError(err, "supportedHubs", logger);
        });
    }

    /**
     * given a specific hub info, does the onboarding given the onboardingInfo and returns the auth info
     */
    onboard(hubId, onboardingInfo, logger, flightInfo) {
        logger.verbose("onboard()");

        if (onboardingInfo) {
            onboardingInfo.flights = _getFlights(flightInfo);
        }

        return this._getHubInfo(hubId, logger).then((hubInfo) => {
            // do the onboarding and return token
            var Onboarding = require(hubInfo.onboarding);
            var onboarding = new Onboarding(logger);
            return onboarding.onboard(onboardingInfo);
        }).catch((err) => {
            return this._handleError(err, "onboard", logger);
        });
    }

    /**
     * Given a specific hub info, onboardingInfo, and existing authInfo blob,
     *  does the OAuthToken refresh, and returns the refreshed
     * auth info object back.
     */
    refreshAuthToken(hubId, onboardingInfo, existingAuthInfo, logger, flightInfo) {
        logger.verbose("refreshAuthToken()");
        let opent2t = new OpenT2T(logger);

        if (onboardingInfo) {
            onboardingInfo.flights = _getFlights(flightInfo);
        }

        return this._getHubInfo(hubId, logger).then((hubInfo) => {

            // create hub translator for given hubId
            return this._createTranslator(opent2t, hubInfo.translator, existingAuthInfo).then((hubInstance) => {

                // hub refreshAuthToken
                return this._invokeMethod(opent2t, hubInstance, "", "refreshAuthToken", [onboardingInfo]);
            });
        }).catch((err) => {
            return this._handleError(err, "refreshAuthToken", logger);
        });
    }

    /**
     * given the specific hub id, returns all the platforms which are connected to it
     */
    platforms(hubId, authInfo, logger, flightInfo) {
        logger.verbose("platforms()");

        if (authInfo) {
            authInfo.flights = _getFlights(flightInfo);
        }

        // will return hub getPlatform contents
        let opent2t = new OpenT2T(logger);
        return this._getHubInfo(hubId, logger).then((hubInfo) => {
            return this._createTranslator(opent2t, hubInfo.translator, authInfo).then((hubInstance) => {
                // hub get
                return this._invokeMethod(opent2t, hubInstance, authInfo, "getPlatforms", [true]);
            });
        }).catch((err) => {
            return this._handleError(err, "platforms", logger);
        });
    }

    /**
     * given the specific hub id and opent2tblob, returns the specific platform
     */
    getPlatform(hubId, authInfo, opent2tBlob, logger, flightInfo) {
        logger.verbose("getPlatform()");
        let opent2t = new OpenT2T(logger);

        if (authInfo) {
            authInfo.flights = _getFlights(flightInfo);
        }

        return this._getHubInfo(hubId, logger).then((hubInfo) => {
            return this._createTranslator(opent2t, hubInfo.translator, authInfo).then((hubInstance) => {
                // platform get
                var deviceInfo = {};
                deviceInfo.hub = hubInstance;
                deviceInfo.deviceInfo = {};
                deviceInfo.deviceInfo.opent2t = opent2tBlob;
                return this._invokeMethod(opent2t, opent2tBlob.translator, deviceInfo, "get", [true]);
            });
        }).catch((err) => {
            return this._handleError(err, "getPlatform", logger);
        });
    }

    /**
     * given the specific hub id, opent2tblob, and resourceId, sets it with the given resourceBlob
     */
    setResource(hubId, authInfo, opent2tBlob, deviceId, resoureceId, resourceBlob, logger, flightInfo) {
        logger.verbose("setResource()");
        let opent2t = new OpenT2T(logger);

        if (authInfo) {
            authInfo.flights = _getFlights(flightInfo);
        }

        return this._getHubInfo(hubId, logger).then((hubInfo) => {
            return this._createTranslator(opent2t, hubInfo.translator, authInfo).then((hubInstance) => {
                // resource set
                var deviceInfo = {};
                deviceInfo.hub = hubInstance;
                deviceInfo.deviceInfo = {};
                deviceInfo.deviceInfo.opent2t = opent2tBlob;

                var propertyName = "postDevices" + this._capitalizeFirstLetter(resoureceId);

                return this._setProperty(opent2t, opent2tBlob.translator, deviceInfo, propertyName, deviceId, resourceBlob);
            });
        }).catch((err) => {
            return this._handleError(err, "setResource", logger);
        });
    }

    /**
     * Subscribe to notifications for device graph updates (add/remove devices from a provider)
     */
    subscribeDeviceGraph(hubId, authInfo, subscriptionInfo, logger, flightInfo) {
        logger.verbose("subscribeDeviceGraph()");
        let opent2t = new OpenT2T(logger);

        if (authInfo) {
            authInfo.flights = _getFlights(flightInfo);
        }

        return this._getHubInfo(hubId, logger).then((hubInfo) => {
            return this._createTranslator(opent2t, hubInfo.translator, authInfo).then((hubInstance) => {
                return hubInstance.postSubscribe(subscriptionInfo);
            });
        });
    }

    /**
     * Subscribe for notifications on all resources composing a platform.  Notifications will be posted to to
     * the subscriptionInfo.callbackURL.
     */
    subscribePlatform(hubId, authInfo, opent2tBlob, subscriptionInfo, logger, flightInfo) {
        logger.verbose("subscribePlatform()");
        let opent2t = new OpenT2T(logger);

        if (authInfo) {
            authInfo.flights = _getFlights(flightInfo);
        }

        return this._getHubInfo(hubId, logger).then((hubInfo) => {
            return this._createTranslator(opent2t, hubInfo.translator, authInfo).then((hubInstance) => {

                var deviceInfo = {};
                deviceInfo.hub = hubInstance;
                deviceInfo.deviceInfo = {};
                deviceInfo.deviceInfo.opent2t = opent2tBlob;

                return this._createTranslator(opent2t, opent2tBlob.translator, deviceInfo).then(translator => {
                    return opent2t.invokeMethodAsync(translator, "", "postSubscribe", [subscriptionInfo]);
                });
            });
        }).catch((err) => {
            return this._handleError(err, "subscribePlatform", logger);
        });
    }

    /**
     * Unsubscribe notification on all resources from a platform.
     */
    unsubscribePlatform(hubId, authInfo, opent2tBlob, subscriptionInfo, logger, flightInfo) {
        logger.verbose("unsubscribePlatform()");
        let opent2t = new OpenT2T(logger);

        if (authInfo) {
            authInfo.flights = _getFlights(flightInfo);
        }

        return this._getHubInfo(hubId, logger).then((hubInfo) => {
            return this._createTranslator(opent2t, hubInfo.translator, authInfo).then((hubInstance) => {

                var deviceInfo = {};
                deviceInfo.hub = hubInstance;
                deviceInfo.deviceInfo = {};
                deviceInfo.deviceInfo.opent2t = opent2tBlob;

                return this._createTranslator(opent2t, opent2tBlob.translator, deviceInfo).then(translator => {
                    return opent2t.invokeMethodAsync(translator, "", "deleteSubscribe", [subscriptionInfo]);
                });
            });
        }).catch((err) => {
            return this._handleError(err, "unsubscribePlatform", logger);
        });
    }

    /**
     * Verification step for cloud notifications for providers that require it.
     */
    subscribeVerify(hubId, authInfo, verificationBlob, logger, flightInfo) {
        logger.verbose("subscribeVerify()");
        let opent2t = new OpenT2T(logger);

        if (authInfo) {
            authInfo.flights = _getFlights(flightInfo);
        }

        return this._getHubInfo(hubId, logger).then((hubInfo) => {
            return this._createTranslator(opent2t, hubInfo.translator, authInfo).then((hubInstance) => {

                var subscriptionInfo = {};
                subscriptionInfo.verificationRequest = verificationBlob;

                return opent2t.invokeMethodAsync(hubInstance, "", "postSubscribe", [subscriptionInfo]);
            });
        }).catch((err) => {
            return this._handleError(err, "subscribePlatformVerify", logger);
        });
    }

    /**
     * Translate a JSON blob from a provider into an opent2t/OCF schema.  This should be called with the contents of
     * the notification post backs.  Verification is an optional object providing a secret and a hash for verification of the payload.
     * Returns an array of translated platforms, even for a single item (size 1 obviously)
     *
     * @param {Object} verificationInfo
     * @param {string} verificationInfo.key - Secret key used to compute HMAC
     * @param {Object} verificationInfo.header - Headers from the notification which will contain a provider specific HMAC.
     */
    translatePlatforms(hubId, authInfo, providerBlob, verificationInfo, logger, flightInfo) {
        logger.verbose("translatePlatforms()");
        let opent2t = new OpenT2T(logger);

        if (authInfo) {
            authInfo.flights = _getFlights(flightInfo);
        }

        // Create a hub, of the requested type.
        return this._getHubInfo(hubId, logger).then((hubInfo) => {
            // Pass the provider blob off to the hub for translation.
            return this._createTranslator(opent2t, hubInfo.translator, authInfo).then((hubInstance) => {
                // The getPlatforms method on the hub can take either single providerSchema, or a list depending
                // on the service that provided the notification.  It's up the the hub to know what to do with the data.
                return opent2t.invokeMethodAsync(hubInstance, "", "getPlatforms", [true, providerBlob, verificationInfo]);
            });
        }).catch((err) => {
            return this._handleError(err, "translatePlatforms", logger);
        });
    }

    /**
     * helper methods
     */

    /**
     * Returns an array of strings
     *  If flightInfo is a string list (expected) "a,b" = ["a", "b"]
     *  If flightInfo is a primitive true = ["true"]
     *  If flight info is an type array [1, "b", null, undefined, [4, 5]] = ["1", "b", "4", "5"]
     *  If flight info is undefined = []
     *  If flight info is null = []
     */
    _getFlights(flightInfo) {
        return (flightInfo === undefined || flightInfo === null) ? [] :
            flightInfo.toString().split(",").filter(n => n.length > 0);
    }

    _getHubInfo(hubId, logger) {
        return this.supportedHubs(logger).then((hubs) => {
            // find the hub referenced by hubId
            var hubInfo = undefined;
            for (var i = 0; hubInfo === undefined && i < hubs.length; i++) {
                var hub = hubs[i];

                // intentional ==
                if (hub.id == hubId) {
                    hubInfo = hub;
                }
            }

            if (!hubInfo) {
                throw new OpenT2TError(404, OpenT2TConstants.InvalidHubId);
            }

            return hubInfo;
        });
    }

    _invokeMethod(opent2t, translator, deviceInfo, methodName, params) {
        if (typeof translator === "object") {
            return opent2t.invokeMethodAsync(translator, "", methodName, params);
        }
        else {
            return this._createTranslator(opent2t, translator, deviceInfo).then(translatorInstance => {
                return opent2t.invokeMethodAsync(translatorInstance, "", methodName, params);
            });
        }
    }

    _setProperty(opent2t, translatorName, deviceInfo, property, deviceId, value) {
        return this._createTranslator(opent2t, translatorName, deviceInfo).then(translator => {
            return opent2t.invokeMethodAsync(translator, "", property, [deviceId, value]);
        });
    }

    _capitalizeFirstLetter(string) {
        return string.charAt(0).toUpperCase() + string.slice(1);
    }

    _createTranslator(opent2t, translatorName, deviceInfo) {
        return opent2t.createTranslatorAsync(translatorName, deviceInfo).then(translator => {
            return translator;
        });
    }

    _handleError(err, message, logger) {
        let customMessage = `OpenT2T call failed in: ${message}; Original message: `;
        let customErrCode = 500;
        let innerError = undefined;

        try {
            if (err instanceof Error) {
                innerError = err;
                customErrCode = err.statusCode;

                // This was a result of a failed HTTP Request promise (Eg request-promise's HttpRequestError)
                // Can also check err.Name
                if ('response' in err && 'statusMessage' in err.response) {
                    customMessage = customMessage + err.response.statusMessage;
                }
                else {
                    // Likely a simple Error-derived class like OpenT2TError
                    customMessage = customMessage + err.message;
                }
            } else {
                // Likely a promise rejected (eg NEST translators) with message string only instead of Error
                // object
                customMessage = customMessage + err;
            }

            let customError = new OpenT2TError(customErrCode, customMessage, innerError);
            logger.error(`Returning error from hubController-
            Message: ${customError.message}; StatusCode: ${customError.statusCode}`);

            return q.reject(customError);
        }
        catch (unexpectedErr) {
            let unexpectedError = new OpenT2TError(customErrCode, customMessage, unexpectedErr);
            logger.error(`ErrorHandler in hubController ran into unexpected error-
            Message: ${unexpectedError.message}`);

            return q.reject(unexpectedError);
        }
    }
}

module.exports = HubController;
<commit_msg>Addressing PR comments<commit_after>/* jshint esversion: 6 */
/* jshint node: true */
'use strict';

var q = require('q');
var HubsConfig = require("./hubsConfig");
var OpenT2TError = require('opent2t').OpenT2TError;
var OpenT2TConstants = require('opent2t').OpenT2TConstants;
var OpenT2T = require('opent2t').OpenT2T;

class HubController {

    constructor() {
        this.supportedHubsCache = undefined;
    }

    /**
     * returns the list of supported hubs
     * format is as follows:
     * [
     *   {
     *     id: "hubId",
     *     name: hubName",
     *     translator: "name of hub translator",
     *     onboarding: "name of hub onboarding",
     *     // this is the onboardingFlow object as defined by the hub's manifest.xml'
     *     onboardingFlow: {}
     *   }
     * ]
     */
    supportedHubs(logger, hubs, i) {
        // use cache if we have it
        if (this.supportedHubsCache !== undefined) {
            return q(this.supportedHubsCache);
        }

        // this is a recursive function, setup the initial call with initial values
        if (hubs === undefined) {
            hubs = HubsConfig.hubs;
        }

        if (i === undefined) {
            logger.verbose("supportedHubs()");
            i = 0;
        }

        // load info for the current hub
        var hubInfo = hubs[i];
        logger.verbose("i: " + i);
        var LocalPackageSourceClass = require('opent2t/package/LocalPackageSource').LocalPackageSource;
        var localPackageSource = new LocalPackageSourceClass("./node_modules/" + hubInfo.translator);

        return localPackageSource.getAllPackageInfoAsync().then((packages) => {

            // default use the first package
            var p = packages[0];
            if (p.translators.length > 0) {

                var tinfo = p.translators[0];
                logger.verbose("Package info: ", tinfo);
                hubInfo.onboarding = tinfo.onboarding;
                hubInfo.onboardingFlow = tinfo.onboardingFlow;
            }

            // we are done, save as the cache and return
            if (i == hubs.length - 1) {
                this.supportedHubsCache = hubs;
                return this.supportedHubsCache;
            }
            // we are not done, recurse to the next hub
            else {
                return this.supportedHubs(logger, hubs, i + 1);
            }
        }).catch((err) => {
            return this._handleError(err, "supportedHubs", logger);
        });
    }

    /**
     * given a specific hub info, does the onboarding given the onboardingInfo and returns the auth info
     */
    onboard(hubId, onboardingInfo, logger, flightInfo) {
        logger.verbose("onboard()");

        if (onboardingInfo) {
            onboardingInfo.flights = _getFlights(flightInfo);
        }

        return this._getHubInfo(hubId, logger).then((hubInfo) => {
            // do the onboarding and return token
            var Onboarding = require(hubInfo.onboarding);
            var onboarding = new Onboarding(logger);
            return onboarding.onboard(onboardingInfo);
        }).catch((err) => {
            return this._handleError(err, "onboard", logger);
        });
    }

    /**
     * Given a specific hub info, onboardingInfo, and existing authInfo blob,
     *  does the OAuthToken refresh, and returns the refreshed
     * auth info object back.
     */
    refreshAuthToken(hubId, onboardingInfo, existingAuthInfo, logger, flightInfo) {
        logger.verbose("refreshAuthToken()");
        let opent2t = new OpenT2T(logger);

        if (onboardingInfo) {
            onboardingInfo.flights = _getFlights(flightInfo);
        }

        return this._getHubInfo(hubId, logger).then((hubInfo) => {

            // create hub translator for given hubId
            return this._createTranslator(opent2t, hubInfo.translator, existingAuthInfo).then((hubInstance) => {

                // hub refreshAuthToken
                return this._invokeMethod(opent2t, hubInstance, "", "refreshAuthToken", [onboardingInfo]);
            });
        }).catch((err) => {
            return this._handleError(err, "refreshAuthToken", logger);
        });
    }

    /**
     * given the specific hub id, returns all the platforms which are connected to it
     */
    platforms(hubId, authInfo, logger, flightInfo) {
        logger.verbose("platforms()");

        if (authInfo) {
            authInfo.flights = _getFlights(flightInfo);
        }

        // will return hub getPlatform contents
        let opent2t = new OpenT2T(logger);
        return this._getHubInfo(hubId, logger).then((hubInfo) => {
            return this._createTranslator(opent2t, hubInfo.translator, authInfo).then((hubInstance) => {
                // hub get
                return this._invokeMethod(opent2t, hubInstance, authInfo, "getPlatforms", [true]);
            });
        }).catch((err) => {
            return this._handleError(err, "platforms", logger);
        });
    }

    /**
     * given the specific hub id and opent2tblob, returns the specific platform
     */
    getPlatform(hubId, authInfo, opent2tBlob, logger, flightInfo) {
        logger.verbose("getPlatform()");
        let opent2t = new OpenT2T(logger);

        if (authInfo) {
            authInfo.flights = _getFlights(flightInfo);
        }

        return this._getHubInfo(hubId, logger).then((hubInfo) => {
            return this._createTranslator(opent2t, hubInfo.translator, authInfo).then((hubInstance) => {
                // platform get
                var deviceInfo = {};
                deviceInfo.hub = hubInstance;
                deviceInfo.deviceInfo = {};
                deviceInfo.deviceInfo.opent2t = opent2tBlob;
                return this._invokeMethod(opent2t, opent2tBlob.translator, deviceInfo, "get", [true]);
            });
        }).catch((err) => {
            return this._handleError(err, "getPlatform", logger);
        });
    }

    /**
     * given the specific hub id, opent2tblob, and resourceId, sets it with the given resourceBlob
     */
    setResource(hubId, authInfo, opent2tBlob, deviceId, resoureceId, resourceBlob, logger, flightInfo) {
        logger.verbose("setResource()");
        let opent2t = new OpenT2T(logger);

        if (authInfo) {
            authInfo.flights = _getFlights(flightInfo);
        }

        return this._getHubInfo(hubId, logger).then((hubInfo) => {
            return this._createTranslator(opent2t, hubInfo.translator, authInfo).then((hubInstance) => {
                // resource set
                var deviceInfo = {};
                deviceInfo.hub = hubInstance;
                deviceInfo.deviceInfo = {};
                deviceInfo.deviceInfo.opent2t = opent2tBlob;

                var propertyName = "postDevices" + this._capitalizeFirstLetter(resoureceId);

                return this._setProperty(opent2t, opent2tBlob.translator, deviceInfo, propertyName, deviceId, resourceBlob);
            });
        }).catch((err) => {
            return this._handleError(err, "setResource", logger);
        });
    }

    /**
     * Subscribe to notifications for device graph updates (add/remove devices from a provider)
     */
    subscribeDeviceGraph(hubId, authInfo, subscriptionInfo, logger, flightInfo) {
        logger.verbose("subscribeDeviceGraph()");
        let opent2t = new OpenT2T(logger);

        if (authInfo) {
            authInfo.flights = _getFlights(flightInfo);
        }

        return this._getHubInfo(hubId, logger).then((hubInfo) => {
            return this._createTranslator(opent2t, hubInfo.translator, authInfo).then((hubInstance) => {
                return hubInstance.postSubscribe(subscriptionInfo);
            });
        });
    }

    /**
     * Subscribe for notifications on all resources composing a platform.  Notifications will be posted to to
     * the subscriptionInfo.callbackURL.
     */
    subscribePlatform(hubId, authInfo, opent2tBlob, subscriptionInfo, logger, flightInfo) {
        logger.verbose("subscribePlatform()");
        let opent2t = new OpenT2T(logger);

        if (authInfo) {
            authInfo.flights = _getFlights(flightInfo);
        }

        return this._getHubInfo(hubId, logger).then((hubInfo) => {
            return this._createTranslator(opent2t, hubInfo.translator, authInfo).then((hubInstance) => {

                var deviceInfo = {};
                deviceInfo.hub = hubInstance;
                deviceInfo.deviceInfo = {};
                deviceInfo.deviceInfo.opent2t = opent2tBlob;

                return this._createTranslator(opent2t, opent2tBlob.translator, deviceInfo).then(translator => {
                    return opent2t.invokeMethodAsync(translator, "", "postSubscribe", [subscriptionInfo]);
                });
            });
        }).catch((err) => {
            return this._handleError(err, "subscribePlatform", logger);
        });
    }

    /**
     * Unsubscribe notification on all resources from a platform.
     */
    unsubscribePlatform(hubId, authInfo, opent2tBlob, subscriptionInfo, logger, flightInfo) {
        logger.verbose("unsubscribePlatform()");
        let opent2t = new OpenT2T(logger);

        if (authInfo) {
            authInfo.flights = _getFlights(flightInfo);
        }

        return this._getHubInfo(hubId, logger).then((hubInfo) => {
            return this._createTranslator(opent2t, hubInfo.translator, authInfo).then((hubInstance) => {

                var deviceInfo = {};
                deviceInfo.hub = hubInstance;
                deviceInfo.deviceInfo = {};
                deviceInfo.deviceInfo.opent2t = opent2tBlob;

                return this._createTranslator(opent2t, opent2tBlob.translator, deviceInfo).then(translator => {
                    return opent2t.invokeMethodAsync(translator, "", "deleteSubscribe", [subscriptionInfo]);
                });
            });
        }).catch((err) => {
            return this._handleError(err, "unsubscribePlatform", logger);
        });
    }

    /**
     * Verification step for cloud notifications for providers that require it.
     */
    subscribeVerify(hubId, authInfo, verificationBlob, logger, flightInfo) {
        logger.verbose("subscribeVerify()");
        let opent2t = new OpenT2T(logger);

        if (authInfo) {
            authInfo.flights = _getFlights(flightInfo);
        }

        return this._getHubInfo(hubId, logger).then((hubInfo) => {
            return this._createTranslator(opent2t, hubInfo.translator, authInfo).then((hubInstance) => {

                var subscriptionInfo = {};
                subscriptionInfo.verificationRequest = verificationBlob;

                return opent2t.invokeMethodAsync(hubInstance, "", "postSubscribe", [subscriptionInfo]);
            });
        }).catch((err) => {
            return this._handleError(err, "subscribePlatformVerify", logger);
        });
    }

    /**
     * Translate a JSON blob from a provider into an opent2t/OCF schema.  This should be called with the contents of
     * the notification post backs.  Verification is an optional object providing a secret and a hash for verification of the payload.
     * Returns an array of translated platforms, even for a single item (size 1 obviously)
     *
     * @param {Object} verificationInfo
     * @param {string} verificationInfo.key - Secret key used to compute HMAC
     * @param {Object} verificationInfo.header - Headers from the notification which will contain a provider specific HMAC.
     */
    translatePlatforms(hubId, authInfo, providerBlob, verificationInfo, logger, flightInfo) {
        logger.verbose("translatePlatforms()");
        let opent2t = new OpenT2T(logger);

        if (authInfo) {
            authInfo.flights = _getFlights(flightInfo);
        }

        // Create a hub, of the requested type.
        return this._getHubInfo(hubId, logger).then((hubInfo) => {
            // Pass the provider blob off to the hub for translation.
            return this._createTranslator(opent2t, hubInfo.translator, authInfo).then((hubInstance) => {
                // The getPlatforms method on the hub can take either single providerSchema, or a list depending
                // on the service that provided the notification.  It's up the the hub to know what to do with the data.
                return opent2t.invokeMethodAsync(hubInstance, "", "getPlatforms", [true, providerBlob, verificationInfo]);
            });
        }).catch((err) => {
            return this._handleError(err, "translatePlatforms", logger);
        });
    }

    /**
     * helper methods
     */

    /**
     * Returns an array of strings, expected input is string:
     *  "flight1,flight2"
     */
    _getFlights(flightInfo) {
        return (flightInfo === undefined || flightInfo === null) ? [] :
            flightInfo.toString().split(",").filter(n => n.length > 0);
    }

    _getHubInfo(hubId, logger) {
        return this.supportedHubs(logger).then((hubs) => {
            // find the hub referenced by hubId
            var hubInfo = undefined;
            for (var i = 0; hubInfo === undefined && i < hubs.length; i++) {
                var hub = hubs[i];

                // intentional ==
                if (hub.id == hubId) {
                    hubInfo = hub;
                }
            }

            if (!hubInfo) {
                throw new OpenT2TError(404, OpenT2TConstants.InvalidHubId);
            }

            return hubInfo;
        });
    }

    _invokeMethod(opent2t, translator, deviceInfo, methodName, params) {
        if (typeof translator === "object") {
            return opent2t.invokeMethodAsync(translator, "", methodName, params);
        }
        else {
            return this._createTranslator(opent2t, translator, deviceInfo).then(translatorInstance => {
                return opent2t.invokeMethodAsync(translatorInstance, "", methodName, params);
            });
        }
    }

    _setProperty(opent2t, translatorName, deviceInfo, property, deviceId, value) {
        return this._createTranslator(opent2t, translatorName, deviceInfo).then(translator => {
            return opent2t.invokeMethodAsync(translator, "", property, [deviceId, value]);
        });
    }

    _capitalizeFirstLetter(string) {
        return string.charAt(0).toUpperCase() + string.slice(1);
    }

    _createTranslator(opent2t, translatorName, deviceInfo) {
        return opent2t.createTranslatorAsync(translatorName, deviceInfo).then(translator => {
            return translator;
        });
    }

    _handleError(err, message, logger) {
        let customMessage = `OpenT2T call failed in: ${message}; Original message: `;
        let customErrCode = 500;
        let innerError = undefined;

        try {
            if (err instanceof Error) {
                innerError = err;
                customErrCode = err.statusCode;

                // This was a result of a failed HTTP Request promise (Eg request-promise's HttpRequestError)
                // Can also check err.Name
                if ('response' in err && 'statusMessage' in err.response) {
                    customMessage = customMessage + err.response.statusMessage;
                }
                else {
                    // Likely a simple Error-derived class like OpenT2TError
                    customMessage = customMessage + err.message;
                }
            } else {
                // Likely a promise rejected (eg NEST translators) with message string only instead of Error
                // object
                customMessage = customMessage + err;
            }

            let customError = new OpenT2TError(customErrCode, customMessage, innerError);
            logger.error(`Returning error from hubController-
            Message: ${customError.message}; StatusCode: ${customError.statusCode}`);

            return q.reject(customError);
        }
        catch (unexpectedErr) {
            let unexpectedError = new OpenT2TError(customErrCode, customMessage, unexpectedErr);
            logger.error(`ErrorHandler in hubController ran into unexpected error-
            Message: ${unexpectedError.message}`);

            return q.reject(unexpectedError);
        }
    }
}

module.exports = HubController;
<|endoftext|>