"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.create = create;
const language_core_1 = require("@vue/language-core");
const utils_1 = require("../utils");
function create(ts, { isRefAtPosition }) {
    return {
        name: 'vue-autoinsert-dotvalue',
        capabilities: {
            autoInsertionProvider: {
                triggerCharacters: ['\\w'],
                configurationSections: ['vue.autoInsert.dotValue'],
            },
        },
        create(context) {
            return {
                async provideAutoInsertSnippet(document, selection, change) {
                    const info = (0, utils_1.resolveEmbeddedCode)(context, document.uri);
                    if (!info?.code.id.startsWith('script_')) {
                        return;
                    }
                    // selection must at end of change
                    if (document.offsetAt(selection) !== change.rangeOffset + change.text.length) {
                        return;
                    }
                    if (!isCharacterTyping(document, change)) {
                        return;
                    }
                    let sourceOffset;
                    const { ir } = info.root;
                    const scriptBlocks = [ir.script, ir.scriptSetup].filter(block => !!block);
                    const map = context.language.maps.get(info.code, info.script);
                    if (!scriptBlocks.length) {
                        return;
                    }
                    for (const [offset] of map.toSourceLocation(document.offsetAt(selection))) {
                        sourceOffset = offset;
                        break;
                    }
                    if (sourceOffset === undefined) {
                        return;
                    }
                    for (const { ast, startTagEnd, endTagStart } of scriptBlocks) {
                        if (sourceOffset < startTagEnd || sourceOffset > endTagStart) {
                            continue;
                        }
                        if (shouldSkip(ts, ast, sourceOffset - startTagEnd, false)) {
                            return;
                        }
                    }
                    if (await isRefAtPosition(info.root.fileName, sourceOffset)) {
                        return '${1:.value}';
                    }
                },
            };
        },
    };
}
const charRE = /\w/;
function isCharacterTyping(document, change) {
    const lastCharacter = change.text[change.text.length - 1];
    const nextCharacter = document.getText().slice(change.rangeOffset + change.text.length, change.rangeOffset + change.text.length + 1);
    if (lastCharacter === undefined) { // delete text
        return false;
    }
    if (change.text.includes('\n')) { // multi-line change
        return false;
    }
    return charRE.test(lastCharacter) && !charRE.test(nextCharacter);
}
function shouldSkip(ts, node, pos, allowAccessDotValue) {
    if (ts.isVariableDeclaration(node) && pos >= node.name.getFullStart() && pos <= node.name.getEnd()) {
        return true;
    }
    else if (ts.isFunctionDeclaration(node) && node.name && pos >= node.name.getFullStart() && pos <= node.name.getEnd()) {
        return true;
    }
    else if (ts.isParameter(node) && pos >= node.name.getFullStart() && pos <= node.name.getEnd()) {
        return true;
    }
    else if (ts.isPropertyAssignment(node) && pos >= node.name.getFullStart() && pos <= node.name.getEnd()) {
        return true;
    }
    else if (ts.isShorthandPropertyAssignment(node)) {
        return true;
    }
    else if (ts.isImportDeclaration(node)) {
        return true;
    }
    else if (ts.isLiteralTypeNode(node)) {
        return true;
    }
    else if (ts.isTypeReferenceNode(node)) {
        return true;
    }
    else if (!allowAccessDotValue && ts.isPropertyAccessExpression(node) && node.expression.end === pos
        && node.name.text === 'value') {
        return true;
    }
    else if (ts.isCallExpression(node)
        && ts.isIdentifier(node.expression)
        && isWatchOrUseFunction(node.expression.text)
        && isTopLevelArgOrArrayTopLevelItemItem(ts, node, pos)) {
        return true;
    }
    else {
        let _shouldSkip = false;
        node.forEachChild(node => {
            if (_shouldSkip) {
                return;
            }
            if (pos >= node.getFullStart() && pos <= node.getEnd()) {
                if (shouldSkip(ts, node, pos, allowAccessDotValue)) {
                    _shouldSkip = true;
                }
            }
        });
        return _shouldSkip;
    }
}
function isWatchOrUseFunction(fnName) {
    return fnName === 'watch'
        || fnName === 'unref'
        || fnName === 'triggerRef'
        || fnName === 'isRef'
        || (0, language_core_1.hyphenateAttr)(fnName).startsWith('use-');
}
function isTopLevelArgOrArrayTopLevelItemItem(ts, node, pos) {
    for (const arg of node.arguments) {
        if (pos >= arg.getFullStart() && pos <= arg.getEnd()) {
            if (ts.isIdentifier(arg)) {
                return true;
            }
            if (ts.isArrayLiteralExpression(arg)) {
                for (const el of arg.elements) {
                    if (pos >= el.getFullStart() && pos <= el.getEnd()) {
                        return ts.isIdentifier(el);
                    }
                }
            }
            return false;
        }
    }
}
//# sourceMappingURL=vue-autoinsert-dotvalue.js.map