text: "use strict";
  var __importStar = (this && this.__importStar) || function (mod) {
      if (mod && mod.__esModule) return mod;
      var result = {};
      if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
      result["default"] = mod;
      return result;
  };
  Object.defineProperty(exports, "__esModule", { value: true });
  const eslint_1 = require("eslint");
  const analyze_scope_1 = require("@typescript-eslint/parser/dist/analyze-scope");
  const simple_traverse_1 = require("@typescript-eslint/parser/dist/simple-traverse");
  const visitor_keys_1 = require("@typescript-eslint/parser/dist/visitor-keys");
  const TsEstree = __importStar(require("@typescript-eslint/typescript-estree/dist/ast-converter"));
  function validateBoolean(value, fallback = false) {
      if (typeof value !== "boolean") {
          return fallback;
      }
      return value;
  }
  function createExtra(code) {
      const base = {
          tokens: null,
          range: false,
          loc: false,
          comment: false,
          comments: [],
          strict: false,
          jsx: false,
          useJSXTextNode: false,
          log: () => { },
          projects: [],
          errorOnUnknownASTType: false,
          errorOnTypeScriptSyntacticAndSemanticIssues: false,
          code: "",
          tsconfigRootDir: process.cwd(),
          extraFileExtensions: [],
          preserveNodeMaps: undefined,
          createDefaultProgram: false,
      };
      return Object.assign({}, base, { code, tokens: [], loc: true, comment: true, comments: [] });
  }
  function applyParserOptionsToExtra(extra, options) {
      /**
       * Track range information in the AST
       */
      extra.range = typeof options.range === "boolean" && options.range;
      extra.loc = typeof options.loc === "boolean" && options.loc;
      /**
       * Track tokens in the AST
       */
      if (typeof options.tokens === "boolean" && options.tokens) {
          extra.tokens = [];
      }
      /**
       * Track comments in the AST
       */
      if (typeof options.comment === "boolean" && options.comment) {
          extra.comment = true;
          extra.comments = [];
      }
      /**
       * Enable JSX - note the applicable file extension is still required
       */
      if (typeof options.jsx === "boolean" && options.jsx) {
          extra.jsx = true;
      }
      /**
       * The JSX AST changed the node type for string literals
       * inside a JSX Element from `Literal` to `JSXText`.
       *
       * When value is `true`, these nodes will be parsed as type `JSXText`.
       * When value is `false`, these nodes will be parsed as type `Literal`.
       */
      if (typeof options.useJSXTextNode === "boolean" && options.useJSXTextNode) {
          extra.useJSXTextNode = true;
      }
      /**
       * Allow the user to cause the parser to error if it encounters an unknown AST Node Type
       * (used in testing)
       */
      if (typeof options.errorOnUnknownASTType === "boolean" &&
          options.errorOnUnknownASTType) {
          extra.errorOnUnknownASTType = true;
      }
      /**
       * Allow the user to override the function used for logging
       */
      if (typeof options.loggerFn === "function") {
          extra.log = options.loggerFn;
      }
      else if (options.loggerFn === false) {
          extra.log = Function.prototype;
      }
      if (typeof options.project === "string") {
          extra.projects = [options.project];
      }
      else if (Array.isArray(options.project) &&
          options.project.every(projectPath => typeof projectPath === "string")) {
          extra.projects = options.project;
      }
      if (typeof options.tsconfigRootDir === "string") {
          extra.tsconfigRootDir = options.tsconfigRootDir;
      }
      if (Array.isArray(options.extraFileExtensions) &&
          options.extraFileExtensions.every(ext => typeof ext === "string")) {
          extra.extraFileExtensions = options.extraFileExtensions;
      }
      /**
       * Allow the user to enable or disable the preservation of the AST node maps
       * during the conversion process.
       *
       * NOTE: For backwards compatibility we also preserve node maps in the case where `project` is set,
       * and `preserveNodeMaps` is not explicitly set to anything.
       */
      extra.preserveNodeMaps =
          typeof options.preserveNodeMaps === "boolean" && options.preserveNodeMaps;
      if (options.preserveNodeMaps === undefined && extra.projects.length > 0) {
          extra.preserveNodeMaps = true;
      }
      return extra;
  }
  class AstConverter {
      constructor({ getProgram } = {}) {
          this.getProgram = getProgram;
      }
      /**
       *
       * see also https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/typescript-estree/src/parser.ts#L346
       *
       */
      parseAndGenerateServices(src, options) {
          const code = src.getFullText();
          let extra = createExtra(code);
          extra.code = code;
          /**
           * Apply the given parser options
           */
          if (typeof options !== "undefined") {
              extra = applyParserOptionsToExtra(extra, options);
              if (typeof options.errorOnTypeScriptSyntacticAndSemanticIssues === "boolean" && options.errorOnTypeScriptSyntacticAndSemanticIssues) {
                  extra.errorOnTypeScriptSyntacticAndSemanticIssues = true;
              }
          }
          // Note:
          //
          // astConverter is an internal API and it has changed from default exported function to named exported one via 1.x -> 2.x
          //
          // See also https://github.com/typescript-eslint/typescript-eslint/pull/535/files#diff-45d8ff2254adb960ab07ac35ada146a8L7
          const convert = TsEstree.astConverter || TsEstree.default;
          const { estree, astMaps } = convert(src, extra, true);
          /**
           * Return the converted AST and additional parser services
           */
          const ret = {
              ast: estree,
              services: {
                  program: this.getProgram && this.getProgram(),
                  esTreeNodeToTSNodeMap: astMaps ? astMaps.esTreeNodeToTSNodeMap : undefined,
                  tsNodeToESTreeNodeMap: astMaps ? astMaps.tsNodeToESTreeNodeMap : undefined,
              },
          };
          return ret;
      }
      /**
       * See also https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/parser/src/parser.ts
       */
      parseForESLint(src, options) {
          try {
              if (!options || typeof options !== "object") {
                  options = {};
              }
              if (options.sourceType !== "module" && options.sourceType !== "script") {
                  options.sourceType = "script";
              }
              if (typeof options.ecmaFeatures !== "object") {
                  options.ecmaFeatures = {};
              }
              const parserOptions = {};
              Object.assign(parserOptions, options, {
                  useJSXTextNode: validateBoolean(options.useJSXTextNode, true),
                  jsx: validateBoolean(options.ecmaFeatures.jsx),
              });
              if (typeof options.filePath === "string") {
                  const tsx = options.filePath.endsWith(".tsx");
                  if (tsx || options.filePath.endsWith(".ts")) {
                      parserOptions.jsx = tsx;
                  }
              }
              const { ast, services } = this.parseAndGenerateServices(src, parserOptions);
              simple_traverse_1.simpleTraverse(ast, {
                  enter(node) {
                      switch (node.type) {
                          // Function#body cannot be null in ESTree spec.
                          case "FunctionExpression":
                              if (!node.body) {
                                  node.type = `TSEmptyBody${node.type}`;
                              }
                              break;
                          // no default
                      }
                  },
              });
              const scopeManager = analyze_scope_1.analyzeScope(ast, parserOptions);
              return {
                  ast: ast,
                  scopeManager: scopeManager,
                  services,
                  visitorKeys: visitor_keys_1.visitorKeys,
              };
          }
          catch (error) {
              throw new Error();
          }
      }
      convertToESLintSourceCode(src, options) {
          const code = src.getFullText();
          const { ast, scopeManager, services, visitorKeys } = this.parseForESLint(src, options);
          return new eslint_1.SourceCode({
              text: code,
              ast,
              scopeManager,
              parserServices: services,
              visitorKeys,
          });
      }
  }
  exports.AstConverter = AstConverter;
  //# sourceMappingURL=ast-converter.js.map