1
0
Matheus Giovani 3 жил өмнө
parent
commit
ad95fe0abf
1 өөрчлөгдсөн 112 нэмэгдсэн , 58 устгасан
  1. 112 58
      src/core/Renderer.ts

+ 112 - 58
src/core/Renderer.ts

@@ -36,6 +36,60 @@ export enum NodePreparationResult {
     FAILED
 }
 
+export class PupperHelper {
+    constructor(
+        protected renderer: Renderer
+    ) {
+
+    }
+
+    /**
+     * 
+     * @param key The path to the data to be retrieved
+     * @param context Any additional contexts
+     * @returns 
+     */
+    public getValue(key: string, context?: Record<string, any>) {
+        let value;
+
+        // First, try from the context
+        if (context !== undefined) {
+            value = deepGetSet(context, key);
+        }
+
+        // Then try from the data itself
+        if (value === undefined) {
+            value = deepGetSet(this.renderer.getData(), key);
+        }
+
+        debug("retrieving value %s: %O", key, value);
+
+        return value;
+    }
+
+    /**
+     * Retrieves an escaped value to be displayed
+     * @param key The path to the data to be escaped
+     * @returns 
+     */
+    public escape(key: string, context?: Record<string, any>): string {
+        const text = document.createTextNode(
+            this.getValue(key, context)
+        );
+
+        return text.textContent;
+    }
+
+    /**
+     * Retrieves a literal value to be displayed
+     * @param key The path to the data to be retrieved
+     * @returns 
+     */
+    public literal<T>(key: string, context?: Record<string, any>): T {
+        return this.getValue(key, context);
+    }
+}
+
 export class Renderer {
     private static SYNTAX_REGEX = /(?: +)?\@p\:(?<command>.+)\((?<property>.+?)\)(?: +)?/;
 
@@ -65,6 +119,28 @@ export class Renderer {
      */
     public reactor: Reactor;
 
+    /**
+     * The cached helpers for this Renderer
+     */
+    public helpers: Record<string, any> & {
+        deepGetSet: (object: object, key: any, value?: any) => any;
+
+        /**
+         * The methods related to this renderer
+         */
+        $methods: Reactive.ReactiveMethods;
+
+        /**
+         * The data related to this renderer
+         */
+        $data: ProxyHandler<Reactive.ReactiveData>;
+
+        /**
+         * Pupper helpers
+         */
+        pupper: PupperHelper;
+    };
+
     /**
      * Creates a new renderer instance
      * @param template The pug compiled template function
@@ -93,72 +169,30 @@ export class Renderer {
      * @returns 
      */
     private getHelpers() {
-        const self = this;
-
-        return {
-            deepGetSet,
+        if (this.helpers === undefined) {
+            const self = this;
 
-            /**
-             * The methods related to this renderer
-             */
-            $methods: this.methods,
+            this.helpers = {
+                deepGetSet,
 
-            /**
-             * The data related to this renderer
-             */
-            $data: this.data,
-
-            /**
-             * Pupper helpers
-             */
-            pupper: class PupperHelper {
                 /**
-                 * 
-                 * @param key The path to the data to be retrieved
-                 * @param context Any additional contexts
-                 * @returns 
+                 * The methods related to this renderer
                  */
-                static getValue(key: string, context?: Record<string, any>) {
-                    let value;
-
-                    // First, try from the context
-                    if (context !== undefined) {
-                        value = deepGetSet(context, key);
-                    }
-
-                    // Then try from the data itself
-                    if (value === undefined) {
-                        value = deepGetSet(self.getData(), key);
-                    }
-
-                    debug("retrieving value %s: %O", key, value);
-
-                    return value;
-                }
+                $methods: this.methods,
 
                 /**
-                 * Retrieves an escaped value to be displayed
-                 * @param key The path to the data to be escaped
-                 * @returns 
+                 * The data related to this renderer
                  */
-                static escape(key: string, context?: Record<string, any>): string {
-                    const text = document.createTextNode(
-                        this.getValue(key, context)
-                    );
-
-                    return text.textContent;
-                }
+                $data: this.data,
 
                 /**
-                 * Retrieves a literal value to be displayed
-                 * @param key The path to the data to be retrieved
-                 * @returns 
+                 * Pupper helpers
                  */
-                static literal<T>(key: string, context?: Record<string, any>): T {
-                    return this.getValue(key, context);
-                }
-            }
-        };
+                pupper: new PupperHelper(this)
+            };
+        }
+
+        return this.helpers;
     }
 
     /**
@@ -360,6 +394,19 @@ export class Renderer {
         return true;
     }
 
+    private scopedEval(expr: string, context: Record<string, any>) {
+        const evaluator = Function.apply(
+            null,
+            [
+                ...Object.keys(context),
+                "expr",
+                `return ${expr}`
+            ]
+        );
+
+        return evaluator.apply(null, [...Object.values(context), expr]);
+    }
+
     /**
      * Prepares a single HTML element
      * @param element The element to be prepared
@@ -462,10 +509,17 @@ export class Renderer {
                 throw new Error("Tried to import an unknown template named " + template)
             }
 
+            const contextualizedHelpers = { ...this.getHelpers(), ...options.context };
+
+            const compiledData = data ? this.scopedEval(data, contextualizedHelpers) : this.data;
+            const compiledMethods = methods ? this.scopedEval(methods, contextualizedHelpers) : this.methods;
+
+            console.log(data, compiledData);
+
             // Create the renderer for this template
             const renderer = new Renderer(compiledTemplate, {
-                data: this.data,
-                methods: this.methods
+                data: compiledData,
+                methods: compiledMethods
             });
 
             // Render the template and replace the element with it