"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.KeyParser = void 0;
exports.parseAriaSnapshot = parseAriaSnapshot;
var _utilsBundle = require("../utilsBundle");
var _utils = require("../utils");
/**
 * Copyright (c) Microsoft Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

function parseAriaSnapshot(text) {
  const fragment = _utilsBundle.yaml.parse(text);
  const result = {
    kind: 'role',
    role: 'fragment'
  };
  populateNode(result, fragment);
  return result;
}
function populateNode(node, container) {
  for (const object of container) {
    if (typeof object === 'string') {
      const childNode = KeyParser.parse(object);
      node.children = node.children || [];
      node.children.push(childNode);
      continue;
    }
    for (const key of Object.keys(object)) {
      node.children = node.children || [];
      const value = object[key];
      if (key === 'text') {
        node.children.push({
          kind: 'text',
          text: valueOrRegex(value)
        });
        continue;
      }
      const childNode = KeyParser.parse(key);
      if (childNode.kind === 'text') {
        node.children.push({
          kind: 'text',
          text: valueOrRegex(value)
        });
        continue;
      }
      if (typeof value === 'string') {
        node.children.push({
          ...childNode,
          children: [{
            kind: 'text',
            text: valueOrRegex(value)
          }]
        });
        continue;
      }
      node.children.push(childNode);
      populateNode(childNode, value);
    }
  }
}
function applyAttribute(node, key, value) {
  if (key === 'checked') {
    (0, _utils.assert)(value === 'true' || value === 'false' || value === 'mixed', 'Value of "disabled" attribute must be a boolean or "mixed"');
    node.checked = value === 'true' ? true : value === 'false' ? false : 'mixed';
    return;
  }
  if (key === 'disabled') {
    (0, _utils.assert)(value === 'true' || value === 'false', 'Value of "disabled" attribute must be a boolean');
    node.disabled = value === 'true';
    return;
  }
  if (key === 'expanded') {
    (0, _utils.assert)(value === 'true' || value === 'false', 'Value of "expanded" attribute must be a boolean');
    node.expanded = value === 'true';
    return;
  }
  if (key === 'level') {
    (0, _utils.assert)(!isNaN(Number(value)), 'Value of "level" attribute must be a number');
    node.level = Number(value);
    return;
  }
  if (key === 'pressed') {
    (0, _utils.assert)(value === 'true' || value === 'false' || value === 'mixed', 'Value of "pressed" attribute must be a boolean or "mixed"');
    node.pressed = value === 'true' ? true : value === 'false' ? false : 'mixed';
    return;
  }
  if (key === 'selected') {
    (0, _utils.assert)(value === 'true' || value === 'false', 'Value of "selected" attribute must be a boolean');
    node.selected = value === 'true';
    return;
  }
  throw new Error(`Unsupported attribute [${key}] `);
}
function normalizeWhitespace(text) {
  return text.replace(/[\r\n\s\t]+/g, ' ').trim();
}
function valueOrRegex(value) {
  return value.startsWith('/') && value.endsWith('/') ? new RegExp(value.slice(1, -1)) : normalizeWhitespace(value);
}
class KeyParser {
  static parse(input) {
    return new KeyParser(input)._parse();
  }
  constructor(input) {
    this._input = void 0;
    this._pos = void 0;
    this._length = void 0;
    this._input = input;
    this._pos = 0;
    this._length = input.length;
  }
  _peek() {
    return this._input[this._pos] || '';
  }
  _next() {
    if (this._pos < this._length) return this._input[this._pos++];
    return null;
  }
  _eof() {
    return this._pos >= this._length;
  }
  _skipWhitespace() {
    while (!this._eof() && /\s/.test(this._peek())) this._pos++;
  }
  _readIdentifier() {
    if (this._eof()) throw new Error('Unexpected end of input when expecting identifier');
    const start = this._pos;
    while (!this._eof() && /[a-zA-Z]/.test(this._peek())) this._pos++;
    return this._input.slice(start, this._pos);
  }
  _readString() {
    let result = '';
    let escaped = false;
    while (!this._eof()) {
      const ch = this._next();
      if (escaped) {
        result += ch;
        escaped = false;
      } else if (ch === '\\') {
        escaped = true;
        result += ch;
      } else if (ch === '"') {
        return result;
      } else {
        result += ch;
      }
    }
    throw new Error('Unterminated string starting at position ' + this._pos);
  }
  _readRegex() {
    let result = '';
    let escaped = false;
    while (!this._eof()) {
      const ch = this._next();
      if (escaped) {
        result += ch;
        escaped = false;
      } else if (ch === '\\') {
        escaped = true;
        result += ch;
      } else if (ch === '/') {
        return result;
      } else {
        result += ch;
      }
    }
    throw new Error('Unterminated regex starting at position ' + this._pos);
  }
  _readStringOrRegex() {
    const ch = this._peek();
    if (ch === '"') {
      this._next();
      return this._readString();
    }
    if (ch === '/') {
      this._next();
      return new RegExp(this._readRegex());
    }
    return null;
  }
  _readFlags() {
    const flags = new Map();
    while (true) {
      this._skipWhitespace();
      if (this._peek() === '[') {
        this._next();
        this._skipWhitespace();
        const flagName = this._readIdentifier();
        this._skipWhitespace();
        let flagValue = '';
        if (this._peek() === '=') {
          this._next();
          this._skipWhitespace();
          while (this._peek() !== ']' && !this._eof()) flagValue += this._next();
        }
        this._skipWhitespace();
        if (this._peek() !== ']') throw new Error('Expected ] at position ' + this._pos);
        this._next(); // Consume ']'
        flags.set(flagName, flagValue || 'true');
      } else {
        break;
      }
    }
    return flags;
  }
  _parse() {
    this._skipWhitespace();
    const role = this._readIdentifier();
    this._skipWhitespace();
    const name = this._readStringOrRegex() || '';
    const result = {
      kind: 'role',
      role,
      name
    };
    const flags = this._readFlags();
    for (const [name, value] of flags) applyAttribute(result, name, value);
    this._skipWhitespace();
    if (!this._eof()) throw new Error('Unexpected input at position ' + this._pos);
    return result;
  }
}
exports.KeyParser = KeyParser;