"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.generateStyleScopedClassReferences = generateStyleScopedClassReferences;
exports.collectStyleScopedClassReferences = collectStyleScopedClassReferences;
const CompilerDOM = require("@vue/compiler-dom");
const scriptSetupRanges_1 = require("../../parsers/scriptSetupRanges");
const utils_1 = require("../utils");
function* generateStyleScopedClassReferences(ctx, withDot = false) {
    if (!ctx.emptyClassOffsets.length && !ctx.scopedClasses.length) {
        return;
    }
    yield `[`;
    for (const offset of ctx.emptyClassOffsets) {
        yield `'`;
        yield [
            '',
            'template',
            offset,
            ctx.codeFeatures.additionalCompletion,
        ];
        yield `', `;
    }
    for (const { source, className, offset } of ctx.scopedClasses) {
        yield [
            '',
            source,
            offset - (withDot ? 1 : 0),
            ctx.codeFeatures.navigation,
        ];
        yield `'`;
        // fix https://github.com/vuejs/language-tools/issues/4537
        yield* escapeString(source, className, offset, ['\\', '\'']);
        yield `'`;
        yield [
            '',
            source,
            offset + className.length,
            ctx.codeFeatures.navigationWithoutRename,
        ];
        yield `, `;
    }
    yield `] as (keyof __VLS_StyleScopedClasses)[]${utils_1.endOfLine}`;
    function* escapeString(source, className, offset, escapeTargets) {
        let count = 0;
        const currentEscapeTargets = [...escapeTargets];
        const firstEscapeTarget = currentEscapeTargets.shift();
        const splitted = className.split(firstEscapeTarget);
        for (let i = 0; i < splitted.length; i++) {
            const part = splitted[i];
            const partLength = part.length;
            if (escapeTargets.length > 0) {
                yield* escapeString(source, part, offset + count, [...currentEscapeTargets]);
            }
            else {
                yield [
                    part,
                    source,
                    offset + count,
                    ctx.codeFeatures.navigationAndAdditionalCompletion,
                ];
            }
            if (i !== splitted.length - 1) {
                yield '\\';
                yield [
                    firstEscapeTarget,
                    source,
                    offset + count + partLength,
                    ctx.codeFeatures.navigationAndAdditionalCompletion,
                ];
                count += partLength + 1;
            }
            else {
                count += partLength;
            }
        }
    }
}
function collectStyleScopedClassReferences(options, ctx, node) {
    for (const prop of node.props) {
        if (prop.type === CompilerDOM.NodeTypes.ATTRIBUTE
            && prop.name === 'class'
            && prop.value) {
            if (options.template.lang === 'pug') {
                const getClassOffset = Reflect.get(prop.value.loc.start, 'getClassOffset');
                const content = prop.value.loc.source.slice(1, -1);
                let startOffset = 1;
                for (const className of content.split(' ')) {
                    if (className) {
                        ctx.scopedClasses.push({
                            source: 'template',
                            className,
                            offset: getClassOffset(startOffset),
                        });
                    }
                    startOffset += className.length + 1;
                }
            }
            else {
                let isWrapped = false;
                const [content, startOffset] = (0, utils_1.normalizeAttributeValue)(prop.value);
                if (content) {
                    const classes = collectClasses(content, startOffset + (isWrapped ? 1 : 0));
                    ctx.scopedClasses.push(...classes);
                }
                else {
                    ctx.emptyClassOffsets.push(startOffset);
                }
            }
        }
        else if (prop.type === CompilerDOM.NodeTypes.DIRECTIVE
            && prop.arg?.type === CompilerDOM.NodeTypes.SIMPLE_EXPRESSION
            && prop.exp?.type === CompilerDOM.NodeTypes.SIMPLE_EXPRESSION
            && prop.arg.content === 'class') {
            const content = '`${' + prop.exp.content + '}`';
            const startOffset = prop.exp.loc.start.offset - 3;
            const { ts } = options;
            const ast = ts.createSourceFile('', content, 99);
            const literals = [];
            ts.forEachChild(ast, node => {
                if (!ts.isExpressionStatement(node) ||
                    !isTemplateExpression(node.expression)) {
                    return;
                }
                const expression = node.expression.templateSpans[0].expression;
                if (ts.isStringLiteralLike(expression)) {
                    literals.push(expression);
                }
                if (ts.isArrayLiteralExpression(expression)) {
                    walkArrayLiteral(expression);
                }
                if (ts.isObjectLiteralExpression(expression)) {
                    walkObjectLiteral(expression);
                }
            });
            for (const literal of literals) {
                if (literal.text) {
                    const classes = collectClasses(literal.text, literal.end - literal.text.length - 1 + startOffset);
                    ctx.scopedClasses.push(...classes);
                }
                else {
                    ctx.emptyClassOffsets.push(literal.end - 1 + startOffset);
                }
            }
            function walkArrayLiteral(node) {
                const { elements } = node;
                for (const element of elements) {
                    if (ts.isStringLiteralLike(element)) {
                        literals.push(element);
                    }
                    else if (ts.isObjectLiteralExpression(element)) {
                        walkObjectLiteral(element);
                    }
                }
            }
            function walkObjectLiteral(node) {
                const { properties } = node;
                for (const property of properties) {
                    if (ts.isPropertyAssignment(property)) {
                        const { name } = property;
                        if (ts.isIdentifier(name)) {
                            walkIdentifier(name);
                        }
                        else if (ts.isStringLiteral(name)) {
                            literals.push(name);
                        }
                        else if (ts.isComputedPropertyName(name)) {
                            const { expression } = name;
                            if (ts.isStringLiteralLike(expression)) {
                                literals.push(expression);
                            }
                        }
                    }
                    else if (ts.isShorthandPropertyAssignment(property)) {
                        walkIdentifier(property.name);
                    }
                }
            }
            function walkIdentifier(node) {
                const text = (0, scriptSetupRanges_1.getNodeText)(ts, node, ast);
                ctx.scopedClasses.push({
                    source: 'template',
                    className: text,
                    offset: node.end - text.length + startOffset
                });
            }
        }
    }
}
function collectClasses(content, startOffset = 0) {
    const classes = [];
    let currentClassName = '';
    let offset = 0;
    for (const char of (content + ' ')) {
        if (char.trim() === '') {
            if (currentClassName !== '') {
                classes.push({
                    source: 'template',
                    className: currentClassName,
                    offset: offset + startOffset
                });
                offset += currentClassName.length;
                currentClassName = '';
            }
            offset += char.length;
        }
        else {
            currentClassName += char;
        }
    }
    return classes;
}
// isTemplateExpression is missing in tsc
function isTemplateExpression(node) {
    return node.kind === 228;
}
//# sourceMappingURL=styleScopedClasses.js.map