"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 });
exports.create = create;
const language_core_1 = require("@vue/language-core");
const html = __importStar(require("vscode-html-languageservice"));
const nameCasing_1 = require("../nameCasing");
const utils_1 = require("../utils");
function create({ getComponentNames, getElementNames, getComponentMeta }) {
    return {
        name: 'vue-missing-props-hints',
        capabilities: {
            inlayHintProvider: {},
        },
        create(context) {
            let intrinsicElementNames;
            return {
                async provideInlayHints(document, range, cancellationToken) {
                    const info = (0, utils_1.resolveEmbeddedCode)(context, document.uri);
                    if (info?.code.id !== 'template') {
                        return;
                    }
                    const enabled = await context.env.getConfiguration?.('vue.inlayHints.missingProps') ?? false;
                    if (!enabled) {
                        return;
                    }
                    const scanner = getScanner(context, document);
                    if (!scanner) {
                        return;
                    }
                    const result = [];
                    const attrNameCasing = await (0, nameCasing_1.getAttrNameCasing)(context, info.script.id);
                    const components = await getComponentNames(info.root.fileName) ?? [];
                    const componentProps = new Map();
                    intrinsicElementNames ??= new Set(await getElementNames(info.root.fileName) ?? []);
                    let token;
                    let current;
                    while ((token = scanner.scan()) !== html.TokenType.EOS) {
                        if (token === html.TokenType.StartTag) {
                            const tagName = scanner.getTokenText();
                            const tagOffset = scanner.getTokenOffset();
                            const checkTag = tagName.includes('.')
                                ? tagName
                                : components.find(component => component === tagName || (0, language_core_1.hyphenateTag)(component) === tagName);
                            if (intrinsicElementNames.has(tagName) || !checkTag) {
                                continue;
                            }
                            if (tagOffset < document.offsetAt(range.start)) {
                                continue;
                            }
                            if (tagOffset > document.offsetAt(range.end)) {
                                break;
                            }
                            if (!componentProps.has(checkTag)) {
                                if (cancellationToken.isCancellationRequested) {
                                    break;
                                }
                                componentProps.set(checkTag, ((await getComponentMeta(info.root.fileName, checkTag))?.props ?? [])
                                    .filter(prop => prop.required));
                            }
                            current = {
                                unburnedRequiredProps: [...componentProps.get(checkTag)],
                                labelOffset: scanner.getTokenOffset() + scanner.getTokenLength(),
                            };
                        }
                        else if (token === html.TokenType.AttributeName) {
                            if (current) {
                                let attrText = scanner.getTokenText();
                                if (attrText === 'v-bind') {
                                    current.unburnedRequiredProps = [];
                                }
                                else {
                                    // remove modifiers
                                    if (attrText.includes('.')) {
                                        attrText = attrText.split('.')[0];
                                    }
                                    // normalize
                                    if (attrText.startsWith('v-bind:')) {
                                        attrText = attrText.slice('v-bind:'.length);
                                    }
                                    else if (attrText.startsWith(':')) {
                                        attrText = attrText.slice(':'.length);
                                    }
                                    else if (attrText.startsWith('v-model:')) {
                                        attrText = attrText.slice('v-model:'.length);
                                    }
                                    else if (attrText === 'v-model') {
                                        attrText = 'modelValue'; // TODO: support for experimentalModelPropName?
                                    }
                                    else if (attrText.startsWith('v-on:')) {
                                        attrText = 'on-' + (0, language_core_1.hyphenateAttr)(attrText.slice('v-on:'.length));
                                    }
                                    else if (attrText.startsWith('@')) {
                                        attrText = 'on-' + (0, language_core_1.hyphenateAttr)(attrText.slice('@'.length));
                                    }
                                    current.unburnedRequiredProps = current.unburnedRequiredProps.filter(prop => {
                                        return attrText !== prop.name
                                            && attrText !== (0, language_core_1.hyphenateAttr)(prop.name);
                                    });
                                }
                            }
                        }
                        else if (token === html.TokenType.StartTagSelfClose || token === html.TokenType.StartTagClose) {
                            if (current) {
                                for (const requiredProp of current.unburnedRequiredProps) {
                                    result.push({
                                        label: requiredProp.name,
                                        paddingLeft: true,
                                        position: document.positionAt(current.labelOffset),
                                        kind: 2,
                                        textEdits: [{
                                                range: {
                                                    start: document.positionAt(current.labelOffset),
                                                    end: document.positionAt(current.labelOffset),
                                                },
                                                newText: ` :${attrNameCasing === 0 /* AttrNameCasing.Kebab */ ? (0, language_core_1.hyphenateAttr)(requiredProp.name) : requiredProp.name}=`,
                                            }],
                                    });
                                }
                                current = undefined;
                            }
                        }
                    }
                    return result;
                },
            };
        },
    };
    function getScanner(context, document) {
        if (document.languageId === 'html') {
            return context.inject('html/languageService').createScanner(document.getText());
        }
        else {
            const pugDocument = context.inject('pug/pugDocument', document);
            if (pugDocument) {
                return context.inject('pug/languageService').createScanner(pugDocument);
            }
        }
    }
}
//# sourceMappingURL=vue-missing-props-hints.js.map