@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.
Files changed (35) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +51 -4
  3. package/__tests__/fixtures/larva.config.js +7 -0
  4. package/__tests__/fixtures/src/patterns/04-components/c-byline/c-byline.twig +1 -1
  5. package/__tests__/fixtures/src/patterns/04-components/c-heading/c-heading.twig +0 -1
  6. package/__tests__/fixtures/src/patterns/04-components/c-logo/c-logo.twig +3 -0
  7. package/__tests__/fixtures/src/patterns/08-modules/array-key-in-loop/array-key-in-loop.twig +11 -0
  8. package/__tests__/fixtures/src/patterns/08-modules/escaped-output-in-loop/escaped-output-in-loop.twig +5 -0
  9. package/__tests__/fixtures/src/patterns/08-modules/html-tag-interpolation/html-tag-interpolation.twig +7 -0
  10. package/__tests__/fixtures/src/patterns/08-modules/trending/trending.twig +1 -0
  11. package/__tests__/fixtures/src/patterns/99-objects/o-nav/o-nav.twig +4 -0
  12. package/__tests__/fixtures/template-parts/.gitkeep +1 -0
  13. package/__tests__/fixtures/template-parts-expected/patterns/components/c-button.php +7 -1
  14. package/__tests__/fixtures/template-parts-expected/patterns/components/c-byline.php +7 -1
  15. package/__tests__/fixtures/template-parts-expected/patterns/components/c-heading.php +7 -2
  16. package/__tests__/fixtures/template-parts-expected/patterns/components/c-logo.php +12 -0
  17. package/__tests__/fixtures/template-parts-expected/patterns/components/c-nav-link.php +8 -2
  18. package/__tests__/fixtures/template-parts-expected/patterns/modules/array-key-in-loop.php +20 -0
  19. package/__tests__/fixtures/template-parts-expected/patterns/modules/breadcrumbs.php +8 -2
  20. package/__tests__/fixtures/template-parts-expected/patterns/modules/escaped-output-in-loop.php +5 -0
  21. package/__tests__/fixtures/template-parts-expected/patterns/modules/html-tag-interpolation.php +16 -0
  22. package/__tests__/fixtures/template-parts-expected/patterns/modules/trending.php +10 -3
  23. package/__tests__/fixtures/template-parts-expected/patterns/objects/o-crap.php +7 -1
  24. package/__tests__/fixtures/template-parts-expected/patterns/objects/o-nav.php +12 -2
  25. package/__tests__/fixtures/template-parts-expected/patterns/objects/o-story-list.php +8 -2
  26. package/__tests__/parser-methods.test.js +74 -9
  27. package/__tests__/twig-to-php-parser.test.js +17 -15
  28. package/index.js +100 -18
  29. package/lib/getConfig.js +42 -0
  30. package/lib/twig-to-php-parser.php +218 -61
  31. package/package.json +3 -3
  32. package/.DS_Store +0 -0
  33. package/__tests__/.DS_Store +0 -0
  34. package/__tests__/fixtures/src/patterns/.DS_Store +0 -0
  35. 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 guidelies: https://confluence.pmcdev.io/x/JoGJAg
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
- $ node_modules/.bin/twig-to-php-parser
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,7 @@
1
+ module.exports = {
2
+ parser: {
3
+ twigDir: `${__dirname}/src/patterns/`,
4
+ phpDir: `${__dirname}/template-parts/patterns/`,
5
+ isUsingPlugin: true,
6
+ }
7
+ };
@@ -1,5 +1,5 @@
1
1
  <p class="c-byline {{ modifier_class }} {{ c_byline_classes }}">
2
2
  {{ c_byline_by_text }}
3
3
 
4
- {{ c_byline_markup }}
4
+ {{ c_byline_markup|raw }}
5
5
  </p>
@@ -1,2 +1 @@
1
1
  <h2 class="c-heading {{ modifier_class }}">{{ c_heading_text }}</h2>
2
- {% include "../modules/trending.twig" with item %}
@@ -0,0 +1,3 @@
1
+ <div>
2
+ {% include '/assets/build/svg/' ~ c_logo_svg ~ '.svg' %}
3
+ </div>
@@ -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 %}
@@ -0,0 +1,5 @@
1
+ {% for item in slides %}
2
+ <div>
3
+ {{ item|markup }}
4
+ </div>
5
+ {% endfor %}
@@ -0,0 +1,7 @@
1
+ <{{ list_type_name }}l class="list larva // {{ list_classes }}">
2
+ {% for item in list_items %}
3
+ <li class="list__item larva // {{ list_item_classes }}">
4
+ {% include "@larva/modules/list/list.twig" with item %}
5
+ </li>
6
+ {% endfor %}
7
+ </{{ list_type_name }}l>
@@ -5,4 +5,5 @@
5
5
  <div class="pmc-u-margin-b-0 u-border-bottom-2">
6
6
  {% include "../../05-objects/o-story-list/o-story-list.twig" with o_story_list %}
7
7
  </div>
8
+ {{ trending_ads_wp_action }}
8
9
  </section>
@@ -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
- // This is a generated file. Refer to the relevant Twig file for adjusting this markup.
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
- // This is a generated file. Refer to the relevant Twig file for adjusting this markup.
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
- // This is a generated file. Refer to the relevant Twig file for adjusting this markup.
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
- // This is a generated file. Refer to the relevant Twig file for adjusting this markup.
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
- // This is a generated file. Refer to the relevant Twig file for adjusting this markup.
2
+ /**
3
+ * Generated file.
4
+ *
5
+ * Refer to the relevant Twig file for adjusting this markup.
6
+ */
7
+
3
8
  ?>
4
- <?php \PMC::render_template( CHILD_THEME_PATH . '/template-parts/patterns/objects/o-nav.php', $o_nav, true ); ?>
9
+
10
+ <?php \PMC\Larva\Pattern::get_instance()->render_pattern_template( 'objects/o-nav', $o_nav, true ); ?>
@@ -0,0 +1,5 @@
1
+ <?php foreach ( $slides ?? [] as $item ) { ?>
2
+ <div>
3
+ <?php echo wp_kses_post( $item ?? '' ); ?>
4
+ </div>
5
+ <?php } ?>
@@ -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
- // This is a generated file. Refer to the relevant Twig file for adjusting this markup.
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::render_template( CHILD_THEME_PATH . '/template-parts/patterns/components/c-heading.php', $c_heading, true ); ?>
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::render_template( CHILD_THEME_PATH . '/template-parts/patterns/objects/o-story-list.php', $o_story_list, true ); ?>
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
- // This is a generated file. Refer to the relevant Twig file for adjusting this markup.
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
- // This is a generated file. Refer to the relevant Twig file for adjusting this markup.
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::render_template( CHILD_THEME_PATH . '/template-parts/patterns/components/c-nav-link.php', $item, true ); ?>
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
- // This is a generated file. Refer to the relevant Twig file for adjusting this markup.
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::render_template( CHILD_THEME_PATH . '/template-parts/patterns/objects/o-tease.php', $item, true ); ?>
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( CHILD_THEME_PATH . \'/template-parts/patterns/objects/o-nav.php\', $o_nav, true ); ?>'
13
- // larvaInclude: '<?php \\PMC::render_template( PMC_CORE_PATH . \'/template-parts/patterns/objects/o-nav.php\', $o_nav, true ); ?>' - uncomment when core logic is reactivated
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 pathConfig = {
10
- twigDir: `${fixture}/src/patterns/`,
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
- exec( 'mkdir ' + pathConfig.phpDir, ( err ) => {
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( pathConfig.twigDir, pathConfig.phpDir )
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( pathConfig.phpDir + 'objects/o-nav.php' ), true );
40
- assert.equal( fs.existsSync( pathConfig.phpDir + 'components/c-nav-link.php' ), true );
41
- assert.equal( fs.existsSync( pathConfig.phpDir + 'modules/breadcrumbs.php' ), true );
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( pathConfig.expectedDir + shortpath ).toString();
48
- let actualContents = fs.readFileSync( pathConfig.phpDir + shortpath ).toString();
49
-
50
- assert.equal( expectedContents, actualContents );
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 ' + pathConfig.phpDir, ( err ) => {
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( '@penskemediacorp/larva' ).config;
5
- const RELATIVE_OUPUT_PATH = '../template-parts/patterns'; // Not permitted to override this because it will break the include paths.
4
+ const getAppConfiguration = require( './lib/getConfig' );
5
+ const config = getAppConfiguration( 'parser' );
6
6
 
7
7
  /**
8
8
  * Twig to PHP Parser
9
- *
10
- * @param {string} twigDirPath Absolute path to Twig patterns
11
- * @param {string} phpDirPath Absolute path to PHP output
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( twigDirPath, phpDirPath, config = {} ) {
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( twigDirPath, phpDirPath, function( error, result, output, printed ) {
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, config = {} ) {
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
- let config = getAppConfiguration( 'parser' );
74
- let relativeSrcPath = config.relativeSrcOverride || './src/patterns';
75
-
76
- twigToPhpParser( path.resolve( process.cwd(), relativeSrcPath ), path.resolve( process.cwd(), RELATIVE_OUPUT_PATH ), config )
77
- .catch( e => console.log( e ) ) // PHP errors
78
- .then( result => console.log( chalk.green( 'Completed parsing Twig templates to PHP.' ) ) )
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
  };
@@ -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 06/26/2019
10
- * @author Lara Schenck and Amit Sannad
7
+ *
8
+ * @since 06/26/2019
9
+ * @author Lara Schenck and Amit Sannad
10
+ * @package pmc-lavra
11
11
  */
12
12
 
13
- function twig_to_php_parser( $patterns_dir_path, $template_dir_path ) {
14
- $twig_files = [];
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/Lnoaau/1
60
- $if_condition_regex = '/({% if\s*)(\w*)(\s*%})/';
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/lceCnz/2/
64
- $loop_regex = '/({% for item in\s*)(\w*)/';
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/1
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/2
72
- $include_regex = '/({%\sinclude ")(.*[c-|o-|l-].*\/)(.*)(.twig)(" with )(\w*)(.*\s%})/';
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
- $twig_markup = \file_get_contents( $twig_file );
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 /*' . "\n",
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
- $variable_name = $loop_matches[2][ $count ];
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 $item';
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
- $is_attr = strpos( $match, 'class' ) || strpos( $match, 'name' ) || strpos( $match, 'attr' );
123
- $is_url = strpos( $match, 'url' );
124
- $is_text = strpos( $match, 'text' );
125
- $is_data_attr = strpos( $match, 'attributes' );
126
- $is_markup = strpos( $match, 'markup' );
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 = (array) array_merge( $mustache_matches[0], $include_matches[0], $loop_matches[0], $if_condition_matches[0] );
161
- $all_replacements = (array) array_merge( $mustache_replacements, $include_replacements, $loop_replacements, $if_condition_replacements );
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// This is a generated file. Refer to the relevant Twig file for adjusting this markup.\n?>\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 $twig_include Full include expression
183
- * @param string $pattern_name o-nav
184
- * @param string $data_name o_nav / usually name of pattern with underscores
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
- $theme_dir = 'CHILD_THEME_PATH';
190
- $start_name = substr( $pattern_name, 0, 2 );
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
- // 08/09/19 - Disabling larva/core theme logic
193
- // if ( strpos( $twig_include, "@larva" ) ) {
194
- // $theme_dir = 'PMC_CORE_PATH';
195
- // }
257
+ if ( strpos( $twig_include, '@larva' ) ) {
258
+ $brand_directory = 'PMC_CORE_PATH';
259
+ }
196
260
 
197
261
  if ( 'c-' === $start_name ) {
198
- $directory = 'components';
262
+ $pattern_type = 'components';
199
263
  } elseif ( 'o-' === $start_name ) {
200
- $directory = 'objects';
264
+ $pattern_type = 'objects';
201
265
  } elseif ( '-' !== substr( $pattern_name, 1, 2 ) ) { // If there is no namespace, it is a module.
202
- $directory = 'modules';
266
+ $pattern_type = 'modules';
203
267
  }
204
268
 
205
- return "<?php \PMC::render_template( " . $theme_dir . " . '/template-parts/patterns/" . $directory . "/" . $pattern_name . ".php', $" . $data_name . ', true ); ?>';
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
- //EOF
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.10.0-alpha.0",
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
- "@penskemediacorp/larva": "^1.10.0-alpha.0",
26
+ "chalk": "^4.1.0",
27
27
  "exec-php": "0.0.5"
28
28
  },
29
- "gitHead": "b5be68c48f8238f421e6521abfe46eca18d51781"
29
+ "gitHead": "fbf545499333b58c945ad92d4be8ffa8a233bae3"
30
30
  }
package/.DS_Store DELETED
Binary file
Binary file
@@ -1,3 +0,0 @@
1
- <?php
2
-
3
- echo "placeholder to commit this directory";