Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(4)

Side by Side Diff: pkg/mustache/lib/template.dart

Issue 804973002: Add appengine/gcloud/mustache dependencies. (Closed) Base URL: git@github.com:dart-lang/pub-dartlang-dart.git@master
Patch Set: Added AUTHORS/LICENSE/PATENTS files Created 6 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « pkg/mustache/lib/scanner.dart ('k') | pkg/mustache/pubspec.yaml » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 part of mustache;
2
3 final Object _NO_SUCH_PROPERTY = new Object();
4
5 final RegExp _validTag = new RegExp(r'^[0-9a-zA-Z\_\-\.]+$');
6 final RegExp _integerTag = new RegExp(r'^[0-9]+$');
7
8 Template _parse(String source, {bool lenient : false}) {
9 var tokens = _scan(source, lenient);
10 var ast = _parseTokens(tokens, lenient);
11 return new _Template(ast, lenient);
12 }
13
14 _Node _parseTokens(List<_Token> tokens, bool lenient) {
15 var stack = new List<_Node>()..add(new _Node(_OPEN_SECTION, 'root', 0, 0 ));
16 for (var t in tokens) {
17 if (t.type == _TEXT || t.type == _VARIABLE || t.type == _UNESC_V ARIABLE) {
18 if (t.type == _VARIABLE || t.type == _UNESC_VARIABLE)
19 _checkTagChars(t, lenient);
20 stack.last.children.add(new _Node.fromToken(t));
21
22 } else if (t.type == _OPEN_SECTION || t.type == _OPEN_INV_SECTIO N) {
23 _checkTagChars(t, lenient);
24 var child = new _Node.fromToken(t);
25 stack.last.children.add(child);
26 stack.add(child);
27
28 } else if (t.type == _CLOSE_SECTION) {
29 _checkTagChars(t, lenient);
30
31 if (stack.last.value != t.value) {
32 throw new MustacheFormatException('Mismatched ta g, '
33 "expected: '${stack.last.value}', "
34 "was: '${t.value}', "
35 'at: ${t.line}:${t.column}.', t.line, t. column);
36 }
37
38 stack.removeLast();
39
40 } else if (t.type == _COMMENT) {
41 // Do nothing
42
43 } else {
44 throw new UnimplementedError();
45 }
46 }
47
48 return stack.last;
49 }
50
51 _checkTagChars(_Token t, bool lenient) {
52 if (!lenient && !_validTag.hasMatch(t.value)) {
53 throw new MustacheFormatException(
54 'Tag contained invalid characters in name, '
55 'allowed: 0-9, a-z, A-Z, underscore, and minus, '
56 'at: ${t.line}:${t.column}.', t.line, t.column);
57 }
58 }
59
60 class _Template implements Template {
61 _Template(this._root, this._lenient) {
62 _htmlEscapeMap[_AMP] = '&amp;';
63 _htmlEscapeMap[_LT] = '&lt;';
64 _htmlEscapeMap[_GT] = '&gt;';
65 _htmlEscapeMap[_QUOTE] = '&quot;';
66 _htmlEscapeMap[_APOS] = '&#x27;';
67 _htmlEscapeMap[_FORWARD_SLASH] = '&#x2F;';
68 }
69
70 final _Node _root;
71 final List _stack = new List();
72 final Map _htmlEscapeMap = new Map<int, String>();
73 final bool _lenient;
74
75 bool _htmlEscapeValues;
76 StringSink _sink;
77
78 String renderString(values, {bool lenient : false, bool htmlEscapeValues : true}) {
79 var buf = new StringBuffer();
80 render(values, buf, lenient: lenient, htmlEscapeValues: htmlEsca peValues);
81 return buf.toString();
82 }
83
84 void render(values, StringSink sink, {bool lenient : false, bool htmlEsc apeValues : true}) {
85 _sink = sink;
86 _htmlEscapeValues = htmlEscapeValues;
87 _stack.clear();
88 _stack.add(values);
89 _root.children.forEach(_renderNode);
90 _sink = null;
91 }
92
93 _write(String output) => _sink.write(output);
94
95 _renderNode(node) {
96 switch (node.type) {
97 case _TEXT:
98 _renderText(node);
99 break;
100 case _VARIABLE:
101 _renderVariable(node);
102 break;
103 case _UNESC_VARIABLE:
104 _renderVariable(node, escape: false);
105 break;
106 case _OPEN_SECTION:
107 _renderSection(node);
108 break;
109 case _OPEN_INV_SECTION:
110 _renderInvSection(node);
111 break;
112 case _COMMENT:
113 break; // Do nothing.
114 default:
115 throw new UnimplementedError();
116 }
117 }
118
119 _renderText(node) {
120 _write(node.value);
121 }
122
123 // Walks up the stack looking for the variable.
124 // Handles dotted names of the form "a.b.c".
125 _resolveValue(String name) {
126 if (name == '.') {
127 return _stack.last;
128 }
129 var parts = name.split('.');
130 var object = _NO_SUCH_PROPERTY;
131 for (var o in _stack.reversed) {
132 object = _getNamedProperty(o, parts[0]);
133 if (object != _NO_SUCH_PROPERTY) {
134 break;
135 }
136 }
137 for (int i = 1; i < parts.length; i++) {
138 if (object == null || object == _NO_SUCH_PROPERTY) {
139 return _NO_SUCH_PROPERTY;
140 }
141 object = _getNamedProperty(object, parts[i]);
142 }
143 return object;
144 }
145
146 // Returns the property of the given object by name. For a map,
147 // which contains the key name, this is object[name]. For other
148 // objects, this is object.name or object.name(). If no property
149 // by the given name exists, this method returns _NO_SUCH_PROPERTY.
150 _getNamedProperty(object, name) {
151 var property = null;
152 if (object is Map && object.containsKey(name)) {
153 return object[name];
154 }
155 if (object is List && _integerTag.hasMatch(name)) {
156 return object[int.parse(name)];
157 }
158 if (_lenient && !_validTag.hasMatch(name)) {
159 return _NO_SUCH_PROPERTY;
160 }
161 var instance = reflect(object);
162 var field = instance.type.instanceMembers[new Symbol(name)];
163 if (field == null) {
164 return _NO_SUCH_PROPERTY;
165 }
166 var invocation = null;
167 if ((field is VariableMirror) || ((field is MethodMirror) && (fi eld.isGetter))) {
168 invocation = instance.getField(field.simpleName);
169 } else if ((field is MethodMirror) && (field.parameters.length = = 0)) {
170 invocation = instance.invoke(field.simpleName, []);
171 }
172 if (invocation == null) {
173 return _NO_SUCH_PROPERTY;
174 }
175 return invocation.reflectee;
176 }
177
178 _renderVariable(node, {bool escape : true}) {
179 final value = _resolveValue(node.value);
180 if (value == _NO_SUCH_PROPERTY) {
181 if (!_lenient)
182 throw new MustacheFormatException(
183 'Value was missing, '
184 'variable: ${node.value}, '
185 'at: ${node.line}:${node.column}.', node .line, node.column);
186 } else {
187 var valueString = (value == null) ? '' : value.toString( );
188 var output = !escape || !_htmlEscapeValues
189 ? valueString
190 : _htmlEscape(valueString);
191 _write(output);
192 }
193 }
194
195 _renderSectionWithValue(node, value) {
196 _stack.add(value);
197 node.children.forEach(_renderNode);
198 _stack.removeLast();
199 }
200
201 _renderSection(node) {
202 final value = _resolveValue(node.value);
203 if (value == null) {
204 // Do nothing.
205 } else if (value is Iterable) {
206 value.forEach((v) => _renderSectionWithValue(node, v));
207 } else if (value is Map) {
208 _renderSectionWithValue(node, value);
209 } else if (value == true) {
210 _renderSectionWithValue(node, value);
211 } else if (value == false) {
212 // Do nothing.
213 } else if (value == _NO_SUCH_PROPERTY) {
214 if (!_lenient)
215 throw new MustacheFormatException(
216 'Value was missing, '
217 'section: ${node.value}, '
218 'at: ${node.line}:${node.column}.', node .line, node.column);
219 } else {
220 throw new MustacheFormatException(
221 'Invalid value type for section, '
222 'section: ${node.value}, '
223 'type: ${value.runtimeType}, '
224 'at: ${node.line}:${node.column}.', node.line, n ode.column);
225 }
226 }
227
228 _renderInvSection(node) {
229 final value = _resolveValue(node.value);
230 if (value == null) {
231 _renderSectionWithValue(node, null);
232 } else if ((value is Iterable && value.isEmpty) || value == fals e) {
233 _renderSectionWithValue(node, value);
234 } else if (value == true || value is Map || value is Iterable) {
235 // Do nothing.
236 } else if (value == _NO_SUCH_PROPERTY) {
237 if (_lenient) {
238 _renderSectionWithValue(node, null);
239 } else {
240 throw new MustacheFormatException(
241 'Value was missing, '
242 'inverse-section: ${node.value}, '
243 'at: ${node.line}:${node.column}.', node .line, node.column);
244 }
245 } else {
246 throw new MustacheFormatException(
247 'Invalid value type for inverse section, '
248 'section: ${node.value}, '
249 'type: ${value.runtimeType}, '
250 'at: ${node.line}:${node.column}.', node.line, n ode.column);
251 }
252 }
253
254 String _htmlEscape(String s) {
255 var buffer = new StringBuffer();
256 int startIndex = 0;
257 int i = 0;
258 for (int c in s.runes) {
259 if (c == _AMP
260 || c == _LT
261 || c == _GT
262 || c == _QUOTE
263 || c == _APOS
264 || c == _FORWARD_SLASH) {
265 buffer.write(s.substring(startIndex, i));
266 buffer.write(_htmlEscapeMap[c]);
267 startIndex = i + 1;
268 }
269 i++;
270 }
271 buffer.write(s.substring(startIndex));
272 return buffer.toString();
273 }
274 }
275
276 _visit(_Node root, visitor(_Node n)) {
277 var _stack = new List<_Node>()..add(root);
278 while (!_stack.isEmpty) {
279 var node = _stack.removeLast();
280 _stack.addAll(node.children);
281 visitor(node);
282 }
283 }
284
285 class _Node {
286 _Node(this.type, this.value, this.line, this.column);
287 _Node.fromToken(_Token token)
288 : type = token.type,
289 value = token.value,
290 line = token.line,
291 column = token.column;
292 final int type;
293 final String value;
294 final int line;
295 final int column;
296 final List<_Node> children = new List<_Node>();
297 String toString() => '_Node: ${tokenTypeString(type)}';
298 }
OLDNEW
« no previous file with comments | « pkg/mustache/lib/scanner.dart ('k') | pkg/mustache/pubspec.yaml » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698