"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.parseHtml = parseHtml;
exports.getAttributeContextAtPosition = getAttributeContextAtPosition;
const vscode_html_languageservice_1 = require("vscode-html-languageservice");
const utils_1 = require("./utils");
const parser = (0, vscode_html_languageservice_1.getLanguageService)();
/**
 * Parses text as HTML
 */
function parseHtml(text) {
    const preprocessed = preprocess(text);
    // We can safely only set getText because only this is used for parsing
    const parsedDoc = parser.parseHTMLDocument({ getText: () => preprocessed });
    return parsedDoc;
}
const createScanner = parser.createScanner;
/**
 * scan the text and remove any `>` or `<` that cause the tag to end short,
 */
function preprocess(text) {
    let scanner = createScanner(text);
    let token = scanner.scan();
    let currentStartTagStart = null;
    let moustacheCheckStart = 0;
    let moustacheCheckEnd = 0;
    let lastToken = token;
    while (token !== vscode_html_languageservice_1.TokenType.EOS) {
        const offset = scanner.getTokenOffset();
        let blanked = false;
        switch (token) {
            case vscode_html_languageservice_1.TokenType.StartTagOpen:
                if (shouldBlankStartOrEndTagLike(offset)) {
                    blankStartOrEndTagLike(offset);
                    blanked = true;
                }
                else {
                    currentStartTagStart = offset;
                }
                break;
            case vscode_html_languageservice_1.TokenType.StartTagClose:
                if (shouldBlankStartOrEndTagLike(offset)) {
                    blankStartOrEndTagLike(offset);
                    blanked = true;
                }
                else {
                    currentStartTagStart = null;
                }
                break;
            case vscode_html_languageservice_1.TokenType.StartTagSelfClose:
                currentStartTagStart = null;
                break;
            // <Foo checked={a < 1}>
            // https://github.com/microsoft/vscode-html-languageservice/blob/71806ef57be07e1068ee40900ef8b0899c80e68a/src/parser/htmlScanner.ts#L327
            case vscode_html_languageservice_1.TokenType.Unknown:
                if (scanner.getScannerState() === vscode_html_languageservice_1.ScannerState.WithinTag &&
                    scanner.getTokenText() === '<' &&
                    shouldBlankStartOrEndTagLike(offset)) {
                    blankStartOrEndTagLike(offset);
                    blanked = true;
                }
                break;
            case vscode_html_languageservice_1.TokenType.Content: {
                moustacheCheckEnd = scanner.getTokenEnd();
                if (token !== lastToken) {
                    moustacheCheckStart = offset;
                }
                break;
            }
        }
        // blanked, so the token type is invalid
        if (!blanked) {
            lastToken = token;
        }
        token = scanner.scan();
    }
    return text;
    function shouldBlankStartOrEndTagLike(offset) {
        if (currentStartTagStart != null) {
            return (0, utils_1.isInsideMoustacheTag)(text, currentStartTagStart, offset);
        }
        const index = text
            .substring(moustacheCheckStart, moustacheCheckEnd)
            .lastIndexOf('{', offset);
        const lastMustacheTagStart = index === -1 ? null : moustacheCheckStart + index;
        if (lastMustacheTagStart == null) {
            return false;
        }
        return (0, utils_1.isInsideMoustacheTag)(text.substring(lastMustacheTagStart), null, offset - lastMustacheTagStart);
    }
    function blankStartOrEndTagLike(offset) {
        text = text.substring(0, offset) + ' ' + text.substring(offset + 1);
        scanner = createScanner(text, offset, currentStartTagStart != null ? vscode_html_languageservice_1.ScannerState.WithinTag : vscode_html_languageservice_1.ScannerState.WithinContent);
    }
}
function getAttributeContextAtPosition(document, position) {
    const offset = document.offsetAt(position);
    const { html } = document;
    const tag = html.findNodeAt(offset);
    if (!inStartTag(offset, tag) || !tag.attributes) {
        return null;
    }
    const text = document.getText();
    const beforeStartTagEnd = text.substring(0, tag.start) + preprocess(text.substring(tag.start, tag.startTagEnd));
    const scanner = createScanner(beforeStartTagEnd, tag.start);
    let token = scanner.scan();
    let currentAttributeName;
    const inTokenRange = () => scanner.getTokenOffset() <= offset && offset <= scanner.getTokenEnd();
    while (token != vscode_html_languageservice_1.TokenType.EOS) {
        // adopted from https://github.com/microsoft/vscode-html-languageservice/blob/2f7ae4df298ac2c299a40e9024d118f4a9dc0c68/src/services/htmlCompletion.ts#L402
        if (token === vscode_html_languageservice_1.TokenType.AttributeName) {
            currentAttributeName = scanner.getTokenText();
            if (inTokenRange()) {
                return {
                    elementTag: tag,
                    name: currentAttributeName,
                    inValue: false
                };
            }
        }
        else if (token === vscode_html_languageservice_1.TokenType.DelimiterAssign) {
            if (scanner.getTokenEnd() === offset && currentAttributeName) {
                const nextToken = scanner.scan();
                return {
                    elementTag: tag,
                    name: currentAttributeName,
                    inValue: true,
                    valueRange: [
                        offset,
                        nextToken === vscode_html_languageservice_1.TokenType.AttributeValue ? scanner.getTokenEnd() : offset
                    ]
                };
            }
        }
        else if (token === vscode_html_languageservice_1.TokenType.AttributeValue) {
            if (inTokenRange() && currentAttributeName) {
                let start = scanner.getTokenOffset();
                let end = scanner.getTokenEnd();
                const char = text[start];
                if (char === '"' || char === "'") {
                    start++;
                    end--;
                }
                return {
                    elementTag: tag,
                    name: currentAttributeName,
                    inValue: true,
                    valueRange: [start, end]
                };
            }
            currentAttributeName = undefined;
        }
        token = scanner.scan();
    }
    return null;
}
function inStartTag(offset, node) {
    return offset > node.start && node.startTagEnd != undefined && offset < node.startTagEnd;
}
//# sourceMappingURL=parseHtml.js.map