"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
var __importStar = (this && this.__importStar) || function (mod) {
    if (mod && mod.__esModule) return mod;
    var result = {};
    if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
    result["default"] = mod;
    return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
const CSS = __importStar(require("css"));
const VueParser = __importStar(require("vue-parser"));
const FS = __importStar(require("fs"));
const PATH = __importStar(require("path"));
const Utils = __importStar(require("../../../../util/src"));
const VueAST = __importStar(require("vue-eslint-parser"));
const EsAST = __importStar(require("@babel/parser"));
const pkg = require('../../../../../package.json');
function parse(path) {
    return __awaiter(this, void 0, void 0, function* () {
        Utils.Console.info(`[v1]编译模板 [${path}]`);
        const content = FS.readFileSync(path).toString();
        const result = new ACPackTemplateResult();
        result.compilerVersion = pkg.version;
        result.compilerType = 0;
        let matched = content.match(/<template>([\s\S]*)<\/template>/);
        const templateContent = matched ? matched[0] : '';
        matched = content.match(/<script>([\s\S]*)<\/script>/);
        const scriptContent = matched ? matched[1] : undefined;
        //  解析 <script>
        if (scriptContent) {
            result.logic = scriptContent;
            const ast = EsAST.parse(scriptContent, { sourceType: 'module' });
            if (ast.program.body) {
                ast.program.body.forEach(ele => {
                    if (ele.type === 'ExportDefaultDeclaration') {
                        if (ele.declaration.type === 'ObjectExpression' && ele.declaration.properties) {
                            ele.declaration.properties.forEach((ele) => {
                                if (ele.key.type === 'Identifier') {
                                    if (ele.key.name === 'beforeCreate') {
                                        result.hasBeforeCreate = true;
                                    }
                                }
                            });
                        }
                    }
                });
            }
        }
        //  解析 <template>
        const program = VueAST.parse(templateContent, {});
        const struct = new ACParseStruct(program.templateBody, templateContent);
        struct.tag = 'body';
        result.struct = struct;
        //  解析 <style>
        let styles = new Array();
        styles = styles.concat(pickDependentStyles(path));
        styles.push(CSS.parse(trimming(VueParser.parse(content, 'style'), 'style')));
        styles.forEach(ele => {
            const astyle = new ACParseStyle(ele);
            if (result.style) {
                if (result.style.entries) {
                    result.style.entries = result.style.entries.concat(astyle.entries ? astyle.entries : []);
                }
                else {
                    result.style.entries = astyle.entries;
                }
            }
            else {
                result.style = astyle;
            }
        });
        const finals = new Array();
        if (result.style && result.style.entries) {
            result.style.entries.forEach(ele => {
                let found = -1;
                for (let index = 0; index < finals.length; index++) {
                    const element = finals[index];
                    if (ele.key === element.key) {
                        found = index;
                        break;
                    }
                }
                if (found !== -1) {
                    //  已存在 - 层叠
                    finals[found].assign(ele);
                }
                else {
                    //  不存在 - 追加
                    finals.push(ele);
                }
            });
        }
        if (result.style && finals.length > 0) {
            result.style.entries = finals;
        }
        return Promise.resolve(result);
    });
}
exports.parse = parse;
function trimming(content, key) {
    const splits = content.split('tslint:enable');
    if (splits.length > 1) {
        content = content.replace(`${splits[0]}tslint:enable`, '');
    }
    let cursor = -1;
    const lines = content.split('\n');
    for (let index = 0; index < lines.length; index++) {
        const element = lines[index];
        if (element.indexOf(`<${key}`) !== -1) {
            cursor = index;
            break;
        }
    }
    return lines.slice(cursor + 1).join('\n');
}
function pickDependentStyles(path) {
    const content = FS.readFileSync(path).toString();
    const root = PATH.dirname(path);
    const depends = content.split('\n').filter(value => {
        const trimming = value.split(' ').join('');
        return trimming.indexOf('<stylesrc=') !== -1 ? true : false;
    });
    const deppaths = new Array();
    depends.forEach(value => {
        let matched = value.match(/src="([\s\S]*)"/);
        if (!matched) {
            matched = value.match(/src="([\s\S]*)"/);
        }
        if (matched) {
            deppaths.push(PATH.resolve(root, matched[1]));
        }
    });
    const styles = new Array();
    deppaths.forEach(value => {
        styles.push(CSS.parse(FS.readFileSync(value).toString()));
    });
    return styles;
}
function pickBindEnvValue(text) {
    const matched = text.trim().match(/falcon_env\(([\s\S]*)\)/);
    return matched ? matched[1].trim() : undefined;
}
class ACParseForAttr {
}
exports.ACParseForAttr = ACParseForAttr;
class ACParseStruct {
    constructor(meta, content) {
        this.textBound = false;
        this.vElse = false;
        if (meta) {
            this.tag = meta.rawName; //  name字段为小写，rawName为原始字符串
            this.nid = Utils.Tool.uuid();
            //  attribute
            const attrs = new ACParseEntry();
            attrs.entries = new Array();
            meta.startTag.attributes.forEach((ele) => {
                if (ele.type === 'VAttribute') {
                    if (ele.directive) {
                        //  运算类
                        if (ele.key.name.name === 'bind') {
                            const item = new ACParseItem();
                            if (ele.key.argument && ele.key.argument.type === 'VIdentifier') {
                                item.key = `${Utils.ACUtils.dash2hump(ele.key.argument.rawName).trim()}`;
                                item.bound = true;
                            }
                            if (ele.value && ele.value.type === 'VExpressionContainer' && ele.value.expression) {
                                const start = ele.value.expression.loc.start;
                                const end = ele.value.expression.loc.end;
                                item.value = Utils.ACUtils.substring(content, start.line, start.column, end.line, end.column);
                                if (item.value) {
                                    const envValue = pickBindEnvValue(item.value);
                                    if (envValue) {
                                        item.value = envValue;
                                        item.boundType = ACParseItemBoundType.Env;
                                    }
                                }
                            }
                            // tslint:disable-next-line:no-unused-expression
                            attrs.entries && attrs.entries.push(item);
                        }
                        else if (ele.key.name.name === 'on') {
                            const item = new ACParseItem();
                            if (ele.key.argument && ele.key.argument.type === 'VIdentifier') {
                                item.key = `${Utils.ACUtils.dash2hump(ele.key.argument.rawName).trim()}`;
                                item.isEvent = true;
                                item.bound = true;
                            }
                            if (ele.value && ele.value.type === 'VExpressionContainer' && ele.value.expression) {
                                const start = ele.value.expression.loc.start;
                                const end = ele.value.expression.loc.end;
                                const event = Utils.ACUtils.substring(content, start.line, start.column, end.line, end.column);
                                if (event && item.key) {
                                    const params = Utils.ACUtils.pickFuncParams(event);
                                    item.value = params;
                                    //  模板二期功能：完整提取事件信息
                                    const eventInfo = new Object(null);
                                    eventInfo.eventName = item.key;
                                    eventInfo.funcParams = new Array();
                                    const funcInfo = EsAST.parseExpression(event);
                                    if (funcInfo.type === 'CallExpression') {
                                        if (funcInfo.callee.type === 'Identifier') {
                                            eventInfo.funcName = funcInfo.callee.name;
                                        }
                                        if (funcInfo.arguments) {
                                            funcInfo.arguments.forEach(ele => {
                                                if (ele.loc) {
                                                    const start = ele.loc.start;
                                                    const end = ele.loc.end;
                                                    eventInfo.funcParams.push(Utils.ACUtils.substring(event, start.line, start.column, end.line, end.column));
                                                }
                                            });
                                        }
                                    }
                                    else if (funcInfo.type === 'Identifier') {
                                        eventInfo.funcName = funcInfo.name;
                                    }
                                    if (eventInfo.eventName) {
                                        item.extraParam = eventInfo;
                                    }
                                }
                            }
                            // tslint:disable-next-line:no-unused-expression
                            attrs.entries && attrs.entries.push(item);
                        }
                        else if (ele.key.name.name === 'if') {
                            let value = '';
                            if (content && ele.value) {
                                const start = ele.value.expression.loc.start;
                                const end = ele.value.expression.loc.end;
                                value = Utils.ACUtils.substring(content, start.line, start.column, end.line, end.column);
                            }
                            this.vIf = value;
                            if (this.vIf) {
                                const envValue = pickBindEnvValue(this.vIf);
                                if (envValue) {
                                    this.vIf = envValue;
                                    this.vIfType = ACParseItemBoundType.Env;
                                }
                            }
                        }
                        else if (ele.key.name.name === 'else-if') {
                            let value = '';
                            if (content && ele.value) {
                                const start = ele.value.expression.loc.start;
                                const end = ele.value.expression.loc.end;
                                value = Utils.ACUtils.substring(content, start.line, start.column, end.line, end.column);
                            }
                            this.vElseIf = value;
                            if (this.vElseIf) {
                                const envValue = pickBindEnvValue(this.vElseIf);
                                if (envValue) {
                                    this.vElseIf = envValue;
                                    this.vElseIfType = ACParseItemBoundType.Env;
                                }
                            }
                        }
                        else if (ele.key.name.name === 'else') {
                            this.vElse = true;
                        }
                        else if (ele.key.name.name === 'show') {
                            let value = '';
                            if (content && ele.value) {
                                const start = ele.value.expression.loc.start;
                                const end = ele.value.expression.loc.end;
                                value = Utils.ACUtils.substring(content, start.line, start.column, end.line, end.column);
                            }
                            this.vShow = value;
                            if (this.vShow) {
                                const envValue = pickBindEnvValue(this.vShow);
                                if (envValue) {
                                    this.vShowType = ACParseItemBoundType.Env;
                                    this.vShow = envValue;
                                }
                            }
                        }
                        else if (ele.key.name.name === 'for') {
                            if (ele.value && ele.value.type === 'VExpressionContainer' && ele.value.expression) {
                                const start = ele.value.expression.loc.start;
                                const end = ele.value.expression.loc.end;
                                const forExpression = Utils.ACUtils.substring(content, start.line, start.column, end.line, end.column);
                                const split4in = forExpression === null || forExpression === void 0 ? void 0 : forExpression.split(' in ');
                                if (split4in && split4in.length > 1) {
                                    const forAttr = new ACParseForAttr();
                                    const forItems = split4in[1].trim();
                                    if (pickBindEnvValue(forItems)) {
                                        forAttr.items = pickBindEnvValue(forItems);
                                        this.vforType = ACParseItemBoundType.Env;
                                    }
                                    else {
                                        forAttr.items = forItems;
                                    }
                                    const split4item = split4in[0].trim().split('(').join('').split(')').join('').split(',');
                                    if (split4item.length > 1) {
                                        forAttr.item = split4item[0].trim();
                                        forAttr.index = split4item[1].trim();
                                    }
                                    else {
                                        forAttr.item = split4item[0].trim();
                                    }
                                    this.vfor = forAttr;
                                }
                            }
                        }
                    }
                    else {
                        //  值传类
                        const item = new ACParseItem();
                        item.key = Utils.ACUtils.dash2hump(ele.key.rawName).trim();
                        if (ele.value) {
                            //  针对内联样式进行驼峰转换
                            if (item.key === 'style' && ele.value.value) {
                                const inlineStyle = new ACParseEntry();
                                inlineStyle.entries = new Array();
                                ele.value.value.split(';').forEach((st) => {
                                    const astyle = new ACParseItem();
                                    const asplit = st.split(':');
                                    astyle.key = asplit.length > 0 ? Utils.ACUtils.dash2hump(asplit[0]).trim() : undefined;
                                    astyle.value = asplit.length > 1 ? asplit[1].trim() : undefined;
                                    // tslint:disable-next-line:no-unused-expression
                                    (astyle.key && astyle.value && inlineStyle.entries) && inlineStyle.entries.push(astyle);
                                });
                                // tslint:disable-next-line:no-unused-expression
                                (inlineStyle.entries.length > 0) && (this.inlineStyle = inlineStyle);
                            }
                            else {
                                item.value = ele.value.value;
                            }
                        }
                        // tslint:disable-next-line:no-unused-expression
                        attrs.entries && attrs.entries.push(item);
                    }
                }
            });
            if (attrs.entries.length > 0) {
                this.attributes = attrs;
            }
            //  children
            if (['template', 'div', 'scroller', 'list', 'slider'].indexOf(meta.name) !== -1) {
                //  只有容器节点支持子节点
                meta.children.forEach((ele) => {
                    if (ele.type === 'VElement') {
                        if (!this.children) {
                            this.children = new Array();
                        }
                        this.children.push(new ACParseStruct(ele, content));
                    }
                });
            }
            //  text
            if (meta.type === 'VElement' && meta.name === 'text') {
                //  仅处理text标签
                const plus = `^^CUBE-PLUS-FALCON^^`;
                let value = '';
                meta.children.forEach((ele) => {
                    if (ele.type === 'VText') {
                        //  拼接文本值
                        let encoded = ele.value.split('\\').join('\\\\');
                        encoded = encoded.split("'").join("\\'");
                        value = `${value}${plus}'${encoded}'`;
                    }
                    else if (ele.type === 'VExpressionContainer' && content) {
                        //  拼接表达式
                        //  模板一期功能：提取falcon_env()数据路径，表达式内仅允许同源路径，匹配到env时认为该表达式内全部为环境数据源
                        let expression = Utils.ACUtils.substring(content, ele.loc.start.line, ele.loc.start.column, ele.loc.end.line, ele.loc.end.column);
                        if (expression) {
                            const envValue = pickBindEnvValue(expression);
                            if (envValue) {
                                expression = `{{${envValue.trim()}}}`;
                                this.textBoundType = ACParseItemBoundType.Env;
                            }
                        }
                        value = `${value}${expression}`;
                    }
                    //  忽略其他节点
                });
                if (value.length > 0) {
                    let result = value;
                    const convert = (v) => {
                        //  提取变量
                        const matched = v.match(/{{([\s\S]*?)}}/);
                        if (matched) {
                            result = v.split(matched[0]).join(`${plus}${matched[1].trim()}`);
                            this.textBound = true;
                            convert(result);
                        }
                    };
                    convert(result);
                    //  转移操作符
                    result = result.startsWith(plus) ? result.substr(plus.length) : result;
                    if (result.indexOf(plus) !== -1) {
                        result = result.split(plus).join(' + ');
                    }
                    this.text = result;
                }
            }
        }
    }
}
exports.ACParseStruct = ACParseStruct;
class ACParseStyle {
    constructor(meta) {
        if (meta.stylesheet) {
            if (!(meta.stylesheet.parsingErrors && meta.stylesheet.parsingErrors.length > 0)) {
                for (let index = 0; index < meta.stylesheet.rules.length; index++) {
                    const rule = meta.stylesheet.rules[index];
                    if (rule.type && rule.type === 'rule') {
                        if (!this.entries) {
                            this.entries = new Array();
                        }
                        this.entries.push(new ACParseStyleEntry(rule));
                    }
                    else if (rule.type && rule.type === 'media') {
                        const media = rule.media ? rule.media : '';
                        if (rule.rules) {
                            for (let index = 0; index < rule.rules.length; index++) {
                                const element = rule.rules[index];
                                if (element.type && element.type === 'rule') {
                                    const entry = new ACParseStyleEntry(element);
                                    entry.key = `${entry.key}@${media}`;
                                    if (!this.entries) {
                                        this.entries = new Array();
                                    }
                                    this.entries.push(entry);
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
exports.ACParseStyle = ACParseStyle;
class ACParseStyleEntry {
    constructor(meta) {
        if (meta) {
            if (meta.selectors) {
                this.key = meta.selectors.join(', ');
            }
            if (meta.declarations) {
                this.value = new ACParseEntry(meta.declarations);
            }
        }
    }
    assign(other) {
        if (this.value && other.value) {
            this.value.assign(other.value);
        }
    }
}
exports.ACParseStyleEntry = ACParseStyleEntry;
class ACParseEntry {
    constructor(meta) {
        if (meta) {
            for (let index = 0; index < meta.length; index++) {
                const element = meta[index];
                if (!this.entries) {
                    this.entries = new Array();
                }
                this.entries.push(new ACParseItem(element));
            }
        }
    }
    assign(other) {
        if (this.entries) {
            if (other.entries) {
                this.entries = this.entries.concat(other.entries);
                const finals = new Array();
                this.entries.forEach(value => {
                    let found = -1;
                    for (let index = 0; index < finals.length; index++) {
                        const element = finals[index];
                        if (element.key === value.key) {
                            found = index;
                            break;
                        }
                    }
                    if (found !== -1) {
                        //  已存在 - 替换
                        finals[found] = value;
                    }
                    else {
                        //  不存在 - 追加
                        finals.push(value);
                    }
                });
                this.entries = finals;
            }
        }
        else {
            this.entries = other.entries;
        }
    }
}
exports.ACParseEntry = ACParseEntry;
var ACParseItemBoundType;
(function (ACParseItemBoundType) {
    ACParseItemBoundType[ACParseItemBoundType["Normal"] = 0] = "Normal";
    ACParseItemBoundType[ACParseItemBoundType["Env"] = 1] = "Env";
})(ACParseItemBoundType = exports.ACParseItemBoundType || (exports.ACParseItemBoundType = {}));
class ACParseItem {
    constructor(meta) {
        this.bound = false;
        this.isEvent = false;
        if (meta) {
            if (meta.property) {
                this.key = Utils.ACUtils.dash2hump(meta.property);
            }
            if (meta.value) {
                this.value = meta.value;
            }
        }
    }
}
exports.ACParseItem = ACParseItem;
class ACPackTemplateResult {
}
exports.ACPackTemplateResult = ACPackTemplateResult;
//# sourceMappingURL=parser.js.map