'use strict';

var utils = require('../utils.js');
var utils$1 = require('@typescript-eslint/utils');
var astUtils = require('@typescript-eslint/utils/ast-utils');
require('eslint-visitor-keys');
require('espree');
require('estraverse');

var _baseRule = utils.createRule(
  {
    name: "object-curly-spacing",
    package: "js",
    meta: {
      type: "layout",
      docs: {
        description: "Enforce consistent spacing inside braces"
      },
      fixable: "whitespace",
      schema: [
        {
          type: "string",
          enum: ["always", "never"]
        },
        {
          type: "object",
          properties: {
            arraysInObjects: {
              type: "boolean"
            },
            objectsInObjects: {
              type: "boolean"
            }
          },
          additionalProperties: false
        }
      ],
      messages: {
        requireSpaceBefore: "A space is required before '{{token}}'.",
        requireSpaceAfter: "A space is required after '{{token}}'.",
        unexpectedSpaceBefore: "There should be no space before '{{token}}'.",
        unexpectedSpaceAfter: "There should be no space after '{{token}}'."
      }
    },
    create(context) {
      const spaced = context.options[0] === "always";
      const sourceCode = context.sourceCode;
      function isOptionSet(option) {
        return context.options[1] ? context.options[1][option] === !spaced : false;
      }
      const options = {
        spaced,
        arraysInObjectsException: isOptionSet("arraysInObjects"),
        objectsInObjectsException: isOptionSet("objectsInObjects")
      };
      function reportNoBeginningSpace(node, token) {
        const nextToken = context.sourceCode.getTokenAfter(token, { includeComments: true });
        context.report({
          node,
          loc: { start: token.loc.end, end: nextToken.loc.start },
          messageId: "unexpectedSpaceAfter",
          data: {
            token: token.value
          },
          fix(fixer) {
            return fixer.removeRange([token.range[1], nextToken.range[0]]);
          }
        });
      }
      function reportNoEndingSpace(node, token) {
        const previousToken = context.sourceCode.getTokenBefore(token, { includeComments: true });
        context.report({
          node,
          loc: { start: previousToken.loc.end, end: token.loc.start },
          messageId: "unexpectedSpaceBefore",
          data: {
            token: token.value
          },
          fix(fixer) {
            return fixer.removeRange([previousToken.range[1], token.range[0]]);
          }
        });
      }
      function reportRequiredBeginningSpace(node, token) {
        context.report({
          node,
          loc: token.loc,
          messageId: "requireSpaceAfter",
          data: {
            token: token.value
          },
          fix(fixer) {
            return fixer.insertTextAfter(token, " ");
          }
        });
      }
      function reportRequiredEndingSpace(node, token) {
        context.report({
          node,
          loc: token.loc,
          messageId: "requireSpaceBefore",
          data: {
            token: token.value
          },
          fix(fixer) {
            return fixer.insertTextBefore(token, " ");
          }
        });
      }
      function validateBraceSpacing(node, first, second, penultimate, last) {
        if (utils.isTokenOnSameLine(first, second)) {
          const firstSpaced = sourceCode.isSpaceBetween(first, second);
          if (options.spaced && !firstSpaced)
            reportRequiredBeginningSpace(node, first);
          if (!options.spaced && firstSpaced && second.type !== "Line")
            reportNoBeginningSpace(node, first);
        }
        if (utils.isTokenOnSameLine(penultimate, last)) {
          const shouldCheckPenultimate = options.arraysInObjectsException && utils.isClosingBracketToken(penultimate) || options.objectsInObjectsException && utils.isClosingBraceToken(penultimate);
          const penultimateType = shouldCheckPenultimate && sourceCode.getNodeByRangeIndex(penultimate.range[0]).type;
          const closingCurlyBraceMustBeSpaced = options.arraysInObjectsException && penultimateType === "ArrayExpression" || options.objectsInObjectsException && (penultimateType === "ObjectExpression" || penultimateType === "ObjectPattern") ? !options.spaced : options.spaced;
          const lastSpaced = sourceCode.isSpaceBetween(penultimate, last);
          if (closingCurlyBraceMustBeSpaced && !lastSpaced)
            reportRequiredEndingSpace(node, last);
          if (!closingCurlyBraceMustBeSpaced && lastSpaced)
            reportNoEndingSpace(node, last);
        }
      }
      function getClosingBraceOfObject(node) {
        const lastProperty = node.properties[node.properties.length - 1];
        return sourceCode.getTokenAfter(lastProperty, utils.isClosingBraceToken);
      }
      function checkForObject(node) {
        if (node.properties.length === 0)
          return;
        const first = sourceCode.getFirstToken(node);
        const last = getClosingBraceOfObject(node);
        const second = sourceCode.getTokenAfter(first, { includeComments: true });
        const penultimate = sourceCode.getTokenBefore(last, { includeComments: true });
        validateBraceSpacing(node, first, second, penultimate, last);
      }
      function checkForImport(node) {
        if (node.specifiers.length === 0)
          return;
        let firstSpecifier = node.specifiers[0];
        const lastSpecifier = node.specifiers[node.specifiers.length - 1];
        if (lastSpecifier.type !== "ImportSpecifier")
          return;
        if (firstSpecifier.type !== "ImportSpecifier")
          firstSpecifier = node.specifiers[1];
        const first = sourceCode.getTokenBefore(firstSpecifier);
        const last = sourceCode.getTokenAfter(lastSpecifier, utils.isNotCommaToken);
        const second = sourceCode.getTokenAfter(first, { includeComments: true });
        const penultimate = sourceCode.getTokenBefore(last, { includeComments: true });
        validateBraceSpacing(node, first, second, penultimate, last);
      }
      function checkForExport(node) {
        if (node.specifiers.length === 0)
          return;
        const firstSpecifier = node.specifiers[0];
        const lastSpecifier = node.specifiers[node.specifiers.length - 1];
        const first = sourceCode.getTokenBefore(firstSpecifier);
        const last = sourceCode.getTokenAfter(lastSpecifier, utils.isNotCommaToken);
        const second = sourceCode.getTokenAfter(first, { includeComments: true });
        const penultimate = sourceCode.getTokenBefore(last, { includeComments: true });
        validateBraceSpacing(node, first, second, penultimate, last);
      }
      return {
        // var {x} = y;
        ObjectPattern: checkForObject,
        // var y = {x: 'y'}
        ObjectExpression: checkForObject,
        // import {y} from 'x';
        ImportDeclaration: checkForImport,
        // export {name} from 'yo';
        ExportNamedDeclaration: checkForExport
      };
    }
  }
);

const baseRule = /* @__PURE__ */ utils.castRuleModule(_baseRule);
var objectCurlySpacing = utils.createRule({
  name: "object-curly-spacing",
  package: "ts",
  meta: {
    ...baseRule.meta,
    docs: {
      description: "Enforce consistent spacing inside braces"
    }
  },
  defaultOptions: ["never"],
  create(context) {
    const [firstOption, secondOption] = context.options;
    const spaced = firstOption === "always";
    const sourceCode = context.sourceCode || context.getSourceCode();
    function isOptionSet(option) {
      return secondOption ? secondOption[option] === !spaced : false;
    }
    const options = {
      spaced,
      arraysInObjectsException: isOptionSet("arraysInObjects"),
      objectsInObjectsException: isOptionSet("objectsInObjects")
    };
    function reportNoBeginningSpace(node, token) {
      const nextToken = sourceCode.getTokenAfter(token, { includeComments: true });
      context.report({
        node,
        loc: { start: token.loc.end, end: nextToken.loc.start },
        messageId: "unexpectedSpaceAfter",
        data: {
          token: token.value
        },
        fix(fixer) {
          return fixer.removeRange([token.range[1], nextToken.range[0]]);
        }
      });
    }
    function reportNoEndingSpace(node, token) {
      const previousToken = sourceCode.getTokenBefore(token, { includeComments: true });
      context.report({
        node,
        loc: { start: previousToken.loc.end, end: token.loc.start },
        messageId: "unexpectedSpaceBefore",
        data: {
          token: token.value
        },
        fix(fixer) {
          return fixer.removeRange([previousToken.range[1], token.range[0]]);
        }
      });
    }
    function reportRequiredBeginningSpace(node, token) {
      context.report({
        node,
        loc: token.loc,
        messageId: "requireSpaceAfter",
        data: {
          token: token.value
        },
        fix(fixer) {
          return fixer.insertTextAfter(token, " ");
        }
      });
    }
    function reportRequiredEndingSpace(node, token) {
      context.report({
        node,
        loc: token.loc,
        messageId: "requireSpaceBefore",
        data: {
          token: token.value
        },
        fix(fixer) {
          return fixer.insertTextBefore(token, " ");
        }
      });
    }
    function validateBraceSpacing(node, first, second, penultimate, last) {
      if (astUtils.isTokenOnSameLine(first, second)) {
        const firstSpaced = sourceCode.isSpaceBetween(first, second);
        const secondType = sourceCode.getNodeByRangeIndex(
          second.range[0]
        ).type;
        const openingCurlyBraceMustBeSpaced = options.arraysInObjectsException && [
          utils$1.AST_NODE_TYPES.TSMappedType,
          utils$1.AST_NODE_TYPES.TSIndexSignature
        ].includes(secondType) ? !options.spaced : options.spaced;
        if (openingCurlyBraceMustBeSpaced && !firstSpaced)
          reportRequiredBeginningSpace(node, first);
        if (!openingCurlyBraceMustBeSpaced && firstSpaced && second.type !== utils$1.AST_TOKEN_TYPES.Line) {
          reportNoBeginningSpace(node, first);
        }
      }
      if (astUtils.isTokenOnSameLine(penultimate, last)) {
        const shouldCheckPenultimate = options.arraysInObjectsException && astUtils.isClosingBracketToken(penultimate) || options.objectsInObjectsException && astUtils.isClosingBraceToken(penultimate);
        const penultimateType = shouldCheckPenultimate ? sourceCode.getNodeByRangeIndex(penultimate.range[0]).type : undefined;
        const closingCurlyBraceMustBeSpaced = options.arraysInObjectsException && penultimateType === utils$1.AST_NODE_TYPES.TSTupleType || options.objectsInObjectsException && penultimateType !== undefined && [
          utils$1.AST_NODE_TYPES.TSMappedType,
          utils$1.AST_NODE_TYPES.TSTypeLiteral
        ].includes(penultimateType) ? !options.spaced : options.spaced;
        const lastSpaced = sourceCode.isSpaceBetween(penultimate, last);
        if (closingCurlyBraceMustBeSpaced && !lastSpaced)
          reportRequiredEndingSpace(node, last);
        if (!closingCurlyBraceMustBeSpaced && lastSpaced)
          reportNoEndingSpace(node, last);
      }
    }
    function getClosingBraceOfObject(node) {
      const lastProperty = node.members[node.members.length - 1];
      return sourceCode.getTokenAfter(lastProperty, astUtils.isClosingBraceToken);
    }
    const rules = baseRule.create(context);
    return {
      ...rules,
      TSMappedType(node) {
        const first = sourceCode.getFirstToken(node);
        const last = sourceCode.getLastToken(node);
        const second = sourceCode.getTokenAfter(first, {
          includeComments: true
        });
        const penultimate = sourceCode.getTokenBefore(last, {
          includeComments: true
        });
        validateBraceSpacing(node, first, second, penultimate, last);
      },
      TSTypeLiteral(node) {
        if (node.members.length === 0)
          return;
        const first = sourceCode.getFirstToken(node);
        const last = getClosingBraceOfObject(node);
        const second = sourceCode.getTokenAfter(first, {
          includeComments: true
        });
        const penultimate = sourceCode.getTokenBefore(last, {
          includeComments: true
        });
        validateBraceSpacing(node, first, second, penultimate, last);
      }
    };
  }
});

module.exports = objectCurlySpacing;
