"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 VueAST = __importStar(require("vue-eslint-parser"));
const EsAST = __importStar(require("@babel/parser"));
const Utils = __importStar(require("../../../../util/src"));
const ACEsParser = __importStar(require("./esparser"));
const pkg = require('../../../../../package.json');
const CSSMediaQuery = require('css-mediaquery');
function parse(path) {
    return __awaiter(this, void 0, void 0, function* () {
        Utils.Console.info(`[v2]编译模板 [${path}]`);
        const content = FS.readFileSync(path).toString();
        const result = new ACPackTemplateResult();
        result.compilerVersion = pkg.version;
        result.compilerType = 1;
        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) {
            const ast = EsAST.parse(scriptContent, { sourceType: 'module' });
            if (ast.program.body) {
                for (const ele of ast.program.body) {
                    if (ele.type === 'ExportDefaultDeclaration') {
                        if (ele.declaration.type === 'ObjectExpression' && ele.declaration.properties) {
                            if (ele.start && ele.end && ele.declaration.start && ele.declaration.end) {
                                const exportContent = scriptContent.substring(ele.start, ele.end);
                                const objectContent = scriptContent.substring(ele.declaration.start, ele.declaration.end);
                                const newScriptContent = scriptContent.split(exportContent).join(`__falcon_render.bind(null, ${objectContent});`);
                                result.logic = uglify(newScriptContent);
                            }
                        }
                    }
                }
            }
        }
        //  解析 <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();
            const asresult = astyle.parse(ele);
            astyle.entries = asresult.entries;
            result.medias = asresult.medias;
            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;
//  压缩script段
function uglify(source) {
    //  去除注释
    const cleanCommends = (src) => {
        const commends = EsAST.parse(src).comments;
        const indexs = new Array();
        indexs.push(0);
        for (const acommend of commends) {
            indexs.push(acommend.start, acommend.end);
        }
        indexs.push(src.length);
        const _indexs = new Array();
        for (let i = 0; i < indexs.length; i += 2) {
            _indexs.push(indexs.slice(i, i + 2));
        }
        let result = '';
        for (const range of _indexs) {
            result = result + src.substring(range[0], range[1]);
        }
        return result;
    };
    //  去除换行及对每一行进行首尾trim
    const joinLines = (src) => {
        let result = '';
        const lines = src.split('\n');
        for (const aline of lines) {
            result = result + aline.trim();
        }
        return result;
    };
    let result = cleanCommends(source);
    result = joinLines(result);
    return result;
}
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;
}
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 = ACUtils.substring(content, start.line, start.column, end.line, end.column);
                                item.value = this.convert2FalconBoundExpression(Utils.ACUtils.substring(content, start.line, start.column, end.line, end.column));
                            }
                            // 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 = false;
                            }
                            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 = ACUtils.pickFuncParams(event);
                                    // item.value = params;
                                    item.value = this.convert2FalconOnEvent(event);
                                }
                            }
                            // 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 = ACUtils.substring(content, start.line, start.column, end.line, end.column);
                                value = this.convert2FalconBoundExpression(Utils.ACUtils.substring(content, start.line, start.column, end.line, end.column));
                            }
                            this.vIf = value;
                        }
                        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 = ACUtils.substring(content, start.line, start.column, end.line, end.column);
                                value = this.convert2FalconBoundExpression(Utils.ACUtils.substring(content, start.line, start.column, end.line, end.column));
                            }
                            this.vElseIf = value;
                        }
                        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 = ACUtils.substring(content, start.line, start.column, end.line, end.column);
                                value = this.convert2FalconBoundExpression(Utils.ACUtils.substring(content, start.line, start.column, end.line, end.column));
                            }
                            this.vShow = value;
                        }
                        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;
                                // this.vfor = ACUtils.substring(content, start.line, start.column, end.line, end.column);
                                this.vfor = this.convert2FalconForAttr(Utils.ACUtils.substring(content, start.line, start.column, end.line, end.column));
                            }
                        }
                    }
                    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', 'cell'].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 needBound = () => {
                    if (meta.children) {
                        return (meta.children.filter((ele) => ele.type !== 'VText')).length > 0 ? true : false;
                    }
                    return false;
                };
                const bindProcess = () => {
                    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("\\'");
                            if (encoded.length > 0) {
                                value = `${value}${plus}'${encoded}'`;
                            }
                        }
                        else if (ele.type === 'VExpressionContainer' && content) {
                            //  拼接表达式
                            value = `${value}${Utils.ACUtils.substring(content, ele.loc.start.line, ele.loc.start.column, ele.loc.end.line, ele.loc.end.column)}`;
                        }
                        //  忽略其他节点
                    });
                    if (value.length > 0) {
                        let result = value;
                        const convert = (v) => {
                            //  提取变量
                            const matched = v.match(/{{([\s\S]*?)}}/);
                            if (matched) {
                                this.textBound = true;
                                result = v.split(matched[0]).join(`${plus}${matched[1].trim()}`);
                                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 = this.convert2FalconBoundExpression(result);
                    }
                };
                const staticProcess = () => {
                    if (meta.children) {
                        let text = '';
                        for (const child of meta.children) {
                            text = `${text}${child.value}`;
                        }
                        this.text = text;
                        //  i18n
                        const i18nMatched = this.text ? this.text.match(/#{([\s\S]*?)}/) : undefined;
                        if (i18nMatched && this.text === `#{${i18nMatched[1]}}`) {
                            this.hasI18n = true;
                            this.text = i18nMatched[1].trim();
                        }
                    }
                };
                if (needBound()) {
                    bindProcess(); //  带有表达式的场景需编译成表达式形式
                }
                else {
                    staticProcess(); //  字面常量场景仅需直接填充字面常量（优化native处理性能）
                }
            }
        }
    }
    convert2FalconExpression(expression) {
        if (expression) {
            const parser = new ACEsParser.default();
            const converts = parser.parserExpression(expression);
            if (converts) {
                return parser.convertExpession(expression, converts);
            }
        }
        return expression;
    }
    convert2FalconBoundExpression(expression) {
        if (expression) {
            return `return ${this.convert2FalconExpression(expression)};`;
        }
        return expression;
    }
    convert2FalconOnEvent(expression) {
        const falconExpression = this.convert2FalconExpression(expression);
        if (falconExpression) {
            const ast = EsAST.parseExpression(falconExpression);
            if (ast.type === 'CallExpression') {
                const callAst = ast;
                const callee = callAst.callee ? falconExpression.substring((callAst.callee.start), (callAst.callee.end)) : '';
                const args = new Array();
                callAst.arguments.forEach(ele => {
                    const arg = falconExpression.substring((ele.start), (ele.end));
                    if (arg) {
                        args.push(arg);
                    }
                });
                const events = [callee, '.bind(', ['this', ...args].join(','), ')'];
                return events.join('');
            }
        }
        return undefined;
    }
    convert2FalconForAttr(expression) {
        if (expression) {
            const forattr = new ACParseForAttr();
            const ast = EsAST.parseExpression(expression);
            if (ast.left) {
                if (ast.left.type === 'Identifier') {
                    forattr.item = ast.left.name;
                }
                else if (ast.left.type === 'SequenceExpression') {
                    if (ast.left.expressions.length === 2) {
                        forattr.item = ast.left.expressions[0].name;
                        forattr.index = ast.left.expressions[1].name;
                    }
                }
            }
            const right = ast.right && ast.right.start && ast.right.end ? expression.substring(ast.right.start, ast.right.end) : undefined;
            if (right) {
                forattr.items = this.convert2FalconBoundExpression(right);
            }
            return forattr;
        }
        return undefined;
    }
}
exports.ACParseStruct = ACParseStruct;
class ACParseForAttr {
}
exports.ACParseForAttr = ACParseForAttr;
class ACParseStyle {
    parse(meta) {
        const entries = new Array();
        const medias = new Array();
        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') {
                        entries.push(new ACParseStyleEntry(rule));
                    }
                    else if (rule.type && rule.type === 'media') {
                        if (rule.rules) {
                            const query = new ACMediaQuery();
                            query.clause = CSSMediaQuery.parse(rule.media);
                            const style = new ACParseStyle();
                            style.entries = new Array();
                            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);
                                    style.entries.push(entry);
                                }
                            }
                            query.style = style.entries.length > 0 ? style : undefined;
                            medias.push(query);
                        }
                    }
                }
            }
        }
        for (let x = 0; x < entries.length; x++) {
            const ent = entries[x];
            for (let y = 0; y < medias.length; y++) {
                const med = medias[y];
                const matched = med.style.entries.filter((value) => value.key === ent.key);
                if (matched && matched.length > 0) {
                    ent.media = y;
                    break;
                }
            }
        }
        return {
            entries: (entries.length > 0 ? entries : undefined),
            medias: (medias.length > 0 ? medias : undefined)
        };
    }
}
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;
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 ACMediaQuery {
}
exports.ACMediaQuery = ACMediaQuery;
class ACPackTemplateResult {
}
exports.ACPackTemplateResult = ACPackTemplateResult;
//# sourceMappingURL=parser.js.map