3
3
namespace JsPhpize ;
4
4
5
5
use Exception ;
6
- use JsPhpize \Compiler \Exception as CompilerException ;
7
- use JsPhpize \Lexer \Exception as LexerException ;
8
- use JsPhpize \Parser \Exception as ParserException ;
6
+ use JsPhpize \Traits \Compilation ;
9
7
use Phug \AbstractCompilerModule ;
10
8
use Phug \Compiler ;
9
+ use Phug \Compiler \Event \NodeEvent ;
11
10
use Phug \CompilerEvent ;
12
- use Phug \CompilerInterface ;
11
+ use Phug \Formatter \Element \KeywordElement ;
12
+ use Phug \Parser \Node \CommentNode ;
13
+ use Phug \Parser \Node \KeywordNode ;
14
+ use Phug \Parser \Node \TextNode ;
13
15
use Phug \Renderer ;
14
16
use Phug \Util \ModuleContainerInterface ;
15
17
16
18
class JsPhpizePhug extends AbstractCompilerModule
17
19
{
20
+ use Compilation;
21
+
22
+ protected $ languages = ['js ' , 'php ' ];
23
+
18
24
public function __construct (ModuleContainerInterface $ container )
19
25
{
20
26
parent ::__construct ($ container );
@@ -35,6 +41,7 @@ public function __construct(ModuleContainerInterface $container)
35
41
36
42
//Set default options
37
43
$ this ->setOptionsRecursive ([
44
+ 'language ' => 'js ' ,
38
45
'allowTruncatedParentheses ' => true ,
39
46
'catchDependencies ' => true ,
40
47
'ignoreDollarVariable ' => true ,
@@ -46,111 +53,122 @@ public function __construct(ModuleContainerInterface $container)
46
53
//Apply options from container
47
54
$ this ->setOptionsRecursive ($ compiler ->getOption (['module_options ' , 'jsphpize ' ]));
48
55
56
+ $ compiler ->attach (CompilerEvent::NODE , [$ this , 'handleNodeEvent ' ]);
57
+
49
58
$ compiler ->setOptionsRecursive ([
59
+ 'keywords ' => [
60
+ 'language ' => [$ this , 'handleLanguageKeyword ' ],
61
+ 'node-language ' => [$ this , 'handleNodeLanguageKeyword ' ],
62
+ ],
50
63
'patterns ' => [
51
- 'transform_expression ' => function ($ jsCode ) use ($ compiler ) {
52
- $ jsPhpize = $ this ->getJsPhpizeEngine ($ compiler );
53
- $ compilation = $ this ->compile ($ jsPhpize , $ jsCode , $ compiler ->getPath ());
54
-
55
- if (!($ compilation instanceof Exception)) {
56
- return $ compilation ;
57
- }
58
-
59
- return $ jsCode ;
64
+ 'transform_expression ' => function ($ code ) use ($ compiler ) {
65
+ return $ this ->transformExpression ($ this ->getJsPhpizeEngine ($ compiler ), $ code , $ compiler ->getPath ());
60
66
},
61
67
],
62
68
'checked_variable_exceptions ' => [
63
- 'js-phpize ' => function ($ variable , $ index , $ tokens ) {
64
- return $ index > 2 &&
65
- $ tokens [$ index - 1 ] === '( ' &&
66
- $ tokens [$ index - 2 ] === '] ' &&
67
- is_array ($ tokens [$ index - 3 ]) &&
68
- $ tokens [$ index - 3 ][0 ] === T_CONSTANT_ENCAPSED_STRING &&
69
- preg_match ('/_with_ref \'$/ ' , $ tokens [$ index - 3 ][1 ]);
70
- },
69
+ 'js-phpize ' => [static ::class, 'checkedVariableExceptions ' ],
71
70
],
72
71
]);
73
72
}
74
73
75
- /**
76
- * @return JsPhpize
77
- */
78
- public function getJsPhpizeEngine (CompilerInterface $ compiler )
74
+ public function handleNodeEvent (NodeEvent $ event )
79
75
{
80
- if (!$ compiler ->hasOption ('jsphpize_engine ' )) {
81
- $ compiler ->setOption ('jsphpize_engine ' , new JsPhpize ($ this ->getOptions ()));
76
+ /* @var CommentNode $node */
77
+ if (($ node = $ event ->getNode ()) instanceof CommentNode &&
78
+ !$ node ->isVisible () &&
79
+ $ node ->hasChildAt (0 ) &&
80
+ ($ firstChild = $ node ->getChildAt (0 )) instanceof TextNode &&
81
+ preg_match (
82
+ '/^@((?:node-)?lang(?:uage)?)([\s(].*)$/ ' ,
83
+ trim ($ firstChild ->getValue ()),
84
+ $ match
85
+ )
86
+ ) {
87
+ $ keyword = new KeywordNode (
88
+ $ node ->getToken (),
89
+ $ node ->getSourceLocation (),
90
+ $ node ->getLevel (),
91
+ $ node ->getParent ()
92
+ );
93
+ $ keyword ->setName ($ match [1 ]);
94
+ $ keyword ->setValue ($ match [2 ]);
95
+ $ event ->setNode ($ keyword );
82
96
}
97
+ }
98
+
99
+ protected function getLanguageKeywordValue ($ value , KeywordElement $ keyword , $ name )
100
+ {
101
+ $ value = trim ($ value , "() \"' \t\n\r\0\x0B" );
102
+
103
+ if (!in_array ($ value , $ this ->languages )) {
104
+ $ file = 'unknown ' ;
105
+ $ line = 'unknown ' ;
106
+ $ offset = 'unknown ' ;
107
+ $ node = $ keyword ->getOriginNode ();
108
+ if ($ node && ($ location = $ node ->getSourceLocation ())) {
109
+ $ file = $ location ->getPath ();
110
+ $ line = $ location ->getLine ();
111
+ $ offset = $ location ->getOffset ();
112
+ }
83
113
84
- return $ compiler ->getOption ('jsphpize_engine ' );
114
+ throw new \InvalidArgumentException (sprintf (
115
+ "Invalid argument for %s keyword: %s. Possible values are: %s \nFile: %s \nLine: %s \nOffset:%s " ,
116
+ $ name ,
117
+ $ value ,
118
+ implode (', ' , $ this ->languages ),
119
+ $ file ,
120
+ $ line ,
121
+ $ offset
122
+ ));
123
+ }
124
+
125
+ return $ value ;
85
126
}
86
127
87
- /**
88
- * @param JsPhpize $jsPhpize
89
- * @param int $code
90
- * @param string $fileName
91
- *
92
- * @throws Exception
93
- *
94
- * @return Exception|string
95
- */
96
- public function compile (JsPhpize $ jsPhpize , $ code , $ fileName )
128
+ public function handleNodeLanguageKeyword ($ value , KeywordElement $ keyword , $ name )
97
129
{
98
- try {
99
- $ phpCode = trim ($ jsPhpize ->compile ($ code , $ fileName ?: 'raw string ' ));
100
- $ phpCode = preg_replace ('/\{\s*\}$/ ' , '' , $ phpCode );
101
- $ phpCode = preg_replace (
102
- '/^(?<!\$)\$+(\$[a-zA-Z \\\\\\x7f- \\xff][a-zA-Z0-9 \\\\_ \\x7f- \\xff]*\s*[=;])/ ' ,
103
- '$1 ' ,
104
- $ phpCode
105
- );
130
+ $ value = $ this ->getLanguageKeywordValue ($ value , $ keyword , $ name );
106
131
107
- return rtrim (trim ($ phpCode ), '; ' );
108
- } catch (Exception $ exception ) {
109
- if (
110
- $ exception instanceof LexerException ||
111
- $ exception instanceof ParserException ||
112
- $ exception instanceof CompilerException
113
- ) {
114
- return $ exception ;
115
- }
132
+ if ($ next = $ keyword ->getNextSibling ()) {
133
+ $ next ->prependChild (new KeywordElement ('language ' , $ value , $ keyword ->getOriginNode ()));
134
+ $ next ->appendChild (new KeywordElement ('language ' , $ this ->getOption ('language ' ), $ keyword ->getOriginNode ()));
135
+ }
136
+
137
+ return '' ;
138
+ }
139
+
140
+ public function handleLanguageKeyword ($ value , KeywordElement $ keyword , $ name )
141
+ {
142
+ $ value = $ this ->getLanguageKeywordValue ($ value , $ keyword , $ name );
143
+
144
+ $ this ->setOption ('language ' , $ value );
116
145
117
- throw $ exception ;
146
+ return '' ;
147
+ }
148
+
149
+ protected function transformExpression (JsPhpize $ jsPhpize , $ code , $ fileName )
150
+ {
151
+ if ($ this ->getOption ('language ' ) === 'php ' ) {
152
+ return $ code ;
118
153
}
154
+
155
+ $ compilation = $ this ->compile ($ jsPhpize , $ code , $ fileName );
156
+
157
+ if (!($ compilation instanceof Exception)) {
158
+ return $ compilation ;
159
+ }
160
+
161
+ return $ code ;
119
162
}
120
163
121
- /**
122
- * @return array
123
- */
124
- public function getEventListeners ()
164
+ public static function checkedVariableExceptions ($ variable , $ index , $ tokens )
125
165
{
126
- return [
127
- CompilerEvent::OUTPUT => function (Compiler \Event \OutputEvent $ event ) {
128
- /** @var CompilerInterface $compiler */
129
- $ compiler = $ event ->getTarget ();
130
- $ jsPhpize = $ this ->getJsPhpizeEngine ($ compiler );
131
- $ output = preg_replace (
132
- '/\{\s*\?><\?(?:php)?\s*\}/ ' ,
133
- '{} ' ,
134
- $ event ->getOutput ()
135
- );
136
- $ output = preg_replace (
137
- '/\}\s*\?><\?(?:php)?\s*( ' .
138
- 'else(if)?|for|while|switch|function ' .
139
- ')(?![a-zA-Z0-9_])/ ' ,
140
- '} $1 ' ,
141
- $ output
142
- );
143
-
144
- $ dependencies = $ jsPhpize ->compileDependencies ();
145
- if ($ dependencies !== '' ) {
146
- $ output = $ compiler ->getFormatter ()->handleCode ($ dependencies ) . $ output ;
147
- }
148
-
149
- $ event ->setOutput ($ output );
150
-
151
- $ jsPhpize ->flushDependencies ();
152
- $ compiler ->unsetOption ('jsphpize_engine ' );
153
- },
154
- ];
166
+ return $ index > 2 &&
167
+ $ tokens [$ index - 1 ] === '( ' &&
168
+ $ tokens [$ index - 2 ] === '] ' &&
169
+ !preg_match ('/^__?pug_/ ' , $ variable ) &&
170
+ is_array ($ tokens [$ index - 3 ]) &&
171
+ $ tokens [$ index - 3 ][0 ] === T_CONSTANT_ENCAPSED_STRING &&
172
+ preg_match ('/_with_ref \'$/ ' , $ tokens [$ index - 3 ][1 ]);
155
173
}
156
174
}
0 commit comments