@penskemediacorp/twig-to-php-parser 1.10.0-alpha.0 → 1.26.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +51 -4
- package/__tests__/fixtures/larva.config.js +7 -0
- package/__tests__/fixtures/src/patterns/04-components/c-byline/c-byline.twig +1 -1
- package/__tests__/fixtures/src/patterns/04-components/c-heading/c-heading.twig +0 -1
- package/__tests__/fixtures/src/patterns/04-components/c-logo/c-logo.twig +3 -0
- package/__tests__/fixtures/src/patterns/08-modules/array-key-in-loop/array-key-in-loop.twig +11 -0
- package/__tests__/fixtures/src/patterns/08-modules/escaped-output-in-loop/escaped-output-in-loop.twig +5 -0
- package/__tests__/fixtures/src/patterns/08-modules/html-tag-interpolation/html-tag-interpolation.twig +7 -0
- package/__tests__/fixtures/src/patterns/08-modules/trending/trending.twig +1 -0
- package/__tests__/fixtures/src/patterns/99-objects/o-nav/o-nav.twig +4 -0
- package/__tests__/fixtures/template-parts/.gitkeep +1 -0
- package/__tests__/fixtures/template-parts-expected/patterns/components/c-button.php +7 -1
- package/__tests__/fixtures/template-parts-expected/patterns/components/c-byline.php +7 -1
- package/__tests__/fixtures/template-parts-expected/patterns/components/c-heading.php +7 -2
- package/__tests__/fixtures/template-parts-expected/patterns/components/c-logo.php +12 -0
- package/__tests__/fixtures/template-parts-expected/patterns/components/c-nav-link.php +8 -2
- package/__tests__/fixtures/template-parts-expected/patterns/modules/array-key-in-loop.php +20 -0
- package/__tests__/fixtures/template-parts-expected/patterns/modules/breadcrumbs.php +8 -2
- package/__tests__/fixtures/template-parts-expected/patterns/modules/escaped-output-in-loop.php +5 -0
- package/__tests__/fixtures/template-parts-expected/patterns/modules/html-tag-interpolation.php +16 -0
- package/__tests__/fixtures/template-parts-expected/patterns/modules/trending.php +10 -3
- package/__tests__/fixtures/template-parts-expected/patterns/objects/o-crap.php +7 -1
- package/__tests__/fixtures/template-parts-expected/patterns/objects/o-nav.php +12 -2
- package/__tests__/fixtures/template-parts-expected/patterns/objects/o-story-list.php +8 -2
- package/__tests__/parser-methods.test.js +107 -32
- package/__tests__/twig-to-php-parser.test.js +44 -28
- package/index.js +140 -49
- package/lib/getConfig.js +48 -0
- package/lib/twig-to-php-parser.php +218 -61
- package/package.json +3 -3
- package/.DS_Store +0 -0
- package/__tests__/.DS_Store +0 -0
- package/__tests__/fixtures/src/patterns/.DS_Store +0 -0
- package/__tests__/fixtures/template-parts/some-template.php +0 -3
package/index.js
CHANGED
|
@@ -1,81 +1,172 @@
|
|
|
1
1
|
const execPhp = require( 'exec-php' );
|
|
2
2
|
const path = require( 'path' );
|
|
3
3
|
const chalk = require( 'chalk' );
|
|
4
|
-
const getAppConfiguration = require( '
|
|
5
|
-
const
|
|
4
|
+
const getAppConfiguration = require( './lib/getConfig' );
|
|
5
|
+
const config = getAppConfiguration( 'parser' );
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* Twig to PHP Parser
|
|
9
|
-
*
|
|
10
|
-
* @param {
|
|
11
|
-
*
|
|
12
|
-
* @param {object} config Containing
|
|
9
|
+
*
|
|
10
|
+
* @param {Object} config Optional object containing configuration. See the
|
|
11
|
+
* package README for supported configuration.
|
|
13
12
|
*/
|
|
14
13
|
|
|
15
|
-
function twigToPhpParser(
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
14
|
+
function twigToPhpParser( config = {} ) {
|
|
15
|
+
// TODO: We need some kind of wrapper here for config...or better:
|
|
16
|
+
// move this to pmc-plugins/pmc-larva and scrap this awkward JS
|
|
17
|
+
// execPhp wrapper situation, and use Larva\Config for this config.
|
|
18
|
+
let twigDir = path.join( process.cwd(), './src/patterns' );
|
|
19
|
+
let phpDir = path.join( process.cwd(), '../template-parts/patterns' );
|
|
20
|
+
let isUsingPlugin = false;
|
|
21
|
+
|
|
22
|
+
if ( 'undefined' !== typeof config.twigDir ) {
|
|
23
|
+
if ( config.twigDir.startsWith( '.' ) ) {
|
|
24
|
+
twigDir = path.join( process.cwd(), config.twigDir );
|
|
25
|
+
} else {
|
|
26
|
+
twigDir = config.twigDir;
|
|
27
|
+
}
|
|
28
|
+
} else if ( 'undefined' !== typeof config.relativeSrcOverride ) {
|
|
29
|
+
if ( config.relativeSrcOverride.startsWith( '/' ) ) {
|
|
30
|
+
twigDir = config.relativeSrcOverride;
|
|
31
|
+
} else {
|
|
32
|
+
twigDir = path.join( process.cwd(), config.relativeSrcOverride );
|
|
33
|
+
}
|
|
34
|
+
}
|
|
20
35
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
36
|
+
if ( 'undefined' !== typeof config.isUsingPlugin ) {
|
|
37
|
+
isUsingPlugin = config.isUsingPlugin;
|
|
38
|
+
}
|
|
24
39
|
|
|
25
|
-
|
|
40
|
+
if ( 'undefined' !== typeof config.phpDir ) {
|
|
41
|
+
phpDir = config.phpDir;
|
|
42
|
+
}
|
|
26
43
|
|
|
44
|
+
return new Promise( ( resolve, reject ) => {
|
|
45
|
+
execPhp(
|
|
46
|
+
path.resolve( __dirname, './lib/twig-to-php-parser.php' ),
|
|
47
|
+
config.phpBinaryPath,
|
|
48
|
+
function ( error, php, output ) {
|
|
27
49
|
if ( error ) {
|
|
28
50
|
reject( error );
|
|
29
51
|
}
|
|
30
52
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
53
|
+
php.twig_to_php_parser(
|
|
54
|
+
twigDir,
|
|
55
|
+
phpDir,
|
|
56
|
+
isUsingPlugin,
|
|
57
|
+
function ( error, result, output, printed ) {
|
|
58
|
+
if ( error ) {
|
|
59
|
+
reject( error );
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
resolve( result );
|
|
63
|
+
}
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
);
|
|
67
|
+
} );
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function parseIncludePath(
|
|
71
|
+
twigIncludeStr,
|
|
72
|
+
patternName,
|
|
73
|
+
dataName,
|
|
74
|
+
isUsingPlugin = false
|
|
75
|
+
) {
|
|
43
76
|
return new Promise( ( resolve, reject ) => {
|
|
77
|
+
execPhp(
|
|
78
|
+
path.resolve( __dirname, './lib/twig-to-php-parser.php' ),
|
|
79
|
+
config.phpBinaryPath,
|
|
80
|
+
function ( error, php, output ) {
|
|
81
|
+
if ( error ) {
|
|
82
|
+
reject( error );
|
|
83
|
+
}
|
|
44
84
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
85
|
+
php.parse_include_path(
|
|
86
|
+
twigIncludeStr,
|
|
87
|
+
patternName,
|
|
88
|
+
dataName,
|
|
89
|
+
isUsingPlugin,
|
|
90
|
+
function ( error, result, output, printed ) {
|
|
91
|
+
if ( error ) {
|
|
92
|
+
reject( error );
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
resolve( result );
|
|
96
|
+
}
|
|
97
|
+
);
|
|
49
98
|
}
|
|
99
|
+
);
|
|
100
|
+
} );
|
|
101
|
+
}
|
|
50
102
|
|
|
51
|
-
|
|
52
|
-
|
|
103
|
+
function parseSvgPath( twigSvgIncludeStr, svgName, isUsingPlugin = false ) {
|
|
104
|
+
return new Promise( ( resolve, reject ) => {
|
|
105
|
+
execPhp(
|
|
106
|
+
path.resolve( __dirname, './lib/twig-to-php-parser.php' ),
|
|
107
|
+
config.phpBinaryPath,
|
|
108
|
+
function ( error, php, output ) {
|
|
53
109
|
if ( error ) {
|
|
54
110
|
reject( error );
|
|
55
111
|
}
|
|
56
112
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
113
|
+
php.parse_svg_path(
|
|
114
|
+
twigSvgIncludeStr,
|
|
115
|
+
svgName,
|
|
116
|
+
isUsingPlugin,
|
|
117
|
+
function ( error, result, output, printed ) {
|
|
118
|
+
if ( error ) {
|
|
119
|
+
reject( error );
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
resolve( result );
|
|
123
|
+
}
|
|
124
|
+
);
|
|
125
|
+
}
|
|
126
|
+
);
|
|
127
|
+
} );
|
|
128
|
+
}
|
|
60
129
|
|
|
61
|
-
|
|
130
|
+
function parseWpAction( twigMarkup ) {
|
|
131
|
+
return new Promise( ( resolve, reject ) => {
|
|
132
|
+
execPhp(
|
|
133
|
+
path.resolve( __dirname, './lib/twig-to-php-parser.php' ),
|
|
134
|
+
config.phpBinaryPath,
|
|
135
|
+
function ( error, php, output ) {
|
|
136
|
+
if ( error ) {
|
|
137
|
+
reject( error );
|
|
138
|
+
}
|
|
62
139
|
|
|
63
|
-
|
|
140
|
+
php.parse_wp_action(
|
|
141
|
+
twigMarkup,
|
|
142
|
+
function ( error, result, output, printed ) {
|
|
143
|
+
if ( error ) {
|
|
144
|
+
reject( error );
|
|
145
|
+
}
|
|
64
146
|
|
|
65
|
-
|
|
147
|
+
resolve( result );
|
|
148
|
+
}
|
|
149
|
+
);
|
|
150
|
+
}
|
|
151
|
+
);
|
|
152
|
+
} );
|
|
153
|
+
}
|
|
66
154
|
|
|
67
155
|
module.exports = {
|
|
68
|
-
twigToPhpParser
|
|
156
|
+
twigToPhpParser,
|
|
69
157
|
methods: {
|
|
70
|
-
parseIncludePath
|
|
158
|
+
parseIncludePath,
|
|
159
|
+
parseSvgPath,
|
|
160
|
+
parseWpAction,
|
|
71
161
|
},
|
|
72
162
|
run: () => {
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
163
|
+
twigToPhpParser( config )
|
|
164
|
+
.catch( ( e ) => console.log( e ) ) // PHP errors
|
|
165
|
+
.then( ( result ) =>
|
|
166
|
+
console.log(
|
|
167
|
+
chalk.green( 'Completed parsing Twig templates to PHP.' )
|
|
168
|
+
)
|
|
169
|
+
)
|
|
170
|
+
.catch( ( e ) => console.log( e ) );
|
|
171
|
+
},
|
|
81
172
|
};
|
package/lib/getConfig.js
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
const chalk = require( 'chalk' );
|
|
2
|
+
const path = require( 'path' );
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Get Larva Configuration.
|
|
6
|
+
*
|
|
7
|
+
* Find larva.config.js according to the current working directory.
|
|
8
|
+
* For consuming projects, this will be theme/assets/, and for the
|
|
9
|
+
* mono-repo, it will be packages/larva.
|
|
10
|
+
*
|
|
11
|
+
* For test env, the CWD is overridden to the local directory for fixtures.
|
|
12
|
+
* (this is a problem for writing project-level tests, but for a later time.)
|
|
13
|
+
*
|
|
14
|
+
* Note that this is copied from packages/larva/lib in order to
|
|
15
|
+
* remove dependency.
|
|
16
|
+
*
|
|
17
|
+
* @param tool string that indicates a specific configuration property, e.g. patterns.
|
|
18
|
+
*
|
|
19
|
+
* @return value of the specified key.
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
module.exports = function getAppConfiguration( key ) {
|
|
23
|
+
try {
|
|
24
|
+
let appRoot = process.cwd();
|
|
25
|
+
|
|
26
|
+
if ( 'test' === process.env.NODE_ENV ) {
|
|
27
|
+
appRoot = path.join( __dirname, '../__tests__/fixtures' );
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const config = require( `${ appRoot }/larva.config.js` )[ key ];
|
|
31
|
+
|
|
32
|
+
if ( undefined === config ) {
|
|
33
|
+
throw new Error(
|
|
34
|
+
`Configuration for \`${ key }\` is required in larva.config.js. \nPlease refer to the Larva's docs for adding configuration: https://github.com/penske-media-corp/pmc-larva`
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return config;
|
|
39
|
+
} catch ( error ) {
|
|
40
|
+
console.error(
|
|
41
|
+
chalk.red(
|
|
42
|
+
chalk.bold(
|
|
43
|
+
'There is no larva.config.js in this directory.\n'
|
|
44
|
+
) + error
|
|
45
|
+
)
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
};
|
|
@@ -1,80 +1,94 @@
|
|
|
1
1
|
<?php
|
|
2
|
-
|
|
3
2
|
/**
|
|
4
3
|
* Twig to PHP Patterns Parser
|
|
5
|
-
*
|
|
4
|
+
*
|
|
6
5
|
* This will slowly be broken up into smaller, testable functions that
|
|
7
6
|
* can be refactored into node if we choose to go that route.
|
|
8
|
-
*
|
|
9
|
-
* @since
|
|
10
|
-
* @author
|
|
7
|
+
*
|
|
8
|
+
* @since 06/26/2019
|
|
9
|
+
* @author Lara Schenck and Amit Sannad
|
|
10
|
+
* @package pmc-lavra
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
/**
|
|
14
|
+
* Function parser to convert twig to php.
|
|
15
|
+
*
|
|
16
|
+
* @param string $patterns_dir_path patterns path.
|
|
17
|
+
* @param string $template_dir_path template directory path.
|
|
18
|
+
* @param bool $is_using_plugin whether or not plugin is in use.
|
|
19
|
+
* @return void
|
|
20
|
+
*/
|
|
21
|
+
function twig_to_php_parser( $patterns_dir_path, $template_dir_path, $is_using_plugin ) {
|
|
22
|
+
$twig_files = [];
|
|
15
23
|
|
|
16
24
|
$twig_dir_iterator = new \RecursiveDirectoryIterator( $patterns_dir_path );
|
|
17
25
|
$recirsive_dir_iterator = new \RecursiveIteratorIterator( $twig_dir_iterator );
|
|
18
26
|
$all_twig_files = new \RegexIterator( $recirsive_dir_iterator, '/\.twig/' );
|
|
19
27
|
|
|
20
|
-
// Get all twig twig_files to generate template for
|
|
28
|
+
// Get all twig twig_files to generate template for.
|
|
21
29
|
foreach ( $all_twig_files as $info ) {
|
|
22
30
|
$twig_files[] = $info->getPathname();
|
|
23
31
|
}
|
|
24
32
|
|
|
25
33
|
foreach ( $twig_files as $twig_file ) {
|
|
26
34
|
|
|
27
|
-
// All components of path in array split by
|
|
35
|
+
// All components of path in array split by /.
|
|
28
36
|
$twig_path_arr = explode( '/', $twig_file );
|
|
29
|
-
|
|
30
|
-
// Get last three parts of the file that includes directory
|
|
37
|
+
|
|
38
|
+
// Get last three parts of the file that includes directory.
|
|
31
39
|
$path_info = array_slice( $twig_path_arr, count( $twig_path_arr ) - 3, 3 );
|
|
32
40
|
|
|
33
41
|
// Generate directory where we wanna write PHP template. Remove any thing thats not alpha string i.e. remove specials chars including numbers
|
|
34
|
-
// "/patterns/06-components/c-title/c-title.twig" => "/template-parts/patterns/components/c-title.php"
|
|
42
|
+
// "/patterns/06-components/c-title/c-title.twig" => "/template-parts/patterns/components/c-title.php".
|
|
35
43
|
$template_dir = $template_dir_path . '/' . preg_replace( '/[^A-Za-z]/', '', $path_info[0] );
|
|
36
44
|
|
|
37
|
-
// Generate path where we wanna write php template
|
|
45
|
+
// Generate path where we wanna write php template.
|
|
38
46
|
$path = $template_dir . '/' . str_replace( '.twig', '.php', $path_info[2] );
|
|
39
47
|
|
|
48
|
+
debug_log( sprintf( 'Source: %s', $twig_file ) );
|
|
49
|
+
debug_log( sprintf( 'Target: %s', $path ) );
|
|
50
|
+
|
|
40
51
|
if ( file_exists( $path ) ) {
|
|
41
52
|
|
|
42
|
-
// Get file time of template and twig
|
|
53
|
+
// Get file time of template and twig.
|
|
43
54
|
$fmtime_twig = filemtime( $twig_file );
|
|
44
55
|
$fmtime_template = filemtime( $path );
|
|
45
56
|
|
|
46
|
-
// Compare twig file time to php template filetime. If twig file is newer than php template then overwrite the php template
|
|
47
|
-
// This is to make sure we are not unnecessarily overwriting the php template
|
|
57
|
+
// Compare twig file time to php template filetime. If twig file is newer than php template then overwrite the php template.
|
|
58
|
+
// This is to make sure we are not unnecessarily overwriting the php template.
|
|
48
59
|
if ( $fmtime_twig < $fmtime_template ) {
|
|
49
|
-
|
|
60
|
+
debug_log( sprintf( " -> Skipped, twig timestamp: %s, template timestamp: %s\n", $fmtime_twig, $fmtime_template ) );
|
|
50
61
|
// NOTE: Ignoring this just to fixing pipeline, however it's showing 100% coverage in local.
|
|
51
62
|
// Ignoring this line is suggested by teach lead.
|
|
52
63
|
continue; // @codeCoverageIgnore
|
|
53
64
|
}
|
|
54
|
-
|
|
55
65
|
}
|
|
56
66
|
|
|
57
67
|
// Get matches for `{% if VARIABLE %}`
|
|
58
68
|
// If condition regex.
|
|
59
|
-
// https://regex101.com/r/
|
|
60
|
-
$if_condition_regex = '/({% if\s*)(\w
|
|
69
|
+
// https://regex101.com/r/BwA2r0/1.
|
|
70
|
+
$if_condition_regex = '/({% if\s*)(\w*\[\'\w+\'\]|\w+)(\s*%})/';
|
|
61
71
|
|
|
62
|
-
// Get matches for `{% for item in VARIABLE
|
|
63
|
-
// https://regex101.com/r/
|
|
64
|
-
$loop_regex = '/({% for
|
|
72
|
+
// Get matches for `{% for item in VARIABLE`.
|
|
73
|
+
// https://regex101.com/r/ijLuIA/3.
|
|
74
|
+
$loop_regex = '/({% for (\w*\[\'\w+\'\]|\w+) in\s*)(\w*\[\'\w+\'\]|\w+)/';
|
|
65
75
|
|
|
66
|
-
// Get matches for {{ name }}
|
|
67
|
-
// https://regex101.com/r/ACN0rE/
|
|
68
|
-
$mustache_regex = '/({{\s*)(\w*)(\s*}})/';
|
|
76
|
+
// Get matches for {{ name }}, {{ name|filter }}, {{ name['item'] }}
|
|
77
|
+
// https://regex101.com/r/ACN0rE/5.
|
|
78
|
+
$mustache_regex = '/({{\s*)(\w*?\[?\'?\w*\'?\]?\|?\w*)(\s*}})/';
|
|
69
79
|
|
|
70
|
-
// Get matches for {% include "path/c-element.twig" with data %}
|
|
71
|
-
// https://regex101.com/r/ns5kBR/
|
|
72
|
-
$include_regex = '/({%\sinclude ")(.*[c-|o-|l-].*\/)(.*)(.twig)(" with )(\w*)(
|
|
80
|
+
// Get matches for {% include "path/c-element.twig" with data['some_data'] %}
|
|
81
|
+
// https://regex101.com/r/ns5kBR/3.
|
|
82
|
+
$include_regex = '/({%\sinclude ")(.*[c-|o-|l-].*\/)(.*)(.twig)(" with )(\w*?\[?\'?\w*\'?\]?\|?\w*)(\s%})/';
|
|
73
83
|
|
|
74
|
-
|
|
84
|
+
// Get matches for {% include '/path/here/' ~ variable_svg ~ '.svg' %}
|
|
85
|
+
// https://regex101.com/r/pdleQb/3.
|
|
86
|
+
$svg_regex = '/({%\sinclude\s.*)(\s?\~\s?)(\S*)(\s?\~\s?)(.*\s.*)(%})/';
|
|
87
|
+
|
|
88
|
+
$twig_markup = \file_get_contents( $twig_file ); // phpcs:ignore
|
|
75
89
|
|
|
76
90
|
$general_replacers = [
|
|
77
|
-
'{#' => '<?php
|
|
91
|
+
'{#' => '<?php' . "\n/**" . "\n",
|
|
78
92
|
'#}' => '*/' . "\n" . '?>',
|
|
79
93
|
'{% endif %}' => '<?php } ?>',
|
|
80
94
|
'{% else %}' => '<?php } else { ?>',
|
|
@@ -88,12 +102,14 @@ function twig_to_php_parser( $patterns_dir_path, $template_dir_path ) {
|
|
|
88
102
|
preg_match_all( $loop_regex, $twig_markup, $loop_matches );
|
|
89
103
|
preg_match_all( $mustache_regex, $twig_markup, $mustache_matches );
|
|
90
104
|
preg_match_all( $include_regex, $twig_markup, $include_matches );
|
|
105
|
+
preg_match_all( $svg_regex, $twig_markup, $svg_matches );
|
|
91
106
|
|
|
92
107
|
// Prepare empty arrays to gather the replacements as they are processed.
|
|
93
108
|
$if_condition_replacements = [];
|
|
94
109
|
$loop_replacements = [];
|
|
95
110
|
$mustache_replacements = [];
|
|
96
111
|
$include_replacements = [];
|
|
112
|
+
$svg_replacements = [];
|
|
97
113
|
|
|
98
114
|
$count = 0;
|
|
99
115
|
foreach ( $if_condition_matches[0] as $key => $match ) {
|
|
@@ -108,9 +124,10 @@ function twig_to_php_parser( $patterns_dir_path, $template_dir_path ) {
|
|
|
108
124
|
$count = 0;
|
|
109
125
|
foreach ( $loop_matches[0] as $key => $match ) {
|
|
110
126
|
|
|
111
|
-
$
|
|
127
|
+
$key_name = $loop_matches[2][ $count ];
|
|
128
|
+
$variable_name = $loop_matches[3][ $count ];
|
|
112
129
|
|
|
113
|
-
$loop_replacements[ $count ] = '<?php foreach ( $' . $variable_name . ' ?? [] as $
|
|
130
|
+
$loop_replacements[ $count ] = '<?php foreach ( $' . $variable_name . ' ?? [] as $' . $key_name;
|
|
114
131
|
|
|
115
132
|
$count ++;
|
|
116
133
|
}
|
|
@@ -119,11 +136,24 @@ function twig_to_php_parser( $patterns_dir_path, $template_dir_path ) {
|
|
|
119
136
|
foreach ( $mustache_matches[0] as $key => $match ) {
|
|
120
137
|
|
|
121
138
|
$variable_name = $mustache_matches[2][ $count ];
|
|
122
|
-
|
|
123
|
-
$
|
|
124
|
-
$
|
|
125
|
-
$
|
|
126
|
-
$
|
|
139
|
+
|
|
140
|
+
$is_attr = strpos( $match, '_class' ) || strpos( $match, '_name' ) || strpos( $match, '_attr' );
|
|
141
|
+
$is_url = strpos( $match, '_url' );
|
|
142
|
+
$is_text = strpos( $match, '_text' );
|
|
143
|
+
$is_data_attr = strpos( $match, '_attributes' );
|
|
144
|
+
$is_markup = strpos( $match, '_markup' );
|
|
145
|
+
$is_action = strpos( $match, '_wp_action' );
|
|
146
|
+
$has_filter = strpos( $match, '|' );
|
|
147
|
+
|
|
148
|
+
// Remove the Twig filter from the variable name.
|
|
149
|
+
if ( $has_filter ) {
|
|
150
|
+
$string_parts = explode( '|', $variable_name );
|
|
151
|
+
$variable_name = $string_parts[0];
|
|
152
|
+
|
|
153
|
+
if ( 'markup' === $string_parts[1] ) {
|
|
154
|
+
$is_markup = true;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
127
157
|
|
|
128
158
|
if ( ! empty( $is_url ) ) {
|
|
129
159
|
$mustache_replacements[ $count ] = '<?php echo esc_url( $' . $variable_name . ' ?? \'\' ); ?>';
|
|
@@ -141,68 +171,195 @@ function twig_to_php_parser( $patterns_dir_path, $template_dir_path ) {
|
|
|
141
171
|
$mustache_replacements[ $count ] = '<?php echo wp_kses_post( $' . $variable_name . ' ?? \'\' ); ?>';
|
|
142
172
|
}
|
|
143
173
|
|
|
174
|
+
if ( ! empty( $is_action ) ) {
|
|
175
|
+
$mustache_replacements[ $count ] = '<?php do_action( \'' . $variable_name . '\' ); ?>';
|
|
176
|
+
}
|
|
177
|
+
|
|
144
178
|
$count ++;
|
|
145
179
|
}
|
|
146
180
|
|
|
147
181
|
// Reset the count to begin accumulating $include_replacements.
|
|
148
182
|
$count = 0;
|
|
149
|
-
|
|
150
183
|
foreach ( $include_matches[0] as $include ) {
|
|
151
184
|
$include_replacements[ $count ] = parse_include_path(
|
|
152
185
|
$include,
|
|
153
186
|
$include_matches[3][ $count ],
|
|
154
|
-
$include_matches[6][ $count ]
|
|
187
|
+
$include_matches[6][ $count ],
|
|
188
|
+
$is_using_plugin
|
|
189
|
+
);
|
|
190
|
+
$count ++;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// Reset the count to begin accumulating $include_replacements.
|
|
194
|
+
$count = 0;
|
|
195
|
+
foreach ( $svg_matches[0] as $svg ) {
|
|
196
|
+
$svg_replacements[ $count ] = parse_svg_path(
|
|
197
|
+
$svg,
|
|
198
|
+
$svg_matches[3][ $count ],
|
|
199
|
+
$is_using_plugin
|
|
155
200
|
);
|
|
156
201
|
$count ++;
|
|
157
202
|
}
|
|
158
203
|
|
|
159
204
|
// Merge replacements and matches arrays.
|
|
160
|
-
$all_matches
|
|
161
|
-
|
|
205
|
+
$all_matches = (array) array_merge(
|
|
206
|
+
$mustache_matches[0],
|
|
207
|
+
$include_matches[0],
|
|
208
|
+
$loop_matches[0],
|
|
209
|
+
$if_condition_matches[0],
|
|
210
|
+
$svg_matches[0]
|
|
211
|
+
);
|
|
212
|
+
|
|
213
|
+
$all_replacements = (array) array_merge(
|
|
214
|
+
$mustache_replacements,
|
|
215
|
+
$include_replacements,
|
|
216
|
+
$loop_replacements,
|
|
217
|
+
$if_condition_replacements,
|
|
218
|
+
$svg_replacements
|
|
219
|
+
);
|
|
162
220
|
|
|
163
221
|
// First replace matches from the regex's, then apply the general replacements.
|
|
164
222
|
$twig_markup_replace_main = str_replace( $all_matches, $all_replacements, $twig_markup );
|
|
223
|
+
$twig_markup_replace_main = parse_wp_action( $twig_markup_replace_main );
|
|
165
224
|
$twig_markup_replace_complete = str_replace( array_keys( (array) $general_replacers ), array_values( $general_replacers ), $twig_markup_replace_main );
|
|
166
225
|
|
|
167
|
-
$php_markup = "<?php\n
|
|
226
|
+
$php_markup = "<?php\n/**\n * Generated file.\n *\n * Refer to the relevant Twig file for adjusting this markup.\n */\n\n?>\n\n";
|
|
168
227
|
$php_markup .= $twig_markup_replace_complete;
|
|
169
228
|
|
|
170
229
|
if ( ! file_exists( $template_dir ) ) {
|
|
171
230
|
mkdir( $template_dir );
|
|
172
231
|
}
|
|
173
232
|
|
|
174
|
-
file_put_contents( $path, $php_markup );
|
|
233
|
+
file_put_contents( $path, $php_markup ); // phpcs:ignore
|
|
234
|
+
|
|
235
|
+
debug_log( " -> Template generated\n" );
|
|
175
236
|
|
|
176
237
|
}
|
|
177
238
|
}
|
|
178
239
|
|
|
179
240
|
/**
|
|
180
241
|
* Parse Twig Includes
|
|
181
|
-
*
|
|
182
|
-
* @param string
|
|
183
|
-
* @param string
|
|
184
|
-
* @param string
|
|
185
|
-
*
|
|
242
|
+
*
|
|
243
|
+
* @param string $twig_include Full include expression.
|
|
244
|
+
* @param string $pattern_name o-nav.
|
|
245
|
+
* @param string $data_name o_nav / usually name of pattern with underscores.
|
|
246
|
+
* @param boolean $is_using_plugin Whether or not the plugin is in use.
|
|
247
|
+
*
|
|
186
248
|
* @return string PMC::render_template call
|
|
187
249
|
*/
|
|
188
|
-
function parse_include_path( $twig_include, $pattern_name, $data_name ) {
|
|
189
|
-
|
|
190
|
-
$
|
|
250
|
+
function parse_include_path( $twig_include, $pattern_name, $data_name, $is_using_plugin ) {
|
|
251
|
+
|
|
252
|
+
$brand_directory = 'CHILD_THEME_PATH';
|
|
253
|
+
$pattern_directory = '/template-parts/patterns/';
|
|
254
|
+
$start_name = substr( $pattern_name, 0, 2 );
|
|
255
|
+
$pattern_type = '';
|
|
191
256
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
// }
|
|
257
|
+
if ( strpos( $twig_include, '@larva' ) ) {
|
|
258
|
+
$brand_directory = 'PMC_CORE_PATH';
|
|
259
|
+
}
|
|
196
260
|
|
|
197
261
|
if ( 'c-' === $start_name ) {
|
|
198
|
-
$
|
|
262
|
+
$pattern_type = 'components';
|
|
199
263
|
} elseif ( 'o-' === $start_name ) {
|
|
200
|
-
$
|
|
264
|
+
$pattern_type = 'objects';
|
|
201
265
|
} elseif ( '-' !== substr( $pattern_name, 1, 2 ) ) { // If there is no namespace, it is a module.
|
|
202
|
-
$
|
|
266
|
+
$pattern_type = 'modules';
|
|
203
267
|
}
|
|
204
268
|
|
|
205
|
-
|
|
269
|
+
if ( $is_using_plugin ) {
|
|
270
|
+
return "<?php \PMC\Larva\Pattern::get_instance()->render_pattern_template( '" . $pattern_type . '/' . $pattern_name . "', $" . $data_name . ", true ); ?>";
|
|
271
|
+
} else {
|
|
272
|
+
$pattern_partial_path = $pattern_directory . $pattern_type . '/' . $pattern_name;
|
|
273
|
+
|
|
274
|
+
return '<?php \PMC::render_template( ' . $brand_directory . " . '" . $pattern_partial_path . ".php', $" . $data_name . ', true ); ?>';
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
/**
|
|
279
|
+
* Parse SVG Path
|
|
280
|
+
*
|
|
281
|
+
* @param string $twig_include Full include expression.
|
|
282
|
+
* @param string $svg_name Name of SVG file, excluding extension.
|
|
283
|
+
* @param boolean $is_using_plugin Whether or not the plugin is in use.
|
|
284
|
+
*
|
|
285
|
+
* @return string PMC::render_template call
|
|
286
|
+
*/
|
|
287
|
+
function parse_svg_path( $twig_include, $svg_name, $is_using_plugin ) {
|
|
288
|
+
$brand_directory = 'CHILD_THEME_PATH';
|
|
289
|
+
$svg_directory = '/assets/build/svg/';
|
|
290
|
+
$start_name = substr( $svg_name, 0, 2 );
|
|
291
|
+
|
|
292
|
+
if ( true === $is_using_plugin ) {
|
|
293
|
+
$svg_directory = '/build/svg/';
|
|
294
|
+
$key_name = 'brand_directory';
|
|
295
|
+
$brand_directory = "\PMC\Larva\Config::get_instance()->get( '" . $key_name . "' )";
|
|
296
|
+
} else {
|
|
297
|
+
if ( strpos( $twig_include, '@larva' ) ) {
|
|
298
|
+
$brand_directory = 'PMC_CORE_PATH';
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
return "<?php \PMC::render_template( " . $brand_directory . " . '" . $svg_directory . "' . ( $" . $svg_name . " ?? '' ) . '.svg', [], true ); ?>";
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
* Parser responsible for translation custom twig function: {{ wp_action( ... ) }}
|
|
307
|
+
* See larva/lib/server.js twing.addFunction for details
|
|
308
|
+
*
|
|
309
|
+
* @param string $twig_markup twig markup string.
|
|
310
|
+
* @return string
|
|
311
|
+
*/
|
|
312
|
+
function parse_wp_action( string $twig_markup ) : string {
|
|
313
|
+
|
|
314
|
+
$twig_markup = preg_replace_callback(
|
|
315
|
+
'/{{\s*wp_action\s*\(\s*(.*?)\s*\)\s*}}/',
|
|
316
|
+
function ( $matches ) {
|
|
317
|
+
|
|
318
|
+
$args = $matches[1];
|
|
319
|
+
|
|
320
|
+
$args = preg_replace_callback(
|
|
321
|
+
'/\s*([\'"])?(\w+)\1?\s*/',
|
|
322
|
+
function ( $matches ) {
|
|
323
|
+
if ( ! empty( $matches[1] ) ) {
|
|
324
|
+
return sprintf( ' \'%s\'', $matches[2] );
|
|
325
|
+
} else {
|
|
326
|
+
return sprintf( ' $%s', $matches[2] );
|
|
327
|
+
}
|
|
328
|
+
},
|
|
329
|
+
$args
|
|
330
|
+
);
|
|
331
|
+
|
|
332
|
+
return '<?php do_action('. $args . ' ); ?>';
|
|
333
|
+
|
|
334
|
+
},
|
|
335
|
+
$twig_markup
|
|
336
|
+
);
|
|
337
|
+
|
|
338
|
+
return $twig_markup;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
/**
|
|
342
|
+
* Set debug state.
|
|
343
|
+
*
|
|
344
|
+
* @param boolean $state debug state.
|
|
345
|
+
*/
|
|
346
|
+
function set_debug( bool $state ): void {
|
|
347
|
+
global $debug_state;
|
|
348
|
+
$debug_state = $state;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
/**
|
|
352
|
+
* Log debug values.
|
|
353
|
+
*
|
|
354
|
+
* @param string $msg message to debug.
|
|
355
|
+
*/
|
|
356
|
+
function debug_log( string $msg ): void {
|
|
357
|
+
global $debug_state;
|
|
358
|
+
// write out to stderr for now.
|
|
359
|
+
if ( $debug_state ) {
|
|
360
|
+
fwrite( STDERR, sprintf( "%s\n", $msg ) ); // phpcs:ignore
|
|
361
|
+
}
|
|
206
362
|
}
|
|
207
363
|
|
|
208
|
-
//
|
|
364
|
+
// Set default to debug mode.
|
|
365
|
+
set_debug( true );
|