/**
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * @flow strict-local
 * @format
 */

'use strict';

import type {AlignmentCase} from '../__test_utils__/alignment-utils';

import {
  expectBabelAlignment,
  expectEspreeAlignment,
} from '../__test_utils__/alignment-utils';
import {parseForSnapshot} from '../__test_utils__/parse';

describe('DeclareVariable', () => {
  describe('var', () => {
    const testCase: AlignmentCase = {
      code: `
        declare var T1: number;
      `,
      espree: {
        expectToFail: 'espree-exception',
        expectedExceptionMessage: 'Unexpected token var',
      },
      babel: {
        expectToFail: false,
      },
    };

    test('ESTree', () => {
      expect(parseForSnapshot(testCase.code)).toMatchInlineSnapshot(`
       {
         "body": [
           {
             "declarations": [
               {
                 "id": {
                   "name": "T1",
                   "optional": false,
                   "type": "Identifier",
                   "typeAnnotation": {
                     "type": "TypeAnnotation",
                     "typeAnnotation": {
                       "type": "NumberTypeAnnotation",
                     },
                   },
                 },
                 "init": null,
                 "type": "VariableDeclarator",
               },
             ],
             "implicitDeclare": false,
             "kind": "var",
             "type": "DeclareVariable",
           },
         ],
         "type": "Program",
       }
      `);
      expectEspreeAlignment(testCase);
    });

    test('Babel', () => {
      expect(parseForSnapshot(testCase.code, {babel: true}))
        .toMatchInlineSnapshot(`
       {
         "body": [
           {
             "id": {
               "name": "T1",
               "type": "Identifier",
               "typeAnnotation": {
                 "type": "TypeAnnotation",
                 "typeAnnotation": {
                   "type": "NumberTypeAnnotation",
                 },
               },
             },
             "type": "DeclareVariable",
           },
         ],
         "type": "Program",
       }
      `);
      expectBabelAlignment(testCase);
    });
  });

  describe('let', () => {
    const testCase: AlignmentCase = {
      code: `
        declare let T1: number;
      `,
      espree: {
        expectToFail: 'espree-exception',
        expectedExceptionMessage: 'Unexpected token let',
      },
      babel: {
        expectToFail: 'espree-exception',
        expectedExceptionMessage: 'Unexpected token',
      },
    };

    test('ESTree', () => {
      expect(parseForSnapshot(testCase.code)).toMatchInlineSnapshot(`
       {
         "body": [
           {
             "declarations": [
               {
                 "id": {
                   "name": "T1",
                   "optional": false,
                   "type": "Identifier",
                   "typeAnnotation": {
                     "type": "TypeAnnotation",
                     "typeAnnotation": {
                       "type": "NumberTypeAnnotation",
                     },
                   },
                 },
                 "init": null,
                 "type": "VariableDeclarator",
               },
             ],
             "implicitDeclare": false,
             "kind": "let",
             "type": "DeclareVariable",
           },
         ],
         "type": "Program",
       }
      `);
      expectEspreeAlignment(testCase);
    });

    test('Babel', () => {
      expect(parseForSnapshot(testCase.code, {babel: true}))
        .toMatchInlineSnapshot(`
       {
         "body": [
           {
             "id": {
               "name": "T1",
               "type": "Identifier",
               "typeAnnotation": {
                 "type": "TypeAnnotation",
                 "typeAnnotation": {
                   "type": "NumberTypeAnnotation",
                 },
               },
             },
             "type": "DeclareVariable",
           },
         ],
         "type": "Program",
       }
      `);
      expectBabelAlignment(testCase);
    });
  });

  describe('const', () => {
    const testCase: AlignmentCase = {
      code: `
        declare const T1: number;
      `,
      espree: {
        expectToFail: 'espree-exception',
        expectedExceptionMessage: 'Unexpected token const',
      },
      babel: {
        expectToFail: 'espree-exception',
        expectedExceptionMessage: 'Unexpected token',
      },
    };

    test('ESTree', () => {
      expect(parseForSnapshot(testCase.code)).toMatchInlineSnapshot(`
       {
         "body": [
           {
             "declarations": [
               {
                 "id": {
                   "name": "T1",
                   "optional": false,
                   "type": "Identifier",
                   "typeAnnotation": {
                     "type": "TypeAnnotation",
                     "typeAnnotation": {
                       "type": "NumberTypeAnnotation",
                     },
                   },
                 },
                 "init": null,
                 "type": "VariableDeclarator",
               },
             ],
             "implicitDeclare": false,
             "kind": "const",
             "type": "DeclareVariable",
           },
         ],
         "type": "Program",
       }
      `);
      expectEspreeAlignment(testCase);
    });

    test('Babel', () => {
      expect(parseForSnapshot(testCase.code, {babel: true}))
        .toMatchInlineSnapshot(`
       {
         "body": [
           {
             "id": {
               "name": "T1",
               "type": "Identifier",
               "typeAnnotation": {
                 "type": "TypeAnnotation",
                 "typeAnnotation": {
                   "type": "NumberTypeAnnotation",
                 },
               },
             },
             "type": "DeclareVariable",
           },
         ],
         "type": "Program",
       }
      `);
      expectBabelAlignment(testCase);
    });
  });

  test('ESTree keeps extra declarators and initializers', () => {
    expect(parseForSnapshot(`declare const A: number = 1, B: string = 'x';`))
      .toMatchInlineSnapshot(`
     {
       "body": [
         {
           "declarations": [
             {
               "id": {
                 "name": "A",
                 "optional": false,
                 "type": "Identifier",
                 "typeAnnotation": {
                   "type": "TypeAnnotation",
                   "typeAnnotation": {
                     "type": "NumberTypeAnnotation",
                   },
                 },
               },
               "init": {
                 "literalType": "numeric",
                 "raw": "1",
                 "type": "Literal",
                 "value": 1,
               },
               "type": "VariableDeclarator",
             },
             {
               "id": {
                 "name": "B",
                 "optional": false,
                 "type": "Identifier",
                 "typeAnnotation": {
                   "type": "TypeAnnotation",
                   "typeAnnotation": {
                     "type": "StringTypeAnnotation",
                   },
                 },
               },
               "init": {
                 "literalType": "string",
                 "raw": "'x'",
                 "type": "Literal",
                 "value": "x",
               },
               "type": "VariableDeclarator",
             },
           ],
           "implicitDeclare": false,
           "kind": "const",
           "type": "DeclareVariable",
         },
       ],
       "type": "Program",
     }
    `);
  });
});
