@@ -10,129 +10,129 @@ |
||
10 | 10 | |
11 | 11 | abstract class Visitor extends KeywordsCompiler |
12 | 12 | { |
13 | - /** |
|
14 | - * @param Nodes\Node $node |
|
15 | - * |
|
16 | - * @return array |
|
17 | - */ |
|
18 | - public function visit(Node $node) |
|
19 | - { |
|
20 | - $this->visitNode($node); |
|
21 | - |
|
22 | - return $this->buffer; |
|
23 | - } |
|
24 | - |
|
25 | - /** |
|
26 | - * @param Nodes\Node $node |
|
27 | - * |
|
28 | - * @return mixed |
|
29 | - */ |
|
30 | - protected function visitNode(Node $node) |
|
31 | - { |
|
32 | - $fqn = get_class($node); |
|
33 | - $parts = explode('\\', $fqn); |
|
34 | - $name = strtolower(end($parts)); |
|
35 | - $method = 'visit' . ucfirst($name); |
|
36 | - |
|
37 | - try { |
|
38 | - return $this->$method($node); |
|
39 | - } catch (\ErrorException $e) { |
|
40 | - if (!in_array($e->getCode(), array(8, 33))) { |
|
41 | - throw $e; |
|
42 | - } |
|
43 | - |
|
44 | - throw new \ErrorException( |
|
45 | - 'Error on the ' . $name . |
|
46 | - (isset($node->name) ? ' "' . $node->name . '"' : '') . |
|
47 | - ($this->filename ? ' in ' . $this->filename : '') . |
|
48 | - ' line ' . $node->line . ":\n" . $e->getMessage(), |
|
49 | - 34, |
|
50 | - 1, |
|
51 | - __FILE__, |
|
52 | - __LINE__, |
|
53 | - $e |
|
54 | - ); |
|
55 | - } |
|
56 | - } |
|
57 | - |
|
58 | - /** |
|
59 | - * @param Nodes\Literal $node |
|
60 | - */ |
|
61 | - protected function visitLiteral(Literal $node) |
|
62 | - { |
|
63 | - $str = preg_replace('/\\n/', '\\\\n', $node->string); |
|
64 | - $this->buffer($str); |
|
65 | - } |
|
66 | - |
|
67 | - /** |
|
68 | - * @param Nodes\Block $block |
|
69 | - */ |
|
70 | - protected function visitBlock(Block $block) |
|
71 | - { |
|
72 | - foreach ($block->nodes as $n) { |
|
73 | - $this->visit($n); |
|
74 | - } |
|
75 | - } |
|
76 | - |
|
77 | - /** |
|
78 | - * @param Nodes\Doctype $doctype |
|
79 | - * |
|
80 | - * @throws \Exception |
|
81 | - */ |
|
82 | - protected function visitDoctype(Doctype $doctype = null) |
|
83 | - { |
|
84 | - $doc = (empty($doctype->value) || $doctype === null || !isset($doctype->value)) |
|
85 | - ? 'default' |
|
86 | - : strtolower($doctype->value); |
|
87 | - |
|
88 | - $str = isset($this->doctypes[$doc]) |
|
89 | - ? $this->doctypes[$doc] |
|
90 | - : "<!DOCTYPE {$doc}>"; |
|
91 | - |
|
92 | - $this->buffer($str . $this->newline()); |
|
93 | - |
|
94 | - $this->terse = (strtolower($str) === '<!doctype html>'); |
|
95 | - |
|
96 | - $this->xml = ($doc === 'xml'); |
|
97 | - } |
|
98 | - |
|
99 | - /** |
|
100 | - * @param Nodes\Mixin $mixin |
|
101 | - */ |
|
102 | - protected function visitMixinBlock() |
|
103 | - { |
|
104 | - $name = var_export($this->visitedMixin->name, true); |
|
105 | - |
|
106 | - $code = $this->restrictedScope |
|
107 | - ? "\\Jade\\Compiler::callMixinBlock($name, \$attributes);" |
|
108 | - : "\$__varHandler = get_defined_vars(); \\Jade\\Compiler::callMixinBlockWithVars($name, \$__varHandler, \$attributes); extract(array_diff_key(\$__varHandler, array('__varHandler' => 1)));"; |
|
109 | - |
|
110 | - $this->buffer($this->createCode($code)); |
|
111 | - } |
|
112 | - |
|
113 | - /** |
|
114 | - * @param Nodes\Text $text |
|
115 | - */ |
|
116 | - protected function visitText($text) |
|
117 | - { |
|
118 | - $this->buffer($this->interpolate($text->value)); |
|
119 | - } |
|
120 | - |
|
121 | - /** |
|
122 | - * @param Nodes\Comment $comment |
|
123 | - */ |
|
124 | - protected function visitComment(Comment $comment) |
|
125 | - { |
|
126 | - if ($comment->buffer) { |
|
127 | - $this->buffer('<!--' . $comment->value . '-->'); |
|
128 | - } |
|
129 | - } |
|
130 | - |
|
131 | - /** |
|
132 | - * @param array $attributes |
|
133 | - */ |
|
134 | - protected function visitAttributes($attributes) |
|
135 | - { |
|
136 | - $this->tempPrettyPrint(false, 'compileAttributes', $attributes); |
|
137 | - } |
|
13 | + /** |
|
14 | + * @param Nodes\Node $node |
|
15 | + * |
|
16 | + * @return array |
|
17 | + */ |
|
18 | + public function visit(Node $node) |
|
19 | + { |
|
20 | + $this->visitNode($node); |
|
21 | + |
|
22 | + return $this->buffer; |
|
23 | + } |
|
24 | + |
|
25 | + /** |
|
26 | + * @param Nodes\Node $node |
|
27 | + * |
|
28 | + * @return mixed |
|
29 | + */ |
|
30 | + protected function visitNode(Node $node) |
|
31 | + { |
|
32 | + $fqn = get_class($node); |
|
33 | + $parts = explode('\\', $fqn); |
|
34 | + $name = strtolower(end($parts)); |
|
35 | + $method = 'visit' . ucfirst($name); |
|
36 | + |
|
37 | + try { |
|
38 | + return $this->$method($node); |
|
39 | + } catch (\ErrorException $e) { |
|
40 | + if (!in_array($e->getCode(), array(8, 33))) { |
|
41 | + throw $e; |
|
42 | + } |
|
43 | + |
|
44 | + throw new \ErrorException( |
|
45 | + 'Error on the ' . $name . |
|
46 | + (isset($node->name) ? ' "' . $node->name . '"' : '') . |
|
47 | + ($this->filename ? ' in ' . $this->filename : '') . |
|
48 | + ' line ' . $node->line . ":\n" . $e->getMessage(), |
|
49 | + 34, |
|
50 | + 1, |
|
51 | + __FILE__, |
|
52 | + __LINE__, |
|
53 | + $e |
|
54 | + ); |
|
55 | + } |
|
56 | + } |
|
57 | + |
|
58 | + /** |
|
59 | + * @param Nodes\Literal $node |
|
60 | + */ |
|
61 | + protected function visitLiteral(Literal $node) |
|
62 | + { |
|
63 | + $str = preg_replace('/\\n/', '\\\\n', $node->string); |
|
64 | + $this->buffer($str); |
|
65 | + } |
|
66 | + |
|
67 | + /** |
|
68 | + * @param Nodes\Block $block |
|
69 | + */ |
|
70 | + protected function visitBlock(Block $block) |
|
71 | + { |
|
72 | + foreach ($block->nodes as $n) { |
|
73 | + $this->visit($n); |
|
74 | + } |
|
75 | + } |
|
76 | + |
|
77 | + /** |
|
78 | + * @param Nodes\Doctype $doctype |
|
79 | + * |
|
80 | + * @throws \Exception |
|
81 | + */ |
|
82 | + protected function visitDoctype(Doctype $doctype = null) |
|
83 | + { |
|
84 | + $doc = (empty($doctype->value) || $doctype === null || !isset($doctype->value)) |
|
85 | + ? 'default' |
|
86 | + : strtolower($doctype->value); |
|
87 | + |
|
88 | + $str = isset($this->doctypes[$doc]) |
|
89 | + ? $this->doctypes[$doc] |
|
90 | + : "<!DOCTYPE {$doc}>"; |
|
91 | + |
|
92 | + $this->buffer($str . $this->newline()); |
|
93 | + |
|
94 | + $this->terse = (strtolower($str) === '<!doctype html>'); |
|
95 | + |
|
96 | + $this->xml = ($doc === 'xml'); |
|
97 | + } |
|
98 | + |
|
99 | + /** |
|
100 | + * @param Nodes\Mixin $mixin |
|
101 | + */ |
|
102 | + protected function visitMixinBlock() |
|
103 | + { |
|
104 | + $name = var_export($this->visitedMixin->name, true); |
|
105 | + |
|
106 | + $code = $this->restrictedScope |
|
107 | + ? "\\Jade\\Compiler::callMixinBlock($name, \$attributes);" |
|
108 | + : "\$__varHandler = get_defined_vars(); \\Jade\\Compiler::callMixinBlockWithVars($name, \$__varHandler, \$attributes); extract(array_diff_key(\$__varHandler, array('__varHandler' => 1)));"; |
|
109 | + |
|
110 | + $this->buffer($this->createCode($code)); |
|
111 | + } |
|
112 | + |
|
113 | + /** |
|
114 | + * @param Nodes\Text $text |
|
115 | + */ |
|
116 | + protected function visitText($text) |
|
117 | + { |
|
118 | + $this->buffer($this->interpolate($text->value)); |
|
119 | + } |
|
120 | + |
|
121 | + /** |
|
122 | + * @param Nodes\Comment $comment |
|
123 | + */ |
|
124 | + protected function visitComment(Comment $comment) |
|
125 | + { |
|
126 | + if ($comment->buffer) { |
|
127 | + $this->buffer('<!--' . $comment->value . '-->'); |
|
128 | + } |
|
129 | + } |
|
130 | + |
|
131 | + /** |
|
132 | + * @param array $attributes |
|
133 | + */ |
|
134 | + protected function visitAttributes($attributes) |
|
135 | + { |
|
136 | + $this->tempPrettyPrint(false, 'compileAttributes', $attributes); |
|
137 | + } |
|
138 | 138 | } |
@@ -8,183 +8,183 @@ |
||
8 | 8 | */ |
9 | 9 | abstract class CompilerUtils extends Indenter |
10 | 10 | { |
11 | - /** |
|
12 | - * Prepend "$" to the given input if it's a varname. |
|
13 | - * |
|
14 | - * @param string $call |
|
15 | - * |
|
16 | - * @throws \InvalidArgumentException |
|
17 | - * |
|
18 | - * @return string |
|
19 | - */ |
|
20 | - protected static function addDollarIfNeeded($call) |
|
21 | - { |
|
22 | - return CommonUtils::addDollarIfNeeded($call); |
|
23 | - } |
|
24 | - |
|
25 | - /** |
|
26 | - * Escape value depanding on the current quote. |
|
27 | - * |
|
28 | - * @param string $val input value |
|
29 | - * |
|
30 | - * @return string |
|
31 | - */ |
|
32 | - protected function escapeValue($val) |
|
33 | - { |
|
34 | - return static::getEscapedValue($val, $this->quote); |
|
35 | - } |
|
36 | - |
|
37 | - /** |
|
38 | - * Return PHP code to translate dot to object/array getter. |
|
39 | - * |
|
40 | - * @example foo.bar return $foo->bar (if foo is an object), or $foo["bar"] if it's an array. |
|
41 | - * |
|
42 | - * @param array $match regex match |
|
43 | - * |
|
44 | - * @return string |
|
45 | - */ |
|
46 | - protected static function convertVarPathCallback($match) |
|
47 | - { |
|
48 | - if (empty($match[1])) { |
|
49 | - return $match[0]; |
|
50 | - } |
|
51 | - |
|
52 | - $var = ($match[0] === ',' ? ',' : '') . $match[1]; |
|
53 | - foreach (explode('.', substr($match[2], 1)) as $name) { |
|
54 | - if (!empty($name)) { |
|
55 | - $var = CommonUtils::getGetter($var, $name, false); |
|
56 | - } |
|
57 | - } |
|
58 | - |
|
59 | - return $var; |
|
60 | - } |
|
61 | - |
|
62 | - /** |
|
63 | - * Replace var paths in a string. |
|
64 | - * |
|
65 | - * @param string $arg |
|
66 | - * @param string $regexp |
|
67 | - * |
|
68 | - * @return string |
|
69 | - */ |
|
70 | - protected static function convertVarPath($arg, $regexp = '/^%s|,%s/') |
|
71 | - { |
|
72 | - $pattern = '\s*(\\${0,2}' . static::VARNAME . ')((\.' . static::VARNAME . ')*)'; |
|
73 | - |
|
74 | - return preg_replace_callback( |
|
75 | - str_replace('%s', $pattern, $regexp), |
|
76 | - array(get_class(), 'convertVarPathCallback'), |
|
77 | - $arg |
|
78 | - ); |
|
79 | - } |
|
80 | - |
|
81 | - /** |
|
82 | - * Concat " = null" to initializations to simulate the JS "var foo;". |
|
83 | - * |
|
84 | - * @param &string $arg reference of an argument containing an expression |
|
85 | - * |
|
86 | - * @throws \InvalidArgumentException |
|
87 | - */ |
|
88 | - protected static function initArgToNull(&$arg) |
|
89 | - { |
|
90 | - $arg = static::addDollarIfNeeded(trim($arg)); |
|
91 | - if (strpos($arg, '=') === false) { |
|
92 | - $arg .= ' = null'; |
|
93 | - } |
|
94 | - } |
|
95 | - |
|
96 | - /** |
|
97 | - * Parse a value from its quoted string (or JSON) representation. |
|
98 | - * |
|
99 | - * @param string $value |
|
100 | - * |
|
101 | - * @return mixed |
|
102 | - */ |
|
103 | - protected static function parseValue($value) |
|
104 | - { |
|
105 | - return json_decode(preg_replace("/'([^']*?)'/", '"$1"', $value)); |
|
106 | - } |
|
107 | - |
|
108 | - /** |
|
109 | - * Decode a value (parse it except if it's null). |
|
110 | - * |
|
111 | - * @param string $value |
|
112 | - * |
|
113 | - * @return mixed |
|
114 | - */ |
|
115 | - protected static function decodeValue($value) |
|
116 | - { |
|
117 | - $parsedValue = static::parseValue($value); |
|
118 | - |
|
119 | - return is_null($parsedValue) ? $value : $parsedValue; |
|
120 | - } |
|
121 | - |
|
122 | - /** |
|
123 | - * Decode each attribute in the given list. |
|
124 | - * |
|
125 | - * @param array $attributes |
|
126 | - * |
|
127 | - * @return array |
|
128 | - */ |
|
129 | - protected static function decodeAttributes($attributes) |
|
130 | - { |
|
131 | - foreach ($attributes as &$attribute) { |
|
132 | - if (is_array($attribute)) { |
|
133 | - $attribute['value'] = is_bool($attribute['value']) ? $attribute['value'] : static::decodeValue($attribute['value']); |
|
134 | - continue; |
|
135 | - } |
|
136 | - |
|
137 | - $attribute = static::decodeValue($attribute); |
|
138 | - } |
|
139 | - |
|
140 | - return $attributes; |
|
141 | - } |
|
142 | - |
|
143 | - /** |
|
144 | - * Get filter by name. |
|
145 | - * |
|
146 | - * @param string $name |
|
147 | - * |
|
148 | - * @return callable |
|
149 | - */ |
|
150 | - protected function getFilter($name) |
|
151 | - { |
|
152 | - $helper = new FilterHelper($this->filters, $this->filterAutoLoad); |
|
153 | - |
|
154 | - return $helper->getValidFilter($name); |
|
155 | - } |
|
156 | - |
|
157 | - /** |
|
158 | - * Return PHP code wich wrap the given value and escape it if $escaped is true. |
|
159 | - * |
|
160 | - * @param bool $escaped need to be escaped |
|
161 | - * @param mixed $value to be escaped if $escaped is true |
|
162 | - * |
|
163 | - * @return callable |
|
164 | - */ |
|
165 | - protected function escapeIfNeeded($escaped, $value) |
|
166 | - { |
|
167 | - $value = rtrim($value, ';'); |
|
168 | - |
|
169 | - if ($escaped) { |
|
170 | - return $this->createCode(static::ESCAPED, $value, var_export($this->quote, true)); |
|
171 | - } |
|
172 | - |
|
173 | - return $this->createCode(static::UNESCAPED, $value); |
|
174 | - } |
|
175 | - |
|
176 | - /** |
|
177 | - * Join with space if the value is an array, else return the input value |
|
178 | - * with no changes. |
|
179 | - * |
|
180 | - * @param array $value |
|
181 | - * |
|
182 | - * @return string|mixed |
|
183 | - */ |
|
184 | - protected static function joinAny($value) |
|
185 | - { |
|
186 | - return is_array($value) |
|
187 | - ? implode(' ', $value) |
|
188 | - : $value; |
|
189 | - } |
|
11 | + /** |
|
12 | + * Prepend "$" to the given input if it's a varname. |
|
13 | + * |
|
14 | + * @param string $call |
|
15 | + * |
|
16 | + * @throws \InvalidArgumentException |
|
17 | + * |
|
18 | + * @return string |
|
19 | + */ |
|
20 | + protected static function addDollarIfNeeded($call) |
|
21 | + { |
|
22 | + return CommonUtils::addDollarIfNeeded($call); |
|
23 | + } |
|
24 | + |
|
25 | + /** |
|
26 | + * Escape value depanding on the current quote. |
|
27 | + * |
|
28 | + * @param string $val input value |
|
29 | + * |
|
30 | + * @return string |
|
31 | + */ |
|
32 | + protected function escapeValue($val) |
|
33 | + { |
|
34 | + return static::getEscapedValue($val, $this->quote); |
|
35 | + } |
|
36 | + |
|
37 | + /** |
|
38 | + * Return PHP code to translate dot to object/array getter. |
|
39 | + * |
|
40 | + * @example foo.bar return $foo->bar (if foo is an object), or $foo["bar"] if it's an array. |
|
41 | + * |
|
42 | + * @param array $match regex match |
|
43 | + * |
|
44 | + * @return string |
|
45 | + */ |
|
46 | + protected static function convertVarPathCallback($match) |
|
47 | + { |
|
48 | + if (empty($match[1])) { |
|
49 | + return $match[0]; |
|
50 | + } |
|
51 | + |
|
52 | + $var = ($match[0] === ',' ? ',' : '') . $match[1]; |
|
53 | + foreach (explode('.', substr($match[2], 1)) as $name) { |
|
54 | + if (!empty($name)) { |
|
55 | + $var = CommonUtils::getGetter($var, $name, false); |
|
56 | + } |
|
57 | + } |
|
58 | + |
|
59 | + return $var; |
|
60 | + } |
|
61 | + |
|
62 | + /** |
|
63 | + * Replace var paths in a string. |
|
64 | + * |
|
65 | + * @param string $arg |
|
66 | + * @param string $regexp |
|
67 | + * |
|
68 | + * @return string |
|
69 | + */ |
|
70 | + protected static function convertVarPath($arg, $regexp = '/^%s|,%s/') |
|
71 | + { |
|
72 | + $pattern = '\s*(\\${0,2}' . static::VARNAME . ')((\.' . static::VARNAME . ')*)'; |
|
73 | + |
|
74 | + return preg_replace_callback( |
|
75 | + str_replace('%s', $pattern, $regexp), |
|
76 | + array(get_class(), 'convertVarPathCallback'), |
|
77 | + $arg |
|
78 | + ); |
|
79 | + } |
|
80 | + |
|
81 | + /** |
|
82 | + * Concat " = null" to initializations to simulate the JS "var foo;". |
|
83 | + * |
|
84 | + * @param &string $arg reference of an argument containing an expression |
|
85 | + * |
|
86 | + * @throws \InvalidArgumentException |
|
87 | + */ |
|
88 | + protected static function initArgToNull(&$arg) |
|
89 | + { |
|
90 | + $arg = static::addDollarIfNeeded(trim($arg)); |
|
91 | + if (strpos($arg, '=') === false) { |
|
92 | + $arg .= ' = null'; |
|
93 | + } |
|
94 | + } |
|
95 | + |
|
96 | + /** |
|
97 | + * Parse a value from its quoted string (or JSON) representation. |
|
98 | + * |
|
99 | + * @param string $value |
|
100 | + * |
|
101 | + * @return mixed |
|
102 | + */ |
|
103 | + protected static function parseValue($value) |
|
104 | + { |
|
105 | + return json_decode(preg_replace("/'([^']*?)'/", '"$1"', $value)); |
|
106 | + } |
|
107 | + |
|
108 | + /** |
|
109 | + * Decode a value (parse it except if it's null). |
|
110 | + * |
|
111 | + * @param string $value |
|
112 | + * |
|
113 | + * @return mixed |
|
114 | + */ |
|
115 | + protected static function decodeValue($value) |
|
116 | + { |
|
117 | + $parsedValue = static::parseValue($value); |
|
118 | + |
|
119 | + return is_null($parsedValue) ? $value : $parsedValue; |
|
120 | + } |
|
121 | + |
|
122 | + /** |
|
123 | + * Decode each attribute in the given list. |
|
124 | + * |
|
125 | + * @param array $attributes |
|
126 | + * |
|
127 | + * @return array |
|
128 | + */ |
|
129 | + protected static function decodeAttributes($attributes) |
|
130 | + { |
|
131 | + foreach ($attributes as &$attribute) { |
|
132 | + if (is_array($attribute)) { |
|
133 | + $attribute['value'] = is_bool($attribute['value']) ? $attribute['value'] : static::decodeValue($attribute['value']); |
|
134 | + continue; |
|
135 | + } |
|
136 | + |
|
137 | + $attribute = static::decodeValue($attribute); |
|
138 | + } |
|
139 | + |
|
140 | + return $attributes; |
|
141 | + } |
|
142 | + |
|
143 | + /** |
|
144 | + * Get filter by name. |
|
145 | + * |
|
146 | + * @param string $name |
|
147 | + * |
|
148 | + * @return callable |
|
149 | + */ |
|
150 | + protected function getFilter($name) |
|
151 | + { |
|
152 | + $helper = new FilterHelper($this->filters, $this->filterAutoLoad); |
|
153 | + |
|
154 | + return $helper->getValidFilter($name); |
|
155 | + } |
|
156 | + |
|
157 | + /** |
|
158 | + * Return PHP code wich wrap the given value and escape it if $escaped is true. |
|
159 | + * |
|
160 | + * @param bool $escaped need to be escaped |
|
161 | + * @param mixed $value to be escaped if $escaped is true |
|
162 | + * |
|
163 | + * @return callable |
|
164 | + */ |
|
165 | + protected function escapeIfNeeded($escaped, $value) |
|
166 | + { |
|
167 | + $value = rtrim($value, ';'); |
|
168 | + |
|
169 | + if ($escaped) { |
|
170 | + return $this->createCode(static::ESCAPED, $value, var_export($this->quote, true)); |
|
171 | + } |
|
172 | + |
|
173 | + return $this->createCode(static::UNESCAPED, $value); |
|
174 | + } |
|
175 | + |
|
176 | + /** |
|
177 | + * Join with space if the value is an array, else return the input value |
|
178 | + * with no changes. |
|
179 | + * |
|
180 | + * @param array $value |
|
181 | + * |
|
182 | + * @return string|mixed |
|
183 | + */ |
|
184 | + protected static function joinAny($value) |
|
185 | + { |
|
186 | + return is_array($value) |
|
187 | + ? implode(' ', $value) |
|
188 | + : $value; |
|
189 | + } |
|
190 | 190 | } |
@@ -6,95 +6,95 @@ |
||
6 | 6 | |
7 | 7 | abstract class TagVisitor extends Visitor |
8 | 8 | { |
9 | - /** |
|
10 | - * @param Nodes\Tag $tag |
|
11 | - */ |
|
12 | - protected function visitTagAttributes(Tag $tag, $newLinePrettyPrint, $close = '>') |
|
13 | - { |
|
14 | - $open = '<' . $tag->name; |
|
15 | - |
|
16 | - if (count($tag->attributes)) { |
|
17 | - $this->buffer($this->indent() . $open, false); |
|
18 | - $this->visitAttributes($tag->attributes); |
|
19 | - $this->buffer($this->getClassesDisplayCode() . $close . $this->newline(), false); |
|
20 | - |
|
21 | - return; |
|
22 | - } |
|
23 | - |
|
24 | - $this->buffer($open . $close, $newLinePrettyPrint ? null : false); |
|
25 | - } |
|
26 | - |
|
27 | - /** |
|
28 | - * @param Nodes\Tag $tag |
|
29 | - */ |
|
30 | - protected function initTagName(Tag $tag) |
|
31 | - { |
|
32 | - if (isset($tag->buffer)) { |
|
33 | - if (preg_match('`^[a-z][a-zA-Z0-9]+(?!\()`', $tag->name)) { |
|
34 | - $tag->name = '$' . $tag->name; |
|
35 | - } |
|
36 | - $tag->name = trim($this->createCode('echo ' . $tag->name . ';')); |
|
37 | - } |
|
38 | - } |
|
39 | - |
|
40 | - protected function trimLastLine() |
|
41 | - { |
|
42 | - $key = count($this->buffer) - 1; |
|
43 | - $this->buffer[$key] = substr($this->buffer[$key], 0, -1); |
|
44 | - if ($this->prettyprint && substr($this->buffer[$key], -1) === ' ') { |
|
45 | - $this->buffer[$key] = substr($this->buffer[$key], 0, -1); |
|
46 | - } |
|
47 | - } |
|
48 | - |
|
49 | - /** |
|
50 | - * @param Nodes\Tag $tag |
|
51 | - */ |
|
52 | - protected function visitTagContents(Tag $tag) |
|
53 | - { |
|
54 | - $inc = $tag->keepWhiteSpaces() ? -$this->indents : 1; |
|
55 | - $this->indents += $inc; |
|
56 | - if (isset($tag->code)) { |
|
57 | - $this->visitCode($tag->code); |
|
58 | - } |
|
59 | - $this->visit($tag->block); |
|
60 | - if ($tag->keepWhiteSpaces() && substr(end($this->buffer), -1) === "\n") { |
|
61 | - $this->trimLastLine(); |
|
62 | - } |
|
63 | - $this->indents -= $inc; |
|
64 | - } |
|
65 | - |
|
66 | - /** |
|
67 | - * @param Nodes\Tag $tag |
|
68 | - */ |
|
69 | - protected function compileTag(Tag $tag) |
|
70 | - { |
|
71 | - $selfClosing = (in_array(strtolower($tag->name), $this->selfClosing) || $tag->selfClosing) && !$this->xml; |
|
72 | - $this->visitTagAttributes($tag, !$tag->keepWhiteSpaces() && $this->prettyprint, (!$selfClosing || $this->terse) ? '>' : ' />'); |
|
73 | - |
|
74 | - if (!$selfClosing) { |
|
75 | - $this->visitTagContents($tag); |
|
76 | - $this->buffer('</' . $tag->name . '>', $tag->keepWhiteSpaces() ? false : null); |
|
77 | - } |
|
78 | - } |
|
79 | - |
|
80 | - /** |
|
81 | - * @param Nodes\Tag $tag |
|
82 | - */ |
|
83 | - protected function visitTag(Tag $tag) |
|
84 | - { |
|
85 | - $this->initTagName($tag); |
|
86 | - |
|
87 | - $insidePrettyprint = !$tag->canInline() && $this->prettyprint && !$tag->isInline(); |
|
88 | - $prettyprint = $tag->keepWhiteSpaces() || $insidePrettyprint; |
|
89 | - |
|
90 | - if ($this->prettyprint && !$insidePrettyprint) { |
|
91 | - $this->buffer[] = $this->indent(); |
|
92 | - } |
|
93 | - |
|
94 | - $this->tempPrettyPrint($prettyprint, 'compileTag', $tag); |
|
95 | - |
|
96 | - if (!$prettyprint && $this->prettyprint && !$tag->isInline()) { |
|
97 | - $this->buffer[] = $this->newline(); |
|
98 | - } |
|
99 | - } |
|
9 | + /** |
|
10 | + * @param Nodes\Tag $tag |
|
11 | + */ |
|
12 | + protected function visitTagAttributes(Tag $tag, $newLinePrettyPrint, $close = '>') |
|
13 | + { |
|
14 | + $open = '<' . $tag->name; |
|
15 | + |
|
16 | + if (count($tag->attributes)) { |
|
17 | + $this->buffer($this->indent() . $open, false); |
|
18 | + $this->visitAttributes($tag->attributes); |
|
19 | + $this->buffer($this->getClassesDisplayCode() . $close . $this->newline(), false); |
|
20 | + |
|
21 | + return; |
|
22 | + } |
|
23 | + |
|
24 | + $this->buffer($open . $close, $newLinePrettyPrint ? null : false); |
|
25 | + } |
|
26 | + |
|
27 | + /** |
|
28 | + * @param Nodes\Tag $tag |
|
29 | + */ |
|
30 | + protected function initTagName(Tag $tag) |
|
31 | + { |
|
32 | + if (isset($tag->buffer)) { |
|
33 | + if (preg_match('`^[a-z][a-zA-Z0-9]+(?!\()`', $tag->name)) { |
|
34 | + $tag->name = '$' . $tag->name; |
|
35 | + } |
|
36 | + $tag->name = trim($this->createCode('echo ' . $tag->name . ';')); |
|
37 | + } |
|
38 | + } |
|
39 | + |
|
40 | + protected function trimLastLine() |
|
41 | + { |
|
42 | + $key = count($this->buffer) - 1; |
|
43 | + $this->buffer[$key] = substr($this->buffer[$key], 0, -1); |
|
44 | + if ($this->prettyprint && substr($this->buffer[$key], -1) === ' ') { |
|
45 | + $this->buffer[$key] = substr($this->buffer[$key], 0, -1); |
|
46 | + } |
|
47 | + } |
|
48 | + |
|
49 | + /** |
|
50 | + * @param Nodes\Tag $tag |
|
51 | + */ |
|
52 | + protected function visitTagContents(Tag $tag) |
|
53 | + { |
|
54 | + $inc = $tag->keepWhiteSpaces() ? -$this->indents : 1; |
|
55 | + $this->indents += $inc; |
|
56 | + if (isset($tag->code)) { |
|
57 | + $this->visitCode($tag->code); |
|
58 | + } |
|
59 | + $this->visit($tag->block); |
|
60 | + if ($tag->keepWhiteSpaces() && substr(end($this->buffer), -1) === "\n") { |
|
61 | + $this->trimLastLine(); |
|
62 | + } |
|
63 | + $this->indents -= $inc; |
|
64 | + } |
|
65 | + |
|
66 | + /** |
|
67 | + * @param Nodes\Tag $tag |
|
68 | + */ |
|
69 | + protected function compileTag(Tag $tag) |
|
70 | + { |
|
71 | + $selfClosing = (in_array(strtolower($tag->name), $this->selfClosing) || $tag->selfClosing) && !$this->xml; |
|
72 | + $this->visitTagAttributes($tag, !$tag->keepWhiteSpaces() && $this->prettyprint, (!$selfClosing || $this->terse) ? '>' : ' />'); |
|
73 | + |
|
74 | + if (!$selfClosing) { |
|
75 | + $this->visitTagContents($tag); |
|
76 | + $this->buffer('</' . $tag->name . '>', $tag->keepWhiteSpaces() ? false : null); |
|
77 | + } |
|
78 | + } |
|
79 | + |
|
80 | + /** |
|
81 | + * @param Nodes\Tag $tag |
|
82 | + */ |
|
83 | + protected function visitTag(Tag $tag) |
|
84 | + { |
|
85 | + $this->initTagName($tag); |
|
86 | + |
|
87 | + $insidePrettyprint = !$tag->canInline() && $this->prettyprint && !$tag->isInline(); |
|
88 | + $prettyprint = $tag->keepWhiteSpaces() || $insidePrettyprint; |
|
89 | + |
|
90 | + if ($this->prettyprint && !$insidePrettyprint) { |
|
91 | + $this->buffer[] = $this->indent(); |
|
92 | + } |
|
93 | + |
|
94 | + $this->tempPrettyPrint($prettyprint, 'compileTag', $tag); |
|
95 | + |
|
96 | + if (!$prettyprint && $this->prettyprint && !$tag->isInline()) { |
|
97 | + $this->buffer[] = $this->newline(); |
|
98 | + } |
|
99 | + } |
|
100 | 100 | } |
@@ -8,64 +8,64 @@ |
||
8 | 8 | */ |
9 | 9 | class CommonUtils |
10 | 10 | { |
11 | - /** |
|
12 | - * @param string $call |
|
13 | - * |
|
14 | - * @throws \InvalidArgumentException |
|
15 | - * |
|
16 | - * @return string |
|
17 | - */ |
|
18 | - public static function addDollarIfNeeded($call) |
|
19 | - { |
|
20 | - if ($call === 'Inf') { |
|
21 | - throw new \InvalidArgumentException($call . ' cannot be read from PHP', 16); |
|
22 | - } |
|
23 | - if ($call === 'undefined') { |
|
24 | - return 'null'; |
|
25 | - } |
|
26 | - $firstChar = substr($call, 0, 1); |
|
27 | - if ( |
|
28 | - !in_array($firstChar, array('$', '\\')) && |
|
29 | - !preg_match('#^(?:' . CompilerConfig::VARNAME . '\\s*\\(|(?:null|false|true)(?![a-z]))#i', $call) && |
|
30 | - ( |
|
31 | - preg_match('#^' . CompilerConfig::VARNAME . '#', $call) || |
|
32 | - $firstChar === '_' |
|
33 | - ) |
|
34 | - ) { |
|
35 | - $call = '$' . $call; |
|
36 | - } |
|
11 | + /** |
|
12 | + * @param string $call |
|
13 | + * |
|
14 | + * @throws \InvalidArgumentException |
|
15 | + * |
|
16 | + * @return string |
|
17 | + */ |
|
18 | + public static function addDollarIfNeeded($call) |
|
19 | + { |
|
20 | + if ($call === 'Inf') { |
|
21 | + throw new \InvalidArgumentException($call . ' cannot be read from PHP', 16); |
|
22 | + } |
|
23 | + if ($call === 'undefined') { |
|
24 | + return 'null'; |
|
25 | + } |
|
26 | + $firstChar = substr($call, 0, 1); |
|
27 | + if ( |
|
28 | + !in_array($firstChar, array('$', '\\')) && |
|
29 | + !preg_match('#^(?:' . CompilerConfig::VARNAME . '\\s*\\(|(?:null|false|true)(?![a-z]))#i', $call) && |
|
30 | + ( |
|
31 | + preg_match('#^' . CompilerConfig::VARNAME . '#', $call) || |
|
32 | + $firstChar === '_' |
|
33 | + ) |
|
34 | + ) { |
|
35 | + $call = '$' . $call; |
|
36 | + } |
|
37 | 37 | |
38 | - return $call; |
|
39 | - } |
|
38 | + return $call; |
|
39 | + } |
|
40 | 40 | |
41 | - /** |
|
42 | - * Return true if the ending quote of the string is escaped. |
|
43 | - * |
|
44 | - * @param string $quotedString |
|
45 | - * |
|
46 | - * @return bool |
|
47 | - */ |
|
48 | - public static function escapedEnd($quotedString) |
|
49 | - { |
|
50 | - $end = substr($quotedString, strlen(rtrim($quotedString, '\\'))); |
|
41 | + /** |
|
42 | + * Return true if the ending quote of the string is escaped. |
|
43 | + * |
|
44 | + * @param string $quotedString |
|
45 | + * |
|
46 | + * @return bool |
|
47 | + */ |
|
48 | + public static function escapedEnd($quotedString) |
|
49 | + { |
|
50 | + $end = substr($quotedString, strlen(rtrim($quotedString, '\\'))); |
|
51 | 51 | |
52 | - return substr($end, 0, 1) === '\\' && strlen($end) & 1; |
|
53 | - } |
|
52 | + return substr($end, 0, 1) === '\\' && strlen($end) & 1; |
|
53 | + } |
|
54 | 54 | |
55 | - /** |
|
56 | - * Return true if the ending quote of the string is escaped. |
|
57 | - * |
|
58 | - * @param object|array $anything object or array (PHP >= 7) that contains a callable |
|
59 | - * @param string|int $key|$method key or method name |
|
60 | - * @param bool $isMethod true if the second argument is a method |
|
61 | - * |
|
62 | - * @return string |
|
63 | - */ |
|
64 | - public static function getGetter($anything, $key) |
|
65 | - { |
|
66 | - return '\\Jade\\Compiler::getPropertyFromAnything(' . |
|
67 | - static::addDollarIfNeeded($anything) . ', ' . |
|
68 | - var_export($key, true) . |
|
69 | - ')'; |
|
70 | - } |
|
55 | + /** |
|
56 | + * Return true if the ending quote of the string is escaped. |
|
57 | + * |
|
58 | + * @param object|array $anything object or array (PHP >= 7) that contains a callable |
|
59 | + * @param string|int $key|$method key or method name |
|
60 | + * @param bool $isMethod true if the second argument is a method |
|
61 | + * |
|
62 | + * @return string |
|
63 | + */ |
|
64 | + public static function getGetter($anything, $key) |
|
65 | + { |
|
66 | + return '\\Jade\\Compiler::getPropertyFromAnything(' . |
|
67 | + static::addDollarIfNeeded($anything) . ', ' . |
|
68 | + var_export($key, true) . |
|
69 | + ')'; |
|
70 | + } |
|
71 | 71 | } |
@@ -6,281 +6,281 @@ |
||
6 | 6 | |
7 | 7 | abstract class MixinVisitor extends CodeVisitor |
8 | 8 | { |
9 | - protected function getMixinArgumentAssign($argument) |
|
10 | - { |
|
11 | - $argument = trim($argument); |
|
12 | - |
|
13 | - if (preg_match('`^[a-zA-Z][a-zA-Z0-9:_-]*\s*=`', $argument)) { |
|
14 | - return explode('=', $argument, 2); |
|
15 | - } |
|
16 | - } |
|
17 | - |
|
18 | - protected function parseMixinArguments(&$arguments, &$containsOnlyArrays, &$defaultAttributes) |
|
19 | - { |
|
20 | - $newArrayKey = null; |
|
21 | - $arguments = is_null($arguments) ? array() : explode(',', $arguments); |
|
22 | - foreach ($arguments as $key => &$argument) { |
|
23 | - if ($tab = $this->getMixinArgumentAssign($argument)) { |
|
24 | - if (is_null($newArrayKey)) { |
|
25 | - $newArrayKey = $key; |
|
26 | - $argument = array(); |
|
27 | - } else { |
|
28 | - unset($arguments[$key]); |
|
29 | - } |
|
30 | - |
|
31 | - $defaultAttributes[] = var_export($tab[0], true) . ' => ' . $tab[1]; |
|
32 | - $arguments[$newArrayKey][$tab[0]] = static::decodeValue($tab[1]); |
|
33 | - continue; |
|
34 | - } |
|
35 | - |
|
36 | - $containsOnlyArrays = false; |
|
37 | - $newArrayKey = null; |
|
38 | - } |
|
39 | - |
|
40 | - return array_map(function ($argument) { |
|
41 | - if (is_array($argument)) { |
|
42 | - $argument = var_export($argument, true); |
|
43 | - } |
|
44 | - |
|
45 | - return $argument; |
|
46 | - }, $arguments); |
|
47 | - } |
|
48 | - |
|
49 | - protected function parseMixinStringAttribute($data) |
|
50 | - { |
|
51 | - $value = is_array($data['value']) |
|
52 | - ? preg_split('`\s+`', trim(implode(' ', $data['value']))) |
|
53 | - : trim($data['value']); |
|
54 | - |
|
55 | - return $data['escaped'] === true |
|
56 | - ? is_array($value) |
|
57 | - ? array_map('htmlspecialchars', $value) |
|
58 | - : htmlspecialchars($value) |
|
59 | - : $value; |
|
60 | - } |
|
61 | - |
|
62 | - protected function parseMixinAttribute($data) |
|
63 | - { |
|
64 | - if ($data['value'] === 'null' || $data['value'] === 'undefined' || is_null($data['value'])) { |
|
65 | - return; |
|
66 | - } |
|
67 | - |
|
68 | - if (is_bool($data['value'])) { |
|
69 | - return $data['value']; |
|
70 | - } |
|
71 | - |
|
72 | - return $this->parseMixinStringAttribute($data); |
|
73 | - } |
|
74 | - |
|
75 | - protected function parseMixinAttributes($attributes, $defaultAttributes, $mixinAttributes) |
|
76 | - { |
|
77 | - if (!count($attributes)) { |
|
78 | - return "(isset(\$attributes)) ? \$attributes : array($defaultAttributes)"; |
|
79 | - } |
|
80 | - |
|
81 | - $parsedAttributes = array(); |
|
82 | - foreach ($attributes as $data) { |
|
83 | - $parsedAttributes[$data['name']] = $this->parseMixinAttribute($data); |
|
84 | - } |
|
85 | - |
|
86 | - $attributes = var_export($parsedAttributes, true); |
|
87 | - $mixinAttributes = var_export(static::decodeAttributes($mixinAttributes), true); |
|
88 | - |
|
89 | - return "array_merge(\\Jade\\Compiler::withMixinAttributes($attributes, $mixinAttributes), (isset(\$attributes)) ? \$attributes : array($defaultAttributes))"; |
|
90 | - } |
|
91 | - |
|
92 | - protected function renderClosureOpenning() |
|
93 | - { |
|
94 | - $arguments = func_get_args(); |
|
95 | - $begin = array_shift($arguments); |
|
96 | - $begin = is_array($begin) |
|
97 | - ? $begin[0] . 'function ' . $begin[1] |
|
98 | - : $begin . 'function '; |
|
99 | - $params = implode(', ', array_map(function ($name) { |
|
100 | - return (substr($name, 0, 1) === '$' ? '' : '$') . $name; |
|
101 | - }, $arguments)); |
|
102 | - |
|
103 | - if ($this->restrictedScope) { |
|
104 | - return $this->buffer($this->createCode($begin . '(' . $params . ') {')); |
|
105 | - } |
|
106 | - |
|
107 | - $params = '&$__varHandler, ' . $params; |
|
108 | - |
|
109 | - $this->buffer( |
|
110 | - $this->createCode($begin . '(' . $params . ') {') . |
|
111 | - $this->createCode($this->indent() . 'extract($__varHandler, EXTR_SKIP);') |
|
112 | - ); |
|
113 | - } |
|
114 | - |
|
115 | - protected function renderClosureClosing($code, $arguments = array()) |
|
116 | - { |
|
117 | - if (!$this->restrictedScope) { |
|
118 | - $arguments = array_filter(array_map(function ($argument) { |
|
119 | - $argument = explode('=', $argument); |
|
120 | - $argument = trim($argument[0]); |
|
121 | - |
|
122 | - return substr($argument, 0, 1) === '$' |
|
123 | - ? substr($argument, 1) |
|
124 | - : false; |
|
125 | - }, array_slice($arguments, 1))); |
|
126 | - $exception = count($arguments) |
|
127 | - ? ' && !in_array($key, ' . var_export($arguments, true) . ')' |
|
128 | - : ''; |
|
129 | - $this->buffer($this->createCode( |
|
130 | - 'foreach ($__varHandler as $key => &$val) {' . |
|
131 | - 'if ($key !== \'__varHandler\'' . $exception . ') {' . |
|
132 | - '$val = ${$key};' . |
|
133 | - '}' . |
|
134 | - '}' |
|
135 | - )); |
|
136 | - } |
|
137 | - |
|
138 | - $this->buffer($this->createCode($code)); |
|
139 | - } |
|
140 | - |
|
141 | - /** |
|
142 | - * @param Nodes\Mixin $mixin |
|
143 | - */ |
|
144 | - protected function visitMixinCall(Mixin $mixin, $name, $blockName, $attributes) |
|
145 | - { |
|
146 | - $arguments = $mixin->arguments; |
|
147 | - $block = $mixin->block; |
|
148 | - $defaultAttributes = array(); |
|
149 | - $containsOnlyArrays = true; |
|
150 | - $arguments = $this->parseMixinArguments($mixin->arguments, $containsOnlyArrays, $defaultAttributes); |
|
151 | - |
|
152 | - $defaultAttributes = implode(', ', $defaultAttributes); |
|
153 | - $attributes = $this->parseMixinAttributes($attributes, $defaultAttributes, $mixin->attributes); |
|
154 | - |
|
155 | - if ($block) { |
|
156 | - $this->renderClosureOpenning("\\Jade\\Compiler::recordMixinBlock($blockName, ", 'attributes'); |
|
157 | - $this->visit($block); |
|
158 | - $this->renderClosureClosing('});'); |
|
159 | - } |
|
160 | - |
|
161 | - $strings = array(); |
|
162 | - $arguments = preg_replace_callback( |
|
163 | - '#([\'"])(.*(?!<\\\\)(?:\\\\{2})*)\\1#U', |
|
164 | - function ($match) use (&$strings) { |
|
165 | - $nextIndex = count($strings); |
|
166 | - $strings[] = $match[0]; |
|
167 | - |
|
168 | - return 'stringToReplaceBy' . $nextIndex . 'ThCapture'; |
|
169 | - }, |
|
170 | - $arguments |
|
171 | - ); |
|
172 | - $arguments = array_map( |
|
173 | - function ($arg) use ($strings) { |
|
174 | - return preg_replace_callback( |
|
175 | - '#stringToReplaceBy([0-9]+)ThCapture#', |
|
176 | - function ($match) use ($strings) { |
|
177 | - return $strings[intval($match[1])]; |
|
178 | - }, |
|
179 | - $arg |
|
180 | - ); |
|
181 | - }, |
|
182 | - $arguments |
|
183 | - ); |
|
184 | - |
|
185 | - array_unshift($arguments, $attributes); |
|
186 | - $arguments = array_filter($arguments, 'strlen'); |
|
187 | - $statements = $this->apply('createStatements', $arguments); |
|
188 | - |
|
189 | - $variables = array_pop($statements); |
|
190 | - if ($mixin->call && $containsOnlyArrays) { |
|
191 | - array_splice($variables, 1, 0, array('null')); |
|
192 | - } |
|
193 | - $variables = implode(', ', $variables); |
|
194 | - array_push($statements, $variables); |
|
195 | - |
|
196 | - $arguments = $statements; |
|
197 | - |
|
198 | - $paramsPrefix = ''; |
|
199 | - if (!$this->restrictedScope) { |
|
200 | - $this->buffer($this->createCode('$__varHandler = get_defined_vars();')); |
|
201 | - $paramsPrefix = '$__varHandler, '; |
|
202 | - } |
|
203 | - $codeFormat = str_repeat('%s;', count($arguments) - 1) . "{$name}({$paramsPrefix}%s)"; |
|
204 | - |
|
205 | - array_unshift($arguments, $codeFormat); |
|
206 | - |
|
207 | - $this->buffer($this->apply('createCode', $arguments)); |
|
208 | - if (!$this->restrictedScope) { |
|
209 | - $this->buffer( |
|
210 | - $this->createCode( |
|
211 | - 'extract(array_diff_key($__varHandler, array(\'__varHandler\' => 1, \'attributes\' => 1)));' |
|
212 | - ) |
|
213 | - ); |
|
214 | - } |
|
215 | - |
|
216 | - if ($block) { |
|
217 | - $code = $this->createCode("\\Jade\\Compiler::terminateMixinBlock($blockName);"); |
|
218 | - $this->buffer($code); |
|
219 | - } |
|
220 | - } |
|
221 | - |
|
222 | - protected function visitMixinCodeAndBlock($name, $block, $arguments) |
|
223 | - { |
|
224 | - $this->renderClosureOpenning( |
|
225 | - $this->allowMixinOverride |
|
226 | - ? "{$name} = " |
|
227 | - : array("if(!function_exists('{$name}')) { ", $name), |
|
228 | - implode(',', $arguments) |
|
229 | - ); |
|
230 | - $this->indents++; |
|
231 | - $this->visit($block); |
|
232 | - $this->indents--; |
|
233 | - $this->renderClosureClosing($this->allowMixinOverride ? '};' : '} }', $arguments); |
|
234 | - } |
|
235 | - |
|
236 | - /** |
|
237 | - * @param Nodes\Mixin $mixin |
|
238 | - */ |
|
239 | - protected function visitMixinDeclaration(Mixin $mixin, $name) |
|
240 | - { |
|
241 | - $arguments = $mixin->arguments; |
|
242 | - $block = $mixin->block; |
|
243 | - $previousVisitedMixin = isset($this->visitedMixin) ? $this->visitedMixin : null; |
|
244 | - $this->visitedMixin = $mixin; |
|
245 | - if ($arguments === null || empty($arguments)) { |
|
246 | - $arguments = array(); |
|
247 | - } elseif (!is_array($arguments)) { |
|
248 | - $arguments = array($arguments); |
|
249 | - } |
|
250 | - |
|
251 | - array_unshift($arguments, 'attributes'); |
|
252 | - $arguments = implode(',', $arguments); |
|
253 | - $arguments = explode(',', $arguments); |
|
254 | - array_walk($arguments, array(get_class(), 'initArgToNull')); |
|
255 | - $this->visitMixinCodeAndBlock($name, $block, $arguments); |
|
256 | - |
|
257 | - if (is_null($previousVisitedMixin)) { |
|
258 | - unset($this->visitedMixin); |
|
259 | - |
|
260 | - return; |
|
261 | - } |
|
262 | - |
|
263 | - $this->visitedMixin = $previousVisitedMixin; |
|
264 | - } |
|
265 | - |
|
266 | - /** |
|
267 | - * @param Nodes\Mixin $mixin |
|
268 | - */ |
|
269 | - protected function visitMixin(Mixin $mixin) |
|
270 | - { |
|
271 | - $name = strtr($mixin->name, '-', '_') . '_mixin'; |
|
272 | - $blockName = var_export($mixin->name, true); |
|
273 | - if ($this->allowMixinOverride) { |
|
274 | - $name = '$GLOBALS[\'' . $name . '\']'; |
|
275 | - } |
|
276 | - $attributes = static::decodeAttributes($mixin->attributes); |
|
277 | - |
|
278 | - if ($mixin->call) { |
|
279 | - $this->visitMixinCall($mixin, $name, $blockName, $attributes); |
|
280 | - |
|
281 | - return; |
|
282 | - } |
|
283 | - |
|
284 | - $this->visitMixinDeclaration($mixin, $name); |
|
285 | - } |
|
9 | + protected function getMixinArgumentAssign($argument) |
|
10 | + { |
|
11 | + $argument = trim($argument); |
|
12 | + |
|
13 | + if (preg_match('`^[a-zA-Z][a-zA-Z0-9:_-]*\s*=`', $argument)) { |
|
14 | + return explode('=', $argument, 2); |
|
15 | + } |
|
16 | + } |
|
17 | + |
|
18 | + protected function parseMixinArguments(&$arguments, &$containsOnlyArrays, &$defaultAttributes) |
|
19 | + { |
|
20 | + $newArrayKey = null; |
|
21 | + $arguments = is_null($arguments) ? array() : explode(',', $arguments); |
|
22 | + foreach ($arguments as $key => &$argument) { |
|
23 | + if ($tab = $this->getMixinArgumentAssign($argument)) { |
|
24 | + if (is_null($newArrayKey)) { |
|
25 | + $newArrayKey = $key; |
|
26 | + $argument = array(); |
|
27 | + } else { |
|
28 | + unset($arguments[$key]); |
|
29 | + } |
|
30 | + |
|
31 | + $defaultAttributes[] = var_export($tab[0], true) . ' => ' . $tab[1]; |
|
32 | + $arguments[$newArrayKey][$tab[0]] = static::decodeValue($tab[1]); |
|
33 | + continue; |
|
34 | + } |
|
35 | + |
|
36 | + $containsOnlyArrays = false; |
|
37 | + $newArrayKey = null; |
|
38 | + } |
|
39 | + |
|
40 | + return array_map(function ($argument) { |
|
41 | + if (is_array($argument)) { |
|
42 | + $argument = var_export($argument, true); |
|
43 | + } |
|
44 | + |
|
45 | + return $argument; |
|
46 | + }, $arguments); |
|
47 | + } |
|
48 | + |
|
49 | + protected function parseMixinStringAttribute($data) |
|
50 | + { |
|
51 | + $value = is_array($data['value']) |
|
52 | + ? preg_split('`\s+`', trim(implode(' ', $data['value']))) |
|
53 | + : trim($data['value']); |
|
54 | + |
|
55 | + return $data['escaped'] === true |
|
56 | + ? is_array($value) |
|
57 | + ? array_map('htmlspecialchars', $value) |
|
58 | + : htmlspecialchars($value) |
|
59 | + : $value; |
|
60 | + } |
|
61 | + |
|
62 | + protected function parseMixinAttribute($data) |
|
63 | + { |
|
64 | + if ($data['value'] === 'null' || $data['value'] === 'undefined' || is_null($data['value'])) { |
|
65 | + return; |
|
66 | + } |
|
67 | + |
|
68 | + if (is_bool($data['value'])) { |
|
69 | + return $data['value']; |
|
70 | + } |
|
71 | + |
|
72 | + return $this->parseMixinStringAttribute($data); |
|
73 | + } |
|
74 | + |
|
75 | + protected function parseMixinAttributes($attributes, $defaultAttributes, $mixinAttributes) |
|
76 | + { |
|
77 | + if (!count($attributes)) { |
|
78 | + return "(isset(\$attributes)) ? \$attributes : array($defaultAttributes)"; |
|
79 | + } |
|
80 | + |
|
81 | + $parsedAttributes = array(); |
|
82 | + foreach ($attributes as $data) { |
|
83 | + $parsedAttributes[$data['name']] = $this->parseMixinAttribute($data); |
|
84 | + } |
|
85 | + |
|
86 | + $attributes = var_export($parsedAttributes, true); |
|
87 | + $mixinAttributes = var_export(static::decodeAttributes($mixinAttributes), true); |
|
88 | + |
|
89 | + return "array_merge(\\Jade\\Compiler::withMixinAttributes($attributes, $mixinAttributes), (isset(\$attributes)) ? \$attributes : array($defaultAttributes))"; |
|
90 | + } |
|
91 | + |
|
92 | + protected function renderClosureOpenning() |
|
93 | + { |
|
94 | + $arguments = func_get_args(); |
|
95 | + $begin = array_shift($arguments); |
|
96 | + $begin = is_array($begin) |
|
97 | + ? $begin[0] . 'function ' . $begin[1] |
|
98 | + : $begin . 'function '; |
|
99 | + $params = implode(', ', array_map(function ($name) { |
|
100 | + return (substr($name, 0, 1) === '$' ? '' : '$') . $name; |
|
101 | + }, $arguments)); |
|
102 | + |
|
103 | + if ($this->restrictedScope) { |
|
104 | + return $this->buffer($this->createCode($begin . '(' . $params . ') {')); |
|
105 | + } |
|
106 | + |
|
107 | + $params = '&$__varHandler, ' . $params; |
|
108 | + |
|
109 | + $this->buffer( |
|
110 | + $this->createCode($begin . '(' . $params . ') {') . |
|
111 | + $this->createCode($this->indent() . 'extract($__varHandler, EXTR_SKIP);') |
|
112 | + ); |
|
113 | + } |
|
114 | + |
|
115 | + protected function renderClosureClosing($code, $arguments = array()) |
|
116 | + { |
|
117 | + if (!$this->restrictedScope) { |
|
118 | + $arguments = array_filter(array_map(function ($argument) { |
|
119 | + $argument = explode('=', $argument); |
|
120 | + $argument = trim($argument[0]); |
|
121 | + |
|
122 | + return substr($argument, 0, 1) === '$' |
|
123 | + ? substr($argument, 1) |
|
124 | + : false; |
|
125 | + }, array_slice($arguments, 1))); |
|
126 | + $exception = count($arguments) |
|
127 | + ? ' && !in_array($key, ' . var_export($arguments, true) . ')' |
|
128 | + : ''; |
|
129 | + $this->buffer($this->createCode( |
|
130 | + 'foreach ($__varHandler as $key => &$val) {' . |
|
131 | + 'if ($key !== \'__varHandler\'' . $exception . ') {' . |
|
132 | + '$val = ${$key};' . |
|
133 | + '}' . |
|
134 | + '}' |
|
135 | + )); |
|
136 | + } |
|
137 | + |
|
138 | + $this->buffer($this->createCode($code)); |
|
139 | + } |
|
140 | + |
|
141 | + /** |
|
142 | + * @param Nodes\Mixin $mixin |
|
143 | + */ |
|
144 | + protected function visitMixinCall(Mixin $mixin, $name, $blockName, $attributes) |
|
145 | + { |
|
146 | + $arguments = $mixin->arguments; |
|
147 | + $block = $mixin->block; |
|
148 | + $defaultAttributes = array(); |
|
149 | + $containsOnlyArrays = true; |
|
150 | + $arguments = $this->parseMixinArguments($mixin->arguments, $containsOnlyArrays, $defaultAttributes); |
|
151 | + |
|
152 | + $defaultAttributes = implode(', ', $defaultAttributes); |
|
153 | + $attributes = $this->parseMixinAttributes($attributes, $defaultAttributes, $mixin->attributes); |
|
154 | + |
|
155 | + if ($block) { |
|
156 | + $this->renderClosureOpenning("\\Jade\\Compiler::recordMixinBlock($blockName, ", 'attributes'); |
|
157 | + $this->visit($block); |
|
158 | + $this->renderClosureClosing('});'); |
|
159 | + } |
|
160 | + |
|
161 | + $strings = array(); |
|
162 | + $arguments = preg_replace_callback( |
|
163 | + '#([\'"])(.*(?!<\\\\)(?:\\\\{2})*)\\1#U', |
|
164 | + function ($match) use (&$strings) { |
|
165 | + $nextIndex = count($strings); |
|
166 | + $strings[] = $match[0]; |
|
167 | + |
|
168 | + return 'stringToReplaceBy' . $nextIndex . 'ThCapture'; |
|
169 | + }, |
|
170 | + $arguments |
|
171 | + ); |
|
172 | + $arguments = array_map( |
|
173 | + function ($arg) use ($strings) { |
|
174 | + return preg_replace_callback( |
|
175 | + '#stringToReplaceBy([0-9]+)ThCapture#', |
|
176 | + function ($match) use ($strings) { |
|
177 | + return $strings[intval($match[1])]; |
|
178 | + }, |
|
179 | + $arg |
|
180 | + ); |
|
181 | + }, |
|
182 | + $arguments |
|
183 | + ); |
|
184 | + |
|
185 | + array_unshift($arguments, $attributes); |
|
186 | + $arguments = array_filter($arguments, 'strlen'); |
|
187 | + $statements = $this->apply('createStatements', $arguments); |
|
188 | + |
|
189 | + $variables = array_pop($statements); |
|
190 | + if ($mixin->call && $containsOnlyArrays) { |
|
191 | + array_splice($variables, 1, 0, array('null')); |
|
192 | + } |
|
193 | + $variables = implode(', ', $variables); |
|
194 | + array_push($statements, $variables); |
|
195 | + |
|
196 | + $arguments = $statements; |
|
197 | + |
|
198 | + $paramsPrefix = ''; |
|
199 | + if (!$this->restrictedScope) { |
|
200 | + $this->buffer($this->createCode('$__varHandler = get_defined_vars();')); |
|
201 | + $paramsPrefix = '$__varHandler, '; |
|
202 | + } |
|
203 | + $codeFormat = str_repeat('%s;', count($arguments) - 1) . "{$name}({$paramsPrefix}%s)"; |
|
204 | + |
|
205 | + array_unshift($arguments, $codeFormat); |
|
206 | + |
|
207 | + $this->buffer($this->apply('createCode', $arguments)); |
|
208 | + if (!$this->restrictedScope) { |
|
209 | + $this->buffer( |
|
210 | + $this->createCode( |
|
211 | + 'extract(array_diff_key($__varHandler, array(\'__varHandler\' => 1, \'attributes\' => 1)));' |
|
212 | + ) |
|
213 | + ); |
|
214 | + } |
|
215 | + |
|
216 | + if ($block) { |
|
217 | + $code = $this->createCode("\\Jade\\Compiler::terminateMixinBlock($blockName);"); |
|
218 | + $this->buffer($code); |
|
219 | + } |
|
220 | + } |
|
221 | + |
|
222 | + protected function visitMixinCodeAndBlock($name, $block, $arguments) |
|
223 | + { |
|
224 | + $this->renderClosureOpenning( |
|
225 | + $this->allowMixinOverride |
|
226 | + ? "{$name} = " |
|
227 | + : array("if(!function_exists('{$name}')) { ", $name), |
|
228 | + implode(',', $arguments) |
|
229 | + ); |
|
230 | + $this->indents++; |
|
231 | + $this->visit($block); |
|
232 | + $this->indents--; |
|
233 | + $this->renderClosureClosing($this->allowMixinOverride ? '};' : '} }', $arguments); |
|
234 | + } |
|
235 | + |
|
236 | + /** |
|
237 | + * @param Nodes\Mixin $mixin |
|
238 | + */ |
|
239 | + protected function visitMixinDeclaration(Mixin $mixin, $name) |
|
240 | + { |
|
241 | + $arguments = $mixin->arguments; |
|
242 | + $block = $mixin->block; |
|
243 | + $previousVisitedMixin = isset($this->visitedMixin) ? $this->visitedMixin : null; |
|
244 | + $this->visitedMixin = $mixin; |
|
245 | + if ($arguments === null || empty($arguments)) { |
|
246 | + $arguments = array(); |
|
247 | + } elseif (!is_array($arguments)) { |
|
248 | + $arguments = array($arguments); |
|
249 | + } |
|
250 | + |
|
251 | + array_unshift($arguments, 'attributes'); |
|
252 | + $arguments = implode(',', $arguments); |
|
253 | + $arguments = explode(',', $arguments); |
|
254 | + array_walk($arguments, array(get_class(), 'initArgToNull')); |
|
255 | + $this->visitMixinCodeAndBlock($name, $block, $arguments); |
|
256 | + |
|
257 | + if (is_null($previousVisitedMixin)) { |
|
258 | + unset($this->visitedMixin); |
|
259 | + |
|
260 | + return; |
|
261 | + } |
|
262 | + |
|
263 | + $this->visitedMixin = $previousVisitedMixin; |
|
264 | + } |
|
265 | + |
|
266 | + /** |
|
267 | + * @param Nodes\Mixin $mixin |
|
268 | + */ |
|
269 | + protected function visitMixin(Mixin $mixin) |
|
270 | + { |
|
271 | + $name = strtr($mixin->name, '-', '_') . '_mixin'; |
|
272 | + $blockName = var_export($mixin->name, true); |
|
273 | + if ($this->allowMixinOverride) { |
|
274 | + $name = '$GLOBALS[\'' . $name . '\']'; |
|
275 | + } |
|
276 | + $attributes = static::decodeAttributes($mixin->attributes); |
|
277 | + |
|
278 | + if ($mixin->call) { |
|
279 | + $this->visitMixinCall($mixin, $name, $blockName, $attributes); |
|
280 | + |
|
281 | + return; |
|
282 | + } |
|
283 | + |
|
284 | + $this->visitMixinDeclaration($mixin, $name); |
|
285 | + } |
|
286 | 286 | } |
@@ -10,180 +10,180 @@ |
||
10 | 10 | |
11 | 11 | abstract class KeywordsCompiler extends AttributesCompiler |
12 | 12 | { |
13 | - /** |
|
14 | - * @param Nodes\CaseNode $node |
|
15 | - */ |
|
16 | - protected function visitCasenode(CaseNode $node) |
|
17 | - { |
|
18 | - $this->switchNode = $node; |
|
19 | - $this->visit($node->block); |
|
20 | - |
|
21 | - if (!isset($this->switchNode)) { |
|
22 | - unset($this->switchNode); |
|
23 | - $this->indents--; |
|
24 | - |
|
25 | - $code = $this->createCode('}'); |
|
26 | - $this->buffer($code); |
|
27 | - } |
|
28 | - } |
|
29 | - |
|
30 | - /** |
|
31 | - * @param string $expression |
|
32 | - * @param &array $arguments |
|
33 | - * |
|
34 | - * @return string |
|
35 | - */ |
|
36 | - protected function visitCase($expression, &$arguments) |
|
37 | - { |
|
38 | - if ('default' === $expression) { |
|
39 | - return 'default:'; |
|
40 | - } |
|
41 | - |
|
42 | - $arguments[] = $expression; |
|
43 | - |
|
44 | - return 'case %s:'; |
|
45 | - } |
|
46 | - |
|
47 | - /** |
|
48 | - * @param Nodes\When $node |
|
49 | - */ |
|
50 | - protected function visitWhen(When $node) |
|
51 | - { |
|
52 | - $code = ''; |
|
53 | - $arguments = array(); |
|
54 | - |
|
55 | - if (isset($this->switchNode)) { |
|
56 | - $code .= 'switch (%s) {'; |
|
57 | - $arguments[] = $this->switchNode->expr; |
|
58 | - unset($this->switchNode); |
|
59 | - |
|
60 | - $this->indents++; |
|
61 | - } |
|
62 | - |
|
63 | - $code .= $this->visitCase($node->expr, $arguments); |
|
64 | - |
|
65 | - array_unshift($arguments, $code); |
|
66 | - |
|
67 | - $code = call_user_func_array(array($this, 'createCode'), $arguments); |
|
68 | - |
|
69 | - $this->buffer($code); |
|
70 | - |
|
71 | - $this->visit($node->block); |
|
72 | - |
|
73 | - $code = $this->createCode('break;'); |
|
74 | - $this->buffer($code . $this->newline()); |
|
75 | - } |
|
76 | - |
|
77 | - /** |
|
78 | - * @param Nodes\Filter $node |
|
79 | - * |
|
80 | - * @throws \InvalidArgumentException |
|
81 | - */ |
|
82 | - protected function visitFilter(Filter $node) |
|
83 | - { |
|
84 | - $filter = $this->getFilter($node->name); |
|
85 | - |
|
86 | - // Filters can be either a iFilter implementation, nor a callable |
|
87 | - if (is_string($filter) && class_exists($filter)) { |
|
88 | - $filter = new $filter(); |
|
89 | - } |
|
90 | - if (!is_callable($filter)) { |
|
91 | - throw new \InvalidArgumentException($node->name . ': Filter must be callable', 18); |
|
92 | - } |
|
93 | - $this->buffer($filter($node, $this)); |
|
94 | - } |
|
95 | - |
|
96 | - /** |
|
97 | - * @param Nodes\Each $node |
|
98 | - */ |
|
99 | - protected function visitEach(Each $node) |
|
100 | - { |
|
101 | - //if (is_numeric($node->obj)) { |
|
102 | - //if (is_string($node->obj)) { |
|
103 | - //$serialized = serialize($node->obj); |
|
104 | - if (isset($node->alternative)) { |
|
105 | - $this->buffer($this->createCode( |
|
106 | - 'if (isset(%s) && %s) {', |
|
107 | - $node->obj, $node->obj |
|
108 | - )); |
|
109 | - $this->indents++; |
|
110 | - } |
|
111 | - |
|
112 | - $this->buffer(isset($node->key) && strlen($node->key) > 0 |
|
113 | - ? $this->createCode( |
|
114 | - 'foreach (%s as %s => %s) {', |
|
115 | - $node->obj, $node->key, $node->value |
|
116 | - ) |
|
117 | - : $this->createCode( |
|
118 | - 'foreach (%s as %s) {', |
|
119 | - $node->obj, $node->value |
|
120 | - ) |
|
121 | - ); |
|
122 | - |
|
123 | - $this->indents++; |
|
124 | - $this->visit($node->block); |
|
125 | - $this->indents--; |
|
126 | - |
|
127 | - $this->buffer($this->createCode('}')); |
|
128 | - |
|
129 | - if (isset($node->alternative)) { |
|
130 | - $this->indents--; |
|
131 | - $this->buffer($this->createCode('} else {')); |
|
132 | - $this->indents++; |
|
133 | - |
|
134 | - $this->visit($node->alternative); |
|
135 | - $this->indents--; |
|
136 | - |
|
137 | - $this->buffer($this->createCode('}')); |
|
138 | - } |
|
139 | - } |
|
140 | - |
|
141 | - protected function bufferCustomKeyword($data, $block) |
|
142 | - { |
|
143 | - if (isset($data['begin'])) { |
|
144 | - $this->buffer($data['begin']); |
|
145 | - } |
|
146 | - |
|
147 | - if ($block) { |
|
148 | - $this->indents++; |
|
149 | - $this->visit($block); |
|
150 | - $this->indents--; |
|
151 | - } |
|
152 | - |
|
153 | - if (isset($data['end'])) { |
|
154 | - $this->buffer($data['end']); |
|
155 | - } |
|
156 | - } |
|
157 | - |
|
158 | - /** |
|
159 | - * @param Nodes\CustomKeyword $node |
|
160 | - */ |
|
161 | - protected function visitCustomKeyword(CustomKeyword $node) |
|
162 | - { |
|
163 | - $action = $this->options['customKeywords'][$node->keyWord]; |
|
164 | - |
|
165 | - $data = $action($node->args, $node->block, $node->keyWord); |
|
166 | - |
|
167 | - if (is_string($data)) { |
|
168 | - $data = array( |
|
169 | - 'begin' => $data, |
|
170 | - ); |
|
171 | - } |
|
172 | - |
|
173 | - if (!is_array($data) && !($data instanceof \ArrayAccess)) { |
|
174 | - throw new \ErrorException("The keyword {$node->keyWord} returned an invalid value type, string or array was expected.", 33); |
|
175 | - } |
|
176 | - |
|
177 | - foreach (array('begin', 'end') as $key) { |
|
178 | - $data[$key] = (isset($data[$key . 'Php']) |
|
179 | - ? $this->createCode($data[$key . 'Php']) |
|
180 | - : '' |
|
181 | - ) . (isset($data[$key]) |
|
182 | - ? $data[$key] |
|
183 | - : '' |
|
184 | - ); |
|
185 | - } |
|
186 | - |
|
187 | - $this->bufferCustomKeyword($data, $node->block); |
|
188 | - } |
|
13 | + /** |
|
14 | + * @param Nodes\CaseNode $node |
|
15 | + */ |
|
16 | + protected function visitCasenode(CaseNode $node) |
|
17 | + { |
|
18 | + $this->switchNode = $node; |
|
19 | + $this->visit($node->block); |
|
20 | + |
|
21 | + if (!isset($this->switchNode)) { |
|
22 | + unset($this->switchNode); |
|
23 | + $this->indents--; |
|
24 | + |
|
25 | + $code = $this->createCode('}'); |
|
26 | + $this->buffer($code); |
|
27 | + } |
|
28 | + } |
|
29 | + |
|
30 | + /** |
|
31 | + * @param string $expression |
|
32 | + * @param &array $arguments |
|
33 | + * |
|
34 | + * @return string |
|
35 | + */ |
|
36 | + protected function visitCase($expression, &$arguments) |
|
37 | + { |
|
38 | + if ('default' === $expression) { |
|
39 | + return 'default:'; |
|
40 | + } |
|
41 | + |
|
42 | + $arguments[] = $expression; |
|
43 | + |
|
44 | + return 'case %s:'; |
|
45 | + } |
|
46 | + |
|
47 | + /** |
|
48 | + * @param Nodes\When $node |
|
49 | + */ |
|
50 | + protected function visitWhen(When $node) |
|
51 | + { |
|
52 | + $code = ''; |
|
53 | + $arguments = array(); |
|
54 | + |
|
55 | + if (isset($this->switchNode)) { |
|
56 | + $code .= 'switch (%s) {'; |
|
57 | + $arguments[] = $this->switchNode->expr; |
|
58 | + unset($this->switchNode); |
|
59 | + |
|
60 | + $this->indents++; |
|
61 | + } |
|
62 | + |
|
63 | + $code .= $this->visitCase($node->expr, $arguments); |
|
64 | + |
|
65 | + array_unshift($arguments, $code); |
|
66 | + |
|
67 | + $code = call_user_func_array(array($this, 'createCode'), $arguments); |
|
68 | + |
|
69 | + $this->buffer($code); |
|
70 | + |
|
71 | + $this->visit($node->block); |
|
72 | + |
|
73 | + $code = $this->createCode('break;'); |
|
74 | + $this->buffer($code . $this->newline()); |
|
75 | + } |
|
76 | + |
|
77 | + /** |
|
78 | + * @param Nodes\Filter $node |
|
79 | + * |
|
80 | + * @throws \InvalidArgumentException |
|
81 | + */ |
|
82 | + protected function visitFilter(Filter $node) |
|
83 | + { |
|
84 | + $filter = $this->getFilter($node->name); |
|
85 | + |
|
86 | + // Filters can be either a iFilter implementation, nor a callable |
|
87 | + if (is_string($filter) && class_exists($filter)) { |
|
88 | + $filter = new $filter(); |
|
89 | + } |
|
90 | + if (!is_callable($filter)) { |
|
91 | + throw new \InvalidArgumentException($node->name . ': Filter must be callable', 18); |
|
92 | + } |
|
93 | + $this->buffer($filter($node, $this)); |
|
94 | + } |
|
95 | + |
|
96 | + /** |
|
97 | + * @param Nodes\Each $node |
|
98 | + */ |
|
99 | + protected function visitEach(Each $node) |
|
100 | + { |
|
101 | + //if (is_numeric($node->obj)) { |
|
102 | + //if (is_string($node->obj)) { |
|
103 | + //$serialized = serialize($node->obj); |
|
104 | + if (isset($node->alternative)) { |
|
105 | + $this->buffer($this->createCode( |
|
106 | + 'if (isset(%s) && %s) {', |
|
107 | + $node->obj, $node->obj |
|
108 | + )); |
|
109 | + $this->indents++; |
|
110 | + } |
|
111 | + |
|
112 | + $this->buffer(isset($node->key) && strlen($node->key) > 0 |
|
113 | + ? $this->createCode( |
|
114 | + 'foreach (%s as %s => %s) {', |
|
115 | + $node->obj, $node->key, $node->value |
|
116 | + ) |
|
117 | + : $this->createCode( |
|
118 | + 'foreach (%s as %s) {', |
|
119 | + $node->obj, $node->value |
|
120 | + ) |
|
121 | + ); |
|
122 | + |
|
123 | + $this->indents++; |
|
124 | + $this->visit($node->block); |
|
125 | + $this->indents--; |
|
126 | + |
|
127 | + $this->buffer($this->createCode('}')); |
|
128 | + |
|
129 | + if (isset($node->alternative)) { |
|
130 | + $this->indents--; |
|
131 | + $this->buffer($this->createCode('} else {')); |
|
132 | + $this->indents++; |
|
133 | + |
|
134 | + $this->visit($node->alternative); |
|
135 | + $this->indents--; |
|
136 | + |
|
137 | + $this->buffer($this->createCode('}')); |
|
138 | + } |
|
139 | + } |
|
140 | + |
|
141 | + protected function bufferCustomKeyword($data, $block) |
|
142 | + { |
|
143 | + if (isset($data['begin'])) { |
|
144 | + $this->buffer($data['begin']); |
|
145 | + } |
|
146 | + |
|
147 | + if ($block) { |
|
148 | + $this->indents++; |
|
149 | + $this->visit($block); |
|
150 | + $this->indents--; |
|
151 | + } |
|
152 | + |
|
153 | + if (isset($data['end'])) { |
|
154 | + $this->buffer($data['end']); |
|
155 | + } |
|
156 | + } |
|
157 | + |
|
158 | + /** |
|
159 | + * @param Nodes\CustomKeyword $node |
|
160 | + */ |
|
161 | + protected function visitCustomKeyword(CustomKeyword $node) |
|
162 | + { |
|
163 | + $action = $this->options['customKeywords'][$node->keyWord]; |
|
164 | + |
|
165 | + $data = $action($node->args, $node->block, $node->keyWord); |
|
166 | + |
|
167 | + if (is_string($data)) { |
|
168 | + $data = array( |
|
169 | + 'begin' => $data, |
|
170 | + ); |
|
171 | + } |
|
172 | + |
|
173 | + if (!is_array($data) && !($data instanceof \ArrayAccess)) { |
|
174 | + throw new \ErrorException("The keyword {$node->keyWord} returned an invalid value type, string or array was expected.", 33); |
|
175 | + } |
|
176 | + |
|
177 | + foreach (array('begin', 'end') as $key) { |
|
178 | + $data[$key] = (isset($data[$key . 'Php']) |
|
179 | + ? $this->createCode($data[$key . 'Php']) |
|
180 | + : '' |
|
181 | + ) . (isset($data[$key]) |
|
182 | + ? $data[$key] |
|
183 | + : '' |
|
184 | + ); |
|
185 | + } |
|
186 | + |
|
187 | + $this->bufferCustomKeyword($data, $node->block); |
|
188 | + } |
|
189 | 189 | } |
@@ -8,165 +8,165 @@ |
||
8 | 8 | */ |
9 | 9 | abstract class CompilerFacade extends ValuesCompiler |
10 | 10 | { |
11 | - protected static $mixinBlocks = array(); |
|
11 | + protected static $mixinBlocks = array(); |
|
12 | 12 | |
13 | - /** |
|
14 | - * Record a closure as a mixin block during execution jade template time. |
|
15 | - * |
|
16 | - * @param string mixin name |
|
17 | - * @param string mixin block treatment |
|
18 | - */ |
|
19 | - public static function recordMixinBlock($name, $func = null) |
|
20 | - { |
|
21 | - if (!isset(static::$mixinBlocks[$name])) { |
|
22 | - static::$mixinBlocks[$name] = array(); |
|
23 | - } |
|
24 | - array_push(static::$mixinBlocks[$name], $func); |
|
25 | - } |
|
13 | + /** |
|
14 | + * Record a closure as a mixin block during execution jade template time. |
|
15 | + * |
|
16 | + * @param string mixin name |
|
17 | + * @param string mixin block treatment |
|
18 | + */ |
|
19 | + public static function recordMixinBlock($name, $func = null) |
|
20 | + { |
|
21 | + if (!isset(static::$mixinBlocks[$name])) { |
|
22 | + static::$mixinBlocks[$name] = array(); |
|
23 | + } |
|
24 | + array_push(static::$mixinBlocks[$name], $func); |
|
25 | + } |
|
26 | 26 | |
27 | - /** |
|
28 | - * Record a closure as a mixin block during execution jade template time. |
|
29 | - * |
|
30 | - * @param string mixin name |
|
31 | - * @param string mixin block treatment |
|
32 | - */ |
|
33 | - public static function callMixinBlock($name, $attributes = array()) |
|
34 | - { |
|
35 | - if (isset(static::$mixinBlocks[$name]) && is_array($mixinBlocks = static::$mixinBlocks[$name])) { |
|
36 | - $func = end($mixinBlocks); |
|
37 | - if (is_callable($func)) { |
|
38 | - $func($attributes); |
|
39 | - } |
|
40 | - } |
|
41 | - } |
|
27 | + /** |
|
28 | + * Record a closure as a mixin block during execution jade template time. |
|
29 | + * |
|
30 | + * @param string mixin name |
|
31 | + * @param string mixin block treatment |
|
32 | + */ |
|
33 | + public static function callMixinBlock($name, $attributes = array()) |
|
34 | + { |
|
35 | + if (isset(static::$mixinBlocks[$name]) && is_array($mixinBlocks = static::$mixinBlocks[$name])) { |
|
36 | + $func = end($mixinBlocks); |
|
37 | + if (is_callable($func)) { |
|
38 | + $func($attributes); |
|
39 | + } |
|
40 | + } |
|
41 | + } |
|
42 | 42 | |
43 | - /** |
|
44 | - * Record a closure as a mixin block during execution jade template time |
|
45 | - * and propagate variables. |
|
46 | - * |
|
47 | - * @param string mixin name |
|
48 | - * @param &array variables handler propagated from parent scope |
|
49 | - * @param string mixin block treatment |
|
50 | - */ |
|
51 | - public static function callMixinBlockWithVars($name, &$varHandler, $attributes = array()) |
|
52 | - { |
|
53 | - if (isset(static::$mixinBlocks[$name]) && is_array($mixinBlocks = static::$mixinBlocks[$name])) { |
|
54 | - $func = end($mixinBlocks); |
|
55 | - if (is_callable($func)) { |
|
56 | - $func($varHandler, $attributes); |
|
57 | - } |
|
58 | - } |
|
59 | - } |
|
43 | + /** |
|
44 | + * Record a closure as a mixin block during execution jade template time |
|
45 | + * and propagate variables. |
|
46 | + * |
|
47 | + * @param string mixin name |
|
48 | + * @param &array variables handler propagated from parent scope |
|
49 | + * @param string mixin block treatment |
|
50 | + */ |
|
51 | + public static function callMixinBlockWithVars($name, &$varHandler, $attributes = array()) |
|
52 | + { |
|
53 | + if (isset(static::$mixinBlocks[$name]) && is_array($mixinBlocks = static::$mixinBlocks[$name])) { |
|
54 | + $func = end($mixinBlocks); |
|
55 | + if (is_callable($func)) { |
|
56 | + $func($varHandler, $attributes); |
|
57 | + } |
|
58 | + } |
|
59 | + } |
|
60 | 60 | |
61 | - /** |
|
62 | - * End of the record of the mixin block. |
|
63 | - * |
|
64 | - * @param string mixin name |
|
65 | - */ |
|
66 | - public static function terminateMixinBlock($name) |
|
67 | - { |
|
68 | - if (isset(static::$mixinBlocks[$name])) { |
|
69 | - array_pop(static::$mixinBlocks); |
|
70 | - } |
|
71 | - } |
|
61 | + /** |
|
62 | + * End of the record of the mixin block. |
|
63 | + * |
|
64 | + * @param string mixin name |
|
65 | + */ |
|
66 | + public static function terminateMixinBlock($name) |
|
67 | + { |
|
68 | + if (isset(static::$mixinBlocks[$name])) { |
|
69 | + array_pop(static::$mixinBlocks); |
|
70 | + } |
|
71 | + } |
|
72 | 72 | |
73 | - /** |
|
74 | - * Get property from object. |
|
75 | - * |
|
76 | - * @param object $object source object |
|
77 | - * @param mixed $key key to retrive from the object or the array |
|
78 | - * |
|
79 | - * @return mixed |
|
80 | - */ |
|
81 | - public static function getPropertyFromObject($anything, $key) |
|
82 | - { |
|
83 | - return isset($anything->$key) |
|
84 | - ? $anything->$key |
|
85 | - : (method_exists($anything, $method = 'get' . ucfirst($key)) |
|
86 | - ? $anything->$method() |
|
87 | - : (method_exists($anything, $key) |
|
88 | - ? array($anything, $key) |
|
89 | - : null |
|
90 | - ) |
|
91 | - ); |
|
92 | - } |
|
73 | + /** |
|
74 | + * Get property from object. |
|
75 | + * |
|
76 | + * @param object $object source object |
|
77 | + * @param mixed $key key to retrive from the object or the array |
|
78 | + * |
|
79 | + * @return mixed |
|
80 | + */ |
|
81 | + public static function getPropertyFromObject($anything, $key) |
|
82 | + { |
|
83 | + return isset($anything->$key) |
|
84 | + ? $anything->$key |
|
85 | + : (method_exists($anything, $method = 'get' . ucfirst($key)) |
|
86 | + ? $anything->$method() |
|
87 | + : (method_exists($anything, $key) |
|
88 | + ? array($anything, $key) |
|
89 | + : null |
|
90 | + ) |
|
91 | + ); |
|
92 | + } |
|
93 | 93 | |
94 | - /** |
|
95 | - * Get property from object or entry from array. |
|
96 | - * |
|
97 | - * @param object|array $anything source |
|
98 | - * @param mixed $key key to retrive from the object or the array |
|
99 | - * |
|
100 | - * @return mixed |
|
101 | - */ |
|
102 | - public static function getPropertyFromAnything($anything, $key) |
|
103 | - { |
|
104 | - return is_array($anything) |
|
105 | - ? (isset($anything[$key]) |
|
106 | - ? $anything[$key] |
|
107 | - : null |
|
108 | - ) : (is_object($anything) |
|
109 | - ? static::getPropertyFromObject($anything, $key) |
|
110 | - : null |
|
111 | - ); |
|
112 | - } |
|
94 | + /** |
|
95 | + * Get property from object or entry from array. |
|
96 | + * |
|
97 | + * @param object|array $anything source |
|
98 | + * @param mixed $key key to retrive from the object or the array |
|
99 | + * |
|
100 | + * @return mixed |
|
101 | + */ |
|
102 | + public static function getPropertyFromAnything($anything, $key) |
|
103 | + { |
|
104 | + return is_array($anything) |
|
105 | + ? (isset($anything[$key]) |
|
106 | + ? $anything[$key] |
|
107 | + : null |
|
108 | + ) : (is_object($anything) |
|
109 | + ? static::getPropertyFromObject($anything, $key) |
|
110 | + : null |
|
111 | + ); |
|
112 | + } |
|
113 | 113 | |
114 | - /** |
|
115 | - * Merge given attributes such as tag attributes with mixin attributes. |
|
116 | - * |
|
117 | - * @param array $attributes |
|
118 | - * @param array $mixinAttributes |
|
119 | - * |
|
120 | - * @return array |
|
121 | - */ |
|
122 | - public static function withMixinAttributes($attributes, $mixinAttributes) |
|
123 | - { |
|
124 | - foreach ($mixinAttributes as $attribute) { |
|
125 | - if ($attribute['name'] === 'class') { |
|
126 | - $value = static::joinAny($attribute['value']); |
|
127 | - $attributes['class'] = empty($attributes['class']) |
|
128 | - ? $value |
|
129 | - : static::joinAny($attributes['class']) . ' ' . $value; |
|
130 | - } |
|
131 | - } |
|
132 | - if (isset($attributes['class'])) { |
|
133 | - $attributes['class'] = implode(' ', array_unique(explode(' ', $attributes['class']))); |
|
134 | - } |
|
114 | + /** |
|
115 | + * Merge given attributes such as tag attributes with mixin attributes. |
|
116 | + * |
|
117 | + * @param array $attributes |
|
118 | + * @param array $mixinAttributes |
|
119 | + * |
|
120 | + * @return array |
|
121 | + */ |
|
122 | + public static function withMixinAttributes($attributes, $mixinAttributes) |
|
123 | + { |
|
124 | + foreach ($mixinAttributes as $attribute) { |
|
125 | + if ($attribute['name'] === 'class') { |
|
126 | + $value = static::joinAny($attribute['value']); |
|
127 | + $attributes['class'] = empty($attributes['class']) |
|
128 | + ? $value |
|
129 | + : static::joinAny($attributes['class']) . ' ' . $value; |
|
130 | + } |
|
131 | + } |
|
132 | + if (isset($attributes['class'])) { |
|
133 | + $attributes['class'] = implode(' ', array_unique(explode(' ', $attributes['class']))); |
|
134 | + } |
|
135 | 135 | |
136 | - return $attributes; |
|
137 | - } |
|
136 | + return $attributes; |
|
137 | + } |
|
138 | 138 | |
139 | - /** |
|
140 | - * Display a list of attributes with the given quote character in HTML. |
|
141 | - * |
|
142 | - * @param array $attributes |
|
143 | - * @param string $quote |
|
144 | - */ |
|
145 | - public static function displayAttributes($attributes, $quote, $terse) |
|
146 | - { |
|
147 | - if (is_array($attributes) || $attributes instanceof Traversable) { |
|
148 | - foreach ($attributes as $key => $value) { |
|
149 | - if ($key !== 'class' && $value !== false && $value !== 'null') { |
|
150 | - if ($value === true) { |
|
151 | - echo ' ' . $key . ($terse ? '' : '=' . $quote . $key . $quote); |
|
152 | - continue; |
|
153 | - } |
|
154 | - echo ' ' . $key . '=' . $quote . htmlspecialchars($value) . $quote; |
|
155 | - } |
|
156 | - } |
|
157 | - } |
|
158 | - } |
|
139 | + /** |
|
140 | + * Display a list of attributes with the given quote character in HTML. |
|
141 | + * |
|
142 | + * @param array $attributes |
|
143 | + * @param string $quote |
|
144 | + */ |
|
145 | + public static function displayAttributes($attributes, $quote, $terse) |
|
146 | + { |
|
147 | + if (is_array($attributes) || $attributes instanceof Traversable) { |
|
148 | + foreach ($attributes as $key => $value) { |
|
149 | + if ($key !== 'class' && $value !== false && $value !== 'null') { |
|
150 | + if ($value === true) { |
|
151 | + echo ' ' . $key . ($terse ? '' : '=' . $quote . $key . $quote); |
|
152 | + continue; |
|
153 | + } |
|
154 | + echo ' ' . $key . '=' . $quote . htmlspecialchars($value) . $quote; |
|
155 | + } |
|
156 | + } |
|
157 | + } |
|
158 | + } |
|
159 | 159 | |
160 | - /** |
|
161 | - * Return true if the given value can be display |
|
162 | - * (null or false should not be displayed in the output HTML). |
|
163 | - * |
|
164 | - * @param $value |
|
165 | - * |
|
166 | - * @return bool |
|
167 | - */ |
|
168 | - public static function isDisplayable($value) |
|
169 | - { |
|
170 | - return !is_null($value) && $value !== false; |
|
171 | - } |
|
160 | + /** |
|
161 | + * Return true if the given value can be display |
|
162 | + * (null or false should not be displayed in the output HTML). |
|
163 | + * |
|
164 | + * @param $value |
|
165 | + * |
|
166 | + * @return bool |
|
167 | + */ |
|
168 | + public static function isDisplayable($value) |
|
169 | + { |
|
170 | + return !is_null($value) && $value !== false; |
|
171 | + } |
|
172 | 172 | } |
@@ -7,163 +7,163 @@ |
||
7 | 7 | |
8 | 8 | class CacheHelper |
9 | 9 | { |
10 | - protected $pug; |
|
11 | - |
|
12 | - public function __construct(Jade $pug) |
|
13 | - { |
|
14 | - $this->pug = $pug; |
|
15 | - } |
|
16 | - |
|
17 | - /** |
|
18 | - * Return a file path in the cache for a given name. |
|
19 | - * |
|
20 | - * @param string $name |
|
21 | - * |
|
22 | - * @return string |
|
23 | - */ |
|
24 | - protected function getCachePath($name) |
|
25 | - { |
|
26 | - return str_replace('//', '/', $this->pug->getOption('cache') . '/' . $name) . '.php'; |
|
27 | - } |
|
28 | - |
|
29 | - /** |
|
30 | - * Return a hashed print from input file or content. |
|
31 | - * |
|
32 | - * @param string $input |
|
33 | - * |
|
34 | - * @return string |
|
35 | - */ |
|
36 | - protected function hashPrint($input) |
|
37 | - { |
|
38 | - // Get the stronger hashing algorithm available to minimize collision risks |
|
39 | - $algos = hash_algos(); |
|
40 | - $algo = $algos[0]; |
|
41 | - $number = 0; |
|
42 | - foreach ($algos as $hashAlgorithm) { |
|
43 | - if (strpos($hashAlgorithm, 'md') === 0) { |
|
44 | - $hashNumber = substr($hashAlgorithm, 2); |
|
45 | - if ($hashNumber > $number) { |
|
46 | - $number = $hashNumber; |
|
47 | - $algo = $hashAlgorithm; |
|
48 | - } |
|
49 | - continue; |
|
50 | - } |
|
51 | - if (strpos($hashAlgorithm, 'sha') === 0) { |
|
52 | - $hashNumber = substr($hashAlgorithm, 3); |
|
53 | - if ($hashNumber > $number) { |
|
54 | - $number = $hashNumber; |
|
55 | - $algo = $hashAlgorithm; |
|
56 | - } |
|
57 | - continue; |
|
58 | - } |
|
59 | - } |
|
60 | - |
|
61 | - return rtrim(strtr(base64_encode(hash($algo, $input, true)), '+/', '-_'), '='); |
|
62 | - } |
|
63 | - |
|
64 | - /** |
|
65 | - * Return true if the file or content is up to date in the cache folder, |
|
66 | - * false else. |
|
67 | - * |
|
68 | - * @param string $input file or pug code |
|
69 | - * @param &string $path to be filled |
|
70 | - * |
|
71 | - * @return bool |
|
72 | - */ |
|
73 | - protected function isCacheUpToDate($input, &$path) |
|
74 | - { |
|
75 | - if (is_file($input)) { |
|
76 | - $path = $this->getCachePath( |
|
77 | - ($this->pug->getOption('keepBaseName') ? basename($input) : '') . |
|
78 | - $this->hashPrint(realpath($input)) |
|
79 | - ); |
|
80 | - |
|
81 | - // Do not re-parse file if original is older |
|
82 | - return (!$this->pug->getOption('upToDateCheck')) || (file_exists($path) && filemtime($input) < filemtime($path)); |
|
83 | - } |
|
84 | - |
|
85 | - $path = $this->getCachePath($this->hashPrint($input)); |
|
86 | - |
|
87 | - // Do not re-parse file if the same hash exists |
|
88 | - return file_exists($path); |
|
89 | - } |
|
90 | - |
|
91 | - protected function getCacheDirectory() |
|
92 | - { |
|
93 | - $cacheFolder = $this->pug->getOption('cache'); |
|
94 | - |
|
95 | - if (!is_dir($cacheFolder)) { |
|
96 | - throw new \ErrorException($cacheFolder . ': Cache directory seem\'s to not exists', 5); |
|
97 | - } |
|
98 | - |
|
99 | - return $cacheFolder; |
|
100 | - } |
|
101 | - |
|
102 | - /** |
|
103 | - * Get cached input/file a matching cache file exists. |
|
104 | - * Else, render the input, cache it in a file and return it. |
|
105 | - * |
|
106 | - * @param string input |
|
107 | - * |
|
108 | - * @throws \InvalidArgumentException |
|
109 | - * @throws \Exception |
|
110 | - * |
|
111 | - * @return string |
|
112 | - */ |
|
113 | - public function cache($input) |
|
114 | - { |
|
115 | - $cacheFolder = $this->getCacheDirectory(); |
|
116 | - |
|
117 | - if ($this->isCacheUpToDate($input, $path)) { |
|
118 | - return $path; |
|
119 | - } |
|
120 | - |
|
121 | - if (!is_writable($cacheFolder)) { |
|
122 | - throw new \ErrorException(sprintf('Cache directory must be writable. "%s" is not.', $cacheFolder), 6); |
|
123 | - } |
|
124 | - |
|
125 | - $rendered = $this->pug->compile($input); |
|
126 | - file_put_contents($path, $rendered); |
|
127 | - |
|
128 | - return $this->pug->stream($rendered); |
|
129 | - } |
|
130 | - |
|
131 | - /** |
|
132 | - * Scan a directory recursively, compile them and save them into the cache directory. |
|
133 | - * |
|
134 | - * @param string $directory the directory to search in pug templates |
|
135 | - * |
|
136 | - * @return array count of cached files and error count |
|
137 | - */ |
|
138 | - public function cacheDirectory($directory) |
|
139 | - { |
|
140 | - $success = 0; |
|
141 | - $errors = 0; |
|
142 | - |
|
143 | - $extensions = new ExtensionsHelper($this->pug->getOption('extension')); |
|
144 | - |
|
145 | - foreach (scandir($directory) as $object) { |
|
146 | - if ($object === '.' || $object === '..') { |
|
147 | - continue; |
|
148 | - } |
|
149 | - $input = $directory . DIRECTORY_SEPARATOR . $object; |
|
150 | - if (is_dir($input)) { |
|
151 | - list($subSuccess, $subErrors) = $this->cacheDirectory($input); |
|
152 | - $success += $subSuccess; |
|
153 | - $errors += $subErrors; |
|
154 | - continue; |
|
155 | - } |
|
156 | - if ($extensions->hasValidTemplateExtension($object)) { |
|
157 | - $this->isCacheUpToDate($input, $path); |
|
158 | - try { |
|
159 | - file_put_contents($path, $this->pug->compile($input)); |
|
160 | - $success++; |
|
161 | - } catch (\Exception $e) { |
|
162 | - $errors++; |
|
163 | - } |
|
164 | - } |
|
165 | - } |
|
166 | - |
|
167 | - return array($success, $errors); |
|
168 | - } |
|
10 | + protected $pug; |
|
11 | + |
|
12 | + public function __construct(Jade $pug) |
|
13 | + { |
|
14 | + $this->pug = $pug; |
|
15 | + } |
|
16 | + |
|
17 | + /** |
|
18 | + * Return a file path in the cache for a given name. |
|
19 | + * |
|
20 | + * @param string $name |
|
21 | + * |
|
22 | + * @return string |
|
23 | + */ |
|
24 | + protected function getCachePath($name) |
|
25 | + { |
|
26 | + return str_replace('//', '/', $this->pug->getOption('cache') . '/' . $name) . '.php'; |
|
27 | + } |
|
28 | + |
|
29 | + /** |
|
30 | + * Return a hashed print from input file or content. |
|
31 | + * |
|
32 | + * @param string $input |
|
33 | + * |
|
34 | + * @return string |
|
35 | + */ |
|
36 | + protected function hashPrint($input) |
|
37 | + { |
|
38 | + // Get the stronger hashing algorithm available to minimize collision risks |
|
39 | + $algos = hash_algos(); |
|
40 | + $algo = $algos[0]; |
|
41 | + $number = 0; |
|
42 | + foreach ($algos as $hashAlgorithm) { |
|
43 | + if (strpos($hashAlgorithm, 'md') === 0) { |
|
44 | + $hashNumber = substr($hashAlgorithm, 2); |
|
45 | + if ($hashNumber > $number) { |
|
46 | + $number = $hashNumber; |
|
47 | + $algo = $hashAlgorithm; |
|
48 | + } |
|
49 | + continue; |
|
50 | + } |
|
51 | + if (strpos($hashAlgorithm, 'sha') === 0) { |
|
52 | + $hashNumber = substr($hashAlgorithm, 3); |
|
53 | + if ($hashNumber > $number) { |
|
54 | + $number = $hashNumber; |
|
55 | + $algo = $hashAlgorithm; |
|
56 | + } |
|
57 | + continue; |
|
58 | + } |
|
59 | + } |
|
60 | + |
|
61 | + return rtrim(strtr(base64_encode(hash($algo, $input, true)), '+/', '-_'), '='); |
|
62 | + } |
|
63 | + |
|
64 | + /** |
|
65 | + * Return true if the file or content is up to date in the cache folder, |
|
66 | + * false else. |
|
67 | + * |
|
68 | + * @param string $input file or pug code |
|
69 | + * @param &string $path to be filled |
|
70 | + * |
|
71 | + * @return bool |
|
72 | + */ |
|
73 | + protected function isCacheUpToDate($input, &$path) |
|
74 | + { |
|
75 | + if (is_file($input)) { |
|
76 | + $path = $this->getCachePath( |
|
77 | + ($this->pug->getOption('keepBaseName') ? basename($input) : '') . |
|
78 | + $this->hashPrint(realpath($input)) |
|
79 | + ); |
|
80 | + |
|
81 | + // Do not re-parse file if original is older |
|
82 | + return (!$this->pug->getOption('upToDateCheck')) || (file_exists($path) && filemtime($input) < filemtime($path)); |
|
83 | + } |
|
84 | + |
|
85 | + $path = $this->getCachePath($this->hashPrint($input)); |
|
86 | + |
|
87 | + // Do not re-parse file if the same hash exists |
|
88 | + return file_exists($path); |
|
89 | + } |
|
90 | + |
|
91 | + protected function getCacheDirectory() |
|
92 | + { |
|
93 | + $cacheFolder = $this->pug->getOption('cache'); |
|
94 | + |
|
95 | + if (!is_dir($cacheFolder)) { |
|
96 | + throw new \ErrorException($cacheFolder . ': Cache directory seem\'s to not exists', 5); |
|
97 | + } |
|
98 | + |
|
99 | + return $cacheFolder; |
|
100 | + } |
|
101 | + |
|
102 | + /** |
|
103 | + * Get cached input/file a matching cache file exists. |
|
104 | + * Else, render the input, cache it in a file and return it. |
|
105 | + * |
|
106 | + * @param string input |
|
107 | + * |
|
108 | + * @throws \InvalidArgumentException |
|
109 | + * @throws \Exception |
|
110 | + * |
|
111 | + * @return string |
|
112 | + */ |
|
113 | + public function cache($input) |
|
114 | + { |
|
115 | + $cacheFolder = $this->getCacheDirectory(); |
|
116 | + |
|
117 | + if ($this->isCacheUpToDate($input, $path)) { |
|
118 | + return $path; |
|
119 | + } |
|
120 | + |
|
121 | + if (!is_writable($cacheFolder)) { |
|
122 | + throw new \ErrorException(sprintf('Cache directory must be writable. "%s" is not.', $cacheFolder), 6); |
|
123 | + } |
|
124 | + |
|
125 | + $rendered = $this->pug->compile($input); |
|
126 | + file_put_contents($path, $rendered); |
|
127 | + |
|
128 | + return $this->pug->stream($rendered); |
|
129 | + } |
|
130 | + |
|
131 | + /** |
|
132 | + * Scan a directory recursively, compile them and save them into the cache directory. |
|
133 | + * |
|
134 | + * @param string $directory the directory to search in pug templates |
|
135 | + * |
|
136 | + * @return array count of cached files and error count |
|
137 | + */ |
|
138 | + public function cacheDirectory($directory) |
|
139 | + { |
|
140 | + $success = 0; |
|
141 | + $errors = 0; |
|
142 | + |
|
143 | + $extensions = new ExtensionsHelper($this->pug->getOption('extension')); |
|
144 | + |
|
145 | + foreach (scandir($directory) as $object) { |
|
146 | + if ($object === '.' || $object === '..') { |
|
147 | + continue; |
|
148 | + } |
|
149 | + $input = $directory . DIRECTORY_SEPARATOR . $object; |
|
150 | + if (is_dir($input)) { |
|
151 | + list($subSuccess, $subErrors) = $this->cacheDirectory($input); |
|
152 | + $success += $subSuccess; |
|
153 | + $errors += $subErrors; |
|
154 | + continue; |
|
155 | + } |
|
156 | + if ($extensions->hasValidTemplateExtension($object)) { |
|
157 | + $this->isCacheUpToDate($input, $path); |
|
158 | + try { |
|
159 | + file_put_contents($path, $this->pug->compile($input)); |
|
160 | + $success++; |
|
161 | + } catch (\Exception $e) { |
|
162 | + $errors++; |
|
163 | + } |
|
164 | + } |
|
165 | + } |
|
166 | + |
|
167 | + return array($success, $errors); |
|
168 | + } |
|
169 | 169 | } |
@@ -8,77 +8,77 @@ |
||
8 | 8 | */ |
9 | 9 | abstract class CompilerConfig |
10 | 10 | { |
11 | - /** |
|
12 | - * @const string |
|
13 | - */ |
|
14 | - const VARNAME = '[a-zA-Z\\\\\\x7f-\\xff][a-zA-Z0-9\\\\_\\x7f-\\xff]*'; |
|
11 | + /** |
|
12 | + * @const string |
|
13 | + */ |
|
14 | + const VARNAME = '[a-zA-Z\\\\\\x7f-\\xff][a-zA-Z0-9\\\\_\\x7f-\\xff]*'; |
|
15 | 15 | |
16 | - // This pattern matches against string constants, some php keywords, number constants and a empty string |
|
17 | - // |
|
18 | - // the pattern without php escaping: |
|
19 | - // |
|
20 | - // [ \t]*((['"])(?:\\.|[^'"\\])*\g{-1}|true|false|null|[0-9]+|\b\b)[ \t]* |
|
21 | - // |
|
22 | - // pattern explained: |
|
23 | - // |
|
24 | - // [ \t]* - we ignore spaces at the beginning and at the end: useful for the recursive pattern bellow |
|
25 | - // |
|
26 | - // the first part of the unamed subpattern matches strings: |
|
27 | - // "(?:\\.|[^"\\])*" - quoted string with " |
|
28 | - // '(?:\\.|[^'\\])*' - quoted string with ' |
|
29 | - // |
|
30 | - // the rest of the pattern: |
|
31 | - // true|false|null - language constants |
|
32 | - // 0-9 - number constants |
|
33 | - // \b\b - matches a empty string: useful for a empty array |
|
34 | - /** |
|
35 | - * @const string |
|
36 | - */ |
|
37 | - const CONSTANT_VALUE = '[ \t]*("(?:\\\\.|[^"\\\\])*"|\'(?:\\\\.|[^\'\\\\])*\'|true|false|null|undefined|[0-9]+|\b\b)[ \t]*'; |
|
16 | + // This pattern matches against string constants, some php keywords, number constants and a empty string |
|
17 | + // |
|
18 | + // the pattern without php escaping: |
|
19 | + // |
|
20 | + // [ \t]*((['"])(?:\\.|[^'"\\])*\g{-1}|true|false|null|[0-9]+|\b\b)[ \t]* |
|
21 | + // |
|
22 | + // pattern explained: |
|
23 | + // |
|
24 | + // [ \t]* - we ignore spaces at the beginning and at the end: useful for the recursive pattern bellow |
|
25 | + // |
|
26 | + // the first part of the unamed subpattern matches strings: |
|
27 | + // "(?:\\.|[^"\\])*" - quoted string with " |
|
28 | + // '(?:\\.|[^'\\])*' - quoted string with ' |
|
29 | + // |
|
30 | + // the rest of the pattern: |
|
31 | + // true|false|null - language constants |
|
32 | + // 0-9 - number constants |
|
33 | + // \b\b - matches a empty string: useful for a empty array |
|
34 | + /** |
|
35 | + * @const string |
|
36 | + */ |
|
37 | + const CONSTANT_VALUE = '[ \t]*("(?:\\\\.|[^"\\\\])*"|\'(?:\\\\.|[^\'\\\\])*\'|true|false|null|undefined|[0-9]+|\b\b)[ \t]*'; |
|
38 | 38 | |
39 | - /** |
|
40 | - * @const string |
|
41 | - */ |
|
42 | - const ESCAPED = 'echo \\Jade\\Compiler::getEscapedValue(%s, %s)'; |
|
39 | + /** |
|
40 | + * @const string |
|
41 | + */ |
|
42 | + const ESCAPED = 'echo \\Jade\\Compiler::getEscapedValue(%s, %s)'; |
|
43 | 43 | |
44 | - /** |
|
45 | - * @const string |
|
46 | - */ |
|
47 | - const UNESCAPED = 'echo \\Jade\\Compiler::getUnescapedValue(%s)'; |
|
44 | + /** |
|
45 | + * @const string |
|
46 | + */ |
|
47 | + const UNESCAPED = 'echo \\Jade\\Compiler::getUnescapedValue(%s)'; |
|
48 | 48 | |
49 | - /** |
|
50 | - * @var array |
|
51 | - */ |
|
52 | - protected $doctypes = array( |
|
53 | - '5' => '<!DOCTYPE html>', |
|
54 | - 'html' => '<!DOCTYPE html>', |
|
55 | - 'default' => '<!DOCTYPE html>', |
|
56 | - 'transitional' => '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">', |
|
57 | - 'strict' => '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">', |
|
58 | - 'frameset' => '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">', |
|
59 | - '1.1' => '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">', |
|
60 | - 'basic' => '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML Basic 1.1//EN" "http://www.w3.org/TR/xhtml-basic/xhtml-basic11.dtd">', |
|
61 | - 'mobile' => '<!DOCTYPE html PUBLIC "-//WAPFORUM//DTD XHTML Mobile 1.2//EN" "http://www.openmobilealliance.org/tech/DTD/xhtml-mobile12.dtd">', |
|
62 | - 'xml' => '<<?php echo \'?xml version="1.0" encoding="utf-8" ?\'; ?>>', |
|
63 | - ); |
|
49 | + /** |
|
50 | + * @var array |
|
51 | + */ |
|
52 | + protected $doctypes = array( |
|
53 | + '5' => '<!DOCTYPE html>', |
|
54 | + 'html' => '<!DOCTYPE html>', |
|
55 | + 'default' => '<!DOCTYPE html>', |
|
56 | + 'transitional' => '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">', |
|
57 | + 'strict' => '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">', |
|
58 | + 'frameset' => '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">', |
|
59 | + '1.1' => '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">', |
|
60 | + 'basic' => '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML Basic 1.1//EN" "http://www.w3.org/TR/xhtml-basic/xhtml-basic11.dtd">', |
|
61 | + 'mobile' => '<!DOCTYPE html PUBLIC "-//WAPFORUM//DTD XHTML Mobile 1.2//EN" "http://www.openmobilealliance.org/tech/DTD/xhtml-mobile12.dtd">', |
|
62 | + 'xml' => '<<?php echo \'?xml version="1.0" encoding="utf-8" ?\'; ?>>', |
|
63 | + ); |
|
64 | 64 | |
65 | - /** |
|
66 | - * @var array |
|
67 | - */ |
|
68 | - protected $selfClosing = array('meta', 'img', 'link', 'input', 'source', 'area', 'base', 'col', 'br', 'hr'); |
|
65 | + /** |
|
66 | + * @var array |
|
67 | + */ |
|
68 | + protected $selfClosing = array('meta', 'img', 'link', 'input', 'source', 'area', 'base', 'col', 'br', 'hr'); |
|
69 | 69 | |
70 | - /** |
|
71 | - * @var array |
|
72 | - */ |
|
73 | - protected $phpKeywords = array('true', 'false', 'null', 'switch', 'case', 'default', 'endswitch', 'if', 'elseif', 'else', 'endif', 'while', 'endwhile', 'do', 'for', 'endfor', 'foreach', 'endforeach', 'as', 'unless'); |
|
70 | + /** |
|
71 | + * @var array |
|
72 | + */ |
|
73 | + protected $phpKeywords = array('true', 'false', 'null', 'switch', 'case', 'default', 'endswitch', 'if', 'elseif', 'else', 'endif', 'while', 'endwhile', 'do', 'for', 'endfor', 'foreach', 'endforeach', 'as', 'unless'); |
|
74 | 74 | |
75 | - /** |
|
76 | - * @var array |
|
77 | - */ |
|
78 | - protected $phpOpenBlock = array('switch', 'if', 'else if', 'elseif', 'else', 'while', 'do', 'foreach', 'for', 'unless'); |
|
75 | + /** |
|
76 | + * @var array |
|
77 | + */ |
|
78 | + protected $phpOpenBlock = array('switch', 'if', 'else if', 'elseif', 'else', 'while', 'do', 'foreach', 'for', 'unless'); |
|
79 | 79 | |
80 | - /** |
|
81 | - * @var array |
|
82 | - */ |
|
83 | - protected $phpCloseBlock = array('endswitch', 'endif', 'endwhile', 'endfor', 'endforeach'); |
|
80 | + /** |
|
81 | + * @var array |
|
82 | + */ |
|
83 | + protected $phpCloseBlock = array('endswitch', 'endif', 'endwhile', 'endfor', 'endforeach'); |
|
84 | 84 | } |