@penskemediacorp/twig-to-php-parser 1.10.0-alpha.0 → 1.14.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 +74 -9
- package/__tests__/twig-to-php-parser.test.js +17 -15
- package/index.js +100 -18
- package/lib/getConfig.js +42 -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/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2019 Penske Media Corporation
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -20,7 +20,7 @@ This package is intended to work with Larva Patterns to both parse patterns into
|
|
|
20
20
|
|
|
21
21
|
~When parsing includes, the parser looks for the `@larva` namespace, and will point includes to `PMC_CORE_PATH` when it finds it. Otherwise, includes will point to CHILD_THEME_PATH.~ This is not in effect yet. Everything is contained to the child theme.
|
|
22
22
|
|
|
23
|
-
The parser supports a *very limited amount of Twig* and relies on keywords in data names in order to parse escaping correctly. Please refer to the Confluence documentation for Twig authoring
|
|
23
|
+
The parser supports a *very limited amount of Twig* and relies on keywords in data names in order to parse escaping correctly. Please refer to the Confluence documentation for Twig authoring guidelines: https://confluence.pmcdev.io/x/JoGJAg
|
|
24
24
|
|
|
25
25
|
## Usage
|
|
26
26
|
|
|
@@ -30,13 +30,60 @@ module.exports = {
|
|
|
30
30
|
// Other config
|
|
31
31
|
|
|
32
32
|
parser: {
|
|
33
|
-
relativeSrcOverride: false, // The default will look in src/patterns for the source path, but if you want to parse from a different directory, you can add that path here.
|
|
34
|
-
isCore: false // Or true, if it is the core theme and should parse everything to PMC_CORE_PATH
|
|
35
33
|
}
|
|
36
34
|
}
|
|
37
35
|
```
|
|
38
36
|
|
|
37
|
+
The parser object supports the following configuration:
|
|
38
|
+
```language-js
|
|
39
|
+
parser: {
|
|
40
|
+
twigDir: path.resolve( './new-path/to-twig/' ), // Default /theme/assets/src/patterns.
|
|
41
|
+
phpDir: path.resolve( './new-path/to-php/' ), // Default /theme/template-parts/patterns.
|
|
42
|
+
isUsingPlugin: true, // Default false.
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
39
46
|
Then, run the script from the assets directory by executing the package binary like so:
|
|
40
47
|
```
|
|
41
|
-
|
|
48
|
+
./node_modules/.bin/twig-to-php-parser
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Supported wp action in twig markup:
|
|
52
|
+
```language-twig
|
|
53
|
+
{{ wp_action( 'action_name', arg1, arg2, ... ) }}
|
|
54
|
+
```
|
|
55
|
+
would translate to
|
|
56
|
+
```language-php
|
|
57
|
+
<?php do_action( 'action_name', $arg1, $arg2, ... ); ?>
|
|
42
58
|
```
|
|
59
|
+
|
|
60
|
+
## How To
|
|
61
|
+
TODO: Standardize and improve code structure for future improvement
|
|
62
|
+
|
|
63
|
+
### Add a new function
|
|
64
|
+
|
|
65
|
+
- New function add must follow twig function syntax: function_name( p1, p2, ... )
|
|
66
|
+
- The new `function_name` must be added to larva/lib/server.js to support twig linting
|
|
67
|
+
|
|
68
|
+
// Add custom function support for doing wp action: {{ function_name( ... ) }}
|
|
69
|
+
twing.addFunction(new TwingFunction('function_name',() => {
|
|
70
|
+
return Promise.resolve(''); // must return a promise result
|
|
71
|
+
}));
|
|
72
|
+
|
|
73
|
+
- Add a new code block function/class to translate twig markup into php code block to twig-to-php-parse.php
|
|
74
|
+
- Code block function should take a twig markup string as input
|
|
75
|
+
- Return the translated php code block
|
|
76
|
+
|
|
77
|
+
function parse_my_new_function( $twig_markup ) {
|
|
78
|
+
// Code to parse and translate $twig_markup
|
|
79
|
+
return $twig_patterns;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
- Modify function twig_to_php_parser and call to the new parser function to process $twig_markup_replace_main variable
|
|
83
|
+
|
|
84
|
+
$twig_markup_replace_main = parse_my_new_function( $twig_markup_replace_main )
|
|
85
|
+
|
|
86
|
+
- Add unit test
|
|
87
|
+
- Add js function to index.js to load the php code
|
|
88
|
+
- Add unit test to test the new parser function
|
|
89
|
+
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
{% for item in list_items %}
|
|
2
|
+
<li class="list__item larva // {{ list_item_classes }}">
|
|
3
|
+
{% if item['list_items'] %}
|
|
4
|
+
{% include "@larva/modules/list/list.twig" with item %}
|
|
5
|
+
{% else %}
|
|
6
|
+
<div class="{{ item['list_item_classes'] }}">
|
|
7
|
+
{{ item['list_item_markup'] }}
|
|
8
|
+
</div>
|
|
9
|
+
{% endif %}
|
|
10
|
+
</li>
|
|
11
|
+
{% endfor %}
|
|
@@ -8,6 +8,10 @@
|
|
|
8
8
|
{% for item in o_nav_list_items %}
|
|
9
9
|
<li class="o-nav__list-item {{ o_nav_list_item_classes }}" data-dropdown-list-item="{{ o_nav_list_item_data_attributes }}">
|
|
10
10
|
{% include "../../04-components/c-nav-link/c-nav-link.twig" with item %}
|
|
11
|
+
|
|
12
|
+
{% if item['newsletter_dropdown'] %}
|
|
13
|
+
{% include "@project/modules/newsletter-dropdown/newsletter-dropdown.twig" with item['newsletter_dropdown'] %}
|
|
14
|
+
{% endif %}
|
|
11
15
|
</li>
|
|
12
16
|
{% endfor %}
|
|
13
17
|
</ul>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Directory is required for tests.
|
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
<?php
|
|
2
|
-
|
|
2
|
+
/**
|
|
3
|
+
* Generated file.
|
|
4
|
+
*
|
|
5
|
+
* Refer to the relevant Twig file for adjusting this markup.
|
|
6
|
+
*/
|
|
7
|
+
|
|
3
8
|
?>
|
|
9
|
+
|
|
4
10
|
<a class="c-button <?php echo esc_attr( $modifier_class ?? '' ); ?>" href="<?php echo esc_url( $c_button_url ?? '' ); ?>">
|
|
5
11
|
<?php echo esc_html( $c_button_text ?? '' ); ?>
|
|
6
12
|
</a>
|
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
<?php
|
|
2
|
-
|
|
2
|
+
/**
|
|
3
|
+
* Generated file.
|
|
4
|
+
*
|
|
5
|
+
* Refer to the relevant Twig file for adjusting this markup.
|
|
6
|
+
*/
|
|
7
|
+
|
|
3
8
|
?>
|
|
9
|
+
|
|
4
10
|
<p class="c-byline <?php echo esc_attr( $modifier_class ?? '' ); ?> <?php echo esc_attr( $c_byline_classes ?? '' ); ?>">
|
|
5
11
|
<?php echo esc_html( $c_byline_by_text ?? '' ); ?>
|
|
6
12
|
|
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
<?php
|
|
2
|
-
|
|
2
|
+
/**
|
|
3
|
+
* Generated file.
|
|
4
|
+
*
|
|
5
|
+
* Refer to the relevant Twig file for adjusting this markup.
|
|
6
|
+
*/
|
|
7
|
+
|
|
3
8
|
?>
|
|
9
|
+
|
|
4
10
|
<h2 class="c-heading <?php echo esc_attr( $modifier_class ?? '' ); ?>"><?php echo esc_html( $c_heading_text ?? '' ); ?></h2>
|
|
5
|
-
<?php \PMC::render_template( CHILD_THEME_PATH . '/template-parts/patterns/modules/trending.php', $item, true ); ?>
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
<?php
|
|
2
|
+
/**
|
|
3
|
+
* Generated file.
|
|
4
|
+
*
|
|
5
|
+
* Refer to the relevant Twig file for adjusting this markup.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
?>
|
|
9
|
+
|
|
10
|
+
<div>
|
|
11
|
+
<?php \PMC::render_template( \PMC\Larva\Config::get_instance()->get( 'brand_directory' ) . '/build/svg/' . ( $c_logo_svg ?? '' ) . '.svg', [], true ); ?>
|
|
12
|
+
</div>
|
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
<?php
|
|
2
|
-
|
|
2
|
+
/**
|
|
3
|
+
* Generated file.
|
|
4
|
+
*
|
|
5
|
+
* Refer to the relevant Twig file for adjusting this markup.
|
|
6
|
+
*/
|
|
7
|
+
|
|
3
8
|
?>
|
|
9
|
+
|
|
4
10
|
<a class="c-nav-link <?php echo esc_attr( $c_nav_link_classes ?? '' ); ?>" href="<?php echo esc_url( $c_nav_link_url ?? '' ); ?>">
|
|
5
11
|
<?php echo esc_html( $c_nav_link_text ?? '' ); ?>
|
|
6
|
-
</a>
|
|
12
|
+
</a>
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
<?php
|
|
2
|
+
/**
|
|
3
|
+
* Generated file.
|
|
4
|
+
*
|
|
5
|
+
* Refer to the relevant Twig file for adjusting this markup.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
?>
|
|
9
|
+
|
|
10
|
+
<?php foreach ( $list_items ?? [] as $item ) { ?>
|
|
11
|
+
<li class="list__item larva // <?php echo esc_attr( $list_item_classes ?? '' ); ?>">
|
|
12
|
+
<?php if ( ! empty( $item['list_items'] ) ) { ?>
|
|
13
|
+
<?php \PMC\Larva\Pattern::get_instance()->render_pattern_template( 'modules/list', $item, true ); ?>
|
|
14
|
+
<?php } else { ?>
|
|
15
|
+
<div class="<?php echo esc_attr( $item['list_item_classes'] ?? '' ); ?>">
|
|
16
|
+
<?php echo wp_kses_post( $item['list_item_markup'] ?? '' ); ?>
|
|
17
|
+
</div>
|
|
18
|
+
<?php } ?>
|
|
19
|
+
</li>
|
|
20
|
+
<?php } ?>
|
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
<?php
|
|
2
|
-
|
|
2
|
+
/**
|
|
3
|
+
* Generated file.
|
|
4
|
+
*
|
|
5
|
+
* Refer to the relevant Twig file for adjusting this markup.
|
|
6
|
+
*/
|
|
7
|
+
|
|
3
8
|
?>
|
|
4
|
-
|
|
9
|
+
|
|
10
|
+
<?php \PMC\Larva\Pattern::get_instance()->render_pattern_template( 'objects/o-nav', $o_nav, true ); ?>
|
package/__tests__/fixtures/template-parts-expected/patterns/modules/html-tag-interpolation.php
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
<?php
|
|
2
|
+
/**
|
|
3
|
+
* Generated file.
|
|
4
|
+
*
|
|
5
|
+
* Refer to the relevant Twig file for adjusting this markup.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
?>
|
|
9
|
+
|
|
10
|
+
<<?php echo esc_attr( $list_type_name ?? '' ); ?>l class="list larva // <?php echo esc_attr( $list_classes ?? '' ); ?>">
|
|
11
|
+
<?php foreach ( $list_items ?? [] as $item ) { ?>
|
|
12
|
+
<li class="list__item larva // <?php echo esc_attr( $list_item_classes ?? '' ); ?>">
|
|
13
|
+
<?php \PMC\Larva\Pattern::get_instance()->render_pattern_template( 'modules/list', $item, true ); ?>
|
|
14
|
+
</li>
|
|
15
|
+
<?php } ?>
|
|
16
|
+
</<?php echo esc_attr( $list_type_name ?? '' ); ?>l>
|
|
@@ -1,11 +1,18 @@
|
|
|
1
1
|
<?php
|
|
2
|
-
|
|
2
|
+
/**
|
|
3
|
+
* Generated file.
|
|
4
|
+
*
|
|
5
|
+
* Refer to the relevant Twig file for adjusting this markup.
|
|
6
|
+
*/
|
|
7
|
+
|
|
3
8
|
?>
|
|
9
|
+
|
|
4
10
|
<section class="u-max-width-300">
|
|
5
11
|
<header>
|
|
6
|
-
<?php \PMC::
|
|
12
|
+
<?php \PMC\Larva\Pattern::get_instance()->render_pattern_template( 'components/c-heading', $c_heading, true ); ?>
|
|
7
13
|
</header>
|
|
8
14
|
<div class="pmc-u-margin-b-0 u-border-bottom-2">
|
|
9
|
-
<?php \PMC::
|
|
15
|
+
<?php \PMC\Larva\Pattern::get_instance()->render_pattern_template( 'objects/o-story-list', $o_story_list, true ); ?>
|
|
10
16
|
</div>
|
|
17
|
+
<?php do_action( 'trending_ads_wp_action' ); ?>
|
|
11
18
|
</section>
|
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
<?php
|
|
2
|
-
|
|
2
|
+
/**
|
|
3
|
+
* Generated file.
|
|
4
|
+
*
|
|
5
|
+
* Refer to the relevant Twig file for adjusting this markup.
|
|
6
|
+
*/
|
|
7
|
+
|
|
3
8
|
?>
|
|
9
|
+
|
|
4
10
|
<p class="o-crap <?php echo esc_attr( $modifier_class ?? '' ); ?> <?php echo esc_attr( $o_crap_classes ?? '' ); ?>"><?php echo esc_html( $o_crap_text ?? '' ); ?></p>
|
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
<?php
|
|
2
|
-
|
|
2
|
+
/**
|
|
3
|
+
* Generated file.
|
|
4
|
+
*
|
|
5
|
+
* Refer to the relevant Twig file for adjusting this markup.
|
|
6
|
+
*/
|
|
7
|
+
|
|
3
8
|
?>
|
|
9
|
+
|
|
4
10
|
<nav class="o-nav <?php echo esc_attr( $modifier_class ?? '' ); ?> <?php echo esc_attr( $o_nav_classes ?? '' ); ?>" data-dropdown="<?php echo esc_attr( $o_nav_data_attributes ?? '' ); ?>">
|
|
5
11
|
|
|
6
12
|
<?php if ( ! empty( $o_nav_title_text ) ) { ?>
|
|
@@ -10,7 +16,11 @@
|
|
|
10
16
|
<ul class="o-nav__list <?php echo esc_attr( $o_nav_list_classes ?? '' ); ?>" data-dropdown-list="<?php echo esc_attr( $o_nav_list_data_attributes ?? '' ); ?>">
|
|
11
17
|
<?php foreach ( $o_nav_list_items ?? [] as $item ) { ?>
|
|
12
18
|
<li class="o-nav__list-item <?php echo esc_attr( $o_nav_list_item_classes ?? '' ); ?>" data-dropdown-list-item="<?php echo esc_attr( $o_nav_list_item_data_attributes ?? '' ); ?>">
|
|
13
|
-
<?php \PMC::
|
|
19
|
+
<?php \PMC\Larva\Pattern::get_instance()->render_pattern_template( 'components/c-nav-link', $item, true ); ?>
|
|
20
|
+
|
|
21
|
+
<?php if ( ! empty( $item['newsletter_dropdown'] ) ) { ?>
|
|
22
|
+
<?php \PMC\Larva\Pattern::get_instance()->render_pattern_template( 'modules/newsletter-dropdown', $item['newsletter_dropdown'], true ); ?>
|
|
23
|
+
<?php } ?>
|
|
14
24
|
</li>
|
|
15
25
|
<?php } ?>
|
|
16
26
|
</ul>
|
|
@@ -1,10 +1,16 @@
|
|
|
1
1
|
<?php
|
|
2
|
-
|
|
2
|
+
/**
|
|
3
|
+
* Generated file.
|
|
4
|
+
*
|
|
5
|
+
* Refer to the relevant Twig file for adjusting this markup.
|
|
6
|
+
*/
|
|
7
|
+
|
|
3
8
|
?>
|
|
9
|
+
|
|
4
10
|
<ul class="o-story-list <?php echo esc_attr( $modifier_class ?? '' ); ?> <?php echo esc_attr( $o_story_list_classes ?? '' ); ?>">
|
|
5
11
|
<?php foreach ( $o_story_list_teases ?? [] as $item ) { ?>
|
|
6
12
|
<li class="o-story-list__item <?php echo esc_attr( $o_story_list_item_classes ?? '' ); ?>">
|
|
7
|
-
<?php \PMC::
|
|
13
|
+
<?php \PMC\Larva\Pattern::get_instance()->render_pattern_template( 'objects/o-tease', $item, true ); ?>
|
|
8
14
|
</li>
|
|
9
15
|
<?php } ?>
|
|
10
16
|
</ul>
|
|
@@ -1,16 +1,11 @@
|
|
|
1
1
|
const assert = require( 'assert' );
|
|
2
|
-
( path = require( 'path' ) );
|
|
3
|
-
( fs = require( 'fs' ) );
|
|
4
2
|
|
|
5
3
|
const parserMethods = require( '../index.js' ).methods;
|
|
6
|
-
const exec = require( 'child_process' ).exec;
|
|
7
|
-
|
|
8
|
-
const fixture = path.join( __dirname, 'fixtures' );
|
|
9
4
|
|
|
10
5
|
const expectations = {
|
|
11
6
|
childInclude: '<?php \\PMC::render_template( CHILD_THEME_PATH . \'/template-parts/patterns/objects/o-nav.php\', $o_nav, true ); ?>',
|
|
12
|
-
larvaInclude: '<?php \\PMC::render_template(
|
|
13
|
-
|
|
7
|
+
larvaInclude: '<?php \\PMC::render_template( PMC_CORE_PATH . \'/template-parts/patterns/objects/o-nav.php\', $o_nav, true ); ?>',
|
|
8
|
+
pluginEnabled: '<?php \\PMC\\Larva\\Pattern::get_instance()->render_pattern_template( \'objects/o-nav\', $o_nav, true ); ?>'
|
|
14
9
|
};
|
|
15
10
|
|
|
16
11
|
describe( 'parse include statements', function() {
|
|
@@ -28,16 +23,86 @@ describe( 'parse include statements', function() {
|
|
|
28
23
|
});
|
|
29
24
|
|
|
30
25
|
it( 'if larva namespace, parsed path references the parent theme', ( done ) => {
|
|
26
|
+
|
|
31
27
|
parserMethods.parseIncludePath(
|
|
32
28
|
'{% include "@larva/objects/o-nav.twig" with o_nav %}',
|
|
33
29
|
'o-nav',
|
|
34
|
-
'o_nav'
|
|
30
|
+
'o_nav'
|
|
31
|
+
)
|
|
35
32
|
.catch( e => console.log( e ) )
|
|
36
33
|
.then( ( result ) => {
|
|
37
34
|
assert.equal( result, expectations.larvaInclude );
|
|
38
35
|
done();
|
|
36
|
+
} );
|
|
37
|
+
} );
|
|
38
|
+
|
|
39
|
+
it( 'if plugin is enabled, use the render_pattern_template method from Larva', ( done ) => {
|
|
40
|
+
|
|
41
|
+
parserMethods.parseIncludePath(
|
|
42
|
+
'{% include "@project/objects/o-nav.twig" with o_nav %}',
|
|
43
|
+
'o-nav',
|
|
44
|
+
'o_nav',
|
|
45
|
+
true )
|
|
46
|
+
.catch( e => console.log( e ) )
|
|
47
|
+
.then( ( result ) => {
|
|
48
|
+
assert.equal( result, expectations.pluginEnabled );
|
|
49
|
+
done();
|
|
50
|
+
} );
|
|
51
|
+
} );
|
|
52
|
+
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
describe( 'parse SVG includes', function () {
|
|
56
|
+
it( 'parses includes to brand_directory when using plugin', ( done ) => {
|
|
57
|
+
|
|
58
|
+
const expectedPluginEnabled = '<?php \\PMC::render_template( \\PMC\\Larva\\Config::get_instance()->get( \'brand_directory\' ) . \'/build/svg/\' . ( $c_logo_svg ?? \'\' ) . \'.svg\', [], true ); ?>';
|
|
59
|
+
|
|
60
|
+
parserMethods.parseSvgPath(
|
|
61
|
+
"{% include '../../build/svg/' ~ c_logo_svg ~ '.svg' %}",
|
|
62
|
+
'c_logo_svg',
|
|
63
|
+
true
|
|
64
|
+
)
|
|
65
|
+
.catch( e => console.log( e ) )
|
|
66
|
+
.then( ( result ) => {
|
|
67
|
+
assert.equal( result, expectedPluginEnabled );
|
|
68
|
+
done();
|
|
69
|
+
});
|
|
70
|
+
} );
|
|
71
|
+
it( 'parses includes to CHILD_THEME_PATH when not using plugin', ( done ) => {
|
|
72
|
+
|
|
73
|
+
const expected = '<?php \\PMC::render_template( CHILD_THEME_PATH . \'/assets/build/svg/\' . ( $c_logo_svg ?? \'\' ) . \'.svg\', [], true ); ?>';
|
|
74
|
+
|
|
75
|
+
parserMethods.parseSvgPath(
|
|
76
|
+
"{% include '../../build/svg/' ~ c_logo_svg ~ '.svg' %}",
|
|
77
|
+
'c_logo_svg'
|
|
78
|
+
)
|
|
79
|
+
.catch( e => console.log( e ) )
|
|
80
|
+
.then( ( result ) => {
|
|
81
|
+
assert.equal( result, expected );
|
|
82
|
+
done();
|
|
39
83
|
});
|
|
40
84
|
});
|
|
85
|
+
} );
|
|
41
86
|
|
|
42
|
-
|
|
87
|
+
describe( 'parse custom functions', function () {
|
|
88
|
+
it( 'parses wp_action function', ( done ) => {
|
|
89
|
+
|
|
90
|
+
parserMethods.parseWpAction("{{wp_action('test','param',variable)}}")
|
|
91
|
+
.catch( e => console.log( e ) )
|
|
92
|
+
.then( ( result ) => {
|
|
93
|
+
assert.equal( result, "<?php do_action( 'test', 'param', $variable ); ?>" );
|
|
94
|
+
done();
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
// Test spacing
|
|
98
|
+
parserMethods.parseWpAction("{{ wp_action( 'test', 'param', variable ) }}")
|
|
99
|
+
.catch( e => console.log( e ) )
|
|
100
|
+
.then( ( result ) => {
|
|
101
|
+
assert.equal( result, "<?php do_action( 'test', 'param', $variable ); ?>" );
|
|
102
|
+
done();
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
} );
|
|
106
|
+
|
|
107
|
+
} );
|
|
43
108
|
|
|
@@ -5,55 +5,57 @@ const twigToPhpParser = require( '../index' ).twigToPhpParser;
|
|
|
5
5
|
const exec = require( 'child_process' ).exec;
|
|
6
6
|
|
|
7
7
|
const fixture = path.join( __dirname, 'fixtures' );
|
|
8
|
+
const expectedDir = `${fixture}/template-parts-expected/patterns/`;
|
|
8
9
|
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
phpDir: `${fixture}/template-parts/patterns/`,
|
|
12
|
-
expectedDir: `${fixture}/template-parts-expected/patterns/`,
|
|
13
|
-
};
|
|
10
|
+
const getAppConfiguration = require( '../lib/getConfig' );
|
|
11
|
+
const appConfiguration = getAppConfiguration( 'parser' );
|
|
14
12
|
|
|
15
13
|
const patternShortPaths = [
|
|
16
14
|
'components/c-byline.php',
|
|
17
15
|
'components/c-heading.php',
|
|
18
16
|
'components/c-button.php',
|
|
17
|
+
'components/c-logo.php',
|
|
19
18
|
'objects/o-nav.php',
|
|
20
19
|
'objects/o-story-list.php',
|
|
21
20
|
'modules/trending.php',
|
|
21
|
+
'modules/array-key-in-loop.php',
|
|
22
|
+
'modules/html-tag-interpolation.php',
|
|
22
23
|
];
|
|
23
24
|
|
|
24
25
|
describe( 'twig to php parser', function() {
|
|
25
26
|
|
|
26
27
|
beforeEach( ( done ) => {
|
|
27
|
-
|
|
28
|
+
|
|
29
|
+
exec( 'mkdir ' + appConfiguration.phpDir, ( err ) => {
|
|
28
30
|
if ( err ) {
|
|
29
31
|
console.error( err );
|
|
30
32
|
}
|
|
31
33
|
});
|
|
32
34
|
|
|
33
|
-
return twigToPhpParser(
|
|
35
|
+
return twigToPhpParser( appConfiguration )
|
|
34
36
|
.catch( ( e ) => console.log( e ) )
|
|
35
37
|
.then( ( result ) => done() ); // Catch PHP errors.
|
|
36
38
|
});
|
|
37
39
|
|
|
38
40
|
it( 'creates new files and directories for objects, components, and modules', ( done ) => {
|
|
39
|
-
assert.equal( fs.existsSync(
|
|
40
|
-
assert.equal( fs.existsSync(
|
|
41
|
-
assert.equal( fs.existsSync(
|
|
41
|
+
assert.equal( fs.existsSync( appConfiguration.phpDir + 'objects/o-nav.php' ), true );
|
|
42
|
+
assert.equal( fs.existsSync( appConfiguration.phpDir + 'components/c-nav-link.php' ), true );
|
|
43
|
+
assert.equal( fs.existsSync( appConfiguration.phpDir + 'modules/breadcrumbs.php' ), true );
|
|
42
44
|
done();
|
|
43
45
|
});
|
|
44
46
|
|
|
45
47
|
it( 'parses patterns as expected', ( done ) => {
|
|
46
48
|
patternShortPaths.forEach( ( shortpath ) => {
|
|
47
|
-
let expectedContents = fs.readFileSync(
|
|
48
|
-
let actualContents = fs.readFileSync(
|
|
49
|
-
|
|
50
|
-
assert.equal(
|
|
49
|
+
let expectedContents = fs.readFileSync( expectedDir + shortpath ).toString();
|
|
50
|
+
let actualContents = fs.readFileSync( appConfiguration.phpDir + shortpath ).toString();
|
|
51
|
+
|
|
52
|
+
assert.equal( actualContents, expectedContents );
|
|
51
53
|
});
|
|
52
54
|
done();
|
|
53
55
|
});
|
|
54
56
|
|
|
55
57
|
afterEach( () => {
|
|
56
|
-
exec( 'rm -r ' +
|
|
58
|
+
exec( 'rm -r ' + appConfiguration.phpDir, ( err ) => {
|
|
57
59
|
if ( err ) {
|
|
58
60
|
console.error( err );
|
|
59
61
|
}
|
package/index.js
CHANGED
|
@@ -1,18 +1,48 @@
|
|
|
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(
|
|
14
|
+
function twigToPhpParser( config = {} ) {
|
|
15
|
+
|
|
16
|
+
// TODO: We need some kind of wrapper here for config...or better:
|
|
17
|
+
// move this to pmc-plugins/pmc-larva and scrap this awkward JS
|
|
18
|
+
// execPhp wrapper situation, and use Larva\Config for this config.
|
|
19
|
+
let twigDir = path.join( process.cwd(), './src/patterns' );
|
|
20
|
+
let phpDir = path.join( process.cwd(), '../template-parts/patterns' );
|
|
21
|
+
let isUsingPlugin = false;
|
|
22
|
+
|
|
23
|
+
if ( 'undefined' !== typeof config.twigDir ) {
|
|
24
|
+
if ( config.twigDir.startsWith( '.' ) ) {
|
|
25
|
+
twigDir = path.join( process.cwd(), config.twigDir );
|
|
26
|
+
} else {
|
|
27
|
+
twigDir = config.twigDir;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
else if ( 'undefined' !== typeof config.relativeSrcOverride ) {
|
|
31
|
+
if ( config.relativeSrcOverride.startsWith( '/' ) ) {
|
|
32
|
+
twigDir = config.relativeSrcOverride;
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
twigDir = path.join( process.cwd(), config.relativeSrcOverride );
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if ( 'undefined' !== typeof config.isUsingPlugin ) {
|
|
40
|
+
isUsingPlugin = config.isUsingPlugin;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if ( 'undefined' !== typeof config.phpDir ) {
|
|
44
|
+
phpDir = config.phpDir;
|
|
45
|
+
}
|
|
16
46
|
|
|
17
47
|
return new Promise( ( resolve, reject ) => {
|
|
18
48
|
|
|
@@ -22,7 +52,7 @@ function twigToPhpParser( twigDirPath, phpDirPath, config = {} ) {
|
|
|
22
52
|
reject( error );
|
|
23
53
|
}
|
|
24
54
|
|
|
25
|
-
php.twig_to_php_parser(
|
|
55
|
+
php.twig_to_php_parser( twigDir, phpDir, isUsingPlugin, function( error, result, output, printed ) {
|
|
26
56
|
|
|
27
57
|
if ( error ) {
|
|
28
58
|
reject( error );
|
|
@@ -38,7 +68,7 @@ function twigToPhpParser( twigDirPath, phpDirPath, config = {} ) {
|
|
|
38
68
|
|
|
39
69
|
};
|
|
40
70
|
|
|
41
|
-
function parseIncludePath( twigIncludeStr, patternName, dataName,
|
|
71
|
+
function parseIncludePath( twigIncludeStr, patternName, dataName, isUsingPlugin = false ) {
|
|
42
72
|
|
|
43
73
|
return new Promise( ( resolve, reject ) => {
|
|
44
74
|
|
|
@@ -48,7 +78,7 @@ function parseIncludePath( twigIncludeStr, patternName, dataName, config = {} )
|
|
|
48
78
|
reject( error );
|
|
49
79
|
}
|
|
50
80
|
|
|
51
|
-
php.parse_include_path( twigIncludeStr, patternName, dataName, function( error, result, output, printed ) {
|
|
81
|
+
php.parse_include_path( twigIncludeStr, patternName, dataName, isUsingPlugin, function( error, result, output, printed ) {
|
|
52
82
|
|
|
53
83
|
if ( error ) {
|
|
54
84
|
reject( error );
|
|
@@ -64,18 +94,70 @@ function parseIncludePath( twigIncludeStr, patternName, dataName, config = {} )
|
|
|
64
94
|
|
|
65
95
|
};
|
|
66
96
|
|
|
97
|
+
function parseSvgPath( twigSvgIncludeStr, svgName, isUsingPlugin = false ) {
|
|
98
|
+
|
|
99
|
+
return new Promise( ( resolve, reject ) => {
|
|
100
|
+
|
|
101
|
+
execPhp( path.resolve( __dirname, './lib/twig-to-php-parser.php' ), config.phpBinaryPath, function( error, php, output ) {
|
|
102
|
+
|
|
103
|
+
if ( error ) {
|
|
104
|
+
reject( error );
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
php.parse_svg_path( twigSvgIncludeStr, svgName, isUsingPlugin, function( error, result, output, printed ) {
|
|
108
|
+
|
|
109
|
+
if ( error ) {
|
|
110
|
+
reject( error );
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
resolve( result );
|
|
114
|
+
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
function parseWpAction( twigMarkup ) {
|
|
124
|
+
return new Promise( ( resolve, reject ) => {
|
|
125
|
+
|
|
126
|
+
execPhp( path.resolve( __dirname, './lib/twig-to-php-parser.php' ), config.phpBinaryPath, function( error, php, output ) {
|
|
127
|
+
|
|
128
|
+
if ( error ) {
|
|
129
|
+
reject( error );
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
php.parse_wp_action( twigMarkup, function( error, result, output, printed ) {
|
|
133
|
+
|
|
134
|
+
if ( error ) {
|
|
135
|
+
reject( error );
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
resolve( result );
|
|
139
|
+
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
}
|
|
147
|
+
|
|
67
148
|
module.exports = {
|
|
68
149
|
twigToPhpParser: twigToPhpParser,
|
|
69
150
|
methods: {
|
|
70
|
-
parseIncludePath: parseIncludePath
|
|
151
|
+
parseIncludePath: parseIncludePath,
|
|
152
|
+
parseSvgPath: parseSvgPath,
|
|
153
|
+
parseWpAction: parseWpAction
|
|
71
154
|
},
|
|
72
155
|
run: () => {
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
.catch( e => console.log( e ) );
|
|
156
|
+
twigToPhpParser( config )
|
|
157
|
+
.catch( e => console.log( e ) ) // PHP errors
|
|
158
|
+
.then( result => console.log(
|
|
159
|
+
chalk.green( 'Completed parsing Twig templates to PHP.' )
|
|
160
|
+
) )
|
|
161
|
+
.catch( e => console.log( e ) );
|
|
80
162
|
}
|
|
81
163
|
};
|
package/lib/getConfig.js
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
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
|
+
|
|
24
|
+
try {
|
|
25
|
+
let appRoot = process.cwd();
|
|
26
|
+
|
|
27
|
+
if ( 'test' === process.env.NODE_ENV ) {
|
|
28
|
+
appRoot = path.join( __dirname, '../__tests__/fixtures' );
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
let config = require( `${appRoot}/larva.config.js` )[ key ];
|
|
32
|
+
|
|
33
|
+
if ( undefined === config ) {
|
|
34
|
+
throw new Error( `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
|
+
return config;
|
|
38
|
+
|
|
39
|
+
} catch ( error ) {
|
|
40
|
+
console.error( chalk.red( chalk.bold( 'There is no larva.config.js in this directory.\n' ) + error ) );
|
|
41
|
+
}
|
|
42
|
+
};
|
|
@@ -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 );
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@penskemediacorp/twig-to-php-parser",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.14.0",
|
|
4
4
|
"description": "> TODO: description",
|
|
5
5
|
"author": "laras126 <laras126@gmail.com>",
|
|
6
6
|
"homepage": "https://github.com/penske-media-corp/pmc-larva#readme",
|
|
@@ -23,8 +23,8 @@
|
|
|
23
23
|
"url": "https://github.com/penske-media-corp/pmc-larva/issues"
|
|
24
24
|
},
|
|
25
25
|
"dependencies": {
|
|
26
|
-
"
|
|
26
|
+
"chalk": "^4.1.0",
|
|
27
27
|
"exec-php": "0.0.5"
|
|
28
28
|
},
|
|
29
|
-
"gitHead": "
|
|
29
|
+
"gitHead": "fbf545499333b58c945ad92d4be8ffa8a233bae3"
|
|
30
30
|
}
|
package/.DS_Store
DELETED
|
Binary file
|
package/__tests__/.DS_Store
DELETED
|
Binary file
|
|
Binary file
|