<commit_before><!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
    <textarea id="t1" style="width:500px;height:300px;">
<div id="app">
    <p style="color:red">姓名：{{user.name}}</p>
    <p>年龄：{{user.age}}</p>
</div>
    </textarea>
    <button id="b1">render一下</button>
    <textarea id="t2" style="width:500px;height:300px;">
window.app = new Vue({
    el: '#app',
    data: {
        user: {
            name: 'youngwind',
            age: 25
        },
        school: 'bupt',
        major: 'computer'
    }
});

// window.app.data.user.name = "test";
// window.app.data.school = "test";
    </textarea>
    <button id="b2">eval一下</button>
    <hr/>
    <h3>Result:</h3>
    <div id="result">

    </div>

    <script>
    // Vue class region
    {
        let scope = {}; // exported class refs
        
        // inner scope(Observer)
        {
            // private field keys
            const $$propWatchHash = Symbol('propWatchHash');
            const $$parent = Symbol('parent');
            const $$parentPath = Symbol('parentPath');

            class Observer {
                constructor(data, parent, parentPath) {
                    this[$$propWatchHash] = {};
                    this[$$parent] = parent;
                    this[$$parentPath] = parentPath;

                    // 递归转化
                    for (let key of Object.keys(data)) {
                        if (typeof data[key] === "object") {
                            data[key] = new Observer(data[key], this, key);
                        }
                    }
                    this.data = new Proxy(data, {
                        get: (obj, prop) => {
                            if (prop === $$propWatchHash)
                                return this[$$propWatchHash];

                            if (obj[prop] instanceof Observer)
                                return obj[prop].data;
                            else
                                return obj[prop];
                        },
                        set: (obj, prop, value) => {
                            console.log(`try to update ${prop}`);

                            if (typeof value === "object")
                                obj[prop] = new Observer(value, this);
                            else
                                obj[prop] = value;

                            if (this[$$propWatchHash][prop] != null) {
                                this[$$propWatchHash][prop](value);
                            }

                            // 判断上层监听
                            let parentPath = this[$$parentPath];
                            let parent = this[$$parent];
                            while (parent != null) {
                                if (parent[$$propWatchHash][parentPath] != null) {
                                    parent[$$propWatchHash][parentPath](parent.data[parentPath]);
                                }
                                parentPath = parent[$$parentPath];
                                parent = parent[$$parent];
                            }
                        }
                    });
                }

                $watch(prop, callback) {
                    let path = prop.split('.');
                    let target = this.data;
                    let i = 0;
                    while (i < path.length - 1) {
                        target = target[path[i]];
                        i++;
                    }
                    target[$$propWatchHash][path[i]] = callback;
                }
            }
            // export to parent scope
            scope.Observer = Observer;
        }

        // inner scope(SimpleVDOM)
        {
            // private field keys
            const $$children = Symbol('children');
            const $$data = Symbol('data');
            const $$dom = Symbol('dom');
            // private method keys
            const $$parse = Symbol('parse');

            class SimpleVDOM {
                constructor(dom, data) {
                    this[$$children] = [];
                    this[$$data] = data;
                    this[$$dom] = dom;
                    this[$$parse](dom);
                }

                [$$parse](dom) {
                    // pure text
                    if (dom.nodeType === 3) {
                        this[$$children] = node.textContent;
                        // set listener
                        let matches = node.textContent.match(/\{\{[^(\{\{)|(\}\})]+?\}\}/gm);
                        if (matches == null) return;
                        let propSet = new Set();
                        for (let vars of matches) {
                            let v = vars.match(/\{\{(.+)\}\}/)[1];
                            this[$$data].$watch(v.trim(), () => {
                                console.log(`${v.trim()} has changed`);
                                this.render();
                                });
                            }
                        }
                        return;
                    }
                    // dom
                    else {
                        for (let node of dom.childNodes) {
                            this[$$children].push(new SimpleVDOM(node, this[$$data]));
                        }
                    }
                }
        
                render() {
                    // pure text
                    if (this[$$dom].nodeType === 3) {
                        // data helper
                        let dataHelper = (prop) => {
                            let paths = prop.split('.');
                            let val = this[$$data].data;
                            for (let path of paths) {
                                val = val[path];
                            }
                            return val;
                        }

                        let result = this[$$children];

                        let matches = result.match(/\{\{(.+?)\}\}/gm);
                        if (matches == null) return result;
                        for (let vars of matches) {
                            let v = vars.match(/\{\{(.+)\}\}/)[1];
                            result = result.replace(`${vars}`, dataHelper(v.trim()));
                        }
                        return result;
                    }
                    // dom
                    else {
                        for (let child of this[$$children]) {
                            child.render();
                        }
                    }
                }
            }
            //export to parent scope
            scope.SimpleVDOM = SimpleVDOM;
        }

        // inner scope(Vue)
        {
            // import defined class
            const SimpleVDom = scope.SimpleVDOM;
            const Observer = scope.Observer;
            
            // private field keys
            const $$vdom = Symbol('vdom');
            
            class Vue {
                constructor(options) {
                    if (options == null)
                        throw(new Error('options not found'));
                    if (typeof options !== "object")
                        throw(new Error('options should be an object'));
                    if (options.el == null)
                        throw(new Error('el not found'));
                    if (options.data == null)
                        throw(new Error('data not found'));
                    if (typeof options.data !== "object")
                        throw(new Error('data should be an object'));
                    
                    let target = document.querySelector(options.el);
                    if (target == null)
                        throw(new Error('element not exist'));
                    
                    let obs = new Observer(options.data);
                    this.data = obs.data;
                    this[$$vdom] = new SimpleVDom(target, obs);
                }
            }
            // export to global
            window.Vue = Vue;
        }
    }

    window.onload = () => {
        document.querySelector('#b1').onclick = () => {
            document.querySelector('#result').innerHTML = document.querySelector('#t1').value;
        }
        document.querySelector('#b2').onclick = () => {
            eval(document.querySelector('#t2').value);
        }<commit_msg>Refactor<commit_after><!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
    <textarea id="t1" style="width:500px;height:300px;">
<div id="app">
    <p style="color:red">姓名：{{{ user.name  }}}</p>
    <p>年龄：{{user.age}}</p>
</div>
    </textarea>
    <button id="b1">render一下</button>
    <textarea id="t2" style="width:500px;height:300px;">
window.app = new Vue({
    el: '#app',
    data: {
        user: {
            name: 'youngwind',
            age: 25
        },
        school: 'bupt',
        major: 'computer'
    }
});

// window.app.data.user.name = "test";
// window.app.data.school = "test";
    </textarea>
    <button id="b2">eval一下</button>
    <hr/>
    <h3>Result:</h3>
    <div id="result">

    </div>

    <script>
    // Vue class region
    {
        let scope = {}; // exported class refs
        
        // inner scope(Observer)
        {
            // private field keys
            const $$propWatchHash = Symbol('propWatchHash');
            const $$parent = Symbol('parent');
            const $$parentPath = Symbol('parentPath');

            class Observer {
                constructor(data, parent, parentPath) {
                    this[$$propWatchHash] = {};
                    this[$$parent] = parent;
                    this[$$parentPath] = parentPath;

                    // 递归转化
                    for (let key of Object.keys(data)) {
                        if (typeof data[key] === "object") {
                            data[key] = new Observer(data[key], this, key);
                        }
                    }
                    this.data = new Proxy(data, {
                        get: (obj, prop) => {
                            if (prop === $$propWatchHash)
                                return this[$$propWatchHash];

                            if (obj[prop] instanceof Observer)
                                return obj[prop].data;
                            else
                                return obj[prop];
                        },
                        set: (obj, prop, value) => {
                            console.log(`try to update ${prop}`);

                            if (typeof value === "object")
                                obj[prop] = new Observer(value, this);
                            else
                                obj[prop] = value;

                            if (this[$$propWatchHash][prop] != null) {
                                this[$$propWatchHash][prop](value);
                            }

                            // 判断上层监听
                            let parentPath = this[$$parentPath];
                            let parent = this[$$parent];
                            while (parent != null) {
                                if (parent[$$propWatchHash][parentPath] != null) {
                                    parent[$$propWatchHash][parentPath](parent.data[parentPath]);
                                }
                                parentPath = parent[$$parentPath];
                                parent = parent[$$parent];
                            }
                        }
                    });
                }

                $watch(prop, callback) {
                    let path = prop.split('.');
                    let target = this.data;
                    let i = 0;
                    while (i < path.length - 1) {
                        target = target[path[i]];
                        i++;
                    }
                    target[$$propWatchHash][path[i]] = callback;
                }
            }
            // export to parent scope
            scope.Observer = Observer;
        }

        // inner scope(SimpleVDOM)
        {
            // private field keys
            const $$children = Symbol('children');
            const $$data = Symbol('data');
            const $$dom = Symbol('dom');
            // private method keys
            const $$parse = Symbol('parse');

            class SimpleVDOM {
                constructor(dom, data) {
                    this[$$children] = [];
                    this[$$data] = data;
                    this[$$dom] = dom;
                    this[$$parse](dom);
                }

                [$$parse](dom) {
                    // pure text
                    if (dom.nodeType === 3) {
                        this[$$children] = dom.textContent;
                        // set listener
                        let matches = dom.textContent.match(/\{\{[^(\{\{)|(\}\})]+?\}\}/gm);
                        if (matches == null) return;
                        let paths = [];
                        for (let vars of matches) {
                            let v = vars.match(/\{\{(.+)\}\}/)[1].trim();
                            this[$$children] = this[$$children].replace(vars, `{{${v}}}`);

                            if (paths.includes(v)) continue;
                            paths.push(v);
                            this[$$data].$watch(v, () => {
                                console.log(`begin to rerender ${v}`);
                                this.render();
                            });
                        }
                        return;
                    }
                    // dom
                    else {
                        for (let node of dom.childNodes) {
                            this[$$children].push(new SimpleVDOM(node, this[$$data]));
                        }
                    }
                }
        
                render() {
                    // pure text
                    if (this[$$dom].nodeType === 3) {
                        // data helper
                        let dataHelper = (prop) => {
                            let paths = prop.split('.');
                            let val = this[$$data].data;
                            for (let path of paths) {
                                val = val[path];
                            }
                            return val;
                        }

                        let result = this[$$children];

                        let matches = result.match(/\{\{[^(\{\{)|(\}\})]+?\}\}/gm);
                        if (matches == null) return result;
                        for (let vars of matches) {
                            let v = vars.match(/\{\{([^(\{\{)|(\}\})]+?)\}\}/)[1];
                            result = result.replace(new RegExp(vars, 'g'), dataHelper(v));
                        }
                        this[$$dom].textContent = result;
                    }
                    // dom
                    else {
                        for (let child of this[$$children]) {
                            child.render();
                        }
                    }
                }
            }
            //export to parent scope
            scope.SimpleVDOM = SimpleVDOM;
        }

        // inner scope(Vue)
        {
            // import defined class
            const SimpleVDom = scope.SimpleVDOM;
            const Observer = scope.Observer;
            
            // private field keys
            const $$vdom = Symbol('vdom');
            
            class Vue {
                constructor(options) {
                    if (options == null)
                        throw(new Error('options not found'));
                    if (typeof options !== "object")
                        throw(new Error('options should be an object'));
                    if (options.el == null)
                        throw(new Error('el not found'));
                    if (options.data == null)
                        throw(new Error('data not found'));
                    if (typeof options.data !== "object")
                        throw(new Error('data should be an object'));
                    
                    let target = document.querySelector(options.el);
                    if (target == null)
                        throw(new Error('element not exist'));
                    
                    let obs = new Observer(options.data);
                    this.data = obs.data;
                    this[$$vdom] = new SimpleVDom(target, obs);
                    this[$$vdom].render();
                }
            }
            // export to global
            window.Vue = Vue;
        }
    }

    window.onload = () => {
        document.querySelector('#b1').onclick = () => {
            document.querySelector('#result').innerHTML = document.querySelector('#t1').value;
        }
        document.querySelector('#b2').onclick = () => {
            eval(document.querySelector('#t2').value);
        }
{'fraction_non_alphanumeric': 0.1271315113291287, 'fraction_numerical': 0.003620649380985751, 'mean_word_length': 0.8783591093561478, 'pattern_counts': {'":': 0, '<': 61, '<?xml version=': 0, '>': 73, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 14, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2542695', 'n_tokens_mistral': 4192, 'n_tokens_neox': 3900, 'n_words': 847}