comparison src/implab/text/template-compile.js @ 21:7c22fc01fcec

rewritten ./text/template-compile
author cin
date Thu, 30 Nov 2017 11:01:22 +0300
parents 23be39fd3851
children f750c89976d3
comparison
equal deleted inserted replaced
20:9718e8de0cb2 21:7c22fc01fcec
1 define( 1 define(
2 [ "dojo/request", "./format" ], 2 ["dojo/request", "./format"],
3 function(request, format) { 3 function (request, format) {
4 var compile = function(str) {
5 var code = "var p=[],print=function(){p.push(format.apply(null,arguments));};" +
6 // Introduce the data as local variables using with(){}
7 "with(obj){p.push('" +
8 // Convert the template into pure JavaScript
9 str.replace(/[\r\t\n]/g, " ").split("<%").join("\t").replace(
10 /(^|%>)[^\t]*/g,
11 function(x) {
12 return x.replace(/('|\\)/g, "\\$1");
13 }).replace(/\t=(.*?)%>/g, "',$1,'").split("\t").join("');")
14 .split("%>").join("p.push('") + "');}return p.join('');";
15 /* jshint -W054 */
16 try {
17 var compiled = new Function("obj, format, nls", code);
18 4
19 /** 5 // разбивает строку шаблона на токены, возвращает контекст для
20 * Функция форматирования по шаблону 6 // дальнейшей обработки в visitTemplate
21 * 7 var parseTemplate = function (str) {
22 * @type{Function} 8 var tokens = str.split(/(<%=|<%|%>)/);
23 * @param{Object} obj объект с параметрами для подстановки 9 var pos = -1;
24 */ 10 var data = [],
25 return function(obj) { 11 code = [];
26 return compiled(obj || {}, format); 12
27 }; 13 return {
28 } catch (e) { 14 next: function () {
29 if (console && console.error) { 15 pos++;
30 console.error(code); 16 return pos < tokens.length;
17 },
18 token: function () {
19 return tokens[pos];
20 },
21 pushData: function () {
22 var i = data.length;
23 data.push.apply(data, arguments);
24 return i;
25 },
26 pushCode : function() {
27 var i = code.length;
28 code.push.apply(code, arguments);
29 return i;
30 },
31 compile: function () {
32 var text = "var $p = [];\n" +
33 "var print = function(){\n" +
34 " $p.push(format.apply(null,arguments));\n" +
35 "};\n" +
36 // Introduce the data as local variables using with(){}
37 "with(obj){\n" +
38 code.join("\n") +
39 "}\n" +
40 "return $p.join('');";
41
42 try {
43 var compiled = new Function("obj, format, $data", text);
44 /**
45 * Функция форматирования по шаблону
46 *
47 * @type{Function}
48 * @param{Object} obj объект с параметрами для подстановки
49 */
50 return function (obj) {
51 return compiled(obj || {}, format, data);
52 };
53 } catch (e) {
54 if (console && console.error) {
55 console.error(text);
56 console.log(data);
57 }
58 }
31 } 59 }
32 } 60 }
33 }; 61 };
34 62
63 function visitTemplate(context) {
64 while (context.next()) {
65 switch (context.token()) {
66 case "<%":
67 visitCode(context);
68 break;
69 case "<%=":
70 visitInline(context);
71 break;
72 default:
73 visitTextFragment(context);
74 break;
75 }
76 }
77 }
78
79 function visitInline(context) {
80 var code = ["$p.push("];
81 while (context.next()) {
82 if (context.token() == "%>")
83 break;
84 code.push(context.token());
85 }
86 code.push(");");
87 context.pushCode(code.join(''));
88 }
89
90 function visitCode(context) {
91 var code = [];
92 while (context.next()) {
93 if (context.token() == "%>")
94 break;
95 code.push(context.token());
96 }
97 context.pushCode(code.join(''));
98 }
99
100 function visitTextFragment(context) {
101 var i = context.pushData(context.token());
102 context.pushCode("$p.push($data["+i+"]);");
103 }
104
105 var compile = function (str) {
106 if (!str)
107 return function() { return "";};
108
109 var ctx = parseTemplate(str);
110 visitTemplate(ctx);
111 return ctx.compile();
112 };
113
35 var cache = {}; 114 var cache = {};
36 115
37 compile.load = function(id, require, callback) { 116 compile.load = function (id, require, callback) {
38 var url = require.toUrl(id); 117 var url = require.toUrl(id);
39 if (url in cache) { 118 if (url in cache) {
40 callback(cache[url]); 119 callback(cache[url]);
41 } else { 120 } else {
42 request(url).then(compile).then(function(tc) { 121 request(url).then(compile).then(function (tc) {
43 callback(cache[url] = tc); 122 callback(cache[url] = tc);
44 }, function(err) { 123 }, function (err) {
45 require.signal("error", [ { 124 require.signal("error", [{
46 error : err, 125 error: err,
47 src : 'implab/text/template-compile' 126 src: 'implab/text/template-compile'
48 } ]); 127 }]);
49 }); 128 });
50 } 129 }
51 }; 130 };
52 131
53 return compile; 132 return compile;