From 4ed4ac5b88f0e6f29998f0e5a49cc23bd67ea1bd Mon Sep 17 00:00:00 2001 From: Janos Erdos Date: Wed, 15 Nov 2023 22:23:54 +0100 Subject: [PATCH] feat: allow expression in fragment include directives (#154) --- src/stencil/cleanup.clj | 10 +++----- src/stencil/model.clj | 46 +++++++++++++++++------------------ test/stencil/errors.clj | 6 ----- test/stencil/process_test.clj | 10 +++++++- 4 files changed, 36 insertions(+), 36 deletions(-) diff --git a/src/stencil/cleanup.clj b/src/stencil/cleanup.clj index 59a1172c..b5cce0db 100644 --- a/src/stencil/cleanup.clj +++ b/src/stencil/cleanup.clj @@ -110,11 +110,7 @@ ;; Itt nincsen blokk, amit normalizálni kellene (defmethod control-ast-normalize :cmd/echo [echo-command] echo-command) -(defmethod control-ast-normalize :cmd/include [include-command] - (if-not (string? (:name include-command)) - (throw (parsing-exception (pr-str (:name include-command)) - "Parameter of include call must be a single string literal!")) - include-command)) +(defmethod control-ast-normalize :cmd/include [include-command] include-command) ;; A feltételes elágazásoknál mindig generálunk egy javított THEN ágat (defmethod control-ast-normalize :if [control-ast] @@ -188,6 +184,7 @@ (collect-1 [mapping x] (case (:cmd x) :cmd/echo (expr mapping (:expression x)) + :cmd/include (expr mapping (:name x)) :if (concat (expr mapping (:condition x)) (collect mapping (apply concat (::blocks x)))) @@ -205,7 +202,8 @@ ;; returns a set of fragment names use in this document (set (for [item (tree-seq map? (comp flatten ::blocks) {::blocks [control-ast]}) :when (map? item) - :when (= :cmd/include (:cmd item))] + :when (= :cmd/include (:cmd item)) + :when (string? (:name item))] (:name item)))) (defn process [raw-token-seq] diff --git a/src/stencil/model.clj b/src/stencil/model.clj index df8f4e49..53a88088 100644 --- a/src/stencil/model.clj +++ b/src/stencil/model.clj @@ -6,6 +6,7 @@ (:require [clojure.data.xml :as xml] [clojure.java.io :as io :refer [file]] [stencil.eval :as eval] + [stencil.infix :refer [eval-rpn]] [stencil.merger :as merger] [stencil.types :refer [->FragmentInvoke]] [stencil.util :refer [unlazy-tree eval-exception]] @@ -193,32 +194,31 @@ ; (xml-map-attrs {ooxml/r-embed id-rename ooxml/r-id id-rename} item)) -(defmethod eval/eval-step :cmd/include [function local-data-map {frag-name :name}] +(defmethod eval/eval-step :cmd/include [function local-data-map step] (assert (map? local-data-map)) - (assert (string? frag-name)) - (do - (if-let [fragment-model (get *all-fragments* frag-name)] - (let [;; merge style definitions from fragment - style-ids-rename (-> fragment-model :main :style :parsed (doto assert) (style/insert-styles!)) + (let [frag-name (eval-rpn local-data-map function (:name step))] + (if-let [fragment-model (get *all-fragments* frag-name)] + (let [;; merge style definitions from fragment + style-ids-rename (-> fragment-model :main :style :parsed (doto assert) (style/insert-styles!)) - relation-ids-rename (relations/ids-rename fragment-model frag-name) - relation-rename-map (into {} (map (juxt :old-id :new-id)) relation-ids-rename) + relation-ids-rename (relations/ids-rename fragment-model frag-name) + relation-rename-map (into {} (map (juxt :old-id :new-id)) relation-ids-rename) ;; evaluate - evaled (eval-template-model fragment-model local-data-map function {}) + evaled (eval-template-model fragment-model local-data-map function {}) ;; write back - get-xml (fn [x] (or (:xml x) @(:xml-delay x))) - evaled-parts (->> evaled :main :result - (get-xml) - (extract-body-parts) - (map (partial relations/xml-rename-relation-ids relation-rename-map)) - (map (partial xml-map-attrs - {ooxml/attr-numId - (partial numbering/copy-numbering fragment-model (atom {}))})) - (map (partial style/xml-rename-style-ids style-ids-rename)) - (doall))] - (swap! *inserted-fragments* conj frag-name) - (run! relations/add-extra-file! relation-ids-rename) - [{:text (->FragmentInvoke {:frag-evaled-parts evaled-parts})}]) - (throw (eval-exception (str "No fragment for name: " frag-name) nil))))) + get-xml (fn [x] (or (:xml x) @(:xml-delay x))) + evaled-parts (->> evaled :main :result + (get-xml) + (extract-body-parts) + (map (partial relations/xml-rename-relation-ids relation-rename-map)) + (map (partial xml-map-attrs + {ooxml/attr-numId + (partial numbering/copy-numbering fragment-model (atom {}))})) + (map (partial style/xml-rename-style-ids style-ids-rename)) + (doall))] + (swap! *inserted-fragments* conj frag-name) + (run! relations/add-extra-file! relation-ids-rename) + [{:text (->FragmentInvoke {:frag-evaled-parts evaled-parts})}]) + (throw (eval-exception (str "No fragment for name: " frag-name) nil))))) diff --git a/test/stencil/errors.clj b/test/stencil/errors.clj index d8d05207..042536ae 100644 --- a/test/stencil/errors.clj +++ b/test/stencil/errors.clj @@ -43,12 +43,6 @@ (throw-ex-parsing? "{%for x in xs%}a"))) -(deftest test-wrong-include - (testing "Unexpected value in inlude tag" - (throw-ex-parsing? "{% include header %}") - (throw-ex-parsing? "{% include a+1 %}"))) - - (deftest test-not-closed (testing "Expressions are not closed properly" (throw-ex-parsing? "{%=") diff --git a/test/stencil/process_test.clj b/test/stencil/process_test.clj index 1c738414..d495ffc1 100644 --- a/test/stencil/process_test.clj +++ b/test/stencil/process_test.clj @@ -33,4 +33,12 @@ {:close :a}], :fragments #{"elefant"} :variables ()} - (test-prepare "{%include \"elefant\"%}"))))) + (test-prepare "{%include \"elefant\"%}")))) + (testing "Fragment invocation is a dynamic expression" + (is (= {:dynamic? true, + :executable [{:open :a} + {:stencil.cleanup/blocks [], :cmd :cmd/include, :name 'valtozo :raw "{%include valtozo%}"} + {:close :a}], + :fragments #{} + :variables '("valtozo")} + (test-prepare "{%include valtozo%}")))))