"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
    var ownKeys = function(o) {
        ownKeys = Object.getOwnPropertyNames || function (o) {
            var ar = [];
            for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
            return ar;
        };
        return ownKeys(o);
    };
    return function (mod) {
        if (mod && mod.__esModule) return mod;
        var result = {};
        if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
        __setModuleDefault(result, mod);
        return result;
    };
})();
Object.defineProperty(exports, "__esModule", { value: true });
const CompilerDOM = __importStar(require("@vue/compiler-dom"));
const codeFeatures_1 = require("../codegen/codeFeatures");
const elementEvents_1 = require("../codegen/template/elementEvents");
const templateChild_1 = require("../codegen/template/templateChild");
const vFor_1 = require("../codegen/template/vFor");
const utils_1 = require("../codegen/utils");
const formatBrackets = {
    normal: ['`${', '}`;'],
    if: ['if (', ') { }'],
    for: ['for (', ') { }'],
    // fix https://github.com/vuejs/language-tools/issues/3572
    params: ['(', ') => {};'],
    // fix https://github.com/vuejs/language-tools/issues/1210
    // fix https://github.com/vuejs/language-tools/issues/2305
    curly: ['0 +', '+ 0;'],
    event: ['() => ', ';'],
    generic: ['<', '>() => {};'],
};
const genericCommentRE = /^<!--\s*@vue-generic\s*\{(?<content>[\s\S]*)\}\s*-->$/;
const plugin = ({ modules: { typescript: ts } }) => {
    const parseds = new WeakMap();
    return {
        version: 2.2,
        getEmbeddedCodes(_fileName, ir) {
            if (!ir.template?.ast) {
                return [];
            }
            const parsed = parse(ir);
            parseds.set(ir, parsed);
            const result = [];
            for (const [id] of parsed) {
                result.push({ id, lang: 'ts' });
            }
            return result;
        },
        resolveEmbeddedCode(_fileName, ir, embeddedFile) {
            if (!embeddedFile.id.startsWith('template_inline_ts_')) {
                return;
            }
            // access template content to watch change
            void ir.template?.content;
            const parsed = parseds.get(ir);
            if (parsed) {
                const codes = parsed.get(embeddedFile.id);
                if (codes) {
                    embeddedFile.content.push(...codes);
                    embeddedFile.parentCodeId = ir.template?.lang === 'md' ? 'root_tags' : 'template';
                }
            }
        },
    };
    function parse(ir) {
        const result = new Map();
        if (!ir.template?.ast) {
            return result;
        }
        const template = ir.template;
        let i = 0;
        ir.template.ast.children.forEach(visit);
        return result;
        function visit(node) {
            if (node.type === CompilerDOM.NodeTypes.COMMENT) {
                const match = node.loc.source.match(genericCommentRE);
                if (match) {
                    const { content } = match.groups;
                    addFormatCodes(content, node.loc.start.offset + node.loc.source.indexOf('{') + 1, formatBrackets.generic);
                }
            }
            else if (node.type === CompilerDOM.NodeTypes.ELEMENT) {
                for (const prop of node.props) {
                    if (prop.type !== CompilerDOM.NodeTypes.DIRECTIVE) {
                        continue;
                    }
                    const isShorthand = prop.arg?.loc.start.offset === prop.exp?.loc.start.offset; // vue 3.4+
                    if (isShorthand) {
                        continue;
                    }
                    if (prop.arg?.type === CompilerDOM.NodeTypes.SIMPLE_EXPRESSION && !prop.arg.isStatic) {
                        addFormatCodes(prop.arg.loc.source, prop.arg.loc.start.offset, formatBrackets.normal);
                    }
                    if (prop.exp?.type === CompilerDOM.NodeTypes.SIMPLE_EXPRESSION
                        && prop.exp.constType !== CompilerDOM.ConstantTypes.CAN_STRINGIFY // style='z-index: 2' will compile to {'z-index':'2'}
                    ) {
                        if (prop.name === 'on' && prop.arg?.type === CompilerDOM.NodeTypes.SIMPLE_EXPRESSION) {
                            const ast = (0, utils_1.getTypeScriptAST)(ts, template, prop.exp.content);
                            if ((0, elementEvents_1.isCompoundExpression)(ts, ast)) {
                                addFormatCodes(prop.exp.loc.source, prop.exp.loc.start.offset, formatBrackets.event);
                            }
                            else {
                                const lines = prop.exp.content.split('\n');
                                const firstLineEmpty = lines[0].trim() === '';
                                const lastLineEmpty = lines[lines.length - 1].trim() === '';
                                if (lines.length <= 1 || (!firstLineEmpty && !lastLineEmpty)) {
                                    addFormatCodes(prop.exp.loc.source, prop.exp.loc.start.offset, formatBrackets.normal);
                                }
                                else {
                                    addFormatCodes(prop.exp.loc.source, prop.exp.loc.start.offset, ['(', ');']);
                                }
                            }
                        }
                        else if (prop.name === 'slot') {
                            addFormatCodes(prop.exp.loc.source, prop.exp.loc.start.offset, formatBrackets.params);
                        }
                        else if (prop.rawName === 'v-for') {
                            // #2586
                            addFormatCodes(prop.exp.loc.source, prop.exp.loc.start.offset, formatBrackets.for);
                        }
                        else {
                            addFormatCodes(prop.exp.loc.source, prop.exp.loc.start.offset, formatBrackets.normal);
                        }
                    }
                }
                for (const child of node.children) {
                    visit(child);
                }
            }
            else if (node.type === CompilerDOM.NodeTypes.IF) {
                for (const branch of node.branches) {
                    if (branch.condition?.type === CompilerDOM.NodeTypes.SIMPLE_EXPRESSION) {
                        addFormatCodes(branch.condition.loc.source, branch.condition.loc.start.offset, formatBrackets.if);
                    }
                    for (const childNode of branch.children) {
                        visit(childNode);
                    }
                }
            }
            else if (node.type === CompilerDOM.NodeTypes.FOR) {
                const { leftExpressionRange, leftExpressionText } = (0, vFor_1.parseVForNode)(node);
                const { source } = node.parseResult;
                if (leftExpressionRange && leftExpressionText && source.type === CompilerDOM.NodeTypes.SIMPLE_EXPRESSION) {
                    let start = leftExpressionRange.start;
                    let end = source.loc.start.offset + source.content.length;
                    while (template.content[start - 1] === ' ' || template.content[start - 1] === '(') {
                        start--;
                    }
                    while (template.content[end] === ' ' || template.content[end] === ')') {
                        end++;
                    }
                    addFormatCodes(template.content.slice(start, end), start, formatBrackets.for);
                }
                for (const child of node.children) {
                    visit(child);
                }
            }
            else if (node.type === CompilerDOM.NodeTypes.COMPOUND_EXPRESSION) {
                // {{ ... }} {{ ... }}
                for (const childNode of node.children) {
                    if (typeof childNode === 'object') {
                        visit(childNode);
                    }
                }
            }
            else if (node.type === CompilerDOM.NodeTypes.INTERPOLATION) {
                // {{ ... }}
                const [content, start] = (0, templateChild_1.parseInterpolationNode)(node, template.content);
                const lines = content.split('\n');
                const firstLineEmpty = lines[0].trim() === '';
                const lastLineEmpty = lines[lines.length - 1].trim() === '';
                if (content.includes('=>')) { // arrow function
                    if (lines.length <= 1 || (!firstLineEmpty && !lastLineEmpty)) {
                        addFormatCodes(content, start, formatBrackets.normal);
                    }
                    else {
                        addFormatCodes(content, start, ['(', ');']);
                    }
                }
                else {
                    if (lines.length <= 1 || (!firstLineEmpty && !lastLineEmpty)) {
                        addFormatCodes(content, start, formatBrackets.curly);
                    }
                    else {
                        addFormatCodes(content, start, [
                            firstLineEmpty ? '(' : '(0 +',
                            lastLineEmpty ? ');' : '+ 0);',
                        ]);
                    }
                }
            }
        }
        function addFormatCodes(code, offset, wrapper) {
            const id = 'template_inline_ts_' + i++;
            result.set(id, [
                wrapper[0],
                [
                    code,
                    'template',
                    offset,
                    codeFeatures_1.codeFeatures.format,
                ],
                wrapper[1],
            ]);
        }
    }
};
exports.default = plugin;
//# sourceMappingURL=vue-template-inline-ts.js.map